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