1 // Copyright 2015-2019 Benjamin Fry <benjaminfry@me.com>
2 //
3 // Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4 // http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5 // http://opensource.org/licenses/MIT>, at your option. This file may not be
6 // copied, modified, or distributed except according to those terms.
7 use std::iter::Chain;
8 use std::slice::Iter;
9 use std::vec;
10 
11 use log::info;
12 
13 use crate::rr::{DNSClass, Name, RData, Record, RecordType};
14 
15 #[cfg(feature = "dnssec")]
16 use crate::rr::dnssec::SupportedAlgorithms;
17 
18 /// Set of resource records associated to a name and type
19 #[derive(Clone, Debug, PartialEq)]
20 pub 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, // serial number at which this record was modified
28 }
29 
30 impl RecordSet {
31     /// Creates a new Resource Record Set.
32     ///
33     /// # Arguments
34     ///
35     /// * `name` - The label for the `RecordSet`
36     /// * `record_type` - `RecordType` of this `RecordSet`, all records in the `RecordSet` must be of the
37     ///                   specified `RecordType`.
38     /// * `serial` - current serial number of the `SOA` record, this is to be used for `IXFR` and
39     ///              signing for DNSSec after updates.
40     ///
41     /// # Return value
42     ///
43     /// The newly created Resource Record Set
44     /// TODO: make all cloned params pass by value
new(name: &Name, record_type: RecordType, serial: u32) -> Self45     pub fn new(name: &Name, record_type: RecordType, serial: u32) -> Self {
46         RecordSet {
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     /// Creates a new Resource Record Set.
58     ///
59     /// # Arguments
60     ///
61     /// * `name` - The label for the `RecordSet`
62     /// * `record_type` - `RecordType` of this `RecordSet`, all records in the `RecordSet` must be of the
63     ///                   specified `RecordType`.
64     /// * `ttl` - time-to-live for the `RecordSet` in seconds.
65     ///
66     /// # Return value
67     ///
68     /// The newly created Resource Record Set
69     /// TODO: make all cloned params pass by value
with_ttl(name: Name, record_type: RecordType, ttl: u32) -> Self70     pub fn with_ttl(name: Name, record_type: RecordType, ttl: u32) -> Self {
71         RecordSet {
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     /// # Return value
83     ///
84     /// Label of the Resource Record Set
name(&self) -> &Name85     pub fn name(&self) -> &Name {
86         &self.name
87     }
88 
89     /// # Return value
90     ///
91     /// `RecordType` of the Resource Record Set
record_type(&self) -> RecordType92     pub fn record_type(&self) -> RecordType {
93         self.record_type
94     }
95 
96     /// Sets the DNSClass to the specified value
97     ///
98     /// This will traverse every record and associate with it the specified dns_class
set_dns_class(&mut self, dns_class: DNSClass)99     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     /// Returns the `DNSClass` of the RecordSet
dns_class(&self) -> DNSClass107     pub fn dns_class(&self) -> DNSClass {
108         self.dns_class
109     }
110 
111     /// Sets the TTL, in seconds, to the specified value
112     ///
113     /// This will traverse every record and associate with it the specified ttl
set_ttl(&mut self, ttl: u32)114     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     /// Returns the time-to-live for the record.
122     ///
123     /// # Return value
124     ///
125     /// TTL, time-to-live, of the Resource Record Set, this is the maximum length of time that an
126     /// RecordSet should be cached.
ttl(&self) -> u32127     pub fn ttl(&self) -> u32 {
128         self.ttl
129     }
130 
131     /// Returns a Vec of all records in the set.
132     ///
133     /// # Arguments
134     ///
135     /// * `and_rrsigs` - if true, RRSIGs will be returned if they exist
136     /// * `supported_algorithms` - the RRSIGs will be filtered by the set of supported_algorithms,
137     ///                            and then only the maximal RRSIG algorithm will be returned.
138     #[cfg(feature = "dnssec")]
records( &self, and_rrsigs: bool, supported_algorithms: SupportedAlgorithms, ) -> RrsetRecords139     pub fn records(
140         &self,
141         and_rrsigs: bool,
142         supported_algorithms: SupportedAlgorithms,
143     ) -> RrsetRecords {
144         if and_rrsigs {
145             self.records_with_rrsigs(supported_algorithms)
146         } else {
147             self.records_without_rrsigs()
148         }
149     }
150 
151     /// Returns a Vec of all records in the set, with RRSIGs, if present.
152     ///
153     /// # Arguments
154     ///
155     /// * `supported_algorithms` - the RRSIGs will be filtered by the set of supported_algorithms,
156     ///                            and then only the maximal RRSIG algorithm will be returned.
157     #[cfg(feature = "dnssec")]
records_with_rrsigs(&self, supported_algorithms: SupportedAlgorithms) -> RrsetRecords158     pub fn records_with_rrsigs(&self, supported_algorithms: SupportedAlgorithms) -> RrsetRecords {
159         if self.records.is_empty() {
160             RrsetRecords::Empty
161         } else {
162             let rrsigs = RrsigsByAlgorithms {
163                 rrsigs: self.rrsigs.iter(),
164                 supported_algorithms,
165             };
166             RrsetRecords::RecordsAndRrsigs(RecordsAndRrsigsIter(self.records.iter().chain(rrsigs)))
167         }
168     }
169 
170     /// Returns a Vec of all records in the set, without any RRSIGs.
records_without_rrsigs(&self) -> RrsetRecords171     pub fn records_without_rrsigs(&self) -> RrsetRecords {
172         if self.records.is_empty() {
173             RrsetRecords::Empty
174         } else {
175             RrsetRecords::RecordsOnly(self.records.iter())
176         }
177     }
178 
179     /// Returns an iterator over the records in the set
180     #[deprecated(note = "see `records_without_rrsigs`")]
iter(&self) -> Iter<Record>181     pub fn iter(&self) -> Iter<Record> {
182         self.records.iter()
183     }
184 
185     /// Returns true if there are no records in this set
is_empty(&self) -> bool186     pub fn is_empty(&self) -> bool {
187         self.records.is_empty()
188     }
189 
190     /// Returns the serial number at which the record was updated.
serial(&self) -> u32191     pub fn serial(&self) -> u32 {
192         self.serial
193     }
194 
195     /// Returns a slice of all the Records signatures in the RecordSet
rrsigs(&self) -> &[Record]196     pub fn rrsigs(&self) -> &[Record] {
197         &self.rrsigs
198     }
199 
200     /// Inserts a Signature for the Record set
201     ///
202     /// Many can be associated with the RecordSet. Once added, the RecordSet should not be changed
203     ///
204     /// # Arguments
205     ///
206     /// * `rrsig` - A signature which covers the RecordSet.
insert_rrsig(&mut self, rrsig: Record)207     pub fn insert_rrsig(&mut self, rrsig: Record) {
208         self.rrsigs.push(rrsig)
209     }
210 
211     /// Useful for clearing all signatures when the RecordSet is updated, or keys are rotated.
clear_rrsigs(&mut self)212     pub fn clear_rrsigs(&mut self) {
213         self.rrsigs.clear()
214     }
215 
updated(&mut self, serial: u32)216     fn updated(&mut self, serial: u32) {
217         self.serial = serial;
218         self.rrsigs.clear(); // on updates, the rrsigs are invalid
219     }
220 
221     /// creates a new Record as part of this RecordSet, adding the associated RData
222     ///
223     /// this interface may be deprecated in the future.
new_record(&mut self, rdata: &RData) -> &Record224     pub fn new_record(&mut self, rdata: &RData) -> &Record {
225         self.add_rdata(rdata.clone());
226 
227         self.records
228             .iter()
229             .find(|r| r.rdata() == rdata)
230             .expect("insert failed")
231     }
232 
233     /// creates a new Record as part of this RecordSet, adding the associated RData
add_rdata(&mut self, rdata: RData) -> bool234     pub fn add_rdata(&mut self, rdata: RData) -> bool {
235         debug_assert_eq!(self.record_type, rdata.to_record_type());
236 
237         let mut record = Record::with(self.name.clone(), self.record_type, self.ttl);
238         record.set_rdata(rdata);
239         self.insert(record, 0)
240     }
241 
242     /// Inserts a new Resource Record into the Set.
243     ///
244     /// If the record is inserted, the ttl for the most recent record will be used for the ttl of
245     /// the entire resource record set.
246     ///
247     /// This abides by the following restrictions in RFC 2136, April 1997:
248     ///
249     /// ```text
250     /// 1.1.5. The following RR types cannot be appended to an RRset.  If the
251     ///  following comparison rules are met, then an attempt to add the new RR
252     ///  will result in the replacement of the previous RR:
253     ///
254     /// SOA    compare only NAME, CLASS and TYPE -- it is not possible to
255     ///         have more than one SOA per zone, even if any of the data
256     ///         fields differ.
257     ///
258     /// CNAME  compare only NAME, CLASS, and TYPE -- it is not possible
259     ///         to have more than one CNAME RR, even if their data fields
260     ///         differ.
261     /// ```
262     ///
263     /// # Arguments
264     ///
265     /// * `record` - `Record` asserts that the `name` and `record_type` match the `RecordSet`.
266     /// * `serial` - current serial number of the `SOA` record, this is to be used for `IXFR` and
267     ///              signing for DNSSec after updates. The serial will only be updated if the
268     ///              record was added.
269     ///
270     /// # Return value
271     ///
272     /// True if the record was inserted.
273     ///
274     /// TODO: make a default add without serial number for basic usage
insert(&mut self, record: Record, serial: u32) -> bool275     pub fn insert(&mut self, record: Record, serial: u32) -> bool {
276         assert_eq!(record.name(), &self.name);
277         assert_eq!(record.rr_type(), self.record_type);
278 
279         // RFC 2136                       DNS Update                     April 1997
280         //
281         // 1.1.5. The following RR types cannot be appended to an RRset.  If the
282         //  following comparison rules are met, then an attempt to add the new RR
283         //  will result in the replacement of the previous RR:
284         match record.rr_type() {
285             // SOA    compare only NAME, CLASS and TYPE -- it is not possible to
286             //         have more than one SOA per zone, even if any of the data
287             //         fields differ.
288             RecordType::SOA => {
289                 assert!(self.records.len() <= 1);
290 
291                 if let Some(soa_record) = self.records.iter().next() {
292                     match soa_record.rdata() {
293                         &RData::SOA(ref existing_soa) => {
294                             if let RData::SOA(ref new_soa) = *record.rdata() {
295                                 if new_soa.serial() <= existing_soa.serial() {
296                                     info!(
297                                         "update ignored serial out of data: {:?} <= {:?}",
298                                         new_soa, existing_soa
299                                     );
300                                     return false;
301                                 }
302                             } else {
303                                 // not panicking here, b/c this is a bad record from the client or something, ignore
304                                 info!("wrong rdata for SOA update: {:?}", record.rdata());
305                                 return false;
306                             }
307                         }
308                         rdata => panic!("wrong rdata: {:?}", rdata), // valid panic, never should happen
309                     }
310                 }
311 
312                 // if we got here, we're updating...
313                 self.records.clear();
314             }
315             // RFC 1034/1035
316             // CNAME  compare only NAME, CLASS, and TYPE -- it is not possible
317             //         to have more than one CNAME RR, even if their data fields
318             //         differ.
319             //
320             // ANAME https://tools.ietf.org/html/draft-ietf-dnsop-aname-02
321             //    2.2.  Coexistence with other types
322             //
323             //   Only one ANAME <target> can be defined per <owner>.  An ANAME RRset
324             //   MUST NOT contain more than one resource record.
325             //
326             //   An ANAME's sibling address records are under the control of ANAME
327             //   processing (see Section 5) and are not first-class records in their
328             //   own right.  They MAY exist in zone files, but they can subsequently
329             //   be altered by ANAME processing.
330             //
331             //   ANAME records MAY freely coexist at the same owner name with other RR
332             //   types, except they MUST NOT coexist with CNAME or any other RR type
333             //   that restricts the types with which it can itself coexist.
334             //
335             //   Like other types, ANAME records can coexist with DNAME records at the
336             //   same owner name; in fact, the two can be used cooperatively to
337             //   redirect both the owner name address records (via ANAME) and
338             //   everything under it (via DNAME).
339             RecordType::CNAME | RecordType::ANAME => {
340                 assert!(self.records.len() <= 1);
341                 self.records.clear();
342             }
343             _ => (),
344         }
345 
346         // collect any records to update based on rdata
347         let to_replace: Vec<usize> = self
348             .records
349             .iter()
350             .enumerate()
351             .filter(|&(_, rr)| rr.rdata() == record.rdata())
352             .map(|(i, _)| i)
353             .collect::<Vec<usize>>();
354 
355         // if the Records are identical, ignore the update, update all that are not (ttl, etc.)
356         let mut replaced = false;
357         for i in to_replace {
358             if self.records[i] == record {
359                 return false;
360             }
361 
362             // TODO: this shouldn't really need a clone since there should only be one...
363             self.records.push(record.clone());
364             self.records.swap_remove(i);
365             self.ttl = record.ttl();
366             self.updated(serial);
367             replaced = true;
368         }
369 
370         if !replaced {
371             self.ttl = record.ttl();
372             self.updated(serial);
373             self.records.push(record);
374             true
375         } else {
376             replaced
377         }
378     }
379 
380     /// Removes the Resource Record if it exists.
381     ///
382     /// # Arguments
383     ///
384     /// * `record` - `Record` asserts that the `name` and `record_type` match the `RecordSet`. Removes
385     ///              any `record` if the record data, `RData`, match.
386     /// * `serial` - current serial number of the `SOA` record, this is to be used for `IXFR` and
387     ///              signing for DNSSec after updates. The serial will only be updated if the
388     ///              record was added.
389     ///
390     /// # Return value
391     ///
392     /// True if a record was removed.
remove(&mut self, record: &Record, serial: u32) -> bool393     pub fn remove(&mut self, record: &Record, serial: u32) -> bool {
394         assert_eq!(record.name(), &self.name);
395         assert!(record.rr_type() == self.record_type || record.rr_type() == RecordType::ANY);
396 
397         match record.rr_type() {
398             // never delete the last NS record
399             RecordType::NS => {
400                 if self.records.len() <= 1 {
401                     info!("ignoring delete of last NS record: {:?}", record);
402                     return false;
403                 }
404             }
405             // never delete SOA
406             RecordType::SOA => {
407                 info!("ignored delete of SOA");
408                 return false;
409             }
410             _ => (), // move on to the delete
411         }
412 
413         // remove the records, first collect all the indexes, then remove the records
414         let to_remove: Vec<usize> = self
415             .records
416             .iter()
417             .enumerate()
418             .filter(|&(_, rr)| rr.rdata() == record.rdata())
419             .map(|(i, _)| i)
420             .collect::<Vec<usize>>();
421 
422         let mut removed = false;
423         for i in to_remove {
424             self.records.remove(i);
425             removed = true;
426             self.updated(serial);
427         }
428 
429         removed
430     }
431 }
432 
433 impl From<Record> for RecordSet {
from(record: Record) -> Self434     fn from(record: Record) -> Self {
435         RecordSet {
436             name: record.name().clone(),
437             record_type: record.rr_type(),
438             dns_class: record.dns_class(),
439             ttl: record.ttl(),
440             records: vec![record],
441             rrsigs: vec![],
442             serial: 0,
443         }
444     }
445 }
446 
447 /// Types which implement this can be converted into a RecordSet
448 #[deprecated(note = "use From/Into")]
449 pub trait IntoRecordSet: Sized {
450     /// Performs the conversion to a RecordSet
into_record_set(self) -> RecordSet451     fn into_record_set(self) -> RecordSet;
452 }
453 
454 #[allow(deprecated)]
455 impl IntoRecordSet for RecordSet {
into_record_set(self) -> Self456     fn into_record_set(self) -> Self {
457         self
458     }
459 }
460 
461 impl IntoIterator for RecordSet {
462     type Item = Record;
463     type IntoIter = Chain<vec::IntoIter<Record>, vec::IntoIter<Record>>;
464 
into_iter(self) -> Self::IntoIter465     fn into_iter(self) -> Self::IntoIter {
466         self.records.into_iter().chain(self.rrsigs.into_iter())
467     }
468 }
469 
470 /// An iterator over all the records and their signatures
471 #[cfg(feature = "dnssec")]
472 #[derive(Debug)]
473 pub struct RecordsAndRrsigsIter<'r>(Chain<Iter<'r, Record>, RrsigsByAlgorithms<'r>>);
474 
475 #[cfg(feature = "dnssec")]
476 impl<'r> Iterator for RecordsAndRrsigsIter<'r> {
477     type Item = &'r Record;
478 
next(&mut self) -> Option<Self::Item>479     fn next(&mut self) -> Option<Self::Item> {
480         self.0.next()
481     }
482 }
483 
484 /// An iterator that limits the record signatures by SupportedAlgorithms
485 #[cfg(feature = "dnssec")]
486 #[derive(Debug)]
487 pub struct RrsigsByAlgorithms<'r> {
488     rrsigs: Iter<'r, Record>,
489     supported_algorithms: SupportedAlgorithms,
490 }
491 
492 #[cfg(feature = "dnssec")]
493 impl<'r> Iterator for RrsigsByAlgorithms<'r> {
494     type Item = &'r Record;
495 
next(&mut self) -> Option<Self::Item>496     fn next(&mut self) -> Option<Self::Item> {
497         use crate::rr::dnssec::rdata::DNSSECRData;
498         use crate::rr::dnssec::Algorithm;
499 
500         let supported_algorithms = self.supported_algorithms;
501 
502         // disable rfc 6975 when no supported_algorithms specified
503         if supported_algorithms.is_empty() {
504             self.rrsigs.next()
505         } else {
506             self.rrsigs
507                 .by_ref()
508                 .filter(|record| {
509                     if let RData::DNSSEC(DNSSECRData::SIG(ref rrsig)) = *record.rdata() {
510                         supported_algorithms.has(rrsig.algorithm())
511                     } else {
512                         false
513                     }
514                 })
515                 .max_by_key(|record| {
516                     if let RData::DNSSEC(DNSSECRData::SIG(ref rrsig)) = *record.rdata() {
517                         rrsig.algorithm()
518                     } else {
519                         Algorithm::RSASHA1
520                     }
521                 })
522         }
523     }
524 }
525 
526 /// An iterator over the RecordSet data
527 #[derive(Debug)]
528 pub enum RrsetRecords<'r> {
529     /// There are no records in the record set
530     Empty,
531     /// The records associated with the record set
532     RecordsOnly(Iter<'r, Record>),
533     /// The records along with their signatures in the record set
534     #[cfg(feature = "dnssec")]
535     RecordsAndRrsigs(RecordsAndRrsigsIter<'r>),
536 }
537 
538 impl<'r> RrsetRecords<'r> {
539     /// This is a best effort emptyness check
is_empty(&self) -> bool540     pub fn is_empty(&self) -> bool {
541         match *self {
542             RrsetRecords::Empty => true,
543             _ => false,
544         }
545     }
546 }
547 
548 impl<'r> Iterator for RrsetRecords<'r> {
549     type Item = &'r Record;
550 
next(&mut self) -> Option<Self::Item>551     fn next(&mut self) -> Option<Self::Item> {
552         match self {
553             RrsetRecords::Empty => None,
554             RrsetRecords::RecordsOnly(i) => i.next(),
555             #[cfg(feature = "dnssec")]
556             RrsetRecords::RecordsAndRrsigs(i) => i.next(),
557         }
558     }
559 }
560 
561 #[cfg(test)]
562 mod test {
563     use std::net::Ipv4Addr;
564     use std::str::FromStr;
565 
566     use crate::rr::rdata::SOA;
567     use crate::rr::*;
568 
569     #[test]
test_insert()570     fn test_insert() {
571         let name = Name::from_str("www.example.com.").unwrap();
572         let record_type = RecordType::A;
573         let mut rr_set = RecordSet::new(&name, record_type, 0);
574 
575         let insert = Record::new()
576             .set_name(name.clone())
577             .set_ttl(86400)
578             .set_rr_type(record_type)
579             .set_dns_class(DNSClass::IN)
580             .set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 24)))
581             .clone();
582 
583         assert!(rr_set.insert(insert.clone(), 0));
584         assert_eq!(rr_set.records_without_rrsigs().count(), 1);
585         assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
586 
587         // dups ignored
588         assert!(!rr_set.insert(insert.clone(), 0));
589         assert_eq!(rr_set.records_without_rrsigs().count(), 1);
590         assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
591 
592         // add one
593         let insert1 = Record::new()
594             .set_name(name)
595             .set_ttl(86400)
596             .set_rr_type(record_type)
597             .set_dns_class(DNSClass::IN)
598             .set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 25)))
599             .clone();
600         assert!(rr_set.insert(insert1.clone(), 0));
601         assert_eq!(rr_set.records_without_rrsigs().count(), 2);
602         assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
603         assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert1));
604     }
605 
606     #[test]
607     #[allow(clippy::unreadable_literal)]
test_insert_soa()608     fn test_insert_soa() {
609         let name = Name::from_str("example.com.").unwrap();
610         let record_type = RecordType::SOA;
611         let mut rr_set = RecordSet::new(&name, record_type, 0);
612 
613         let insert = Record::new()
614             .set_name(name.clone())
615             .set_ttl(3600)
616             .set_rr_type(RecordType::SOA)
617             .set_dns_class(DNSClass::IN)
618             .set_rdata(RData::SOA(SOA::new(
619                 Name::from_str("sns.dns.icann.org.").unwrap(),
620                 Name::from_str("noc.dns.icann.org.").unwrap(),
621                 2015082403,
622                 7200,
623                 3600,
624                 1209600,
625                 3600,
626             )))
627             .clone();
628         let same_serial = Record::new()
629             .set_name(name.clone())
630             .set_ttl(3600)
631             .set_rr_type(RecordType::SOA)
632             .set_dns_class(DNSClass::IN)
633             .set_rdata(RData::SOA(SOA::new(
634                 Name::from_str("sns.dns.icann.net.").unwrap(),
635                 Name::from_str("noc.dns.icann.net.").unwrap(),
636                 2015082403,
637                 7200,
638                 3600,
639                 1209600,
640                 3600,
641             )))
642             .clone();
643         let new_serial = Record::new()
644             .set_name(name)
645             .set_ttl(3600)
646             .set_rr_type(RecordType::SOA)
647             .set_dns_class(DNSClass::IN)
648             .set_rdata(RData::SOA(SOA::new(
649                 Name::from_str("sns.dns.icann.net.").unwrap(),
650                 Name::from_str("noc.dns.icann.net.").unwrap(),
651                 2015082404,
652                 7200,
653                 3600,
654                 1209600,
655                 3600,
656             )))
657             .clone();
658 
659         assert!(rr_set.insert(insert.clone(), 0));
660         assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
661         // same serial number
662         assert!(!rr_set.insert(same_serial.clone(), 0));
663         assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
664         assert!(!rr_set
665             .records_without_rrsigs()
666             .any(|ref x| x == &&same_serial));
667 
668         assert!(rr_set.insert(new_serial.clone(), 0));
669         assert!(!rr_set.insert(same_serial.clone(), 0));
670         assert!(!rr_set.insert(insert.clone(), 0));
671 
672         assert!(rr_set
673             .records_without_rrsigs()
674             .any(|ref x| x == &&new_serial));
675         assert!(!rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
676         assert!(!rr_set
677             .records_without_rrsigs()
678             .any(|ref x| x == &&same_serial));
679     }
680 
681     #[test]
test_insert_cname()682     fn test_insert_cname() {
683         let name = Name::from_str("web.example.com.").unwrap();
684         let cname = Name::from_str("www.example.com.").unwrap();
685         let new_cname = Name::from_str("w2.example.com.").unwrap();
686 
687         let record_type = RecordType::CNAME;
688         let mut rr_set = RecordSet::new(&name, record_type, 0);
689 
690         let insert = Record::new()
691             .set_name(name.clone())
692             .set_ttl(3600)
693             .set_rr_type(RecordType::CNAME)
694             .set_dns_class(DNSClass::IN)
695             .set_rdata(RData::CNAME(cname))
696             .clone();
697         let new_record = Record::new()
698             .set_name(name)
699             .set_ttl(3600)
700             .set_rr_type(RecordType::CNAME)
701             .set_dns_class(DNSClass::IN)
702             .set_rdata(RData::CNAME(new_cname))
703             .clone();
704 
705         assert!(rr_set.insert(insert.clone(), 0));
706         assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
707 
708         // update the record
709         assert!(rr_set.insert(new_record.clone(), 0));
710         assert!(!rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
711         assert!(rr_set
712             .records_without_rrsigs()
713             .any(|ref x| x == &&new_record));
714     }
715 
716     #[test]
test_remove()717     fn test_remove() {
718         let name = Name::from_str("www.example.com.").unwrap();
719         let record_type = RecordType::A;
720         let mut rr_set = RecordSet::new(&name, record_type, 0);
721 
722         let insert = Record::new()
723             .set_name(name.clone())
724             .set_ttl(86400)
725             .set_rr_type(record_type)
726             .set_dns_class(DNSClass::IN)
727             .set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 24)))
728             .clone();
729         let insert1 = Record::new()
730             .set_name(name)
731             .set_ttl(86400)
732             .set_rr_type(record_type)
733             .set_dns_class(DNSClass::IN)
734             .set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 25)))
735             .clone();
736 
737         assert!(rr_set.insert(insert.clone(), 0));
738         assert!(rr_set.insert(insert1.clone(), 0));
739 
740         assert!(rr_set.remove(&insert, 0));
741         assert!(!rr_set.remove(&insert, 0));
742         assert!(rr_set.remove(&insert1, 0));
743         assert!(!rr_set.remove(&insert1, 0));
744     }
745 
746     #[test]
747     #[allow(clippy::unreadable_literal)]
test_remove_soa()748     fn test_remove_soa() {
749         let name = Name::from_str("www.example.com.").unwrap();
750         let record_type = RecordType::SOA;
751         let mut rr_set = RecordSet::new(&name, record_type, 0);
752 
753         let insert = Record::new()
754             .set_name(name)
755             .set_ttl(3600)
756             .set_rr_type(RecordType::SOA)
757             .set_dns_class(DNSClass::IN)
758             .set_rdata(RData::SOA(SOA::new(
759                 Name::from_str("sns.dns.icann.org.").unwrap(),
760                 Name::from_str("noc.dns.icann.org.").unwrap(),
761                 2015082403,
762                 7200,
763                 3600,
764                 1209600,
765                 3600,
766             )))
767             .clone();
768 
769         assert!(rr_set.insert(insert.clone(), 0));
770         assert!(!rr_set.remove(&insert, 0));
771         assert!(rr_set.records_without_rrsigs().any(|ref x| x == &&insert));
772     }
773 
774     #[test]
test_remove_ns()775     fn test_remove_ns() {
776         let name = Name::from_str("example.com.").unwrap();
777         let record_type = RecordType::NS;
778         let mut rr_set = RecordSet::new(&name, record_type, 0);
779 
780         let ns1 = Record::new()
781             .set_name(name.clone())
782             .set_ttl(86400)
783             .set_rr_type(RecordType::NS)
784             .set_dns_class(DNSClass::IN)
785             .set_rdata(RData::NS(Name::from_str("a.iana-servers.net.").unwrap()))
786             .clone();
787         let ns2 = Record::new()
788             .set_name(name)
789             .set_ttl(86400)
790             .set_rr_type(RecordType::NS)
791             .set_dns_class(DNSClass::IN)
792             .set_rdata(RData::NS(Name::from_str("b.iana-servers.net.").unwrap()))
793             .clone();
794 
795         assert!(rr_set.insert(ns1.clone(), 0));
796         assert!(rr_set.insert(ns2.clone(), 0));
797 
798         // ok to remove one, but not two...
799         assert!(rr_set.remove(&ns1, 0));
800         assert!(!rr_set.remove(&ns2, 0));
801 
802         // check that we can swap which ones are removed
803         assert!(rr_set.insert(ns1.clone(), 0));
804 
805         assert!(rr_set.remove(&ns2, 0));
806         assert!(!rr_set.remove(&ns1, 0));
807     }
808 
809     #[test]
810     #[cfg(feature = "dnssec")] // This tests RFC 6975, a DNSSEC-specific feature.
811     #[allow(clippy::block_in_if_condition_stmt)]
test_get_filter()812     fn test_get_filter() {
813         use crate::rr::dnssec::rdata::SIG;
814         use crate::rr::dnssec::rdata::{DNSSECRData, DNSSECRecordType};
815         use crate::rr::dnssec::{Algorithm, SupportedAlgorithms};
816 
817         let name = Name::root();
818         let rsasha256 = SIG::new(
819             RecordType::A,
820             Algorithm::RSASHA256,
821             0,
822             0,
823             0,
824             0,
825             0,
826             Name::root(),
827             vec![],
828         );
829         let ecp256 = SIG::new(
830             RecordType::A,
831             Algorithm::ECDSAP256SHA256,
832             0,
833             0,
834             0,
835             0,
836             0,
837             Name::root(),
838             vec![],
839         );
840         let ecp384 = SIG::new(
841             RecordType::A,
842             Algorithm::ECDSAP384SHA384,
843             0,
844             0,
845             0,
846             0,
847             0,
848             Name::root(),
849             vec![],
850         );
851         let ed25519 = SIG::new(
852             RecordType::A,
853             Algorithm::ED25519,
854             0,
855             0,
856             0,
857             0,
858             0,
859             Name::root(),
860             vec![],
861         );
862 
863         let rrsig_rsa = Record::new()
864             .set_name(name.clone())
865             .set_ttl(3600)
866             .set_rr_type(RecordType::DNSSEC(DNSSECRecordType::RRSIG))
867             .set_dns_class(DNSClass::IN)
868             .set_rdata(RData::DNSSEC(DNSSECRData::SIG(rsasha256)))
869             .clone();
870         let rrsig_ecp256 = Record::new()
871             .set_name(name.clone())
872             .set_ttl(3600)
873             .set_rr_type(RecordType::DNSSEC(DNSSECRecordType::RRSIG))
874             .set_dns_class(DNSClass::IN)
875             .set_rdata(RData::DNSSEC(DNSSECRData::SIG(ecp256)))
876             .clone();
877         let rrsig_ecp384 = Record::new()
878             .set_name(name.clone())
879             .set_ttl(3600)
880             .set_rr_type(RecordType::DNSSEC(DNSSECRecordType::RRSIG))
881             .set_dns_class(DNSClass::IN)
882             .set_rdata(RData::DNSSEC(DNSSECRData::SIG(ecp384)))
883             .clone();
884         let rrsig_ed25519 = Record::new()
885             .set_name(name.clone())
886             .set_ttl(3600)
887             .set_rr_type(RecordType::DNSSEC(DNSSECRecordType::RRSIG))
888             .set_dns_class(DNSClass::IN)
889             .set_rdata(RData::DNSSEC(DNSSECRData::SIG(ed25519)))
890             .clone();
891 
892         let a = Record::new()
893             .set_name(name)
894             .set_ttl(3600)
895             .set_rr_type(RecordType::A)
896             .set_dns_class(DNSClass::IN)
897             .set_rdata(RData::A(Ipv4Addr::new(93, 184, 216, 24)))
898             .clone();
899 
900         let mut rrset = RecordSet::from(a);
901         rrset.insert_rrsig(rrsig_rsa);
902         rrset.insert_rrsig(rrsig_ecp256);
903         rrset.insert_rrsig(rrsig_ecp384);
904         rrset.insert_rrsig(rrsig_ed25519);
905 
906         assert!(rrset
907             .records_with_rrsigs(SupportedAlgorithms::all(),)
908             .any(
909                 |r| if let RData::DNSSEC(DNSSECRData::SIG(ref sig)) = *r.rdata() {
910                     sig.algorithm() == Algorithm::ED25519
911                 } else {
912                     false
913                 },
914             ));
915 
916         let mut supported_algorithms = SupportedAlgorithms::new();
917         supported_algorithms.set(Algorithm::ECDSAP384SHA384);
918         assert!(rrset.records_with_rrsigs(supported_algorithms).any(|r| {
919             if let RData::DNSSEC(DNSSECRData::SIG(ref sig)) = *r.rdata() {
920                 sig.algorithm() == Algorithm::ECDSAP384SHA384
921             } else {
922                 false
923             }
924         }));
925 
926         let mut supported_algorithms = SupportedAlgorithms::new();
927         supported_algorithms.set(Algorithm::ED25519);
928         assert!(rrset.records_with_rrsigs(supported_algorithms).any(|r| {
929             if let RData::DNSSEC(DNSSECRData::SIG(ref sig)) = *r.rdata() {
930                 sig.algorithm() == Algorithm::ED25519
931             } else {
932                 false
933             }
934         }));
935     }
936 }
937