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 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 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 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] 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] 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() = {}, want = {}", 277 got, want 278 ); 279 280 Ok(()) 281 } 282 283 #[test] 284 fn test_name() -> Result<()> { 285 let tests = vec![ 286 "", 287 ".", 288 "google..com", 289 "google.com", 290 "google..com.", 291 "google.com.", 292 ".google.com.", 293 "www..google.com.", 294 "www.google.com.", 295 ]; 296 297 for test in tests { 298 let name = Name::new(test)?; 299 let ns = name.to_string(); 300 assert_eq!(ns, test, "got {} = {}, want = {}", name, ns, test); 301 } 302 303 Ok(()) 304 } 305 306 #[test] 307 fn test_name_pack_unpack() -> Result<()> { 308 let tests: Vec<(&str, &str, Option<Error>)> = vec![ 309 ("", "", Some(Error::ErrNonCanonicalName)), 310 (".", ".", None), 311 ("google..com", "", Some(Error::ErrNonCanonicalName)), 312 ("google.com", "", Some(Error::ErrNonCanonicalName)), 313 ("google..com.", "", Some(Error::ErrZeroSegLen)), 314 ("google.com.", "google.com.", None), 315 (".google.com.", "", Some(Error::ErrZeroSegLen)), 316 ("www..google.com.", "", Some(Error::ErrZeroSegLen)), 317 ("www.google.com.", "www.google.com.", None), 318 ]; 319 320 for (input, want, want_err) in tests { 321 let input = Name::new(input)?; 322 let result = input.pack(vec![], &mut Some(HashMap::new()), 0); 323 if let Some(want_err) = want_err { 324 if let Err(actual_err) = result { 325 assert_eq!(actual_err, want_err); 326 } else { 327 panic!(); 328 } 329 continue; 330 } else { 331 assert!(result.is_ok()); 332 } 333 334 let buf = result.unwrap(); 335 336 let want = Name::new(want)?; 337 338 let mut got = Name::default(); 339 let n = got.unpack(&buf, 0)?; 340 assert_eq!( 341 n, 342 buf.len(), 343 "unpacked different amount than packed for {}: got = {}, want = {}", 344 input, 345 n, 346 buf.len(), 347 ); 348 349 assert_eq!( 350 got, want, 351 "unpacking packing of {}: got = {}, want = {}", 352 input, got, want 353 ); 354 } 355 356 Ok(()) 357 } 358 359 #[test] 360 fn test_incompressible_name() -> Result<()> { 361 let name = Name::new("example.com.")?; 362 let mut compression = Some(HashMap::new()); 363 let buf = name.pack(vec![], &mut compression, 0)?; 364 let buf = name.pack(buf, &mut compression, 0)?; 365 let mut n1 = Name::default(); 366 let off = n1.unpack_compressed(&buf, 0, false /* allowCompression */)?; 367 let mut n2 = Name::default(); 368 let result = n2.unpack_compressed(&buf, off, false /* allowCompression */); 369 if let Err(err) = result { 370 assert_eq!( 371 Error::ErrCompressedSrv, 372 err, 373 "unpacking compressed incompressible name with pointers: got {}, want = {}", 374 err, 375 Error::ErrCompressedSrv 376 ); 377 } else { 378 panic!(); 379 } 380 381 Ok(()) 382 } 383 384 #[test] 385 fn test_header_unpack_error() -> Result<()> { 386 let wants = vec![ 387 "id", 388 "bits", 389 "questions", 390 "answers", 391 "authorities", 392 "additionals", 393 ]; 394 395 let mut buf = vec![]; 396 for want in wants { 397 let mut h = HeaderInternal::default(); 398 let result = h.unpack(&buf, 0); 399 assert!(result.is_err(), "{}", want); 400 buf.extend_from_slice(&[0, 0]); 401 } 402 403 Ok(()) 404 } 405 406 #[test] 407 fn test_parser_start() -> Result<()> { 408 let mut p = Parser::default(); 409 let result = p.start(&[]); 410 assert!(result.is_err()); 411 412 Ok(()) 413 } 414 415 #[test] 416 fn test_resource_not_started() -> Result<()> { 417 let tests: Vec<(&str, Box<dyn Fn(&mut Parser<'_>) -> Result<()>>)> = vec![ 418 ( 419 "CNAMEResource", 420 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.resource_body().map(|_| ()) }), 421 ), 422 ( 423 "MXResource", 424 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.resource_body().map(|_| ()) }), 425 ), 426 ( 427 "NSResource", 428 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.resource_body().map(|_| ()) }), 429 ), 430 ( 431 "PTRResource", 432 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.resource_body().map(|_| ()) }), 433 ), 434 ( 435 "SOAResource", 436 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.resource_body().map(|_| ()) }), 437 ), 438 ( 439 "TXTResource", 440 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.resource_body().map(|_| ()) }), 441 ), 442 ( 443 "SRVResource", 444 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.resource_body().map(|_| ()) }), 445 ), 446 ( 447 "AResource", 448 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.resource_body().map(|_| ()) }), 449 ), 450 ( 451 "AAAAResource", 452 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.resource_body().map(|_| ()) }), 453 ), 454 ]; 455 456 for (name, test_fn) in tests { 457 let mut p = Parser::default(); 458 if let Err(err) = test_fn(&mut p) { 459 assert_eq!(err, Error::ErrNotStarted, "{}", name); 460 } 461 } 462 463 Ok(()) 464 } 465 466 #[test] 467 fn test_srv_pack_unpack() -> Result<()> { 468 let want = Box::new(SrvResource { 469 priority: 8, 470 weight: 9, 471 port: 11, 472 target: Name::new("srv.example.com.")?, 473 }); 474 475 let b = want.pack(vec![], &mut None, 0)?; 476 let mut got = SrvResource::default(); 477 got.unpack(&b, 0, 0)?; 478 assert_eq!(got.to_string(), want.to_string(),); 479 480 Ok(()) 481 } 482 483 #[test] 484 fn test_dns_pack_unpack() -> Result<()> { 485 let wants = vec![ 486 Message { 487 header: Header::default(), 488 questions: vec![Question { 489 name: Name::new(".")?, 490 typ: DnsType::Aaaa, 491 class: DNSCLASS_INET, 492 }], 493 answers: vec![], 494 authorities: vec![], 495 additionals: vec![], 496 }, 497 large_test_msg()?, 498 ]; 499 500 for mut want in wants { 501 let b = want.pack()?; 502 let mut got = Message::default(); 503 got.unpack(&b)?; 504 assert_eq!(got.to_string(), want.to_string()); 505 } 506 507 Ok(()) 508 } 509 510 #[test] 511 fn test_dns_append_pack_unpack() -> Result<()> { 512 let wants = vec![ 513 Message { 514 header: Header::default(), 515 questions: vec![Question { 516 name: Name::new(".")?, 517 typ: DnsType::Aaaa, 518 class: DNSCLASS_INET, 519 }], 520 answers: vec![], 521 authorities: vec![], 522 additionals: vec![], 523 }, 524 large_test_msg()?, 525 ]; 526 527 for mut want in wants { 528 let mut b = vec![0; 2]; 529 b = want.append_pack(b)?; 530 let mut got = Message::default(); 531 got.unpack(&b[2..])?; 532 assert_eq!(got.to_string(), want.to_string()); 533 } 534 535 Ok(()) 536 } 537 538 #[test] 539 fn test_skip_all() -> Result<()> { 540 let mut msg = large_test_msg()?; 541 let buf = msg.pack()?; 542 let mut p = Parser::default(); 543 p.start(&buf)?; 544 545 for _ in 1..=3 { 546 p.skip_all_questions()?; 547 } 548 for _ in 1..=3 { 549 p.skip_all_answers()?; 550 } 551 for _ in 1..=3 { 552 p.skip_all_authorities()?; 553 } 554 for _ in 1..=3 { 555 p.skip_all_additionals()?; 556 } 557 558 Ok(()) 559 } 560 561 #[test] 562 fn test_skip_each() -> Result<()> { 563 let mut msg = small_test_msg()?; 564 let buf = msg.pack()?; 565 let mut p = Parser::default(); 566 p.start(&buf)?; 567 568 // {"SkipQuestion", p.SkipQuestion}, 569 // {"SkipAnswer", p.SkipAnswer}, 570 // {"SkipAuthority", p.SkipAuthority}, 571 // {"SkipAdditional", p.SkipAdditional}, 572 573 p.skip_question()?; 574 if let Err(err) = p.skip_question() { 575 assert_eq!(err, Error::ErrSectionDone); 576 } else { 577 panic!("expected error, but got ok"); 578 } 579 580 p.skip_answer()?; 581 if let Err(err) = p.skip_answer() { 582 assert_eq!(err, Error::ErrSectionDone); 583 } else { 584 panic!("expected error, but got ok"); 585 } 586 587 p.skip_authority()?; 588 if let Err(err) = p.skip_authority() { 589 assert_eq!(err, Error::ErrSectionDone); 590 } else { 591 panic!("expected error, but got ok"); 592 } 593 594 p.skip_additional()?; 595 if let Err(err) = p.skip_additional() { 596 assert_eq!(err, Error::ErrSectionDone); 597 } else { 598 panic!("expected error, but got ok"); 599 } 600 601 Ok(()) 602 } 603 604 #[test] 605 fn test_skip_after_read() -> Result<()> { 606 let mut msg = small_test_msg()?; 607 let buf = msg.pack()?; 608 let mut p = Parser::default(); 609 p.start(&buf)?; 610 611 let tests: Vec<(&str, Box<dyn Fn(&mut Parser<'_>) -> Result<()>>)> = vec![ 612 ( 613 "Question", 614 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.question().map(|_| ()) }), 615 ), 616 ( 617 "Answer", 618 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.answer().map(|_| ()) }), 619 ), 620 ( 621 "Authority", 622 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.authority().map(|_| ()) }), 623 ), 624 ( 625 "Additional", 626 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.additional().map(|_| ()) }), 627 ), 628 ]; 629 630 for (name, read_fn) in tests { 631 read_fn(&mut p)?; 632 633 let result = match name { 634 "Question" => p.skip_question(), 635 "Answer" => p.skip_answer(), 636 "Authority" => p.skip_authority(), 637 _ => p.skip_additional(), 638 }; 639 640 if let Err(err) = result { 641 assert_eq!(err, Error::ErrSectionDone); 642 } else { 643 panic!("expected error, but got ok"); 644 } 645 } 646 647 Ok(()) 648 } 649 650 #[test] 651 fn test_skip_not_started() -> Result<()> { 652 let tests: Vec<(&str, Box<dyn Fn(&mut Parser<'_>) -> Result<()>>)> = vec![ 653 ( 654 "SkipAllQuestions", 655 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.skip_all_questions() }), 656 ), 657 ( 658 "SkipAllAnswers", 659 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.skip_all_answers() }), 660 ), 661 ( 662 "SkipAllAuthorities", 663 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.skip_all_authorities() }), 664 ), 665 ( 666 "SkipAllAdditionals", 667 Box::new(|p: &mut Parser<'_>| -> Result<()> { p.skip_all_additionals() }), 668 ), 669 ]; 670 671 let mut p = Parser::default(); 672 for (name, test_fn) in tests { 673 if let Err(err) = test_fn(&mut p) { 674 assert_eq!(err, Error::ErrNotStarted); 675 } else { 676 panic!("{} expected error, but got ok", name); 677 } 678 } 679 680 Ok(()) 681 } 682 683 #[test] 684 fn test_too_many_records() -> Result<()> { 685 let recs: usize = u16::MAX as usize + 1; 686 let tests = vec![ 687 ( 688 "Questions", 689 Message { 690 questions: vec![Question::default(); recs], 691 ..Default::default() 692 }, 693 Error::ErrTooManyQuestions, 694 ), 695 ( 696 "Answers", 697 Message { 698 answers: { 699 let mut a = vec![]; 700 for _ in 0..recs { 701 a.push(Resource::default()); 702 } 703 a 704 }, 705 ..Default::default() 706 }, 707 Error::ErrTooManyAnswers, 708 ), 709 ( 710 "Authorities", 711 Message { 712 authorities: { 713 let mut a = vec![]; 714 for _ in 0..recs { 715 a.push(Resource::default()); 716 } 717 a 718 }, 719 ..Default::default() 720 }, 721 Error::ErrTooManyAuthorities, 722 ), 723 ( 724 "Additionals", 725 Message { 726 additionals: { 727 let mut a = vec![]; 728 for _ in 0..recs { 729 a.push(Resource::default()); 730 } 731 a 732 }, 733 ..Default::default() 734 }, 735 Error::ErrTooManyAdditionals, 736 ), 737 ]; 738 739 for (name, mut msg, want) in tests { 740 if let Err(got) = msg.pack() { 741 assert_eq!( 742 got, want, 743 "got Message.Pack() for {} = {}, want = {}", 744 name, got, want 745 ) 746 } else { 747 panic!("expected error, but got ok"); 748 } 749 } 750 751 Ok(()) 752 } 753 754 #[test] 755 fn test_very_long_txt() -> Result<()> { 756 let mut str255 = String::new(); 757 for _ in 0..255 { 758 str255.push('.'); 759 } 760 761 let mut want = Resource { 762 header: ResourceHeader { 763 name: Name::new("foo.bar.example.com.")?, 764 typ: DnsType::Txt, 765 class: DNSCLASS_INET, 766 ..Default::default() 767 }, 768 body: Some(Box::new(TxtResource { 769 txt: vec![ 770 "".to_owned(), 771 "".to_owned(), 772 "foo bar".to_owned(), 773 "".to_owned(), 774 "www.example.com".to_owned(), 775 "www.example.com.".to_owned(), 776 str255, 777 ], 778 })), 779 }; 780 781 let buf = want.pack(vec![], &mut Some(HashMap::new()), 0)?; 782 let mut got = Resource::default(); 783 let off = got.header.unpack(&buf, 0, 0)?; 784 let (body, n) = unpack_resource_body(got.header.typ, &buf, off, got.header.length as usize)?; 785 got.body = Some(body); 786 assert_eq!( 787 n, 788 buf.len(), 789 "unpacked different amount than packed: got = {}, want = {}", 790 n, 791 buf.len(), 792 ); 793 assert_eq!(got.to_string(), want.to_string()); 794 795 Ok(()) 796 } 797 798 #[test] 799 fn test_too_long_txt() -> Result<()> { 800 let mut str256 = String::new(); 801 for _ in 0..256 { 802 str256.push('.'); 803 } 804 let rb = TxtResource { txt: vec![str256] }; 805 if let Err(err) = rb.pack(vec![], &mut Some(HashMap::new()), 0) { 806 assert_eq!(err, Error::ErrStringTooLong); 807 } else { 808 panic!("expected error, but got ok"); 809 } 810 811 Ok(()) 812 } 813 814 #[test] 815 fn test_start_error() -> Result<()> { 816 let tests: Vec<(&str, Box<dyn Fn(&mut Builder) -> Result<()>>)> = vec![ 817 ( 818 "Questions", 819 Box::new(|b: &mut Builder| -> Result<()> { b.start_questions() }), 820 ), 821 ( 822 "Answers", 823 Box::new(|b: &mut Builder| -> Result<()> { b.start_answers() }), 824 ), 825 ( 826 "Authorities", 827 Box::new(|b: &mut Builder| -> Result<()> { b.start_authorities() }), 828 ), 829 ( 830 "Additionals", 831 Box::new(|b: &mut Builder| -> Result<()> { b.start_additionals() }), 832 ), 833 ]; 834 835 let envs: Vec<(&str, Box<dyn Fn() -> Builder>, Error)> = vec![ 836 ( 837 "sectionNotStarted", 838 Box::new(|| -> Builder { 839 Builder { 840 section: Section::NotStarted, 841 ..Default::default() 842 } 843 }), 844 Error::ErrNotStarted, 845 ), 846 ( 847 "sectionDone", 848 Box::new(|| -> Builder { 849 Builder { 850 section: Section::Done, 851 ..Default::default() 852 } 853 }), 854 Error::ErrSectionDone, 855 ), 856 ]; 857 858 for (env_name, env_fn, env_err) in &envs { 859 for (test_name, test_fn) in &tests { 860 let mut b = env_fn(); 861 if let Err(got_err) = test_fn(&mut b) { 862 assert_eq!( 863 got_err, *env_err, 864 "got Builder{}.{} = {}, want = {}", 865 env_name, test_name, got_err, env_err 866 ); 867 } else { 868 panic!("{}.{}expected error, but got ok", env_name, test_name); 869 } 870 } 871 } 872 873 Ok(()) 874 } 875 876 #[test] 877 fn test_builder_resource_error() -> Result<()> { 878 let tests: Vec<(&str, Box<dyn Fn(&mut Builder) -> Result<()>>)> = vec![ 879 ( 880 "CNAMEResource", 881 Box::new(|b: &mut Builder| -> Result<()> { 882 b.add_resource(&mut Resource { 883 header: ResourceHeader::default(), 884 body: Some(Box::<CnameResource>::default()), 885 }) 886 }), 887 ), 888 ( 889 "MXResource", 890 Box::new(|b: &mut Builder| -> Result<()> { 891 b.add_resource(&mut Resource { 892 header: ResourceHeader::default(), 893 body: Some(Box::<MxResource>::default()), 894 }) 895 }), 896 ), 897 ( 898 "NSResource", 899 Box::new(|b: &mut Builder| -> Result<()> { 900 b.add_resource(&mut Resource { 901 header: ResourceHeader::default(), 902 body: Some(Box::<NsResource>::default()), 903 }) 904 }), 905 ), 906 ( 907 "PTRResource", 908 Box::new(|b: &mut Builder| -> Result<()> { 909 b.add_resource(&mut Resource { 910 header: ResourceHeader::default(), 911 body: Some(Box::<PtrResource>::default()), 912 }) 913 }), 914 ), 915 ( 916 "SOAResource", 917 Box::new(|b: &mut Builder| -> Result<()> { 918 b.add_resource(&mut Resource { 919 header: ResourceHeader::default(), 920 body: Some(Box::<SoaResource>::default()), 921 }) 922 }), 923 ), 924 ( 925 "TXTResource", 926 Box::new(|b: &mut Builder| -> Result<()> { 927 b.add_resource(&mut Resource { 928 header: ResourceHeader::default(), 929 body: Some(Box::<TxtResource>::default()), 930 }) 931 }), 932 ), 933 ( 934 "SRVResource", 935 Box::new(|b: &mut Builder| -> Result<()> { 936 b.add_resource(&mut Resource { 937 header: ResourceHeader::default(), 938 body: Some(Box::<SrvResource>::default()), 939 }) 940 }), 941 ), 942 ( 943 "AResource", 944 Box::new(|b: &mut Builder| -> Result<()> { 945 b.add_resource(&mut Resource { 946 header: ResourceHeader::default(), 947 body: Some(Box::<AResource>::default()), 948 }) 949 }), 950 ), 951 ( 952 "AAAAResource", 953 Box::new(|b: &mut Builder| -> Result<()> { 954 b.add_resource(&mut Resource { 955 header: ResourceHeader::default(), 956 body: Some(Box::<AaaaResource>::default()), 957 }) 958 }), 959 ), 960 ( 961 "OPTResource", 962 Box::new(|b: &mut Builder| -> Result<()> { 963 b.add_resource(&mut Resource { 964 header: ResourceHeader::default(), 965 body: Some(Box::<OptResource>::default()), 966 }) 967 }), 968 ), 969 ]; 970 971 let envs: Vec<(&str, Box<dyn Fn() -> Builder>, Error)> = vec![ 972 ( 973 "sectionNotStarted", 974 Box::new(|| -> Builder { 975 Builder { 976 section: Section::NotStarted, 977 ..Default::default() 978 } 979 }), 980 Error::ErrNotStarted, 981 ), 982 ( 983 "sectionHeader", 984 Box::new(|| -> Builder { 985 Builder { 986 section: Section::Header, 987 ..Default::default() 988 } 989 }), 990 Error::ErrNotStarted, 991 ), 992 ( 993 "sectionQuestions", 994 Box::new(|| -> Builder { 995 Builder { 996 section: Section::Questions, 997 ..Default::default() 998 } 999 }), 1000 Error::ErrNotStarted, 1001 ), 1002 ( 1003 "sectionDone", 1004 Box::new(|| -> Builder { 1005 Builder { 1006 section: Section::Done, 1007 ..Default::default() 1008 } 1009 }), 1010 Error::ErrSectionDone, 1011 ), 1012 ]; 1013 1014 for (env_name, env_fn, env_err) in &envs { 1015 for (test_name, test_fn) in &tests { 1016 let mut b = env_fn(); 1017 if let Err(got_err) = test_fn(&mut b) { 1018 assert_eq!( 1019 got_err, *env_err, 1020 "got Builder{}.{} = {}, want = {}", 1021 env_name, test_name, got_err, env_err 1022 ); 1023 } else { 1024 panic!("{}.{}expected error, but got ok", env_name, test_name); 1025 } 1026 } 1027 } 1028 1029 Ok(()) 1030 } 1031 1032 #[test] 1033 fn test_finish_error() -> Result<()> { 1034 let mut b = Builder::default(); 1035 let want = Error::ErrNotStarted; 1036 if let Err(got) = b.finish() { 1037 assert_eq!(got, want, "got Builder.Finish() = {}, want = {}", got, want); 1038 } else { 1039 panic!("expected error, but got ok"); 1040 } 1041 1042 Ok(()) 1043 } 1044 1045 #[test] 1046 fn test_builder() -> Result<()> { 1047 let mut msg = large_test_msg()?; 1048 let want = msg.pack()?; 1049 1050 let mut b = Builder::new(&msg.header); 1051 b.enable_compression(); 1052 1053 b.start_questions()?; 1054 for q in &msg.questions { 1055 b.add_question(q)?; 1056 } 1057 1058 b.start_answers()?; 1059 for r in &mut msg.answers { 1060 b.add_resource(r)?; 1061 } 1062 1063 b.start_authorities()?; 1064 for r in &mut msg.authorities { 1065 b.add_resource(r)?; 1066 } 1067 1068 b.start_additionals()?; 1069 for r in &mut msg.additionals { 1070 b.add_resource(r)?; 1071 } 1072 1073 let got = b.finish()?; 1074 assert_eq!( 1075 got, 1076 want, 1077 "got.len()={}, want.len()={}", 1078 got.len(), 1079 want.len() 1080 ); 1081 1082 Ok(()) 1083 } 1084 1085 #[test] 1086 fn test_resource_pack() -> Result<()> { 1087 let tests = vec![ 1088 ( 1089 Message { 1090 questions: vec![Question { 1091 name: Name::new(".")?, 1092 typ: DnsType::Aaaa, 1093 class: DNSCLASS_INET, 1094 }], 1095 answers: vec![Resource { 1096 header: ResourceHeader::default(), 1097 body: None, 1098 }], 1099 ..Default::default() 1100 }, 1101 Error::ErrNilResourceBody, 1102 ), 1103 ( 1104 Message { 1105 questions: vec![Question { 1106 name: Name::new(".")?, 1107 typ: DnsType::Aaaa, 1108 class: DNSCLASS_INET, 1109 }], 1110 authorities: vec![Resource { 1111 header: ResourceHeader::default(), 1112 body: Some(Box::<NsResource>::default()), 1113 }], 1114 ..Default::default() 1115 }, 1116 Error::ErrNonCanonicalName, 1117 ), 1118 ( 1119 Message { 1120 questions: vec![Question { 1121 name: Name::new(".")?, 1122 typ: DnsType::A, 1123 class: DNSCLASS_INET, 1124 }], 1125 additionals: vec![Resource { 1126 header: ResourceHeader::default(), 1127 body: None, 1128 }], 1129 ..Default::default() 1130 }, 1131 Error::ErrNilResourceBody, 1132 ), 1133 ]; 1134 1135 for (mut m, want_err) in tests { 1136 if let Err(err) = m.pack() { 1137 assert_eq!(err, want_err); 1138 } else { 1139 panic!("expected error, but got ok"); 1140 } 1141 } 1142 1143 Ok(()) 1144 } 1145 1146 #[test] 1147 fn test_resource_pack_length() -> Result<()> { 1148 let mut r = Resource { 1149 header: ResourceHeader { 1150 name: Name::new(".")?, 1151 typ: DnsType::A, 1152 class: DNSCLASS_INET, 1153 ..Default::default() 1154 }, 1155 body: Some(Box::new(AResource { a: [127, 0, 0, 2] })), 1156 }; 1157 1158 let (hb, _) = r.header.pack(vec![], &mut None, 0)?; 1159 let buf = r.pack(vec![], &mut None, 0)?; 1160 1161 let mut hdr = ResourceHeader::default(); 1162 hdr.unpack(&buf, 0, 0)?; 1163 1164 let (got, want) = (hdr.length as usize, buf.len() - hb.len()); 1165 assert_eq!(got, want, "got hdr.Length = {}, want = {}", got, want); 1166 1167 Ok(()) 1168 } 1169 1170 #[test] 1171 fn test_option_pack_unpack() -> Result<()> { 1172 let tests = vec![ 1173 ( 1174 "without EDNS(0) options", 1175 vec![ 1176 0x00, 0x00, 0x29, 0x10, 0x00, 0xfe, 0x00, 0x80, 0x00, 0x00, 0x00, 1177 ], 1178 Message { 1179 header: Header { 1180 rcode: RCode::FormatError, 1181 ..Default::default() 1182 }, 1183 questions: vec![Question { 1184 name: Name::new(".")?, 1185 typ: DnsType::A, 1186 class: DNSCLASS_INET, 1187 }], 1188 additionals: vec![Resource { 1189 header: must_edns0_resource_header( 1190 4096, 1191 0xfe0 | RCode::FormatError as u32, 1192 true, 1193 )?, 1194 body: Some(Box::<OptResource>::default()), 1195 }], 1196 ..Default::default() 1197 }, 1198 //true, 1199 //0xfe0 | RCode::FormatError as u32, 1200 ), 1201 ( 1202 "with EDNS(0) options", 1203 vec![ 1204 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x0c, 0x00, 1205 0x02, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x02, 0x12, 0x34, 1206 ], 1207 Message { 1208 header: Header { 1209 rcode: RCode::ServerFailure, 1210 ..Default::default() 1211 }, 1212 questions: vec![Question { 1213 name: Name::new(".")?, 1214 typ: DnsType::Aaaa, 1215 class: DNSCLASS_INET, 1216 }], 1217 additionals: vec![Resource { 1218 header: must_edns0_resource_header( 1219 4096, 1220 0xff0 | RCode::ServerFailure as u32, 1221 false, 1222 )?, 1223 body: Some(Box::new(OptResource { 1224 options: vec![ 1225 DnsOption { 1226 code: 12, // see RFC 7828 1227 data: vec![0x00, 0x00], 1228 }, 1229 DnsOption { 1230 code: 11, // see RFC 7830 1231 data: vec![0x12, 0x34], 1232 }, 1233 ], 1234 })), 1235 }], 1236 ..Default::default() 1237 }, 1238 //dnssecOK: false, 1239 //extRCode: 0xff0 | RCodeServerFailure, 1240 ), 1241 ( 1242 // Containing multiple OPT resources in a 1243 // message is invalid, but it's necessary for 1244 // protocol conformance testing. 1245 "with multiple OPT resources", 1246 vec![ 1247 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x0b, 0x00, 1248 0x02, 0x12, 0x34, 0x00, 0x00, 0x29, 0x10, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x06, 1249 0x00, 0x0c, 0x00, 0x02, 0x00, 0x00, 1250 ], 1251 Message { 1252 header: Header { 1253 rcode: RCode::NameError, 1254 ..Default::default() 1255 }, 1256 questions: vec![Question { 1257 name: Name::new(".")?, 1258 typ: DnsType::Aaaa, 1259 class: DNSCLASS_INET, 1260 }], 1261 additionals: vec![ 1262 Resource { 1263 header: must_edns0_resource_header( 1264 4096, 1265 0xff0 | RCode::NameError as u32, 1266 false, 1267 )?, 1268 body: Some(Box::new(OptResource { 1269 options: vec![DnsOption { 1270 code: 11, // see RFC 7830 1271 data: vec![0x12, 0x34], 1272 }], 1273 })), 1274 }, 1275 Resource { 1276 header: must_edns0_resource_header( 1277 4096, 1278 0xff0 | RCode::NameError as u32, 1279 false, 1280 )?, 1281 body: Some(Box::new(OptResource { 1282 options: vec![DnsOption { 1283 code: 12, // see RFC 7828 1284 data: vec![0x00, 0x00], 1285 }], 1286 })), 1287 }, 1288 ], 1289 ..Default::default() 1290 }, 1291 ), 1292 ]; 1293 1294 for (_tt_name, tt_w, mut tt_m) in tests { 1295 let w = tt_m.pack()?; 1296 1297 assert_eq!(&w[w.len() - tt_w.len()..], &tt_w[..]); 1298 1299 let mut m = Message::default(); 1300 m.unpack(&w)?; 1301 1302 let ms: Vec<String> = m.additionals.iter().map(|s| s.to_string()).collect(); 1303 let tt_ms: Vec<String> = tt_m.additionals.iter().map(|s| s.to_string()).collect(); 1304 assert_eq!(ms, tt_ms); 1305 } 1306 1307 Ok(()) 1308 } 1309