xref: /webrtc/mdns/src/message/message_test.rs (revision 7ceeeeb0)
1 use super::builder::*;
2 use super::header::*;
3 use super::name::*;
4 use super::parser::*;
5 use super::question::*;
6 use super::resource::{
7     a::*, aaaa::*, cname::*, mx::*, ns::*, opt::*, ptr::*, soa::*, srv::*, txt::*, *,
8 };
9 use super::*;
10 use crate::error::*;
11 
12 use std::collections::HashMap;
13 
14 fn small_test_msg() -> Result<Message> {
15     let name = Name::new("example.com.")?;
16     Ok(Message {
17         header: Header {
18             response: true,
19             authoritative: true,
20             ..Default::default()
21         },
22         questions: vec![Question {
23             name: name.clone(),
24             typ: DnsType::A,
25             class: DNSCLASS_INET,
26         }],
27         answers: vec![Resource {
28             header: ResourceHeader {
29                 name: name.clone(),
30                 typ: DnsType::A,
31                 class: DNSCLASS_INET,
32                 ..Default::default()
33             },
34             body: Some(Box::new(AResource { a: [127, 0, 0, 1] })),
35         }],
36         authorities: vec![Resource {
37             header: ResourceHeader {
38                 name: name.clone(),
39                 typ: DnsType::A,
40                 class: DNSCLASS_INET,
41                 ..Default::default()
42             },
43             body: Some(Box::new(AResource { a: [127, 0, 0, 1] })),
44         }],
45         additionals: vec![Resource {
46             header: ResourceHeader {
47                 name,
48                 typ: DnsType::A,
49                 class: DNSCLASS_INET,
50                 ..Default::default()
51             },
52             body: Some(Box::new(AResource { a: [127, 0, 0, 1] })),
53         }],
54     })
55 }
56 
57 fn large_test_msg() -> Result<Message> {
58     let name = Name::new("foo.bar.example.com.")?;
59     Ok(Message {
60         header: Header {
61             response: true,
62             authoritative: true,
63             ..Default::default()
64         },
65         questions: vec![Question {
66             name: name.clone(),
67             typ: DnsType::A,
68             class: DNSCLASS_INET,
69         }],
70         answers: vec![
71             Resource {
72                 header: ResourceHeader {
73                     name: name.clone(),
74                     typ: DnsType::A,
75                     class: DNSCLASS_INET,
76                     ..Default::default()
77                 },
78                 body: Some(Box::new(AResource { a: [127, 0, 0, 1] })),
79             },
80             Resource {
81                 header: ResourceHeader {
82                     name: name.clone(),
83                     typ: DnsType::A,
84                     class: DNSCLASS_INET,
85                     ..Default::default()
86                 },
87                 body: Some(Box::new(AResource { a: [127, 0, 0, 2] })),
88             },
89             Resource {
90                 header: ResourceHeader {
91                     name: name.clone(),
92                     typ: DnsType::Aaaa,
93                     class: DNSCLASS_INET,
94                     ..Default::default()
95                 },
96                 body: Some(Box::new(AaaaResource {
97                     aaaa: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
98                 })),
99             },
100             Resource {
101                 header: ResourceHeader {
102                     name: name.clone(),
103                     typ: DnsType::Cname,
104                     class: DNSCLASS_INET,
105                     ..Default::default()
106                 },
107                 body: Some(Box::new(CnameResource {
108                     cname: Name::new("alias.example.com.")?,
109                 })),
110             },
111             Resource {
112                 header: ResourceHeader {
113                     name: name.clone(),
114                     typ: DnsType::Soa,
115                     class: DNSCLASS_INET,
116                     ..Default::default()
117                 },
118                 body: Some(Box::new(SoaResource {
119                     ns: Name::new("ns1.example.com.")?,
120                     mbox: Name::new("mb.example.com.")?,
121                     serial: 1,
122                     refresh: 2,
123                     retry: 3,
124                     expire: 4,
125                     min_ttl: 5,
126                 })),
127             },
128             Resource {
129                 header: ResourceHeader {
130                     name: name.clone(),
131                     typ: DnsType::Ptr,
132                     class: DNSCLASS_INET,
133                     ..Default::default()
134                 },
135                 body: Some(Box::new(PtrResource {
136                     ptr: Name::new("ptr.example.com.")?,
137                 })),
138             },
139             Resource {
140                 header: ResourceHeader {
141                     name: name.clone(),
142                     typ: DnsType::Mx,
143                     class: DNSCLASS_INET,
144                     ..Default::default()
145                 },
146                 body: Some(Box::new(MxResource {
147                     pref: 7,
148                     mx: Name::new("mx.example.com.")?,
149                 })),
150             },
151             Resource {
152                 header: ResourceHeader {
153                     name: name.clone(),
154                     typ: DnsType::Srv,
155                     class: DNSCLASS_INET,
156                     ..Default::default()
157                 },
158                 body: Some(Box::new(SrvResource {
159                     priority: 8,
160                     weight: 9,
161                     port: 11,
162                     target: Name::new("srv.example.com.")?,
163                 })),
164             },
165         ],
166         authorities: vec![
167             Resource {
168                 header: ResourceHeader {
169                     name: name.clone(),
170                     typ: DnsType::Ns,
171                     class: DNSCLASS_INET,
172                     ..Default::default()
173                 },
174                 body: Some(Box::new(NsResource {
175                     ns: Name::new("ns1.example.com.")?,
176                 })),
177             },
178             Resource {
179                 header: ResourceHeader {
180                     name: name.clone(),
181                     typ: DnsType::Ns,
182                     class: DNSCLASS_INET,
183                     ..Default::default()
184                 },
185                 body: Some(Box::new(NsResource {
186                     ns: Name::new("ns2.example.com.")?,
187                 })),
188             },
189         ],
190         additionals: vec![
191             Resource {
192                 header: ResourceHeader {
193                     name: name.clone(),
194                     typ: DnsType::Txt,
195                     class: DNSCLASS_INET,
196                     ..Default::default()
197                 },
198                 body: Some(Box::new(TxtResource {
199                     txt: vec!["So Long, and Thanks for All the Fish".into()],
200                 })),
201             },
202             Resource {
203                 header: ResourceHeader {
204                     name,
205                     typ: DnsType::Txt,
206                     class: DNSCLASS_INET,
207                     ..Default::default()
208                 },
209                 body: Some(Box::new(TxtResource {
210                     txt: vec!["Hamster Huey and the Gooey Kablooie".into()],
211                 })),
212             },
213             Resource {
214                 header: must_edns0_resource_header(4096, 0xfe0 | (RCode::Success as u32), false)?,
215                 body: Some(Box::new(OptResource {
216                     options: vec![DnsOption {
217                         code: 10, // see RFC 7873
218                         data: vec![0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef],
219                     }],
220                 })),
221             },
222         ],
223     })
224 }
225 
226 fn must_edns0_resource_header(l: u16, extrc: u32, d: bool) -> Result<ResourceHeader> {
227     let mut h = ResourceHeader {
228         class: DNSCLASS_INET,
229         ..Default::default()
230     };
231     h.set_edns0(l, extrc, d)?;
232     Ok(h)
233 }
234 
235 #[test]
236 fn test_name_string() -> Result<()> {
237     let want = "foo";
238     let name = Name::new(want)?;
239     assert_eq!(name.to_string(), want);
240 
241     Ok(())
242 }
243 
244 #[test]
245 fn test_question_pack_unpack() -> Result<()> {
246     let want = Question {
247         name: Name::new(".")?,
248         typ: DnsType::A,
249         class: DNSCLASS_INET,
250     };
251     let buf = want.pack(vec![0; 1], &mut Some(HashMap::new()), 1)?;
252     let mut p = Parser {
253         msg: &buf,
254         header: HeaderInternal {
255             questions: 1,
256             ..Default::default()
257         },
258         section: Section::Questions,
259         off: 1,
260         ..Default::default()
261     };
262 
263     let got = p.question()?;
264     assert_eq!(
265         p.off,
266         buf.len(),
267         "unpacked different amount than packed: got = {}, want = {}",
268         p.off,
269         buf.len(),
270     );
271     assert_eq!(
272         got, want,
273         "got from Parser.Question() = {}, want = {}",
274         got, want
275     );
276 
277     Ok(())
278 }
279 
280 #[test]
281 fn test_name() -> Result<()> {
282     let tests = vec![
283         "",
284         ".",
285         "google..com",
286         "google.com",
287         "google..com.",
288         "google.com.",
289         ".google.com.",
290         "www..google.com.",
291         "www.google.com.",
292     ];
293 
294     for test in tests {
295         let name = Name::new(test)?;
296         let ns = name.to_string();
297         assert_eq!(ns, test, "got {} = {}, want = {}", name, ns, test);
298     }
299 
300     Ok(())
301 }
302 
303 #[test]
304 fn test_name_pack_unpack() -> Result<()> {
305     let tests: Vec<(&str, &str, Option<Error>)> = vec![
306         ("", "", Some(Error::ErrNonCanonicalName)),
307         (".", ".", None),
308         ("google..com", "", Some(Error::ErrNonCanonicalName)),
309         ("google.com", "", Some(Error::ErrNonCanonicalName)),
310         ("google..com.", "", Some(Error::ErrZeroSegLen)),
311         ("google.com.", "google.com.", None),
312         (".google.com.", "", Some(Error::ErrZeroSegLen)),
313         ("www..google.com.", "", Some(Error::ErrZeroSegLen)),
314         ("www.google.com.", "www.google.com.", None),
315     ];
316 
317     for (input, want, want_err) in tests {
318         let input = Name::new(input)?;
319         let result = input.pack(vec![], &mut Some(HashMap::new()), 0);
320         if let Some(want_err) = want_err {
321             if let Err(actual_err) = result {
322                 assert_eq!(want_err, actual_err);
323             } else {
324                 assert!(false);
325             }
326             continue;
327         } else {
328             assert!(result.is_ok());
329         }
330 
331         let buf = result.unwrap();
332 
333         let want = Name::new(want)?;
334 
335         let mut got = Name::default();
336         let n = got.unpack(&buf, 0)?;
337         assert_eq!(
338             n,
339             buf.len(),
340             "unpacked different amount than packed for {}: got = {}, want = {}",
341             input,
342             n,
343             buf.len(),
344         );
345 
346         assert_eq!(
347             got, want,
348             "unpacking packing of {}: got = {}, want = {}",
349             input, got, want
350         );
351     }
352 
353     Ok(())
354 }
355 
356 #[test]
357 fn test_incompressible_name() -> Result<()> {
358     let name = Name::new("example.com.")?;
359     let mut compression = Some(HashMap::new());
360     let buf = name.pack(vec![], &mut compression, 0)?;
361     let buf = name.pack(buf, &mut compression, 0)?;
362     let mut n1 = Name::default();
363     let off = n1.unpack_compressed(&buf, 0, false /* allowCompression */)?;
364     let mut n2 = Name::default();
365     let result = n2.unpack_compressed(&buf, off, false /* allowCompression */);
366     if let Err(err) = result {
367         assert_eq!(
368             Error::ErrCompressedSrv,
369             err,
370             "unpacking compressed incompressible name with pointers: got {}, want = {}",
371             err,
372             Error::ErrCompressedSrv
373         );
374     } else {
375         assert!(false);
376     }
377 
378     Ok(())
379 }
380 
381 #[test]
382 fn test_header_unpack_error() -> Result<()> {
383     let wants = vec![
384         "id",
385         "bits",
386         "questions",
387         "answers",
388         "authorities",
389         "additionals",
390     ];
391 
392     let mut buf = vec![];
393     for want in wants {
394         let mut h = HeaderInternal::default();
395         let result = h.unpack(&buf, 0);
396         assert!(result.is_err(), "{}", want);
397         buf.extend_from_slice(&[0, 0]);
398     }
399 
400     Ok(())
401 }
402 
403 #[test]
404 fn test_parser_start() -> Result<()> {
405     let mut p = Parser::default();
406     let result = p.start(&[]);
407     assert!(result.is_err());
408 
409     Ok(())
410 }
411 
412 #[test]
413 fn test_resource_not_started() -> Result<()> {
414     let tests: Vec<(&str, Box<dyn Fn(&mut Parser<'_>) -> Result<()>>)> = vec![
415         (
416             "CNAMEResource",
417             Box::new(|p: &mut Parser<'_>| -> Result<()> {
418                 if let Err(err) = p.resource_body() {
419                     Err(err)
420                 } else {
421                     Ok(())
422                 }
423             }),
424         ),
425         (
426             "MXResource",
427             Box::new(|p: &mut Parser<'_>| -> Result<()> {
428                 if let Err(err) = p.resource_body() {
429                     Err(err)
430                 } else {
431                     Ok(())
432                 }
433             }),
434         ),
435         (
436             "NSResource",
437             Box::new(|p: &mut Parser<'_>| -> Result<()> {
438                 if let Err(err) = p.resource_body() {
439                     Err(err)
440                 } else {
441                     Ok(())
442                 }
443             }),
444         ),
445         (
446             "PTRResource",
447             Box::new(|p: &mut Parser<'_>| -> Result<()> {
448                 if let Err(err) = p.resource_body() {
449                     Err(err)
450                 } else {
451                     Ok(())
452                 }
453             }),
454         ),
455         (
456             "SOAResource",
457             Box::new(|p: &mut Parser<'_>| -> Result<()> {
458                 if let Err(err) = p.resource_body() {
459                     Err(err)
460                 } else {
461                     Ok(())
462                 }
463             }),
464         ),
465         (
466             "TXTResource",
467             Box::new(|p: &mut Parser<'_>| -> Result<()> {
468                 if let Err(err) = p.resource_body() {
469                     Err(err)
470                 } else {
471                     Ok(())
472                 }
473             }),
474         ),
475         (
476             "SRVResource",
477             Box::new(|p: &mut Parser<'_>| -> Result<()> {
478                 if let Err(err) = p.resource_body() {
479                     Err(err)
480                 } else {
481                     Ok(())
482                 }
483             }),
484         ),
485         (
486             "AResource",
487             Box::new(|p: &mut Parser<'_>| -> Result<()> {
488                 if let Err(err) = p.resource_body() {
489                     Err(err)
490                 } else {
491                     Ok(())
492                 }
493             }),
494         ),
495         (
496             "AAAAResource",
497             Box::new(|p: &mut Parser<'_>| -> Result<()> {
498                 if let Err(err) = p.resource_body() {
499                     Err(err)
500                 } else {
501                     Ok(())
502                 }
503             }),
504         ),
505     ];
506 
507     for (name, test_fn) in tests {
508         let mut p = Parser::default();
509         if let Err(err) = test_fn(&mut p) {
510             assert_eq!(Error::ErrNotStarted, err, "{}", name);
511         }
512     }
513 
514     Ok(())
515 }
516 
517 #[test]
518 fn test_srv_pack_unpack() -> Result<()> {
519     let want = Box::new(SrvResource {
520         priority: 8,
521         weight: 9,
522         port: 11,
523         target: Name::new("srv.example.com.")?,
524     });
525 
526     let b = want.pack(vec![], &mut None, 0)?;
527     let mut got = SrvResource::default();
528     got.unpack(&b, 0, 0)?;
529     assert_eq!(got.to_string(), want.to_string(),);
530 
531     Ok(())
532 }
533 
534 #[test]
535 fn test_dns_pack_unpack() -> Result<()> {
536     let wants = vec![
537         Message {
538             header: Header::default(),
539             questions: vec![Question {
540                 name: Name::new(".")?,
541                 typ: DnsType::Aaaa,
542                 class: DNSCLASS_INET,
543             }],
544             answers: vec![],
545             authorities: vec![],
546             additionals: vec![],
547         },
548         large_test_msg()?,
549     ];
550 
551     for mut want in wants {
552         let b = want.pack()?;
553         let mut got = Message::default();
554         got.unpack(&b)?;
555         assert_eq!(got.to_string(), want.to_string());
556     }
557 
558     Ok(())
559 }
560 
561 #[test]
562 fn test_dns_append_pack_unpack() -> Result<()> {
563     let wants = vec![
564         Message {
565             header: Header::default(),
566             questions: vec![Question {
567                 name: Name::new(".")?,
568                 typ: DnsType::Aaaa,
569                 class: DNSCLASS_INET,
570             }],
571             answers: vec![],
572             authorities: vec![],
573             additionals: vec![],
574         },
575         large_test_msg()?,
576     ];
577 
578     for mut want in wants {
579         let mut b = vec![0; 2];
580         b = want.append_pack(b)?;
581         let mut got = Message::default();
582         got.unpack(&b[2..])?;
583         assert_eq!(got.to_string(), want.to_string());
584     }
585 
586     Ok(())
587 }
588 
589 #[test]
590 fn test_skip_all() -> Result<()> {
591     let mut msg = large_test_msg()?;
592     let buf = msg.pack()?;
593     let mut p = Parser::default();
594     p.start(&buf)?;
595 
596     for _ in 1..=3 {
597         p.skip_all_questions()?;
598     }
599     for _ in 1..=3 {
600         p.skip_all_answers()?;
601     }
602     for _ in 1..=3 {
603         p.skip_all_authorities()?;
604     }
605     for _ in 1..=3 {
606         p.skip_all_additionals()?;
607     }
608 
609     Ok(())
610 }
611 
612 #[test]
613 fn test_skip_each() -> Result<()> {
614     let mut msg = small_test_msg()?;
615     let buf = msg.pack()?;
616     let mut p = Parser::default();
617     p.start(&buf)?;
618 
619     //	{"SkipQuestion", p.SkipQuestion},
620     //	{"SkipAnswer", p.SkipAnswer},
621     //	{"SkipAuthority", p.SkipAuthority},
622     //  {"SkipAdditional", p.SkipAdditional},
623 
624     p.skip_question()?;
625     if let Err(err) = p.skip_question() {
626         assert_eq!(Error::ErrSectionDone, err);
627     } else {
628         assert!(false, "expected error, but got ok");
629     }
630 
631     p.skip_answer()?;
632     if let Err(err) = p.skip_answer() {
633         assert_eq!(Error::ErrSectionDone, err);
634     } else {
635         assert!(false, "expected error, but got ok");
636     }
637 
638     p.skip_authority()?;
639     if let Err(err) = p.skip_authority() {
640         assert_eq!(Error::ErrSectionDone, err);
641     } else {
642         assert!(false, "expected error, but got ok");
643     }
644 
645     p.skip_additional()?;
646     if let Err(err) = p.skip_additional() {
647         assert_eq!(Error::ErrSectionDone, err);
648     } else {
649         assert!(false, "expected error, but got ok");
650     }
651 
652     Ok(())
653 }
654 
655 #[test]
656 fn test_skip_after_read() -> Result<()> {
657     let mut msg = small_test_msg()?;
658     let buf = msg.pack()?;
659     let mut p = Parser::default();
660     p.start(&buf)?;
661 
662     let tests: Vec<(&str, Box<dyn Fn(&mut Parser<'_>) -> Result<()>>)> = vec![
663         (
664             "Question",
665             Box::new(|p: &mut Parser<'_>| -> Result<()> {
666                 if let Err(err) = p.question() {
667                     Err(err)
668                 } else {
669                     Ok(())
670                 }
671             }),
672         ),
673         (
674             "Answer",
675             Box::new(|p: &mut Parser<'_>| -> Result<()> {
676                 if let Err(err) = p.answer() {
677                     Err(err)
678                 } else {
679                     Ok(())
680                 }
681             }),
682         ),
683         (
684             "Authority",
685             Box::new(|p: &mut Parser<'_>| -> Result<()> {
686                 if let Err(err) = p.authority() {
687                     Err(err)
688                 } else {
689                     Ok(())
690                 }
691             }),
692         ),
693         (
694             "Additional",
695             Box::new(|p: &mut Parser<'_>| -> Result<()> {
696                 if let Err(err) = p.additional() {
697                     Err(err)
698                 } else {
699                     Ok(())
700                 }
701             }),
702         ),
703     ];
704 
705     for (name, read_fn) in tests {
706         read_fn(&mut p)?;
707 
708         let result = match name {
709             "Question" => p.skip_question(),
710             "Answer" => p.skip_answer(),
711             "Authority" => p.skip_authority(),
712             _ => p.skip_additional(),
713         };
714 
715         if let Err(err) = result {
716             assert_eq!(Error::ErrSectionDone, err);
717         } else {
718             assert!(false, "expected error, but got ok");
719         }
720     }
721 
722     Ok(())
723 }
724 
725 #[test]
726 fn test_skip_not_started() -> Result<()> {
727     let tests: Vec<(&str, Box<dyn Fn(&mut Parser<'_>) -> Result<()>>)> = vec![
728         (
729             "SkipAllQuestions",
730             Box::new(|p: &mut Parser<'_>| -> Result<()> { p.skip_all_questions() }),
731         ),
732         (
733             "SkipAllAnswers",
734             Box::new(|p: &mut Parser<'_>| -> Result<()> { p.skip_all_answers() }),
735         ),
736         (
737             "SkipAllAuthorities",
738             Box::new(|p: &mut Parser<'_>| -> Result<()> { p.skip_all_authorities() }),
739         ),
740         (
741             "SkipAllAdditionals",
742             Box::new(|p: &mut Parser<'_>| -> Result<()> { p.skip_all_additionals() }),
743         ),
744     ];
745 
746     let mut p = Parser::default();
747     for (name, test_fn) in tests {
748         if let Err(err) = test_fn(&mut p) {
749             assert_eq!(Error::ErrNotStarted, err);
750         } else {
751             assert!(false, "{} expected error, but got ok", name);
752         }
753     }
754 
755     Ok(())
756 }
757 
758 #[test]
759 fn test_too_many_records() -> Result<()> {
760     let recs: usize = u16::MAX as usize + 1;
761     let tests = vec![
762         (
763             "Questions",
764             Message {
765                 questions: vec![Question::default(); recs],
766                 ..Default::default()
767             },
768             Error::ErrTooManyQuestions,
769         ),
770         (
771             "Answers",
772             Message {
773                 answers: {
774                     let mut a = vec![];
775                     for _ in 0..recs {
776                         a.push(Resource::default());
777                     }
778                     a
779                 },
780                 ..Default::default()
781             },
782             Error::ErrTooManyAnswers,
783         ),
784         (
785             "Authorities",
786             Message {
787                 authorities: {
788                     let mut a = vec![];
789                     for _ in 0..recs {
790                         a.push(Resource::default());
791                     }
792                     a
793                 },
794                 ..Default::default()
795             },
796             Error::ErrTooManyAuthorities,
797         ),
798         (
799             "Additionals",
800             Message {
801                 additionals: {
802                     let mut a = vec![];
803                     for _ in 0..recs {
804                         a.push(Resource::default());
805                     }
806                     a
807                 },
808                 ..Default::default()
809             },
810             Error::ErrTooManyAdditionals,
811         ),
812     ];
813 
814     for (name, mut msg, want) in tests {
815         if let Err(got) = msg.pack() {
816             assert_eq!(
817                 want, got,
818                 "got Message.Pack() for {} = {}, want = {}",
819                 name, got, want
820             )
821         } else {
822             assert!(false, "expected error, but got ok");
823         }
824     }
825 
826     Ok(())
827 }
828 
829 #[test]
830 fn test_very_long_txt() -> Result<()> {
831     let mut str255 = String::new();
832     for _ in 0..255 {
833         str255.push('.');
834     }
835 
836     let mut want = Resource {
837         header: ResourceHeader {
838             name: Name::new("foo.bar.example.com.")?,
839             typ: DnsType::Txt,
840             class: DNSCLASS_INET,
841             ..Default::default()
842         },
843         body: Some(Box::new(TxtResource {
844             txt: vec![
845                 "".to_owned(),
846                 "".to_owned(),
847                 "foo bar".to_owned(),
848                 "".to_owned(),
849                 "www.example.com".to_owned(),
850                 "www.example.com.".to_owned(),
851                 str255,
852             ],
853         })),
854     };
855 
856     let buf = want.pack(vec![], &mut Some(HashMap::new()), 0)?;
857     let mut got = Resource::default();
858     let off = got.header.unpack(&buf, 0, 0)?;
859     let (body, n) = unpack_resource_body(got.header.typ, &buf, off, got.header.length as usize)?;
860     got.body = Some(body);
861     assert_eq!(
862         n,
863         buf.len(),
864         "unpacked different amount than packed: got = {}, want = {}",
865         n,
866         buf.len(),
867     );
868     assert_eq!(got.to_string(), want.to_string());
869 
870     Ok(())
871 }
872 
873 #[test]
874 fn test_too_long_txt() -> Result<()> {
875     let mut str256 = String::new();
876     for _ in 0..256 {
877         str256.push('.');
878     }
879     let rb = TxtResource { txt: vec![str256] };
880     if let Err(err) = rb.pack(vec![], &mut Some(HashMap::new()), 0) {
881         assert_eq!(Error::ErrStringTooLong, err);
882     } else {
883         assert!(false, "expected error, but got ok");
884     }
885 
886     Ok(())
887 }
888 
889 #[test]
890 fn test_start_error() -> Result<()> {
891     let tests: Vec<(&str, Box<dyn Fn(&mut Builder) -> Result<()>>)> = vec![
892         (
893             "Questions",
894             Box::new(|b: &mut Builder| -> Result<()> { b.start_questions() }),
895         ),
896         (
897             "Answers",
898             Box::new(|b: &mut Builder| -> Result<()> { b.start_answers() }),
899         ),
900         (
901             "Authorities",
902             Box::new(|b: &mut Builder| -> Result<()> { b.start_authorities() }),
903         ),
904         (
905             "Additionals",
906             Box::new(|b: &mut Builder| -> Result<()> { b.start_additionals() }),
907         ),
908     ];
909 
910     let envs: Vec<(&str, Box<dyn Fn() -> Builder>, Error)> = vec![
911         (
912             "sectionNotStarted",
913             Box::new(|| -> Builder {
914                 Builder {
915                     section: Section::NotStarted,
916                     ..Default::default()
917                 }
918             }),
919             Error::ErrNotStarted,
920         ),
921         (
922             "sectionDone",
923             Box::new(|| -> Builder {
924                 Builder {
925                     section: Section::Done,
926                     ..Default::default()
927                 }
928             }),
929             Error::ErrSectionDone,
930         ),
931     ];
932 
933     for (env_name, env_fn, env_err) in &envs {
934         for (test_name, test_fn) in &tests {
935             let mut b = env_fn();
936             if let Err(got_err) = test_fn(&mut b) {
937                 assert_eq!(
938                     *env_err, got_err,
939                     "got Builder{}.{} = {}, want = {}",
940                     env_name, test_name, got_err, env_err
941                 );
942             } else {
943                 assert!(
944                     false,
945                     "{}.{}expected error, but got ok",
946                     env_name, test_name
947                 );
948             }
949         }
950     }
951 
952     Ok(())
953 }
954 
955 #[test]
956 fn test_builder_resource_error() -> Result<()> {
957     let tests: Vec<(&str, Box<dyn Fn(&mut Builder) -> Result<()>>)> = vec![
958         (
959             "CNAMEResource",
960             Box::new(|b: &mut Builder| -> Result<()> {
961                 b.add_resource(&mut Resource {
962                     header: ResourceHeader::default(),
963                     body: Some(Box::new(CnameResource::default())),
964                 })
965             }),
966         ),
967         (
968             "MXResource",
969             Box::new(|b: &mut Builder| -> Result<()> {
970                 b.add_resource(&mut Resource {
971                     header: ResourceHeader::default(),
972                     body: Some(Box::new(MxResource::default())),
973                 })
974             }),
975         ),
976         (
977             "NSResource",
978             Box::new(|b: &mut Builder| -> Result<()> {
979                 b.add_resource(&mut Resource {
980                     header: ResourceHeader::default(),
981                     body: Some(Box::new(NsResource::default())),
982                 })
983             }),
984         ),
985         (
986             "PTRResource",
987             Box::new(|b: &mut Builder| -> Result<()> {
988                 b.add_resource(&mut Resource {
989                     header: ResourceHeader::default(),
990                     body: Some(Box::new(PtrResource::default())),
991                 })
992             }),
993         ),
994         (
995             "SOAResource",
996             Box::new(|b: &mut Builder| -> Result<()> {
997                 b.add_resource(&mut Resource {
998                     header: ResourceHeader::default(),
999                     body: Some(Box::new(SoaResource::default())),
1000                 })
1001             }),
1002         ),
1003         (
1004             "TXTResource",
1005             Box::new(|b: &mut Builder| -> Result<()> {
1006                 b.add_resource(&mut Resource {
1007                     header: ResourceHeader::default(),
1008                     body: Some(Box::new(TxtResource::default())),
1009                 })
1010             }),
1011         ),
1012         (
1013             "SRVResource",
1014             Box::new(|b: &mut Builder| -> Result<()> {
1015                 b.add_resource(&mut Resource {
1016                     header: ResourceHeader::default(),
1017                     body: Some(Box::new(SrvResource::default())),
1018                 })
1019             }),
1020         ),
1021         (
1022             "AResource",
1023             Box::new(|b: &mut Builder| -> Result<()> {
1024                 b.add_resource(&mut Resource {
1025                     header: ResourceHeader::default(),
1026                     body: Some(Box::new(AResource::default())),
1027                 })
1028             }),
1029         ),
1030         (
1031             "AAAAResource",
1032             Box::new(|b: &mut Builder| -> Result<()> {
1033                 b.add_resource(&mut Resource {
1034                     header: ResourceHeader::default(),
1035                     body: Some(Box::new(AaaaResource::default())),
1036                 })
1037             }),
1038         ),
1039         (
1040             "OPTResource",
1041             Box::new(|b: &mut Builder| -> Result<()> {
1042                 b.add_resource(&mut Resource {
1043                     header: ResourceHeader::default(),
1044                     body: Some(Box::new(OptResource::default())),
1045                 })
1046             }),
1047         ),
1048     ];
1049 
1050     let envs: Vec<(&str, Box<dyn Fn() -> Builder>, Error)> = vec![
1051         (
1052             "sectionNotStarted",
1053             Box::new(|| -> Builder {
1054                 Builder {
1055                     section: Section::NotStarted,
1056                     ..Default::default()
1057                 }
1058             }),
1059             Error::ErrNotStarted,
1060         ),
1061         (
1062             "sectionHeader",
1063             Box::new(|| -> Builder {
1064                 Builder {
1065                     section: Section::Header,
1066                     ..Default::default()
1067                 }
1068             }),
1069             Error::ErrNotStarted,
1070         ),
1071         (
1072             "sectionQuestions",
1073             Box::new(|| -> Builder {
1074                 Builder {
1075                     section: Section::Questions,
1076                     ..Default::default()
1077                 }
1078             }),
1079             Error::ErrNotStarted,
1080         ),
1081         (
1082             "sectionDone",
1083             Box::new(|| -> Builder {
1084                 Builder {
1085                     section: Section::Done,
1086                     ..Default::default()
1087                 }
1088             }),
1089             Error::ErrSectionDone,
1090         ),
1091     ];
1092 
1093     for (env_name, env_fn, env_err) in &envs {
1094         for (test_name, test_fn) in &tests {
1095             let mut b = env_fn();
1096             if let Err(got_err) = test_fn(&mut b) {
1097                 assert_eq!(
1098                     *env_err, got_err,
1099                     "got Builder{}.{} = {}, want = {}",
1100                     env_name, test_name, got_err, env_err
1101                 );
1102             } else {
1103                 assert!(
1104                     false,
1105                     "{}.{}expected error, but got ok",
1106                     env_name, test_name
1107                 );
1108             }
1109         }
1110     }
1111 
1112     Ok(())
1113 }
1114 
1115 #[test]
1116 fn test_finish_error() -> Result<()> {
1117     let mut b = Builder::default();
1118     let want = Error::ErrNotStarted;
1119     if let Err(got) = b.finish() {
1120         assert_eq!(want, got, "got Builder.Finish() = {}, want = {}", got, want);
1121     } else {
1122         assert!(false, "expected error, but got ok");
1123     }
1124 
1125     Ok(())
1126 }
1127 
1128 #[test]
1129 fn test_builder() -> Result<()> {
1130     let mut msg = large_test_msg()?;
1131     let want = msg.pack()?;
1132 
1133     let mut b = Builder::new(&msg.header);
1134     b.enable_compression();
1135 
1136     b.start_questions()?;
1137     for q in &msg.questions {
1138         b.add_question(q)?;
1139     }
1140 
1141     b.start_answers()?;
1142     for r in &mut msg.answers {
1143         b.add_resource(r)?;
1144     }
1145 
1146     b.start_authorities()?;
1147     for r in &mut msg.authorities {
1148         b.add_resource(r)?;
1149     }
1150 
1151     b.start_additionals()?;
1152     for r in &mut msg.additionals {
1153         b.add_resource(r)?;
1154     }
1155 
1156     let got = b.finish()?;
1157     assert_eq!(
1158         got,
1159         want,
1160         "got.len()={}, want.len()={}",
1161         got.len(),
1162         want.len()
1163     );
1164 
1165     Ok(())
1166 }
1167 
1168 #[test]
1169 fn test_resource_pack() -> Result<()> {
1170     let tests = vec![
1171         (
1172             Message {
1173                 questions: vec![Question {
1174                     name: Name::new(".")?,
1175                     typ: DnsType::Aaaa,
1176                     class: DNSCLASS_INET,
1177                 }],
1178                 answers: vec![Resource {
1179                     header: ResourceHeader::default(),
1180                     body: None,
1181                 }],
1182                 ..Default::default()
1183             },
1184             Error::ErrNilResourceBody,
1185         ),
1186         (
1187             Message {
1188                 questions: vec![Question {
1189                     name: Name::new(".")?,
1190                     typ: DnsType::Aaaa,
1191                     class: DNSCLASS_INET,
1192                 }],
1193                 authorities: vec![Resource {
1194                     header: ResourceHeader::default(),
1195                     body: Some(Box::new(NsResource::default())),
1196                 }],
1197                 ..Default::default()
1198             },
1199             Error::ErrNonCanonicalName,
1200         ),
1201         (
1202             Message {
1203                 questions: vec![Question {
1204                     name: Name::new(".")?,
1205                     typ: DnsType::A,
1206                     class: DNSCLASS_INET,
1207                 }],
1208                 additionals: vec![Resource {
1209                     header: ResourceHeader::default(),
1210                     body: None,
1211                 }],
1212                 ..Default::default()
1213             },
1214             Error::ErrNilResourceBody,
1215         ),
1216     ];
1217 
1218     for (mut m, want_err) in tests {
1219         if let Err(err) = m.pack() {
1220             assert_eq!(want_err, err);
1221         } else {
1222             assert!(false, "expected error, but got ok");
1223         }
1224     }
1225 
1226     Ok(())
1227 }
1228 
1229 #[test]
1230 fn test_resource_pack_length() -> Result<()> {
1231     let mut r = Resource {
1232         header: ResourceHeader {
1233             name: Name::new(".")?,
1234             typ: DnsType::A,
1235             class: DNSCLASS_INET,
1236             ..Default::default()
1237         },
1238         body: Some(Box::new(AResource { a: [127, 0, 0, 2] })),
1239     };
1240 
1241     let (hb, _) = r.header.pack(vec![], &mut None, 0)?;
1242     let buf = r.pack(vec![], &mut None, 0)?;
1243 
1244     let mut hdr = ResourceHeader::default();
1245     hdr.unpack(&buf, 0, 0)?;
1246 
1247     let (got, want) = (hdr.length as usize, buf.len() - hb.len());
1248     assert_eq!(got, want, "got hdr.Length = {}, want = {}", got, want);
1249 
1250     Ok(())
1251 }
1252 
1253 #[test]
1254 fn test_option_pack_unpack() -> Result<()> {
1255     let tests = vec![
1256         (
1257             "without EDNS(0) options",
1258             vec![
1259                 0x00, 0x00, 0x29, 0x10, 0x00, 0xfe, 0x00, 0x80, 0x00, 0x00, 0x00,
1260             ],
1261             Message {
1262                 header: Header {
1263                     rcode: RCode::FormatError,
1264                     ..Default::default()
1265                 },
1266                 questions: vec![Question {
1267                     name: Name::new(".")?,
1268                     typ: DnsType::A,
1269                     class: DNSCLASS_INET,
1270                 }],
1271                 additionals: vec![Resource {
1272                     header: must_edns0_resource_header(
1273                         4096,
1274                         0xfe0 | RCode::FormatError as u32,
1275                         true,
1276                     )?,
1277                     body: Some(Box::new(OptResource::default())),
1278                 }],
1279                 ..Default::default()
1280             },
1281             //true,
1282             //0xfe0 | RCode::FormatError as u32,
1283         ),
1284         (
1285             "with EDNS(0) options",
1286             vec![
1287                 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00,
1288                 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x12, 0x34,
1289             ],
1290             Message {
1291                 header: Header {
1292                     rcode: RCode::ServerFailure,
1293                     ..Default::default()
1294                 },
1295                 questions: vec![Question {
1296                     name: Name::new(".")?,
1297                     typ: DnsType::Aaaa,
1298                     class: DNSCLASS_INET,
1299                 }],
1300                 additionals: vec![Resource {
1301                     header: must_edns0_resource_header(
1302                         4096,
1303                         0xff0 | RCode::ServerFailure as u32,
1304                         false,
1305                     )?,
1306                     body: Some(Box::new(OptResource {
1307                         options: vec![
1308                             DnsOption {
1309                                 code: 12, // see RFC 7828
1310                                 data: vec![0x00, 0x00],
1311                             },
1312                             DnsOption {
1313                                 code: 11, // see RFC 7830
1314                                 data: vec![0x12, 0x34],
1315                             },
1316                         ],
1317                     })),
1318                 }],
1319                 ..Default::default()
1320             },
1321             //dnssecOK: false,
1322             //extRCode: 0xff0 | RCodeServerFailure,
1323         ),
1324         (
1325             // Containing multiple OPT resources in a
1326             // message is invalid, but it's necessary for
1327             // protocol conformance testing.
1328             "with multiple OPT resources",
1329             vec![
1330                 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00,
1331                 0x02, 0x12, 0x34, 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06,
1332                 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00,
1333             ],
1334             Message {
1335                 header: Header {
1336                     rcode: RCode::NameError,
1337                     ..Default::default()
1338                 },
1339                 questions: vec![Question {
1340                     name: Name::new(".")?,
1341                     typ: DnsType::Aaaa,
1342                     class: DNSCLASS_INET,
1343                 }],
1344                 additionals: vec![
1345                     Resource {
1346                         header: must_edns0_resource_header(
1347                             4096,
1348                             0xff0 | RCode::NameError as u32,
1349                             false,
1350                         )?,
1351                         body: Some(Box::new(OptResource {
1352                             options: vec![DnsOption {
1353                                 code: 11, // see RFC 7830
1354                                 data: vec![0x12, 0x34],
1355                             }],
1356                         })),
1357                     },
1358                     Resource {
1359                         header: must_edns0_resource_header(
1360                             4096,
1361                             0xff0 | RCode::NameError as u32,
1362                             false,
1363                         )?,
1364                         body: Some(Box::new(OptResource {
1365                             options: vec![DnsOption {
1366                                 code: 12, // see RFC 7828
1367                                 data: vec![0x00, 0x00],
1368                             }],
1369                         })),
1370                     },
1371                 ],
1372                 ..Default::default()
1373             },
1374         ),
1375     ];
1376 
1377     for (_tt_name, tt_w, mut tt_m) in tests {
1378         let w = tt_m.pack()?;
1379 
1380         assert_eq!(&w[w.len() - tt_w.len()..], &tt_w[..]);
1381 
1382         let mut m = Message::default();
1383         m.unpack(&w)?;
1384 
1385         let ms: Vec<String> = m.additionals.iter().map(|s| s.to_string()).collect();
1386         let tt_ms: Vec<String> = tt_m.additionals.iter().map(|s| s.to_string()).collect();
1387         assert_eq!(ms, tt_ms);
1388     }
1389 
1390     Ok(())
1391 }
1392