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 {
42 Self {
43 name,
44 record_type,
45 dns_class: DNSClass::IN,
46 ttl: 0,
47 records: Vec::new(),
48 rrsigs: Vec::new(),
49 serial,
50 }
51 }
52
53 pub fn with_ttl(name: Name, record_type: RecordType, ttl: u32) -> Self {
66 Self {
67 name,
68 record_type,
69 dns_class: DNSClass::IN,
70 ttl,
71 records: Vec::new(),
72 rrsigs: Vec::new(),
73 serial: 0,
74 }
75 }
76
77 pub fn name(&self) -> &Name {
81 &self.name
82 }
83
84 pub fn record_type(&self) -> RecordType {
88 self.record_type
89 }
90
91 pub fn set_dns_class(&mut self, dns_class: DNSClass) {
95 self.dns_class = dns_class;
96 for r in &mut self.records {
97 r.dns_class = dns_class;
98 }
99 }
100
101 pub fn dns_class(&self) -> DNSClass {
103 self.dns_class
104 }
105
106 pub fn set_ttl(&mut self, ttl: u32) {
110 self.ttl = ttl;
111 for r in &mut self.records {
112 r.ttl = ttl;
113 }
114 }
115
116 pub fn ttl(&self) -> u32 {
123 self.ttl
124 }
125
126 pub fn set_records(&mut self, records: Vec<Record>) {
132 self.records = records;
133 }
134
135 pub fn set_rrsigs(&mut self, rrsigs: Vec<Record>) {
141 self.rrsigs = rrsigs;
142 }
143
144 pub fn record(&self) -> Option<&Record> {
146 self.records.first()
147 }
148
149 pub fn records_count(&self) -> usize {
151 self.records.len()
152 }
153
154 #[cfg(feature = "__dnssec")]
160 pub fn records(&self, and_rrsigs: bool) -> RrsetRecords<'_> {
161 if and_rrsigs {
162 self.records_with_rrsigs()
163 } else {
164 self.records_without_rrsigs()
165 }
166 }
167
168 #[cfg(feature = "__dnssec")]
170 pub fn records_with_rrsigs(&self) -> RrsetRecords<'_> {
171 if self.records.is_empty() {
172 RrsetRecords::Empty
173 } else {
174 RrsetRecords::RecordsAndRrsigs(RecordsAndRrsigsIter(
175 self.records.iter().chain(self.rrsigs.iter()),
176 ))
177 }
178 }
179
180 pub fn records_without_rrsigs(&self) -> RrsetRecords<'_> {
182 if self.records.is_empty() {
183 RrsetRecords::Empty
184 } else {
185 RrsetRecords::RecordsOnly(self.records.iter())
186 }
187 }
188
189 pub fn is_empty(&self) -> bool {
191 self.records.is_empty()
192 }
193
194 pub fn serial(&self) -> u32 {
196 self.serial
197 }
198
199 pub fn rrsigs(&self) -> &[Record] {
201 &self.rrsigs
202 }
203
204 pub fn insert_rrsig(&mut self, rrsig: Record) {
212 self.rrsigs.push(rrsig)
213 }
214
215 pub fn clear_rrsigs(&mut self) {
217 self.rrsigs.clear()
218 }
219
220 fn updated(&mut self, serial: u32) {
221 self.serial = serial;
222 self.rrsigs.clear(); }
224
225 pub fn new_record(&mut self, rdata: &RData) -> &Record {
229 self.add_rdata(rdata.clone());
230
231 self.records
232 .iter()
233 .find(|r| &r.data == rdata)
234 .expect("insert failed")
235 }
236
237 pub fn add_rdata(&mut self, rdata: RData) -> bool {
239 debug_assert_eq!(self.record_type, rdata.record_type());
240
241 let record = Record::from_rdata(self.name.clone(), self.ttl, rdata);
242 self.insert(record, 0)
243 }
244
245 pub fn insert(&mut self, record: Record, serial: u32) -> bool {
279 assert_eq!(&record.name, &self.name);
280 assert_eq!(record.record_type(), self.record_type);
281
282 match record.record_type() {
288 RecordType::SOA => {
292 assert!(self.records.len() <= 1);
293
294 if let Some(soa_record) = self.records.first() {
295 match &soa_record.data {
296 RData::SOA(existing_soa) => {
297 if let RData::SOA(new_soa) = &record.data {
298 if new_soa.serial <= existing_soa.serial {
299 info!(
300 "update ignored serial out of data: {:?} <= {:?}",
301 new_soa, existing_soa
302 );
303 return false;
304 }
305 } else {
306 info!("wrong rdata for SOA update: {:?}", record.data);
308 return false;
309 }
310 }
311 rdata => {
312 warn!("wrong rdata: {:?}, expected SOA", rdata);
313 return false;
314 }
315 }
316 }
317
318 self.records.clear();
320 }
321 RecordType::CNAME | RecordType::ANAME => {
350 assert!(self.records.len() <= 1);
351 self.records.clear();
352 }
353 _ => (),
354 }
355
356 let to_replace: Vec<usize> = self
358 .records
359 .iter()
360 .enumerate()
361 .filter(|&(_, rr)| rr.data == record.data)
362 .map(|(i, _)| i)
363 .collect::<Vec<usize>>();
364
365 let mut replaced = false;
367 for i in to_replace {
368 if self.records[i] == record {
369 return false;
370 }
371
372 self.records.push(record.clone());
374 self.records.swap_remove(i);
375 self.ttl = record.ttl;
376 self.updated(serial);
377 replaced = true;
378 }
379
380 if !replaced {
381 self.ttl = record.ttl;
382 self.updated(serial);
383 self.records.push(record);
384 true
385 } else {
386 replaced
387 }
388 }
389
390 pub fn remove(&mut self, record: &Record, serial: u32) -> bool {
404 assert_eq!(record.name, self.name);
405 assert!(
406 record.record_type() == self.record_type || record.record_type() == RecordType::ANY
407 );
408
409 match record.record_type() {
410 RecordType::NS if self.records.len() <= 1 => {
412 info!("ignoring delete of last NS record: {:?}", record);
413 return false;
414 }
415 RecordType::SOA => {
417 info!("ignored delete of SOA");
418 return false;
419 }
420 _ => (), }
422
423 let old_size = self.records.len();
425 self.records.retain(|rr| rr.data != record.data);
426 let removed = self.records.len() < old_size;
427
428 if removed {
429 self.updated(serial);
430 }
431
432 removed
433 }
434
435 pub fn into_parts(self) -> RecordSetParts {
437 self.into()
438 }
439}
440
441#[derive(Clone, Debug, PartialEq, Eq)]
444pub struct RecordSetParts {
445 pub name: Name,
447 pub record_type: RecordType,
449 pub dns_class: DNSClass,
451 pub ttl: u32,
453 pub records: Vec<Record>,
455 pub rrsigs: Vec<Record>,
457 pub serial: u32,
459}
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
498impl IntoIterator for RecordSet {
499 type Item = Record;
500 type IntoIter = Chain<vec::IntoIter<Record>, vec::IntoIter<Record>>;
501
502 fn into_iter(self) -> Self::IntoIter {
503 self.records.into_iter().chain(self.rrsigs)
504 }
505}
506
507#[cfg(feature = "__dnssec")]
509#[derive(Debug)]
510pub struct RecordsAndRrsigsIter<'r>(Chain<Iter<'r, Record>, Iter<'r, Record>>);
511
512#[cfg(feature = "__dnssec")]
513impl<'r> Iterator for RecordsAndRrsigsIter<'r> {
514 type Item = &'r Record;
515
516 fn next(&mut self) -> Option<Self::Item> {
517 self.0.next()
518 }
519
520 fn size_hint(&self) -> (usize, Option<usize>) {
521 self.0.size_hint()
522 }
523}
524
525#[derive(Debug)]
527pub enum RrsetRecords<'r> {
528 Empty,
530 RecordsOnly(Iter<'r, Record>),
532 #[cfg(feature = "__dnssec")]
534 RecordsAndRrsigs(RecordsAndRrsigsIter<'r>),
535}
536
537impl RrsetRecords<'_> {
538 pub fn is_empty(&self) -> bool {
540 matches!(*self, RrsetRecords::Empty)
541 }
542}
543
544impl<'r> Iterator for RrsetRecords<'r> {
545 type Item = &'r Record;
546
547 fn next(&mut self) -> Option<Self::Item> {
548 match self {
549 Self::Empty => None,
550 Self::RecordsOnly(i) => i.next(),
551 #[cfg(feature = "__dnssec")]
552 Self::RecordsAndRrsigs(i) => i.next(),
553 }
554 }
555
556 fn size_hint(&self) -> (usize, Option<usize>) {
557 match self {
558 Self::Empty => (0, Some(0)),
559 Self::RecordsOnly(i) => i.size_hint(),
560 #[cfg(feature = "__dnssec")]
561 Self::RecordsAndRrsigs(i) => i.size_hint(),
562 }
563 }
564}
565
566#[cfg(test)]
567mod test {
568 use core::net::Ipv4Addr;
569 use core::str::FromStr;
570
571 use crate::rr::rdata::{CNAME, NS, SOA};
572 use crate::rr::*;
573
574 #[test]
575 fn test_insert() {
576 let name = Name::from_str("www.example.com.").unwrap();
577 let record_type = RecordType::A;
578 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
579
580 let insert = Record::from_rdata(
581 name.clone(),
582 86400,
583 RData::A(Ipv4Addr::new(93, 184, 216, 24).into()),
584 );
585
586 assert!(rr_set.insert(insert.clone(), 0));
587 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
588 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
589
590 assert!(!rr_set.insert(insert.clone(), 0));
592 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
593 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
594
595 let insert1 = Record::from_rdata(
597 name,
598 86400,
599 RData::A(Ipv4Addr::new(93, 184, 216, 25).into()),
600 );
601 assert!(rr_set.insert(insert1.clone(), 0));
602 assert_eq!(rr_set.records_without_rrsigs().count(), 2);
603 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
604 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert1));
605 }
606
607 #[test]
608 fn test_size_hint() {
609 let name = Name::from_str("www.example.com.").unwrap();
610 let mut rr_set = RecordSet::with_ttl(name.clone(), RecordType::A, 3600);
611
612 assert_eq!(rr_set.records_without_rrsigs().size_hint(), (0, Some(0)));
613
614 assert!(rr_set.add_rdata(RData::A(Ipv4Addr::new(192, 0, 2, 1).into())));
615 assert!(rr_set.add_rdata(RData::A(Ipv4Addr::new(192, 0, 2, 2).into())));
616
617 let mut iter = rr_set.records_without_rrsigs();
618 assert_eq!(iter.size_hint(), (2, Some(2)));
619 assert!(iter.next().is_some());
620 assert_eq!(iter.size_hint(), (1, Some(1)));
621
622 #[cfg(feature = "__dnssec")]
623 {
624 use crate::dnssec::{
625 Algorithm,
626 rdata::{DNSSECRData, RRSIG, sig::SigInput},
627 };
628
629 let input = SigInput {
630 type_covered: RecordType::A,
631 algorithm: Algorithm::ED25519,
632 num_labels: 0,
633 original_ttl: 0,
634 sig_expiration: SerialNumber(0),
635 sig_inception: SerialNumber(0),
636 key_tag: 0,
637 signer_name: Name::root(),
638 };
639 rr_set.insert_rrsig(Record::from_rdata(
640 name,
641 3600,
642 RData::DNSSEC(DNSSECRData::RRSIG(RRSIG::from_sig(input, vec![]))),
643 ));
644
645 assert_eq!(rr_set.records_with_rrsigs().size_hint(), (3, Some(3)));
646 }
647 }
648
649 #[test]
650 #[allow(clippy::unreadable_literal)]
651 fn test_insert_soa() {
652 let name = Name::from_str("example.com.").unwrap();
653 let record_type = RecordType::SOA;
654 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
655
656 let insert = Record::from_rdata(
657 name.clone(),
658 3600,
659 RData::SOA(SOA::new(
660 Name::from_str("sns.dns.icann.org.").unwrap(),
661 Name::from_str("noc.dns.icann.org.").unwrap(),
662 2015082403,
663 7200,
664 3600,
665 1209600,
666 3600,
667 )),
668 );
669 let same_serial = Record::from_rdata(
670 name.clone(),
671 3600,
672 RData::SOA(SOA::new(
673 Name::from_str("sns.dns.icann.net.").unwrap(),
674 Name::from_str("noc.dns.icann.net.").unwrap(),
675 2015082403,
676 7200,
677 3600,
678 1209600,
679 3600,
680 )),
681 );
682 let new_serial = Record::from_rdata(
683 name,
684 3600,
685 RData::SOA(SOA::new(
686 Name::from_str("sns.dns.icann.net.").unwrap(),
687 Name::from_str("noc.dns.icann.net.").unwrap(),
688 2015082404,
689 7200,
690 3600,
691 1209600,
692 3600,
693 )),
694 );
695
696 assert!(rr_set.insert(insert.clone(), 0));
697 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
698 assert!(!rr_set.insert(same_serial.clone(), 0));
700 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
701 assert!(!rr_set.records_without_rrsigs().any(|x| x == &same_serial));
702
703 assert!(rr_set.insert(new_serial.clone(), 0));
704 assert!(!rr_set.insert(same_serial.clone(), 0));
705 assert!(!rr_set.insert(insert.clone(), 0));
706
707 assert!(rr_set.records_without_rrsigs().any(|x| x == &new_serial));
708 assert!(!rr_set.records_without_rrsigs().any(|x| x == &insert));
709 assert!(!rr_set.records_without_rrsigs().any(|x| x == &same_serial));
710 }
711
712 #[test]
713 fn test_insert_cname() {
714 let name = Name::from_str("web.example.com.").unwrap();
715 let cname = Name::from_str("www.example.com.").unwrap();
716 let new_cname = Name::from_str("w2.example.com.").unwrap();
717
718 let record_type = RecordType::CNAME;
719 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
720
721 let insert = Record::from_rdata(name.clone(), 3600, RData::CNAME(CNAME(cname)));
722 let new_record = Record::from_rdata(name, 3600, RData::CNAME(CNAME(new_cname)));
723
724 assert!(rr_set.insert(insert.clone(), 0));
725 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
726
727 assert!(rr_set.insert(new_record.clone(), 0));
729 assert!(!rr_set.records_without_rrsigs().any(|x| x == &insert));
730 assert!(rr_set.records_without_rrsigs().any(|x| x == &new_record));
731 }
732
733 #[test]
734 fn test_remove() {
735 let name = Name::from_str("www.example.com.").unwrap();
736 let record_type = RecordType::A;
737 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
738
739 let insert = Record::from_rdata(
740 name.clone(),
741 86400,
742 RData::A(Ipv4Addr::new(93, 184, 216, 24).into()),
743 );
744 let insert1 = Record::from_rdata(
745 name,
746 86400,
747 RData::A(Ipv4Addr::new(93, 184, 216, 25).into()),
748 );
749
750 assert!(rr_set.insert(insert.clone(), 0));
751 assert!(rr_set.insert(insert1.clone(), 0));
752
753 assert!(rr_set.remove(&insert, 0));
754 assert!(!rr_set.remove(&insert, 0));
755 assert!(rr_set.remove(&insert1, 0));
756 assert!(!rr_set.remove(&insert1, 0));
757 }
758
759 #[test]
760 #[allow(clippy::unreadable_literal)]
761 fn test_remove_soa() {
762 let name = Name::from_str("www.example.com.").unwrap();
763 let record_type = RecordType::SOA;
764 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
765
766 let insert = Record::from_rdata(
767 name,
768 3600,
769 RData::SOA(SOA::new(
770 Name::from_str("sns.dns.icann.org.").unwrap(),
771 Name::from_str("noc.dns.icann.org.").unwrap(),
772 2015082403,
773 7200,
774 3600,
775 1209600,
776 3600,
777 )),
778 );
779
780 assert!(rr_set.insert(insert.clone(), 0));
781 assert!(!rr_set.remove(&insert, 0));
782 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
783 }
784
785 #[test]
786 fn test_remove_ns() {
787 let name = Name::from_str("example.com.").unwrap();
788 let record_type = RecordType::NS;
789 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
790
791 let ns1 = Record::from_rdata(
792 name.clone(),
793 86400,
794 RData::NS(NS(Name::from_str("a.iana-servers.net.").unwrap())),
795 );
796 let ns2 = Record::from_rdata(
797 name,
798 86400,
799 RData::NS(NS(Name::from_str("b.iana-servers.net.").unwrap())),
800 );
801
802 assert!(rr_set.insert(ns1.clone(), 0));
803 assert!(rr_set.insert(ns2.clone(), 0));
804
805 assert!(rr_set.remove(&ns1, 0));
807 assert!(!rr_set.remove(&ns2, 0));
808
809 assert!(rr_set.insert(ns1.clone(), 0));
811
812 assert!(rr_set.remove(&ns2, 0));
813 assert!(!rr_set.remove(&ns1, 0));
814 }
815}