1use std::iter::Chain;
8use std::slice::Iter;
9use std::vec;
10
11use tracing::{info, warn};
12
13use crate::rr::{DNSClass, Name, RData, Record, RecordType};
14
15#[cfg(feature = "dnssec")]
16#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
17use crate::rr::dnssec::SupportedAlgorithms;
18
19#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct RecordSet {
22 name: Name,
23 record_type: RecordType,
24 dns_class: DNSClass,
25 ttl: u32,
26 records: Vec<Record>,
27 rrsigs: Vec<Record>,
28 serial: u32, }
30
31impl RecordSet {
32 pub fn new(name: &Name, record_type: RecordType, serial: u32) -> Self {
47 Self {
48 name: name.clone(),
49 record_type,
50 dns_class: DNSClass::IN,
51 ttl: 0,
52 records: Vec::new(),
53 rrsigs: Vec::new(),
54 serial,
55 }
56 }
57
58 pub fn with_ttl(name: Name, record_type: RecordType, ttl: u32) -> Self {
72 Self {
73 name,
74 record_type,
75 dns_class: DNSClass::IN,
76 ttl,
77 records: Vec::new(),
78 rrsigs: Vec::new(),
79 serial: 0,
80 }
81 }
82
83 pub fn name(&self) -> &Name {
87 &self.name
88 }
89
90 pub fn record_type(&self) -> RecordType {
94 self.record_type
95 }
96
97 pub fn set_dns_class(&mut self, dns_class: DNSClass) {
101 self.dns_class = dns_class;
102 for r in &mut self.records {
103 r.set_dns_class(dns_class);
104 }
105 }
106
107 pub fn dns_class(&self) -> DNSClass {
109 self.dns_class
110 }
111
112 pub fn set_ttl(&mut self, ttl: u32) {
116 self.ttl = ttl;
117 for r in &mut self.records {
118 r.set_ttl(ttl);
119 }
120 }
121
122 pub fn ttl(&self) -> u32 {
129 self.ttl
130 }
131
132 #[cfg(feature = "dnssec")]
140 #[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
141 pub fn records(
142 &self,
143 and_rrsigs: bool,
144 supported_algorithms: SupportedAlgorithms,
145 ) -> RrsetRecords<'_> {
146 if and_rrsigs {
147 self.records_with_rrsigs(supported_algorithms)
148 } else {
149 self.records_without_rrsigs()
150 }
151 }
152
153 #[cfg(feature = "dnssec")]
160 #[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
161 pub fn records_with_rrsigs(
162 &self,
163 supported_algorithms: SupportedAlgorithms,
164 ) -> RrsetRecords<'_> {
165 if self.records.is_empty() {
166 RrsetRecords::Empty
167 } else {
168 let rrsigs = RrsigsByAlgorithms {
169 rrsigs: self.rrsigs.iter(),
170 supported_algorithms,
171 };
172 RrsetRecords::RecordsAndRrsigs(RecordsAndRrsigsIter(self.records.iter().chain(rrsigs)))
173 }
174 }
175
176 pub fn records_without_rrsigs(&self) -> RrsetRecords<'_> {
178 if self.records.is_empty() {
179 RrsetRecords::Empty
180 } else {
181 RrsetRecords::RecordsOnly(self.records.iter())
182 }
183 }
184
185 #[deprecated(note = "see `records_without_rrsigs`")]
187 pub fn iter(&self) -> Iter<'_, Record> {
188 self.records.iter()
189 }
190
191 pub fn is_empty(&self) -> bool {
193 self.records.is_empty()
194 }
195
196 pub fn serial(&self) -> u32 {
198 self.serial
199 }
200
201 pub fn rrsigs(&self) -> &[Record] {
203 &self.rrsigs
204 }
205
206 pub fn insert_rrsig(&mut self, rrsig: Record) {
214 self.rrsigs.push(rrsig)
215 }
216
217 pub fn clear_rrsigs(&mut self) {
219 self.rrsigs.clear()
220 }
221
222 fn updated(&mut self, serial: u32) {
223 self.serial = serial;
224 self.rrsigs.clear(); }
226
227 pub fn new_record(&mut self, rdata: &RData) -> &Record {
231 self.add_rdata(rdata.clone());
232
233 self.records
234 .iter()
235 .find(|r| r.data().map(|r| r == rdata).unwrap_or(false))
236 .expect("insert failed")
237 }
238
239 pub fn add_rdata(&mut self, rdata: RData) -> bool {
241 debug_assert_eq!(self.record_type, rdata.to_record_type());
242
243 let mut record = Record::with(self.name.clone(), self.record_type, self.ttl);
244 record.set_data(Some(rdata));
245 self.insert(record, 0)
246 }
247
248 pub fn insert(&mut self, record: Record, serial: u32) -> bool {
282 assert_eq!(record.name(), &self.name);
283 assert_eq!(record.rr_type(), self.record_type);
284
285 match record.rr_type() {
291 RecordType::SOA => {
295 assert!(self.records.len() <= 1);
296
297 if let Some(soa_record) = self.records.get(0) {
298 match soa_record.data() {
299 Some(RData::SOA(ref existing_soa)) => {
300 if let Some(RData::SOA(ref new_soa)) = record.data() {
301 if new_soa.serial() <= existing_soa.serial() {
302 info!(
303 "update ignored serial out of data: {:?} <= {:?}",
304 new_soa, existing_soa
305 );
306 return false;
307 }
308 } else {
309 info!("wrong rdata for SOA update: {:?}", record.data());
311 return false;
312 }
313 }
314 rdata => {
315 warn!("wrong rdata: {:?}, expected SOA", rdata);
316 return false;
317 }
318 }
319 }
320
321 self.records.clear();
323 }
324 RecordType::CNAME | RecordType::ANAME => {
349 assert!(self.records.len() <= 1);
350 self.records.clear();
351 }
352 _ => (),
353 }
354
355 let to_replace: Vec<usize> = self
357 .records
358 .iter()
359 .enumerate()
360 .filter(|&(_, rr)| rr.data() == record.data())
361 .map(|(i, _)| i)
362 .collect::<Vec<usize>>();
363
364 let mut replaced = false;
366 for i in to_replace {
367 if self.records[i] == record {
368 return false;
369 }
370
371 self.records.push(record.clone());
373 self.records.swap_remove(i);
374 self.ttl = record.ttl();
375 self.updated(serial);
376 replaced = true;
377 }
378
379 if !replaced {
380 self.ttl = record.ttl();
381 self.updated(serial);
382 self.records.push(record);
383 true
384 } else {
385 replaced
386 }
387 }
388
389 pub fn remove(&mut self, record: &Record, serial: u32) -> bool {
403 assert_eq!(record.name(), &self.name);
404 assert!(record.rr_type() == self.record_type || record.rr_type() == RecordType::ANY);
405
406 match record.rr_type() {
407 RecordType::NS => {
409 if self.records.len() <= 1 {
410 info!("ignoring delete of last NS record: {:?}", record);
411 return false;
412 }
413 }
414 RecordType::SOA => {
416 info!("ignored delete of SOA");
417 return false;
418 }
419 _ => (), }
421
422 let to_remove: Vec<usize> = self
424 .records
425 .iter()
426 .enumerate()
427 .filter(|&(_, rr)| rr.data() == record.data())
428 .map(|(i, _)| i)
429 .collect::<Vec<usize>>();
430
431 let mut removed = false;
432 for i in to_remove {
433 self.records.remove(i);
434 removed = true;
435 self.updated(serial);
436 }
437
438 removed
439 }
440
441 pub fn into_parts(self) -> RecordSetParts {
443 self.into()
444 }
445}
446
447#[derive(Clone, Debug, PartialEq, Eq)]
450pub struct RecordSetParts {
451 pub name: Name,
452 pub record_type: RecordType,
453 pub dns_class: DNSClass,
454 pub ttl: u32,
455 pub records: Vec<Record>,
456 pub rrsigs: Vec<Record>,
457 pub serial: u32, }
459
460impl From<RecordSet> for RecordSetParts {
461 fn from(rset: RecordSet) -> Self {
462 let RecordSet {
463 name,
464 record_type,
465 dns_class,
466 ttl,
467 records,
468 rrsigs,
469 serial,
470 } = rset;
471 Self {
472 name,
473 record_type,
474 dns_class,
475 ttl,
476 records,
477 rrsigs,
478 serial,
479 }
480 }
481}
482
483impl From<Record> for RecordSet {
484 fn from(record: Record) -> Self {
485 Self {
486 name: record.name().clone(),
487 record_type: record.rr_type(),
488 dns_class: record.dns_class(),
489 ttl: record.ttl(),
490 records: vec![record],
491 rrsigs: vec![],
492 serial: 0,
493 }
494 }
495}
496
497#[deprecated(note = "use From/Into")]
499pub trait IntoRecordSet: Sized {
500 fn into_record_set(self) -> RecordSet;
502}
503
504#[allow(deprecated)]
505impl IntoRecordSet for RecordSet {
506 fn into_record_set(self) -> Self {
507 self
508 }
509}
510
511impl IntoIterator for RecordSet {
512 type Item = Record;
513 type IntoIter = Chain<vec::IntoIter<Record>, vec::IntoIter<Record>>;
514
515 fn into_iter(self) -> Self::IntoIter {
516 self.records.into_iter().chain(self.rrsigs.into_iter())
517 }
518}
519
520#[cfg(feature = "dnssec")]
522#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
523#[derive(Debug)]
524pub struct RecordsAndRrsigsIter<'r>(Chain<Iter<'r, Record>, RrsigsByAlgorithms<'r>>);
525
526#[cfg(feature = "dnssec")]
527#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
528impl<'r> Iterator for RecordsAndRrsigsIter<'r> {
529 type Item = &'r Record;
530
531 fn next(&mut self) -> Option<Self::Item> {
532 self.0.next()
533 }
534}
535
536#[cfg(feature = "dnssec")]
538#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
539#[derive(Debug)]
540pub(crate) struct RrsigsByAlgorithms<'r> {
541 rrsigs: Iter<'r, Record>,
542 supported_algorithms: SupportedAlgorithms,
543}
544
545#[cfg(feature = "dnssec")]
546#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
547impl<'r> Iterator for RrsigsByAlgorithms<'r> {
548 type Item = &'r Record;
549
550 fn next(&mut self) -> Option<Self::Item> {
551 use crate::rr::dnssec::rdata::DNSSECRData;
552 use crate::rr::dnssec::Algorithm;
553
554 let supported_algorithms = self.supported_algorithms;
555
556 if supported_algorithms.is_empty() {
558 self.rrsigs.next()
559 } else {
560 self.rrsigs
561 .by_ref()
562 .filter(|record| {
563 if let Some(RData::DNSSEC(DNSSECRData::SIG(ref rrsig))) = record.data() {
564 supported_algorithms.has(rrsig.algorithm())
565 } else {
566 false
567 }
568 })
569 .max_by_key(|record| {
570 if let Some(RData::DNSSEC(DNSSECRData::SIG(ref rrsig))) = record.data() {
571 rrsig.algorithm()
572 } else {
573 #[allow(deprecated)]
574 Algorithm::RSASHA1
575 }
576 })
577 }
578 }
579}
580
581#[derive(Debug)]
583pub enum RrsetRecords<'r> {
584 Empty,
586 RecordsOnly(Iter<'r, Record>),
588 #[cfg(feature = "dnssec")]
590 #[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
591 RecordsAndRrsigs(RecordsAndRrsigsIter<'r>),
592}
593
594impl<'r> RrsetRecords<'r> {
595 pub fn is_empty(&self) -> bool {
597 matches!(*self, RrsetRecords::Empty)
598 }
599}
600
601impl<'r> Iterator for RrsetRecords<'r> {
602 type Item = &'r Record;
603
604 fn next(&mut self) -> Option<Self::Item> {
605 match self {
606 RrsetRecords::Empty => None,
607 RrsetRecords::RecordsOnly(i) => i.next(),
608 #[cfg(feature = "dnssec")]
609 RrsetRecords::RecordsAndRrsigs(i) => i.next(),
610 }
611 }
612}
613
614#[cfg(test)]
615mod test {
616 use std::net::Ipv4Addr;
617 use std::str::FromStr;
618
619 use crate::rr::rdata::SOA;
620 use crate::rr::*;
621
622 #[test]
623 fn test_insert() {
624 let name = Name::from_str("www.example.com.").unwrap();
625 let record_type = RecordType::A;
626 let mut rr_set = RecordSet::new(&name, record_type, 0);
627
628 let insert = Record::new()
629 .set_name(name.clone())
630 .set_ttl(86400)
631 .set_rr_type(record_type)
632 .set_dns_class(DNSClass::IN)
633 .set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 24))))
634 .clone();
635
636 assert!(rr_set.insert(insert.clone(), 0));
637 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
638 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
639
640 assert!(!rr_set.insert(insert.clone(), 0));
642 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
643 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
644
645 let insert1 = Record::new()
647 .set_name(name)
648 .set_ttl(86400)
649 .set_rr_type(record_type)
650 .set_dns_class(DNSClass::IN)
651 .set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 25))))
652 .clone();
653 assert!(rr_set.insert(insert1.clone(), 0));
654 assert_eq!(rr_set.records_without_rrsigs().count(), 2);
655 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
656 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert1));
657 }
658
659 #[test]
660 #[allow(clippy::unreadable_literal)]
661 fn test_insert_soa() {
662 let name = Name::from_str("example.com.").unwrap();
663 let record_type = RecordType::SOA;
664 let mut rr_set = RecordSet::new(&name, record_type, 0);
665
666 let insert = Record::new()
667 .set_name(name.clone())
668 .set_ttl(3600)
669 .set_rr_type(RecordType::SOA)
670 .set_dns_class(DNSClass::IN)
671 .set_data(Some(RData::SOA(SOA::new(
672 Name::from_str("sns.dns.icann.org.").unwrap(),
673 Name::from_str("noc.dns.icann.org.").unwrap(),
674 2015082403,
675 7200,
676 3600,
677 1209600,
678 3600,
679 ))))
680 .clone();
681 let same_serial = Record::new()
682 .set_name(name.clone())
683 .set_ttl(3600)
684 .set_rr_type(RecordType::SOA)
685 .set_dns_class(DNSClass::IN)
686 .set_data(Some(RData::SOA(SOA::new(
687 Name::from_str("sns.dns.icann.net.").unwrap(),
688 Name::from_str("noc.dns.icann.net.").unwrap(),
689 2015082403,
690 7200,
691 3600,
692 1209600,
693 3600,
694 ))))
695 .clone();
696 let new_serial = Record::new()
697 .set_name(name)
698 .set_ttl(3600)
699 .set_rr_type(RecordType::SOA)
700 .set_dns_class(DNSClass::IN)
701 .set_data(Some(RData::SOA(SOA::new(
702 Name::from_str("sns.dns.icann.net.").unwrap(),
703 Name::from_str("noc.dns.icann.net.").unwrap(),
704 2015082404,
705 7200,
706 3600,
707 1209600,
708 3600,
709 ))))
710 .clone();
711
712 assert!(rr_set.insert(insert.clone(), 0));
713 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
714 assert!(!rr_set.insert(same_serial.clone(), 0));
716 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
717 assert!(!rr_set
718 .records_without_rrsigs()
719 .any(|ref x| x == &&same_serial));
720
721 assert!(rr_set.insert(new_serial.clone(), 0));
722 assert!(!rr_set.insert(same_serial.clone(), 0));
723 assert!(!rr_set.insert(insert.clone(), 0));
724
725 assert!(rr_set
726 .records_without_rrsigs()
727 .any(|ref x| x == &&new_serial));
728 assert!(!rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
729 assert!(!rr_set
730 .records_without_rrsigs()
731 .any(|ref x| x == &&same_serial));
732 }
733
734 #[test]
735 fn test_insert_cname() {
736 let name = Name::from_str("web.example.com.").unwrap();
737 let cname = Name::from_str("www.example.com.").unwrap();
738 let new_cname = Name::from_str("w2.example.com.").unwrap();
739
740 let record_type = RecordType::CNAME;
741 let mut rr_set = RecordSet::new(&name, record_type, 0);
742
743 let insert = Record::new()
744 .set_name(name.clone())
745 .set_ttl(3600)
746 .set_rr_type(RecordType::CNAME)
747 .set_dns_class(DNSClass::IN)
748 .set_data(Some(RData::CNAME(cname)))
749 .clone();
750 let new_record = Record::new()
751 .set_name(name)
752 .set_ttl(3600)
753 .set_rr_type(RecordType::CNAME)
754 .set_dns_class(DNSClass::IN)
755 .set_data(Some(RData::CNAME(new_cname)))
756 .clone();
757
758 assert!(rr_set.insert(insert.clone(), 0));
759 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
760
761 assert!(rr_set.insert(new_record.clone(), 0));
763 assert!(!rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
764 assert!(rr_set
765 .records_without_rrsigs()
766 .any(|ref x| x == &&new_record));
767 }
768
769 #[test]
770 fn test_remove() {
771 let name = Name::from_str("www.example.com.").unwrap();
772 let record_type = RecordType::A;
773 let mut rr_set = RecordSet::new(&name, record_type, 0);
774
775 let insert = Record::new()
776 .set_name(name.clone())
777 .set_ttl(86400)
778 .set_rr_type(record_type)
779 .set_dns_class(DNSClass::IN)
780 .set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 24))))
781 .clone();
782 let insert1 = Record::new()
783 .set_name(name)
784 .set_ttl(86400)
785 .set_rr_type(record_type)
786 .set_dns_class(DNSClass::IN)
787 .set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 25))))
788 .clone();
789
790 assert!(rr_set.insert(insert.clone(), 0));
791 assert!(rr_set.insert(insert1.clone(), 0));
792
793 assert!(rr_set.remove(&insert, 0));
794 assert!(!rr_set.remove(&insert, 0));
795 assert!(rr_set.remove(&insert1, 0));
796 assert!(!rr_set.remove(&insert1, 0));
797 }
798
799 #[test]
800 #[allow(clippy::unreadable_literal)]
801 fn test_remove_soa() {
802 let name = Name::from_str("www.example.com.").unwrap();
803 let record_type = RecordType::SOA;
804 let mut rr_set = RecordSet::new(&name, record_type, 0);
805
806 let insert = Record::new()
807 .set_name(name)
808 .set_ttl(3600)
809 .set_rr_type(RecordType::SOA)
810 .set_dns_class(DNSClass::IN)
811 .set_data(Some(RData::SOA(SOA::new(
812 Name::from_str("sns.dns.icann.org.").unwrap(),
813 Name::from_str("noc.dns.icann.org.").unwrap(),
814 2015082403,
815 7200,
816 3600,
817 1209600,
818 3600,
819 ))))
820 .clone();
821
822 assert!(rr_set.insert(insert.clone(), 0));
823 assert!(!rr_set.remove(&insert, 0));
824 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
825 }
826
827 #[test]
828 fn test_remove_ns() {
829 let name = Name::from_str("example.com.").unwrap();
830 let record_type = RecordType::NS;
831 let mut rr_set = RecordSet::new(&name, record_type, 0);
832
833 let ns1 = Record::new()
834 .set_name(name.clone())
835 .set_ttl(86400)
836 .set_rr_type(RecordType::NS)
837 .set_dns_class(DNSClass::IN)
838 .set_data(Some(RData::NS(
839 Name::from_str("a.iana-servers.net.").unwrap(),
840 )))
841 .clone();
842 let ns2 = Record::new()
843 .set_name(name)
844 .set_ttl(86400)
845 .set_rr_type(RecordType::NS)
846 .set_dns_class(DNSClass::IN)
847 .set_data(Some(RData::NS(
848 Name::from_str("b.iana-servers.net.").unwrap(),
849 )))
850 .clone();
851
852 assert!(rr_set.insert(ns1.clone(), 0));
853 assert!(rr_set.insert(ns2.clone(), 0));
854
855 assert!(rr_set.remove(&ns1, 0));
857 assert!(!rr_set.remove(&ns2, 0));
858
859 assert!(rr_set.insert(ns1.clone(), 0));
861
862 assert!(rr_set.remove(&ns2, 0));
863 assert!(!rr_set.remove(&ns1, 0));
864 }
865
866 #[test]
867 #[cfg(feature = "dnssec")] #[allow(clippy::blocks_in_if_conditions)]
869 fn test_get_filter() {
870 use crate::rr::dnssec::rdata::DNSSECRData;
871 use crate::rr::dnssec::rdata::SIG;
872 use crate::rr::dnssec::{Algorithm, SupportedAlgorithms};
873
874 let name = Name::root();
875 let rsasha256 = SIG::new(
876 RecordType::A,
877 Algorithm::RSASHA256,
878 0,
879 0,
880 0,
881 0,
882 0,
883 Name::root(),
884 vec![],
885 );
886 let ecp256 = SIG::new(
887 RecordType::A,
888 Algorithm::ECDSAP256SHA256,
889 0,
890 0,
891 0,
892 0,
893 0,
894 Name::root(),
895 vec![],
896 );
897 let ecp384 = SIG::new(
898 RecordType::A,
899 Algorithm::ECDSAP384SHA384,
900 0,
901 0,
902 0,
903 0,
904 0,
905 Name::root(),
906 vec![],
907 );
908 let ed25519 = SIG::new(
909 RecordType::A,
910 Algorithm::ED25519,
911 0,
912 0,
913 0,
914 0,
915 0,
916 Name::root(),
917 vec![],
918 );
919
920 let rrsig_rsa = Record::new()
921 .set_name(name.clone())
922 .set_ttl(3600)
923 .set_rr_type(RecordType::RRSIG)
924 .set_dns_class(DNSClass::IN)
925 .set_data(Some(RData::DNSSEC(DNSSECRData::SIG(rsasha256))))
926 .clone();
927 let rrsig_ecp256 = Record::new()
928 .set_name(name.clone())
929 .set_ttl(3600)
930 .set_rr_type(RecordType::RRSIG)
931 .set_dns_class(DNSClass::IN)
932 .set_data(Some(RData::DNSSEC(DNSSECRData::SIG(ecp256))))
933 .clone();
934 let rrsig_ecp384 = Record::new()
935 .set_name(name.clone())
936 .set_ttl(3600)
937 .set_rr_type(RecordType::RRSIG)
938 .set_dns_class(DNSClass::IN)
939 .set_data(Some(RData::DNSSEC(DNSSECRData::SIG(ecp384))))
940 .clone();
941 let rrsig_ed25519 = Record::new()
942 .set_name(name.clone())
943 .set_ttl(3600)
944 .set_rr_type(RecordType::RRSIG)
945 .set_dns_class(DNSClass::IN)
946 .set_data(Some(RData::DNSSEC(DNSSECRData::SIG(ed25519))))
947 .clone();
948
949 let a = Record::new()
950 .set_name(name)
951 .set_ttl(3600)
952 .set_rr_type(RecordType::A)
953 .set_dns_class(DNSClass::IN)
954 .set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 24))))
955 .clone();
956
957 let mut rrset = RecordSet::from(a);
958 rrset.insert_rrsig(rrsig_rsa);
959 rrset.insert_rrsig(rrsig_ecp256);
960 rrset.insert_rrsig(rrsig_ecp384);
961 rrset.insert_rrsig(rrsig_ed25519);
962
963 assert!(rrset
964 .records_with_rrsigs(SupportedAlgorithms::all(),)
965 .any(
966 |r| if let Some(RData::DNSSEC(DNSSECRData::SIG(ref sig))) = r.data() {
967 sig.algorithm() == Algorithm::ED25519
968 } else {
969 false
970 },
971 ));
972
973 let mut supported_algorithms = SupportedAlgorithms::new();
974 supported_algorithms.set(Algorithm::ECDSAP384SHA384);
975 assert!(rrset.records_with_rrsigs(supported_algorithms).any(|r| {
976 if let Some(RData::DNSSEC(DNSSECRData::SIG(ref sig))) = r.data() {
977 sig.algorithm() == Algorithm::ECDSAP384SHA384
978 } else {
979 false
980 }
981 }));
982
983 let mut supported_algorithms = SupportedAlgorithms::new();
984 supported_algorithms.set(Algorithm::ED25519);
985 assert!(rrset.records_with_rrsigs(supported_algorithms).any(|r| {
986 if let Some(RData::DNSSEC(DNSSECRData::SIG(ref sig))) = r.data() {
987 sig.algorithm() == Algorithm::ED25519
988 } else {
989 false
990 }
991 }));
992 }
993}