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