1use hickory_proto::rr::{DNSClass, LowerName, RData, RecordData, RecordType, RrKey};
2
3use super::{AsHickory, SerialNumber, record::Record, ttl::TimeToLive};
4use hickory_proto::rr::Name;
5
6#[derive(Debug, Clone, PartialEq)]
14pub struct RecordSet {
15 name: Name,
16 record_type: RecordType,
17 dns_class: DNSClass,
18 ttl: TimeToLive,
19 records: Vec<Record>,
20 rrsigs: Vec<Record>,
21 serial: SerialNumber,
22}
23
24impl RecordSet {
25 pub fn new(name: Name, record_type: RecordType) -> Self {
39 Self {
40 name,
41 record_type,
42 dns_class: DNSClass::IN,
43 ttl: TimeToLive::ZERO,
44 records: Vec::new(),
45 rrsigs: Vec::new(),
46 serial: SerialNumber::ZERO,
47 }
48 }
49
50 pub fn from_record<R: RecordData>(name: Name, record: Record<R>) -> Self {
63 let record = record.into_record_rdata();
64 let mut rrset = Self {
65 name,
66 record_type: record.record_type(),
67 dns_class: DNSClass::IN,
68 ttl: record.ttl(),
69 records: Vec::new(),
70 rrsigs: Vec::new(),
71 serial: SerialNumber::ZERO,
72 };
73 rrset.records.push(record);
75 rrset
76 }
77
78 pub fn name(&self) -> &Name {
86 &self.name
87 }
88
89 pub fn record_type(&self) -> RecordType {
98 self.record_type
99 }
100
101 pub fn dns_class(&self) -> DNSClass {
110 self.dns_class
111 }
112
113 pub fn set_dns_class(&mut self, dns_class: DNSClass) -> &mut Self {
125 self.dns_class = dns_class;
126 self
127 }
128
129 pub fn set_ttl(&mut self, ttl: TimeToLive) -> &mut Self {
142 self.ttl = ttl;
143 for r in &mut self.records {
144 r.set_ttl(ttl);
145 }
146 self
147 }
148
149 pub fn with_name(&self, name: Name) -> Self {
162 RecordSet {
163 name: name.clone(),
164 record_type: self.record_type,
165 dns_class: self.dns_class,
166 ttl: self.ttl,
167 serial: self.serial,
168 records: self.records.clone(),
169 rrsigs: Default::default(),
170 }
171 }
172
173 pub fn ttl(&self) -> TimeToLive {
182 self.ttl
183 }
184
185 pub fn serial(&self) -> SerialNumber {
193 self.serial
194 }
195}
196
197impl RecordSet {
198 pub fn rrkey(&self) -> RrKey {
200 RrKey::new(self.name().into(), self.record_type())
201 }
202
203 pub fn records(&self) -> impl Iterator<Item = &Record> {
212 self.records.iter()
213 }
214
215 pub(crate) fn records_mut(&mut self) -> impl Iterator<Item = &mut Record> {
216 self.records.iter_mut()
217 }
218
219 pub fn into_records(self) -> impl Iterator<Item = Record> {
228 self.records.into_iter()
229 }
230
231 pub fn into_signed_records(self) -> impl Iterator<Item = Record> {
240 self.records.into_iter().chain(self.rrsigs)
241 }
242
243 pub fn signed_records(&self) -> impl Iterator<Item = &Record> {
252 self.records.iter().chain(self.rrsigs.iter())
253 }
254
255 pub fn is_empty(&self) -> bool {
264 self.records.is_empty()
265 }
266
267 pub fn len(&self) -> usize {
276 self.records.len()
277 }
278
279 pub fn rrsigs(&self) -> &[Record] {
288 &self.rrsigs
289 }
290
291 #[allow(dead_code)]
292 pub(crate) fn rrsigs_mut(&mut self) -> &mut Vec<Record> {
293 &mut self.rrsigs
294 }
295
296 pub fn insert_rrsig(&mut self, rrsig: Record) -> Result<(), Mismatch> {
313 if rrsig
314 .rdata()
315 .as_dnssec()
316 .and_then(|dnssecdata| dnssecdata.as_rrsig())
317 .map(|rrsig| rrsig.type_covered())
318 != Some(self.record_type)
319 {
320 return Err(Mismatch("RRSIG Covered type"));
321 }
322
323 self.rrsigs.push(rrsig);
324 Ok(())
325 }
326
327 pub fn clear_rrsigs(&mut self) {
332 self.rrsigs.clear()
333 }
334
335 pub fn push(&mut self, rdata: RData) -> Result<bool, Mismatch> {
353 let record = Record::from_rdata(self.name.clone(), self.ttl, rdata);
354 self.insert(record, SerialNumber::ZERO)
355 }
356
357 fn updated(&mut self, serial: SerialNumber) {
358 self.serial = serial;
359 self.rrsigs.clear(); }
361
362 pub fn insert(&mut self, record: Record, serial: SerialNumber) -> Result<bool, Mismatch> {
382 if record.name() != self.name() {
383 return Err(Mismatch("name"));
384 }
385 if record.record_type() != self.record_type() {
386 return Err(Mismatch("type"));
387 }
388
389 match record.record_type() {
396 RecordType::SOA => {
397 assert!(self.records.len() <= 1);
398
399 if let Some(soa_record) = self.records.first() {
403 match soa_record.rdata() {
404 RData::SOA(existing_soa) => {
405 if let RData::SOA(new_soa) = record.rdata() {
406 if SerialNumber::from(new_soa.serial())
407 <= SerialNumber::from(existing_soa.serial())
408 {
409 tracing::debug!(
410 "update SOA ignored serial out of date: {:?} <= {:?}",
411 new_soa,
412 existing_soa
413 );
414 return Ok(false);
415 }
416 }
417 }
418 _ => unreachable!("Wrong rdata, expected SOA rdata"),
419 }
420 }
421 self.records.clear();
422 }
423 RecordType::CNAME | RecordType::ANAME => {
427 assert!(self.records.len() <= 1);
428 self.records.clear();
429 }
430 _ => (),
431 };
432
433 let mut ttl_modified = false;
434 let mut found = false;
435
436 for target in &mut self.records {
437 if target.rdata() == record.rdata() {
438 found = true;
439 if target.ttl() != record.ttl() {
440 ttl_modified = true
442 }
443 if target.expires() != record.expires() {
444 if let Some(expires) = record.expires() {
447 target.set_expires(expires);
448 } else {
449 target.clear_expires();
450 }
451 }
452 }
453 }
454
455 if ttl_modified {
456 self.set_ttl(record.ttl());
457 self.updated(serial);
458 return Ok(true);
459 }
460
461 if !found {
462 self.set_ttl(record.ttl());
463 self.records.push(record);
464 self.updated(serial);
465 return Ok(true);
466 }
467
468 Ok(false)
469 }
470
471 pub fn remove(&mut self, record: &Record, serial: SerialNumber) -> Result<bool, Mismatch> {
490 if record.name() != self.name() {
491 return Err(Mismatch("name"));
492 }
493 if record.record_type() != self.record_type() {
494 return Err(Mismatch("type"));
495 }
496
497 match record.record_type() {
498 RecordType::NS => {
500 if self.records.len() <= 1 {
501 tracing::warn!("ignoring delete of last NS record: {:?}", record);
502 return Ok(false);
503 }
504 }
505 RecordType::SOA => {
507 tracing::warn!("ignored delete of SOA");
508 return Ok(false);
509 }
510 _ => (), }
512
513 let before = self.records.len();
514 self.records
515 .retain(|target| target.rdata() != record.rdata());
516 if before != self.records.len() {
517 self.updated(serial);
518 Ok(true)
519 } else {
520 Ok(false)
521 }
522 }
523
524 pub(crate) fn next_lookup_name(
527 &self,
528 query_type: RecordType,
529 ) -> Option<(LowerName, RecordType)> {
530 match (self.record_type(), query_type) {
531 (t @ RecordType::ANAME, RecordType::A)
532 | (t @ RecordType::ANAME, RecordType::AAAA)
533 | (t @ RecordType::ANAME, RecordType::ANAME) => {
534 self.records().next().and_then(|record| {
535 record
536 .rdata()
537 .as_aname()
538 .map(|aname| (LowerName::new(&aname.0), t))
539 .inspect(|(name, record_type)| {
540 tracing::trace!("Next name: {}, record type: {:?}", name, record_type);
541 })
542 })
543 }
544 (t @ RecordType::NS, RecordType::NS) => self
545 .records()
546 .next()
547 .and_then(|record| record.rdata().as_ns().map(|ns| (LowerName::from(&ns.0), t)))
548 .inspect(|(name, record_type)| {
549 tracing::trace!("Next name: {}, record type: {:?}", name, record_type);
550 }),
551 (t @ RecordType::CNAME, _) => self.records().next().and_then(|record| {
552 record
553 .rdata()
554 .as_cname()
555 .map(|cname| (LowerName::from(&cname.0), t))
556 .inspect(|(name, record_type)| {
557 tracing::trace!("Next name: {}, record type: {:?}", name, record_type);
558 })
559 }),
560 (t @ RecordType::MX, RecordType::MX) => self.records().next().and_then(|record| {
561 record
562 .rdata()
563 .as_mx()
564 .map(|mx| (LowerName::from(mx.exchange()), t))
565 .inspect(|(name, record_type)| {
566 tracing::trace!("Next name: {}, record type: {:?}", name, record_type);
567 })
568 }),
569 (t @ RecordType::SRV, RecordType::SRV) => self.records().next().and_then(|record| {
570 record
571 .rdata()
572 .as_srv()
573 .map(|srv| (LowerName::from(srv.target()), t))
574 .inspect(|(name, record_type)| {
575 tracing::trace!("Next name: {}, record type: {:?}", name, record_type);
576 })
577 }),
578 _ => None,
579 }
580 }
581}
582
583impl From<Record> for RecordSet {
584 fn from(record: Record) -> Self {
585 let mut rrset = RecordSet::new(record.name().clone(), record.record_type());
586 rrset.insert(record, SerialNumber::ZERO).unwrap();
587 rrset
588 }
589}
590
591impl From<hickory_proto::rr::RecordSet> for RecordSet {
592 fn from(value: hickory_proto::rr::RecordSet) -> Self {
593 let mut rrset = RecordSet::new(value.name().clone(), value.record_type());
594 let parts = value.into_parts();
595
596 for record in parts.records {
597 rrset.insert(record.into(), parts.serial.into()).unwrap();
598 }
599 for record in parts.rrsigs {
600 rrset.insert_rrsig(record.into()).unwrap();
601 }
602
603 rrset
604 }
605}
606
607impl AsHickory for RecordSet {
608 type Hickory = hickory_proto::rr::RecordSet;
609
610 fn as_hickory(&self) -> Self::Hickory {
611 let mut rset = hickory_proto::rr::RecordSet::new(
612 self.name().clone(),
613 self.record_type(),
614 self.serial().get(),
615 );
616 for record in self.records() {
617 rset.insert(
618 record.as_hickory().into_record_of_rdata(),
619 self.serial().get(),
620 );
621 }
622
623 for record in self.rrsigs() {
624 rset.insert_rrsig(record.as_hickory().into_record_of_rdata());
625 }
626
627 rset
628 }
629}
630
631#[derive(Debug, Clone, Copy, thiserror::Error)]
636#[error("Mismatched {0} between new record and record set")]
637pub struct Mismatch(pub(super) &'static str);
638
639#[cfg(test)]
640mod tests {
641 use std::net::Ipv4Addr;
642
643 use super::*;
644 use hickory_proto::rr::{RecordType, rdata::A};
645
646 fn create_test_name() -> Name {
647 Name::from_utf8("test.example.com").unwrap()
648 }
649
650 fn create_test_a_record() -> Record {
651 let name = create_test_name();
652 let ttl = TimeToLive::from(300);
653 let rdata = A::new(192, 168, 1, 1);
654 Record::from_rdata(name, ttl, rdata).into_record_rdata()
655 }
656
657 #[test]
658 fn test_recordset_new() {
659 let name = create_test_name();
660 let rrset = RecordSet::new(name.clone(), RecordType::A);
661
662 assert_eq!(rrset.name(), &name);
663 assert_eq!(rrset.record_type(), RecordType::A);
664 assert_eq!(rrset.dns_class(), DNSClass::IN);
665 assert_eq!(rrset.ttl(), TimeToLive::ZERO);
666 assert!(rrset.is_empty());
667 assert_eq!(rrset.len(), 0);
668 assert_eq!(rrset.serial(), SerialNumber::ZERO);
669 }
670
671 #[test]
672 fn test_recordset_from_record() {
673 let name = create_test_name();
674 let record = create_test_a_record();
675 let ttl = record.ttl();
676
677 let rrset = RecordSet::from_record(name.clone(), record);
678
679 assert_eq!(rrset.name(), &name);
680 assert_eq!(rrset.record_type(), RecordType::A);
681 assert_eq!(rrset.dns_class(), DNSClass::IN);
682 assert_eq!(rrset.ttl(), ttl);
683 assert!(!rrset.is_empty());
684 assert_eq!(rrset.len(), 1);
685 }
686
687 #[test]
688 fn test_recordset_with_name() {
689 let name1 = create_test_name();
690 let name2 = Name::from_utf8("other.example.com").unwrap();
691 let record = create_test_a_record();
692
693 let rrset1 = RecordSet::from_record(name1, record);
694 let rrset2 = rrset1.with_name(name2.clone());
695
696 assert_eq!(rrset2.name(), &name2);
697 assert_eq!(rrset2.record_type(), RecordType::A);
698 assert_eq!(rrset2.len(), 1);
699 assert!(rrset2.rrsigs().is_empty()); }
701
702 #[test]
703 fn test_recordset_push() {
704 let name = create_test_name();
705 let mut rrset = RecordSet::new(name, RecordType::A);
706 let rdata = RData::A(A::new(192, 168, 1, 1));
707
708 let result = rrset.push(rdata);
709 assert!(result.is_ok());
710 assert!(result.unwrap());
711 assert_eq!(rrset.len(), 1);
712 assert!(!rrset.is_empty());
713 }
714
715 #[test]
716 fn test_recordset_set_ttl() {
717 let name = create_test_name();
718 let record = create_test_a_record();
719 let mut rrset = RecordSet::from_record(name, record);
720
721 let new_ttl = TimeToLive::from(600);
722 rrset.set_ttl(new_ttl);
723
724 assert_eq!(rrset.ttl(), new_ttl);
725 for record in rrset.records() {
726 assert_eq!(record.ttl(), new_ttl);
727 }
728 }
729
730 #[test]
731 fn test_recordset_set_dns_class() {
732 let name = create_test_name();
733 let mut rrset = RecordSet::new(name, RecordType::A);
734
735 rrset.set_dns_class(DNSClass::CH);
736 assert_eq!(rrset.dns_class(), DNSClass::CH);
737 }
738
739 #[test]
740 fn test_recordset_insert_duplicate() {
741 let name = create_test_name();
742 let mut rrset = RecordSet::new(name.clone(), RecordType::A);
743 let rdata = RData::A(A::new(192, 168, 1, 1));
744
745 let record1 = Record::from_rdata(name.clone(), TimeToLive::from(300), rdata.clone())
747 .into_record_rdata();
748 let result1 = rrset.insert(record1, SerialNumber::from(1));
749 assert!(result1.is_ok());
750 assert!(result1.unwrap());
751 assert_eq!(rrset.len(), 1);
752
753 let record2 = Record::from_rdata(name, TimeToLive::from(300), rdata).into_record_rdata();
755 let result2 = rrset.insert(record2, SerialNumber::from(2));
756 assert!(result2.is_ok());
757 assert!(!result2.unwrap()); assert_eq!(rrset.len(), 1); }
760
761 #[test]
762 fn test_recordset_insert_wrong_name() {
763 let name1 = create_test_name();
764 let name2 = Name::from_utf8("other.example.com").unwrap();
765 let mut rrset = RecordSet::new(name1, RecordType::A);
766
767 let record = Record::from_rdata(
768 name2,
769 TimeToLive::from(300),
770 RData::A(A::new(192, 168, 1, 1)),
771 )
772 .into_record_rdata();
773 let result = rrset.insert(record, SerialNumber::from(1));
774
775 assert!(result.is_err());
776 if let Err(Mismatch(msg)) = result {
777 assert_eq!(msg, "name");
778 }
779 }
780
781 #[test]
782 fn test_recordset_insert_wrong_type() {
783 let name = create_test_name();
784 let mut rrset = RecordSet::new(name.clone(), RecordType::A);
785
786 let record = Record::from_rdata(
787 name,
788 TimeToLive::from(300),
789 RData::CNAME(hickory_proto::rr::rdata::CNAME(
790 Name::from_utf8("target.example.com").unwrap(),
791 )),
792 )
793 .into_record_rdata();
794 let result = rrset.insert(record, SerialNumber::from(1));
795
796 assert!(result.is_err());
797 if let Err(Mismatch(msg)) = result {
798 assert_eq!(msg, "type");
799 }
800 }
801
802 #[test]
803 fn test_recordset_remove() {
804 let name = create_test_name();
805 let mut rrset = RecordSet::new(name.clone(), RecordType::A);
806 let rdata = RData::A(A::new(192, 168, 1, 1));
807 let record = Record::from_rdata(name, TimeToLive::from(300), rdata).into_record_rdata();
808
809 rrset.insert(record.clone(), SerialNumber::from(1)).unwrap();
811 assert_eq!(rrset.len(), 1);
812
813 let result = rrset.remove(&record, SerialNumber::from(2));
815 assert!(result.is_ok());
816 assert!(result.unwrap());
817 assert_eq!(rrset.len(), 0);
818 assert!(rrset.is_empty());
819 }
820
821 #[test]
822 fn test_recordset_rrkey() {
823 let name = create_test_name();
824 let rrset = RecordSet::new(name.clone(), RecordType::A);
825 let rrkey = rrset.rrkey();
826
827 assert_eq!(rrkey.name(), &LowerName::from(name));
828 assert_eq!(rrkey.record_type, RecordType::A);
829 }
830
831 #[test]
832 fn test_recordset_iterators() {
833 let name = create_test_name();
834 let record = create_test_a_record();
835 let rrset = RecordSet::from_record(name, record);
836
837 assert_eq!(rrset.records().count(), 1);
839
840 let records: Vec<_> = rrset.clone().into_records().collect();
842 assert_eq!(records.len(), 1);
843
844 assert_eq!(rrset.signed_records().count(), 1);
846
847 let signed_records: Vec<_> = rrset.into_signed_records().collect();
849 assert_eq!(signed_records.len(), 1);
850 }
851
852 #[test]
853 fn test_recordset_rrsigs() {
854 let name = create_test_name();
855 let mut rrset = RecordSet::new(name, RecordType::A);
856
857 assert!(rrset.rrsigs().is_empty());
858
859 rrset.clear_rrsigs();
861 assert!(rrset.rrsigs().is_empty());
862 }
863
864 #[test]
865 fn test_recordset_as_hickory() {
866 let name = create_test_name();
867 let record = create_test_a_record();
868 let rrset = RecordSet::from_record(name.clone(), record);
869
870 let hickory_rrset = rrset.as_hickory();
871 assert_eq!(hickory_rrset.name(), &name);
872 assert_eq!(hickory_rrset.record_type(), RecordType::A);
873 }
874
875 #[test]
876 fn test_mismatch_error() {
877 let mismatch = Mismatch("test");
878 assert_eq!(
879 format!("{mismatch}"),
880 "Mismatched test between new record and record set"
881 );
882 }
883
884 #[test]
885 fn test_recordset_clone() {
886 let name = create_test_name();
887 let record = create_test_a_record();
888 let rrset1 = RecordSet::from_record(name, record);
889 let rrset2 = rrset1.clone();
890
891 assert_eq!(rrset1, rrset2);
892 assert_eq!(rrset1.name(), rrset2.name());
893 assert_eq!(rrset1.len(), rrset2.len());
894 }
895
896 #[test]
897 fn test_recordset_soa_serial_number_handling() {
898 use hickory_proto::rr::rdata::SOA;
899
900 let name = create_test_name();
901 let mut rrset = RecordSet::new(name.clone(), RecordType::SOA);
902
903 let soa1 = SOA::new(
905 name.clone(),
906 Name::from_utf8("admin.example.com").unwrap(),
907 100, 3600,
909 1800,
910 604800,
911 86400,
912 );
913 let record1 =
914 Record::from_rdata(name.clone(), TimeToLive::from(3600), soa1).into_record_rdata();
915
916 let result = rrset.insert(record1, SerialNumber::from(1));
918 assert!(result.is_ok());
919 assert!(result.unwrap()); assert_eq!(rrset.len(), 1);
921
922 let soa2 = SOA::new(
924 name.clone(),
925 Name::from_utf8("admin.example.com").unwrap(),
926 50, 3600,
928 1800,
929 604800,
930 86400,
931 );
932 let record2 =
933 Record::from_rdata(name.clone(), TimeToLive::from(3600), soa2).into_record_rdata();
934
935 let result = rrset.insert(record2, SerialNumber::from(2));
936 assert!(result.is_ok());
937 assert!(!result.unwrap()); assert_eq!(rrset.len(), 1); let soa3 = SOA::new(
942 name.clone(),
943 Name::from_utf8("admin.example.com").unwrap(),
944 200, 3600,
946 1800,
947 604800,
948 86400,
949 );
950 let record3 = Record::from_rdata(name, TimeToLive::from(3600), soa3).into_record_rdata();
951
952 let result = rrset.insert(record3, SerialNumber::from(3));
953 assert!(result.is_ok());
954 assert!(result.unwrap()); assert_eq!(rrset.len(), 1); let soa_record = rrset.records().next().unwrap();
959 if let RData::SOA(soa) = soa_record.rdata() {
960 assert_eq!(soa.serial(), 200);
961 } else {
962 panic!("Expected SOA record");
963 }
964 }
965
966 #[test]
967 fn test_recordset_ns_last_record_protection() {
968 use hickory_proto::rr::rdata::NS;
969
970 let name = create_test_name();
971 let mut rrset = RecordSet::new(name.clone(), RecordType::NS);
972
973 let ns1 = NS(Name::from_utf8("ns1.example.com").unwrap());
975 let record1 = Record::from_rdata(name.clone(), TimeToLive::from(86400), ns1.clone())
976 .into_record_rdata();
977 rrset
978 .insert(record1.clone(), SerialNumber::from(1))
979 .unwrap();
980 assert_eq!(rrset.len(), 1);
981
982 let ns2 = NS(Name::from_utf8("ns2.example.com").unwrap());
984 let record2 =
985 Record::from_rdata(name.clone(), TimeToLive::from(86400), ns2).into_record_rdata();
986 rrset
987 .insert(record2.clone(), SerialNumber::from(2))
988 .unwrap();
989 assert_eq!(rrset.len(), 2);
990
991 let result = rrset.remove(&record1, SerialNumber::from(3));
993 assert!(result.is_ok());
994 assert!(result.unwrap()); assert_eq!(rrset.len(), 1);
996
997 let result = rrset.remove(&record2, SerialNumber::from(4));
999 assert!(result.is_ok());
1000 assert!(!result.unwrap()); assert_eq!(rrset.len(), 1); }
1003
1004 #[test]
1005 fn test_recordset_soa_deletion_protection() {
1006 use hickory_proto::rr::rdata::SOA;
1007
1008 let name = create_test_name();
1009 let mut rrset = RecordSet::new(name.clone(), RecordType::SOA);
1010
1011 let soa = SOA::new(
1013 name.clone(),
1014 Name::from_utf8("admin.example.com").unwrap(),
1015 1,
1016 3600,
1017 1800,
1018 604800,
1019 86400,
1020 );
1021 let record = Record::from_rdata(name, TimeToLive::from(3600), soa).into_record_rdata();
1022 rrset.insert(record.clone(), SerialNumber::from(1)).unwrap();
1023 assert_eq!(rrset.len(), 1);
1024
1025 let result = rrset.remove(&record, SerialNumber::from(2));
1027 assert!(result.is_ok());
1028 assert!(!result.unwrap()); assert_eq!(rrset.len(), 1); }
1031
1032 #[test]
1033 fn test_recordset_cname_replacement() {
1034 use hickory_proto::rr::rdata::CNAME;
1035
1036 let name = create_test_name();
1037 let mut rrset = RecordSet::new(name.clone(), RecordType::CNAME);
1038
1039 let cname1 = CNAME(Name::from_utf8("target1.example.com").unwrap());
1041 let record1 =
1042 Record::from_rdata(name.clone(), TimeToLive::from(300), cname1).into_record_rdata();
1043 rrset.insert(record1, SerialNumber::from(1)).unwrap();
1044 assert_eq!(rrset.len(), 1);
1045
1046 let cname2 = CNAME(Name::from_utf8("target2.example.com").unwrap());
1048 let record2 = Record::from_rdata(name, TimeToLive::from(300), cname2).into_record_rdata();
1049 rrset.insert(record2, SerialNumber::from(2)).unwrap();
1050 assert_eq!(rrset.len(), 1); let cname_record = rrset.records().next().unwrap();
1054 if let RData::CNAME(cname) = cname_record.rdata() {
1055 assert!(cname.0.to_utf8().starts_with("target2.example.com"));
1056 } else {
1057 panic!("Expected CNAME record");
1058 }
1059 }
1060
1061 #[test]
1062 fn test_recordset_aname_replacement() {
1063 use hickory_proto::rr::rdata::ANAME;
1064
1065 let name = create_test_name();
1066 let mut rrset = RecordSet::new(name.clone(), RecordType::ANAME);
1067
1068 let aname1 = ANAME(Name::from_utf8("target1.example.com").unwrap());
1070 let record1 =
1071 Record::from_rdata(name.clone(), TimeToLive::from(300), aname1).into_record_rdata();
1072 rrset.insert(record1, SerialNumber::from(1)).unwrap();
1073 assert_eq!(rrset.len(), 1);
1074
1075 let aname2 = ANAME(Name::from_utf8("target2.example.com").unwrap());
1077 let record2 = Record::from_rdata(name, TimeToLive::from(300), aname2).into_record_rdata();
1078 rrset.insert(record2, SerialNumber::from(2)).unwrap();
1079 assert_eq!(rrset.len(), 1); let aname_record = rrset.records().next().unwrap();
1083 if let RData::ANAME(aname) = aname_record.rdata() {
1084 assert!(aname.0.to_utf8().starts_with("target2.example.com"));
1085 } else {
1086 panic!("Expected ANAME record");
1087 }
1088 }
1089
1090 #[test]
1091 #[allow(clippy::blocks_in_conditions)]
1092 fn test_get_filter() {
1093 use hickory_proto::dnssec::{
1094 Algorithm,
1095 rdata::{DNSSECRData, RRSIG},
1096 };
1097
1098 let name = Name::root();
1099 let rsasha256 = RRSIG::new(
1100 RecordType::A,
1101 Algorithm::RSASHA256,
1102 0,
1103 0,
1104 0,
1105 0,
1106 0,
1107 Name::root(),
1108 vec![],
1109 );
1110 let ecp256 = RRSIG::new(
1111 RecordType::A,
1112 Algorithm::ECDSAP256SHA256,
1113 0,
1114 0,
1115 0,
1116 0,
1117 0,
1118 Name::root(),
1119 vec![],
1120 );
1121 let ecp384 = RRSIG::new(
1122 RecordType::A,
1123 Algorithm::ECDSAP384SHA384,
1124 0,
1125 0,
1126 0,
1127 0,
1128 0,
1129 Name::root(),
1130 vec![],
1131 );
1132 let ed25519 = RRSIG::new(
1133 RecordType::A,
1134 Algorithm::ED25519,
1135 0,
1136 0,
1137 0,
1138 0,
1139 0,
1140 Name::root(),
1141 vec![],
1142 );
1143
1144 let rrsig_rsa = Record::from_rdata(
1145 name.clone(),
1146 3600.into(),
1147 RData::DNSSEC(DNSSECRData::RRSIG(rsasha256)),
1148 )
1149 .set_dns_class(DNSClass::IN)
1150 .clone();
1151 let rrsig_ecp256 = Record::from_rdata(
1152 name.clone(),
1153 3600.into(),
1154 RData::DNSSEC(DNSSECRData::RRSIG(ecp256)),
1155 )
1156 .set_dns_class(DNSClass::IN)
1157 .clone();
1158 let rrsig_ecp384 = Record::from_rdata(
1159 name.clone(),
1160 3600.into(),
1161 RData::DNSSEC(DNSSECRData::RRSIG(ecp384)),
1162 )
1163 .set_dns_class(DNSClass::IN)
1164 .clone();
1165 let rrsig_ed25519 = Record::from_rdata(
1166 name.clone(),
1167 3600.into(),
1168 RData::DNSSEC(DNSSECRData::RRSIG(ed25519)),
1169 )
1170 .set_dns_class(DNSClass::IN)
1171 .clone();
1172
1173 let a = Record::from_rdata(
1174 name,
1175 3600.into(),
1176 RData::A(Ipv4Addr::new(93, 184, 216, 24).into()),
1177 )
1178 .set_dns_class(DNSClass::IN)
1179 .clone();
1180
1181 let mut rrset = RecordSet::from(a);
1182 rrset.insert_rrsig(rrsig_rsa).unwrap();
1183 rrset.insert_rrsig(rrsig_ecp256).unwrap();
1184 rrset.insert_rrsig(rrsig_ecp384).unwrap();
1185 rrset.insert_rrsig(rrsig_ed25519).unwrap();
1186
1187 assert!(rrset.signed_records().any(|r| {
1188 if let RData::DNSSEC(DNSSECRData::RRSIG(sig)) = r.rdata() {
1189 sig.algorithm() == Algorithm::ED25519
1190 } else {
1191 false
1192 }
1193 },));
1194
1195 assert!(rrset.signed_records().any(|r| {
1196 if let RData::DNSSEC(DNSSECRData::RRSIG(sig)) = r.rdata() {
1197 sig.algorithm() == Algorithm::ECDSAP384SHA384
1198 } else {
1199 false
1200 }
1201 }));
1202
1203 assert!(rrset.signed_records().any(|r| {
1204 if let RData::DNSSEC(DNSSECRData::RRSIG(sig)) = r.rdata() {
1205 sig.algorithm() == Algorithm::ED25519
1206 } else {
1207 false
1208 }
1209 }));
1210 }
1211}