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