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