hickory_proto/op/
query.rs1use std::fmt;
20use std::fmt::{Display, Formatter};
21
22use crate::error::*;
23use crate::rr::dns_class::DNSClass;
24use crate::rr::domain::Name;
25use crate::rr::record_type::RecordType;
26use crate::serialize::binary::*;
27
28#[cfg(feature = "mdns")]
29const MDNS_UNICAST_RESPONSE: u16 = 1 << 15;
36
37#[derive(Clone, Debug, Eq, Hash, PartialEq)]
62pub struct Query {
63 name: Name,
64 query_type: RecordType,
65 query_class: DNSClass,
66 #[cfg(feature = "mdns")]
67 mdns_unicast_response: bool,
68}
69
70impl Default for Query {
71 fn default() -> Self {
73 Self {
74 name: Name::new(),
75 query_type: RecordType::A,
76 query_class: DNSClass::IN,
77 #[cfg(feature = "mdns")]
78 mdns_unicast_response: false,
79 }
80 }
81}
82
83impl Query {
84 pub fn new() -> Self {
86 Self::default()
87 }
88
89 #[allow(clippy::self_named_constructors)]
91 pub fn query(name: Name, query_type: RecordType) -> Self {
92 Self {
93 name,
94 query_type,
95 query_class: DNSClass::IN,
96 #[cfg(feature = "mdns")]
97 mdns_unicast_response: false,
98 }
99 }
100
101 pub fn set_name(&mut self, name: Name) -> &mut Self {
103 self.name = name;
104 self
105 }
106
107 pub fn set_query_type(&mut self, query_type: RecordType) -> &mut Self {
109 self.query_type = query_type;
110 self
111 }
112
113 pub fn set_query_class(&mut self, query_class: DNSClass) -> &mut Self {
115 self.query_class = query_class;
116 self
117 }
118
119 #[cfg(feature = "mdns")]
122 #[cfg_attr(docsrs, doc(cfg(feature = "mdns")))]
123 pub fn set_mdns_unicast_response(&mut self, flag: bool) -> &mut Self {
124 self.mdns_unicast_response = flag;
125 self
126 }
127
128 pub fn name(&self) -> &Name {
137 &self.name
138 }
139
140 pub fn query_type(&self) -> RecordType {
147 self.query_type
148 }
149
150 pub fn query_class(&self) -> DNSClass {
155 self.query_class
156 }
157
158 #[cfg(feature = "mdns")]
161 #[cfg_attr(docsrs, doc(cfg(feature = "mdns")))]
162 pub fn mdns_unicast_response(&self) -> bool {
163 self.mdns_unicast_response
164 }
165
166 pub fn into_parts(self) -> QueryParts {
168 self.into()
169 }
170}
171
172#[derive(Clone, Debug, Eq, Hash, PartialEq)]
175pub struct QueryParts {
176 pub name: Name,
178 pub query_type: RecordType,
180 pub query_class: DNSClass,
182 #[cfg(feature = "mdns")]
184 #[cfg_attr(docsrs, doc(cfg(feature = "mdns")))]
185 pub mdns_unicast_response: bool,
186}
187
188impl From<Query> for QueryParts {
189 fn from(q: Query) -> Self {
190 cfg_if::cfg_if! {
191 if #[cfg(feature = "mdns")] {
192 let Query {
193 name,
194 query_type,
195 query_class,
196 mdns_unicast_response,
197 } = q;
198 } else {
199 let Query {
200 name,
201 query_type,
202 query_class,
203 } = q;
204 }
205 }
206
207 Self {
208 name,
209 query_type,
210 query_class,
211 #[cfg(feature = "mdns")]
212 mdns_unicast_response,
213 }
214 }
215}
216
217impl BinEncodable for Query {
218 fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
219 self.name.emit(encoder)?;
220 self.query_type.emit(encoder)?;
221
222 #[cfg(not(feature = "mdns"))]
223 self.query_class.emit(encoder)?;
224
225 #[cfg(feature = "mdns")]
226 {
227 if self.mdns_unicast_response {
228 encoder.emit_u16(u16::from(self.query_class()) | MDNS_UNICAST_RESPONSE)?;
229 } else {
230 self.query_class.emit(encoder)?;
231 }
232 }
233
234 Ok(())
235 }
236}
237
238impl<'r> BinDecodable<'r> for Query {
239 fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
240 let name = Name::read(decoder)?;
241 let query_type = RecordType::read(decoder)?;
242
243 #[cfg(feature = "mdns")]
244 let mut mdns_unicast_response = false;
245
246 #[cfg(not(feature = "mdns"))]
247 let query_class = DNSClass::read(decoder)?;
248
249 #[cfg(feature = "mdns")]
250 let query_class = {
251 let query_class_value =
252 decoder.read_u16()?.unverified();
253 if query_class_value & MDNS_UNICAST_RESPONSE > 0 {
254 mdns_unicast_response = true;
255 DNSClass::from(query_class_value & !MDNS_UNICAST_RESPONSE)
256 } else {
257 DNSClass::from(query_class_value)
258 }
259 };
260
261 Ok(Self {
262 name,
263 query_type,
264 query_class,
265 #[cfg(feature = "mdns")]
266 mdns_unicast_response,
267 })
268 }
269}
270
271impl Display for Query {
272 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
273 #[cfg(not(feature = "mdns"))]
274 {
275 write!(
276 f,
277 "{name} {class} {ty}",
278 name = self.name,
279 class = self.query_class,
280 ty = self.query_type,
281 )
282 }
283
284 #[cfg(feature = "mdns")]
285 {
286 write!(
287 f,
288 "{name} {class} {ty}; mdns_unicast_response: {mdns}",
289 name = self.name,
290 class = self.query_class,
291 ty = self.query_type,
292 mdns = self.mdns_unicast_response
293 )
294 }
295 }
296}
297
298#[test]
299#[allow(clippy::needless_update)]
300fn test_read_and_emit() {
301 let expect = Query {
302 name: Name::from_ascii("WWW.example.com").unwrap(),
303 query_type: RecordType::AAAA,
304 query_class: DNSClass::IN,
305 ..Query::default()
306 };
307
308 let mut byte_vec: Vec<u8> = Vec::with_capacity(512);
309 {
310 let mut encoder = BinEncoder::new(&mut byte_vec);
311 expect.emit(&mut encoder).unwrap();
312 }
313
314 let mut decoder = BinDecoder::new(&byte_vec);
315 let got = Query::read(&mut decoder).unwrap();
316 assert_eq!(got, expect);
317}
318
319#[cfg(feature = "mdns")]
320#[test]
321fn test_mdns_unicast_response_bit_handling() {
322 const QCLASS_OFFSET: usize = 1 +
323 std::mem::size_of::<u16>() ;
324
325 let mut query = Query::new();
326 query.set_mdns_unicast_response(true);
327
328 let mut vec_bytes: Vec<u8> = Vec::with_capacity(512);
329 {
330 let mut encoder = BinEncoder::new(&mut vec_bytes);
331 query.emit(&mut encoder).unwrap();
332
333 let query_class_slice = encoder.slice_of(QCLASS_OFFSET, QCLASS_OFFSET + 2);
334 assert_eq!(query_class_slice, &[0x80, 0x01]);
335 }
336
337 let mut decoder = BinDecoder::new(&vec_bytes);
338
339 let got = Query::read(&mut decoder).unwrap();
340
341 assert_eq!(got.query_class(), DNSClass::IN);
342 assert!(got.mdns_unicast_response());
343}