• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
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 <string>
9 
10 #include "base/basictypes.h"
11 #include "base/memory/ref_counted.h"
12 #include "base/strings/string_piece.h"
13 #include "base/time/time.h"
14 #include "net/base/net_export.h"
15 #include "net/base/net_util.h"
16 
17 namespace net {
18 
19 class AddressList;
20 class DnsQuery;
21 class IOBufferWithSize;
22 
23 namespace dns_protocol {
24 struct Header;
25 }
26 
27 // Parsed resource record.
28 struct NET_EXPORT_PRIVATE DnsResourceRecord {
29   DnsResourceRecord();
30   ~DnsResourceRecord();
31 
32   std::string name;  // in dotted form
33   uint16 type;
34   uint16 klass;
35   uint32 ttl;
36   base::StringPiece rdata;  // points to the original response buffer
37 };
38 
39 // Iterator to walk over resource records of the DNS response packet.
40 class NET_EXPORT_PRIVATE DnsRecordParser {
41  public:
42   // Construct an uninitialized iterator.
43   DnsRecordParser();
44 
45   // Construct an iterator to process the |packet| of given |length|.
46   // |offset| points to the beginning of the answer section.
47   DnsRecordParser(const void* packet, size_t length, size_t offset);
48 
49   // Returns |true| if initialized.
IsValid()50   bool IsValid() const { return packet_ != NULL; }
51 
52   // Returns |true| if no more bytes remain in the packet.
AtEnd()53   bool AtEnd() const { return cur_ == packet_ + length_; }
54 
55   // Returns current offset into the packet.
GetOffset()56   size_t GetOffset() const { return cur_ - packet_; }
57 
58   // Parses a (possibly compressed) DNS name from the packet starting at
59   // |pos|. Stores output (even partial) in |out| unless |out| is NULL. |out|
60   // is stored in the dotted form, e.g., "example.com". Returns number of bytes
61   // consumed or 0 on failure.
62   // This is exposed to allow parsing compressed names within RRDATA for TYPEs
63   // such as NS, CNAME, PTR, MX, SOA.
64   // See RFC 1035 section 4.1.4.
65   unsigned ReadName(const void* pos, std::string* out) const;
66 
67   // Parses the next resource record into |record|. Returns true if succeeded.
68   bool ReadRecord(DnsResourceRecord* record);
69 
70   // Skip a question section, returns true if succeeded.
71   bool SkipQuestion();
72 
73  private:
74   const char* packet_;
75   size_t length_;
76   // Current offset within the packet.
77   const char* cur_;
78 };
79 
80 // Buffer-holder for the DNS response allowing easy access to the header fields
81 // and resource records. After reading into |io_buffer| must call InitParse to
82 // position the RR parser.
83 class NET_EXPORT_PRIVATE DnsResponse {
84  public:
85   // Possible results from ParseToAddressList.
86   enum Result {
87     DNS_PARSE_OK = 0,
88     DNS_MALFORMED_RESPONSE,    // DnsRecordParser failed before the end of
89                                // packet.
90     DNS_MALFORMED_CNAME,       // Could not parse CNAME out of RRDATA.
91     DNS_NAME_MISMATCH,         // Got an address but no ordered chain of CNAMEs
92                                // leads there.
93     DNS_SIZE_MISMATCH,         // Got an address but size does not match.
94     DNS_CNAME_AFTER_ADDRESS,   // Found CNAME after an address record.
95     DNS_ADDRESS_TTL_MISMATCH,  // OBSOLETE. No longer used.
96     DNS_NO_ADDRESSES,          // OBSOLETE. No longer used.
97     // Only add new values here.
98     DNS_PARSE_RESULT_MAX,      // Bounding value for histograms.
99   };
100 
101   // Constructs a response buffer large enough to store one byte more than
102   // largest possible response, to detect malformed responses.
103   DnsResponse();
104 
105   // Constructs a response buffer of given length. Used for TCP transactions.
106   explicit DnsResponse(size_t length);
107 
108   // Constructs a response from |data|. Used for testing purposes only!
109   DnsResponse(const void* data, size_t length, size_t answer_offset);
110 
111   ~DnsResponse();
112 
113   // Internal buffer accessor into which actual bytes of response will be
114   // read.
io_buffer()115   IOBufferWithSize* io_buffer() { return io_buffer_.get(); }
116 
117   // Assuming the internal buffer holds |nbytes| bytes, returns true iff the
118   // packet matches the |query| id and question.
119   bool InitParse(int nbytes, const DnsQuery& query);
120 
121   // Assuming the internal buffer holds |nbytes| bytes, initialize the parser
122   // without matching it against an existing query.
123   bool InitParseWithoutQuery(int nbytes);
124 
125   // Returns true if response is valid, that is, after successful InitParse.
126   bool IsValid() const;
127 
128   // All of the methods below are valid only if the response is valid.
129 
130   // Accessors for the header.
131   uint16 flags() const;  // excluding rcode
132   uint8 rcode() const;
133 
134   unsigned answer_count() const;
135   unsigned additional_answer_count() const;
136 
137   // Accessors to the question. The qname is unparsed.
138   base::StringPiece qname() const;
139   uint16 qtype() const;
140 
141   // Returns qname in dotted format.
142   std::string GetDottedName() const;
143 
144   // Returns an iterator to the resource records in the answer section.
145   // The iterator is valid only in the scope of the DnsResponse.
146   // This operation is idempotent.
147   DnsRecordParser Parser() const;
148 
149   // Extracts an AddressList from this response. Returns SUCCESS if succeeded.
150   // Otherwise returns a detailed error number.
151   Result ParseToAddressList(AddressList* addr_list, base::TimeDelta* ttl) const;
152 
153  private:
154   // Convenience for header access.
155   const dns_protocol::Header* header() const;
156 
157   // Buffer into which response bytes are read.
158   scoped_refptr<IOBufferWithSize> io_buffer_;
159 
160   // Iterator constructed after InitParse positioned at the answer section.
161   // It is never updated afterwards, so can be used in accessors.
162   DnsRecordParser parser_;
163 
164   DISALLOW_COPY_AND_ASSIGN(DnsResponse);
165 };
166 
167 }  // namespace net
168 
169 #endif  // NET_DNS_DNS_RESPONSE_H_
170