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