Skip to main content

smoltcp/wire/
dns.rs

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    /// DNS OpCodes
16    pub enum Opcode(u8) {
17        Query  = 0x00,
18        Status = 0x01,
19    }
20}
21enum_with_unknown! {
22    /// DNS OpCodes
23    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    /// DNS record types
40    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
75// DNS class IN (Internet)
76const CLASS_IN: u16 = 1;
77
78/// A read/write wrapper around a DNS packet buffer.
79#[derive(Debug, PartialEq, Eq)]
80pub struct Packet<T: AsRef<[u8]>> {
81    buffer: T,
82}
83
84impl<T: AsRef<[u8]>> Packet<T> {
85    /// Imbue a raw octet buffer with DNS packet structure.
86    pub const fn new_unchecked(buffer: T) -> Packet<T> {
87        Packet { buffer }
88    }
89
90    /// Shorthand for a combination of [new_unchecked] and [check_len].
91    ///
92    /// [new_unchecked]: #method.new_unchecked
93    /// [check_len]: #method.check_len
94    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    /// Ensure that no accessor method will panic if called.
101    /// Returns `Err(Error)` if the buffer is smaller than
102    /// the header length.
103    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    /// Consume the packet, returning the underlying buffer.
113    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    /// Parse part of a name from `bytes`, following pointers if any.
164    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                        // RFC1035 says: "In this scheme, an entire domain name or a list of labels at
194                        //      the end of a domain name is replaced with a pointer to a ***prior*** occurrence
195                        //      of the same name.
196                        //
197                        // Is it unclear if this means the pointer MUST point backwards in the packet or not. Either way,
198                        // pointers that don't point backwards are never seen in the fields, so use this to check that
199                        // there are no pointer loops.
200
201                        // Split packet into parts before and after `ptr`.
202                        // parse the part after, keep only the part before in `packet`. This ensure we never
203                        // parse the same byte twice, therefore eliminating pointer loops.
204
205                        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
260/// Parse part of a name from `bytes`, not following pointers.
261/// Returns the unused part of `bytes`, and the pointer offset if the sequence ends with a pointer.
262fn 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    /// Return the length of a packet that will be emitted from this high-level representation.
316    pub const fn buffer_len(&self) -> usize {
317        self.name.len() + 4
318    }
319
320    /// Emit a high-level representation into a DNS packet.
321    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/// High-level DNS packet representation.
398///
399/// Currently only supports query packets.
400#[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    /// Return the length of a packet that will be emitted from this high-level representation.
411    pub const fn buffer_len(&self) -> usize {
412        field::HEADER_END + self.question.buffer_len()
413    }
414
415    /// Emit a high-level representation into a DNS packet.
416    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")] // tests assume ipv4
432#[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!(parse_name_len(bytes, 0x0c), Ok(18));
458        assert_eq!(
459            name_vec(&bytes[0x0c..]),
460            Ok(vec![&b"www"[..], &b"facebook"[..], &b"com"[..]])
461        );
462        //assert_eq!(parse_name_len(bytes, 0x22), Ok(2));
463        assert_eq!(
464            name_vec(&bytes[0x22..]),
465            Ok(vec![&b"www"[..], &b"facebook"[..], &b"com"[..]])
466        );
467        //assert_eq!(parse_name_len(bytes, 0x2e), Ok(17));
468        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!(parse_name_len(bytes, 0x3f), Ok(2));
478        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            // Check that there are no bytes left
529            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        // cname
709        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        // a
719        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        // SOA authority
757        assert_eq!(p.authorities[0].name, &[0xc0, 0x20]); // com.
758        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}