Skip to main content

mtop_client/dns/
message.rs

1use crate::core::MtopError;
2use crate::dns::bytes::{read_be_u16, read_be_u32, write_be_u16, write_be_u32};
3use crate::dns::core::{RecordClass, RecordType};
4use crate::dns::name::Name;
5use crate::dns::rdata::RecordData;
6use std::fmt;
7use std::io::{Read, Seek, Write};
8
9#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
10#[repr(transparent)]
11pub struct MessageId(u16);
12
13impl MessageId {
14    pub fn random() -> Self {
15        Self(rand::random())
16    }
17
18    pub fn size(&self) -> usize {
19        2
20    }
21}
22
23impl From<u16> for MessageId {
24    fn from(value: u16) -> Self {
25        Self(value)
26    }
27}
28
29impl From<MessageId> for u16 {
30    fn from(value: MessageId) -> Self {
31        value.0
32    }
33}
34
35impl fmt::Display for MessageId {
36    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37        fmt::Display::fmt(&self.0, f)
38    }
39}
40
41#[derive(Debug, Clone, Eq, PartialEq)]
42pub struct Message {
43    id: MessageId,
44    flags: Flags,
45    questions: Vec<Question>,
46    answers: Vec<Record>,
47    authority: Vec<Record>,
48    extra: Vec<Record>,
49}
50
51impl Message {
52    pub fn new(id: MessageId, flags: Flags) -> Self {
53        Self {
54            id,
55            flags,
56            questions: Vec::new(),
57            answers: Vec::new(),
58            authority: Vec::new(),
59            extra: Vec::new(),
60        }
61    }
62
63    pub fn size(&self) -> usize {
64        self.id.size()
65            + self.flags.size()
66            + (2 * 4) // lengths of questions, answers, authority, extra
67            + self.questions.iter().map(Question::size).sum::<usize>()
68            + self.answers.iter().map(Record::size).sum::<usize>()
69            + self.authority.iter().map(Record::size).sum::<usize>()
70            + self.extra.iter().map(Record::size).sum::<usize>()
71    }
72
73    pub fn id(&self) -> MessageId {
74        self.id
75    }
76
77    #[must_use]
78    pub fn set_id(mut self, id: MessageId) -> Self {
79        self.id = id;
80        self
81    }
82
83    pub fn flags(&self) -> Flags {
84        self.flags
85    }
86
87    #[must_use]
88    pub fn set_flags(mut self, flags: Flags) -> Self {
89        self.flags = flags;
90        self
91    }
92
93    pub fn questions(&self) -> &[Question] {
94        &self.questions
95    }
96
97    #[must_use]
98    pub fn add_question(mut self, q: Question) -> Self {
99        self.questions.push(q);
100        self
101    }
102
103    pub fn answers(&self) -> &[Record] {
104        &self.answers
105    }
106
107    #[must_use]
108    pub fn add_answer(mut self, r: Record) -> Self {
109        self.answers.push(r);
110        self
111    }
112
113    pub fn authority(&self) -> &[Record] {
114        &self.authority
115    }
116
117    #[must_use]
118    pub fn add_authority(mut self, r: Record) -> Self {
119        self.authority.push(r);
120        self
121    }
122
123    pub fn extra(&self) -> &[Record] {
124        &self.extra
125    }
126
127    #[must_use]
128    pub fn add_extra(mut self, r: Record) -> Self {
129        self.extra.push(r);
130        self
131    }
132
133    fn header(&self) -> Header {
134        assert!(self.questions.len() < usize::from(u16::MAX));
135        assert!(self.answers.len() < usize::from(u16::MAX));
136        assert!(self.authority.len() < usize::from(u16::MAX));
137        assert!(self.extra.len() < usize::from(u16::MAX));
138
139        Header {
140            id: self.id,
141            flags: self.flags,
142            num_questions: u16::try_from(self.questions.len()).unwrap(),
143            num_answers: u16::try_from(self.answers.len()).unwrap(),
144            num_authority: u16::try_from(self.authority.len()).unwrap(),
145            num_extra: u16::try_from(self.extra.len()).unwrap(),
146        }
147    }
148
149    pub fn write_network_bytes<T>(&self, mut buf: T) -> Result<(), MtopError>
150    where
151        T: Write,
152    {
153        let header = self.header();
154        header.write_network_bytes(&mut buf)?;
155
156        for q in &self.questions {
157            q.write_network_bytes(&mut buf)?;
158        }
159
160        for r in &self.answers {
161            r.write_network_bytes(&mut buf)?;
162        }
163
164        for r in &self.authority {
165            r.write_network_bytes(&mut buf)?;
166        }
167
168        for r in &self.extra {
169            r.write_network_bytes(&mut buf)?;
170        }
171
172        Ok(())
173    }
174
175    pub fn read_network_bytes<T>(mut buf: T) -> Result<Self, MtopError>
176    where
177        T: Read + Seek,
178    {
179        let header = Header::read_network_bytes(&mut buf)?;
180
181        let mut questions = Vec::new();
182        for _ in 0..header.num_questions {
183            questions.push(Question::read_network_bytes(&mut buf)?);
184        }
185
186        let mut answers = Vec::new();
187        for _ in 0..header.num_answers {
188            answers.push(Record::read_network_bytes(&mut buf)?);
189        }
190
191        let mut authority = Vec::new();
192        for _ in 0..header.num_authority {
193            authority.push(Record::read_network_bytes(&mut buf)?);
194        }
195
196        let mut extra = Vec::new();
197        for _ in 0..header.num_extra {
198            extra.push(Record::read_network_bytes(&mut buf)?);
199        }
200
201        Ok(Self {
202            id: header.id,
203            flags: header.flags,
204            questions,
205            answers,
206            authority,
207            extra,
208        })
209    }
210}
211
212#[derive(Debug, Clone, Eq, PartialEq)]
213struct Header {
214    id: MessageId,
215    flags: Flags,
216    num_questions: u16,
217    num_answers: u16,
218    num_authority: u16,
219    num_extra: u16,
220}
221
222impl Header {
223    fn write_network_bytes<T>(&self, mut buf: T) -> Result<(), MtopError>
224    where
225        T: Write,
226    {
227        write_be_u16(&mut buf, self.id.into())?;
228        write_be_u16(&mut buf, self.flags.as_u16())?;
229        write_be_u16(&mut buf, self.num_questions)?;
230        write_be_u16(&mut buf, self.num_answers)?;
231        write_be_u16(&mut buf, self.num_authority)?;
232        write_be_u16(&mut buf, self.num_extra)
233    }
234
235    fn read_network_bytes<T>(mut buf: T) -> Result<Self, MtopError>
236    where
237        T: Read,
238    {
239        let id = MessageId::from(read_be_u16(&mut buf)?);
240        let flags = Flags::try_from(read_be_u16(&mut buf)?)?;
241        let num_questions = read_be_u16(&mut buf)?;
242        let num_answers = read_be_u16(&mut buf)?;
243        let num_authority = read_be_u16(&mut buf)?;
244        let num_extra = read_be_u16(&mut buf)?;
245
246        Ok(Header {
247            id,
248            flags,
249            num_questions,
250            num_answers,
251            num_authority,
252            num_extra,
253        })
254    }
255}
256
257#[derive(Default, Copy, Clone, Eq, PartialEq)]
258#[repr(transparent)]
259pub struct Flags(u16);
260
261impl Flags {
262    const MASK_QR: u16 = 0b1000_0000_0000_0000; // query / response
263    const MASK_OP: u16 = 0b0111_1000_0000_0000; // 4 bits, op code
264    const MASK_AA: u16 = 0b0000_0100_0000_0000; // authoritative answer
265    const MASK_TC: u16 = 0b0000_0010_0000_0000; // truncated
266    const MASK_RD: u16 = 0b0000_0001_0000_0000; // recursion desired
267    const MASK_RA: u16 = 0b0000_0000_1000_0000; // recursion available
268    const MASK_RC: u16 = 0b0000_0000_0000_1111; // 4 bits, response code
269
270    const OFFSET_QR: usize = 15;
271    const OFFSET_OP: usize = 11;
272    const OFFSET_AA: usize = 10;
273    const OFFSET_TC: usize = 9;
274    const OFFSET_RD: usize = 8;
275    const OFFSET_RA: usize = 7;
276    const OFFSET_RC: usize = 0;
277
278    pub fn size(&self) -> usize {
279        2
280    }
281
282    pub fn is_query(&self) -> bool {
283        !(self.0 & Self::MASK_QR) > 0
284    }
285
286    #[must_use]
287    pub fn set_query(self) -> Self {
288        Flags(self.0 & !Self::MASK_QR)
289    }
290
291    pub fn is_response(&self) -> bool {
292        self.0 & Self::MASK_QR > 0
293    }
294
295    #[must_use]
296    pub fn set_response(self) -> Self {
297        Flags(self.0 | Self::MASK_QR)
298    }
299
300    pub fn get_op_code(&self) -> Operation {
301        Operation::try_from((self.0 & Self::MASK_OP) >> Self::OFFSET_OP).unwrap()
302    }
303
304    #[must_use]
305    pub fn set_op_code(self, op: Operation) -> Self {
306        let op = (op as u16) << Self::OFFSET_OP;
307        Flags(self.0 | op)
308    }
309
310    pub fn is_authoritative(&self) -> bool {
311        self.0 & Self::MASK_AA > 0
312    }
313
314    #[must_use]
315    pub fn set_authoritative(self) -> Self {
316        Flags(self.0 | Self::MASK_AA)
317    }
318
319    pub fn is_truncated(&self) -> bool {
320        self.0 & Self::MASK_TC > 0
321    }
322
323    #[must_use]
324    pub fn set_truncated(self) -> Self {
325        Flags(self.0 | Self::MASK_TC)
326    }
327
328    pub fn is_recursion_desired(&self) -> bool {
329        self.0 & Self::MASK_RD > 0
330    }
331
332    #[must_use]
333    pub fn set_recursion_desired(self) -> Self {
334        Flags(self.0 | Self::MASK_RD)
335    }
336
337    pub fn is_recursion_available(&self) -> bool {
338        self.0 & Self::MASK_RA > 0
339    }
340
341    #[must_use]
342    pub fn set_recursion_available(self) -> Self {
343        Flags(self.0 | Self::MASK_RA)
344    }
345
346    pub fn get_response_code(&self) -> ResponseCode {
347        ResponseCode::try_from((self.0 & Self::MASK_RC) >> Self::OFFSET_RC).unwrap()
348    }
349
350    #[must_use]
351    pub fn set_response_code(self, code: ResponseCode) -> Self {
352        let code = (code as u16) << Self::OFFSET_RC;
353        Flags(self.0 | code)
354    }
355
356    pub fn as_u16(&self) -> u16 {
357        self.0
358    }
359}
360
361impl TryFrom<u16> for Flags {
362    type Error = MtopError;
363
364    fn try_from(value: u16) -> Result<Self, Self::Error> {
365        // Ensure that operation and response code are valid values but
366        // otherwise use the value as is. The rest of the fields are on/off
367        // bits so any combination is valid even if they don't make sense.
368        let _op = Operation::try_from((value & Self::MASK_OP) >> Self::OFFSET_OP)?;
369        let _rc = ResponseCode::try_from((value & Self::MASK_RC) >> Self::OFFSET_RC)?;
370        Ok(Flags(value))
371    }
372}
373
374impl fmt::Debug for Flags {
375    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
376        let qr = (self.0 & Self::MASK_QR) >> Self::OFFSET_QR;
377        let op = Operation::try_from((self.0 & Self::MASK_OP) >> Self::OFFSET_OP).unwrap();
378        let aa = (self.0 & Self::MASK_AA) >> Self::OFFSET_AA;
379        let tc = (self.0 & Self::MASK_TC) >> Self::OFFSET_TC;
380        let rd = (self.0 & Self::MASK_RD) >> Self::OFFSET_RD;
381        let ra = (self.0 & Self::MASK_RA) >> Self::OFFSET_RA;
382        let rc = ResponseCode::try_from((self.0 & Self::MASK_RC) >> Self::OFFSET_RC).unwrap();
383
384        write!(
385            f,
386            "Flags{{qr = {qr}, op = {op:?}, aa = {aa}, tc = {tc}, rd = {rd}, ra = {ra}, rc = {rc:?}}}"
387        )
388    }
389}
390
391#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
392#[repr(u16)]
393pub enum ResponseCode {
394    #[default]
395    NoError = 0,
396    FormatError = 1,
397    ServerFailure = 2,
398    NameError = 3,
399    NotImplemented = 4,
400    Refused = 5,
401    YxDomain = 6,
402    YxRrSet = 7,
403    NxRrSet = 8,
404    NotAuth = 9,
405    NotZone = 10,
406    BadVersion = 16,
407}
408
409impl fmt::Display for ResponseCode {
410    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411        fmt::Debug::fmt(self, f)
412    }
413}
414
415impl TryFrom<u16> for ResponseCode {
416    type Error = MtopError;
417
418    fn try_from(value: u16) -> Result<Self, Self::Error> {
419        match value {
420            0 => Ok(ResponseCode::NoError),
421            1 => Ok(ResponseCode::FormatError),
422            2 => Ok(ResponseCode::ServerFailure),
423            3 => Ok(ResponseCode::NameError),
424            4 => Ok(ResponseCode::NotImplemented),
425            5 => Ok(ResponseCode::Refused),
426            6 => Ok(ResponseCode::YxDomain),
427            7 => Ok(ResponseCode::YxRrSet),
428            8 => Ok(ResponseCode::NxRrSet),
429            9 => Ok(ResponseCode::NotAuth),
430            10 => Ok(ResponseCode::NotZone),
431            16 => Ok(ResponseCode::BadVersion),
432            _ => Err(MtopError::runtime(format!(
433                "invalid or unsupported response code {}",
434                value
435            ))),
436        }
437    }
438}
439
440#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
441#[repr(u16)]
442pub enum Operation {
443    #[default]
444    Query = 0,
445    IQuery = 1,
446    Status = 2,
447    Notify = 4,
448    Update = 5,
449}
450
451impl TryFrom<u16> for Operation {
452    type Error = MtopError;
453
454    fn try_from(value: u16) -> Result<Self, Self::Error> {
455        match value {
456            0 => Ok(Operation::Query),
457            1 => Ok(Operation::IQuery),
458            2 => Ok(Operation::Status),
459            4 => Ok(Operation::Notify),
460            5 => Ok(Operation::Update),
461            _ => Err(MtopError::runtime(format!(
462                "invalid or unsupported operation {}",
463                value
464            ))),
465        }
466    }
467}
468
469#[derive(Debug, Clone, Eq, PartialEq)]
470pub struct Question {
471    name: Name,
472    qtype: RecordType,
473    qclass: RecordClass,
474}
475
476impl Question {
477    pub fn new(name: Name, qtype: RecordType) -> Self {
478        Self {
479            name,
480            qtype,
481            qclass: RecordClass::INET,
482        }
483    }
484
485    pub fn size(&self) -> usize {
486        self.name.size() + self.qtype.size() + self.qclass.size()
487    }
488
489    #[must_use]
490    pub fn set_qclass(mut self, qclass: RecordClass) -> Self {
491        self.qclass = qclass;
492        self
493    }
494
495    pub fn name(&self) -> &Name {
496        &self.name
497    }
498
499    pub fn qtype(&self) -> RecordType {
500        self.qtype
501    }
502
503    pub fn qclass(&self) -> RecordClass {
504        self.qclass
505    }
506
507    pub fn write_network_bytes<T>(&self, mut buf: T) -> Result<(), MtopError>
508    where
509        T: Write,
510    {
511        self.name.write_network_bytes(&mut buf)?;
512        write_be_u16(&mut buf, self.qtype.into())?;
513        write_be_u16(&mut buf, self.qclass.into())
514    }
515
516    pub fn read_network_bytes<T>(mut buf: T) -> Result<Self, MtopError>
517    where
518        T: Read + Seek,
519    {
520        let name = Name::read_network_bytes(&mut buf)?;
521        let qtype = RecordType::from(read_be_u16(&mut buf)?);
522        let qclass = RecordClass::from(read_be_u16(&mut buf)?);
523        Ok(Self { name, qtype, qclass })
524    }
525}
526
527#[derive(Debug, Clone, Eq, PartialEq)]
528pub struct Record {
529    name: Name,
530    rtype: RecordType,
531    rclass: RecordClass,
532    ttl: u32,
533    rdata: RecordData,
534}
535
536impl Record {
537    pub fn new(name: Name, rtype: RecordType, rclass: RecordClass, ttl: u32, rdata: RecordData) -> Self {
538        Self {
539            name,
540            rtype,
541            rclass,
542            ttl,
543            rdata,
544        }
545    }
546
547    pub fn size(&self) -> usize {
548        self.name.size()
549            + self.rtype.size()
550            + self.rclass.size()
551            + 4 // ttl
552            + 2 // rdata length
553            + self.rdata.size()
554    }
555
556    pub fn name(&self) -> &Name {
557        &self.name
558    }
559
560    pub fn rtype(&self) -> RecordType {
561        self.rtype
562    }
563
564    pub fn rclass(&self) -> RecordClass {
565        self.rclass
566    }
567
568    pub fn ttl(&self) -> u32 {
569        self.ttl
570    }
571
572    pub fn rdata(&self) -> &RecordData {
573        &self.rdata
574    }
575
576    pub fn write_network_bytes<T>(&self, mut buf: T) -> Result<(), MtopError>
577    where
578        T: Write,
579    {
580        // It shouldn't be possible for rdata to overflow u16 so if we do, that's a bug.
581        let size = self.rdata.size();
582        assert!(
583            u16::try_from(size).is_ok(),
584            "rdata length of {} bytes exceeds max of {} bytes",
585            size,
586            u16::MAX
587        );
588
589        self.name.write_network_bytes(&mut buf)?;
590        write_be_u16(&mut buf, self.rtype.into())?;
591        write_be_u16(&mut buf, self.rclass.into())?;
592        write_be_u32(&mut buf, self.ttl)?;
593        write_be_u16(&mut buf, u16::try_from(size).unwrap())?;
594        self.rdata.write_network_bytes(&mut buf)
595    }
596
597    pub fn read_network_bytes<T>(mut buf: T) -> Result<Self, MtopError>
598    where
599        T: Read + Seek,
600    {
601        let name = Name::read_network_bytes(&mut buf)?;
602        let rtype = RecordType::from(read_be_u16(&mut buf)?);
603        let rclass = RecordClass::from(read_be_u16(&mut buf)?);
604        let ttl = read_be_u32(&mut buf)?;
605        let rdata_len = read_be_u16(&mut buf)?;
606        let rdata = RecordData::read_network_bytes(rtype, rdata_len, &mut buf)?;
607
608        Ok(Self {
609            name,
610            rtype,
611            rclass,
612            ttl,
613            rdata,
614        })
615    }
616}
617
618#[cfg(test)]
619mod test {
620    use super::{Flags, Header, Message, MessageId, Operation, Question, Record, ResponseCode};
621    use crate::dns::core::{RecordClass, RecordType};
622    use crate::dns::name::Name;
623    use crate::dns::rdata::{RecordData, RecordDataA, RecordDataSRV};
624    use std::io::Cursor;
625    use std::net::Ipv4Addr;
626    use std::str::FromStr;
627
628    #[rustfmt::skip]
629    #[test]
630    fn test_message_write_network_bytes() {
631        let question = Question::new(Name::from_str("_cache._tcp.example.com.").unwrap(), RecordType::SRV);
632        let answer_rdata = RecordData::SRV(RecordDataSRV::new(
633            10,
634            10,
635            11211,
636            Name::from_str("cache01.example.com.").unwrap(),
637        ));
638        let answer = Record::new(
639            Name::from_str("_cache._tcp.example.com.").unwrap(),
640            RecordType::SRV,
641            RecordClass::INET,
642            300,
643            answer_rdata,
644        );
645        let extra_rdata = RecordData::A(RecordDataA::new(Ipv4Addr::new(127, 0, 0, 100)));
646        let extra = Record::new(
647            Name::from_str("cache01.example.com.").unwrap(),
648            RecordType::A,
649            RecordClass::INET,
650            60,
651            extra_rdata,
652        );
653
654        let message = Message::new(
655            MessageId::from(65333), Flags::default()
656                .set_response()
657                .set_op_code(Operation::Query)
658                .set_response_code(ResponseCode::NoError))
659            .add_question(question)
660            .add_answer(answer)
661            .add_extra(extra);
662
663        let mut cur = Cursor::new(Vec::new());
664        message.write_network_bytes(&mut cur).unwrap();
665        let buf = cur.into_inner();
666
667        assert_eq!(
668            vec![
669                // Header
670                255, 53, // ID
671                128, 0,  // Flags: response, query op, no error
672                0, 1,    // questions
673                0, 1,    // answers
674                0, 0,    // authority
675                0, 1,    // extra
676
677                // Question
678                6,                                // length
679                95, 99, 97, 99, 104, 101,         // "_cache"
680                4,                                // length
681                95, 116, 99, 112,                 // "_tcp"
682                7,                                // length
683                101, 120, 97, 109, 112, 108, 101, // "example"
684                3,                                // length
685                99, 111, 109,                     // "com"
686                0,                                // root
687                0, 33,                            // record type, SRV
688                0, 1,                             // record class, INET
689
690                // Answer
691                6,                                // length
692                95, 99, 97, 99, 104, 101,         // "_cache"
693                4,                                // length
694                95, 116, 99, 112,                 // "_tcp"
695                7,                                // length
696                101, 120, 97, 109, 112, 108, 101, // "example"
697                3,                                // length
698                99, 111, 109,                     // "com"
699                0,                                // root
700                0, 33,                            // record type, SRV
701                0, 1,                             // record class, INET
702                0, 0, 1, 44,                      // TTL
703                0, 27,                            // rdata size
704                0, 10,                            // priority
705                0, 10,                            // weight
706                43, 203,                          // port
707                7,                                // length
708                99, 97, 99, 104, 101, 48, 49,     // "cache01"
709                7,                                // length
710                101, 120, 97, 109, 112, 108, 101, // "example"
711                3,                                // length
712                99, 111, 109,                     // "com"
713                0,                                // root
714
715                // Extra
716                7,                                // length
717                99, 97, 99, 104, 101, 48, 49,     // "cache01"
718                7,                                // length
719                101, 120, 97, 109, 112, 108, 101, // "example"
720                3,                                // length
721                99, 111, 109,                     // "com"
722                0,                                // root
723                0, 1,                             // record type, A
724                0, 1,                             // record class, INET
725                0, 0, 0, 60,                      // TTL
726                0, 4,                             // rdata size
727                127, 0, 0, 100,                   // rdata, A address
728            ],
729            buf,
730        );
731    }
732
733    #[rustfmt::skip]
734    #[test]
735    fn test_message_read_network_bytes() {
736        let cur = Cursor::new(vec![
737            // Header
738            255, 53, // ID
739            128, 0,  // Flags: response, query op, no error
740            0, 1,    // questions
741            0, 1,    // answers
742            0, 0,    // authority
743            0, 1,    // extra
744
745            // Question
746            6,                                // length
747            95, 99, 97, 99, 104, 101,         // "_cache"
748            4,                                // length
749            95, 116, 99, 112,                 // "_tcp"
750            7,                                // length
751            101, 120, 97, 109, 112, 108, 101, // "example"
752            3,                                // length
753            99, 111, 109,                     // "com"
754            0,                                // root
755            0, 33,                            // record type, SRV
756            0, 1,                             // record class, INET
757
758            // Answer
759            6,                                // length
760            95, 99, 97, 99, 104, 101,         // "_cache"
761            4,                                // length
762            95, 116, 99, 112,                 // "_tcp"
763            7,                                // length
764            101, 120, 97, 109, 112, 108, 101, // "example"
765            3,                                // length
766            99, 111, 109,                     // "com"
767            0,                                // root
768            0, 33,                            // record type, SRV
769            0, 1,                             // record class, INET
770            0, 0, 1, 44,                      // TTL
771            0, 27,                            // rdata size
772            0, 10,                            // priority
773            0, 10,                            // weight
774            43, 203,                          // port
775            7,                                // length
776            99, 97, 99, 104, 101, 48, 49,     // "cache01"
777            7,                                // length
778            101, 120, 97, 109, 112, 108, 101, // "example"
779            3,                                // length
780            99, 111, 109,                     // "com"
781            0,                                // root
782
783            // Extra
784            7,                                // length
785            99, 97, 99, 104, 101, 48, 49,     // "cache01"
786            7,                                // length
787            101, 120, 97, 109, 112, 108, 101, // "example"
788            3,                                // length
789            99, 111, 109,                     // "com"
790            0,                                // root
791            0, 1,                             // record type, A
792            0, 1,                             // record class, INET
793            0, 0, 0, 60,                      // TTL
794            0, 4,                             // rdata size
795            127, 0, 0, 100,                   // rdata, A address
796        ]);
797
798        let message = Message::read_network_bytes(cur).unwrap();
799        assert_eq!(MessageId::from(65333), message.id());
800        assert_eq!(
801            Flags::default()
802                .set_response()
803                .set_response_code(ResponseCode::NoError)
804                .set_op_code(Operation::Query),
805            message.flags()
806        );
807
808        let questions = message.questions();
809        assert_eq!("_cache._tcp.example.com.", questions[0].name().to_string());
810        assert_eq!(RecordType::SRV, questions[0].qtype());
811        assert_eq!(RecordClass::INET, questions[0].qclass());
812
813        let answers = message.answers();
814        assert_eq!("_cache._tcp.example.com.", answers[0].name().to_string());
815        assert_eq!(RecordType::SRV, answers[0].rtype());
816        assert_eq!(RecordClass::INET, answers[0].rclass());
817        assert_eq!(300, answers[0].ttl());
818
819        if let RecordData::SRV(rd) = answers[0].rdata() {
820            assert_eq!(10, rd.weight());
821            assert_eq!(10, rd.priority());
822            assert_eq!(11211, rd.port());
823            assert_eq!("cache01.example.com.", rd.target().to_string());
824        } else {
825            panic!("unexpected record data type: {:?}", answers[0].rdata());
826        }
827
828        let extra = message.extra();
829        assert_eq!("cache01.example.com.", extra[0].name().to_string());
830        assert_eq!(RecordType::A, extra[0].rtype());
831        assert_eq!(RecordClass::INET, extra[0].rclass());
832        assert_eq!(60, extra[0].ttl());
833
834        if let RecordData::A(rd) = extra[0].rdata() {
835            assert_eq!(Ipv4Addr::new(127, 0, 0, 100), rd.addr());
836        } else {
837            panic!("unexpected record data type: {:?}", extra[0].rdata());
838        }
839    }
840
841    #[rustfmt::skip]
842    #[test]
843    fn test_header_write_network_bytes() {
844        let h = Header {
845            id: MessageId::from(65333),
846            flags: Flags::default().set_recursion_desired(),
847            num_questions: 1,
848            num_answers: 2,
849            num_authority: 3,
850            num_extra: 4,
851        };
852        let mut cur = Cursor::new(Vec::new());
853        h.write_network_bytes(&mut cur).unwrap();
854        let buf = cur.into_inner();
855
856        assert_eq!(
857            vec![
858                255, 53, // ID
859                1, 0,    // Flags, recursion desired
860                0, 1,    // questions
861                0, 2,    // answers
862                0, 3,    // authority
863                0, 4,    // extra
864            ],
865            buf,
866        );
867    }
868
869    #[rustfmt::skip]
870    #[test]
871    fn test_header_read_network_bytes() {
872        let cur = Cursor::new(vec![
873            255, 53, // ID
874            1, 0,    // Flags, recursion desired
875            0, 1,    // questions
876            0, 2,    // answers,
877            0, 3,    // authority
878            0, 4,    // extra
879        ]);
880
881        let h = Header::read_network_bytes(cur).unwrap();
882        assert_eq!(MessageId::from(65333), h.id);
883        assert_eq!(Flags::default().set_recursion_desired(), h.flags);
884        assert_eq!(1, h.num_questions);
885        assert_eq!(2, h.num_answers);
886        assert_eq!(3, h.num_authority);
887        assert_eq!(4, h.num_extra);
888    }
889
890    #[test]
891    fn test_flags() {
892        let f = Flags::default().set_query();
893        assert!(f.is_query());
894
895        let f = Flags::default().set_response();
896        assert!(f.is_response());
897
898        let f = Flags::default().set_op_code(Operation::Notify);
899        assert_eq!(Operation::Notify, f.get_op_code());
900
901        let f = Flags::default().set_authoritative();
902        assert!(f.is_authoritative());
903
904        let f = Flags::default().set_truncated();
905        assert!(f.is_truncated());
906
907        let f = Flags::default().set_recursion_desired();
908        assert!(f.is_recursion_desired());
909
910        let f = Flags::default().set_recursion_available();
911        assert!(f.is_recursion_available());
912
913        let f = Flags::default().set_response_code(ResponseCode::ServerFailure);
914        assert_eq!(ResponseCode::ServerFailure, f.get_response_code());
915
916        let f = Flags::default()
917            .set_query()
918            .set_recursion_desired()
919            .set_op_code(Operation::Query);
920        assert!(f.is_query());
921        assert!(f.is_recursion_desired());
922        assert_eq!(Operation::Query, f.get_op_code());
923    }
924
925    #[rustfmt::skip]
926    #[test]
927    fn test_question_write_network_bytes() {
928        let q = Question::new(Name::from_str("example.com.").unwrap(), RecordType::AAAA);
929        let size = q.size();
930        let mut cur = Cursor::new(Vec::new());
931        q.write_network_bytes(&mut cur).unwrap();
932        let buf = cur.into_inner();
933
934        assert_eq!(
935            vec![
936                7,                                // length
937                101, 120, 97, 109, 112, 108, 101, // "example"
938                3,                                // length
939                99, 111, 109,                     // "com"
940                0,                                // root
941                0, 28,                            // AAAA record
942                0, 1,                             // INET class
943            ],
944            buf,
945        );
946        assert_eq!(size, buf.len());
947    }
948
949    #[rustfmt::skip]
950    #[test]
951    fn test_question_read_network_bytes() {
952        let cur = Cursor::new(vec![
953            7,                                // length
954            101, 120, 97, 109, 112, 108, 101, // "example"
955            3,                                // length
956            99, 111, 109,                     // "com"
957            0,                                // root
958            0, 28,                            // AAAA record
959            0, 1,                             // INET class
960        ]);
961
962        let size = cur.get_ref().len();
963        let q = Question::read_network_bytes(cur).unwrap();
964        assert_eq!("example.com.", q.name().to_string());
965        assert_eq!(RecordType::AAAA, q.qtype());
966        assert_eq!(RecordClass::INET, q.qclass());
967        assert_eq!(size, q.size());
968    }
969
970    #[rustfmt::skip]
971    #[test]
972    fn test_record_write_network_bytes() {
973        let rr = Record::new(
974            Name::from_str("www.example.com.").unwrap(),
975            RecordType::A,
976            RecordClass::INET,
977            300,
978            RecordData::A(RecordDataA::new(Ipv4Addr::new(127, 0, 0, 100))),
979        );
980        let size = rr.size();
981        let mut cur = Cursor::new(Vec::new());
982        rr.write_network_bytes(&mut cur).unwrap();
983        let buf = cur.into_inner();
984
985        assert_eq!(
986            vec![
987                3,                                // length
988                119, 119, 119,                    // "www"
989                7,                                // length
990                101, 120, 97, 109, 112, 108, 101, // "example"
991                3,                                // length
992                99, 111, 109,                     // "com"
993                0,                                // root
994                0, 1,                             // record type, A
995                0, 1,                             // record class, INET
996                0, 0, 1, 44,                      // TTL
997                0, 4,                             // rdata size
998                127, 0, 0, 100,                   // rdata, A address
999            ],
1000            buf,
1001        );
1002        assert_eq!(size, buf.len());
1003    }
1004
1005    #[rustfmt::skip]
1006    #[test]
1007    fn test_record_read_network_bytes() {
1008        let cur = Cursor::new(vec![
1009            3,                                // length
1010            119, 119, 119,                    // "www"
1011            7,                                // length
1012            101, 120, 97, 109, 112, 108, 101, // "example"
1013            3,                                // length
1014            99, 111, 109,                     // "com"
1015            0,                                // root
1016            0, 1,                             // record type, A
1017            0, 1,                             // record class, INET
1018            0, 0, 1, 44,                      // TTL
1019            0, 4,                             // rdata size
1020            127, 0, 0, 100,                   // rdata, A address
1021        ]);
1022
1023        let size = cur.get_ref().len();
1024        let rr = Record::read_network_bytes(cur).unwrap();
1025        assert_eq!("www.example.com.", rr.name().to_string());
1026        assert_eq!(RecordType::A, rr.rtype());
1027        assert_eq!(RecordClass::INET, rr.rclass());
1028        assert_eq!(300, rr.ttl());
1029        if let RecordData::A(rd) = rr.rdata() {
1030            assert_eq!(Ipv4Addr::new(127, 0, 0, 100), rd.addr());
1031        } else {
1032            panic!("unexpected rdata type: {:?}", rr.rdata());
1033        }
1034        assert_eq!(size, rr.size());
1035    }
1036}