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