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
521#[derive(Debug)]
523pub enum RrsetRecords<'r> {
524 Empty,
526 RecordsOnly(Iter<'r, Record>),
528 #[cfg(feature = "__dnssec")]
530 RecordsAndRrsigs(RecordsAndRrsigsIter<'r>),
531}
532
533impl RrsetRecords<'_> {
534 pub fn is_empty(&self) -> bool {
536 matches!(*self, RrsetRecords::Empty)
537 }
538}
539
540impl<'r> Iterator for RrsetRecords<'r> {
541 type Item = &'r Record;
542
543 fn next(&mut self) -> Option<Self::Item> {
544 match self {
545 RrsetRecords::Empty => None,
546 RrsetRecords::RecordsOnly(i) => i.next(),
547 #[cfg(feature = "__dnssec")]
548 RrsetRecords::RecordsAndRrsigs(i) => i.next(),
549 }
550 }
551}
552
553#[cfg(test)]
554mod test {
555 use core::net::Ipv4Addr;
556 use core::str::FromStr;
557
558 use crate::rr::rdata::{CNAME, NS, SOA};
559 use crate::rr::*;
560
561 #[test]
562 fn test_insert() {
563 let name = Name::from_str("www.example.com.").unwrap();
564 let record_type = RecordType::A;
565 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
566
567 let insert = Record::from_rdata(
568 name.clone(),
569 86400,
570 RData::A(Ipv4Addr::new(93, 184, 216, 24).into()),
571 );
572
573 assert!(rr_set.insert(insert.clone(), 0));
574 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
575 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
576
577 assert!(!rr_set.insert(insert.clone(), 0));
579 assert_eq!(rr_set.records_without_rrsigs().count(), 1);
580 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
581
582 let insert1 = Record::from_rdata(
584 name,
585 86400,
586 RData::A(Ipv4Addr::new(93, 184, 216, 25).into()),
587 );
588 assert!(rr_set.insert(insert1.clone(), 0));
589 assert_eq!(rr_set.records_without_rrsigs().count(), 2);
590 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
591 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert1));
592 }
593
594 #[test]
595 #[allow(clippy::unreadable_literal)]
596 fn test_insert_soa() {
597 let name = Name::from_str("example.com.").unwrap();
598 let record_type = RecordType::SOA;
599 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
600
601 let insert = Record::from_rdata(
602 name.clone(),
603 3600,
604 RData::SOA(SOA::new(
605 Name::from_str("sns.dns.icann.org.").unwrap(),
606 Name::from_str("noc.dns.icann.org.").unwrap(),
607 2015082403,
608 7200,
609 3600,
610 1209600,
611 3600,
612 )),
613 );
614 let same_serial = Record::from_rdata(
615 name.clone(),
616 3600,
617 RData::SOA(SOA::new(
618 Name::from_str("sns.dns.icann.net.").unwrap(),
619 Name::from_str("noc.dns.icann.net.").unwrap(),
620 2015082403,
621 7200,
622 3600,
623 1209600,
624 3600,
625 )),
626 );
627 let new_serial = Record::from_rdata(
628 name,
629 3600,
630 RData::SOA(SOA::new(
631 Name::from_str("sns.dns.icann.net.").unwrap(),
632 Name::from_str("noc.dns.icann.net.").unwrap(),
633 2015082404,
634 7200,
635 3600,
636 1209600,
637 3600,
638 )),
639 );
640
641 assert!(rr_set.insert(insert.clone(), 0));
642 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
643 assert!(!rr_set.insert(same_serial.clone(), 0));
645 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
646 assert!(!rr_set.records_without_rrsigs().any(|x| x == &same_serial));
647
648 assert!(rr_set.insert(new_serial.clone(), 0));
649 assert!(!rr_set.insert(same_serial.clone(), 0));
650 assert!(!rr_set.insert(insert.clone(), 0));
651
652 assert!(rr_set.records_without_rrsigs().any(|x| x == &new_serial));
653 assert!(!rr_set.records_without_rrsigs().any(|x| x == &insert));
654 assert!(!rr_set.records_without_rrsigs().any(|x| x == &same_serial));
655 }
656
657 #[test]
658 fn test_insert_cname() {
659 let name = Name::from_str("web.example.com.").unwrap();
660 let cname = Name::from_str("www.example.com.").unwrap();
661 let new_cname = Name::from_str("w2.example.com.").unwrap();
662
663 let record_type = RecordType::CNAME;
664 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
665
666 let insert = Record::from_rdata(name.clone(), 3600, RData::CNAME(CNAME(cname)));
667 let new_record = Record::from_rdata(name, 3600, RData::CNAME(CNAME(new_cname)));
668
669 assert!(rr_set.insert(insert.clone(), 0));
670 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
671
672 assert!(rr_set.insert(new_record.clone(), 0));
674 assert!(!rr_set.records_without_rrsigs().any(|x| x == &insert));
675 assert!(rr_set.records_without_rrsigs().any(|x| x == &new_record));
676 }
677
678 #[test]
679 fn test_remove() {
680 let name = Name::from_str("www.example.com.").unwrap();
681 let record_type = RecordType::A;
682 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
683
684 let insert = Record::from_rdata(
685 name.clone(),
686 86400,
687 RData::A(Ipv4Addr::new(93, 184, 216, 24).into()),
688 );
689 let insert1 = Record::from_rdata(
690 name,
691 86400,
692 RData::A(Ipv4Addr::new(93, 184, 216, 25).into()),
693 );
694
695 assert!(rr_set.insert(insert.clone(), 0));
696 assert!(rr_set.insert(insert1.clone(), 0));
697
698 assert!(rr_set.remove(&insert, 0));
699 assert!(!rr_set.remove(&insert, 0));
700 assert!(rr_set.remove(&insert1, 0));
701 assert!(!rr_set.remove(&insert1, 0));
702 }
703
704 #[test]
705 #[allow(clippy::unreadable_literal)]
706 fn test_remove_soa() {
707 let name = Name::from_str("www.example.com.").unwrap();
708 let record_type = RecordType::SOA;
709 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
710
711 let insert = Record::from_rdata(
712 name,
713 3600,
714 RData::SOA(SOA::new(
715 Name::from_str("sns.dns.icann.org.").unwrap(),
716 Name::from_str("noc.dns.icann.org.").unwrap(),
717 2015082403,
718 7200,
719 3600,
720 1209600,
721 3600,
722 )),
723 );
724
725 assert!(rr_set.insert(insert.clone(), 0));
726 assert!(!rr_set.remove(&insert, 0));
727 assert!(rr_set.records_without_rrsigs().any(|x| x == &insert));
728 }
729
730 #[test]
731 fn test_remove_ns() {
732 let name = Name::from_str("example.com.").unwrap();
733 let record_type = RecordType::NS;
734 let mut rr_set = RecordSet::new(name.clone(), record_type, 0);
735
736 let ns1 = Record::from_rdata(
737 name.clone(),
738 86400,
739 RData::NS(NS(Name::from_str("a.iana-servers.net.").unwrap())),
740 );
741 let ns2 = Record::from_rdata(
742 name,
743 86400,
744 RData::NS(NS(Name::from_str("b.iana-servers.net.").unwrap())),
745 );
746
747 assert!(rr_set.insert(ns1.clone(), 0));
748 assert!(rr_set.insert(ns2.clone(), 0));
749
750 assert!(rr_set.remove(&ns1, 0));
752 assert!(!rr_set.remove(&ns2, 0));
753
754 assert!(rr_set.insert(ns1.clone(), 0));
756
757 assert!(rr_set.remove(&ns2, 0));
758 assert!(!rr_set.remove(&ns1, 0));
759 }
760}