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 => {
326 assert!(self.records.len() <= 1);
327 self.records.clear();
328 }
329 _ => (),
330 }
331
332 let to_replace: Vec<usize> = self
334 .records
335 .iter()
336 .enumerate()
337 .filter(|&(_, rr)| rr.data() == record.data())
338 .map(|(i, _)| i)
339 .collect::<Vec<usize>>();
340
341 let mut replaced = false;
343 for i in to_replace {
344 if self.records[i] == record {
345 return false;
346 }
347
348 self.records.push(record.clone());
350 self.records.swap_remove(i);
351 self.ttl = record.ttl();
352 self.updated(serial);
353 replaced = true;
354 }
355
356 if !replaced {
357 self.ttl = record.ttl();
358 self.updated(serial);
359 self.records.push(record);
360 true
361 } else {
362 replaced
363 }
364 }
365
366 pub fn remove(&mut self, record: &Record, serial: u32) -> bool {
380 assert_eq!(record.name(), &self.name);
381 assert!(
382 record.record_type() == self.record_type || record.record_type() == RecordType::ANY
383 );
384
385 match record.record_type() {
386 RecordType::NS => {
388 if self.records.len() <= 1 {
389 info!("ignoring delete of last NS record: {:?}", record);
390 return false;
391 }
392 }
393 RecordType::SOA => {
395 info!("ignored delete of SOA");
396 return false;
397 }
398 _ => (), }
400
401 let to_remove: Vec<usize> = self
403 .records
404 .iter()
405 .enumerate()
406 .filter(|&(_, rr)| rr.data() == record.data())
407 .map(|(i, _)| i)
408 .collect::<Vec<usize>>();
409
410 let mut removed = false;
411 for i in to_remove {
412 self.records.remove(i);
413 removed = true;
414 self.updated(serial);
415 }
416
417 removed
418 }
419
420 pub fn into_parts(self) -> RecordSetParts {
422 self.into()
423 }
424}
425
426#[derive(Clone, Debug, PartialEq, Eq)]
429pub struct RecordSetParts {
430 pub name: Name,
431 pub record_type: RecordType,
432 pub dns_class: DNSClass,
433 pub ttl: u32,
434 pub records: Vec<Record>,
435 pub rrsigs: Vec<Record>,
436 pub serial: u32, }
438
439impl From<RecordSet> for RecordSetParts {
440 fn from(rset: RecordSet) -> Self {
441 let RecordSet {
442 name,
443 record_type,
444 dns_class,
445 ttl,
446 records,
447 rrsigs,
448 serial,
449 } = rset;
450 Self {
451 name,
452 record_type,
453 dns_class,
454 ttl,
455 records,
456 rrsigs,
457 serial,
458 }
459 }
460}
461
462impl From<Record> for RecordSet {
463 fn from(record: Record) -> Self {
464 Self {
465 name: record.name().clone(),
466 record_type: record.record_type(),
467 dns_class: record.dns_class(),
468 ttl: record.ttl(),
469 records: vec![record],
470 rrsigs: vec![],
471 serial: 0,
472 }
473 }
474}
475
476#[deprecated(note = "use From/Into")]
478pub trait IntoRecordSet: Sized {
479 fn into_record_set(self) -> RecordSet;
481}
482
483#[allow(deprecated)]
484impl IntoRecordSet for RecordSet {
485 fn into_record_set(self) -> Self {
486 self
487 }
488}
489
490impl IntoIterator for RecordSet {
491 type Item = Record;
492 type IntoIter = Chain<vec::IntoIter<Record>, vec::IntoIter<Record>>;
493
494 fn into_iter(self) -> Self::IntoIter {
495 self.records.into_iter().chain(self.rrsigs)
496 }
497}
498
499#[cfg(feature = "__dnssec")]
501#[derive(Debug)]
502pub struct RecordsAndRrsigsIter<'r>(Chain<Iter<'r, Record>, Iter<'r, Record>>);
503
504#[cfg(feature = "__dnssec")]
505impl<'r> Iterator for RecordsAndRrsigsIter<'r> {
506 type Item = &'r Record;
507
508 fn next(&mut self) -> Option<Self::Item> {
509 self.0.next()
510 }
511}
512
513#[derive(Debug)]
515pub enum RrsetRecords<'r> {
516 Empty,
518 RecordsOnly(Iter<'r, Record>),
520 #[cfg(feature = "__dnssec")]
522 RecordsAndRrsigs(RecordsAndRrsigsIter<'r>),
523}
524
525impl RrsetRecords<'_> {
526 pub fn is_empty(&self) -> bool {
528 matches!(*self, RrsetRecords::Empty)
529 }
530}
531
532impl<'r> Iterator for RrsetRecords<'r> {
533 type Item = &'r Record;
534
535 fn next(&mut self) -> Option<Self::Item> {
536 match self {
537 RrsetRecords::Empty => None,
538 RrsetRecords::RecordsOnly(i) => i.next(),
539 #[cfg(feature = "__dnssec")]
540 RrsetRecords::RecordsAndRrsigs(i) => i.next(),
541 }
542 }
543}
544
545#[cfg(test)]
546mod test {
547 #[cfg(not(feature = "std"))]
548 use core::net::Ipv4Addr;
549 use core::str::FromStr;
550 #[cfg(feature = "std")]
551 use std::net::Ipv4Addr;
552
553 use crate::rr::rdata::{CNAME, NS, SOA};
554 use crate::rr::*;
555
556 #[test]
557 fn test_insert() {
558 let name = Name::from_str("www.example.com.").unwrap();
559 let record_type = RecordType::A;
560 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
561
562 let insert = Record::from_rdata(
563 name.clone(),
564 86400,
565 RData::A(Ipv4Addr::new(93, 184, 216, 24).into()),
566 )
567 .set_dns_class(DNSClass::IN)
568 .clone();
569
570 assert!(rr_set.insert(insert.clone(), 0));
571 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
572 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
573
574 assert!(!rr_set.insert(insert.clone(), 0));
576 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
577 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
578
579 let insert1 = Record::from_rdata(
581 name,
582 86400,
583 RData::A(Ipv4Addr::new(93, 184, 216, 25).into()),
584 )
585 .set_dns_class(DNSClass::IN)
586 .clone();
587 assert!(rr_set.insert(insert1.clone(), 0));
588 assert_eq!(rr_set.records_without_rrsigs().count(), 2);
589 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
590 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert1));
591 }
592
593 #[test]
594 #[allow(clippy::unreadable_literal)]
595 fn test_insert_soa() {
596 let name = Name::from_str("example.com.").unwrap();
597 let record_type = RecordType::SOA;
598 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
599
600 let insert = Record::from_rdata(
601 name.clone(),
602 3600,
603 RData::SOA(SOA::new(
604 Name::from_str("sns.dns.icann.org.").unwrap(),
605 Name::from_str("noc.dns.icann.org.").unwrap(),
606 2015082403,
607 7200,
608 3600,
609 1209600,
610 3600,
611 )),
612 )
613 .set_dns_class(DNSClass::IN)
614 .clone();
615 let same_serial = Record::from_rdata(
616 name.clone(),
617 3600,
618 RData::SOA(SOA::new(
619 Name::from_str("sns.dns.icann.net.").unwrap(),
620 Name::from_str("noc.dns.icann.net.").unwrap(),
621 2015082403,
622 7200,
623 3600,
624 1209600,
625 3600,
626 )),
627 )
628 .set_dns_class(DNSClass::IN)
629 .clone();
630 let new_serial = Record::from_rdata(
631 name,
632 3600,
633 RData::SOA(SOA::new(
634 Name::from_str("sns.dns.icann.net.").unwrap(),
635 Name::from_str("noc.dns.icann.net.").unwrap(),
636 2015082404,
637 7200,
638 3600,
639 1209600,
640 3600,
641 )),
642 )
643 .set_dns_class(DNSClass::IN)
644 .clone();
645
646 assert!(rr_set.insert(insert.clone(), 0));
647 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
648 assert!(!rr_set.insert(same_serial.clone(), 0));
650 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
651 assert!(!rr_set.records_without_rrsigs().any(|x| x == &same_serial));
652
653 assert!(rr_set.insert(new_serial.clone(), 0));
654 assert!(!rr_set.insert(same_serial.clone(), 0));
655 assert!(!rr_set.insert(insert.clone(), 0));
656
657 assert!(rr_set.records_without_rrsigs().any(|x| x == &new_serial));
658 assert!(!rr_set.records_without_rrsigs().any(|x| x == &insert));
659 assert!(!rr_set.records_without_rrsigs().any(|x| x == &same_serial));
660 }
661
662 #[test]
663 fn test_insert_cname() {
664 let name = Name::from_str("web.example.com.").unwrap();
665 let cname = Name::from_str("www.example.com.").unwrap();
666 let new_cname = Name::from_str("w2.example.com.").unwrap();
667
668 let record_type = RecordType::CNAME;
669 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
670
671 let insert = Record::from_rdata(name.clone(), 3600, RData::CNAME(CNAME(cname)))
672 .set_dns_class(DNSClass::IN)
673 .clone();
674 let new_record = Record::from_rdata(name, 3600, RData::CNAME(CNAME(new_cname)))
675 .set_dns_class(DNSClass::IN)
676 .clone();
677
678 assert!(rr_set.insert(insert.clone(), 0));
679 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
680
681 assert!(rr_set.insert(new_record.clone(), 0));
683 assert!(!rr_set.records_without_rrsigs().any(|x| x == &insert));
684 assert!(rr_set.records_without_rrsigs().any(|x| x == &new_record));
685 }
686
687 #[test]
688 fn test_remove() {
689 let name = Name::from_str("www.example.com.").unwrap();
690 let record_type = RecordType::A;
691 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
692
693 let insert = Record::from_rdata(
694 name.clone(),
695 86400,
696 RData::A(Ipv4Addr::new(93, 184, 216, 24).into()),
697 )
698 .set_dns_class(DNSClass::IN)
699 .clone();
700 let insert1 = Record::from_rdata(
701 name,
702 86400,
703 RData::A(Ipv4Addr::new(93, 184, 216, 25).into()),
704 )
705 .set_dns_class(DNSClass::IN)
706 .clone();
707
708 assert!(rr_set.insert(insert.clone(), 0));
709 assert!(rr_set.insert(insert1.clone(), 0));
710
711 assert!(rr_set.remove(&insert, 0));
712 assert!(!rr_set.remove(&insert, 0));
713 assert!(rr_set.remove(&insert1, 0));
714 assert!(!rr_set.remove(&insert1, 0));
715 }
716
717 #[test]
718 #[allow(clippy::unreadable_literal)]
719 fn test_remove_soa() {
720 let name = Name::from_str("www.example.com.").unwrap();
721 let record_type = RecordType::SOA;
722 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
723
724 let insert = Record::from_rdata(
725 name,
726 3600,
727 RData::SOA(SOA::new(
728 Name::from_str("sns.dns.icann.org.").unwrap(),
729 Name::from_str("noc.dns.icann.org.").unwrap(),
730 2015082403,
731 7200,
732 3600,
733 1209600,
734 3600,
735 )),
736 )
737 .set_dns_class(DNSClass::IN)
738 .clone();
739
740 assert!(rr_set.insert(insert.clone(), 0));
741 assert!(!rr_set.remove(&insert, 0));
742 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
743 }
744
745 #[test]
746 fn test_remove_ns() {
747 let name = Name::from_str("example.com.").unwrap();
748 let record_type = RecordType::NS;
749 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
750
751 let ns1 = Record::from_rdata(
752 name.clone(),
753 86400,
754 RData::NS(NS(Name::from_str("a.iana-servers.net.").unwrap())),
755 )
756 .set_dns_class(DNSClass::IN)
757 .clone();
758 let ns2 = Record::from_rdata(
759 name,
760 86400,
761 RData::NS(NS(Name::from_str("b.iana-servers.net.").unwrap())),
762 )
763 .set_dns_class(DNSClass::IN)
764 .clone();
765
766 assert!(rr_set.insert(ns1.clone(), 0));
767 assert!(rr_set.insert(ns2.clone(), 0));
768
769 assert!(rr_set.remove(&ns1, 0));
771 assert!(!rr_set.remove(&ns2, 0));
772
773 assert!(rr_set.insert(ns1.clone(), 0));
775
776 assert!(rr_set.remove(&ns2, 0));
777 assert!(!rr_set.remove(&ns1, 0));
778 }
779
780 #[test]
781 #[cfg(feature = "__dnssec")] #[allow(clippy::blocks_in_conditions)]
783 fn test_get_filter() {
784 use crate::dnssec::{
785 Algorithm,
786 rdata::{DNSSECRData, RRSIG},
787 };
788
789 let name = Name::root();
790 let rsasha256 = RRSIG::new(
791 RecordType::A,
792 Algorithm::RSASHA256,
793 0,
794 0,
795 0,
796 0,
797 0,
798 Name::root(),
799 vec![],
800 );
801 let ecp256 = RRSIG::new(
802 RecordType::A,
803 Algorithm::ECDSAP256SHA256,
804 0,
805 0,
806 0,
807 0,
808 0,
809 Name::root(),
810 vec![],
811 );
812 let ecp384 = RRSIG::new(
813 RecordType::A,
814 Algorithm::ECDSAP384SHA384,
815 0,
816 0,
817 0,
818 0,
819 0,
820 Name::root(),
821 vec![],
822 );
823 let ed25519 = RRSIG::new(
824 RecordType::A,
825 Algorithm::ED25519,
826 0,
827 0,
828 0,
829 0,
830 0,
831 Name::root(),
832 vec![],
833 );
834
835 let rrsig_rsa = Record::from_rdata(
836 name.clone(),
837 3600,
838 RData::DNSSEC(DNSSECRData::RRSIG(rsasha256)),
839 )
840 .set_dns_class(DNSClass::IN)
841 .clone();
842 let rrsig_ecp256 = Record::from_rdata(
843 name.clone(),
844 3600,
845 RData::DNSSEC(DNSSECRData::RRSIG(ecp256)),
846 )
847 .set_dns_class(DNSClass::IN)
848 .clone();
849 let rrsig_ecp384 = Record::from_rdata(
850 name.clone(),
851 3600,
852 RData::DNSSEC(DNSSECRData::RRSIG(ecp384)),
853 )
854 .set_dns_class(DNSClass::IN)
855 .clone();
856 let rrsig_ed25519 = Record::from_rdata(
857 name.clone(),
858 3600,
859 RData::DNSSEC(DNSSECRData::RRSIG(ed25519)),
860 )
861 .set_dns_class(DNSClass::IN)
862 .clone();
863
864 let a = Record::from_rdata(name, 3600, RData::A(Ipv4Addr::new(93, 184, 216, 24).into()))
865 .set_dns_class(DNSClass::IN)
866 .clone();
867
868 let mut rrset = RecordSet::from(a);
869 rrset.insert_rrsig(rrsig_rsa);
870 rrset.insert_rrsig(rrsig_ecp256);
871 rrset.insert_rrsig(rrsig_ecp384);
872 rrset.insert_rrsig(rrsig_ed25519);
873
874 assert!(rrset.records_with_rrsigs().any(|r| {
875 if let RData::DNSSEC(DNSSECRData::RRSIG(sig)) = r.data() {
876 sig.algorithm() == Algorithm::ED25519
877 } else {
878 false
879 }
880 },));
881
882 assert!(rrset.records_with_rrsigs().any(|r| {
883 if let RData::DNSSEC(DNSSECRData::RRSIG(sig)) = r.data() {
884 sig.algorithm() == Algorithm::ECDSAP384SHA384
885 } else {
886 false
887 }
888 }));
889
890 assert!(rrset.records_with_rrsigs().any(|r| {
891 if let RData::DNSSEC(DNSSECRData::RRSIG(sig)) = r.data() {
892 sig.algorithm() == Algorithm::ED25519
893 } else {
894 false
895 }
896 }));
897 }
898}