• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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