1#![allow(dead_code)]
2
3use bitflags::bitflags;
4use byteorder::{ByteOrder, NetworkEndian};
5use core::iter;
6use core::iter::Iterator;
7
8use super::{Error, Result};
9#[cfg(feature = "proto-ipv4")]
10use crate::wire::Ipv4Address;
11#[cfg(feature = "proto-ipv6")]
12use crate::wire::Ipv6Address;
13
14enum_with_unknown! {
15 pub enum Opcode(u8) {
17 Query = 0x00,
18 Status = 0x01,
19 }
20}
21enum_with_unknown! {
22 pub enum Rcode(u8) {
24 NoError = 0x00,
25 FormErr = 0x01,
26 ServFail = 0x02,
27 NXDomain = 0x03,
28 NotImp = 0x04,
29 Refused = 0x05,
30 YXDomain = 0x06,
31 YXRRSet = 0x07,
32 NXRRSet = 0x08,
33 NotAuth = 0x09,
34 NotZone = 0x0a,
35 }
36}
37
38enum_with_unknown! {
39 pub enum Type(u16) {
41 A = 0x0001,
42 Ns = 0x0002,
43 Cname = 0x0005,
44 Soa = 0x0006,
45 Aaaa = 0x001c,
46 }
47}
48
49bitflags! {
50 #[cfg_attr(feature = "defmt", derive(defmt::Format))]
51 pub struct Flags: u16 {
52 const RESPONSE = 0b1000_0000_0000_0000;
53 const AUTHORITATIVE = 0b0000_0100_0000_0000;
54 const TRUNCATED = 0b0000_0010_0000_0000;
55 const RECURSION_DESIRED = 0b0000_0001_0000_0000;
56 const RECURSION_AVAILABLE = 0b0000_0000_1000_0000;
57 const AUTHENTIC_DATA = 0b0000_0000_0010_0000;
58 const CHECK_DISABLED = 0b0000_0000_0001_0000;
59 }
60}
61
62mod field {
63 use crate::wire::field::*;
64
65 pub const ID: Field = 0..2;
66 pub const FLAGS: Field = 2..4;
67 pub const QDCOUNT: Field = 4..6;
68 pub const ANCOUNT: Field = 6..8;
69 pub const NSCOUNT: Field = 8..10;
70 pub const ARCOUNT: Field = 10..12;
71
72 pub const HEADER_END: usize = 12;
73}
74
75const CLASS_IN: u16 = 1;
77
78#[derive(Debug, PartialEq, Eq)]
80pub struct Packet<T: AsRef<[u8]>> {
81 buffer: T,
82}
83
84impl<T: AsRef<[u8]>> Packet<T> {
85 pub const fn new_unchecked(buffer: T) -> Packet<T> {
87 Packet { buffer }
88 }
89
90 pub fn new_checked(buffer: T) -> Result<Packet<T>> {
95 let packet = Self::new_unchecked(buffer);
96 packet.check_len()?;
97 Ok(packet)
98 }
99
100 pub fn check_len(&self) -> Result<()> {
104 let len = self.buffer.as_ref().len();
105 if len < field::HEADER_END {
106 Err(Error)
107 } else {
108 Ok(())
109 }
110 }
111
112 pub fn into_inner(self) -> T {
114 self.buffer
115 }
116
117 pub fn payload(&self) -> &[u8] {
118 &self.buffer.as_ref()[field::HEADER_END..]
119 }
120
121 pub fn transaction_id(&self) -> u16 {
122 let field = &self.buffer.as_ref()[field::ID];
123 NetworkEndian::read_u16(field)
124 }
125
126 pub fn flags(&self) -> Flags {
127 let field = &self.buffer.as_ref()[field::FLAGS];
128 Flags::from_bits_truncate(NetworkEndian::read_u16(field))
129 }
130
131 pub fn opcode(&self) -> Opcode {
132 let field = &self.buffer.as_ref()[field::FLAGS];
133 let flags = NetworkEndian::read_u16(field);
134 Opcode::from((flags >> 11 & 0xF) as u8)
135 }
136
137 pub fn rcode(&self) -> Rcode {
138 let field = &self.buffer.as_ref()[field::FLAGS];
139 let flags = NetworkEndian::read_u16(field);
140 Rcode::from((flags & 0xF) as u8)
141 }
142
143 pub fn question_count(&self) -> u16 {
144 let field = &self.buffer.as_ref()[field::QDCOUNT];
145 NetworkEndian::read_u16(field)
146 }
147
148 pub fn answer_record_count(&self) -> u16 {
149 let field = &self.buffer.as_ref()[field::ANCOUNT];
150 NetworkEndian::read_u16(field)
151 }
152
153 pub fn authority_record_count(&self) -> u16 {
154 let field = &self.buffer.as_ref()[field::NSCOUNT];
155 NetworkEndian::read_u16(field)
156 }
157
158 pub fn additional_record_count(&self) -> u16 {
159 let field = &self.buffer.as_ref()[field::ARCOUNT];
160 NetworkEndian::read_u16(field)
161 }
162
163 pub fn parse_name<'a>(&'a self, mut bytes: &'a [u8]) -> impl Iterator<Item = Result<&'a [u8]>> {
165 let mut packet = self.buffer.as_ref();
166
167 iter::from_fn(move || {
168 loop {
169 if bytes.is_empty() {
170 return Some(Err(Error));
171 }
172 match bytes[0] {
173 0x00 => return None,
174 x if x & 0xC0 == 0x00 => {
175 let len = (x & 0x3F) as usize;
176 if bytes.len() < 1 + len {
177 return Some(Err(Error));
178 }
179 let label = &bytes[1..1 + len];
180 bytes = &bytes[1 + len..];
181 return Some(Ok(label));
182 }
183 x if x & 0xC0 == 0xC0 => {
184 if bytes.len() < 2 {
185 return Some(Err(Error));
186 }
187 let y = bytes[1];
188 let ptr = ((x & 0x3F) as usize) << 8 | (y as usize);
189 if packet.len() <= ptr {
190 return Some(Err(Error));
191 }
192
193 bytes = &packet[ptr..];
206 packet = &packet[..ptr];
207 }
208 _ => return Some(Err(Error)),
209 }
210 }
211 })
212 }
213}
214
215impl<T: AsRef<[u8]> + AsMut<[u8]>> Packet<T> {
216 pub fn payload_mut(&mut self) -> &mut [u8] {
217 let data = self.buffer.as_mut();
218 &mut data[field::HEADER_END..]
219 }
220
221 pub fn set_transaction_id(&mut self, val: u16) {
222 let field = &mut self.buffer.as_mut()[field::ID];
223 NetworkEndian::write_u16(field, val)
224 }
225
226 pub fn set_flags(&mut self, val: Flags) {
227 let field = &mut self.buffer.as_mut()[field::FLAGS];
228 let mask = Flags::all().bits;
229 let old = NetworkEndian::read_u16(field);
230 NetworkEndian::write_u16(field, (old & !mask) | val.bits());
231 }
232
233 pub fn set_opcode(&mut self, val: Opcode) {
234 let field = &mut self.buffer.as_mut()[field::FLAGS];
235 let mask = 0x3800;
236 let val: u8 = val.into();
237 let val = (val as u16) << 11;
238 let old = NetworkEndian::read_u16(field);
239 NetworkEndian::write_u16(field, (old & !mask) | val);
240 }
241
242 pub fn set_question_count(&mut self, val: u16) {
243 let field = &mut self.buffer.as_mut()[field::QDCOUNT];
244 NetworkEndian::write_u16(field, val)
245 }
246 pub fn set_answer_record_count(&mut self, val: u16) {
247 let field = &mut self.buffer.as_mut()[field::ANCOUNT];
248 NetworkEndian::write_u16(field, val)
249 }
250 pub fn set_authority_record_count(&mut self, val: u16) {
251 let field = &mut self.buffer.as_mut()[field::NSCOUNT];
252 NetworkEndian::write_u16(field, val)
253 }
254 pub fn set_additional_record_count(&mut self, val: u16) {
255 let field = &mut self.buffer.as_mut()[field::ARCOUNT];
256 NetworkEndian::write_u16(field, val)
257 }
258}
259
260fn parse_name_part<'a>(
263 mut bytes: &'a [u8],
264 mut f: impl FnMut(&'a [u8]),
265) -> Result<(&'a [u8], Option<usize>)> {
266 loop {
267 let x = *bytes.first().ok_or(Error)?;
268 bytes = &bytes[1..];
269 match x {
270 0x00 => return Ok((bytes, None)),
271 x if x & 0xC0 == 0x00 => {
272 let len = (x & 0x3F) as usize;
273 let label = bytes.get(..len).ok_or(Error)?;
274 bytes = &bytes[len..];
275 f(label);
276 }
277 x if x & 0xC0 == 0xC0 => {
278 let y = *bytes.first().ok_or(Error)?;
279 bytes = &bytes[1..];
280
281 let ptr = ((x & 0x3F) as usize) << 8 | (y as usize);
282 return Ok((bytes, Some(ptr)));
283 }
284 _ => return Err(Error),
285 }
286 }
287}
288
289#[derive(Debug, PartialEq, Eq)]
290#[cfg_attr(feature = "defmt", derive(defmt::Format))]
291pub struct Question<'a> {
292 pub name: &'a [u8],
293 pub type_: Type,
294}
295
296impl<'a> Question<'a> {
297 pub fn parse(buffer: &'a [u8]) -> Result<(&'a [u8], Question<'a>)> {
298 let (rest, _) = parse_name_part(buffer, |_| ())?;
299 let name = &buffer[..buffer.len() - rest.len()];
300
301 if rest.len() < 4 {
302 return Err(Error);
303 }
304 let type_ = NetworkEndian::read_u16(&rest[0..2]).into();
305 let class = NetworkEndian::read_u16(&rest[2..4]);
306 let rest = &rest[4..];
307
308 if class != CLASS_IN {
309 return Err(Error);
310 }
311
312 Ok((rest, Question { name, type_ }))
313 }
314
315 pub const fn buffer_len(&self) -> usize {
317 self.name.len() + 4
318 }
319
320 pub fn emit(&self, packet: &mut [u8]) {
322 packet[..self.name.len()].copy_from_slice(self.name);
323 let rest = &mut packet[self.name.len()..];
324 NetworkEndian::write_u16(&mut rest[0..2], self.type_.into());
325 NetworkEndian::write_u16(&mut rest[2..4], CLASS_IN);
326 }
327}
328
329#[derive(Debug, PartialEq, Eq)]
330#[cfg_attr(feature = "defmt", derive(defmt::Format))]
331pub struct Record<'a> {
332 pub name: &'a [u8],
333 pub ttl: u32,
334 pub data: RecordData<'a>,
335}
336
337impl<'a> RecordData<'a> {
338 pub fn parse(type_: Type, data: &'a [u8]) -> Result<RecordData<'a>> {
339 match type_ {
340 #[cfg(feature = "proto-ipv4")]
341 Type::A => Ok(RecordData::A(Ipv4Address::from_octets(
342 data.try_into().map_err(|_| Error)?,
343 ))),
344 #[cfg(feature = "proto-ipv6")]
345 Type::Aaaa => Ok(RecordData::Aaaa(Ipv6Address::from_octets(
346 data.try_into().map_err(|_| Error)?,
347 ))),
348 Type::Cname => Ok(RecordData::Cname(data)),
349 x => Ok(RecordData::Other(x, data)),
350 }
351 }
352}
353
354#[derive(Debug, PartialEq, Eq)]
355#[cfg_attr(feature = "defmt", derive(defmt::Format))]
356pub enum RecordData<'a> {
357 #[cfg(feature = "proto-ipv4")]
358 A(Ipv4Address),
359 #[cfg(feature = "proto-ipv6")]
360 Aaaa(Ipv6Address),
361 Cname(&'a [u8]),
362 Other(Type, &'a [u8]),
363}
364
365impl<'a> Record<'a> {
366 pub fn parse(buffer: &'a [u8]) -> Result<(&'a [u8], Record<'a>)> {
367 let (rest, _) = parse_name_part(buffer, |_| ())?;
368 let name = &buffer[..buffer.len() - rest.len()];
369
370 if rest.len() < 10 {
371 return Err(Error);
372 }
373 let type_ = NetworkEndian::read_u16(&rest[0..2]).into();
374 let class = NetworkEndian::read_u16(&rest[2..4]);
375 let ttl = NetworkEndian::read_u32(&rest[4..8]);
376 let len = NetworkEndian::read_u16(&rest[8..10]) as usize;
377 let rest = &rest[10..];
378
379 if class != CLASS_IN {
380 return Err(Error);
381 }
382
383 let data = rest.get(..len).ok_or(Error)?;
384 let rest = &rest[len..];
385
386 Ok((
387 rest,
388 Record {
389 name,
390 ttl,
391 data: RecordData::parse(type_, data)?,
392 },
393 ))
394 }
395}
396
397#[derive(Debug, PartialEq, Eq)]
401#[cfg_attr(feature = "defmt", derive(defmt::Format))]
402pub struct Repr<'a> {
403 pub transaction_id: u16,
404 pub opcode: Opcode,
405 pub flags: Flags,
406 pub question: Question<'a>,
407}
408
409impl<'a> Repr<'a> {
410 pub const fn buffer_len(&self) -> usize {
412 field::HEADER_END + self.question.buffer_len()
413 }
414
415 pub fn emit<T>(&self, packet: &mut Packet<&mut T>)
417 where
418 T: AsRef<[u8]> + AsMut<[u8]> + ?Sized,
419 {
420 packet.set_transaction_id(self.transaction_id);
421 packet.set_flags(self.flags);
422 packet.set_opcode(self.opcode);
423 packet.set_question_count(1);
424 packet.set_answer_record_count(0);
425 packet.set_authority_record_count(0);
426 packet.set_additional_record_count(0);
427 self.question.emit(packet.payload_mut())
428 }
429}
430
431#[cfg(feature = "proto-ipv4")] #[cfg(test)]
433mod test {
434 use super::*;
435 use std::vec::Vec;
436
437 #[test]
438 fn test_parse_name() {
439 let bytes = &[
440 0x78, 0x6c, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77,
441 0x77, 0x77, 0x08, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x03, 0x63, 0x6f,
442 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
443 0x05, 0xf3, 0x00, 0x11, 0x09, 0x73, 0x74, 0x61, 0x72, 0x2d, 0x6d, 0x69, 0x6e, 0x69,
444 0x04, 0x63, 0x31, 0x30, 0x72, 0xc0, 0x10, 0xc0, 0x2e, 0x00, 0x01, 0x00, 0x01, 0x00,
445 0x00, 0x00, 0x05, 0x00, 0x04, 0x1f, 0x0d, 0x53, 0x24,
446 ];
447 let packet = Packet::new_unchecked(bytes);
448
449 let name_vec = |bytes| {
450 let mut v = Vec::new();
451 packet
452 .parse_name(bytes)
453 .try_for_each(|label| label.map(|label| v.push(label)))
454 .map(|_| v)
455 };
456
457 assert_eq!(
459 name_vec(&bytes[0x0c..]),
460 Ok(vec![&b"www"[..], &b"facebook"[..], &b"com"[..]])
461 );
462 assert_eq!(
464 name_vec(&bytes[0x22..]),
465 Ok(vec![&b"www"[..], &b"facebook"[..], &b"com"[..]])
466 );
467 assert_eq!(
469 name_vec(&bytes[0x2e..]),
470 Ok(vec![
471 &b"star-mini"[..],
472 &b"c10r"[..],
473 &b"facebook"[..],
474 &b"com"[..]
475 ])
476 );
477 assert_eq!(
479 name_vec(&bytes[0x3f..]),
480 Ok(vec![
481 &b"star-mini"[..],
482 &b"c10r"[..],
483 &b"facebook"[..],
484 &b"com"[..]
485 ])
486 );
487 }
488
489 struct Parsed<'a> {
490 packet: Packet<&'a [u8]>,
491 questions: Vec<Question<'a>>,
492 answers: Vec<Record<'a>>,
493 authorities: Vec<Record<'a>>,
494 additionals: Vec<Record<'a>>,
495 }
496
497 impl<'a> Parsed<'a> {
498 fn parse(bytes: &'a [u8]) -> Result<Self> {
499 let packet = Packet::new_unchecked(bytes);
500 let mut questions = Vec::new();
501 let mut answers = Vec::new();
502 let mut authorities = Vec::new();
503 let mut additionals = Vec::new();
504
505 let mut payload = &bytes[12..];
506
507 for _ in 0..packet.question_count() {
508 let (p, r) = Question::parse(payload)?;
509 questions.push(r);
510 payload = p;
511 }
512 for _ in 0..packet.answer_record_count() {
513 let (p, r) = Record::parse(payload)?;
514 answers.push(r);
515 payload = p;
516 }
517 for _ in 0..packet.authority_record_count() {
518 let (p, r) = Record::parse(payload)?;
519 authorities.push(r);
520 payload = p;
521 }
522 for _ in 0..packet.additional_record_count() {
523 let (p, r) = Record::parse(payload)?;
524 additionals.push(r);
525 payload = p;
526 }
527
528 assert_eq!(payload.len(), 0);
530
531 Ok(Parsed {
532 packet,
533 questions,
534 answers,
535 authorities,
536 additionals,
537 })
538 }
539 }
540
541 #[test]
542 fn test_parse_request() {
543 let p = Parsed::parse(&[
544 0x51, 0x84, 0x01, 0x20, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x67,
545 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
546 ])
547 .unwrap();
548
549 assert_eq!(p.packet.transaction_id(), 0x5184);
550 assert_eq!(
551 p.packet.flags(),
552 Flags::RECURSION_DESIRED | Flags::AUTHENTIC_DATA
553 );
554 assert_eq!(p.packet.opcode(), Opcode::Query);
555 assert_eq!(p.packet.question_count(), 1);
556 assert_eq!(p.packet.answer_record_count(), 0);
557 assert_eq!(p.packet.authority_record_count(), 0);
558 assert_eq!(p.packet.additional_record_count(), 0);
559
560 assert_eq!(p.questions.len(), 1);
561 assert_eq!(
562 p.questions[0].name,
563 &[
564 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00
565 ]
566 );
567 assert_eq!(p.questions[0].type_, Type::A);
568
569 assert_eq!(p.answers.len(), 0);
570 assert_eq!(p.authorities.len(), 0);
571 assert_eq!(p.additionals.len(), 0);
572 }
573
574 #[test]
575 fn test_parse_response() {
576 let p = Parsed::parse(&[
577 0x51, 0x84, 0x81, 0x80, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x06, 0x67,
578 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01,
579 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xca, 0x00, 0x04, 0xac, 0xd9,
580 0xa8, 0xae,
581 ])
582 .unwrap();
583
584 assert_eq!(p.packet.transaction_id(), 0x5184);
585 assert_eq!(
586 p.packet.flags(),
587 Flags::RESPONSE | Flags::RECURSION_DESIRED | Flags::RECURSION_AVAILABLE
588 );
589 assert_eq!(p.packet.opcode(), Opcode::Query);
590 assert_eq!(p.packet.rcode(), Rcode::NoError);
591 assert_eq!(p.packet.question_count(), 1);
592 assert_eq!(p.packet.answer_record_count(), 1);
593 assert_eq!(p.packet.authority_record_count(), 0);
594 assert_eq!(p.packet.additional_record_count(), 0);
595
596 assert_eq!(
597 p.questions[0].name,
598 &[
599 0x06, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x03, 0x63, 0x6f, 0x6d, 0x00
600 ]
601 );
602 assert_eq!(p.questions[0].type_, Type::A);
603
604 assert_eq!(p.answers[0].name, &[0xc0, 0x0c]);
605 assert_eq!(p.answers[0].ttl, 202);
606 assert_eq!(
607 p.answers[0].data,
608 RecordData::A(Ipv4Address::new(0xac, 0xd9, 0xa8, 0xae))
609 );
610 }
611
612 #[test]
613 fn test_parse_response_multiple_a() {
614 let p = Parsed::parse(&[
615 0x4b, 0x9e, 0x81, 0x80, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x09, 0x72,
616 0x75, 0x73, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00,
617 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x09, 0x00,
618 0x04, 0x0d, 0xe0, 0x77, 0x35, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
619 0x09, 0x00, 0x04, 0x0d, 0xe0, 0x77, 0x28, 0xc0, 0x0c, 0x00, 0x01, 0x00, 0x01, 0x00,
620 0x00, 0x00, 0x09, 0x00, 0x04, 0x0d, 0xe0, 0x77, 0x43, 0xc0, 0x0c, 0x00, 0x01, 0x00,
621 0x01, 0x00, 0x00, 0x00, 0x09, 0x00, 0x04, 0x0d, 0xe0, 0x77, 0x62,
622 ])
623 .unwrap();
624
625 assert_eq!(p.packet.transaction_id(), 0x4b9e);
626 assert_eq!(
627 p.packet.flags(),
628 Flags::RESPONSE | Flags::RECURSION_DESIRED | Flags::RECURSION_AVAILABLE
629 );
630 assert_eq!(p.packet.opcode(), Opcode::Query);
631 assert_eq!(p.packet.rcode(), Rcode::NoError);
632 assert_eq!(p.packet.question_count(), 1);
633 assert_eq!(p.packet.answer_record_count(), 4);
634 assert_eq!(p.packet.authority_record_count(), 0);
635 assert_eq!(p.packet.additional_record_count(), 0);
636
637 assert_eq!(
638 p.questions[0].name,
639 &[
640 0x09, 0x72, 0x75, 0x73, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x03, 0x6f, 0x72, 0x67,
641 0x00
642 ]
643 );
644 assert_eq!(p.questions[0].type_, Type::A);
645
646 assert_eq!(p.answers[0].name, &[0xc0, 0x0c]);
647 assert_eq!(p.answers[0].ttl, 9);
648 assert_eq!(
649 p.answers[0].data,
650 RecordData::A(Ipv4Address::new(0x0d, 0xe0, 0x77, 0x35))
651 );
652
653 assert_eq!(p.answers[1].name, &[0xc0, 0x0c]);
654 assert_eq!(p.answers[1].ttl, 9);
655 assert_eq!(
656 p.answers[1].data,
657 RecordData::A(Ipv4Address::new(0x0d, 0xe0, 0x77, 0x28))
658 );
659
660 assert_eq!(p.answers[2].name, &[0xc0, 0x0c]);
661 assert_eq!(p.answers[2].ttl, 9);
662 assert_eq!(
663 p.answers[2].data,
664 RecordData::A(Ipv4Address::new(0x0d, 0xe0, 0x77, 0x43))
665 );
666
667 assert_eq!(p.answers[3].name, &[0xc0, 0x0c]);
668 assert_eq!(p.answers[3].ttl, 9);
669 assert_eq!(
670 p.answers[3].data,
671 RecordData::A(Ipv4Address::new(0x0d, 0xe0, 0x77, 0x62))
672 );
673 }
674
675 #[test]
676 fn test_parse_response_cname() {
677 let p = Parsed::parse(&[
678 0x78, 0x6c, 0x81, 0x80, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x77,
679 0x77, 0x77, 0x08, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x03, 0x63, 0x6f,
680 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0, 0x0c, 0x00, 0x05, 0x00, 0x01, 0x00, 0x00,
681 0x05, 0xf3, 0x00, 0x11, 0x09, 0x73, 0x74, 0x61, 0x72, 0x2d, 0x6d, 0x69, 0x6e, 0x69,
682 0x04, 0x63, 0x31, 0x30, 0x72, 0xc0, 0x10, 0xc0, 0x2e, 0x00, 0x01, 0x00, 0x01, 0x00,
683 0x00, 0x00, 0x05, 0x00, 0x04, 0x1f, 0x0d, 0x53, 0x24,
684 ])
685 .unwrap();
686
687 assert_eq!(p.packet.transaction_id(), 0x786c);
688 assert_eq!(
689 p.packet.flags(),
690 Flags::RESPONSE | Flags::RECURSION_DESIRED | Flags::RECURSION_AVAILABLE
691 );
692 assert_eq!(p.packet.opcode(), Opcode::Query);
693 assert_eq!(p.packet.rcode(), Rcode::NoError);
694 assert_eq!(p.packet.question_count(), 1);
695 assert_eq!(p.packet.answer_record_count(), 2);
696 assert_eq!(p.packet.authority_record_count(), 0);
697 assert_eq!(p.packet.additional_record_count(), 0);
698
699 assert_eq!(
700 p.questions[0].name,
701 &[
702 0x03, 0x77, 0x77, 0x77, 0x08, 0x66, 0x61, 0x63, 0x65, 0x62, 0x6f, 0x6f, 0x6b, 0x03,
703 0x63, 0x6f, 0x6d, 0x00
704 ]
705 );
706 assert_eq!(p.questions[0].type_, Type::A);
707
708 assert_eq!(p.answers[0].name, &[0xc0, 0x0c]);
710 assert_eq!(p.answers[0].ttl, 1523);
711 assert_eq!(
712 p.answers[0].data,
713 RecordData::Cname(&[
714 0x09, 0x73, 0x74, 0x61, 0x72, 0x2d, 0x6d, 0x69, 0x6e, 0x69, 0x04, 0x63, 0x31, 0x30,
715 0x72, 0xc0, 0x10
716 ])
717 );
718 assert_eq!(p.answers[1].name, &[0xc0, 0x2e]);
720 assert_eq!(p.answers[1].ttl, 5);
721 assert_eq!(
722 p.answers[1].data,
723 RecordData::A(Ipv4Address::new(0x1f, 0x0d, 0x53, 0x24))
724 );
725 }
726
727 #[test]
728 fn test_parse_response_nxdomain() {
729 let p = Parsed::parse(&[
730 0x63, 0xc4, 0x81, 0x83, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x13, 0x61,
731 0x68, 0x61, 0x73, 0x64, 0x67, 0x68, 0x6c, 0x61, 0x6b, 0x73, 0x6a, 0x68, 0x62, 0x61,
732 0x61, 0x73, 0x6c, 0x64, 0x03, 0x63, 0x6f, 0x6d, 0x00, 0x00, 0x01, 0x00, 0x01, 0xc0,
733 0x20, 0x00, 0x06, 0x00, 0x01, 0x00, 0x00, 0x03, 0x83, 0x00, 0x3d, 0x01, 0x61, 0x0c,
734 0x67, 0x74, 0x6c, 0x64, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x03, 0x6e,
735 0x65, 0x74, 0x00, 0x05, 0x6e, 0x73, 0x74, 0x6c, 0x64, 0x0c, 0x76, 0x65, 0x72, 0x69,
736 0x73, 0x69, 0x67, 0x6e, 0x2d, 0x67, 0x72, 0x73, 0xc0, 0x20, 0x5f, 0xce, 0x8b, 0x85,
737 0x00, 0x00, 0x07, 0x08, 0x00, 0x00, 0x03, 0x84, 0x00, 0x09, 0x3a, 0x80, 0x00, 0x01,
738 0x51, 0x80,
739 ])
740 .unwrap();
741
742 assert_eq!(p.packet.transaction_id(), 0x63c4);
743 assert_eq!(
744 p.packet.flags(),
745 Flags::RESPONSE | Flags::RECURSION_DESIRED | Flags::RECURSION_AVAILABLE
746 );
747 assert_eq!(p.packet.opcode(), Opcode::Query);
748 assert_eq!(p.packet.rcode(), Rcode::NXDomain);
749 assert_eq!(p.packet.question_count(), 1);
750 assert_eq!(p.packet.answer_record_count(), 0);
751 assert_eq!(p.packet.authority_record_count(), 1);
752 assert_eq!(p.packet.additional_record_count(), 0);
753
754 assert_eq!(p.questions[0].type_, Type::A);
755
756 assert_eq!(p.authorities[0].name, &[0xc0, 0x20]); assert_eq!(p.authorities[0].ttl, 899);
759 assert!(matches!(
760 p.authorities[0].data,
761 RecordData::Other(Type::Soa, _)
762 ));
763 }
764
765 #[test]
766 fn test_emit() {
767 let name = &[
768 0x09, 0x72, 0x75, 0x73, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x03, 0x6f, 0x72, 0x67,
769 0x00,
770 ];
771
772 let repr = Repr {
773 transaction_id: 0x1234,
774 flags: Flags::RECURSION_DESIRED,
775 opcode: Opcode::Query,
776 question: Question {
777 name,
778 type_: Type::A,
779 },
780 };
781
782 let mut buf = vec![0; repr.buffer_len()];
783 repr.emit(&mut Packet::new_unchecked(&mut buf));
784
785 let want = &[
786 0x12, 0x34, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x72,
787 0x75, 0x73, 0x74, 0x2d, 0x6c, 0x61, 0x6e, 0x67, 0x03, 0x6f, 0x72, 0x67, 0x00, 0x00,
788 0x01, 0x00, 0x01,
789 ];
790 assert_eq!(&buf, want);
791 }
792}