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