1use alloc::vec;
9use alloc::vec::Vec;
10use core::{iter::Chain, slice::Iter};
11use tracing::{info, warn};
12
13use crate::rr::{DNSClass, Name, RData, Record, RecordType};
14
15#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct RecordSet {
18 name: Name,
19 record_type: RecordType,
20 dns_class: DNSClass,
21 ttl: u32,
22 records: Vec<Record>,
23 rrsigs: Vec<Record>,
24 serial: u32, }
26
27impl RecordSet {
28 pub fn new(name: Name, record_type: RecordType, serial: u32) -> Self {
43 Self {
44 name,
45 record_type,
46 dns_class: DNSClass::IN,
47 ttl: 0,
48 records: Vec::new(),
49 rrsigs: Vec::new(),
50 serial,
51 }
52 }
53
54 pub fn with_ttl(name: Name, record_type: RecordType, ttl: u32) -> Self {
68 Self {
69 name,
70 record_type,
71 dns_class: DNSClass::IN,
72 ttl,
73 records: Vec::new(),
74 rrsigs: Vec::new(),
75 serial: 0,
76 }
77 }
78
79 pub fn name(&self) -> &Name {
83 &self.name
84 }
85
86 pub fn record_type(&self) -> RecordType {
90 self.record_type
91 }
92
93 pub fn set_dns_class(&mut self, dns_class: DNSClass) {
97 self.dns_class = dns_class;
98 for r in &mut self.records {
99 r.set_dns_class(dns_class);
100 }
101 }
102
103 pub fn dns_class(&self) -> DNSClass {
105 self.dns_class
106 }
107
108 pub fn set_ttl(&mut self, ttl: u32) {
112 self.ttl = ttl;
113 for r in &mut self.records {
114 r.set_ttl(ttl);
115 }
116 }
117
118 pub fn ttl(&self) -> u32 {
125 self.ttl
126 }
127
128 #[cfg(feature = "__dnssec")]
134 pub fn records(&self, and_rrsigs: bool) -> RrsetRecords<'_> {
135 if and_rrsigs {
136 self.records_with_rrsigs()
137 } else {
138 self.records_without_rrsigs()
139 }
140 }
141
142 #[cfg(feature = "__dnssec")]
144 pub fn records_with_rrsigs(&self) -> RrsetRecords<'_> {
145 if self.records.is_empty() {
146 RrsetRecords::Empty
147 } else {
148 RrsetRecords::RecordsAndRrsigs(RecordsAndRrsigsIter(
149 self.records.iter().chain(self.rrsigs.iter()),
150 ))
151 }
152 }
153
154 pub fn records_without_rrsigs(&self) -> RrsetRecords<'_> {
156 if self.records.is_empty() {
157 RrsetRecords::Empty
158 } else {
159 RrsetRecords::RecordsOnly(self.records.iter())
160 }
161 }
162
163 #[deprecated(note = "see `records_without_rrsigs`")]
165 pub fn iter(&self) -> Iter<'_, Record> {
166 self.records.iter()
167 }
168
169 pub fn is_empty(&self) -> bool {
171 self.records.is_empty()
172 }
173
174 pub fn serial(&self) -> u32 {
176 self.serial
177 }
178
179 pub fn rrsigs(&self) -> &[Record] {
181 &self.rrsigs
182 }
183
184 pub fn insert_rrsig(&mut self, rrsig: Record) {
192 self.rrsigs.push(rrsig)
193 }
194
195 pub fn clear_rrsigs(&mut self) {
197 self.rrsigs.clear()
198 }
199
200 fn updated(&mut self, serial: u32) {
201 self.serial = serial;
202 self.rrsigs.clear(); }
204
205 pub fn new_record(&mut self, rdata: &RData) -> &Record {
209 self.add_rdata(rdata.clone());
210
211 self.records
212 .iter()
213 .find(|r| r.data() == rdata)
214 .expect("insert failed")
215 }
216
217 pub fn add_rdata(&mut self, rdata: RData) -> bool {
219 debug_assert_eq!(self.record_type, rdata.record_type());
220
221 let record = Record::from_rdata(self.name.clone(), self.ttl, rdata);
222 self.insert(record, 0)
223 }
224
225 pub fn insert(&mut self, record: Record, serial: u32) -> bool {
259 assert_eq!(record.name(), &self.name);
260 assert_eq!(record.record_type(), self.record_type);
261
262 match record.record_type() {
268 RecordType::SOA => {
272 assert!(self.records.len() <= 1);
273
274 if let Some(soa_record) = self.records.first() {
275 match soa_record.data() {
276 RData::SOA(existing_soa) => {
277 if let RData::SOA(new_soa) = record.data() {
278 if new_soa.serial() <= existing_soa.serial() {
279 info!(
280 "update ignored serial out of data: {:?} <= {:?}",
281 new_soa, existing_soa
282 );
283 return false;
284 }
285 } else {
286 info!("wrong rdata for SOA update: {:?}", record.data());
288 return false;
289 }
290 }
291 rdata => {
292 warn!("wrong rdata: {:?}, expected SOA", rdata);
293 return false;
294 }
295 }
296 }
297
298 self.records.clear();
300 }
301 RecordType::CNAME | RecordType::ANAME => {
330 assert!(self.records.len() <= 1);
331 self.records.clear();
332 }
333 _ => (),
334 }
335
336 let to_replace: Vec<usize> = self
338 .records
339 .iter()
340 .enumerate()
341 .filter(|&(_, rr)| rr.data() == record.data())
342 .map(|(i, _)| i)
343 .collect::<Vec<usize>>();
344
345 let mut replaced = false;
347 for i in to_replace {
348 if self.records[i] == record {
349 return false;
350 }
351
352 self.records.push(record.clone());
354 self.records.swap_remove(i);
355 self.ttl = record.ttl();
356 self.updated(serial);
357 replaced = true;
358 }
359
360 if !replaced {
361 self.ttl = record.ttl();
362 self.updated(serial);
363 self.records.push(record);
364 true
365 } else {
366 replaced
367 }
368 }
369
370 pub fn remove(&mut self, record: &Record, serial: u32) -> bool {
384 assert_eq!(record.name(), &self.name);
385 assert!(
386 record.record_type() == self.record_type || record.record_type() == RecordType::ANY
387 );
388
389 match record.record_type() {
390 RecordType::NS => {
392 if self.records.len() <= 1 {
393 info!("ignoring delete of last NS record: {:?}", record);
394 return false;
395 }
396 }
397 RecordType::SOA => {
399 info!("ignored delete of SOA");
400 return false;
401 }
402 _ => (), }
404
405 let to_remove: Vec<usize> = self
407 .records
408 .iter()
409 .enumerate()
410 .filter(|&(_, rr)| rr.data() == record.data())
411 .map(|(i, _)| i)
412 .collect::<Vec<usize>>();
413
414 let mut removed = false;
415 for i in to_remove {
416 self.records.remove(i);
417 removed = true;
418 self.updated(serial);
419 }
420
421 removed
422 }
423
424 pub fn into_parts(self) -> RecordSetParts {
426 self.into()
427 }
428}
429
430#[derive(Clone, Debug, PartialEq, Eq)]
433pub struct RecordSetParts {
434 pub name: Name,
435 pub record_type: RecordType,
436 pub dns_class: DNSClass,
437 pub ttl: u32,
438 pub records: Vec<Record>,
439 pub rrsigs: Vec<Record>,
440 pub serial: u32, }
442
443impl From<RecordSet> for RecordSetParts {
444 fn from(rset: RecordSet) -> Self {
445 let RecordSet {
446 name,
447 record_type,
448 dns_class,
449 ttl,
450 records,
451 rrsigs,
452 serial,
453 } = rset;
454 Self {
455 name,
456 record_type,
457 dns_class,
458 ttl,
459 records,
460 rrsigs,
461 serial,
462 }
463 }
464}
465
466impl From<Record> for RecordSet {
467 fn from(record: Record) -> Self {
468 Self {
469 name: record.name().clone(),
470 record_type: record.record_type(),
471 dns_class: record.dns_class(),
472 ttl: record.ttl(),
473 records: vec![record],
474 rrsigs: vec![],
475 serial: 0,
476 }
477 }
478}
479
480#[deprecated(note = "use From/Into")]
482pub trait IntoRecordSet: Sized {
483 fn into_record_set(self) -> RecordSet;
485}
486
487#[allow(deprecated)]
488impl IntoRecordSet for RecordSet {
489 fn into_record_set(self) -> Self {
490 self
491 }
492}
493
494impl IntoIterator for RecordSet {
495 type Item = Record;
496 type IntoIter = Chain<vec::IntoIter<Record>, vec::IntoIter<Record>>;
497
498 fn into_iter(self) -> Self::IntoIter {
499 self.records.into_iter().chain(self.rrsigs)
500 }
501}
502
503#[cfg(feature = "__dnssec")]
505#[derive(Debug)]
506pub struct RecordsAndRrsigsIter<'r>(Chain<Iter<'r, Record>, Iter<'r, Record>>);
507
508#[cfg(feature = "__dnssec")]
509impl<'r> Iterator for RecordsAndRrsigsIter<'r> {
510 type Item = &'r Record;
511
512 fn next(&mut self) -> Option<Self::Item> {
513 self.0.next()
514 }
515}
516
517#[derive(Debug)]
519pub enum RrsetRecords<'r> {
520 Empty,
522 RecordsOnly(Iter<'r, Record>),
524 #[cfg(feature = "__dnssec")]
526 RecordsAndRrsigs(RecordsAndRrsigsIter<'r>),
527}
528
529impl RrsetRecords<'_> {
530 pub fn is_empty(&self) -> bool {
532 matches!(*self, RrsetRecords::Empty)
533 }
534}
535
536impl<'r> Iterator for RrsetRecords<'r> {
537 type Item = &'r Record;
538
539 fn next(&mut self) -> Option<Self::Item> {
540 match self {
541 RrsetRecords::Empty => None,
542 RrsetRecords::RecordsOnly(i) => i.next(),
543 #[cfg(feature = "__dnssec")]
544 RrsetRecords::RecordsAndRrsigs(i) => i.next(),
545 }
546 }
547}
548
549#[cfg(test)]
550mod test {
551 #[cfg(not(feature = "std"))]
552 use core::net::Ipv4Addr;
553 use core::str::FromStr;
554 #[cfg(feature = "std")]
555 use std::net::Ipv4Addr;
556
557 use crate::rr::rdata::{CNAME, NS, SOA};
558 use crate::rr::*;
559
560 #[test]
561 fn test_insert() {
562 let name = Name::from_str("www.example.com.").unwrap();
563 let record_type = RecordType::A;
564 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
565
566 let insert = Record::from_rdata(
567 name.clone(),
568 86400,
569 RData::A(Ipv4Addr::new(93, 184, 216, 24).into()),
570 )
571 .set_dns_class(DNSClass::IN)
572 .clone();
573
574 assert!(rr_set.insert(insert.clone(), 0));
575 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
576 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
577
578 assert!(!rr_set.insert(insert.clone(), 0));
580 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
581 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
582
583 let insert1 = Record::from_rdata(
585 name,
586 86400,
587 RData::A(Ipv4Addr::new(93, 184, 216, 25).into()),
588 )
589 .set_dns_class(DNSClass::IN)
590 .clone();
591 assert!(rr_set.insert(insert1.clone(), 0));
592 assert_eq!(rr_set.records_without_rrsigs().count(), 2);
593 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
594 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert1));
595 }
596
597 #[test]
598 #[allow(clippy::unreadable_literal)]
599 fn test_insert_soa() {
600 let name = Name::from_str("example.com.").unwrap();
601 let record_type = RecordType::SOA;
602 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
603
604 let insert = Record::from_rdata(
605 name.clone(),
606 3600,
607 RData::SOA(SOA::new(
608 Name::from_str("sns.dns.icann.org.").unwrap(),
609 Name::from_str("noc.dns.icann.org.").unwrap(),
610 2015082403,
611 7200,
612 3600,
613 1209600,
614 3600,
615 )),
616 )
617 .set_dns_class(DNSClass::IN)
618 .clone();
619 let same_serial = Record::from_rdata(
620 name.clone(),
621 3600,
622 RData::SOA(SOA::new(
623 Name::from_str("sns.dns.icann.net.").unwrap(),
624 Name::from_str("noc.dns.icann.net.").unwrap(),
625 2015082403,
626 7200,
627 3600,
628 1209600,
629 3600,
630 )),
631 )
632 .set_dns_class(DNSClass::IN)
633 .clone();
634 let new_serial = Record::from_rdata(
635 name,
636 3600,
637 RData::SOA(SOA::new(
638 Name::from_str("sns.dns.icann.net.").unwrap(),
639 Name::from_str("noc.dns.icann.net.").unwrap(),
640 2015082404,
641 7200,
642 3600,
643 1209600,
644 3600,
645 )),
646 )
647 .set_dns_class(DNSClass::IN)
648 .clone();
649
650 assert!(rr_set.insert(insert.clone(), 0));
651 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
652 assert!(!rr_set.insert(same_serial.clone(), 0));
654 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
655 assert!(!rr_set.records_without_rrsigs().any(|x| x == &same_serial));
656
657 assert!(rr_set.insert(new_serial.clone(), 0));
658 assert!(!rr_set.insert(same_serial.clone(), 0));
659 assert!(!rr_set.insert(insert.clone(), 0));
660
661 assert!(rr_set.records_without_rrsigs().any(|x| x == &new_serial));
662 assert!(!rr_set.records_without_rrsigs().any(|x| x == &insert));
663 assert!(!rr_set.records_without_rrsigs().any(|x| x == &same_serial));
664 }
665
666 #[test]
667 fn test_insert_cname() {
668 let name = Name::from_str("web.example.com.").unwrap();
669 let cname = Name::from_str("www.example.com.").unwrap();
670 let new_cname = Name::from_str("w2.example.com.").unwrap();
671
672 let record_type = RecordType::CNAME;
673 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
674
675 let insert = Record::from_rdata(name.clone(), 3600, RData::CNAME(CNAME(cname)))
676 .set_dns_class(DNSClass::IN)
677 .clone();
678 let new_record = Record::from_rdata(name, 3600, RData::CNAME(CNAME(new_cname)))
679 .set_dns_class(DNSClass::IN)
680 .clone();
681
682 assert!(rr_set.insert(insert.clone(), 0));
683 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
684
685 assert!(rr_set.insert(new_record.clone(), 0));
687 assert!(!rr_set.records_without_rrsigs().any(|x| x == &insert));
688 assert!(rr_set.records_without_rrsigs().any(|x| x == &new_record));
689 }
690
691 #[test]
692 fn test_remove() {
693 let name = Name::from_str("www.example.com.").unwrap();
694 let record_type = RecordType::A;
695 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
696
697 let insert = Record::from_rdata(
698 name.clone(),
699 86400,
700 RData::A(Ipv4Addr::new(93, 184, 216, 24).into()),
701 )
702 .set_dns_class(DNSClass::IN)
703 .clone();
704 let insert1 = Record::from_rdata(
705 name,
706 86400,
707 RData::A(Ipv4Addr::new(93, 184, 216, 25).into()),
708 )
709 .set_dns_class(DNSClass::IN)
710 .clone();
711
712 assert!(rr_set.insert(insert.clone(), 0));
713 assert!(rr_set.insert(insert1.clone(), 0));
714
715 assert!(rr_set.remove(&insert, 0));
716 assert!(!rr_set.remove(&insert, 0));
717 assert!(rr_set.remove(&insert1, 0));
718 assert!(!rr_set.remove(&insert1, 0));
719 }
720
721 #[test]
722 #[allow(clippy::unreadable_literal)]
723 fn test_remove_soa() {
724 let name = Name::from_str("www.example.com.").unwrap();
725 let record_type = RecordType::SOA;
726 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
727
728 let insert = Record::from_rdata(
729 name,
730 3600,
731 RData::SOA(SOA::new(
732 Name::from_str("sns.dns.icann.org.").unwrap(),
733 Name::from_str("noc.dns.icann.org.").unwrap(),
734 2015082403,
735 7200,
736 3600,
737 1209600,
738 3600,
739 )),
740 )
741 .set_dns_class(DNSClass::IN)
742 .clone();
743
744 assert!(rr_set.insert(insert.clone(), 0));
745 assert!(!rr_set.remove(&insert, 0));
746 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
747 }
748
749 #[test]
750 fn test_remove_ns() {
751 let name = Name::from_str("example.com.").unwrap();
752 let record_type = RecordType::NS;
753 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
754
755 let ns1 = Record::from_rdata(
756 name.clone(),
757 86400,
758 RData::NS(NS(Name::from_str("a.iana-servers.net.").unwrap())),
759 )
760 .set_dns_class(DNSClass::IN)
761 .clone();
762 let ns2 = Record::from_rdata(
763 name,
764 86400,
765 RData::NS(NS(Name::from_str("b.iana-servers.net.").unwrap())),
766 )
767 .set_dns_class(DNSClass::IN)
768 .clone();
769
770 assert!(rr_set.insert(ns1.clone(), 0));
771 assert!(rr_set.insert(ns2.clone(), 0));
772
773 assert!(rr_set.remove(&ns1, 0));
775 assert!(!rr_set.remove(&ns2, 0));
776
777 assert!(rr_set.insert(ns1.clone(), 0));
779
780 assert!(rr_set.remove(&ns2, 0));
781 assert!(!rr_set.remove(&ns1, 0));
782 }
783
784 #[test]
785 #[cfg(feature = "__dnssec")] #[allow(clippy::blocks_in_conditions)]
787 fn test_get_filter() {
788 use crate::dnssec::{
789 Algorithm,
790 rdata::{DNSSECRData, RRSIG},
791 };
792
793 let name = Name::root();
794 let rsasha256 = RRSIG::new(
795 RecordType::A,
796 Algorithm::RSASHA256,
797 0,
798 0,
799 0,
800 0,
801 0,
802 Name::root(),
803 vec![],
804 );
805 let ecp256 = RRSIG::new(
806 RecordType::A,
807 Algorithm::ECDSAP256SHA256,
808 0,
809 0,
810 0,
811 0,
812 0,
813 Name::root(),
814 vec![],
815 );
816 let ecp384 = RRSIG::new(
817 RecordType::A,
818 Algorithm::ECDSAP384SHA384,
819 0,
820 0,
821 0,
822 0,
823 0,
824 Name::root(),
825 vec![],
826 );
827 let ed25519 = RRSIG::new(
828 RecordType::A,
829 Algorithm::ED25519,
830 0,
831 0,
832 0,
833 0,
834 0,
835 Name::root(),
836 vec![],
837 );
838
839 let rrsig_rsa = Record::from_rdata(
840 name.clone(),
841 3600,
842 RData::DNSSEC(DNSSECRData::RRSIG(rsasha256)),
843 )
844 .set_dns_class(DNSClass::IN)
845 .clone();
846 let rrsig_ecp256 = Record::from_rdata(
847 name.clone(),
848 3600,
849 RData::DNSSEC(DNSSECRData::RRSIG(ecp256)),
850 )
851 .set_dns_class(DNSClass::IN)
852 .clone();
853 let rrsig_ecp384 = Record::from_rdata(
854 name.clone(),
855 3600,
856 RData::DNSSEC(DNSSECRData::RRSIG(ecp384)),
857 )
858 .set_dns_class(DNSClass::IN)
859 .clone();
860 let rrsig_ed25519 = Record::from_rdata(
861 name.clone(),
862 3600,
863 RData::DNSSEC(DNSSECRData::RRSIG(ed25519)),
864 )
865 .set_dns_class(DNSClass::IN)
866 .clone();
867
868 let a = Record::from_rdata(name, 3600, RData::A(Ipv4Addr::new(93, 184, 216, 24).into()))
869 .set_dns_class(DNSClass::IN)
870 .clone();
871
872 let mut rrset = RecordSet::from(a);
873 rrset.insert_rrsig(rrsig_rsa);
874 rrset.insert_rrsig(rrsig_ecp256);
875 rrset.insert_rrsig(rrsig_ecp384);
876 rrset.insert_rrsig(rrsig_ed25519);
877
878 assert!(rrset.records_with_rrsigs().any(|r| {
879 if let RData::DNSSEC(DNSSECRData::RRSIG(sig)) = r.data() {
880 sig.algorithm() == Algorithm::ED25519
881 } else {
882 false
883 }
884 },));
885
886 assert!(rrset.records_with_rrsigs().any(|r| {
887 if let RData::DNSSEC(DNSSECRData::RRSIG(sig)) = r.data() {
888 sig.algorithm() == Algorithm::ECDSAP384SHA384
889 } else {
890 false
891 }
892 }));
893
894 assert!(rrset.records_with_rrsigs().any(|r| {
895 if let RData::DNSSEC(DNSSECRData::RRSIG(sig)) = r.data() {
896 sig.algorithm() == Algorithm::ED25519
897 } else {
898 false
899 }
900 }));
901 }
902}