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