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
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 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 pub fn is_revoked(&self) -> bool {
148 self.flags() & 0b0000_0000_1000_0000 != 0
149 }
150
151 pub fn is_secure_entry_point(&self) -> bool {
162 self.flags() & 0b0000_0000_0000_0001 != 0
163 }
164
165 pub fn is_zone_key(&self) -> bool {
172 self.flags() & 0b0000_0001_0000_0000 != 0
173 }
174
175 pub fn key_tag(&self) -> u16
177 where
178 Octs: AsRef<[u8]>,
179 {
180 if self.algorithm == SecurityAlgorithm::RSAMD5 {
181 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 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 #[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
273impl<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
293impl<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
310impl<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
350impl<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
361impl<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
417impl<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
426impl<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
439impl<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#[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)] 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
556impl<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#[derive(Clone, Copy, Debug, PartialEq)]
633#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
634pub struct Timestamp(Serial);
635
636impl Timestamp {
637 #[cfg(feature = "std")]
639 #[must_use]
640 pub fn now() -> Self {
641 Self(Serial::now())
642 }
643
644 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 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 #[must_use]
704 pub fn into_int(self) -> u32 {
705 self.0.into_int()
706 }
707}
708
709impl 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
728impl 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 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
782impl fmt::Display for Timestamp {
785 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
786 write!(f, "{}", self.0)
787 }
788}
789
790impl ZonefileFmt for Timestamp {
793 fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
794 p.write_token(self.0)
795 }
796}
797
798impl 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
812fn 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#[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 pub(crate) const RTYPE: Rtype = Rtype::RRSIG;
868}
869
870impl<Octs, Name> Rrsig<Octs, Name> {
871 #[allow(clippy::too_many_arguments)] 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 #[allow(clippy::too_many_arguments)] 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
1083impl<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
1126impl<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
1155impl<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
1253impl<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
1269impl<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
1349impl<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
1373impl<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
1395impl<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#[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 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
1514impl<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
1547impl<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
1563impl<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 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
1612impl<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
1621impl<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 self.compose_rdata(target)
1673 }
1674}
1675
1676impl<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
1688impl<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
1703impl<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#[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 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 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
1867impl<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
1887impl<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
1904impl<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
1956impl<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
1967impl<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
2022impl<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
2038impl<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
2051impl<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#[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 if data.len() < 2 {
2080 return Err(RtypeBitmapErrorEnum::ShortInput.into());
2081 }
2082
2083 let len = (data[1] as usize) + 2;
2084 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
2182impl<T, Octs: AsRef<T>> AsRef<T> for RtypeBitmap<Octs> {
2185 fn as_ref(&self) -> &T {
2186 self.0.as_ref()
2187 }
2188}
2189
2190impl<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
2205impl<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
2219impl<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
2247impl<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
2255impl<'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
2266impl<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
2281impl<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
2292impl<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#[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#[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 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 let len = self.buf.as_ref().len();
2517
2518 self.buf.append_slice(&[0; 34])?;
2520
2521 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
2555impl<Builder> Default for RtypeBitmapBuilder<Builder>
2558where
2559 Builder: OctetsBuilder + EmptyBuilder,
2560{
2561 fn default() -> Self {
2562 Self::new()
2563 }
2564}
2565
2566pub struct RtypeBitmapIter<'a> {
2569 data: &'a [u8],
2574
2575 block: u16,
2577
2578 len: usize,
2580
2581 octet: usize,
2583
2584 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#[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
2665impl 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
2684impl 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
2700fn 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#[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#[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#[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 #[test]
2758 #[allow(clippy::redundant_closure)] 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 #[test]
2770 #[allow(clippy::redundant_closure)] 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 #[test]
2806 #[allow(clippy::redundant_closure)] 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 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 #[test]
2830 #[allow(clippy::redundant_closure)] 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 #[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(); builder.add(Rtype::A).unwrap(); builder.add(Rtype::MX).unwrap(); builder.add(Rtype::RRSIG).unwrap(); builder.add(Rtype::NSEC).unwrap(); 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}