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")]
158 #[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
159 pub fn records_with_rrsigs(
160 &self,
161 _supported_algorithms: SupportedAlgorithms,
162 ) -> RrsetRecords<'_> {
163 if self.records.is_empty() {
164 RrsetRecords::Empty
165 } else {
166 RrsetRecords::RecordsAndRrsigs(RecordsAndRrsigsIter(
167 self.records.iter().chain(self.rrsigs.iter()),
168 ))
169 }
170 }
171
172 pub fn records_without_rrsigs(&self) -> RrsetRecords<'_> {
174 if self.records.is_empty() {
175 RrsetRecords::Empty
176 } else {
177 RrsetRecords::RecordsOnly(self.records.iter())
178 }
179 }
180
181 #[deprecated(note = "see `records_without_rrsigs`")]
183 pub fn iter(&self) -> Iter<'_, Record> {
184 self.records.iter()
185 }
186
187 pub fn is_empty(&self) -> bool {
189 self.records.is_empty()
190 }
191
192 pub fn serial(&self) -> u32 {
194 self.serial
195 }
196
197 pub fn rrsigs(&self) -> &[Record] {
199 &self.rrsigs
200 }
201
202 pub fn insert_rrsig(&mut self, rrsig: Record) {
210 self.rrsigs.push(rrsig)
211 }
212
213 pub fn clear_rrsigs(&mut self) {
215 self.rrsigs.clear()
216 }
217
218 fn updated(&mut self, serial: u32) {
219 self.serial = serial;
220 self.rrsigs.clear(); }
222
223 pub fn new_record(&mut self, rdata: &RData) -> &Record {
227 self.add_rdata(rdata.clone());
228
229 self.records
230 .iter()
231 .find(|r| r.data().map(|r| r == rdata).unwrap_or(false))
232 .expect("insert failed")
233 }
234
235 pub fn add_rdata(&mut self, rdata: RData) -> bool {
237 debug_assert_eq!(self.record_type, rdata.record_type());
238
239 let mut record = Record::with(self.name.clone(), self.record_type, self.ttl);
240 record.set_data(Some(rdata));
241 self.insert(record, 0)
242 }
243
244 pub fn insert(&mut self, record: Record, serial: u32) -> bool {
278 assert_eq!(record.name(), &self.name);
279 assert_eq!(record.record_type(), self.record_type);
280
281 match record.record_type() {
287 RecordType::SOA => {
291 assert!(self.records.len() <= 1);
292
293 if let Some(soa_record) = self.records.first() {
294 match soa_record.data() {
295 Some(RData::SOA(ref existing_soa)) => {
296 if let Some(RData::SOA(ref new_soa)) = record.data() {
297 if new_soa.serial() <= existing_soa.serial() {
298 info!(
299 "update ignored serial out of data: {:?} <= {:?}",
300 new_soa, existing_soa
301 );
302 return false;
303 }
304 } else {
305 info!("wrong rdata for SOA update: {:?}", record.data());
307 return false;
308 }
309 }
310 rdata => {
311 warn!("wrong rdata: {:?}, expected SOA", rdata);
312 return false;
313 }
314 }
315 }
316
317 self.records.clear();
319 }
320 RecordType::CNAME | RecordType::ANAME => {
345 assert!(self.records.len() <= 1);
346 self.records.clear();
347 }
348 _ => (),
349 }
350
351 let to_replace: Vec<usize> = self
353 .records
354 .iter()
355 .enumerate()
356 .filter(|&(_, rr)| rr.data() == record.data())
357 .map(|(i, _)| i)
358 .collect::<Vec<usize>>();
359
360 let mut replaced = false;
362 for i in to_replace {
363 if self.records[i] == record {
364 return false;
365 }
366
367 self.records.push(record.clone());
369 self.records.swap_remove(i);
370 self.ttl = record.ttl();
371 self.updated(serial);
372 replaced = true;
373 }
374
375 if !replaced {
376 self.ttl = record.ttl();
377 self.updated(serial);
378 self.records.push(record);
379 true
380 } else {
381 replaced
382 }
383 }
384
385 pub fn remove(&mut self, record: &Record, serial: u32) -> bool {
399 assert_eq!(record.name(), &self.name);
400 assert!(
401 record.record_type() == self.record_type || record.record_type() == RecordType::ANY
402 );
403
404 match record.record_type() {
405 RecordType::NS => {
407 if self.records.len() <= 1 {
408 info!("ignoring delete of last NS record: {:?}", record);
409 return false;
410 }
411 }
412 RecordType::SOA => {
414 info!("ignored delete of SOA");
415 return false;
416 }
417 _ => (), }
419
420 let to_remove: Vec<usize> = self
422 .records
423 .iter()
424 .enumerate()
425 .filter(|&(_, rr)| rr.data() == record.data())
426 .map(|(i, _)| i)
427 .collect::<Vec<usize>>();
428
429 let mut removed = false;
430 for i in to_remove {
431 self.records.remove(i);
432 removed = true;
433 self.updated(serial);
434 }
435
436 removed
437 }
438
439 pub fn into_parts(self) -> RecordSetParts {
441 self.into()
442 }
443}
444
445#[derive(Clone, Debug, PartialEq, Eq)]
448pub struct RecordSetParts {
449 pub name: Name,
450 pub record_type: RecordType,
451 pub dns_class: DNSClass,
452 pub ttl: u32,
453 pub records: Vec<Record>,
454 pub rrsigs: Vec<Record>,
455 pub serial: u32, }
457
458impl From<RecordSet> for RecordSetParts {
459 fn from(rset: RecordSet) -> Self {
460 let RecordSet {
461 name,
462 record_type,
463 dns_class,
464 ttl,
465 records,
466 rrsigs,
467 serial,
468 } = rset;
469 Self {
470 name,
471 record_type,
472 dns_class,
473 ttl,
474 records,
475 rrsigs,
476 serial,
477 }
478 }
479}
480
481impl From<Record> for RecordSet {
482 fn from(record: Record) -> Self {
483 Self {
484 name: record.name().clone(),
485 record_type: record.record_type(),
486 dns_class: record.dns_class(),
487 ttl: record.ttl(),
488 records: vec![record],
489 rrsigs: vec![],
490 serial: 0,
491 }
492 }
493}
494
495#[deprecated(note = "use From/Into")]
497pub trait IntoRecordSet: Sized {
498 fn into_record_set(self) -> RecordSet;
500}
501
502#[allow(deprecated)]
503impl IntoRecordSet for RecordSet {
504 fn into_record_set(self) -> Self {
505 self
506 }
507}
508
509impl IntoIterator for RecordSet {
510 type Item = Record;
511 type IntoIter = Chain<vec::IntoIter<Record>, vec::IntoIter<Record>>;
512
513 fn into_iter(self) -> Self::IntoIter {
514 self.records.into_iter().chain(self.rrsigs)
515 }
516}
517
518#[cfg(feature = "dnssec")]
520#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
521#[derive(Debug)]
522pub struct RecordsAndRrsigsIter<'r>(Chain<Iter<'r, Record>, Iter<'r, Record>>);
523
524#[cfg(feature = "dnssec")]
525#[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
526impl<'r> Iterator for RecordsAndRrsigsIter<'r> {
527 type Item = &'r Record;
528
529 fn next(&mut self) -> Option<Self::Item> {
530 self.0.next()
531 }
532}
533
534#[derive(Debug)]
536pub enum RrsetRecords<'r> {
537 Empty,
539 RecordsOnly(Iter<'r, Record>),
541 #[cfg(feature = "dnssec")]
543 #[cfg_attr(docsrs, doc(cfg(feature = "dnssec")))]
544 RecordsAndRrsigs(RecordsAndRrsigsIter<'r>),
545}
546
547impl RrsetRecords<'_> {
548 pub fn is_empty(&self) -> bool {
550 matches!(*self, RrsetRecords::Empty)
551 }
552}
553
554impl<'r> Iterator for RrsetRecords<'r> {
555 type Item = &'r Record;
556
557 fn next(&mut self) -> Option<Self::Item> {
558 match self {
559 RrsetRecords::Empty => None,
560 RrsetRecords::RecordsOnly(i) => i.next(),
561 #[cfg(feature = "dnssec")]
562 RrsetRecords::RecordsAndRrsigs(i) => i.next(),
563 }
564 }
565}
566
567#[cfg(test)]
568mod test {
569 use std::net::Ipv4Addr;
570 use std::str::FromStr;
571
572 use crate::rr::rdata::{CNAME, NS, SOA};
573 use crate::rr::*;
574
575 #[test]
576 fn test_insert() {
577 let name = Name::from_str("www.example.com.").unwrap();
578 let record_type = RecordType::A;
579 let mut rr_set = RecordSet::new(&name, record_type, 0);
580
581 let insert = Record::new()
582 .set_name(name.clone())
583 .set_ttl(86400)
584 .set_rr_type(record_type)
585 .set_dns_class(DNSClass::IN)
586 .set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 24).into())))
587 .clone();
588
589 assert!(rr_set.insert(insert.clone(), 0));
590 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
591 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
592
593 assert!(!rr_set.insert(insert.clone(), 0));
595 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
596 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
597
598 let insert1 = Record::new()
600 .set_name(name)
601 .set_ttl(86400)
602 .set_rr_type(record_type)
603 .set_dns_class(DNSClass::IN)
604 .set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 25).into())))
605 .clone();
606 assert!(rr_set.insert(insert1.clone(), 0));
607 assert_eq!(rr_set.records_without_rrsigs().count(), 2);
608 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
609 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert1));
610 }
611
612 #[test]
613 #[allow(clippy::unreadable_literal)]
614 fn test_insert_soa() {
615 let name = Name::from_str("example.com.").unwrap();
616 let record_type = RecordType::SOA;
617 let mut rr_set = RecordSet::new(&name, record_type, 0);
618
619 let insert = Record::new()
620 .set_name(name.clone())
621 .set_ttl(3600)
622 .set_rr_type(RecordType::SOA)
623 .set_dns_class(DNSClass::IN)
624 .set_data(Some(RData::SOA(SOA::new(
625 Name::from_str("sns.dns.icann.org.").unwrap(),
626 Name::from_str("noc.dns.icann.org.").unwrap(),
627 2015082403,
628 7200,
629 3600,
630 1209600,
631 3600,
632 ))))
633 .clone();
634 let same_serial = Record::new()
635 .set_name(name.clone())
636 .set_ttl(3600)
637 .set_rr_type(RecordType::SOA)
638 .set_dns_class(DNSClass::IN)
639 .set_data(Some(RData::SOA(SOA::new(
640 Name::from_str("sns.dns.icann.net.").unwrap(),
641 Name::from_str("noc.dns.icann.net.").unwrap(),
642 2015082403,
643 7200,
644 3600,
645 1209600,
646 3600,
647 ))))
648 .clone();
649 let new_serial = Record::new()
650 .set_name(name)
651 .set_ttl(3600)
652 .set_rr_type(RecordType::SOA)
653 .set_dns_class(DNSClass::IN)
654 .set_data(Some(RData::SOA(SOA::new(
655 Name::from_str("sns.dns.icann.net.").unwrap(),
656 Name::from_str("noc.dns.icann.net.").unwrap(),
657 2015082404,
658 7200,
659 3600,
660 1209600,
661 3600,
662 ))))
663 .clone();
664
665 assert!(rr_set.insert(insert.clone(), 0));
666 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
667 assert!(!rr_set.insert(same_serial.clone(), 0));
669 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
670 assert!(!rr_set
671 .records_without_rrsigs()
672 .any(|ref x| x == &&same_serial));
673
674 assert!(rr_set.insert(new_serial.clone(), 0));
675 assert!(!rr_set.insert(same_serial.clone(), 0));
676 assert!(!rr_set.insert(insert.clone(), 0));
677
678 assert!(rr_set
679 .records_without_rrsigs()
680 .any(|ref x| x == &&new_serial));
681 assert!(!rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
682 assert!(!rr_set
683 .records_without_rrsigs()
684 .any(|ref x| x == &&same_serial));
685 }
686
687 #[test]
688 fn test_insert_cname() {
689 let name = Name::from_str("web.example.com.").unwrap();
690 let cname = Name::from_str("www.example.com.").unwrap();
691 let new_cname = Name::from_str("w2.example.com.").unwrap();
692
693 let record_type = RecordType::CNAME;
694 let mut rr_set = RecordSet::new(&name, record_type, 0);
695
696 let insert = Record::new()
697 .set_name(name.clone())
698 .set_ttl(3600)
699 .set_rr_type(RecordType::CNAME)
700 .set_dns_class(DNSClass::IN)
701 .set_data(Some(RData::CNAME(CNAME(cname))))
702 .clone();
703 let new_record = Record::new()
704 .set_name(name)
705 .set_ttl(3600)
706 .set_rr_type(RecordType::CNAME)
707 .set_dns_class(DNSClass::IN)
708 .set_data(Some(RData::CNAME(CNAME(new_cname))))
709 .clone();
710
711 assert!(rr_set.insert(insert.clone(), 0));
712 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
713
714 assert!(rr_set.insert(new_record.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 == &&new_record));
720 }
721
722 #[test]
723 fn test_remove() {
724 let name = Name::from_str("www.example.com.").unwrap();
725 let record_type = RecordType::A;
726 let mut rr_set = RecordSet::new(&name, record_type, 0);
727
728 let insert = Record::new()
729 .set_name(name.clone())
730 .set_ttl(86400)
731 .set_rr_type(record_type)
732 .set_dns_class(DNSClass::IN)
733 .set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 24).into())))
734 .clone();
735 let insert1 = Record::new()
736 .set_name(name)
737 .set_ttl(86400)
738 .set_rr_type(record_type)
739 .set_dns_class(DNSClass::IN)
740 .set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 25).into())))
741 .clone();
742
743 assert!(rr_set.insert(insert.clone(), 0));
744 assert!(rr_set.insert(insert1.clone(), 0));
745
746 assert!(rr_set.remove(&insert, 0));
747 assert!(!rr_set.remove(&insert, 0));
748 assert!(rr_set.remove(&insert1, 0));
749 assert!(!rr_set.remove(&insert1, 0));
750 }
751
752 #[test]
753 #[allow(clippy::unreadable_literal)]
754 fn test_remove_soa() {
755 let name = Name::from_str("www.example.com.").unwrap();
756 let record_type = RecordType::SOA;
757 let mut rr_set = RecordSet::new(&name, record_type, 0);
758
759 let insert = Record::new()
760 .set_name(name)
761 .set_ttl(3600)
762 .set_rr_type(RecordType::SOA)
763 .set_dns_class(DNSClass::IN)
764 .set_data(Some(RData::SOA(SOA::new(
765 Name::from_str("sns.dns.icann.org.").unwrap(),
766 Name::from_str("noc.dns.icann.org.").unwrap(),
767 2015082403,
768 7200,
769 3600,
770 1209600,
771 3600,
772 ))))
773 .clone();
774
775 assert!(rr_set.insert(insert.clone(), 0));
776 assert!(!rr_set.remove(&insert, 0));
777 assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
778 }
779
780 #[test]
781 fn test_remove_ns() {
782 let name = Name::from_str("example.com.").unwrap();
783 let record_type = RecordType::NS;
784 let mut rr_set = RecordSet::new(&name, record_type, 0);
785
786 let ns1 = Record::new()
787 .set_name(name.clone())
788 .set_ttl(86400)
789 .set_rr_type(RecordType::NS)
790 .set_dns_class(DNSClass::IN)
791 .set_data(Some(RData::NS(NS(
792 Name::from_str("a.iana-servers.net.").unwrap()
793 ))))
794 .clone();
795 let ns2 = Record::new()
796 .set_name(name)
797 .set_ttl(86400)
798 .set_rr_type(RecordType::NS)
799 .set_dns_class(DNSClass::IN)
800 .set_data(Some(RData::NS(NS(
801 Name::from_str("b.iana-servers.net.").unwrap()
802 ))))
803 .clone();
804
805 assert!(rr_set.insert(ns1.clone(), 0));
806 assert!(rr_set.insert(ns2.clone(), 0));
807
808 assert!(rr_set.remove(&ns1, 0));
810 assert!(!rr_set.remove(&ns2, 0));
811
812 assert!(rr_set.insert(ns1.clone(), 0));
814
815 assert!(rr_set.remove(&ns2, 0));
816 assert!(!rr_set.remove(&ns1, 0));
817 }
818
819 #[test]
820 #[cfg(feature = "dnssec")] #[allow(clippy::blocks_in_conditions)]
822 fn test_get_filter() {
823 use crate::rr::dnssec::rdata::DNSSECRData;
824 use crate::rr::dnssec::rdata::RRSIG;
825 use crate::rr::dnssec::{Algorithm, SupportedAlgorithms};
826
827 let name = Name::root();
828 let rsasha256 = RRSIG::new(
829 RecordType::A,
830 Algorithm::RSASHA256,
831 0,
832 0,
833 0,
834 0,
835 0,
836 Name::root(),
837 vec![],
838 );
839 let ecp256 = RRSIG::new(
840 RecordType::A,
841 Algorithm::ECDSAP256SHA256,
842 0,
843 0,
844 0,
845 0,
846 0,
847 Name::root(),
848 vec![],
849 );
850 let ecp384 = RRSIG::new(
851 RecordType::A,
852 Algorithm::ECDSAP384SHA384,
853 0,
854 0,
855 0,
856 0,
857 0,
858 Name::root(),
859 vec![],
860 );
861 let ed25519 = RRSIG::new(
862 RecordType::A,
863 Algorithm::ED25519,
864 0,
865 0,
866 0,
867 0,
868 0,
869 Name::root(),
870 vec![],
871 );
872
873 let rrsig_rsa = Record::new()
874 .set_name(name.clone())
875 .set_ttl(3600)
876 .set_rr_type(RecordType::RRSIG)
877 .set_dns_class(DNSClass::IN)
878 .set_data(Some(RData::DNSSEC(DNSSECRData::RRSIG(rsasha256))))
879 .clone();
880 let rrsig_ecp256 = Record::new()
881 .set_name(name.clone())
882 .set_ttl(3600)
883 .set_rr_type(RecordType::RRSIG)
884 .set_dns_class(DNSClass::IN)
885 .set_data(Some(RData::DNSSEC(DNSSECRData::RRSIG(ecp256))))
886 .clone();
887 let rrsig_ecp384 = Record::new()
888 .set_name(name.clone())
889 .set_ttl(3600)
890 .set_rr_type(RecordType::RRSIG)
891 .set_dns_class(DNSClass::IN)
892 .set_data(Some(RData::DNSSEC(DNSSECRData::RRSIG(ecp384))))
893 .clone();
894 let rrsig_ed25519 = Record::new()
895 .set_name(name.clone())
896 .set_ttl(3600)
897 .set_rr_type(RecordType::RRSIG)
898 .set_dns_class(DNSClass::IN)
899 .set_data(Some(RData::DNSSEC(DNSSECRData::RRSIG(ed25519))))
900 .clone();
901
902 let a = Record::new()
903 .set_name(name)
904 .set_ttl(3600)
905 .set_rr_type(RecordType::A)
906 .set_dns_class(DNSClass::IN)
907 .set_data(Some(RData::A(Ipv4Addr::new(93, 184, 216, 24).into())))
908 .clone();
909
910 let mut rrset = RecordSet::from(a);
911 rrset.insert_rrsig(rrsig_rsa);
912 rrset.insert_rrsig(rrsig_ecp256);
913 rrset.insert_rrsig(rrsig_ecp384);
914 rrset.insert_rrsig(rrsig_ed25519);
915
916 assert!(rrset
917 .records_with_rrsigs(SupportedAlgorithms::all(),)
918 .any(
919 |r| if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref sig))) = r.data() {
920 sig.algorithm() == Algorithm::ED25519
921 } else {
922 false
923 },
924 ));
925
926 let mut supported_algorithms = SupportedAlgorithms::new();
927 supported_algorithms.set(Algorithm::ECDSAP384SHA384);
928 assert!(rrset.records_with_rrsigs(supported_algorithms).any(|r| {
929 if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref sig))) = r.data() {
930 sig.algorithm() == Algorithm::ECDSAP384SHA384
931 } else {
932 false
933 }
934 }));
935
936 let mut supported_algorithms = SupportedAlgorithms::new();
937 supported_algorithms.set(Algorithm::ED25519);
938 assert!(rrset.records_with_rrsigs(supported_algorithms).any(|r| {
939 if let Some(RData::DNSSEC(DNSSECRData::RRSIG(ref sig))) = r.data() {
940 sig.algorithm() == Algorithm::ED25519
941 } else {
942 false
943 }
944 }));
945 }
946}