• 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 <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