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