/src/hickory-dns/crates/proto/src/op/query.rs
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) 2015 Benjamin Fry <benjaminfry@me.com> |
3 | | * |
4 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | | * you may not use this file except in compliance with the License. |
6 | | * You may obtain a copy of the License at |
7 | | * |
8 | | * https://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | //! Query struct for looking up resource records |
18 | | |
19 | | #[cfg(test)] |
20 | | use alloc::vec::Vec; |
21 | | use core::fmt::{self, Display, Formatter}; |
22 | | |
23 | | #[cfg(feature = "serde")] |
24 | | use serde::{Deserialize, Serialize}; |
25 | | |
26 | | use crate::error::*; |
27 | | use crate::rr::dns_class::DNSClass; |
28 | | use crate::rr::domain::Name; |
29 | | use crate::rr::record_type::RecordType; |
30 | | use crate::rr::{Record, RecordData}; |
31 | | use crate::serialize::binary::*; |
32 | | |
33 | | #[cfg(feature = "mdns")] |
34 | | /// From [RFC 6762](https://tools.ietf.org/html/rfc6762#section-5.4) |
35 | | /// ```text |
36 | | // To avoid large floods of potentially unnecessary responses in these |
37 | | // cases, Multicast DNS defines the top bit in the class field of a DNS |
38 | | // question as the unicast-response bit. |
39 | | /// ``` |
40 | | const MDNS_UNICAST_RESPONSE: u16 = 1 << 15; |
41 | | |
42 | | /// Query struct for looking up resource records, basically a resource record without RDATA. |
43 | | /// |
44 | | /// [RFC 1035, DOMAIN NAMES - IMPLEMENTATION AND SPECIFICATION, November 1987](https://tools.ietf.org/html/rfc1035) |
45 | | /// |
46 | | /// ```text |
47 | | /// 4.1.2. Question section format |
48 | | /// |
49 | | /// The question section is used to carry the "question" in most queries, |
50 | | /// i.e., the parameters that define what is being asked. The section |
51 | | /// contains QDCOUNT (usually 1) entries, each of the following format: |
52 | | /// |
53 | | /// 1 1 1 1 1 1 |
54 | | /// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 |
55 | | /// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
56 | | /// | | |
57 | | /// / QNAME / ZNAME / |
58 | | /// / / |
59 | | /// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
60 | | /// | QTYPE / ZTYPE | |
61 | | /// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
62 | | /// | QCLASS / ZCLASS | |
63 | | /// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+ |
64 | | /// |
65 | | /// ``` |
66 | | #[derive(Clone, Debug, Eq, Hash, PartialEq)] |
67 | | #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))] |
68 | | #[non_exhaustive] |
69 | | pub struct Query { |
70 | | /// QNAME |
71 | | pub name: Name, |
72 | | |
73 | | /// QTYPE |
74 | | pub query_type: RecordType, |
75 | | |
76 | | /// QCLASS |
77 | | pub query_class: DNSClass, |
78 | | |
79 | | /// mDNS unicast-response bit set or not |
80 | | #[cfg(feature = "mdns")] |
81 | | pub mdns_unicast_response: bool, |
82 | | } |
83 | | |
84 | | impl Query { |
85 | | /// Return a default query with an empty name and A, IN for the query_type and query_class |
86 | 0 | pub fn root() -> Self { |
87 | 0 | Self::new(Name::root(), RecordType::A) |
88 | 0 | } |
89 | | |
90 | | /// Create a new query from name and type, class defaults to IN |
91 | 0 | pub fn new(name: Name, query_type: RecordType) -> Self { |
92 | 0 | Self { |
93 | 0 | name, |
94 | 0 | query_type, |
95 | 0 | query_class: DNSClass::IN, |
96 | 0 | #[cfg(feature = "mdns")] |
97 | 0 | mdns_unicast_response: false, |
98 | 0 | } |
99 | 0 | } |
100 | | |
101 | | /// replaces name with the new name |
102 | 0 | pub fn set_name(&mut self, name: Name) -> &mut Self { |
103 | 0 | self.name = name; |
104 | 0 | self |
105 | 0 | } |
106 | | |
107 | | /// Specify the RecordType being queried |
108 | 0 | pub fn set_query_type(&mut self, query_type: RecordType) -> &mut Self { |
109 | 0 | self.query_type = query_type; |
110 | 0 | self |
111 | 0 | } |
112 | | |
113 | | /// Specify÷ the DNS class of the Query, almost always IN |
114 | 0 | pub fn set_query_class(&mut self, query_class: DNSClass) -> &mut Self { |
115 | 0 | self.query_class = query_class; |
116 | 0 | self |
117 | 0 | } |
118 | | |
119 | | /// Changes mDNS unicast-response bit |
120 | | /// See [RFC 6762](https://tools.ietf.org/html/rfc6762#section-5.4) |
121 | | #[cfg(feature = "mdns")] |
122 | | pub fn set_mdns_unicast_response(&mut self, flag: bool) -> &mut Self { |
123 | | self.mdns_unicast_response = flag; |
124 | | self |
125 | | } |
126 | | |
127 | | /// Determines if a record is responsive to this |
128 | 0 | pub fn matches_record<T: RecordData>(&self, record: &Record<T>) -> bool { |
129 | 0 | self.name == record.name |
130 | 0 | && (self.query_type == record.record_type() |
131 | 0 | || record.record_type() == RecordType::CNAME) |
132 | 0 | && self.query_class == record.dns_class |
133 | 0 | } |
134 | | } |
135 | | |
136 | | impl BinEncodable for Query { |
137 | 355k | fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> { |
138 | 355k | self.name.emit(encoder)?; |
139 | 355k | self.query_type.emit(encoder)?; |
140 | | |
141 | | #[cfg(not(feature = "mdns"))] |
142 | 355k | self.query_class.emit(encoder)?; |
143 | | |
144 | | #[cfg(feature = "mdns")] |
145 | | { |
146 | | if self.mdns_unicast_response { |
147 | | (u16::from(self.query_class) | MDNS_UNICAST_RESPONSE).emit(encoder)?; |
148 | | } else { |
149 | | self.query_class.emit(encoder)?; |
150 | | } |
151 | | } |
152 | | |
153 | 355k | Ok(()) |
154 | 355k | } |
155 | | } |
156 | | |
157 | | impl<'r> BinDecodable<'r> for Query { |
158 | 1.08M | fn read(decoder: &mut BinDecoder<'r>) -> Result<Self, DecodeError> { |
159 | 1.08M | let name = Name::read(decoder)?; |
160 | 1.08M | let query_type = RecordType::read(decoder)?; |
161 | | |
162 | | #[cfg(feature = "mdns")] |
163 | | let mut mdns_unicast_response = false; |
164 | | |
165 | | #[cfg(not(feature = "mdns"))] |
166 | 1.08M | let query_class = DNSClass::read(decoder)?; |
167 | | |
168 | | #[cfg(feature = "mdns")] |
169 | | let query_class = { |
170 | | let query_class_value = |
171 | | decoder.read_u16()?.unverified(/*DNSClass::from_u16 will verify the value*/); |
172 | | if query_class_value & MDNS_UNICAST_RESPONSE > 0 { |
173 | | mdns_unicast_response = true; |
174 | | DNSClass::from(query_class_value & !MDNS_UNICAST_RESPONSE) |
175 | | } else { |
176 | | DNSClass::from(query_class_value) |
177 | | } |
178 | | }; |
179 | | |
180 | 1.08M | Ok(Self { |
181 | 1.08M | name, |
182 | 1.08M | query_type, |
183 | 1.08M | query_class, |
184 | 1.08M | #[cfg(feature = "mdns")] |
185 | 1.08M | mdns_unicast_response, |
186 | 1.08M | }) |
187 | 1.08M | } |
188 | | } |
189 | | |
190 | | impl Display for Query { |
191 | 0 | fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> { |
192 | | #[cfg(not(feature = "mdns"))] |
193 | | { |
194 | 0 | write!( |
195 | 0 | f, |
196 | 0 | "{name} {class} {ty}", |
197 | | name = self.name, |
198 | | class = self.query_class, |
199 | | ty = self.query_type, |
200 | | ) |
201 | | } |
202 | | |
203 | | #[cfg(feature = "mdns")] |
204 | | { |
205 | | write!( |
206 | | f, |
207 | | "{name} {class} {ty}; mdns_unicast_response: {mdns}", |
208 | | name = self.name, |
209 | | class = self.query_class, |
210 | | ty = self.query_type, |
211 | | mdns = self.mdns_unicast_response |
212 | | ) |
213 | | } |
214 | 0 | } |
215 | | } |
216 | | |
217 | | #[cfg(test)] |
218 | | mod tests { |
219 | | use super::*; |
220 | | |
221 | | #[test] |
222 | | fn test_read_and_emit() { |
223 | | let expect = Query { |
224 | | name: Name::from_ascii("WWW.example.com.").unwrap(), |
225 | | query_type: RecordType::AAAA, |
226 | | query_class: DNSClass::IN, |
227 | | ..Query::root() |
228 | | }; |
229 | | |
230 | | let mut byte_vec: Vec<u8> = Vec::with_capacity(512); |
231 | | { |
232 | | let mut encoder = BinEncoder::new(&mut byte_vec); |
233 | | expect.emit(&mut encoder).unwrap(); |
234 | | } |
235 | | |
236 | | let mut decoder = BinDecoder::new(&byte_vec); |
237 | | let got = Query::read(&mut decoder).unwrap(); |
238 | | assert_eq!(got, expect); |
239 | | } |
240 | | |
241 | | #[cfg(feature = "mdns")] |
242 | | #[test] |
243 | | fn test_mdns_unicast_response_bit_handling() { |
244 | | const QCLASS_OFFSET: usize = 1 /* empty name */ + |
245 | | size_of::<u16>() /* query_type */; |
246 | | |
247 | | let mut query = Query::root(); |
248 | | query.set_mdns_unicast_response(true); |
249 | | |
250 | | let mut vec_bytes: Vec<u8> = Vec::with_capacity(512); |
251 | | { |
252 | | let mut encoder = BinEncoder::new(&mut vec_bytes); |
253 | | query.emit(&mut encoder).unwrap(); |
254 | | |
255 | | let query_class_slice = encoder.slice_of(QCLASS_OFFSET, QCLASS_OFFSET + 2); |
256 | | assert_eq!(query_class_slice, &[0x80, 0x01]); |
257 | | } |
258 | | |
259 | | let mut decoder = BinDecoder::new(&vec_bytes); |
260 | | |
261 | | let got = Query::read(&mut decoder).unwrap(); |
262 | | |
263 | | assert_eq!(got.query_class, DNSClass::IN); |
264 | | assert!(got.mdns_unicast_response); |
265 | | } |
266 | | } |