domain/rdata/
dnssec.rs

1//! Record data from [RFC 4034]: DS, DNSKEY, RRSIG, and NSEC records.
2//!
3//! This RFC defines the record types for DNSSEC.
4//!
5//! [RFC 4034]: https://tools.ietf.org/html/rfc4034
6
7use crate::base::cmp::CanonicalOrd;
8use crate::base::iana::{DigestAlgorithm, Rtype, SecurityAlgorithm};
9use crate::base::name::{FlattenInto, ParsedName, ToName};
10use crate::base::rdata::{
11    ComposeRecordData, LongRecordData, ParseRecordData, RecordData,
12};
13use crate::base::scan::{Scan, Scanner, ScannerError};
14use crate::base::serial::Serial;
15use crate::base::wire::{Compose, Composer, FormError, Parse, ParseError};
16use crate::base::zonefile_fmt::{self, Formatter, ZonefileFmt};
17use crate::base::Ttl;
18use crate::utils::{base16, base64};
19use core::cmp::Ordering;
20use core::convert::TryInto;
21use core::{cmp, fmt, hash, str};
22use octseq::builder::{
23    EmptyBuilder, FreezeBuilder, FromBuilder, OctetsBuilder, Truncate,
24};
25use octseq::octets::{Octets, OctetsFrom, OctetsInto};
26use octseq::parse::Parser;
27#[cfg(feature = "serde")]
28use octseq::serde::{DeserializeOctets, SerializeOctets};
29#[cfg(feature = "std")]
30use std::vec::Vec;
31use time::{Date, Month, PrimitiveDateTime, Time};
32
33//------------ Dnskey --------------------------------------------------------
34
35#[derive(Clone)]
36#[cfg_attr(
37    feature = "serde",
38    derive(serde::Serialize, serde::Deserialize),
39    serde(bound(
40        serialize = "
41            Octs: octseq::serde::SerializeOctets + AsRef<[u8]>
42        ",
43        deserialize = "
44            Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
45            <Octs as FromBuilder>::Builder:
46                OctetsBuilder + EmptyBuilder,
47        ",
48    ))
49)]
50pub struct Dnskey<Octs> {
51    flags: u16,
52    protocol: u8,
53    algorithm: SecurityAlgorithm,
54    #[cfg_attr(
55        feature = "serde",
56        serde(with = "crate::utils::base64::serde")
57    )]
58    public_key: Octs,
59}
60
61impl Dnskey<()> {
62    /// The rtype of this record data type.
63    pub(crate) const RTYPE: Rtype = Rtype::DNSKEY;
64}
65
66impl<Octs> Dnskey<Octs> {
67    pub fn new(
68        flags: u16,
69        protocol: u8,
70        algorithm: SecurityAlgorithm,
71        public_key: Octs,
72    ) -> Result<Self, LongRecordData>
73    where
74        Octs: AsRef<[u8]>,
75    {
76        LongRecordData::check_len(
77            usize::from(
78                u16::COMPOSE_LEN
79                    + u8::COMPOSE_LEN
80                    + SecurityAlgorithm::COMPOSE_LEN,
81            )
82            .checked_add(public_key.as_ref().len())
83            .expect("long key"),
84        )?;
85        Ok(Dnskey {
86            flags,
87            protocol,
88            algorithm,
89            public_key,
90        })
91    }
92
93    /// Creates new DNSKEY record data without checking.
94    ///
95    /// # Safety
96    ///
97    /// The caller needs to ensure that wire format representation of the
98    /// record data is at most 65,535 octets long.
99    pub unsafe fn new_unchecked(
100        flags: u16,
101        protocol: u8,
102        algorithm: SecurityAlgorithm,
103        public_key: Octs,
104    ) -> Self {
105        Dnskey {
106            flags,
107            protocol,
108            algorithm,
109            public_key,
110        }
111    }
112
113    pub fn flags(&self) -> u16 {
114        self.flags
115    }
116
117    pub fn protocol(&self) -> u8 {
118        self.protocol
119    }
120
121    pub fn algorithm(&self) -> SecurityAlgorithm {
122        self.algorithm
123    }
124
125    pub fn public_key(&self) -> &Octs {
126        &self.public_key
127    }
128
129    pub fn into_public_key(self) -> Octs {
130        self.public_key
131    }
132
133    pub fn convert<Other: From<Octs>>(self) -> Dnskey<Other> {
134        Dnskey {
135            flags: self.flags,
136            protocol: self.protocol,
137            algorithm: self.algorithm,
138            public_key: self.public_key.into(),
139        }
140    }
141
142    /// Returns whether the Revoke flag is set.
143    ///
144    /// See [RFC 5011, Section 3].
145    ///
146    /// [RFC 5011, Section 3]: https://tools.ietf.org/html/rfc5011#section-3
147    pub fn is_revoked(&self) -> bool {
148        self.flags() & 0b0000_0000_1000_0000 != 0
149    }
150
151    /// Returns whether the the Secure Entry Point (SEP) flag is set.
152    ///
153    /// See [RFC 4034, Section 2.1.1]:
154    ///
155    /// > This flag is only intended to be a hint to zone signing or
156    /// > debugging software as to the intended use of this DNSKEY record;
157    /// > validators MUST NOT alter their behavior during the signature
158    /// > validation process in any way based on the setting of this bit.
159    ///
160    /// [RFC 4034, Section 2.1.1]: https://tools.ietf.org/html/rfc4034#section-2.1.1
161    pub fn is_secure_entry_point(&self) -> bool {
162        self.flags() & 0b0000_0000_0000_0001 != 0
163    }
164
165    /// Returns whether the Zone Key flag is set.
166    ///
167    /// If the flag is not set, the key MUST NOT be used to verify RRSIGs that
168    /// cover RRSETs. See [RFC 4034, Section 2.1.1].
169    ///
170    /// [RFC 4034, Section 2.1.1]: https://tools.ietf.org/html/rfc4034#section-2.1.1
171    pub fn is_zone_key(&self) -> bool {
172        self.flags() & 0b0000_0001_0000_0000 != 0
173    }
174
175    /// Returns the key tag for this DNSKEY data.
176    pub fn key_tag(&self) -> u16
177    where
178        Octs: AsRef<[u8]>,
179    {
180        if self.algorithm == SecurityAlgorithm::RSAMD5 {
181            // The key tag is third-to-last and second-to-last octets of the
182            // key as a big-endian u16. If we don’t have enough octets in the
183            // key, we return 0.
184            let len = self.public_key.as_ref().len();
185            if len > 2 {
186                u16::from_be_bytes(
187                    self.public_key.as_ref()[len - 3..len - 1]
188                        .try_into()
189                        .unwrap(),
190                )
191            } else {
192                0
193            }
194        } else {
195            // Treat record data as a octet sequence. Add octets at odd
196            // indexes as they are, add octets at even indexes shifted left
197            // by 8 bits.
198            let mut res = u32::from(self.flags);
199            res += u32::from(self.protocol) << 8;
200            res += u32::from(self.algorithm.to_int());
201            let mut iter = self.public_key().as_ref().iter();
202
203            // I find this clearer with a loop.
204            #[allow(clippy::while_let_loop)]
205            loop {
206                match iter.next() {
207                    Some(&x) => res += u32::from(x) << 8,
208                    None => break,
209                }
210                match iter.next() {
211                    Some(&x) => res += u32::from(x),
212                    None => break,
213                }
214            }
215
216            res += (res >> 16) & 0xFFFF;
217            (res & 0xFFFF) as u16
218        }
219    }
220
221    pub(super) fn convert_octets<Target: OctetsFrom<Octs>>(
222        self,
223    ) -> Result<Dnskey<Target>, Target::Error> {
224        Ok(unsafe {
225            Dnskey::new_unchecked(
226                self.flags,
227                self.protocol,
228                self.algorithm,
229                self.public_key.try_octets_into()?,
230            )
231        })
232    }
233
234    pub(super) fn flatten<Target: OctetsFrom<Octs>>(
235        self,
236    ) -> Result<Dnskey<Target>, Target::Error> {
237        self.convert_octets()
238    }
239
240    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
241        parser: &mut Parser<'a, Src>,
242    ) -> Result<Self, ParseError> {
243        let len = match parser.remaining().checked_sub(4) {
244            Some(len) => len,
245            None => return Err(ParseError::ShortInput),
246        };
247        Ok(unsafe {
248            Self::new_unchecked(
249                u16::parse(parser)?,
250                u8::parse(parser)?,
251                SecurityAlgorithm::parse(parser)?,
252                parser.parse_octets(len)?,
253            )
254        })
255    }
256
257    pub fn scan<S: Scanner<Octets = Octs>>(
258        scanner: &mut S,
259    ) -> Result<Self, S::Error>
260    where
261        Octs: AsRef<[u8]>,
262    {
263        Self::new(
264            u16::scan(scanner)?,
265            u8::scan(scanner)?,
266            SecurityAlgorithm::scan(scanner)?,
267            scanner.convert_entry(base64::SymbolConverter::new())?,
268        )
269        .map_err(|err| S::Error::custom(err.as_str()))
270    }
271}
272
273//--- OctetsFrom
274
275impl<Octs, SrcOcts> OctetsFrom<Dnskey<SrcOcts>> for Dnskey<Octs>
276where
277    Octs: OctetsFrom<SrcOcts>,
278{
279    type Error = Octs::Error;
280
281    fn try_octets_from(source: Dnskey<SrcOcts>) -> Result<Self, Self::Error> {
282        Ok(unsafe {
283            Dnskey::new_unchecked(
284                source.flags,
285                source.protocol,
286                source.algorithm,
287                Octs::try_octets_from(source.public_key)?,
288            )
289        })
290    }
291}
292
293//--- PartialEq and Eq
294
295impl<Octs, Other> PartialEq<Dnskey<Other>> for Dnskey<Octs>
296where
297    Octs: AsRef<[u8]>,
298    Other: AsRef<[u8]>,
299{
300    fn eq(&self, other: &Dnskey<Other>) -> bool {
301        self.flags == other.flags
302            && self.protocol == other.protocol
303            && self.algorithm == other.algorithm
304            && self.public_key.as_ref() == other.public_key.as_ref()
305    }
306}
307
308impl<Octs: AsRef<[u8]>> Eq for Dnskey<Octs> {}
309
310//--- PartialOrd, CanonicalOrd, and Ord
311
312impl<Octs, Other> PartialOrd<Dnskey<Other>> for Dnskey<Octs>
313where
314    Octs: AsRef<[u8]>,
315    Other: AsRef<[u8]>,
316{
317    fn partial_cmp(&self, other: &Dnskey<Other>) -> Option<Ordering> {
318        Some(self.canonical_cmp(other))
319    }
320}
321
322impl<Octs, Other> CanonicalOrd<Dnskey<Other>> for Dnskey<Octs>
323where
324    Octs: AsRef<[u8]>,
325    Other: AsRef<[u8]>,
326{
327    fn canonical_cmp(&self, other: &Dnskey<Other>) -> Ordering {
328        match self.flags.cmp(&other.flags) {
329            Ordering::Equal => {}
330            other => return other,
331        }
332        match self.protocol.cmp(&other.protocol) {
333            Ordering::Equal => {}
334            other => return other,
335        }
336        match self.algorithm.cmp(&other.algorithm) {
337            Ordering::Equal => {}
338            other => return other,
339        }
340        self.public_key.as_ref().cmp(other.public_key.as_ref())
341    }
342}
343
344impl<Octs: AsRef<[u8]>> Ord for Dnskey<Octs> {
345    fn cmp(&self, other: &Self) -> Ordering {
346        self.canonical_cmp(other)
347    }
348}
349
350//--- Hash
351
352impl<Octs: AsRef<[u8]>> hash::Hash for Dnskey<Octs> {
353    fn hash<H: hash::Hasher>(&self, state: &mut H) {
354        self.flags.hash(state);
355        self.protocol.hash(state);
356        self.algorithm.hash(state);
357        self.public_key.as_ref().hash(state);
358    }
359}
360
361//--- RecordData, ParseRecordData, ComposeRecordData
362
363impl<Octs> RecordData for Dnskey<Octs> {
364    fn rtype(&self) -> Rtype {
365        Dnskey::RTYPE
366    }
367}
368
369impl<'a, Octs> ParseRecordData<'a, Octs> for Dnskey<Octs::Range<'a>>
370where
371    Octs: Octets + ?Sized,
372{
373    fn parse_rdata(
374        rtype: Rtype,
375        parser: &mut Parser<'a, Octs>,
376    ) -> Result<Option<Self>, ParseError> {
377        if rtype == Dnskey::RTYPE {
378            Self::parse(parser).map(Some)
379        } else {
380            Ok(None)
381        }
382    }
383}
384
385impl<Octs: AsRef<[u8]>> ComposeRecordData for Dnskey<Octs> {
386    fn rdlen(&self, _compress: bool) -> Option<u16> {
387        Some(
388            u16::try_from(self.public_key.as_ref().len())
389                .expect("long key")
390                .checked_add(
391                    u16::COMPOSE_LEN
392                        + u8::COMPOSE_LEN
393                        + SecurityAlgorithm::COMPOSE_LEN,
394                )
395                .expect("long key"),
396        )
397    }
398
399    fn compose_rdata<Target: Composer + ?Sized>(
400        &self,
401        target: &mut Target,
402    ) -> Result<(), Target::AppendError> {
403        self.flags.compose(target)?;
404        self.protocol.compose(target)?;
405        self.algorithm.compose(target)?;
406        target.append_slice(self.public_key.as_ref())
407    }
408
409    fn compose_canonical_rdata<Target: Composer + ?Sized>(
410        &self,
411        target: &mut Target,
412    ) -> Result<(), Target::AppendError> {
413        self.compose_rdata(target)
414    }
415}
416
417//--- Display
418
419impl<Octs: AsRef<[u8]>> fmt::Display for Dnskey<Octs> {
420    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
421        write!(f, "{} {} {} ", self.flags, self.protocol, self.algorithm)?;
422        base64::display(&self.public_key, f)
423    }
424}
425
426//--- Debug
427
428impl<Octs: AsRef<[u8]>> fmt::Debug for Dnskey<Octs> {
429    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
430        f.debug_struct("Dnskey")
431            .field("flags", &self.flags)
432            .field("protocol", &self.protocol)
433            .field("algorithm", &self.algorithm)
434            .field("public_key", &self.public_key.as_ref())
435            .finish()
436    }
437}
438
439//--- ZonefileFmt
440
441impl<Octs: AsRef<[u8]>> ZonefileFmt for Dnskey<Octs> {
442    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
443        let revoked = self.is_revoked();
444        let sep = self.is_secure_entry_point();
445        let zone_key = self.is_zone_key();
446
447        p.block(|p| {
448            p.write_token(self.flags)?;
449            p.write_comment(format_args!(
450                "flags:{}{}{}{}",
451                if revoked { " revoked" } else { "" },
452                if sep { " sep" } else { "" },
453                if zone_key { " zone_key" } else { "" },
454                if self.flags == 0 { " <none>" } else { "" },
455            ))?;
456            p.write_token(self.protocol)?;
457            p.write_comment("protocol")?;
458            p.write_show(self.algorithm)?;
459            p.write_token(base64::encode_display(&self.public_key))?;
460            p.write_comment(format_args!("key tag: {}", self.key_tag()))
461        })
462    }
463}
464
465//------------ ProtoRrsig ----------------------------------------------------
466
467/// The RRSIG RDATA to be included when creating the signature.
468#[derive(Clone)]
469pub struct ProtoRrsig<Name> {
470    type_covered: Rtype,
471    algorithm: SecurityAlgorithm,
472    labels: u8,
473    original_ttl: Ttl,
474    expiration: Timestamp,
475    inception: Timestamp,
476    key_tag: u16,
477    signer_name: Name,
478}
479
480impl<Name> ProtoRrsig<Name> {
481    #[allow(clippy::too_many_arguments)] // XXX Consider changing.
482    pub fn new(
483        type_covered: Rtype,
484        algorithm: SecurityAlgorithm,
485        labels: u8,
486        original_ttl: Ttl,
487        expiration: Timestamp,
488        inception: Timestamp,
489        key_tag: u16,
490        signer_name: Name,
491    ) -> Self {
492        ProtoRrsig {
493            type_covered,
494            algorithm,
495            labels,
496            original_ttl,
497            expiration,
498            inception,
499            key_tag,
500            signer_name,
501        }
502    }
503
504    pub fn into_rrsig<Octs: AsRef<[u8]>>(
505        self,
506        signature: Octs,
507    ) -> Result<Rrsig<Octs, Name>, LongRecordData>
508    where
509        Name: ToName,
510    {
511        Rrsig::new(
512            self.type_covered,
513            self.algorithm,
514            self.labels,
515            self.original_ttl,
516            self.expiration,
517            self.inception,
518            self.key_tag,
519            self.signer_name,
520            signature,
521        )
522    }
523}
524
525impl<Name: ToName> ProtoRrsig<Name> {
526    pub fn compose<Target: Composer + ?Sized>(
527        &self,
528        target: &mut Target,
529    ) -> Result<(), Target::AppendError> {
530        self.compose_head(target)?;
531        self.signer_name.compose(target)
532    }
533
534    pub fn compose_canonical<Target: Composer + ?Sized>(
535        &self,
536        target: &mut Target,
537    ) -> Result<(), Target::AppendError> {
538        self.compose_head(target)?;
539        self.signer_name.compose_canonical(target)
540    }
541
542    fn compose_head<Target: Composer + ?Sized>(
543        &self,
544        target: &mut Target,
545    ) -> Result<(), Target::AppendError> {
546        self.type_covered.compose(target)?;
547        self.algorithm.compose(target)?;
548        self.labels.compose(target)?;
549        self.original_ttl.compose(target)?;
550        self.expiration.compose(target)?;
551        self.inception.compose(target)?;
552        self.key_tag.compose(target)
553    }
554}
555
556//--- OctetsFrom and FlattenInto
557
558impl<Name, SrcName> OctetsFrom<ProtoRrsig<SrcName>> for ProtoRrsig<Name>
559where
560    Name: OctetsFrom<SrcName>,
561{
562    type Error = Name::Error;
563
564    fn try_octets_from(
565        source: ProtoRrsig<SrcName>,
566    ) -> Result<Self, Self::Error> {
567        Ok(ProtoRrsig::new(
568            source.type_covered,
569            source.algorithm,
570            source.labels,
571            source.original_ttl,
572            source.expiration,
573            source.inception,
574            source.key_tag,
575            Name::try_octets_from(source.signer_name)?,
576        ))
577    }
578}
579
580impl<Name, TName> FlattenInto<ProtoRrsig<TName>> for ProtoRrsig<Name>
581where
582    Name: FlattenInto<TName>,
583{
584    type AppendError = Name::AppendError;
585
586    fn try_flatten_into(
587        self,
588    ) -> Result<ProtoRrsig<TName>, Name::AppendError> {
589        Ok(ProtoRrsig::new(
590            self.type_covered,
591            self.algorithm,
592            self.labels,
593            self.original_ttl,
594            self.expiration,
595            self.inception,
596            self.key_tag,
597            self.signer_name.try_flatten_into()?,
598        ))
599    }
600}
601
602//------------ Timestamp ------------------------------------------------------
603
604/// A Timestamp for RRSIG Records.
605///
606/// DNS uses 32 bit timestamps that are conceptionally
607/// viewed as the 32 bit modulus of a larger number space. Because of that,
608/// special rules apply when processing these values.
609///
610/// [RFC 4034] defines Timestamps as the number of seconds elepased since
611/// since 1 January 1970 00:00:00 UTC, ignoring leap seconds. Timestamps
612/// are compared using so-called "Serial number arithmetic", as defined in
613/// [RFC 1982].
614///
615/// The RFC defines the semantics for doing arithmetics in the
616/// face of these wrap-arounds. This type implements these semantics atop a
617/// native `u32`. The RFC defines two operations: addition and comparison.
618///
619/// For addition, the amount added can only be a positive number of up to
620/// `2^31 - 1`. Because of this, we decided to not implement the
621/// `Add` trait but rather have a dedicated method `add` so as to not cause
622/// surprise panics.
623///
624/// Timestamps only implement a partial ordering. That is, there are
625/// pairs of values that are not equal but there still isn’t one value larger
626/// than the other. Since this is neatly implemented by the `PartialOrd`
627/// trait, the type implements that.
628///
629/// [RFC 1982]: https://tools.ietf.org/html/rfc1982
630/// [RFC 4034]: https://tools.ietf.org/html/rfc4034
631
632#[derive(Clone, Copy, Debug, PartialEq)]
633#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
634pub struct Timestamp(Serial);
635
636impl Timestamp {
637    /// Returns a serial number for the current Unix time.
638    #[cfg(feature = "std")]
639    #[must_use]
640    pub fn now() -> Self {
641        Self(Serial::now())
642    }
643
644    /// Scan a serial represention signature time value.
645    ///
646    /// In [RRSIG] records, the expiration and inception times are given as
647    /// serial values. Their representation format can either be the
648    /// value or a specific date in `YYYYMMDDHHmmSS` format.
649    ///
650    /// [RRSIG]: Rrsig
651    pub fn scan<S: Scanner>(scanner: &mut S) -> Result<Self, S::Error> {
652        let mut pos = 0;
653        let mut buf = [0u8; 14];
654        scanner.scan_symbols(|symbol| {
655            if pos >= 14 {
656                return Err(S::Error::custom("illegal signature time"));
657            }
658            buf[pos] = symbol
659                .into_digit(10)
660                .map_err(|_| S::Error::custom("illegal signature time"))?
661                as u8;
662            pos += 1;
663            Ok(())
664        })?;
665        if pos <= 10 {
666            // We have an integer. We generate it into a u64 to deal
667            // with possible overflows.
668            let mut res = 0u64;
669            for ch in &buf[..pos] {
670                res = res * 10 + (u64::from(*ch));
671            }
672            if res > u64::from(u32::MAX) {
673                Err(S::Error::custom("illegal signature time"))
674            } else {
675                Ok(Self(Serial(res as u32)))
676            }
677        } else if pos == 14 {
678            let year = u32_from_buf(&buf[0..4]) as i32;
679            let month = Month::try_from(u8_from_buf(&buf[4..6]))
680                .map_err(|_| S::Error::custom("illegal signature time"))?;
681            let day = u8_from_buf(&buf[6..8]);
682            let hour = u8_from_buf(&buf[8..10]);
683            let minute = u8_from_buf(&buf[10..12]);
684            let second = u8_from_buf(&buf[12..14]);
685            Ok(Self(Serial(
686                PrimitiveDateTime::new(
687                    Date::from_calendar_date(year, month, day).map_err(
688                        |_| S::Error::custom("illegal signature time"),
689                    )?,
690                    Time::from_hms(hour, minute, second).map_err(|_| {
691                        S::Error::custom("illegal signature time")
692                    })?,
693                )
694                .assume_utc()
695                .unix_timestamp() as u32,
696            )))
697        } else {
698            Err(S::Error::custom("illegal signature time"))
699        }
700    }
701
702    /// Returns the timestamp as a raw integer.
703    #[must_use]
704    pub fn into_int(self) -> u32 {
705        self.0.into_int()
706    }
707}
708
709/// # Parsing and Composing
710///
711impl Timestamp {
712    pub const COMPOSE_LEN: u16 = Serial::COMPOSE_LEN;
713
714    pub fn parse<Octs: AsRef<[u8]> + ?Sized>(
715        parser: &mut Parser<'_, Octs>,
716    ) -> Result<Self, ParseError> {
717        Serial::parse(parser).map(Self)
718    }
719
720    pub fn compose<Target: Composer + ?Sized>(
721        &self,
722        target: &mut Target,
723    ) -> Result<(), Target::AppendError> {
724        self.0.compose(target)
725    }
726}
727
728//--- From and FromStr
729
730impl From<u32> for Timestamp {
731    fn from(item: u32) -> Self {
732        Self(Serial::from(item))
733    }
734}
735
736impl str::FromStr for Timestamp {
737    type Err = IllegalSignatureTime;
738
739    /// Parses a timestamp value from a string.
740    ///
741    /// The presentation format can either be their integer value or a
742    /// specific date in `YYYYMMDDHHmmSS` format.
743    fn from_str(src: &str) -> Result<Self, Self::Err> {
744        if !src.is_ascii() {
745            return Err(IllegalSignatureTime(()));
746        }
747        if src.len() == 14 {
748            let year = u32::from_str(&src[0..4])
749                .map_err(|_| IllegalSignatureTime(()))?
750                as i32;
751            let month = Month::try_from(
752                u8::from_str(&src[4..6])
753                    .map_err(|_| IllegalSignatureTime(()))?,
754            )
755            .map_err(|_| IllegalSignatureTime(()))?;
756            let day = u8::from_str(&src[6..8])
757                .map_err(|_| IllegalSignatureTime(()))?;
758            let hour = u8::from_str(&src[8..10])
759                .map_err(|_| IllegalSignatureTime(()))?;
760            let minute = u8::from_str(&src[10..12])
761                .map_err(|_| IllegalSignatureTime(()))?;
762            let second = u8::from_str(&src[12..14])
763                .map_err(|_| IllegalSignatureTime(()))?;
764            Ok(Timestamp(Serial(
765                PrimitiveDateTime::new(
766                    Date::from_calendar_date(year, month, day)
767                        .map_err(|_| IllegalSignatureTime(()))?,
768                    Time::from_hms(hour, minute, second)
769                        .map_err(|_| IllegalSignatureTime(()))?,
770                )
771                .assume_utc()
772                .unix_timestamp() as u32,
773            )))
774        } else {
775            Serial::from_str(src)
776                .map(Timestamp)
777                .map_err(|_| IllegalSignatureTime(()))
778        }
779    }
780}
781
782//--- Display
783
784impl fmt::Display for Timestamp {
785    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
786        write!(f, "{}", self.0)
787    }
788}
789
790//--- ZonefileFmt
791
792impl ZonefileFmt for Timestamp {
793    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
794        p.write_token(self.0)
795    }
796}
797
798//--- PartialOrd and CanonicalOrd
799
800impl cmp::PartialOrd for Timestamp {
801    fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
802        self.0.partial_cmp(&other.0)
803    }
804}
805
806impl CanonicalOrd for Timestamp {
807    fn canonical_cmp(&self, other: &Self) -> cmp::Ordering {
808        self.0.canonical_cmp(&other.0)
809    }
810}
811
812//------------ Helper Functions ----------------------------------------------
813
814fn u8_from_buf(buf: &[u8]) -> u8 {
815    let mut res = 0;
816    for ch in buf {
817        res = res * 10 + *ch;
818    }
819    res
820}
821
822fn u32_from_buf(buf: &[u8]) -> u32 {
823    let mut res = 0;
824    for ch in buf {
825        res = res * 10 + (u32::from(*ch));
826    }
827    res
828}
829
830//------------ Rrsig ---------------------------------------------------------
831
832#[derive(Clone)]
833#[cfg_attr(
834    feature = "serde",
835    derive(serde::Serialize, serde::Deserialize),
836    serde(bound(
837        serialize = "
838            Octs: octseq::serde::SerializeOctets + AsRef<[u8]>,
839            Name: serde::Serialize,
840        ",
841        deserialize = "
842            Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
843            <Octs as FromBuilder>::Builder:
844                OctetsBuilder + EmptyBuilder,
845            Name: serde::Deserialize<'de>,
846        ",
847    ))
848)]
849pub struct Rrsig<Octs, Name> {
850    type_covered: Rtype,
851    algorithm: SecurityAlgorithm,
852    labels: u8,
853    original_ttl: Ttl,
854    expiration: Timestamp,
855    inception: Timestamp,
856    key_tag: u16,
857    signer_name: Name,
858    #[cfg_attr(
859        feature = "serde",
860        serde(with = "crate::utils::base64::serde")
861    )]
862    signature: Octs,
863}
864
865impl Rrsig<(), ()> {
866    /// The rtype of this record data type.
867    pub(crate) const RTYPE: Rtype = Rtype::RRSIG;
868}
869
870impl<Octs, Name> Rrsig<Octs, Name> {
871    #[allow(clippy::too_many_arguments)] // XXX Consider changing.
872    pub fn new(
873        type_covered: Rtype,
874        algorithm: SecurityAlgorithm,
875        labels: u8,
876        original_ttl: Ttl,
877        expiration: Timestamp,
878        inception: Timestamp,
879        key_tag: u16,
880        signer_name: Name,
881        signature: Octs,
882    ) -> Result<Self, LongRecordData>
883    where
884        Octs: AsRef<[u8]>,
885        Name: ToName,
886    {
887        LongRecordData::check_len(
888            usize::from(
889                Rtype::COMPOSE_LEN
890                    + SecurityAlgorithm::COMPOSE_LEN
891                    + u8::COMPOSE_LEN
892                    + u32::COMPOSE_LEN
893                    + Timestamp::COMPOSE_LEN
894                    + Timestamp::COMPOSE_LEN
895                    + u16::COMPOSE_LEN
896                    + signer_name.compose_len(),
897            )
898            .checked_add(signature.as_ref().len())
899            .expect("long signature"),
900        )?;
901        Ok(unsafe {
902            Rrsig::new_unchecked(
903                type_covered,
904                algorithm,
905                labels,
906                original_ttl,
907                expiration,
908                inception,
909                key_tag,
910                signer_name,
911                signature,
912            )
913        })
914    }
915
916    /// Creates new RRSIG record data without checking.
917    ///
918    /// # Safety
919    ///
920    /// The caller needs to ensure that wire format representation of the
921    /// record data is at most 65,535 octets long.
922    #[allow(clippy::too_many_arguments)] // XXX Consider changing.
923    pub unsafe fn new_unchecked(
924        type_covered: Rtype,
925        algorithm: SecurityAlgorithm,
926        labels: u8,
927        original_ttl: Ttl,
928        expiration: Timestamp,
929        inception: Timestamp,
930        key_tag: u16,
931        signer_name: Name,
932        signature: Octs,
933    ) -> Self {
934        Rrsig {
935            type_covered,
936            algorithm,
937            labels,
938            original_ttl,
939            expiration,
940            inception,
941            key_tag,
942            signer_name,
943            signature,
944        }
945    }
946
947    pub fn type_covered(&self) -> Rtype {
948        self.type_covered
949    }
950
951    pub fn algorithm(&self) -> SecurityAlgorithm {
952        self.algorithm
953    }
954
955    pub fn labels(&self) -> u8 {
956        self.labels
957    }
958
959    pub fn original_ttl(&self) -> Ttl {
960        self.original_ttl
961    }
962
963    pub fn expiration(&self) -> Timestamp {
964        self.expiration
965    }
966
967    pub fn inception(&self) -> Timestamp {
968        self.inception
969    }
970
971    pub fn key_tag(&self) -> u16 {
972        self.key_tag
973    }
974
975    pub fn signer_name(&self) -> &Name {
976        &self.signer_name
977    }
978
979    pub fn signature(&self) -> &Octs {
980        &self.signature
981    }
982
983    pub fn set_signature(&mut self, signature: Octs) {
984        self.signature = signature
985    }
986
987    pub(super) fn convert_octets<TOcts, TName>(
988        self,
989    ) -> Result<Rrsig<TOcts, TName>, TOcts::Error>
990    where
991        TOcts: OctetsFrom<Octs>,
992        TName: OctetsFrom<Name, Error = TOcts::Error>,
993    {
994        Ok(unsafe {
995            Rrsig::new_unchecked(
996                self.type_covered,
997                self.algorithm,
998                self.labels,
999                self.original_ttl,
1000                self.expiration,
1001                self.inception,
1002                self.key_tag,
1003                TName::try_octets_from(self.signer_name)?,
1004                TOcts::try_octets_from(self.signature)?,
1005            )
1006        })
1007    }
1008
1009    pub(super) fn flatten<TOcts, TName>(
1010        self,
1011    ) -> Result<Rrsig<TOcts, TName>, TOcts::Error>
1012    where
1013        TOcts: OctetsFrom<Octs>,
1014        Name: FlattenInto<TName, AppendError = TOcts::Error>,
1015    {
1016        Ok(unsafe {
1017            Rrsig::new_unchecked(
1018                self.type_covered,
1019                self.algorithm,
1020                self.labels,
1021                self.original_ttl,
1022                self.expiration,
1023                self.inception,
1024                self.key_tag,
1025                self.signer_name.try_flatten_into()?,
1026                TOcts::try_octets_from(self.signature)?,
1027            )
1028        })
1029    }
1030
1031    pub fn scan<S: Scanner<Octets = Octs, Name = Name>>(
1032        scanner: &mut S,
1033    ) -> Result<Self, S::Error>
1034    where
1035        Octs: AsRef<[u8]>,
1036        Name: ToName,
1037    {
1038        Self::new(
1039            Rtype::scan(scanner)?,
1040            SecurityAlgorithm::scan(scanner)?,
1041            u8::scan(scanner)?,
1042            Ttl::scan(scanner)?,
1043            Timestamp::scan(scanner)?,
1044            Timestamp::scan(scanner)?,
1045            u16::scan(scanner)?,
1046            scanner.scan_name()?,
1047            scanner.convert_entry(base64::SymbolConverter::new())?,
1048        )
1049        .map_err(|err| S::Error::custom(err.as_str()))
1050    }
1051}
1052
1053impl<Octs> Rrsig<Octs, ParsedName<Octs>> {
1054    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
1055        parser: &mut Parser<'a, Src>,
1056    ) -> Result<Self, ParseError> {
1057        let type_covered = Rtype::parse(parser)?;
1058        let algorithm = SecurityAlgorithm::parse(parser)?;
1059        let labels = u8::parse(parser)?;
1060        let original_ttl = Ttl::parse(parser)?;
1061        let expiration = Timestamp::parse(parser)?;
1062        let inception = Timestamp::parse(parser)?;
1063        let key_tag = u16::parse(parser)?;
1064        let signer_name = ParsedName::parse(parser)?;
1065        let len = parser.remaining();
1066        let signature = parser.parse_octets(len)?;
1067        Ok(unsafe {
1068            Self::new_unchecked(
1069                type_covered,
1070                algorithm,
1071                labels,
1072                original_ttl,
1073                expiration,
1074                inception,
1075                key_tag,
1076                signer_name,
1077                signature,
1078            )
1079        })
1080    }
1081}
1082
1083//--- OctetsFrom and FlattenInto
1084
1085impl<Octs, SrcOcts, Name, SrcName> OctetsFrom<Rrsig<SrcOcts, SrcName>>
1086    for Rrsig<Octs, Name>
1087where
1088    Octs: OctetsFrom<SrcOcts>,
1089    Name: OctetsFrom<SrcName>,
1090    Octs::Error: From<Name::Error>,
1091{
1092    type Error = Octs::Error;
1093
1094    fn try_octets_from(
1095        source: Rrsig<SrcOcts, SrcName>,
1096    ) -> Result<Self, Self::Error> {
1097        Ok(unsafe {
1098            Rrsig::new_unchecked(
1099                source.type_covered,
1100                source.algorithm,
1101                source.labels,
1102                source.original_ttl,
1103                source.expiration,
1104                source.inception,
1105                source.key_tag,
1106                Name::try_octets_from(source.signer_name)?,
1107                Octs::try_octets_from(source.signature)?,
1108            )
1109        })
1110    }
1111}
1112
1113impl<Octs, TOcts, Name, TName> FlattenInto<Rrsig<TOcts, TName>>
1114    for Rrsig<Octs, Name>
1115where
1116    TOcts: OctetsFrom<Octs>,
1117    Name: FlattenInto<TName, AppendError = TOcts::Error>,
1118{
1119    type AppendError = TOcts::Error;
1120
1121    fn try_flatten_into(self) -> Result<Rrsig<TOcts, TName>, TOcts::Error> {
1122        self.flatten()
1123    }
1124}
1125
1126//--- PartialEq and Eq
1127
1128impl<N, NN, O, OO> PartialEq<Rrsig<OO, NN>> for Rrsig<O, N>
1129where
1130    N: ToName,
1131    NN: ToName,
1132    O: AsRef<[u8]>,
1133    OO: AsRef<[u8]>,
1134{
1135    fn eq(&self, other: &Rrsig<OO, NN>) -> bool {
1136        self.type_covered == other.type_covered
1137            && self.algorithm == other.algorithm
1138            && self.labels == other.labels
1139            && self.original_ttl == other.original_ttl
1140            && self.expiration.into_int() == other.expiration.into_int()
1141            && self.inception.into_int() == other.inception.into_int()
1142            && self.key_tag == other.key_tag
1143            && self.signer_name.name_eq(&other.signer_name)
1144            && self.signature.as_ref() == other.signature.as_ref()
1145    }
1146}
1147
1148impl<Octs, Name> Eq for Rrsig<Octs, Name>
1149where
1150    Octs: AsRef<[u8]>,
1151    Name: ToName,
1152{
1153}
1154
1155//--- PartialOrd, CanonicalOrd, and Ord
1156
1157impl<N, NN, O, OO> PartialOrd<Rrsig<OO, NN>> for Rrsig<O, N>
1158where
1159    N: ToName,
1160    NN: ToName,
1161    O: AsRef<[u8]>,
1162    OO: AsRef<[u8]>,
1163{
1164    fn partial_cmp(&self, other: &Rrsig<OO, NN>) -> Option<Ordering> {
1165        match self.type_covered.partial_cmp(&other.type_covered) {
1166            Some(Ordering::Equal) => {}
1167            other => return other,
1168        }
1169        match self.algorithm.partial_cmp(&other.algorithm) {
1170            Some(Ordering::Equal) => {}
1171            other => return other,
1172        }
1173        match self.labels.partial_cmp(&other.labels) {
1174            Some(Ordering::Equal) => {}
1175            other => return other,
1176        }
1177        match self.original_ttl.partial_cmp(&other.original_ttl) {
1178            Some(Ordering::Equal) => {}
1179            other => return other,
1180        }
1181        match self.expiration.partial_cmp(&other.expiration) {
1182            Some(Ordering::Equal) => {}
1183            other => return other,
1184        }
1185        match self.inception.partial_cmp(&other.inception) {
1186            Some(Ordering::Equal) => {}
1187            other => return other,
1188        }
1189        match self.key_tag.partial_cmp(&other.key_tag) {
1190            Some(Ordering::Equal) => {}
1191            other => return other,
1192        }
1193        match self.signer_name.name_cmp(&other.signer_name) {
1194            Ordering::Equal => {}
1195            other => return Some(other),
1196        }
1197        self.signature
1198            .as_ref()
1199            .partial_cmp(other.signature.as_ref())
1200    }
1201}
1202
1203impl<N, NN, O, OO> CanonicalOrd<Rrsig<OO, NN>> for Rrsig<O, N>
1204where
1205    N: ToName,
1206    NN: ToName,
1207    O: AsRef<[u8]>,
1208    OO: AsRef<[u8]>,
1209{
1210    fn canonical_cmp(&self, other: &Rrsig<OO, NN>) -> Ordering {
1211        match self.type_covered.cmp(&other.type_covered) {
1212            Ordering::Equal => {}
1213            other => return other,
1214        }
1215        match self.algorithm.cmp(&other.algorithm) {
1216            Ordering::Equal => {}
1217            other => return other,
1218        }
1219        match self.labels.cmp(&other.labels) {
1220            Ordering::Equal => {}
1221            other => return other,
1222        }
1223        match self.original_ttl.cmp(&other.original_ttl) {
1224            Ordering::Equal => {}
1225            other => return other,
1226        }
1227        match self.expiration.canonical_cmp(&other.expiration) {
1228            Ordering::Equal => {}
1229            other => return other,
1230        }
1231        match self.inception.canonical_cmp(&other.inception) {
1232            Ordering::Equal => {}
1233            other => return other,
1234        }
1235        match self.key_tag.cmp(&other.key_tag) {
1236            Ordering::Equal => {}
1237            other => return other,
1238        }
1239        match self.signer_name.lowercase_composed_cmp(&other.signer_name) {
1240            Ordering::Equal => {}
1241            other => return other,
1242        }
1243        self.signature.as_ref().cmp(other.signature.as_ref())
1244    }
1245}
1246
1247impl<O: AsRef<[u8]>, N: ToName> Ord for Rrsig<O, N> {
1248    fn cmp(&self, other: &Self) -> Ordering {
1249        self.canonical_cmp(other)
1250    }
1251}
1252
1253//--- Hash
1254
1255impl<O: AsRef<[u8]>, N: hash::Hash> hash::Hash for Rrsig<O, N> {
1256    fn hash<H: hash::Hasher>(&self, state: &mut H) {
1257        self.type_covered.hash(state);
1258        self.algorithm.hash(state);
1259        self.labels.hash(state);
1260        self.original_ttl.hash(state);
1261        self.expiration.into_int().hash(state);
1262        self.inception.into_int().hash(state);
1263        self.key_tag.hash(state);
1264        self.signer_name.hash(state);
1265        self.signature.as_ref().hash(state);
1266    }
1267}
1268
1269//--- RecordData, ParseRecordData, ComposeRecordData
1270
1271impl<Octs, Name> RecordData for Rrsig<Octs, Name> {
1272    fn rtype(&self) -> Rtype {
1273        Rrsig::RTYPE
1274    }
1275}
1276
1277impl<'a, Octs: Octets + ?Sized> ParseRecordData<'a, Octs>
1278    for Rrsig<Octs::Range<'a>, ParsedName<Octs::Range<'a>>>
1279{
1280    fn parse_rdata(
1281        rtype: Rtype,
1282        parser: &mut Parser<'a, Octs>,
1283    ) -> Result<Option<Self>, ParseError> {
1284        if rtype == Rrsig::RTYPE {
1285            Self::parse(parser).map(Some)
1286        } else {
1287            Ok(None)
1288        }
1289    }
1290}
1291
1292impl<Octs, Name> ComposeRecordData for Rrsig<Octs, Name>
1293where
1294    Octs: AsRef<[u8]>,
1295    Name: ToName,
1296{
1297    fn rdlen(&self, _compress: bool) -> Option<u16> {
1298        Some(
1299            (Rtype::COMPOSE_LEN
1300                + SecurityAlgorithm::COMPOSE_LEN
1301                + u8::COMPOSE_LEN
1302                + u32::COMPOSE_LEN
1303                + Timestamp::COMPOSE_LEN
1304                + Timestamp::COMPOSE_LEN
1305                + u16::COMPOSE_LEN
1306                + self.signer_name.compose_len())
1307            .checked_add(
1308                u16::try_from(self.signature.as_ref().len())
1309                    .expect("long signature"),
1310            )
1311            .expect("long signature"),
1312        )
1313    }
1314
1315    fn compose_rdata<Target: Composer + ?Sized>(
1316        &self,
1317        target: &mut Target,
1318    ) -> Result<(), Target::AppendError> {
1319        self.compose_head(target)?;
1320        self.signer_name.compose(target)?;
1321        target.append_slice(self.signature.as_ref())
1322    }
1323
1324    fn compose_canonical_rdata<Target: Composer + ?Sized>(
1325        &self,
1326        target: &mut Target,
1327    ) -> Result<(), Target::AppendError> {
1328        self.compose_head(target)?;
1329        self.signer_name.compose_canonical(target)?;
1330        target.append_slice(self.signature.as_ref())
1331    }
1332}
1333
1334impl<Octs: AsRef<[u8]>, Name: ToName> Rrsig<Octs, Name> {
1335    fn compose_head<Target: Composer + ?Sized>(
1336        &self,
1337        target: &mut Target,
1338    ) -> Result<(), Target::AppendError> {
1339        self.type_covered.compose(target)?;
1340        self.algorithm.compose(target)?;
1341        self.labels.compose(target)?;
1342        self.original_ttl.compose(target)?;
1343        self.expiration.compose(target)?;
1344        self.inception.compose(target)?;
1345        self.key_tag.compose(target)
1346    }
1347}
1348
1349//--- Display
1350
1351impl<Octs, Name> fmt::Display for Rrsig<Octs, Name>
1352where
1353    Octs: AsRef<[u8]>,
1354    Name: fmt::Display,
1355{
1356    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1357        write!(
1358            f,
1359            "{} {} {} {} {} {} {} {}. ",
1360            self.type_covered,
1361            self.algorithm,
1362            self.labels,
1363            self.original_ttl.as_secs(),
1364            self.expiration,
1365            self.inception,
1366            self.key_tag,
1367            self.signer_name
1368        )?;
1369        base64::display(&self.signature, f)
1370    }
1371}
1372
1373//--- Debug
1374
1375impl<Octs, Name> fmt::Debug for Rrsig<Octs, Name>
1376where
1377    Octs: AsRef<[u8]>,
1378    Name: fmt::Debug,
1379{
1380    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1381        f.debug_struct("Rrsig")
1382            .field("type_covered", &self.type_covered)
1383            .field("algorithm", &self.algorithm)
1384            .field("labels", &self.labels)
1385            .field("original_ttl", &self.original_ttl)
1386            .field("expiration", &self.expiration)
1387            .field("inception", &self.inception)
1388            .field("key_tag", &self.key_tag)
1389            .field("signer_name", &self.signer_name)
1390            .field("signature", &self.signature.as_ref())
1391            .finish()
1392    }
1393}
1394
1395//--- ZonefileFmt
1396
1397impl<Octs, Name> ZonefileFmt for Rrsig<Octs, Name>
1398where
1399    Octs: AsRef<[u8]>,
1400    Name: ToName,
1401{
1402    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
1403        p.block(|p| {
1404            p.write_show(self.type_covered)?;
1405            p.write_show(self.algorithm)?;
1406            p.write_token(self.labels)?;
1407            p.write_comment("labels")?;
1408            p.write_show(self.original_ttl)?;
1409            p.write_comment("original ttl")?;
1410            p.write_show(self.expiration)?;
1411            p.write_comment("expiration")?;
1412            p.write_show(self.inception)?;
1413            p.write_comment("inception")?;
1414            p.write_token(self.key_tag)?;
1415            p.write_comment("key tag")?;
1416            p.write_token(self.signer_name.fmt_with_dot())?;
1417            p.write_comment("signer name")?;
1418            p.write_token(base64::encode_display(&self.signature))
1419        })
1420    }
1421}
1422
1423//------------ Nsec ----------------------------------------------------------
1424
1425#[derive(Clone)]
1426#[cfg_attr(
1427    feature = "serde",
1428    derive(serde::Serialize, serde::Deserialize),
1429    serde(bound(
1430        serialize = "
1431            Octs: octseq::serde::SerializeOctets + AsRef<[u8]>,
1432            Name: serde::Serialize,
1433        ",
1434        deserialize = "
1435            Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
1436            <Octs as FromBuilder>::Builder:
1437                OctetsBuilder + EmptyBuilder + Truncate 
1438                + AsRef<[u8]> + AsMut<[u8]>,
1439            Name: serde::Deserialize<'de>,
1440        ",
1441    ))
1442)]
1443pub struct Nsec<Octs, Name> {
1444    next_name: Name,
1445    types: RtypeBitmap<Octs>,
1446}
1447
1448impl Nsec<(), ()> {
1449    /// The rtype of this record data type.
1450    pub(crate) const RTYPE: Rtype = Rtype::NSEC;
1451}
1452
1453impl<Octs, Name> Nsec<Octs, Name> {
1454    pub fn new(next_name: Name, types: RtypeBitmap<Octs>) -> Self {
1455        Nsec { next_name, types }
1456    }
1457
1458    pub fn next_name(&self) -> &Name {
1459        &self.next_name
1460    }
1461
1462    pub fn set_next_name(&mut self, next_name: Name) {
1463        self.next_name = next_name
1464    }
1465
1466    pub fn types(&self) -> &RtypeBitmap<Octs> {
1467        &self.types
1468    }
1469
1470    pub(super) fn convert_octets<TOcts, TName>(
1471        self,
1472    ) -> Result<Nsec<TOcts, TName>, TOcts::Error>
1473    where
1474        TOcts: OctetsFrom<Octs>,
1475        TName: OctetsFrom<Name, Error = TOcts::Error>,
1476    {
1477        Ok(Nsec::new(
1478            self.next_name.try_octets_into()?,
1479            self.types.convert_octets()?,
1480        ))
1481    }
1482
1483    pub(super) fn flatten<TOcts, TName>(
1484        self,
1485    ) -> Result<Nsec<TOcts, TName>, TOcts::Error>
1486    where
1487        TOcts: OctetsFrom<Octs>,
1488        Name: FlattenInto<TName, AppendError = TOcts::Error>,
1489    {
1490        Ok(Nsec::new(
1491            self.next_name.try_flatten_into()?,
1492            self.types.convert_octets()?,
1493        ))
1494    }
1495
1496    pub fn scan<S: Scanner<Octets = Octs, Name = Name>>(
1497        scanner: &mut S,
1498    ) -> Result<Self, S::Error> {
1499        Ok(Self::new(scanner.scan_name()?, RtypeBitmap::scan(scanner)?))
1500    }
1501}
1502
1503impl<Octs: AsRef<[u8]>> Nsec<Octs, ParsedName<Octs>> {
1504    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
1505        parser: &mut Parser<'a, Src>,
1506    ) -> Result<Self, ParseError> {
1507        Ok(Nsec::new(
1508            ParsedName::parse(parser)?,
1509            RtypeBitmap::parse(parser)?,
1510        ))
1511    }
1512}
1513
1514//--- OctetsFrom and FlattenInto
1515
1516impl<Octs, SrcOcts, Name, SrcName> OctetsFrom<Nsec<SrcOcts, SrcName>>
1517    for Nsec<Octs, Name>
1518where
1519    Octs: OctetsFrom<SrcOcts>,
1520    Name: OctetsFrom<SrcName, Error = Octs::Error>,
1521{
1522    type Error = Octs::Error;
1523
1524    fn try_octets_from(
1525        source: Nsec<SrcOcts, SrcName>,
1526    ) -> Result<Self, Self::Error> {
1527        Ok(Nsec::new(
1528            Name::try_octets_from(source.next_name)?,
1529            RtypeBitmap::try_octets_from(source.types)?,
1530        ))
1531    }
1532}
1533
1534impl<Octs, TOcts, Name, TName> FlattenInto<Nsec<TOcts, TName>>
1535    for Nsec<Octs, Name>
1536where
1537    TOcts: OctetsFrom<Octs>,
1538    Name: FlattenInto<TName, AppendError = TOcts::Error>,
1539{
1540    type AppendError = TOcts::Error;
1541
1542    fn try_flatten_into(self) -> Result<Nsec<TOcts, TName>, TOcts::Error> {
1543        self.flatten()
1544    }
1545}
1546
1547//--- PartialEq and Eq
1548
1549impl<O, OO, N, NN> PartialEq<Nsec<OO, NN>> for Nsec<O, N>
1550where
1551    O: AsRef<[u8]>,
1552    OO: AsRef<[u8]>,
1553    N: ToName,
1554    NN: ToName,
1555{
1556    fn eq(&self, other: &Nsec<OO, NN>) -> bool {
1557        self.next_name.name_eq(&other.next_name) && self.types == other.types
1558    }
1559}
1560
1561impl<O: AsRef<[u8]>, N: ToName> Eq for Nsec<O, N> {}
1562
1563//--- PartialOrd, Ord, and CanonicalOrd
1564
1565impl<O, OO, N, NN> PartialOrd<Nsec<OO, NN>> for Nsec<O, N>
1566where
1567    O: AsRef<[u8]>,
1568    OO: AsRef<[u8]>,
1569    N: ToName,
1570    NN: ToName,
1571{
1572    fn partial_cmp(&self, other: &Nsec<OO, NN>) -> Option<Ordering> {
1573        match self.next_name.name_cmp(&other.next_name) {
1574            Ordering::Equal => {}
1575            other => return Some(other),
1576        }
1577        self.types.partial_cmp(&self.types)
1578    }
1579}
1580
1581impl<O, OO, N, NN> CanonicalOrd<Nsec<OO, NN>> for Nsec<O, N>
1582where
1583    O: AsRef<[u8]>,
1584    OO: AsRef<[u8]>,
1585    N: ToName,
1586    NN: ToName,
1587{
1588    fn canonical_cmp(&self, other: &Nsec<OO, NN>) -> Ordering {
1589        // RFC 6840 says that Nsec::next_name is not converted to lower case.
1590        match self.next_name.composed_cmp(&other.next_name) {
1591            Ordering::Equal => {}
1592            other => return other,
1593        }
1594        self.types.cmp(&self.types)
1595    }
1596}
1597
1598impl<O, N> Ord for Nsec<O, N>
1599where
1600    O: AsRef<[u8]>,
1601    N: ToName,
1602{
1603    fn cmp(&self, other: &Self) -> Ordering {
1604        match self.next_name.name_cmp(&other.next_name) {
1605            Ordering::Equal => {}
1606            other => return other,
1607        }
1608        self.types.cmp(&self.types)
1609    }
1610}
1611
1612//--- Hash
1613
1614impl<Octs: AsRef<[u8]>, Name: hash::Hash> hash::Hash for Nsec<Octs, Name> {
1615    fn hash<H: hash::Hasher>(&self, state: &mut H) {
1616        self.next_name.hash(state);
1617        self.types.hash(state);
1618    }
1619}
1620
1621//--- RecordData, ParseRecordData, ComposeRecordData
1622
1623impl<Octs, Name> RecordData for Nsec<Octs, Name> {
1624    fn rtype(&self) -> Rtype {
1625        Nsec::RTYPE
1626    }
1627}
1628
1629impl<'a, Octs: Octets + ?Sized> ParseRecordData<'a, Octs>
1630    for Nsec<Octs::Range<'a>, ParsedName<Octs::Range<'a>>>
1631{
1632    fn parse_rdata(
1633        rtype: Rtype,
1634        parser: &mut Parser<'a, Octs>,
1635    ) -> Result<Option<Self>, ParseError> {
1636        if rtype == Nsec::RTYPE {
1637            Self::parse(parser).map(Some)
1638        } else {
1639            Ok(None)
1640        }
1641    }
1642}
1643
1644impl<Octs, Name> ComposeRecordData for Nsec<Octs, Name>
1645where
1646    Octs: AsRef<[u8]>,
1647    Name: ToName,
1648{
1649    fn rdlen(&self, _compress: bool) -> Option<u16> {
1650        Some(
1651            self.next_name
1652                .compose_len()
1653                .checked_add(self.types.compose_len())
1654                .expect("long type bitmap"),
1655        )
1656    }
1657
1658    fn compose_rdata<Target: Composer + ?Sized>(
1659        &self,
1660        target: &mut Target,
1661    ) -> Result<(), Target::AppendError> {
1662        self.next_name.compose(target)?;
1663        self.types.compose(target)
1664    }
1665
1666    fn compose_canonical_rdata<Target: Composer + ?Sized>(
1667        &self,
1668        target: &mut Target,
1669    ) -> Result<(), Target::AppendError> {
1670        // Deferring to compose_rdata is correct as we keep the case of the
1671        // next name.
1672        self.compose_rdata(target)
1673    }
1674}
1675
1676//--- Display
1677
1678impl<Octs, Name> fmt::Display for Nsec<Octs, Name>
1679where
1680    Octs: AsRef<[u8]>,
1681    Name: fmt::Display,
1682{
1683    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1684        write!(f, "{}. {}", self.next_name, self.types)
1685    }
1686}
1687
1688//--- Debug
1689
1690impl<Octs, Name> fmt::Debug for Nsec<Octs, Name>
1691where
1692    Octs: AsRef<[u8]>,
1693    Name: fmt::Debug,
1694{
1695    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1696        f.debug_struct("Nsec")
1697            .field("next_name", &self.next_name)
1698            .field("types", &self.types)
1699            .finish()
1700    }
1701}
1702
1703//--- ZonefileFmt
1704
1705impl<Octs, Name> ZonefileFmt for Nsec<Octs, Name>
1706where
1707    Octs: AsRef<[u8]>,
1708    Name: ToName,
1709{
1710    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
1711        p.block(|p| {
1712            p.write_token(self.next_name.fmt_with_dot())?;
1713            p.write_show(&self.types)
1714        })
1715    }
1716}
1717
1718//------------ Ds -----------------------------------------------------------
1719
1720#[derive(Clone)]
1721#[cfg_attr(
1722    feature = "serde",
1723    derive(serde::Serialize, serde::Deserialize),
1724    serde(bound(
1725        serialize = "
1726            Octs: octseq::serde::SerializeOctets + AsRef<[u8]>
1727        ",
1728        deserialize = "
1729            Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
1730            <Octs as FromBuilder>::Builder:
1731                OctetsBuilder + EmptyBuilder,
1732        ",
1733    ))
1734)]
1735pub struct Ds<Octs> {
1736    key_tag: u16,
1737    algorithm: SecurityAlgorithm,
1738    digest_type: DigestAlgorithm,
1739    #[cfg_attr(
1740        feature = "serde",
1741        serde(with = "crate::utils::base16::serde")
1742    )]
1743    digest: Octs,
1744}
1745
1746impl Ds<()> {
1747    /// The rtype of this record data type.
1748    pub(crate) const RTYPE: Rtype = Rtype::DS;
1749}
1750
1751impl<Octs> Ds<Octs> {
1752    pub fn new(
1753        key_tag: u16,
1754        algorithm: SecurityAlgorithm,
1755        digest_type: DigestAlgorithm,
1756        digest: Octs,
1757    ) -> Result<Self, LongRecordData>
1758    where
1759        Octs: AsRef<[u8]>,
1760    {
1761        LongRecordData::check_len(
1762            usize::from(
1763                u16::COMPOSE_LEN
1764                    + SecurityAlgorithm::COMPOSE_LEN
1765                    + DigestAlgorithm::COMPOSE_LEN,
1766            )
1767            .checked_add(digest.as_ref().len())
1768            .expect("long digest"),
1769        )?;
1770        Ok(unsafe {
1771            Ds::new_unchecked(key_tag, algorithm, digest_type, digest)
1772        })
1773    }
1774
1775    /// Creates new DS record data without checking.
1776    ///
1777    /// # Safety
1778    ///
1779    /// The caller needs to ensure that wire format representation of the
1780    /// record data is at most 65,535 octets long.
1781    pub unsafe fn new_unchecked(
1782        key_tag: u16,
1783        algorithm: SecurityAlgorithm,
1784        digest_type: DigestAlgorithm,
1785        digest: Octs,
1786    ) -> Self {
1787        Ds {
1788            key_tag,
1789            algorithm,
1790            digest_type,
1791            digest,
1792        }
1793    }
1794
1795    pub fn key_tag(&self) -> u16 {
1796        self.key_tag
1797    }
1798
1799    pub fn algorithm(&self) -> SecurityAlgorithm {
1800        self.algorithm
1801    }
1802
1803    pub fn digest_type(&self) -> DigestAlgorithm {
1804        self.digest_type
1805    }
1806
1807    pub fn digest(&self) -> &Octs {
1808        &self.digest
1809    }
1810
1811    pub fn into_digest(self) -> Octs {
1812        self.digest
1813    }
1814
1815    pub(super) fn convert_octets<Target: OctetsFrom<Octs>>(
1816        self,
1817    ) -> Result<Ds<Target>, Target::Error> {
1818        Ok(unsafe {
1819            Ds::new_unchecked(
1820                self.key_tag,
1821                self.algorithm,
1822                self.digest_type,
1823                self.digest.try_octets_into()?,
1824            )
1825        })
1826    }
1827
1828    pub(super) fn flatten<Target: OctetsFrom<Octs>>(
1829        self,
1830    ) -> Result<Ds<Target>, Target::Error> {
1831        self.convert_octets()
1832    }
1833
1834    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
1835        parser: &mut Parser<'a, Src>,
1836    ) -> Result<Self, ParseError> {
1837        let len = match parser.remaining().checked_sub(4) {
1838            Some(len) => len,
1839            None => return Err(ParseError::ShortInput),
1840        };
1841        Ok(unsafe {
1842            Self::new_unchecked(
1843                u16::parse(parser)?,
1844                SecurityAlgorithm::parse(parser)?,
1845                DigestAlgorithm::parse(parser)?,
1846                parser.parse_octets(len)?,
1847            )
1848        })
1849    }
1850
1851    pub fn scan<S: Scanner<Octets = Octs>>(
1852        scanner: &mut S,
1853    ) -> Result<Self, S::Error>
1854    where
1855        Octs: AsRef<[u8]>,
1856    {
1857        Self::new(
1858            u16::scan(scanner)?,
1859            SecurityAlgorithm::scan(scanner)?,
1860            DigestAlgorithm::scan(scanner)?,
1861            scanner.convert_entry(base16::SymbolConverter::new())?,
1862        )
1863        .map_err(|err| S::Error::custom(err.as_str()))
1864    }
1865}
1866
1867//--- OctetsFrom
1868
1869impl<Octs, SrcOcts> OctetsFrom<Ds<SrcOcts>> for Ds<Octs>
1870where
1871    Octs: OctetsFrom<SrcOcts>,
1872{
1873    type Error = Octs::Error;
1874
1875    fn try_octets_from(source: Ds<SrcOcts>) -> Result<Self, Self::Error> {
1876        Ok(unsafe {
1877            Ds::new_unchecked(
1878                source.key_tag,
1879                source.algorithm,
1880                source.digest_type,
1881                Octs::try_octets_from(source.digest)?,
1882            )
1883        })
1884    }
1885}
1886
1887//--- PartialEq and Eq
1888
1889impl<Octs, Other> PartialEq<Ds<Other>> for Ds<Octs>
1890where
1891    Octs: AsRef<[u8]>,
1892    Other: AsRef<[u8]>,
1893{
1894    fn eq(&self, other: &Ds<Other>) -> bool {
1895        self.key_tag == other.key_tag
1896            && self.algorithm == other.algorithm
1897            && self.digest_type == other.digest_type
1898            && self.digest.as_ref().eq(other.digest.as_ref())
1899    }
1900}
1901
1902impl<Octs: AsRef<[u8]>> Eq for Ds<Octs> {}
1903
1904//--- PartialOrd, CanonicalOrd, and Ord
1905
1906impl<Octs, Other> PartialOrd<Ds<Other>> for Ds<Octs>
1907where
1908    Octs: AsRef<[u8]>,
1909    Other: AsRef<[u8]>,
1910{
1911    fn partial_cmp(&self, other: &Ds<Other>) -> Option<Ordering> {
1912        match self.key_tag.partial_cmp(&other.key_tag) {
1913            Some(Ordering::Equal) => {}
1914            other => return other,
1915        }
1916        match self.algorithm.partial_cmp(&other.algorithm) {
1917            Some(Ordering::Equal) => {}
1918            other => return other,
1919        }
1920        match self.digest_type.partial_cmp(&other.digest_type) {
1921            Some(Ordering::Equal) => {}
1922            other => return other,
1923        }
1924        self.digest.as_ref().partial_cmp(other.digest.as_ref())
1925    }
1926}
1927
1928impl<Octs, Other> CanonicalOrd<Ds<Other>> for Ds<Octs>
1929where
1930    Octs: AsRef<[u8]>,
1931    Other: AsRef<[u8]>,
1932{
1933    fn canonical_cmp(&self, other: &Ds<Other>) -> Ordering {
1934        match self.key_tag.cmp(&other.key_tag) {
1935            Ordering::Equal => {}
1936            other => return other,
1937        }
1938        match self.algorithm.cmp(&other.algorithm) {
1939            Ordering::Equal => {}
1940            other => return other,
1941        }
1942        match self.digest_type.cmp(&other.digest_type) {
1943            Ordering::Equal => {}
1944            other => return other,
1945        }
1946        self.digest.as_ref().cmp(other.digest.as_ref())
1947    }
1948}
1949
1950impl<Octs: AsRef<[u8]>> Ord for Ds<Octs> {
1951    fn cmp(&self, other: &Self) -> Ordering {
1952        self.canonical_cmp(other)
1953    }
1954}
1955
1956//--- Hash
1957
1958impl<Octs: AsRef<[u8]>> hash::Hash for Ds<Octs> {
1959    fn hash<H: hash::Hasher>(&self, state: &mut H) {
1960        self.key_tag.hash(state);
1961        self.algorithm.hash(state);
1962        self.digest_type.hash(state);
1963        self.digest.as_ref().hash(state);
1964    }
1965}
1966
1967//--- RecordData, ParseRecordData, ComposeRecordData
1968
1969impl<Octs> RecordData for Ds<Octs> {
1970    fn rtype(&self) -> Rtype {
1971        Ds::RTYPE
1972    }
1973}
1974
1975impl<'a, Octs> ParseRecordData<'a, Octs> for Ds<Octs::Range<'a>>
1976where
1977    Octs: Octets + ?Sized,
1978{
1979    fn parse_rdata(
1980        rtype: Rtype,
1981        parser: &mut Parser<'a, Octs>,
1982    ) -> Result<Option<Self>, ParseError> {
1983        if rtype == Ds::RTYPE {
1984            Self::parse(parser).map(Some)
1985        } else {
1986            Ok(None)
1987        }
1988    }
1989}
1990
1991impl<Octs: AsRef<[u8]>> ComposeRecordData for Ds<Octs> {
1992    fn rdlen(&self, _compress: bool) -> Option<u16> {
1993        Some(
1994            u16::checked_add(
1995                u16::COMPOSE_LEN
1996                    + SecurityAlgorithm::COMPOSE_LEN
1997                    + DigestAlgorithm::COMPOSE_LEN,
1998                self.digest.as_ref().len().try_into().expect("long digest"),
1999            )
2000            .expect("long digest"),
2001        )
2002    }
2003
2004    fn compose_rdata<Target: Composer + ?Sized>(
2005        &self,
2006        target: &mut Target,
2007    ) -> Result<(), Target::AppendError> {
2008        self.key_tag.compose(target)?;
2009        self.algorithm.compose(target)?;
2010        self.digest_type.compose(target)?;
2011        target.append_slice(self.digest.as_ref())
2012    }
2013
2014    fn compose_canonical_rdata<Target: Composer + ?Sized>(
2015        &self,
2016        target: &mut Target,
2017    ) -> Result<(), Target::AppendError> {
2018        self.compose_rdata(target)
2019    }
2020}
2021
2022//--- Display
2023
2024impl<Octs: AsRef<[u8]>> fmt::Display for Ds<Octs> {
2025    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2026        write!(
2027            f,
2028            "{} {} {} ",
2029            self.key_tag, self.algorithm, self.digest_type
2030        )?;
2031        for ch in self.digest.as_ref() {
2032            write!(f, "{:02x}", ch)?
2033        }
2034        Ok(())
2035    }
2036}
2037
2038//--- Debug
2039
2040impl<Octs: AsRef<[u8]>> fmt::Debug for Ds<Octs> {
2041    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2042        f.debug_struct("Ds")
2043            .field("key_tag", &self.key_tag)
2044            .field("algorithm", &self.algorithm)
2045            .field("digest_type", &self.digest_type)
2046            .field("digest", &self.digest.as_ref())
2047            .finish()
2048    }
2049}
2050
2051//--- ZonefileFmt
2052
2053impl<Octs: AsRef<[u8]>> ZonefileFmt for Ds<Octs> {
2054    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
2055        p.block(|p| {
2056            p.write_token(self.key_tag)?;
2057            p.write_comment("key tag")?;
2058            p.write_show(self.algorithm)?;
2059            p.write_show(self.digest_type)?;
2060            p.write_token(base16::encode_display(&self.digest))
2061        })
2062    }
2063}
2064
2065//------------ RtypeBitmap ---------------------------------------------------
2066
2067#[derive(Clone)]
2068pub struct RtypeBitmap<Octs>(Octs);
2069
2070impl<Octs> RtypeBitmap<Octs> {
2071    pub fn from_octets(octets: Octs) -> Result<Self, RtypeBitmapError>
2072    where
2073        Octs: AsRef<[u8]>,
2074    {
2075        {
2076            let mut data = octets.as_ref();
2077            while !data.is_empty() {
2078                // At least bitmap number and length must be present.
2079                if data.len() < 2 {
2080                    return Err(RtypeBitmapErrorEnum::ShortInput.into());
2081                }
2082
2083                let len = (data[1] as usize) + 2;
2084                // https://tools.ietf.org/html/rfc4034#section-4.1.2:
2085                //  Blocks with no types present MUST NOT be included.
2086                if len == 2 {
2087                    return Err(RtypeBitmapErrorEnum::BadRtypeBitmap.into());
2088                }
2089                if len > 34 {
2090                    return Err(RtypeBitmapErrorEnum::BadRtypeBitmap.into());
2091                }
2092                if data.len() < len {
2093                    return Err(RtypeBitmapErrorEnum::ShortInput.into());
2094                }
2095                data = &data[len..];
2096            }
2097        }
2098        Ok(RtypeBitmap(octets))
2099    }
2100
2101    #[must_use]
2102    pub fn builder() -> RtypeBitmapBuilder<Octs::Builder>
2103    where
2104        Octs: FromBuilder,
2105        <Octs as FromBuilder>::Builder: EmptyBuilder,
2106    {
2107        RtypeBitmapBuilder::new()
2108    }
2109
2110    pub fn scan<S: Scanner<Octets = Octs>>(
2111        scanner: &mut S,
2112    ) -> Result<Self, S::Error> {
2113        let mut builder =
2114            RtypeBitmapBuilder::with_builder(scanner.octets_builder()?);
2115        while scanner.continues() {
2116            builder
2117                .add(Rtype::scan(scanner)?)
2118                .map_err(|_| S::Error::short_buf())?;
2119        }
2120        Ok(builder.finalize())
2121    }
2122
2123    pub fn as_octets(&self) -> &Octs {
2124        &self.0
2125    }
2126
2127    pub(super) fn convert_octets<Target: OctetsFrom<Octs>>(
2128        self,
2129    ) -> Result<RtypeBitmap<Target>, Target::Error> {
2130        Ok(RtypeBitmap(self.0.try_octets_into()?))
2131    }
2132}
2133
2134impl<Octs: AsRef<[u8]>> RtypeBitmap<Octs> {
2135    pub fn as_slice(&self) -> &[u8] {
2136        self.0.as_ref()
2137    }
2138
2139    pub fn iter(&self) -> RtypeBitmapIter<'_> {
2140        RtypeBitmapIter::new(self.0.as_ref())
2141    }
2142
2143    pub fn contains(&self, rtype: Rtype) -> bool {
2144        let (block, octet, mask) = split_rtype(rtype);
2145        let mut data = self.0.as_ref();
2146        while !data.is_empty() {
2147            let ((window_num, window), next_data) =
2148                read_window(data).unwrap();
2149            if window_num == block {
2150                return !(window.len() <= octet || window[octet] & mask == 0);
2151            }
2152            data = next_data;
2153        }
2154        false
2155    }
2156
2157    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
2158        parser: &mut Parser<'a, Src>,
2159    ) -> Result<Self, ParseError> {
2160        let len = parser.remaining();
2161        RtypeBitmap::from_octets(parser.parse_octets(len)?)
2162            .map_err(Into::into)
2163    }
2164
2165    pub fn compose_len(&self) -> u16 {
2166        u16::try_from(self.0.as_ref().len()).expect("long rtype bitmap")
2167    }
2168
2169    pub fn compose<Target: OctetsBuilder + ?Sized>(
2170        &self,
2171        target: &mut Target,
2172    ) -> Result<(), Target::AppendError> {
2173        target.append_slice(self.0.as_ref())
2174    }
2175
2176    #[must_use]
2177    pub fn is_empty(&self) -> bool {
2178        self.iter().next().is_none()
2179    }
2180}
2181
2182//--- AsRef
2183
2184impl<T, Octs: AsRef<T>> AsRef<T> for RtypeBitmap<Octs> {
2185    fn as_ref(&self) -> &T {
2186        self.0.as_ref()
2187    }
2188}
2189
2190//--- OctetsFrom
2191
2192impl<Octs, SrcOcts> OctetsFrom<RtypeBitmap<SrcOcts>> for RtypeBitmap<Octs>
2193where
2194    Octs: OctetsFrom<SrcOcts>,
2195{
2196    type Error = Octs::Error;
2197
2198    fn try_octets_from(
2199        source: RtypeBitmap<SrcOcts>,
2200    ) -> Result<Self, Self::Error> {
2201        Octs::try_octets_from(source.0).map(RtypeBitmap)
2202    }
2203}
2204
2205//--- PartialEq and Eq
2206
2207impl<O, OO> PartialEq<RtypeBitmap<OO>> for RtypeBitmap<O>
2208where
2209    O: AsRef<[u8]>,
2210    OO: AsRef<[u8]>,
2211{
2212    fn eq(&self, other: &RtypeBitmap<OO>) -> bool {
2213        self.0.as_ref().eq(other.0.as_ref())
2214    }
2215}
2216
2217impl<O: AsRef<[u8]>> Eq for RtypeBitmap<O> {}
2218
2219//--- PartialOrd, CanonicalOrd, and Ord
2220
2221impl<O, OO> PartialOrd<RtypeBitmap<OO>> for RtypeBitmap<O>
2222where
2223    O: AsRef<[u8]>,
2224    OO: AsRef<[u8]>,
2225{
2226    fn partial_cmp(&self, other: &RtypeBitmap<OO>) -> Option<Ordering> {
2227        self.0.as_ref().partial_cmp(other.0.as_ref())
2228    }
2229}
2230
2231impl<O, OO> CanonicalOrd<RtypeBitmap<OO>> for RtypeBitmap<O>
2232where
2233    O: AsRef<[u8]>,
2234    OO: AsRef<[u8]>,
2235{
2236    fn canonical_cmp(&self, other: &RtypeBitmap<OO>) -> Ordering {
2237        self.0.as_ref().cmp(other.0.as_ref())
2238    }
2239}
2240
2241impl<O: AsRef<[u8]>> Ord for RtypeBitmap<O> {
2242    fn cmp(&self, other: &Self) -> Ordering {
2243        self.0.as_ref().cmp(other.0.as_ref())
2244    }
2245}
2246
2247//--- Hash
2248
2249impl<O: AsRef<[u8]>> hash::Hash for RtypeBitmap<O> {
2250    fn hash<H: hash::Hasher>(&self, state: &mut H) {
2251        self.0.as_ref().hash(state)
2252    }
2253}
2254
2255//--- IntoIterator
2256
2257impl<'a, Octs: AsRef<[u8]>> IntoIterator for &'a RtypeBitmap<Octs> {
2258    type Item = Rtype;
2259    type IntoIter = RtypeBitmapIter<'a>;
2260
2261    fn into_iter(self) -> Self::IntoIter {
2262        self.iter()
2263    }
2264}
2265
2266//--- Display
2267
2268impl<Octs: AsRef<[u8]>> fmt::Display for RtypeBitmap<Octs> {
2269    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2270        let mut iter = self.iter();
2271        if let Some(rtype) = iter.next() {
2272            fmt::Display::fmt(&rtype, f)?;
2273        }
2274        for rtype in iter {
2275            write!(f, " {}", rtype)?
2276        }
2277        Ok(())
2278    }
2279}
2280
2281//--- ZonefileFmt
2282
2283impl<Octs: AsRef<[u8]>> ZonefileFmt for RtypeBitmap<Octs> {
2284    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
2285        for rtype in self {
2286            p.write_token(rtype)?;
2287        }
2288        Ok(())
2289    }
2290}
2291
2292//--- Debug
2293
2294impl<Octs: AsRef<[u8]>> fmt::Debug for RtypeBitmap<Octs> {
2295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2296        f.write_str("RtypeBitmap(")?;
2297        fmt::Display::fmt(self, f)?;
2298        f.write_str(")")
2299    }
2300}
2301
2302//--- Serialize and Deserialize
2303
2304#[cfg(feature = "serde")]
2305impl<Octs> serde::Serialize for RtypeBitmap<Octs>
2306where
2307    Octs: AsRef<[u8]> + SerializeOctets,
2308{
2309    fn serialize<S: serde::Serializer>(
2310        &self,
2311        serializer: S,
2312    ) -> Result<S::Ok, S::Error> {
2313        if serializer.is_human_readable() {
2314            struct Inner<'a>(&'a [u8]);
2315
2316            impl serde::Serialize for Inner<'_> {
2317                fn serialize<S: serde::Serializer>(
2318                    &self,
2319                    serializer: S,
2320                ) -> Result<S::Ok, S::Error> {
2321                    use serde::ser::SerializeSeq;
2322
2323                    let mut serializer = serializer.serialize_seq(None)?;
2324                    for item in RtypeBitmapIter::new(self.0) {
2325                        serializer.serialize_element(&item)?;
2326                    }
2327                    serializer.end()
2328                }
2329            }
2330
2331            serializer.serialize_newtype_struct(
2332                "RtypeBitmap",
2333                &Inner(self.0.as_ref()),
2334            )
2335        } else {
2336            serializer.serialize_newtype_struct(
2337                "RtypeBitmap",
2338                &self.0.as_serialized_octets(),
2339            )
2340        }
2341    }
2342}
2343
2344#[cfg(feature = "serde")]
2345impl<'de, Octs> serde::Deserialize<'de> for RtypeBitmap<Octs>
2346where
2347    Octs: FromBuilder + DeserializeOctets<'de>,
2348    <Octs as FromBuilder>::Builder:
2349        EmptyBuilder + Truncate + AsRef<[u8]> + AsMut<[u8]>,
2350{
2351    fn deserialize<D: serde::Deserializer<'de>>(
2352        deserializer: D,
2353    ) -> Result<Self, D::Error> {
2354        use core::marker::PhantomData;
2355
2356        struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
2357
2358        impl<'de, Octs> serde::de::Visitor<'de> for InnerVisitor<'de, Octs>
2359        where
2360            Octs: FromBuilder + DeserializeOctets<'de>,
2361            <Octs as FromBuilder>::Builder: OctetsBuilder
2362                + EmptyBuilder
2363                + Truncate
2364                + AsRef<[u8]>
2365                + AsMut<[u8]>,
2366        {
2367            type Value = RtypeBitmap<Octs>;
2368
2369            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2370                f.write_str("a record type bitmap")
2371            }
2372
2373            fn visit_seq<A: serde::de::SeqAccess<'de>>(
2374                self,
2375                mut seq: A,
2376            ) -> Result<Self::Value, A::Error> {
2377                use serde::de::Error;
2378
2379                let mut builder = RtypeBitmap::<Octs>::builder();
2380                while let Some(element) = seq.next_element()? {
2381                    builder.add(element).map_err(|_| {
2382                        A::Error::custom(octseq::builder::ShortBuf)
2383                    })?;
2384                }
2385
2386                Ok(builder.finalize())
2387            }
2388
2389            fn visit_borrowed_bytes<E: serde::de::Error>(
2390                self,
2391                value: &'de [u8],
2392            ) -> Result<Self::Value, E> {
2393                self.0.visit_borrowed_bytes(value).and_then(|octets| {
2394                    RtypeBitmap::from_octets(octets).map_err(E::custom)
2395                })
2396            }
2397
2398            #[cfg(feature = "std")]
2399            fn visit_byte_buf<E: serde::de::Error>(
2400                self,
2401                value: std::vec::Vec<u8>,
2402            ) -> Result<Self::Value, E> {
2403                self.0.visit_byte_buf(value).and_then(|octets| {
2404                    RtypeBitmap::from_octets(octets).map_err(E::custom)
2405                })
2406            }
2407        }
2408
2409        struct NewtypeVisitor<T>(PhantomData<T>);
2410
2411        impl<'de, Octs> serde::de::Visitor<'de> for NewtypeVisitor<Octs>
2412        where
2413            Octs: FromBuilder + DeserializeOctets<'de>,
2414            <Octs as FromBuilder>::Builder: OctetsBuilder
2415                + EmptyBuilder
2416                + Truncate
2417                + AsRef<[u8]>
2418                + AsMut<[u8]>,
2419        {
2420            type Value = RtypeBitmap<Octs>;
2421
2422            fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2423                f.write_str("a record type bitmap")
2424            }
2425
2426            fn visit_newtype_struct<D: serde::Deserializer<'de>>(
2427                self,
2428                deserializer: D,
2429            ) -> Result<Self::Value, D::Error> {
2430                if deserializer.is_human_readable() {
2431                    deserializer
2432                        .deserialize_seq(InnerVisitor(Octs::visitor()))
2433                } else {
2434                    Octs::deserialize_with_visitor(
2435                        deserializer,
2436                        InnerVisitor(Octs::visitor()),
2437                    )
2438                }
2439            }
2440        }
2441
2442        deserializer.deserialize_newtype_struct(
2443            "RtypeBitmap",
2444            NewtypeVisitor(PhantomData),
2445        )
2446    }
2447}
2448
2449//------------ RtypeBitmapBuilder --------------------------------------------
2450
2451/// A builder for a record type bitmap.
2452//
2453//  Here is how this is going to work: We keep one long Builder into which
2454//  we place all added types. The buffer contains a sequence of blocks
2455//  encoded similarly to the final format but with all 32 octets of the
2456//  bitmap present. Blocks are in order and are only added when needed (which
2457//  means we may have to insert a block in the middle). When finalizing, we
2458//  compress the block buffer by dropping the unncessary octets of each
2459//  block.
2460#[derive(Clone, Debug)]
2461pub struct RtypeBitmapBuilder<Builder> {
2462    buf: Builder,
2463}
2464
2465impl<Builder: OctetsBuilder> RtypeBitmapBuilder<Builder> {
2466    #[must_use]
2467    pub fn new() -> Self
2468    where
2469        Builder: EmptyBuilder,
2470    {
2471        RtypeBitmapBuilder {
2472            // Start out with the capacity for one block.
2473            buf: Builder::with_capacity(34),
2474        }
2475    }
2476
2477    pub fn with_builder(builder: Builder) -> Self {
2478        RtypeBitmapBuilder { buf: builder }
2479    }
2480}
2481
2482#[cfg(feature = "std")]
2483impl RtypeBitmapBuilder<Vec<u8>> {
2484    #[must_use]
2485    pub fn new_vec() -> Self {
2486        Self::new()
2487    }
2488}
2489
2490impl<Builder> RtypeBitmapBuilder<Builder>
2491where
2492    Builder: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>,
2493{
2494    pub fn add(&mut self, rtype: Rtype) -> Result<(), Builder::AppendError> {
2495        let (block, octet, bit) = split_rtype(rtype);
2496        let block = self.get_block(block)?;
2497        if (block[1] as usize) < (octet + 1) {
2498            block[1] = (octet + 1) as u8
2499        }
2500        block[octet + 2] |= bit;
2501        Ok(())
2502    }
2503
2504    fn get_block(
2505        &mut self,
2506        block: u8,
2507    ) -> Result<&mut [u8], Builder::AppendError> {
2508        let mut pos = 0;
2509        while pos < self.buf.as_ref().len() {
2510            match self.buf.as_ref()[pos].cmp(&block) {
2511                Ordering::Equal => {
2512                    return Ok(&mut self.buf.as_mut()[pos..pos + 34])
2513                }
2514                Ordering::Greater => {
2515                    // We need the length from before we add the new block
2516                    let len = self.buf.as_ref().len();
2517
2518                    // Allocate space for the new block
2519                    self.buf.append_slice(&[0; 34])?;
2520
2521                    // Move everything after this block back by 34 bytes
2522                    let buf = self.buf.as_mut();
2523                    buf.copy_within(pos..len, pos + 34);
2524                    buf[pos..pos + 34].fill(0);
2525                    buf[pos] = block;
2526
2527                    return Ok(&mut buf[pos..pos + 34]);
2528                }
2529                Ordering::Less => pos += 34,
2530            }
2531        }
2532
2533        self.buf.append_slice(&[0; 34])?;
2534        self.buf.as_mut()[pos] = block;
2535        Ok(&mut self.buf.as_mut()[pos..pos + 34])
2536    }
2537
2538    pub fn finalize(mut self) -> RtypeBitmap<Builder::Octets>
2539    where
2540        Builder: FreezeBuilder + Truncate,
2541    {
2542        let mut dst_pos = 0;
2543        let buf_len = self.buf.as_ref().len();
2544        for src_pos in (0..buf_len).step_by(34) {
2545            let chunk_len = (self.buf.as_ref()[src_pos + 1] as usize) + 2;
2546            let buf = self.buf.as_mut();
2547            buf.copy_within(src_pos..src_pos + chunk_len, dst_pos);
2548            dst_pos += chunk_len;
2549        }
2550        self.buf.truncate(dst_pos);
2551        RtypeBitmap(self.buf.freeze())
2552    }
2553}
2554
2555//--- Default
2556
2557impl<Builder> Default for RtypeBitmapBuilder<Builder>
2558where
2559    Builder: OctetsBuilder + EmptyBuilder,
2560{
2561    fn default() -> Self {
2562        Self::new()
2563    }
2564}
2565
2566//------------ RtypeBitmapIter -----------------------------------------------
2567
2568pub struct RtypeBitmapIter<'a> {
2569    /// The data to iterate over.
2570    ///
2571    /// This starts with the octets of the current block without the block
2572    /// number and length.
2573    data: &'a [u8],
2574
2575    /// The base value of the current block, i.e., its upper 8 bits.
2576    block: u16,
2577
2578    /// The length of the current block’s data.
2579    len: usize,
2580
2581    /// Index of the current octet in the current block.
2582    octet: usize,
2583
2584    /// Index of the next set bit in the current octet in the current block.
2585    bit: u16,
2586}
2587
2588impl<'a> RtypeBitmapIter<'a> {
2589    fn new(data: &'a [u8]) -> Self {
2590        if data.is_empty() {
2591            RtypeBitmapIter {
2592                data,
2593                block: 0,
2594                len: 0,
2595                octet: 0,
2596                bit: 0,
2597            }
2598        } else {
2599            let mut res = RtypeBitmapIter {
2600                data: &data[2..],
2601                block: u16::from(data[0]) << 8,
2602                len: usize::from(data[1]),
2603                octet: 0,
2604                bit: 0,
2605            };
2606            if res.data[0] & 0x80 == 0 {
2607                res.advance()
2608            }
2609            res
2610        }
2611    }
2612
2613    fn advance(&mut self) {
2614        loop {
2615            self.bit += 1;
2616            if self.bit == 8 {
2617                self.bit = 0;
2618                self.octet += 1;
2619                if self.octet == self.len {
2620                    self.data = &self.data[self.len..];
2621                    if self.data.is_empty() {
2622                        return;
2623                    }
2624                    self.block = u16::from(self.data[0]) << 8;
2625                    self.len = usize::from(self.data[1]);
2626                    self.data = &self.data[2..];
2627                    self.octet = 0;
2628                }
2629            }
2630            if self.data[self.octet] & (0x80 >> self.bit) != 0 {
2631                return;
2632            }
2633        }
2634    }
2635}
2636
2637impl Iterator for RtypeBitmapIter<'_> {
2638    type Item = Rtype;
2639
2640    fn next(&mut self) -> Option<Self::Item> {
2641        if self.data.is_empty() {
2642            return None;
2643        }
2644        let res = Rtype::from_int(
2645            self.block | ((self.octet as u16) << 3) | self.bit,
2646        );
2647        self.advance();
2648        Some(res)
2649    }
2650}
2651
2652//============ Error Types ===================================================
2653
2654//------------ RtypeBitmapError ----------------------------------------------
2655
2656#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2657pub struct RtypeBitmapError(RtypeBitmapErrorEnum);
2658
2659#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2660enum RtypeBitmapErrorEnum {
2661    ShortInput,
2662    BadRtypeBitmap,
2663}
2664
2665//--- From
2666
2667impl From<RtypeBitmapError> for ParseError {
2668    fn from(err: RtypeBitmapError) -> ParseError {
2669        match err.0 {
2670            RtypeBitmapErrorEnum::ShortInput => ParseError::ShortInput,
2671            RtypeBitmapErrorEnum::BadRtypeBitmap => {
2672                FormError::new("invalid NSEC bitmap").into()
2673            }
2674        }
2675    }
2676}
2677
2678impl From<RtypeBitmapErrorEnum> for RtypeBitmapError {
2679    fn from(err: RtypeBitmapErrorEnum) -> Self {
2680        Self(err)
2681    }
2682}
2683
2684//--- Display and Error
2685
2686impl fmt::Display for RtypeBitmapError {
2687    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2688        match self.0 {
2689            RtypeBitmapErrorEnum::ShortInput => ParseError::ShortInput.fmt(f),
2690            RtypeBitmapErrorEnum::BadRtypeBitmap => {
2691                f.write_str("invalid record type bitmap")
2692            }
2693        }
2694    }
2695}
2696
2697#[cfg(feature = "std")]
2698impl std::error::Error for RtypeBitmapError {}
2699
2700//============ Friendly Helper Functions =====================================
2701
2702/// Splits an Rtype value into window number, octet number, and octet mask.
2703fn split_rtype(rtype: Rtype) -> (u8, usize, u8) {
2704    let rtype = rtype.to_int();
2705    (
2706        (rtype >> 8) as u8,
2707        ((rtype & 0xFF) >> 3) as usize,
2708        0b1000_0000 >> (rtype & 0x07),
2709    )
2710}
2711
2712/// Splits the next bitmap window from the bitmap and returns None when there's no next window.
2713#[allow(clippy::type_complexity)]
2714fn read_window(data: &[u8]) -> Option<((u8, &[u8]), &[u8])> {
2715    data.split_first().and_then(|(n, data)| {
2716        data.split_first().and_then(|(l, data)| {
2717            if data.len() >= usize::from(*l) {
2718                let (window, data) = data.split_at(usize::from(*l));
2719                Some(((*n, window), data))
2720            } else {
2721                None
2722            }
2723        })
2724    })
2725}
2726
2727//============ Errors ========================================================
2728
2729#[derive(Clone, Copy, Debug)]
2730pub struct IllegalSignatureTime(());
2731
2732impl fmt::Display for IllegalSignatureTime {
2733    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2734        f.write_str("illegal signature time")
2735    }
2736}
2737
2738#[cfg(feature = "std")]
2739impl std::error::Error for IllegalSignatureTime {}
2740
2741//============ Test ==========================================================
2742
2743#[cfg(test)]
2744#[cfg(all(feature = "std", feature = "bytes"))]
2745mod test {
2746    use super::*;
2747    use crate::base::iana::Rtype;
2748    use crate::base::name::Name;
2749    use crate::base::rdata::test::{
2750        test_compose_parse, test_rdlen, test_scan,
2751    };
2752    use core::str::FromStr;
2753    use std::vec::Vec;
2754
2755    //--- Dnskey
2756
2757    #[test]
2758    #[allow(clippy::redundant_closure)] // lifetimes ...
2759    fn dnskey_compose_parse_scan() {
2760        let rdata =
2761            Dnskey::new(10, 11, SecurityAlgorithm::RSASHA1, b"key0").unwrap();
2762        test_rdlen(&rdata);
2763        test_compose_parse(&rdata, |parser| Dnskey::parse(parser));
2764        test_scan(&["10", "11", "5", "a2V5MA=="], Dnskey::scan, &rdata);
2765    }
2766
2767    //--- Rrsig
2768
2769    #[test]
2770    #[allow(clippy::redundant_closure)] // lifetimes ...
2771    fn rrsig_compose_parse_scan() {
2772        let rdata = Rrsig::new(
2773            Rtype::A,
2774            SecurityAlgorithm::RSASHA1,
2775            3,
2776            Ttl::from_secs(12),
2777            Timestamp::from(13),
2778            Timestamp::from(14),
2779            15,
2780            Name::<Vec<u8>>::from_str("example.com.").unwrap(),
2781            b"key",
2782        )
2783        .unwrap();
2784        test_rdlen(&rdata);
2785        test_compose_parse(&rdata, |parser| Rrsig::parse(parser));
2786        test_scan(
2787            &[
2788                "A",
2789                "5",
2790                "3",
2791                "12",
2792                "13",
2793                "14",
2794                "15",
2795                "example.com.",
2796                "a2V5",
2797            ],
2798            Rrsig::scan,
2799            &rdata,
2800        );
2801    }
2802
2803    //--- Nsec
2804
2805    #[test]
2806    #[allow(clippy::redundant_closure)] // lifetimes ...
2807    fn nsec_compose_parse_scan() {
2808        let mut rtype = RtypeBitmapBuilder::new_vec();
2809        rtype.add(Rtype::A).unwrap();
2810        rtype.add(Rtype::SRV).unwrap();
2811        let rdata = Nsec::new(
2812            Name::<Vec<u8>>::from_str("example.com.").unwrap(),
2813            rtype.finalize(),
2814        );
2815        test_rdlen(&rdata);
2816        test_compose_parse(&rdata, |parser| Nsec::parse(parser));
2817        test_scan(&["example.com.", "A", "SRV"], Nsec::scan, &rdata);
2818
2819        // scan empty rtype bitmap
2820        let rdata = Nsec::new(
2821            Name::<Vec<u8>>::from_str("example.com.").unwrap(),
2822            RtypeBitmapBuilder::new_vec().finalize(),
2823        );
2824        test_scan(&["example.com."], Nsec::scan, &rdata);
2825    }
2826
2827    //--- Ds
2828
2829    #[test]
2830    #[allow(clippy::redundant_closure)] // lifetimes ...
2831    fn ds_compose_parse_scan() {
2832        let rdata = Ds::new(
2833            10,
2834            SecurityAlgorithm::RSASHA1,
2835            DigestAlgorithm::SHA256,
2836            b"key",
2837        )
2838        .unwrap();
2839        test_rdlen(&rdata);
2840        test_compose_parse(&rdata, |parser| Ds::parse(parser));
2841        test_scan(&["10", "5", "2", "6b6579"], Ds::scan, &rdata);
2842    }
2843
2844    //--- RtypeBitmape
2845
2846    #[test]
2847    fn rtype_split() {
2848        assert_eq!(split_rtype(Rtype::A), (0, 0, 0b01000000));
2849        assert_eq!(split_rtype(Rtype::NS), (0, 0, 0b00100000));
2850        assert_eq!(split_rtype(Rtype::CAA), (1, 0, 0b01000000));
2851    }
2852
2853    #[test]
2854    fn rtype_bitmap_read_window() {
2855        let mut builder = RtypeBitmapBuilder::new_vec();
2856        builder.add(Rtype::A).unwrap();
2857        builder.add(Rtype::CAA).unwrap();
2858        let bitmap = builder.finalize();
2859
2860        let ((n, window), data) = read_window(bitmap.as_slice()).unwrap();
2861        assert_eq!((n, window), (0u8, b"\x40".as_ref()));
2862        let ((n, window), data) = read_window(data).unwrap();
2863        assert_eq!((n, window), (1u8, b"\x40".as_ref()));
2864        assert!(data.is_empty());
2865        assert!(read_window(data).is_none());
2866    }
2867
2868    #[test]
2869    fn rtype_bitmap_builder() {
2870        let mut builder = RtypeBitmapBuilder::new_vec();
2871        builder.add(Rtype::from_int(1234)).unwrap(); // 0x04D2
2872        builder.add(Rtype::A).unwrap(); // 0x0001
2873        builder.add(Rtype::MX).unwrap(); // 0x000F
2874        builder.add(Rtype::RRSIG).unwrap(); // 0x002E
2875        builder.add(Rtype::NSEC).unwrap(); // 0x002F
2876        let bitmap = builder.finalize();
2877        assert_eq!(
2878            bitmap.as_slice(),
2879            &b"\x00\x06\x40\x01\x00\x00\x00\x03\
2880                     \x04\x1b\x00\x00\x00\x00\x00\x00\
2881                     \x00\x00\x00\x00\x00\x00\x00\x00\
2882                     \x00\x00\x00\x00\x00\x00\x00\x00\
2883                     \x00\x00\x00\x00\x20"[..]
2884        );
2885
2886        assert!(bitmap.contains(Rtype::A));
2887        assert!(bitmap.contains(Rtype::MX));
2888        assert!(bitmap.contains(Rtype::RRSIG));
2889        assert!(bitmap.contains(Rtype::NSEC));
2890        assert!(bitmap.contains(Rtype::from(1234)));
2891        assert!(!bitmap.contains(Rtype::from(1235)));
2892        assert!(!bitmap.contains(Rtype::NS));
2893    }
2894
2895    #[test]
2896    fn rtype_bitmap_iter() {
2897        use std::vec::Vec;
2898
2899        let mut builder = RtypeBitmapBuilder::new_vec();
2900        let types = vec![
2901            Rtype::NS,
2902            Rtype::SOA,
2903            Rtype::MX,
2904            Rtype::TXT,
2905            Rtype::RRSIG,
2906            Rtype::DNSKEY,
2907            Rtype::NSEC3PARAM,
2908            Rtype::SPF,
2909            Rtype::CAA,
2910        ];
2911        for t in types.iter() {
2912            builder.add(*t).unwrap();
2913        }
2914
2915        let bitmap = builder.finalize();
2916        let bitmap_types: Vec<_> = bitmap.iter().collect();
2917        assert_eq!(types, bitmap_types);
2918    }
2919
2920    #[test]
2921    fn dnskey_key_tag() {
2922        assert_eq!(
2923            Dnskey::new(
2924                256,
2925                3,
2926                SecurityAlgorithm::RSASHA256,
2927                base64::decode::<Vec<u8>>(
2928                    "AwEAAcTQyaIe6nt3xSPOG2L/YfwBkOVTJN6mlnZ249O5Rtt3ZSRQHxQS\
2929                     W61AODYw6bvgxrrGq8eeOuenFjcSYgNAMcBYoEYYmKDW6e9EryW4ZaT/\
2930                     MCq+8Am06oR40xAA3fClOM6QjRcT85tP41Go946AicBGP8XOP/Aj1aI/\
2931                     oPRGzRnboUPUok/AzTNnW5npBU69+BuiIwYE7mQOiNBFePyvjQBdoiuY\
2932                     bmuD3Py0IyjlBxzZUXbqLsRL9gYFkCqeTY29Ik7usuzMTa+JRSLz6KGS\
2933                     5RSJ7CTSMjZg8aNaUbN2dvGhakJPh92HnLvMA3TefFgbKJphFNPA3BWS\
2934                     KLZ02cRWXqM="
2935                )
2936                .unwrap()
2937            ).unwrap()
2938            .key_tag(),
2939            59944
2940        );
2941        assert_eq!(
2942            Dnskey::new(
2943                257,
2944                3,
2945                SecurityAlgorithm::RSASHA256,
2946                base64::decode::<Vec<u8>>(
2947                    "AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTO\
2948                    iW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN\
2949                    7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5\
2950                    LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8\
2951                    efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7\
2952                    pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLY\
2953                    A4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws\
2954                    9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU="
2955                )
2956                .unwrap()
2957            )
2958            .unwrap()
2959            .key_tag(),
2960            20326
2961        );
2962        assert_eq!(
2963            Dnskey::new(
2964                257,
2965                3,
2966                SecurityAlgorithm::RSAMD5,
2967                base64::decode::<Vec<u8>>(
2968                    "AwEAAcVaA4jSBIGRrSzpecoJELvKE9+OMuFnL8mmUBsY\
2969                    lB6epN1CqX7NzwjDpi6VySiEXr0C4uTYkU/L1uMv2mHE\
2970                    AljThFDJ1GuozJ6gA7jf3lnaGppRg2IoVQ9IVmLORmjw\
2971                    C+7Eoi12SqybMTicD3Ezwa9XbG1iPjmjhbMrLh7MSQpX"
2972                )
2973                .unwrap()
2974            )
2975            .unwrap()
2976            .key_tag(),
2977            18698
2978        );
2979    }
2980
2981    #[test]
2982    fn dnskey_flags() {
2983        let dnskey = Dnskey::new(
2984            257,
2985            3,
2986            SecurityAlgorithm::RSASHA256,
2987            bytes::Bytes::new(),
2988        )
2989        .unwrap();
2990        assert!(dnskey.is_zone_key());
2991        assert!(dnskey.is_secure_entry_point());
2992        assert!(!dnskey.is_revoked());
2993    }
2994}