1 // Copyright 2012 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_DNS_DNS_RESPONSE_H_ 6 #define NET_DNS_DNS_RESPONSE_H_ 7 8 #include <stddef.h> 9 #include <stdint.h> 10 11 #include <optional> 12 #include <string> 13 #include <string_view> 14 #include <vector> 15 16 #include "base/compiler_specific.h" 17 #include "base/containers/span.h" 18 #include "base/containers/span_writer.h" 19 #include "base/memory/scoped_refptr.h" 20 #include "net/base/net_export.h" 21 #include "net/dns/dns_response_result_extractor.h" 22 #include "net/dns/public/dns_protocol.h" 23 24 namespace net { 25 26 class DnsQuery; 27 class IOBuffer; 28 29 namespace dns_protocol { 30 struct Header; 31 } // namespace dns_protocol 32 33 // Structure representing a Resource Record as specified in RFC 1035, Section 34 // 4.1.3. 35 struct NET_EXPORT_PRIVATE DnsResourceRecord { 36 DnsResourceRecord(); 37 DnsResourceRecord(const DnsResourceRecord& other); 38 DnsResourceRecord(DnsResourceRecord&& other); 39 ~DnsResourceRecord(); 40 41 DnsResourceRecord& operator=(const DnsResourceRecord& other); 42 DnsResourceRecord& operator=(DnsResourceRecord&& other); 43 44 // A helper to set |owned_rdata| that also sets |rdata| to point to it. The 45 // |value| must be non-empty. See the definition of |owned_rdata| below. 46 void SetOwnedRdata(std::string value); 47 48 // NAME (variable length) + TYPE (2 bytes) + CLASS (2 bytes) + TTL (4 bytes) + 49 // RDLENGTH (2 bytes) + RDATA (variable length) 50 // 51 // Uses |owned_rdata| for RDATA if non-empty. 52 size_t CalculateRecordSize() const; 53 54 std::string name; // in dotted form 55 uint16_t type = 0; 56 uint16_t klass = 0; 57 uint32_t ttl = 0; 58 // Points to the original response buffer or otherwise to |owned_rdata|. 59 std::string_view rdata; 60 // Used to construct a DnsResponse from data. This field is empty if |rdata| 61 // points to the response buffer. 62 std::string owned_rdata; 63 }; 64 65 // Iterator to walk over resource records of the DNS response packet. 66 class NET_EXPORT_PRIVATE DnsRecordParser { 67 public: 68 // Construct an uninitialized iterator. 69 DnsRecordParser(); 70 71 // Construct an iterator to process the `packet`. 72 // `offset` points to the beginning of the answer section. `ReadRecord()` will 73 // fail if called more than `num_records` times, no matter whether or not 74 // there is additional data at the end of the buffer that may appear to be a 75 // valid record. 76 DnsRecordParser(base::span<const uint8_t> packet, 77 size_t offset, 78 size_t num_records); 79 80 // TODO(crbug.com/40284755): Deprecated, use the span-based constructor. 81 UNSAFE_BUFFER_USAGE DnsRecordParser(const void* packet, 82 size_t length, 83 size_t offset, 84 size_t num_records); 85 86 // Returns |true| if initialized. IsValid()87 bool IsValid() const { return !packet_.empty(); } 88 89 // Returns |true| if no more bytes remain in the packet. AtEnd()90 bool AtEnd() const { return cur_ == packet_.size(); } 91 92 // Returns current offset into the packet. GetOffset()93 size_t GetOffset() const { return cur_; } 94 95 // Parses a (possibly compressed) DNS name from the packet starting at 96 // |pos|. Stores output (even partial) in |out| unless |out| is NULL. |out| 97 // is stored in the dotted form, e.g., "example.com". Returns number of bytes 98 // consumed or 0 on failure. 99 // This is exposed to allow parsing compressed names within RRDATA for TYPEs 100 // such as NS, CNAME, PTR, MX, SOA. 101 // See RFC 1035 section 4.1.4. 102 unsigned ReadName(const void* pos, std::string* out) const; 103 104 // Parses the next resource record into |record|. Returns true if succeeded. 105 bool ReadRecord(DnsResourceRecord* record); 106 107 // Read a question section, returns true if succeeded. In `DnsResponse`, 108 // expected to be called during parse, after which the current offset will be 109 // after all questions. 110 bool ReadQuestion(std::string& out_dotted_qname, uint16_t& out_qtype); 111 112 private: 113 base::span<const uint8_t> packet_; 114 size_t num_records_ = 0u; 115 size_t num_records_parsed_ = 0u; 116 // Current offset within the packet. 117 size_t cur_ = 0u; 118 }; 119 120 // Buffer-holder for the DNS response allowing easy access to the header fields 121 // and resource records. After reading into |io_buffer| must call InitParse to 122 // position the RR parser. 123 class NET_EXPORT_PRIVATE DnsResponse { 124 public: 125 // Constructs a response buffer large enough to store one byte more than 126 // largest possible response, to detect malformed responses. 127 DnsResponse(); 128 129 // Constructs a response message from `answers` and the originating `query`. 130 // After the successful construction, and the parser is also initialized. 131 // 132 // If `validate_records` is false, DCHECKs validating the correctness of 133 // records will be skipped. Intended for tests to allow creation of malformed 134 // responses. 135 DnsResponse(uint16_t id, 136 bool is_authoritative, 137 const std::vector<DnsResourceRecord>& answers, 138 const std::vector<DnsResourceRecord>& authority_records, 139 const std::vector<DnsResourceRecord>& additional_records, 140 const std::optional<DnsQuery>& query, 141 uint8_t rcode = dns_protocol::kRcodeNOERROR, 142 bool validate_records = true, 143 bool validate_names_as_internet_hostnames = true); 144 145 // Constructs a response buffer of given length. Used for TCP transactions. 146 explicit DnsResponse(size_t length); 147 148 // Constructs a response from the passed buffer. 149 DnsResponse(scoped_refptr<IOBuffer> buffer, size_t size); 150 151 // Constructs a response from |data|. Used for testing purposes only! 152 DnsResponse(const void* data, size_t length, size_t answer_offset); 153 154 static DnsResponse CreateEmptyNoDataResponse(uint16_t id, 155 bool is_authoritative, 156 base::span<const uint8_t> qname, 157 uint16_t qtype); 158 159 // Move-only. 160 DnsResponse(DnsResponse&& other); 161 DnsResponse& operator=(DnsResponse&& other); 162 163 ~DnsResponse(); 164 165 // Internal buffer accessor into which actual bytes of response will be 166 // read. io_buffer()167 IOBuffer* io_buffer() { return io_buffer_.get(); } io_buffer()168 const IOBuffer* io_buffer() const { return io_buffer_.get(); } 169 170 // Size of the internal buffer. io_buffer_size()171 size_t io_buffer_size() const { return io_buffer_size_; } 172 173 // Assuming the internal buffer holds |nbytes| bytes, returns true iff the 174 // packet matches the |query| id and question. This should only be called if 175 // the response is constructed from a raw buffer. 176 bool InitParse(size_t nbytes, const DnsQuery& query); 177 178 // Assuming the internal buffer holds |nbytes| bytes, initialize the parser 179 // without matching it against an existing query. This should only be called 180 // if the response is constructed from a raw buffer. 181 bool InitParseWithoutQuery(size_t nbytes); 182 183 // Does not require the response to be fully parsed and valid, but will return 184 // nullopt if the ID is unknown. The ID will only be known if the response is 185 // successfully constructed from data or if InitParse...() has been able to 186 // parse at least as far as the ID (not necessarily a fully successful parse). 187 std::optional<uint16_t> id() const; 188 189 // Returns true if response is valid, that is, after successful InitParse, or 190 // after successful construction of a new response from data. 191 bool IsValid() const; 192 193 // All of the methods below are valid only if the response is valid. 194 195 // Accessors for the header. 196 uint16_t flags() const; // excluding rcode 197 uint8_t rcode() const; 198 199 unsigned question_count() const; 200 unsigned answer_count() const; 201 unsigned authority_count() const; 202 unsigned additional_answer_count() const; 203 qtypes()204 const std::vector<uint16_t>& qtypes() const { 205 DCHECK(parser_.IsValid()); 206 DCHECK_EQ(question_count(), qtypes_.size()); 207 return qtypes_; 208 } dotted_qnames()209 const std::vector<std::string>& dotted_qnames() const { 210 DCHECK(parser_.IsValid()); 211 DCHECK_EQ(question_count(), dotted_qnames_.size()); 212 return dotted_qnames_; 213 } 214 215 // Shortcuts to get qtype or qname for single-query responses. Should only be 216 // used in cases where there is known to be exactly one question (e.g. because 217 // that has been validated by `InitParse()`). 218 uint16_t GetSingleQType() const; 219 std::string_view GetSingleDottedName() const; 220 221 // Returns an iterator to the resource records in the answer section. 222 // The iterator is valid only in the scope of the DnsResponse. 223 // This operation is idempotent. 224 DnsRecordParser Parser() const; 225 226 private: 227 bool WriteHeader(base::SpanWriter<uint8_t>* writer, 228 const dns_protocol::Header& header); 229 bool WriteQuestion(base::SpanWriter<uint8_t>* writer, const DnsQuery& query); 230 bool WriteRecord(base::SpanWriter<uint8_t>* writer, 231 const DnsResourceRecord& record, 232 bool validate_record, 233 bool validate_name_as_internet_hostname); 234 bool WriteAnswer(base::SpanWriter<uint8_t>* writer, 235 const DnsResourceRecord& answer, 236 const std::optional<DnsQuery>& query, 237 bool validate_record, 238 bool validate_name_as_internet_hostname); 239 240 // Convenience for header access. 241 const dns_protocol::Header* header() const; 242 243 // Buffer into which response bytes are read. 244 scoped_refptr<IOBuffer> io_buffer_; 245 246 // Size of the buffer. 247 size_t io_buffer_size_; 248 249 // Iterator constructed after InitParse positioned at the answer section. 250 // It is never updated afterwards, so can be used in accessors. 251 DnsRecordParser parser_; 252 bool id_available_ = false; 253 std::vector<std::string> dotted_qnames_; 254 std::vector<uint16_t> qtypes_; 255 }; 256 257 } // namespace net 258 259 #endif // NET_DNS_DNS_RESPONSE_H_ 260