hickory_proto/op/
query.rs1#[cfg(test)]
20use alloc::vec::Vec;
21use core::fmt::{self, Display, Formatter};
22
23#[cfg(feature = "serde")]
24use serde::{Deserialize, Serialize};
25
26use crate::error::*;
27use crate::rr::dns_class::DNSClass;
28use crate::rr::domain::Name;
29use crate::rr::record_type::RecordType;
30use crate::serialize::binary::*;
31
32#[cfg(feature = "mdns")]
33const MDNS_UNICAST_RESPONSE: u16 = 1 << 15;
40
41#[derive(Clone, Debug, Eq, Hash, PartialEq)]
66#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
67#[non_exhaustive]
68pub struct Query {
69 pub name: Name,
71
72 pub query_type: RecordType,
74
75 pub query_class: DNSClass,
77
78 #[cfg(feature = "mdns")]
80 pub mdns_unicast_response: bool,
81}
82
83impl Default for Query {
84 fn default() -> Self {
86 Self {
87 name: Name::root(),
88 query_type: RecordType::A,
89 query_class: DNSClass::IN,
90 #[cfg(feature = "mdns")]
91 mdns_unicast_response: false,
92 }
93 }
94}
95
96impl Query {
97 pub fn new() -> Self {
99 Self::default()
100 }
101
102 #[allow(clippy::self_named_constructors)]
104 pub fn query(name: Name, query_type: RecordType) -> Self {
105 Self {
106 name,
107 query_type,
108 query_class: DNSClass::IN,
109 #[cfg(feature = "mdns")]
110 mdns_unicast_response: false,
111 }
112 }
113
114 pub fn set_name(&mut self, name: Name) -> &mut Self {
116 self.name = name;
117 self
118 }
119
120 pub fn set_query_type(&mut self, query_type: RecordType) -> &mut Self {
122 self.query_type = query_type;
123 self
124 }
125
126 pub fn set_query_class(&mut self, query_class: DNSClass) -> &mut Self {
128 self.query_class = query_class;
129 self
130 }
131
132 #[cfg(feature = "mdns")]
135 pub fn set_mdns_unicast_response(&mut self, flag: bool) -> &mut Self {
136 self.mdns_unicast_response = flag;
137 self
138 }
139
140 pub fn name(&self) -> &Name {
149 &self.name
150 }
151
152 pub fn query_type(&self) -> RecordType {
159 self.query_type
160 }
161
162 pub fn query_class(&self) -> DNSClass {
167 self.query_class
168 }
169
170 #[cfg(feature = "mdns")]
173 pub fn mdns_unicast_response(&self) -> bool {
174 self.mdns_unicast_response
175 }
176}
177
178impl BinEncodable for Query {
179 fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
180 self.name.emit(encoder)?;
181 self.query_type.emit(encoder)?;
182
183 #[cfg(not(feature = "mdns"))]
184 self.query_class.emit(encoder)?;
185
186 #[cfg(feature = "mdns")]
187 {
188 if self.mdns_unicast_response {
189 encoder.emit_u16(u16::from(self.query_class()) | MDNS_UNICAST_RESPONSE)?;
190 } else {
191 self.query_class.emit(encoder)?;
192 }
193 }
194
195 Ok(())
196 }
197}
198
199impl<'r> BinDecodable<'r> for Query {
200 fn read(decoder: &mut BinDecoder<'r>) -> ProtoResult<Self> {
201 let name = Name::read(decoder)?;
202 let query_type = RecordType::read(decoder)?;
203
204 #[cfg(feature = "mdns")]
205 let mut mdns_unicast_response = false;
206
207 #[cfg(not(feature = "mdns"))]
208 let query_class = DNSClass::read(decoder)?;
209
210 #[cfg(feature = "mdns")]
211 let query_class = {
212 let query_class_value =
213 decoder.read_u16()?.unverified();
214 if query_class_value & MDNS_UNICAST_RESPONSE > 0 {
215 mdns_unicast_response = true;
216 DNSClass::from(query_class_value & !MDNS_UNICAST_RESPONSE)
217 } else {
218 DNSClass::from(query_class_value)
219 }
220 };
221
222 Ok(Self {
223 name,
224 query_type,
225 query_class,
226 #[cfg(feature = "mdns")]
227 mdns_unicast_response,
228 })
229 }
230}
231
232impl Display for Query {
233 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
234 #[cfg(not(feature = "mdns"))]
235 {
236 write!(
237 f,
238 "{name} {class} {ty}",
239 name = self.name,
240 class = self.query_class,
241 ty = self.query_type,
242 )
243 }
244
245 #[cfg(feature = "mdns")]
246 {
247 write!(
248 f,
249 "{name} {class} {ty}; mdns_unicast_response: {mdns}",
250 name = self.name,
251 class = self.query_class,
252 ty = self.query_type,
253 mdns = self.mdns_unicast_response
254 )
255 }
256 }
257}
258
259#[test]
260#[allow(clippy::needless_update)]
261fn test_read_and_emit() {
262 let expect = Query {
263 name: Name::from_ascii("WWW.example.com.").unwrap(),
264 query_type: RecordType::AAAA,
265 query_class: DNSClass::IN,
266 ..Query::default()
267 };
268
269 let mut byte_vec: Vec<u8> = Vec::with_capacity(512);
270 {
271 let mut encoder = BinEncoder::new(&mut byte_vec);
272 expect.emit(&mut encoder).unwrap();
273 }
274
275 let mut decoder = BinDecoder::new(&byte_vec);
276 let got = Query::read(&mut decoder).unwrap();
277 assert_eq!(got, expect);
278}
279
280#[cfg(feature = "mdns")]
281#[test]
282fn test_mdns_unicast_response_bit_handling() {
283 const QCLASS_OFFSET: usize = 1 +
284 core::mem::size_of::<u16>() ;
285
286 let mut query = Query::new();
287 query.set_mdns_unicast_response(true);
288
289 let mut vec_bytes: Vec<u8> = Vec::with_capacity(512);
290 {
291 let mut encoder = BinEncoder::new(&mut vec_bytes);
292 query.emit(&mut encoder).unwrap();
293
294 let query_class_slice = encoder.slice_of(QCLASS_OFFSET, QCLASS_OFFSET + 2);
295 assert_eq!(query_class_slice, &[0x80, 0x01]);
296 }
297
298 let mut decoder = BinDecoder::new(&vec_bytes);
299
300 let got = Query::read(&mut decoder).unwrap();
301
302 assert_eq!(got.query_class(), DNSClass::IN);
303 assert!(got.mdns_unicast_response());
304}