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>) -> Result<Self, DecodeError> {
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]
260fn test_read_and_emit() {
261 let expect = Query {
262 name: Name::from_ascii("WWW.example.com.").unwrap(),
263 query_type: RecordType::AAAA,
264 query_class: DNSClass::IN,
265 ..Query::default()
266 };
267
268 let mut byte_vec: Vec<u8> = Vec::with_capacity(512);
269 {
270 let mut encoder = BinEncoder::new(&mut byte_vec);
271 expect.emit(&mut encoder).unwrap();
272 }
273
274 let mut decoder = BinDecoder::new(&byte_vec);
275 let got = Query::read(&mut decoder).unwrap();
276 assert_eq!(got, expect);
277}
278
279#[cfg(feature = "mdns")]
280#[test]
281fn test_mdns_unicast_response_bit_handling() {
282 const QCLASS_OFFSET: usize = 1 +
283 size_of::<u16>() ;
284
285 let mut query = Query::new();
286 query.set_mdns_unicast_response(true);
287
288 let mut vec_bytes: Vec<u8> = Vec::with_capacity(512);
289 {
290 let mut encoder = BinEncoder::new(&mut vec_bytes);
291 query.emit(&mut encoder).unwrap();
292
293 let query_class_slice = encoder.slice_of(QCLASS_OFFSET, QCLASS_OFFSET + 2);
294 assert_eq!(query_class_slice, &[0x80, 0x01]);
295 }
296
297 let mut decoder = BinDecoder::new(&vec_bytes);
298
299 let got = Query::read(&mut decoder).unwrap();
300
301 assert_eq!(got.query_class(), DNSClass::IN);
302 assert!(got.mdns_unicast_response());
303}