Avi Drissman | 6459548 | 2022-09-14 20:52:29 | [diff] [blame] | 1 | // Copyright 2011 The Chromium Authors |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
agayev@chromium.org | 4b0112ab | 2011-07-22 15:58:20 | [diff] [blame] | 5 | #ifndef NET_DNS_DNS_QUERY_H_ |
| 6 | #define NET_DNS_DNS_QUERY_H_ |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 7 | |
Avi Drissman | 13fc893 | 2015-12-20 04:40:46 | [diff] [blame] | 8 | #include <stddef.h> |
| 9 | #include <stdint.h> |
| 10 | |
danakj | 22f90e7 | 2016-04-16 01:55:40 | [diff] [blame] | 11 | #include <memory> |
Eric Orth | bc28a52 | 2019-06-04 16:03:56 | [diff] [blame] | 12 | #include <string> |
Md Hasibul Hasan | 7495cd7 | 2024-03-26 01:02:32 | [diff] [blame] | 13 | #include <string_view> |
danakj | 22f90e7 | 2016-04-16 01:55:40 | [diff] [blame] | 14 | |
Eric Orth | 0eeeef18 | 2022-12-01 23:49:57 | [diff] [blame] | 15 | #include "base/containers/span.h" |
danakj | 1a2d0e3 | 2024-04-12 18:33:40 | [diff] [blame] | 16 | #include "base/containers/span_reader.h" |
Ho Cheung | 7964ef3 | 2023-05-25 20:07:44 | [diff] [blame] | 17 | #include "base/memory/raw_ptr.h" |
Lei Zhang | 58a108245 | 2022-11-08 04:23:20 | [diff] [blame] | 18 | #include "base/memory/scoped_refptr.h" |
danakj | 16923e2 | 2024-03-05 19:39:55 | [diff] [blame] | 19 | #include "net/base/io_buffer.h" |
darin@chromium.org | 172da1b | 2011-08-12 15:52:26 | [diff] [blame] | 20 | #include "net/base/net_export.h" |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 21 | |
agayev@chromium.org | 78400831 | 2011-06-28 22:15:17 | [diff] [blame] | 22 | namespace net { |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 23 | |
Rob Percival | c2b1a17 | 2017-09-25 13:30:42 | [diff] [blame] | 24 | class OptRecordRdata; |
| 25 | |
tfarina | 0e534a8 | 2015-12-30 13:34:06 | [diff] [blame] | 26 | namespace dns_protocol { |
| 27 | struct Header; |
Qingsi Wang | ecd6925 | 2018-09-27 21:35:55 | [diff] [blame] | 28 | } // namespace dns_protocol |
tfarina | 0e534a8 | 2015-12-30 13:34:06 | [diff] [blame] | 29 | |
agayev@chromium.org | 4b0112ab | 2011-07-22 15:58:20 | [diff] [blame] | 30 | class IOBufferWithSize; |
| 31 | |
agayev@chromium.org | 168c432 | 2011-06-09 18:05:15 | [diff] [blame] | 32 | // Represents on-the-wire DNS query message as an object. |
darin@chromium.org | 172da1b | 2011-08-12 15:52:26 | [diff] [blame] | 33 | class NET_EXPORT_PRIVATE DnsQuery { |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 34 | public: |
Eric Orth | bc28a52 | 2019-06-04 16:03:56 | [diff] [blame] | 35 | enum class PaddingStrategy { |
| 36 | // Query will not be padded. Recommended strategy when query will not be |
| 37 | // encrypted. |
| 38 | NONE, |
| 39 | |
| 40 | // Query will be padded to the next multiple of 128 octets. Recommended |
| 41 | // strategy (per RFC 8467) when query will be encrypted, e.g. through |
| 42 | // DNS-over-HTTPS. |
| 43 | BLOCK_LENGTH_128, |
| 44 | }; |
| 45 | |
agayev@chromium.org | 511d1651 | 2011-06-29 20:20:38 | [diff] [blame] | 46 | // Constructs a query message from |qname| which *MUST* be in a valid |
szym@chromium.org | 7556ea2 | 2011-12-08 19:29:15 | [diff] [blame] | 47 | // DNS name format, and |qtype|. The qclass is set to IN. |
Eric Orth | bc28a52 | 2019-06-04 16:03:56 | [diff] [blame] | 48 | // If |opt_rdata| is not null, an OPT record will be added to the "Additional" |
Rob Percival | c2b1a17 | 2017-09-25 13:30:42 | [diff] [blame] | 49 | // section of the query. |
| 50 | DnsQuery(uint16_t id, |
Eric Orth | 0eeeef18 | 2022-12-01 23:49:57 | [diff] [blame] | 51 | base::span<const uint8_t> qname, |
Rob Percival | c2b1a17 | 2017-09-25 13:30:42 | [diff] [blame] | 52 | uint16_t qtype, |
Eric Orth | bc28a52 | 2019-06-04 16:03:56 | [diff] [blame] | 53 | const OptRecordRdata* opt_rdata = nullptr, |
| 54 | PaddingStrategy padding_strategy = PaddingStrategy::NONE); |
Qingsi Wang | ecd6925 | 2018-09-27 21:35:55 | [diff] [blame] | 55 | |
| 56 | // Constructs an empty query from a raw packet in |buffer|. If the raw packet |
| 57 | // represents a valid DNS query in the wire format (RFC 1035), Parse() will |
| 58 | // populate the empty query. |
Eric Orth | bc28a52 | 2019-06-04 16:03:56 | [diff] [blame] | 59 | explicit DnsQuery(scoped_refptr<IOBufferWithSize> buffer); |
Qingsi Wang | ecd6925 | 2018-09-27 21:35:55 | [diff] [blame] | 60 | |
Eric Orth | be910d40 | 2020-08-04 21:48:24 | [diff] [blame] | 61 | // Copies are constructed with an independent cloned, not mirrored, buffer. |
| 62 | DnsQuery(const DnsQuery& query); |
| 63 | DnsQuery& operator=(const DnsQuery& query); |
| 64 | |
Tom Sepez | 145443a | 2024-11-05 23:54:05 | [diff] [blame] | 65 | // Moves do not clone an independent buffer. |
| 66 | DnsQuery(DnsQuery&& query); |
| 67 | DnsQuery& operator=(DnsQuery&& query); |
| 68 | |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 69 | ~DnsQuery(); |
| 70 | |
szym@chromium.org | 7556ea2 | 2011-12-08 19:29:15 | [diff] [blame] | 71 | // Clones |this| verbatim, with ID field of the header set to |id|. |
danakj | 22f90e7 | 2016-04-16 01:55:40 | [diff] [blame] | 72 | std::unique_ptr<DnsQuery> CloneWithNewId(uint16_t id) const; |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 73 | |
Qingsi Wang | ecd6925 | 2018-09-27 21:35:55 | [diff] [blame] | 74 | // Returns true and populates the query if the internally stored raw packet |
| 75 | // can be parsed. This should only be called when DnsQuery is constructed from |
| 76 | // the raw buffer. |
Matthew Denton | fa9af6a | 2018-10-18 20:44:17 | [diff] [blame] | 77 | // |valid_bytes| indicates the number of initialized bytes in the raw buffer. |
| 78 | // E.g. if the buffer holds a packet received from the network, the buffer may |
| 79 | // be allocated with the maximum size of a UDP packet, but |valid_bytes| |
| 80 | // indicates the number of bytes actually received from the network. If the |
| 81 | // parsing requires reading more than the number of initialized bytes, this |
| 82 | // method fails and returns false. |
| 83 | bool Parse(size_t valid_bytes); |
Qingsi Wang | ecd6925 | 2018-09-27 21:35:55 | [diff] [blame] | 84 | |
agayev@chromium.org | 168c432 | 2011-06-09 18:05:15 | [diff] [blame] | 85 | // DnsQuery field accessors. |
Avi Drissman | 13fc893 | 2015-12-20 04:40:46 | [diff] [blame] | 86 | uint16_t id() const; |
Eric Orth | 0eeeef18 | 2022-12-01 23:49:57 | [diff] [blame] | 87 | base::span<const uint8_t> qname() const; |
Avi Drissman | 13fc893 | 2015-12-20 04:40:46 | [diff] [blame] | 88 | uint16_t qtype() const; |
agayev@chromium.org | 168c432 | 2011-06-09 18:05:15 | [diff] [blame] | 89 | |
szym@chromium.org | 7556ea2 | 2011-12-08 19:29:15 | [diff] [blame] | 90 | // Returns the Question section of the query. Used when matching the |
| 91 | // response. |
Md Hasibul Hasan | 7495cd7 | 2024-03-26 01:02:32 | [diff] [blame] | 92 | std::string_view question() const; |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 93 | |
Qingsi Wang | 6584107 | 2018-10-09 01:14:45 | [diff] [blame] | 94 | // Returns the size of the question section. |
Eric Orth | bc28a52 | 2019-06-04 16:03:56 | [diff] [blame] | 95 | size_t question_size() const; |
Qingsi Wang | 6584107 | 2018-10-09 01:14:45 | [diff] [blame] | 96 | |
Qingsi Wang | ecd6925 | 2018-09-27 21:35:55 | [diff] [blame] | 97 | // IOBuffer accessor to be used for writing out the query. The buffer has |
| 98 | // the same byte layout as the DNS query wire format. |
rsleevi@chromium.org | 9049948 | 2013-06-01 00:39:50 | [diff] [blame] | 99 | IOBufferWithSize* io_buffer() const { return io_buffer_.get(); } |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 100 | |
Avi Drissman | 13fc893 | 2015-12-20 04:40:46 | [diff] [blame] | 101 | void set_flags(uint16_t flags); |
noamsml@chromium.org | 245b164e | 2013-06-13 22:31:42 | [diff] [blame] | 102 | |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 103 | private: |
Avi Drissman | 13fc893 | 2015-12-20 04:40:46 | [diff] [blame] | 104 | DnsQuery(const DnsQuery& orig, uint16_t id); |
Eric Orth | be910d40 | 2020-08-04 21:48:24 | [diff] [blame] | 105 | void CopyFrom(const DnsQuery& orig); |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 106 | |
danakj | 1a2d0e3 | 2024-04-12 18:33:40 | [diff] [blame] | 107 | bool ReadHeader(base::SpanReader<const uint8_t>* reader, |
| 108 | dns_protocol::Header* out); |
Qingsi Wang | ecd6925 | 2018-09-27 21:35:55 | [diff] [blame] | 109 | // After read, |out| is in the DNS format, e.g. |
| 110 | // "\x03""www""\x08""chromium""\x03""com""\x00". Use DNSDomainToString to |
| 111 | // convert to the dotted format "www.chromium.com" with no trailing dot. |
danakj | 1a2d0e3 | 2024-04-12 18:33:40 | [diff] [blame] | 112 | bool ReadName(base::SpanReader<const uint8_t>* reader, std::string* out); |
Qingsi Wang | ecd6925 | 2018-09-27 21:35:55 | [diff] [blame] | 113 | |
danakj | 16923e2 | 2024-03-05 19:39:55 | [diff] [blame] | 114 | // Returns the Header pointer into the `io_buffer_`. Only valid to call on a |
| 115 | // DNSQuery has a valid IOBuffer, so this never returns null. |
| 116 | // |
| 117 | // TODO(davidben): Dereferencing the returned pointer will be UB. The correct |
| 118 | // shape of this function would be to do a memcpy into/out of a Header to read |
| 119 | // out of/into the buffer. |
| 120 | const dns_protocol::Header* header_in_io_buffer() const { |
| 121 | CHECK(io_buffer_ && !io_buffer_->span().empty()); |
| 122 | return reinterpret_cast<dns_protocol::Header*>(io_buffer_->span().data()); |
| 123 | } |
| 124 | dns_protocol::Header* header_in_io_buffer() { |
| 125 | CHECK(io_buffer_ && !io_buffer_->span().empty()); |
| 126 | return reinterpret_cast<dns_protocol::Header*>(io_buffer_->span().data()); |
| 127 | } |
| 128 | |
agayev@chromium.org | 168c432 | 2011-06-09 18:05:15 | [diff] [blame] | 129 | // Size of the DNS name (*NOT* hostname) we are trying to resolve; used |
| 130 | // to calculate offsets. |
Qingsi Wang | ecd6925 | 2018-09-27 21:35:55 | [diff] [blame] | 131 | size_t qname_size_ = 0; |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 132 | |
| 133 | // Contains query bytes to be consumed by higher level Write() call. |
| 134 | scoped_refptr<IOBufferWithSize> io_buffer_; |
agayev@chromium.org | b581064 | 2011-06-03 21:26:49 | [diff] [blame] | 135 | }; |
| 136 | |
| 137 | } // namespace net |
| 138 | |
agayev@chromium.org | 4b0112ab | 2011-07-22 15:58:20 | [diff] [blame] | 139 | #endif // NET_DNS_DNS_QUERY_H_ |