1#![deny(missing_docs)]
22
23use packet_dissector_core::dissector::{DissectResult, Dissector};
24use packet_dissector_core::error::PacketError;
25use packet_dissector_core::field::FieldDescriptor;
26use packet_dissector_core::packet::DissectBuffer;
27use packet_dissector_dns::{DnsDissector, dissect_as_mdns};
28
29pub struct MdnsDissector;
37
38impl Dissector for MdnsDissector {
39 fn name(&self) -> &'static str {
40 "Multicast Domain Name System"
41 }
42
43 fn short_name(&self) -> &'static str {
44 "mDNS"
45 }
46
47 fn field_descriptors(&self) -> &'static [FieldDescriptor] {
48 DnsDissector.field_descriptors()
49 }
50
51 fn dissect<'pkt>(
52 &self,
53 data: &'pkt [u8],
54 buf: &mut DissectBuffer<'pkt>,
55 offset: usize,
56 ) -> Result<DissectResult, PacketError> {
57 dissect_as_mdns(data, buf, offset)
61 }
62}
63
64#[cfg(test)]
65mod tests {
66 use super::*;
67 use packet_dissector_core::field::{Field, FieldValue};
68 use packet_dissector_core::packet::Layer;
69
70 fn mdns_query_bytes() -> Vec<u8> {
86 vec![
87 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, b'_', b'h', b't', b't', b'p', 0x04, b'_', b't', b'c', b'p', 0x05, b'l', b'o', b'c', b'a', b'l', 0x00, 0x00, 0x0c, 0x00, 0x01, ]
101 }
102
103 fn first_question_children<'a, 'pkt>(
106 buf: &'a DissectBuffer<'pkt>,
107 layer: &'a Layer,
108 ) -> &'a [Field<'pkt>] {
109 let questions = buf.field_by_name(layer, "questions").expect("questions");
110 let arr = match &questions.value {
111 FieldValue::Array(r) => r.clone(),
112 other => panic!("expected Array, got {:?}", other),
113 };
114 let first = &buf.nested_fields(&arr)[0];
115 let obj = match &first.value {
116 FieldValue::Object(r) => r.clone(),
117 other => panic!("expected Object, got {:?}", other),
118 };
119 buf.nested_fields(&obj)
120 }
121
122 fn first_rr_children<'a, 'pkt>(
125 buf: &'a DissectBuffer<'pkt>,
126 layer: &'a Layer,
127 section: &str,
128 ) -> &'a [Field<'pkt>] {
129 let arr_field = buf.field_by_name(layer, section).expect("section array");
130 let arr = match &arr_field.value {
131 FieldValue::Array(r) => r.clone(),
132 other => panic!("expected Array, got {:?}", other),
133 };
134 let first = &buf.nested_fields(&arr)[0];
135 let obj = match &first.value {
136 FieldValue::Object(r) => r.clone(),
137 other => panic!("expected Object, got {:?}", other),
138 };
139 buf.nested_fields(&obj)
140 }
141
142 fn child_by_name<'a, 'pkt>(children: &'a [Field<'pkt>], name: &str) -> Option<&'a Field<'pkt>> {
143 children.iter().find(|f| f.name() == name)
144 }
145
146 #[test]
147 fn parse_mdns_query() {
148 let data = mdns_query_bytes();
149 let mut buf = DissectBuffer::new();
150 let result = MdnsDissector.dissect(&data, &mut buf, 0).unwrap();
151
152 assert_eq!(result.bytes_consumed, data.len());
153 assert_eq!(buf.layers().len(), 1);
154
155 let layer = &buf.layers()[0];
156 assert_eq!(layer.name, "mDNS");
157
158 assert_eq!(
160 buf.field_by_name(layer, "id").unwrap().value,
161 FieldValue::U16(0)
162 );
163 assert_eq!(
165 buf.field_by_name(layer, "qr").unwrap().value,
166 FieldValue::U8(0)
167 );
168 assert_eq!(
169 buf.field_by_name(layer, "qdcount").unwrap().value,
170 FieldValue::U16(1)
171 );
172 }
173
174 #[test]
175 fn parse_mdns_response() {
176 let data: &[u8] = &[
179 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, b'm', b'y', b'h', b'o', b's', b't', 0x05, b'l', b'o', b'c', b'a', b'l', 0x00, 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x0a, ];
195
196 let mut buf = DissectBuffer::new();
197 let result = MdnsDissector.dissect(data, &mut buf, 0).unwrap();
198
199 assert_eq!(result.bytes_consumed, data.len());
200 assert_eq!(buf.layers().len(), 1);
201 assert_eq!(buf.layers()[0].name, "mDNS");
202
203 let layer = &buf.layers()[0];
204 assert_eq!(
206 buf.field_by_name(layer, "qr").unwrap().value,
207 FieldValue::U8(1)
208 );
209 assert_eq!(
211 buf.field_by_name(layer, "aa").unwrap().value,
212 FieldValue::U8(1)
213 );
214 assert_eq!(
215 buf.field_by_name(layer, "ancount").unwrap().value,
216 FieldValue::U16(1)
217 );
218 }
219
220 #[test]
221 fn parse_mdns_qu_bit_set() {
222 let data: &[u8] = &[
225 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, b'h', b'o', b's', b't', 0x05, b'l', b'o', b'c', b'a', b'l', 0x00, 0x00,
229 0x01, 0x80, 0x01, ];
232 let mut buf = DissectBuffer::new();
233 MdnsDissector.dissect(data, &mut buf, 0).unwrap();
234 let layer = &buf.layers()[0];
235 let fields = first_question_children(&buf, layer);
236
237 assert_eq!(
239 child_by_name(fields, "qu").map(|f| f.value.clone()),
240 Some(FieldValue::U8(1)),
241 "qu bit should be 1 when top bit of qclass is set"
242 );
243 assert_eq!(
245 child_by_name(fields, "class").map(|f| f.value.clone()),
246 Some(FieldValue::U16(1)),
247 "class should be 0x0001 (IN) after masking off QU bit"
248 );
249 }
250
251 #[test]
252 fn parse_mdns_qm_bit_clear() {
253 let data = mdns_query_bytes();
255 let mut buf = DissectBuffer::new();
256 MdnsDissector.dissect(&data, &mut buf, 0).unwrap();
257 let layer = &buf.layers()[0];
258 let fields = first_question_children(&buf, layer);
259
260 assert_eq!(
261 child_by_name(fields, "qu").map(|f| f.value.clone()),
262 Some(FieldValue::U8(0))
263 );
264 assert_eq!(
265 child_by_name(fields, "class").map(|f| f.value.clone()),
266 Some(FieldValue::U16(1))
267 );
268 }
269
270 #[test]
271 fn parse_mdns_cache_flush_bit_set() {
272 let data: &[u8] = &[
275 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, b'm', b'y', b'h', b'o', b's', b't', 0x05, b'l', b'o', b'c', b'a', b'l', 0x00,
279 0x00, 0x01, 0x80, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x0a, ];
284 let mut buf = DissectBuffer::new();
285 MdnsDissector.dissect(data, &mut buf, 0).unwrap();
286 let layer = &buf.layers()[0];
287 let fields = first_rr_children(&buf, layer, "answers");
288
289 assert_eq!(
291 child_by_name(fields, "cache_flush").map(|f| f.value.clone()),
292 Some(FieldValue::U8(1)),
293 "cache_flush should be 1 when top bit of rrclass is set"
294 );
295 assert_eq!(
296 child_by_name(fields, "class").map(|f| f.value.clone()),
297 Some(FieldValue::U16(1)),
298 "class should be 0x0001 (IN) after masking off cache-flush bit"
299 );
300 }
301
302 #[test]
303 fn parse_mdns_cache_flush_bit_clear() {
304 let data: &[u8] = &[
306 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, b'm', b'y', b'h', b'o', b's', b't', 0x05, b'l', b'o', b'c', b'a', b'l', 0x00,
309 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x78, 0x00, 0x04, 0xc0, 0xa8, 0x01, 0x0a,
312 ];
313 let mut buf = DissectBuffer::new();
314 MdnsDissector.dissect(data, &mut buf, 0).unwrap();
315 let layer = &buf.layers()[0];
316 let fields = first_rr_children(&buf, layer, "answers");
317
318 assert_eq!(
319 child_by_name(fields, "cache_flush").map(|f| f.value.clone()),
320 Some(FieldValue::U8(0))
321 );
322 assert_eq!(
323 child_by_name(fields, "class").map(|f| f.value.clone()),
324 Some(FieldValue::U16(1))
325 );
326 }
327
328 #[test]
329 fn parse_mdns_opt_rrclass_unchanged() {
330 let data: &[u8] = &[
336 0x00, 0x00, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x29, 0x05, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ];
345 let mut buf = DissectBuffer::new();
346 MdnsDissector.dissect(data, &mut buf, 0).unwrap();
347 let layer = &buf.layers()[0];
348 let fields = first_rr_children(&buf, layer, "additionals");
349
350 assert!(
352 child_by_name(fields, "cache_flush").is_none(),
353 "OPT pseudo-RR must not expose a cache_flush bit"
354 );
355 assert_eq!(
357 child_by_name(fields, "udp_payload_size").map(|f| f.value.clone()),
358 Some(FieldValue::U16(1440))
359 );
360 }
361
362 #[test]
363 fn parse_mdns_truncated() {
364 let data: &[u8] = &[0x00, 0x00, 0x00]; let mut buf = DissectBuffer::new();
366 let err = MdnsDissector.dissect(data, &mut buf, 0).unwrap_err();
367 assert!(matches!(
368 err,
369 PacketError::Truncated {
370 expected: 12,
371 actual: 3
372 }
373 ));
374 }
375
376 #[test]
377 fn field_descriptors_match_dns() {
378 assert_eq!(
379 MdnsDissector.field_descriptors().len(),
380 DnsDissector.field_descriptors().len()
381 );
382 }
383
384 #[test]
385 fn name_and_short_name() {
386 assert_eq!(MdnsDissector.name(), "Multicast Domain Name System");
387 assert_eq!(MdnsDissector.short_name(), "mDNS");
388 }
389}