1use crate::base::cmp::CanonicalOrd;
8use crate::base::iana::{DigestAlg, Rtype, SecAlg};
9use crate::base::name::{FlattenInto, ParsedDname, ToDname};
10use crate::base::rdata::{
11 ComposeRecordData, LongRecordData, ParseRecordData, RecordData,
12};
13use crate::base::Ttl;
14use crate::base::scan::{Scan, Scanner, ScannerError};
15use crate::base::serial::Serial;
16use crate::base::wire::{Compose, Composer, FormError, Parse, ParseError};
17use crate::utils::{base16, base64};
18use core::cmp::Ordering;
19use core::convert::TryInto;
20use core::{fmt, hash, ptr};
21use octseq::builder::{
22 EmptyBuilder, FreezeBuilder, FromBuilder, OctetsBuilder, Truncate,
23};
24use octseq::octets::{Octets, OctetsFrom, OctetsInto};
25use octseq::parse::Parser;
26#[cfg(feature = "serde")]
27use octseq::serde::{DeserializeOctets, SerializeOctets};
28#[cfg(feature = "std")]
29use std::vec::Vec;
30
31#[derive(Clone)]
34#[cfg_attr(
35 feature = "serde",
36 derive(serde::Serialize, serde::Deserialize),
37 serde(bound(
38 serialize = "
39 Octs: octseq::serde::SerializeOctets + AsRef<[u8]>
40 ",
41 deserialize = "
42 Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
43 <Octs as FromBuilder>::Builder:
44 OctetsBuilder + EmptyBuilder,
45 ",
46 ))
47)]
48pub struct Dnskey<Octs> {
49 flags: u16,
50 protocol: u8,
51 algorithm: SecAlg,
52 #[cfg_attr(
53 feature = "serde",
54 serde(with = "crate::utils::base64::serde")
55 )]
56 public_key: Octs,
57}
58
59impl<Octs> Dnskey<Octs> {
60 pub fn new(
61 flags: u16,
62 protocol: u8,
63 algorithm: SecAlg,
64 public_key: Octs,
65 ) -> Result<Self, LongRecordData>
66 where
67 Octs: AsRef<[u8]>,
68 {
69 LongRecordData::check_len(
70 usize::from(
71 u16::COMPOSE_LEN + u8::COMPOSE_LEN + SecAlg::COMPOSE_LEN,
72 )
73 .checked_add(public_key.as_ref().len())
74 .expect("long key"),
75 )?;
76 Ok(Dnskey {
77 flags,
78 protocol,
79 algorithm,
80 public_key,
81 })
82 }
83
84 pub unsafe fn new_unchecked(
91 flags: u16,
92 protocol: u8,
93 algorithm: SecAlg,
94 public_key: Octs,
95 ) -> Self {
96 Dnskey {
97 flags,
98 protocol,
99 algorithm,
100 public_key,
101 }
102 }
103
104 pub fn flags(&self) -> u16 {
105 self.flags
106 }
107
108 pub fn protocol(&self) -> u8 {
109 self.protocol
110 }
111
112 pub fn algorithm(&self) -> SecAlg {
113 self.algorithm
114 }
115
116 pub fn public_key(&self) -> &Octs {
117 &self.public_key
118 }
119
120 pub fn into_public_key(self) -> Octs {
121 self.public_key
122 }
123
124 pub fn convert<Other: From<Octs>>(self) -> Dnskey<Other> {
125 Dnskey {
126 flags: self.flags,
127 protocol: self.protocol,
128 algorithm: self.algorithm,
129 public_key: self.public_key.into(),
130 }
131 }
132
133 pub fn is_revoked(&self) -> bool {
139 self.flags() & 0b0000_0000_1000_0000 != 0
140 }
141
142 pub fn is_secure_entry_point(&self) -> bool {
153 self.flags() & 0b0000_0000_0000_0001 != 0
154 }
155
156 pub fn is_zsk(&self) -> bool {
163 self.flags() & 0b0000_0001_0000_0000 != 0
164 }
165
166 #[allow(clippy::while_let_loop)] pub fn key_tag(&self) -> u16
169 where
170 Octs: AsRef<[u8]>,
171 {
172 if self.algorithm == SecAlg::RsaMd5 {
173 let len = self.public_key.as_ref().len();
177 if len > 2 {
178 u16::from_be_bytes(
179 self.public_key.as_ref()[len - 3..len - 1]
180 .try_into()
181 .unwrap(),
182 )
183 } else {
184 0
185 }
186 } else {
187 let mut res = u32::from(self.flags);
191 res += u32::from(self.protocol) << 8;
192 res += u32::from(self.algorithm.to_int());
193 let mut iter = self.public_key().as_ref().iter();
194 loop {
195 match iter.next() {
196 Some(&x) => res += u32::from(x) << 8,
197 None => break,
198 }
199 match iter.next() {
200 Some(&x) => res += u32::from(x),
201 None => break,
202 }
203 }
204 res += (res >> 16) & 0xFFFF;
205 (res & 0xFFFF) as u16
206 }
207 }
208
209 pub(super) fn convert_octets<Target: OctetsFrom<Octs>>(
210 self,
211 ) -> Result<Dnskey<Target>, Target::Error> {
212 Ok(unsafe {
213 Dnskey::new_unchecked(
214 self.flags,
215 self.protocol,
216 self.algorithm,
217 self.public_key.try_octets_into()?,
218 )
219 })
220 }
221
222 pub(super) fn flatten<Target: OctetsFrom<Octs>>(
223 self,
224 ) -> Result<Dnskey<Target>, Target::Error> {
225 self.convert_octets()
226 }
227
228 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
229 parser: &mut Parser<'a, Src>,
230 ) -> Result<Self, ParseError> {
231 let len = match parser.remaining().checked_sub(4) {
232 Some(len) => len,
233 None => return Err(ParseError::ShortInput),
234 };
235 Ok(unsafe {
236 Self::new_unchecked(
237 u16::parse(parser)?,
238 u8::parse(parser)?,
239 SecAlg::parse(parser)?,
240 parser.parse_octets(len)?,
241 )
242 })
243 }
244
245 pub fn scan<S: Scanner<Octets = Octs>>(
246 scanner: &mut S,
247 ) -> Result<Self, S::Error>
248 where
249 Octs: AsRef<[u8]>,
250 {
251 Self::new(
252 u16::scan(scanner)?,
253 u8::scan(scanner)?,
254 SecAlg::scan(scanner)?,
255 scanner.convert_entry(base64::SymbolConverter::new())?,
256 )
257 .map_err(|err| S::Error::custom(err.as_str()))
258 }
259}
260
261impl<Octs, SrcOcts> OctetsFrom<Dnskey<SrcOcts>> for Dnskey<Octs>
264where
265 Octs: OctetsFrom<SrcOcts>,
266{
267 type Error = Octs::Error;
268
269 fn try_octets_from(source: Dnskey<SrcOcts>) -> Result<Self, Self::Error> {
270 Ok(unsafe {
271 Dnskey::new_unchecked(
272 source.flags,
273 source.protocol,
274 source.algorithm,
275 Octs::try_octets_from(source.public_key)?,
276 )
277 })
278 }
279}
280
281impl<Octs, Other> PartialEq<Dnskey<Other>> for Dnskey<Octs>
284where
285 Octs: AsRef<[u8]>,
286 Other: AsRef<[u8]>,
287{
288 fn eq(&self, other: &Dnskey<Other>) -> bool {
289 self.flags == other.flags
290 && self.protocol == other.protocol
291 && self.algorithm == other.algorithm
292 && self.public_key.as_ref() == other.public_key.as_ref()
293 }
294}
295
296impl<Octs: AsRef<[u8]>> Eq for Dnskey<Octs> {}
297
298impl<Octs, Other> PartialOrd<Dnskey<Other>> for Dnskey<Octs>
301where
302 Octs: AsRef<[u8]>,
303 Other: AsRef<[u8]>,
304{
305 fn partial_cmp(&self, other: &Dnskey<Other>) -> Option<Ordering> {
306 Some(self.canonical_cmp(other))
307 }
308}
309
310impl<Octs, Other> CanonicalOrd<Dnskey<Other>> for Dnskey<Octs>
311where
312 Octs: AsRef<[u8]>,
313 Other: AsRef<[u8]>,
314{
315 fn canonical_cmp(&self, other: &Dnskey<Other>) -> Ordering {
316 match self.flags.cmp(&other.flags) {
317 Ordering::Equal => {}
318 other => return other,
319 }
320 match self.protocol.cmp(&other.protocol) {
321 Ordering::Equal => {}
322 other => return other,
323 }
324 match self.algorithm.cmp(&other.algorithm) {
325 Ordering::Equal => {}
326 other => return other,
327 }
328 self.public_key.as_ref().cmp(other.public_key.as_ref())
329 }
330}
331
332impl<Octs: AsRef<[u8]>> Ord for Dnskey<Octs> {
333 fn cmp(&self, other: &Self) -> Ordering {
334 self.canonical_cmp(other)
335 }
336}
337
338impl<Octs: AsRef<[u8]>> hash::Hash for Dnskey<Octs> {
341 fn hash<H: hash::Hasher>(&self, state: &mut H) {
342 self.flags.hash(state);
343 self.protocol.hash(state);
344 self.algorithm.hash(state);
345 self.public_key.as_ref().hash(state);
346 }
347}
348
349impl<Octs> RecordData for Dnskey<Octs> {
352 fn rtype(&self) -> Rtype {
353 Rtype::Dnskey
354 }
355}
356
357impl<'a, Octs> ParseRecordData<'a, Octs> for Dnskey<Octs::Range<'a>>
358where
359 Octs: Octets + ?Sized,
360{
361 fn parse_rdata(
362 rtype: Rtype,
363 parser: &mut Parser<'a, Octs>,
364 ) -> Result<Option<Self>, ParseError> {
365 if rtype == Rtype::Dnskey {
366 Self::parse(parser).map(Some)
367 } else {
368 Ok(None)
369 }
370 }
371}
372
373impl<Octs: AsRef<[u8]>> ComposeRecordData for Dnskey<Octs> {
374 fn rdlen(&self, _compress: bool) -> Option<u16> {
375 Some(
376 u16::try_from(self.public_key.as_ref().len())
377 .expect("long key")
378 .checked_add(
379 u16::COMPOSE_LEN + u8::COMPOSE_LEN + SecAlg::COMPOSE_LEN,
380 )
381 .expect("long key"),
382 )
383 }
384
385 fn compose_rdata<Target: Composer + ?Sized>(
386 &self,
387 target: &mut Target,
388 ) -> Result<(), Target::AppendError> {
389 self.flags.compose(target)?;
390 self.protocol.compose(target)?;
391 self.algorithm.compose(target)?;
392 target.append_slice(self.public_key.as_ref())
393 }
394
395 fn compose_canonical_rdata<Target: Composer + ?Sized>(
396 &self,
397 target: &mut Target,
398 ) -> Result<(), Target::AppendError> {
399 self.compose_rdata(target)
400 }
401}
402
403impl<Octs: AsRef<[u8]>> fmt::Display for Dnskey<Octs> {
406 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
407 write!(f, "{} {} {} ", self.flags, self.protocol, self.algorithm)?;
408 base64::display(&self.public_key, f)
409 }
410}
411
412impl<Octs: AsRef<[u8]>> fmt::Debug for Dnskey<Octs> {
415 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
416 f.debug_struct("Dnskey")
417 .field("flags", &self.flags)
418 .field("protocol", &self.protocol)
419 .field("algorithm", &self.algorithm)
420 .field("public_key", &self.public_key.as_ref())
421 .finish()
422 }
423}
424
425#[derive(Clone)]
429pub struct ProtoRrsig<Name> {
430 type_covered: Rtype,
431 algorithm: SecAlg,
432 labels: u8,
433 original_ttl: Ttl,
434 expiration: Serial,
435 inception: Serial,
436 key_tag: u16,
437 signer_name: Name,
438}
439
440impl<Name> ProtoRrsig<Name> {
441 #[allow(clippy::too_many_arguments)] pub fn new(
443 type_covered: Rtype,
444 algorithm: SecAlg,
445 labels: u8,
446 original_ttl: Ttl,
447 expiration: Serial,
448 inception: Serial,
449 key_tag: u16,
450 signer_name: Name,
451 ) -> Self {
452 ProtoRrsig {
453 type_covered,
454 algorithm,
455 labels,
456 original_ttl,
457 expiration,
458 inception,
459 key_tag,
460 signer_name,
461 }
462 }
463
464 pub fn into_rrsig<Octs: AsRef<[u8]>>(
465 self,
466 signature: Octs,
467 ) -> Result<Rrsig<Octs, Name>, LongRecordData>
468 where
469 Name: ToDname,
470 {
471 Rrsig::new(
472 self.type_covered,
473 self.algorithm,
474 self.labels,
475 self.original_ttl,
476 self.expiration,
477 self.inception,
478 self.key_tag,
479 self.signer_name,
480 signature,
481 )
482 }
483}
484
485impl<Name: ToDname> ProtoRrsig<Name> {
486 pub fn compose<Target: Composer + ?Sized>(
487 &self,
488 target: &mut Target,
489 ) -> Result<(), Target::AppendError> {
490 self.compose_head(target)?;
491 self.signer_name.compose(target)
492 }
493
494 pub fn compose_canonical<Target: Composer + ?Sized>(
495 &self,
496 target: &mut Target,
497 ) -> Result<(), Target::AppendError> {
498 self.compose_head(target)?;
499 self.signer_name.compose_canonical(target)
500 }
501
502 fn compose_len(&self) -> u16 {
503 Rtype::COMPOSE_LEN
504 + SecAlg::COMPOSE_LEN
505 + u8::COMPOSE_LEN
506 + u32::COMPOSE_LEN
507 + Serial::COMPOSE_LEN
508 + Serial::COMPOSE_LEN
509 + u16::COMPOSE_LEN
510 + self.signer_name.compose_len()
511 }
512
513 fn compose_head<Target: Composer + ?Sized>(
514 &self,
515 target: &mut Target,
516 ) -> Result<(), Target::AppendError> {
517 self.compose_len().compose(target)?;
518 self.type_covered.compose(target)?;
519 self.algorithm.compose(target)?;
520 self.labels.compose(target)?;
521 self.original_ttl.compose(target)?;
522 self.expiration.compose(target)?;
523 self.inception.compose(target)?;
524 self.key_tag.compose(target)
525 }
526}
527
528impl<Name, SrcName> OctetsFrom<ProtoRrsig<SrcName>> for ProtoRrsig<Name>
531where
532 Name: OctetsFrom<SrcName>,
533{
534 type Error = Name::Error;
535
536 fn try_octets_from(
537 source: ProtoRrsig<SrcName>,
538 ) -> Result<Self, Self::Error> {
539 Ok(ProtoRrsig::new(
540 source.type_covered,
541 source.algorithm,
542 source.labels,
543 source.original_ttl,
544 source.expiration,
545 source.inception,
546 source.key_tag,
547 Name::try_octets_from(source.signer_name)?,
548 ))
549 }
550}
551
552impl<Name, TName> FlattenInto<ProtoRrsig<TName>> for ProtoRrsig<Name>
553where
554 Name: FlattenInto<TName>,
555{
556 type AppendError = Name::AppendError;
557
558 fn try_flatten_into(
559 self
560 ) -> Result<ProtoRrsig<TName>, Name::AppendError> {
561 Ok(ProtoRrsig::new(
562 self.type_covered,
563 self.algorithm,
564 self.labels,
565 self.original_ttl,
566 self.expiration,
567 self.inception,
568 self.key_tag,
569 self.signer_name.try_flatten_into()?,
570 ))
571 }
572}
573
574#[derive(Clone)]
577#[cfg_attr(
578 feature = "serde",
579 derive(serde::Serialize, serde::Deserialize),
580 serde(bound(
581 serialize = "
582 Octs: octseq::serde::SerializeOctets + AsRef<[u8]>,
583 Name: serde::Serialize,
584 ",
585 deserialize = "
586 Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
587 <Octs as FromBuilder>::Builder:
588 OctetsBuilder + EmptyBuilder,
589 Name: serde::Deserialize<'de>,
590 ",
591 ))
592)]
593pub struct Rrsig<Octs, Name> {
594 type_covered: Rtype,
595 algorithm: SecAlg,
596 labels: u8,
597 original_ttl: Ttl,
598 expiration: Serial,
599 inception: Serial,
600 key_tag: u16,
601 signer_name: Name,
602 #[cfg_attr(
603 feature = "serde",
604 serde(with = "crate::utils::base64::serde")
605 )]
606 signature: Octs,
607}
608
609impl<Octs, Name> Rrsig<Octs, Name> {
610 #[allow(clippy::too_many_arguments)] pub fn new(
612 type_covered: Rtype,
613 algorithm: SecAlg,
614 labels: u8,
615 original_ttl: Ttl,
616 expiration: Serial,
617 inception: Serial,
618 key_tag: u16,
619 signer_name: Name,
620 signature: Octs,
621 ) -> Result<Self, LongRecordData>
622 where
623 Octs: AsRef<[u8]>,
624 Name: ToDname,
625 {
626 LongRecordData::check_len(
627 usize::from(
628 Rtype::COMPOSE_LEN
629 + SecAlg::COMPOSE_LEN
630 + u8::COMPOSE_LEN
631 + u32::COMPOSE_LEN
632 + Serial::COMPOSE_LEN
633 + Serial::COMPOSE_LEN
634 + u16::COMPOSE_LEN
635 + signer_name.compose_len(),
636 )
637 .checked_add(signature.as_ref().len())
638 .expect("long signature"),
639 )?;
640 Ok(unsafe {
641 Rrsig::new_unchecked(
642 type_covered,
643 algorithm,
644 labels,
645 original_ttl,
646 expiration,
647 inception,
648 key_tag,
649 signer_name,
650 signature,
651 )
652 })
653 }
654
655 #[allow(clippy::too_many_arguments)] pub unsafe fn new_unchecked(
663 type_covered: Rtype,
664 algorithm: SecAlg,
665 labels: u8,
666 original_ttl: Ttl,
667 expiration: Serial,
668 inception: Serial,
669 key_tag: u16,
670 signer_name: Name,
671 signature: Octs,
672 ) -> Self {
673 Rrsig {
674 type_covered,
675 algorithm,
676 labels,
677 original_ttl,
678 expiration,
679 inception,
680 key_tag,
681 signer_name,
682 signature,
683 }
684 }
685
686 pub fn type_covered(&self) -> Rtype {
687 self.type_covered
688 }
689
690 pub fn algorithm(&self) -> SecAlg {
691 self.algorithm
692 }
693
694 pub fn labels(&self) -> u8 {
695 self.labels
696 }
697
698 pub fn original_ttl(&self) -> Ttl {
699 self.original_ttl
700 }
701
702 pub fn expiration(&self) -> Serial {
703 self.expiration
704 }
705
706 pub fn inception(&self) -> Serial {
707 self.inception
708 }
709
710 pub fn key_tag(&self) -> u16 {
711 self.key_tag
712 }
713
714 pub fn signer_name(&self) -> &Name {
715 &self.signer_name
716 }
717
718 pub fn signature(&self) -> &Octs {
719 &self.signature
720 }
721
722 pub fn set_signature(&mut self, signature: Octs) {
723 self.signature = signature
724 }
725
726 pub(super) fn convert_octets<TOcts, TName>(
727 self,
728 ) -> Result<Rrsig<TOcts, TName>, TOcts::Error>
729 where
730 TOcts: OctetsFrom<Octs>,
731 TName: OctetsFrom<Name, Error = TOcts::Error>,
732 {
733 Ok(unsafe {
734 Rrsig::new_unchecked(
735 self.type_covered,
736 self.algorithm,
737 self.labels,
738 self.original_ttl,
739 self.expiration,
740 self.inception,
741 self.key_tag,
742 TName::try_octets_from(self.signer_name)?,
743 TOcts::try_octets_from(self.signature)?,
744 )
745 })
746 }
747
748 pub(super) fn flatten<TOcts, TName>(
749 self,
750 ) -> Result<Rrsig<TOcts, TName>, TOcts::Error>
751 where
752 TOcts: OctetsFrom<Octs>,
753 Name: FlattenInto<TName, AppendError = TOcts::Error>,
754 {
755 Ok(unsafe {
756 Rrsig::new_unchecked(
757 self.type_covered,
758 self.algorithm,
759 self.labels,
760 self.original_ttl,
761 self.expiration,
762 self.inception,
763 self.key_tag,
764 self.signer_name.try_flatten_into()?,
765 TOcts::try_octets_from(self.signature)?,
766 )
767 })
768 }
769
770 pub fn scan<S: Scanner<Octets = Octs, Dname = Name>>(
771 scanner: &mut S,
772 ) -> Result<Self, S::Error>
773 where
774 Octs: AsRef<[u8]>,
775 Name: ToDname,
776 {
777 Self::new(
778 Rtype::scan(scanner)?,
779 SecAlg::scan(scanner)?,
780 u8::scan(scanner)?,
781 Ttl::scan(scanner)?,
782 Serial::scan_rrsig(scanner)?,
783 Serial::scan_rrsig(scanner)?,
784 u16::scan(scanner)?,
785 scanner.scan_dname()?,
786 scanner.convert_entry(base64::SymbolConverter::new())?,
787 )
788 .map_err(|err| S::Error::custom(err.as_str()))
789 }
790}
791
792impl<Octs> Rrsig<Octs, ParsedDname<Octs>> {
793 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
794 parser: &mut Parser<'a, Src>,
795 ) -> Result<Self, ParseError> {
796 let type_covered = Rtype::parse(parser)?;
797 let algorithm = SecAlg::parse(parser)?;
798 let labels = u8::parse(parser)?;
799 let original_ttl = Ttl::parse(parser)?;
800 let expiration = Serial::parse(parser)?;
801 let inception = Serial::parse(parser)?;
802 let key_tag = u16::parse(parser)?;
803 let signer_name = ParsedDname::parse(parser)?;
804 let len = parser.remaining();
805 let signature = parser.parse_octets(len)?;
806 Ok(unsafe {
807 Self::new_unchecked(
808 type_covered,
809 algorithm,
810 labels,
811 original_ttl,
812 expiration,
813 inception,
814 key_tag,
815 signer_name,
816 signature,
817 )
818 })
819 }
820}
821
822impl<Octs, SrcOcts, Name, SrcName> OctetsFrom<Rrsig<SrcOcts, SrcName>>
825 for Rrsig<Octs, Name>
826where
827 Octs: OctetsFrom<SrcOcts>,
828 Name: OctetsFrom<SrcName>,
829 Octs::Error: From<Name::Error>,
830{
831 type Error = Octs::Error;
832
833 fn try_octets_from(
834 source: Rrsig<SrcOcts, SrcName>,
835 ) -> Result<Self, Self::Error> {
836 Ok(unsafe {
837 Rrsig::new_unchecked(
838 source.type_covered,
839 source.algorithm,
840 source.labels,
841 source.original_ttl,
842 source.expiration,
843 source.inception,
844 source.key_tag,
845 Name::try_octets_from(source.signer_name)?,
846 Octs::try_octets_from(source.signature)?,
847 )
848 })
849 }
850}
851
852impl<Octs, TOcts, Name, TName> FlattenInto<Rrsig<TOcts, TName>>
853 for Rrsig<Octs, Name>
854where
855 TOcts: OctetsFrom<Octs>,
856 Name: FlattenInto<TName, AppendError = TOcts::Error>,
857{
858 type AppendError = TOcts::Error;
859
860 fn try_flatten_into(self) -> Result<Rrsig<TOcts, TName>, TOcts::Error> {
861 self.flatten()
862 }
863}
864
865impl<N, NN, O, OO> PartialEq<Rrsig<OO, NN>> for Rrsig<O, N>
868where
869 N: ToDname,
870 NN: ToDname,
871 O: AsRef<[u8]>,
872 OO: AsRef<[u8]>,
873{
874 fn eq(&self, other: &Rrsig<OO, NN>) -> bool {
875 self.type_covered == other.type_covered
876 && self.algorithm == other.algorithm
877 && self.labels == other.labels
878 && self.original_ttl == other.original_ttl
879 && self.expiration.into_int() == other.expiration.into_int()
880 && self.inception.into_int() == other.inception.into_int()
881 && self.key_tag == other.key_tag
882 && self.signer_name.name_eq(&other.signer_name)
883 && self.signature.as_ref() == other.signature.as_ref()
884 }
885}
886
887impl<Octs, Name> Eq for Rrsig<Octs, Name>
888where
889 Octs: AsRef<[u8]>,
890 Name: ToDname,
891{
892}
893
894impl<N, NN, O, OO> PartialOrd<Rrsig<OO, NN>> for Rrsig<O, N>
897where
898 N: ToDname,
899 NN: ToDname,
900 O: AsRef<[u8]>,
901 OO: AsRef<[u8]>,
902{
903 fn partial_cmp(&self, other: &Rrsig<OO, NN>) -> Option<Ordering> {
904 match self.type_covered.partial_cmp(&other.type_covered) {
905 Some(Ordering::Equal) => {}
906 other => return other,
907 }
908 match self.algorithm.partial_cmp(&other.algorithm) {
909 Some(Ordering::Equal) => {}
910 other => return other,
911 }
912 match self.labels.partial_cmp(&other.labels) {
913 Some(Ordering::Equal) => {}
914 other => return other,
915 }
916 match self.original_ttl.partial_cmp(&other.original_ttl) {
917 Some(Ordering::Equal) => {}
918 other => return other,
919 }
920 match self.expiration.partial_cmp(&other.expiration) {
921 Some(Ordering::Equal) => {}
922 other => return other,
923 }
924 match self.inception.partial_cmp(&other.inception) {
925 Some(Ordering::Equal) => {}
926 other => return other,
927 }
928 match self.key_tag.partial_cmp(&other.key_tag) {
929 Some(Ordering::Equal) => {}
930 other => return other,
931 }
932 match self.signer_name.name_cmp(&other.signer_name) {
933 Ordering::Equal => {}
934 other => return Some(other),
935 }
936 self.signature
937 .as_ref()
938 .partial_cmp(other.signature.as_ref())
939 }
940}
941
942impl<N, NN, O, OO> CanonicalOrd<Rrsig<OO, NN>> for Rrsig<O, N>
943where
944 N: ToDname,
945 NN: ToDname,
946 O: AsRef<[u8]>,
947 OO: AsRef<[u8]>,
948{
949 fn canonical_cmp(&self, other: &Rrsig<OO, NN>) -> Ordering {
950 match self.type_covered.cmp(&other.type_covered) {
951 Ordering::Equal => {}
952 other => return other,
953 }
954 match self.algorithm.cmp(&other.algorithm) {
955 Ordering::Equal => {}
956 other => return other,
957 }
958 match self.labels.cmp(&other.labels) {
959 Ordering::Equal => {}
960 other => return other,
961 }
962 match self.original_ttl.cmp(&other.original_ttl) {
963 Ordering::Equal => {}
964 other => return other,
965 }
966 match self.expiration.canonical_cmp(&other.expiration) {
967 Ordering::Equal => {}
968 other => return other,
969 }
970 match self.inception.canonical_cmp(&other.inception) {
971 Ordering::Equal => {}
972 other => return other,
973 }
974 match self.key_tag.cmp(&other.key_tag) {
975 Ordering::Equal => {}
976 other => return other,
977 }
978 match self.signer_name.lowercase_composed_cmp(&other.signer_name) {
979 Ordering::Equal => {}
980 other => return other,
981 }
982 self.signature.as_ref().cmp(other.signature.as_ref())
983 }
984}
985
986impl<O: AsRef<[u8]>, N: ToDname> Ord for Rrsig<O, N> {
987 fn cmp(&self, other: &Self) -> Ordering {
988 self.canonical_cmp(other)
989 }
990}
991
992impl<O: AsRef<[u8]>, N: hash::Hash> hash::Hash for Rrsig<O, N> {
995 fn hash<H: hash::Hasher>(&self, state: &mut H) {
996 self.type_covered.hash(state);
997 self.algorithm.hash(state);
998 self.labels.hash(state);
999 self.original_ttl.hash(state);
1000 self.expiration.into_int().hash(state);
1001 self.inception.into_int().hash(state);
1002 self.key_tag.hash(state);
1003 self.signer_name.hash(state);
1004 self.signature.as_ref().hash(state);
1005 }
1006}
1007
1008impl<Octs, Name> RecordData for Rrsig<Octs, Name> {
1011 fn rtype(&self) -> Rtype {
1012 Rtype::Rrsig
1013 }
1014}
1015
1016impl<'a, Octs: Octets + ?Sized> ParseRecordData<'a, Octs>
1017 for Rrsig<Octs::Range<'a>, ParsedDname<Octs::Range<'a>>>
1018{
1019 fn parse_rdata(
1020 rtype: Rtype,
1021 parser: &mut Parser<'a, Octs>,
1022 ) -> Result<Option<Self>, ParseError> {
1023 if rtype == Rtype::Rrsig {
1024 Self::parse(parser).map(Some)
1025 } else {
1026 Ok(None)
1027 }
1028 }
1029}
1030
1031impl<Octs, Name> ComposeRecordData for Rrsig<Octs, Name>
1032where
1033 Octs: AsRef<[u8]>,
1034 Name: ToDname,
1035{
1036 fn rdlen(&self, _compress: bool) -> Option<u16> {
1037 Some(
1038 (Rtype::COMPOSE_LEN
1039 + SecAlg::COMPOSE_LEN
1040 + u8::COMPOSE_LEN
1041 + u32::COMPOSE_LEN
1042 + Serial::COMPOSE_LEN
1043 + Serial::COMPOSE_LEN
1044 + u16::COMPOSE_LEN
1045 + self.signer_name.compose_len())
1046 .checked_add(
1047 u16::try_from(self.signature.as_ref().len())
1048 .expect("long signature"),
1049 )
1050 .expect("long signature"),
1051 )
1052 }
1053
1054 fn compose_rdata<Target: Composer + ?Sized>(
1055 &self,
1056 target: &mut Target,
1057 ) -> Result<(), Target::AppendError> {
1058 self.compose_head(target)?;
1059 self.signer_name.compose(target)?;
1060 target.append_slice(self.signature.as_ref())
1061 }
1062
1063 fn compose_canonical_rdata<Target: Composer + ?Sized>(
1064 &self,
1065 target: &mut Target,
1066 ) -> Result<(), Target::AppendError> {
1067 self.compose_head(target)?;
1068 self.signer_name.compose_canonical(target)?;
1069 target.append_slice(self.signature.as_ref())
1070 }
1071}
1072
1073impl<Octs: AsRef<[u8]>, Name: ToDname> Rrsig<Octs, Name> {
1074 fn compose_head<Target: Composer + ?Sized>(
1075 &self,
1076 target: &mut Target,
1077 ) -> Result<(), Target::AppendError> {
1078 self.type_covered.compose(target)?;
1079 self.algorithm.compose(target)?;
1080 self.labels.compose(target)?;
1081 self.original_ttl.compose(target)?;
1082 self.expiration.compose(target)?;
1083 self.inception.compose(target)?;
1084 self.key_tag.compose(target)
1085 }
1086}
1087
1088impl<Octs, Name> fmt::Display for Rrsig<Octs, Name>
1091where
1092 Octs: AsRef<[u8]>,
1093 Name: fmt::Display,
1094{
1095 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1096 write!(
1097 f,
1098 "{} {} {} {} {} {} {} {}. ",
1099 self.type_covered,
1100 self.algorithm,
1101 self.labels,
1102 self.original_ttl.as_secs(),
1103 self.expiration,
1104 self.inception,
1105 self.key_tag,
1106 self.signer_name
1107 )?;
1108 base64::display(&self.signature, f)
1109 }
1110}
1111
1112impl<Octs, Name> fmt::Debug for Rrsig<Octs, Name>
1115where
1116 Octs: AsRef<[u8]>,
1117 Name: fmt::Debug,
1118{
1119 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1120 f.debug_struct("Rrsig")
1121 .field("type_covered", &self.type_covered)
1122 .field("algorithm", &self.algorithm)
1123 .field("labels", &self.labels)
1124 .field("original_ttl", &self.original_ttl)
1125 .field("expiration", &self.expiration)
1126 .field("inception", &self.inception)
1127 .field("key_tag", &self.key_tag)
1128 .field("signer_name", &self.signer_name)
1129 .field("signature", &self.signature.as_ref())
1130 .finish()
1131 }
1132}
1133
1134#[derive(Clone)]
1137#[cfg_attr(
1138 feature = "serde",
1139 derive(serde::Serialize, serde::Deserialize),
1140 serde(bound(
1141 serialize = "
1142 Octs: octseq::serde::SerializeOctets + AsRef<[u8]>,
1143 Name: serde::Serialize,
1144 ",
1145 deserialize = "
1146 Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
1147 <Octs as FromBuilder>::Builder:
1148 OctetsBuilder + EmptyBuilder + Truncate
1149 + AsRef<[u8]> + AsMut<[u8]>,
1150 Name: serde::Deserialize<'de>,
1151 ",
1152 ))
1153)]
1154pub struct Nsec<Octs, Name> {
1155 next_name: Name,
1156 types: RtypeBitmap<Octs>,
1157}
1158
1159impl<Octs, Name> Nsec<Octs, Name> {
1160 pub fn new(next_name: Name, types: RtypeBitmap<Octs>) -> Self {
1161 Nsec { next_name, types }
1162 }
1163
1164 pub fn next_name(&self) -> &Name {
1165 &self.next_name
1166 }
1167
1168 pub fn set_next_name(&mut self, next_name: Name) {
1169 self.next_name = next_name
1170 }
1171
1172 pub fn types(&self) -> &RtypeBitmap<Octs> {
1173 &self.types
1174 }
1175
1176 pub(super) fn convert_octets<TOcts, TName>(
1177 self,
1178 ) -> Result<Nsec<TOcts, TName>, TOcts::Error>
1179 where
1180 TOcts: OctetsFrom<Octs>,
1181 TName: OctetsFrom<Name, Error = TOcts::Error>,
1182 {
1183 Ok(Nsec::new(
1184 self.next_name.try_octets_into()?,
1185 self.types.convert_octets()?,
1186 ))
1187 }
1188
1189 pub(super) fn flatten<TOcts, TName>(
1190 self,
1191 ) -> Result<Nsec<TOcts, TName>, TOcts::Error>
1192 where
1193 TOcts: OctetsFrom<Octs>,
1194 Name: FlattenInto<TName, AppendError = TOcts::Error>,
1195 {
1196 Ok(Nsec::new(
1197 self.next_name.try_flatten_into()?,
1198 self.types.convert_octets()?,
1199 ))
1200 }
1201
1202 pub fn scan<S: Scanner<Octets = Octs, Dname = Name>>(
1203 scanner: &mut S,
1204 ) -> Result<Self, S::Error> {
1205 Ok(Self::new(
1206 scanner.scan_dname()?,
1207 RtypeBitmap::scan(scanner)?,
1208 ))
1209 }
1210}
1211
1212impl<Octs: AsRef<[u8]>> Nsec<Octs, ParsedDname<Octs>> {
1213 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized + 'a>(
1214 parser: &mut Parser<'a, Src>,
1215 ) -> Result<Self, ParseError> {
1216 Ok(Nsec::new(
1217 ParsedDname::parse(parser)?,
1218 RtypeBitmap::parse(parser)?,
1219 ))
1220 }
1221}
1222
1223impl<Octs, SrcOcts, Name, SrcName> OctetsFrom<Nsec<SrcOcts, SrcName>>
1226 for Nsec<Octs, Name>
1227where
1228 Octs: OctetsFrom<SrcOcts>,
1229 Name: OctetsFrom<SrcName, Error = Octs::Error>,
1230{
1231 type Error = Octs::Error;
1232
1233 fn try_octets_from(
1234 source: Nsec<SrcOcts, SrcName>,
1235 ) -> Result<Self, Self::Error> {
1236 Ok(Nsec::new(
1237 Name::try_octets_from(source.next_name)?,
1238 RtypeBitmap::try_octets_from(source.types)?,
1239 ))
1240 }
1241}
1242
1243impl<Octs, TOcts, Name, TName> FlattenInto<Nsec<TOcts, TName>>
1244 for Nsec<Octs, Name>
1245where
1246 TOcts: OctetsFrom<Octs>,
1247 Name: FlattenInto<TName, AppendError = TOcts::Error>,
1248{
1249 type AppendError = TOcts::Error;
1250
1251 fn try_flatten_into(self) -> Result<Nsec<TOcts, TName>, TOcts::Error> {
1252 self.flatten()
1253 }
1254}
1255
1256impl<O, OO, N, NN> PartialEq<Nsec<OO, NN>> for Nsec<O, N>
1259where
1260 O: AsRef<[u8]>,
1261 OO: AsRef<[u8]>,
1262 N: ToDname,
1263 NN: ToDname,
1264{
1265 fn eq(&self, other: &Nsec<OO, NN>) -> bool {
1266 self.next_name.name_eq(&other.next_name) && self.types == other.types
1267 }
1268}
1269
1270impl<O: AsRef<[u8]>, N: ToDname> Eq for Nsec<O, N> {}
1271
1272impl<O, OO, N, NN> PartialOrd<Nsec<OO, NN>> for Nsec<O, N>
1275where
1276 O: AsRef<[u8]>,
1277 OO: AsRef<[u8]>,
1278 N: ToDname,
1279 NN: ToDname,
1280{
1281 fn partial_cmp(&self, other: &Nsec<OO, NN>) -> Option<Ordering> {
1282 match self.next_name.name_cmp(&other.next_name) {
1283 Ordering::Equal => {}
1284 other => return Some(other),
1285 }
1286 self.types.partial_cmp(&self.types)
1287 }
1288}
1289
1290impl<O, OO, N, NN> CanonicalOrd<Nsec<OO, NN>> for Nsec<O, N>
1291where
1292 O: AsRef<[u8]>,
1293 OO: AsRef<[u8]>,
1294 N: ToDname,
1295 NN: ToDname,
1296{
1297 fn canonical_cmp(&self, other: &Nsec<OO, NN>) -> Ordering {
1298 match self.next_name.composed_cmp(&other.next_name) {
1300 Ordering::Equal => {}
1301 other => return other,
1302 }
1303 self.types.cmp(&self.types)
1304 }
1305}
1306
1307impl<O, N> Ord for Nsec<O, N>
1308where
1309 O: AsRef<[u8]>,
1310 N: ToDname,
1311{
1312 fn cmp(&self, other: &Self) -> Ordering {
1313 match self.next_name.name_cmp(&other.next_name) {
1314 Ordering::Equal => {}
1315 other => return other,
1316 }
1317 self.types.cmp(&self.types)
1318 }
1319}
1320
1321impl<Octs: AsRef<[u8]>, Name: hash::Hash> hash::Hash for Nsec<Octs, Name> {
1324 fn hash<H: hash::Hasher>(&self, state: &mut H) {
1325 self.next_name.hash(state);
1326 self.types.hash(state);
1327 }
1328}
1329
1330impl<Octs, Name> RecordData for Nsec<Octs, Name> {
1333 fn rtype(&self) -> Rtype {
1334 Rtype::Nsec
1335 }
1336}
1337
1338impl<'a, Octs: Octets + ?Sized> ParseRecordData<'a, Octs>
1339 for Nsec<Octs::Range<'a>, ParsedDname<Octs::Range<'a>>>
1340{
1341 fn parse_rdata(
1342 rtype: Rtype,
1343 parser: &mut Parser<'a, Octs>,
1344 ) -> Result<Option<Self>, ParseError> {
1345 if rtype == Rtype::Nsec {
1346 Self::parse(parser).map(Some)
1347 } else {
1348 Ok(None)
1349 }
1350 }
1351}
1352
1353impl<Octs, Name> ComposeRecordData for Nsec<Octs, Name>
1354where
1355 Octs: AsRef<[u8]>,
1356 Name: ToDname,
1357{
1358 fn rdlen(&self, _compress: bool) -> Option<u16> {
1359 Some(
1360 self.next_name
1361 .compose_len()
1362 .checked_add(self.types.compose_len())
1363 .expect("long type bitmap"),
1364 )
1365 }
1366
1367 fn compose_rdata<Target: Composer + ?Sized>(
1368 &self,
1369 target: &mut Target,
1370 ) -> Result<(), Target::AppendError> {
1371 self.next_name.compose(target)?;
1372 self.types.compose(target)
1373 }
1374
1375 fn compose_canonical_rdata<Target: Composer + ?Sized>(
1376 &self,
1377 target: &mut Target,
1378 ) -> Result<(), Target::AppendError> {
1379 self.compose_rdata(target)
1382 }
1383}
1384
1385impl<Octs, Name> fmt::Display for Nsec<Octs, Name>
1388where
1389 Octs: AsRef<[u8]>,
1390 Name: fmt::Display,
1391{
1392 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1393 write!(f, "{}. {}", self.next_name, self.types)
1394 }
1395}
1396
1397impl<Octs, Name> fmt::Debug for Nsec<Octs, Name>
1400where
1401 Octs: AsRef<[u8]>,
1402 Name: fmt::Debug,
1403{
1404 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1405 f.debug_struct("Nsec")
1406 .field("next_name", &self.next_name)
1407 .field("types", &self.types)
1408 .finish()
1409 }
1410}
1411
1412#[derive(Clone)]
1415#[cfg_attr(
1416 feature = "serde",
1417 derive(serde::Serialize, serde::Deserialize),
1418 serde(bound(
1419 serialize = "
1420 Octs: octseq::serde::SerializeOctets + AsRef<[u8]>
1421 ",
1422 deserialize = "
1423 Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
1424 <Octs as FromBuilder>::Builder:
1425 OctetsBuilder + EmptyBuilder,
1426 ",
1427 ))
1428)]
1429pub struct Ds<Octs> {
1430 key_tag: u16,
1431 algorithm: SecAlg,
1432 digest_type: DigestAlg,
1433 #[cfg_attr(
1434 feature = "serde",
1435 serde(with = "crate::utils::base64::serde")
1436 )]
1437 digest: Octs,
1438}
1439
1440impl<Octs> Ds<Octs> {
1441 pub fn new(
1442 key_tag: u16,
1443 algorithm: SecAlg,
1444 digest_type: DigestAlg,
1445 digest: Octs,
1446 ) -> Result<Self, LongRecordData>
1447 where
1448 Octs: AsRef<[u8]>,
1449 {
1450 LongRecordData::check_len(
1451 usize::from(
1452 u16::COMPOSE_LEN
1453 + SecAlg::COMPOSE_LEN
1454 + DigestAlg::COMPOSE_LEN,
1455 )
1456 .checked_add(digest.as_ref().len())
1457 .expect("long digest"),
1458 )?;
1459 Ok(unsafe {
1460 Ds::new_unchecked(key_tag, algorithm, digest_type, digest)
1461 })
1462 }
1463
1464 pub unsafe fn new_unchecked(
1471 key_tag: u16,
1472 algorithm: SecAlg,
1473 digest_type: DigestAlg,
1474 digest: Octs,
1475 ) -> Self {
1476 Ds {
1477 key_tag,
1478 algorithm,
1479 digest_type,
1480 digest,
1481 }
1482 }
1483
1484 pub fn key_tag(&self) -> u16 {
1485 self.key_tag
1486 }
1487
1488 pub fn algorithm(&self) -> SecAlg {
1489 self.algorithm
1490 }
1491
1492 pub fn digest_type(&self) -> DigestAlg {
1493 self.digest_type
1494 }
1495
1496 pub fn digest(&self) -> &Octs {
1497 &self.digest
1498 }
1499
1500 pub fn into_digest(self) -> Octs {
1501 self.digest
1502 }
1503
1504 pub(super) fn convert_octets<Target: OctetsFrom<Octs>>(
1505 self,
1506 ) -> Result<Ds<Target>, Target::Error> {
1507 Ok(unsafe {
1508 Ds::new_unchecked(
1509 self.key_tag,
1510 self.algorithm,
1511 self.digest_type,
1512 self.digest.try_octets_into()?,
1513 )
1514 })
1515 }
1516
1517 pub(super) fn flatten<Target: OctetsFrom<Octs>>(
1518 self,
1519 ) -> Result<Ds<Target>, Target::Error> {
1520 self.convert_octets()
1521 }
1522
1523 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
1524 parser: &mut Parser<'a, Src>,
1525 ) -> Result<Self, ParseError> {
1526 let len = match parser.remaining().checked_sub(4) {
1527 Some(len) => len,
1528 None => return Err(ParseError::ShortInput),
1529 };
1530 Ok(unsafe {
1531 Self::new_unchecked(
1532 u16::parse(parser)?,
1533 SecAlg::parse(parser)?,
1534 DigestAlg::parse(parser)?,
1535 parser.parse_octets(len)?,
1536 )
1537 })
1538 }
1539
1540 pub fn scan<S: Scanner<Octets = Octs>>(
1541 scanner: &mut S,
1542 ) -> Result<Self, S::Error>
1543 where
1544 Octs: AsRef<[u8]>,
1545 {
1546 Self::new(
1547 u16::scan(scanner)?,
1548 SecAlg::scan(scanner)?,
1549 DigestAlg::scan(scanner)?,
1550 scanner.convert_entry(base16::SymbolConverter::new())?,
1551 )
1552 .map_err(|err| S::Error::custom(err.as_str()))
1553 }
1554}
1555
1556impl<Octs, SrcOcts> OctetsFrom<Ds<SrcOcts>> for Ds<Octs>
1559where
1560 Octs: OctetsFrom<SrcOcts>,
1561{
1562 type Error = Octs::Error;
1563
1564 fn try_octets_from(source: Ds<SrcOcts>) -> Result<Self, Self::Error> {
1565 Ok(unsafe {
1566 Ds::new_unchecked(
1567 source.key_tag,
1568 source.algorithm,
1569 source.digest_type,
1570 Octs::try_octets_from(source.digest)?,
1571 )
1572 })
1573 }
1574}
1575
1576impl<Octs, Other> PartialEq<Ds<Other>> for Ds<Octs>
1579where
1580 Octs: AsRef<[u8]>,
1581 Other: AsRef<[u8]>,
1582{
1583 fn eq(&self, other: &Ds<Other>) -> bool {
1584 self.key_tag == other.key_tag
1585 && self.algorithm == other.algorithm
1586 && self.digest_type == other.digest_type
1587 && self.digest.as_ref().eq(other.digest.as_ref())
1588 }
1589}
1590
1591impl<Octs: AsRef<[u8]>> Eq for Ds<Octs> {}
1592
1593impl<Octs, Other> PartialOrd<Ds<Other>> for Ds<Octs>
1596where
1597 Octs: AsRef<[u8]>,
1598 Other: AsRef<[u8]>,
1599{
1600 fn partial_cmp(&self, other: &Ds<Other>) -> Option<Ordering> {
1601 match self.key_tag.partial_cmp(&other.key_tag) {
1602 Some(Ordering::Equal) => {}
1603 other => return other,
1604 }
1605 match self.algorithm.partial_cmp(&other.algorithm) {
1606 Some(Ordering::Equal) => {}
1607 other => return other,
1608 }
1609 match self.digest_type.partial_cmp(&other.digest_type) {
1610 Some(Ordering::Equal) => {}
1611 other => return other,
1612 }
1613 self.digest.as_ref().partial_cmp(other.digest.as_ref())
1614 }
1615}
1616
1617impl<Octs, Other> CanonicalOrd<Ds<Other>> for Ds<Octs>
1618where
1619 Octs: AsRef<[u8]>,
1620 Other: AsRef<[u8]>,
1621{
1622 fn canonical_cmp(&self, other: &Ds<Other>) -> Ordering {
1623 match self.key_tag.cmp(&other.key_tag) {
1624 Ordering::Equal => {}
1625 other => return other,
1626 }
1627 match self.algorithm.cmp(&other.algorithm) {
1628 Ordering::Equal => {}
1629 other => return other,
1630 }
1631 match self.digest_type.cmp(&other.digest_type) {
1632 Ordering::Equal => {}
1633 other => return other,
1634 }
1635 self.digest.as_ref().cmp(other.digest.as_ref())
1636 }
1637}
1638
1639impl<Octs: AsRef<[u8]>> Ord for Ds<Octs> {
1640 fn cmp(&self, other: &Self) -> Ordering {
1641 self.canonical_cmp(other)
1642 }
1643}
1644
1645impl<Octs: AsRef<[u8]>> hash::Hash for Ds<Octs> {
1648 fn hash<H: hash::Hasher>(&self, state: &mut H) {
1649 self.key_tag.hash(state);
1650 self.algorithm.hash(state);
1651 self.digest_type.hash(state);
1652 self.digest.as_ref().hash(state);
1653 }
1654}
1655
1656impl<Octs> RecordData for Ds<Octs> {
1659 fn rtype(&self) -> Rtype {
1660 Rtype::Ds
1661 }
1662}
1663
1664impl<'a, Octs> ParseRecordData<'a, Octs> for Ds<Octs::Range<'a>>
1665where
1666 Octs: Octets + ?Sized,
1667{
1668 fn parse_rdata(
1669 rtype: Rtype,
1670 parser: &mut Parser<'a, Octs>,
1671 ) -> Result<Option<Self>, ParseError> {
1672 if rtype == Rtype::Ds {
1673 Self::parse(parser).map(Some)
1674 } else {
1675 Ok(None)
1676 }
1677 }
1678}
1679
1680impl<Octs: AsRef<[u8]>> ComposeRecordData for Ds<Octs> {
1681 fn rdlen(&self, _compress: bool) -> Option<u16> {
1682 Some(
1683 u16::checked_add(
1684 u16::COMPOSE_LEN
1685 + SecAlg::COMPOSE_LEN
1686 + DigestAlg::COMPOSE_LEN,
1687 self.digest.as_ref().len().try_into().expect("long digest"),
1688 )
1689 .expect("long digest"),
1690 )
1691 }
1692
1693 fn compose_rdata<Target: Composer + ?Sized>(
1694 &self,
1695 target: &mut Target,
1696 ) -> Result<(), Target::AppendError> {
1697 self.key_tag.compose(target)?;
1698 self.algorithm.compose(target)?;
1699 self.digest_type.compose(target)?;
1700 target.append_slice(self.digest.as_ref())
1701 }
1702
1703 fn compose_canonical_rdata<Target: Composer + ?Sized>(
1704 &self,
1705 target: &mut Target,
1706 ) -> Result<(), Target::AppendError> {
1707 self.compose_rdata(target)
1708 }
1709}
1710
1711impl<Octs: AsRef<[u8]>> fmt::Display for Ds<Octs> {
1714 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1715 write!(
1716 f,
1717 "{} {} {} ",
1718 self.key_tag, self.algorithm, self.digest_type
1719 )?;
1720 for ch in self.digest.as_ref() {
1721 write!(f, "{:02x}", ch)?
1722 }
1723 Ok(())
1724 }
1725}
1726
1727impl<Octs: AsRef<[u8]>> fmt::Debug for Ds<Octs> {
1730 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1731 f.debug_struct("Ds")
1732 .field("key_tag", &self.key_tag)
1733 .field("algorithm", &self.algorithm)
1734 .field("digest_type", &self.digest_type)
1735 .field("digest", &self.digest.as_ref())
1736 .finish()
1737 }
1738}
1739
1740#[derive(Clone)]
1743pub struct RtypeBitmap<Octs>(Octs);
1744
1745impl<Octs> RtypeBitmap<Octs> {
1746 pub fn from_octets(octets: Octs) -> Result<Self, RtypeBitmapError>
1747 where
1748 Octs: AsRef<[u8]>,
1749 {
1750 {
1751 let mut data = octets.as_ref();
1752 while !data.is_empty() {
1753 if data.len() < 2 {
1755 return Err(RtypeBitmapError::ShortInput);
1756 }
1757
1758 let len = (data[1] as usize) + 2;
1759 if len == 2 {
1762 return Err(RtypeBitmapError::BadRtypeBitmap);
1763 }
1764 if len > 34 {
1765 return Err(RtypeBitmapError::BadRtypeBitmap);
1766 }
1767 if data.len() < len {
1768 return Err(RtypeBitmapError::ShortInput);
1769 }
1770 data = &data[len..];
1771 }
1772 }
1773 Ok(RtypeBitmap(octets))
1774 }
1775
1776 #[must_use]
1777 pub fn builder() -> RtypeBitmapBuilder<Octs::Builder>
1778 where
1779 Octs: FromBuilder,
1780 <Octs as FromBuilder>::Builder: EmptyBuilder,
1781 {
1782 RtypeBitmapBuilder::new()
1783 }
1784
1785 pub fn scan<S: Scanner<Octets = Octs>>(
1786 scanner: &mut S,
1787 ) -> Result<Self, S::Error> {
1788 let first = Rtype::scan(scanner)?;
1789 let mut builder =
1790 RtypeBitmapBuilder::with_builder(scanner.octets_builder()?);
1791 builder.add(first).map_err(|_| S::Error::short_buf())?;
1792 while scanner.continues() {
1793 builder
1794 .add(Rtype::scan(scanner)?)
1795 .map_err(|_| S::Error::short_buf())?;
1796 }
1797 Ok(builder.finalize())
1798 }
1799
1800 pub fn as_octets(&self) -> &Octs {
1801 &self.0
1802 }
1803
1804 pub(super) fn convert_octets<Target: OctetsFrom<Octs>>(
1805 self,
1806 ) -> Result<RtypeBitmap<Target>, Target::Error> {
1807 Ok(RtypeBitmap(self.0.try_octets_into()?))
1808 }
1809}
1810
1811impl<Octs: AsRef<[u8]>> RtypeBitmap<Octs> {
1812 pub fn as_slice(&self) -> &[u8] {
1813 self.0.as_ref()
1814 }
1815
1816 pub fn iter(&self) -> RtypeBitmapIter {
1817 RtypeBitmapIter::new(self.0.as_ref())
1818 }
1819
1820 pub fn contains(&self, rtype: Rtype) -> bool {
1821 let (block, octet, mask) = split_rtype(rtype);
1822 let mut data = self.0.as_ref();
1823 while !data.is_empty() {
1824 let ((window_num, window), next_data) =
1825 read_window(data).unwrap();
1826 if window_num == block {
1827 return !(window.len() <= octet || window[octet] & mask == 0);
1828 }
1829 data = next_data;
1830 }
1831 false
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 = parser.remaining();
1838 RtypeBitmap::from_octets(parser.parse_octets(len)?)
1839 .map_err(Into::into)
1840 }
1841
1842 pub fn compose_len(&self) -> u16 {
1843 u16::try_from(self.0.as_ref().len()).expect("long rtype bitmap")
1844 }
1845
1846 pub fn compose<Target: OctetsBuilder + ?Sized>(
1847 &self,
1848 target: &mut Target,
1849 ) -> Result<(), Target::AppendError> {
1850 target.append_slice(self.0.as_ref())
1851 }
1852}
1853
1854impl<T, Octs: AsRef<T>> AsRef<T> for RtypeBitmap<Octs> {
1857 fn as_ref(&self) -> &T {
1858 self.0.as_ref()
1859 }
1860}
1861
1862impl<Octs, SrcOcts> OctetsFrom<RtypeBitmap<SrcOcts>> for RtypeBitmap<Octs>
1865where
1866 Octs: OctetsFrom<SrcOcts>,
1867{
1868 type Error = Octs::Error;
1869
1870 fn try_octets_from(
1871 source: RtypeBitmap<SrcOcts>,
1872 ) -> Result<Self, Self::Error> {
1873 Octs::try_octets_from(source.0).map(RtypeBitmap)
1874 }
1875}
1876
1877impl<O, OO> PartialEq<RtypeBitmap<OO>> for RtypeBitmap<O>
1880where
1881 O: AsRef<[u8]>,
1882 OO: AsRef<[u8]>,
1883{
1884 fn eq(&self, other: &RtypeBitmap<OO>) -> bool {
1885 self.0.as_ref().eq(other.0.as_ref())
1886 }
1887}
1888
1889impl<O: AsRef<[u8]>> Eq for RtypeBitmap<O> {}
1890
1891impl<O, OO> PartialOrd<RtypeBitmap<OO>> for RtypeBitmap<O>
1894where
1895 O: AsRef<[u8]>,
1896 OO: AsRef<[u8]>,
1897{
1898 fn partial_cmp(&self, other: &RtypeBitmap<OO>) -> Option<Ordering> {
1899 self.0.as_ref().partial_cmp(other.0.as_ref())
1900 }
1901}
1902
1903impl<O, OO> CanonicalOrd<RtypeBitmap<OO>> for RtypeBitmap<O>
1904where
1905 O: AsRef<[u8]>,
1906 OO: AsRef<[u8]>,
1907{
1908 fn canonical_cmp(&self, other: &RtypeBitmap<OO>) -> Ordering {
1909 self.0.as_ref().cmp(other.0.as_ref())
1910 }
1911}
1912
1913impl<O: AsRef<[u8]>> Ord for RtypeBitmap<O> {
1914 fn cmp(&self, other: &Self) -> Ordering {
1915 self.0.as_ref().cmp(other.0.as_ref())
1916 }
1917}
1918
1919impl<O: AsRef<[u8]>> hash::Hash for RtypeBitmap<O> {
1922 fn hash<H: hash::Hasher>(&self, state: &mut H) {
1923 self.0.as_ref().hash(state)
1924 }
1925}
1926
1927impl<'a, Octs: AsRef<[u8]>> IntoIterator for &'a RtypeBitmap<Octs> {
1930 type Item = Rtype;
1931 type IntoIter = RtypeBitmapIter<'a>;
1932
1933 fn into_iter(self) -> Self::IntoIter {
1934 self.iter()
1935 }
1936}
1937
1938impl<Octs: AsRef<[u8]>> fmt::Display for RtypeBitmap<Octs> {
1941 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1942 let mut iter = self.iter();
1943 if let Some(rtype) = iter.next() {
1944 rtype.fmt(f)?;
1945 }
1946 for rtype in iter {
1947 write!(f, " {}", rtype)?
1948 }
1949 Ok(())
1950 }
1951}
1952
1953impl<Octs: AsRef<[u8]>> fmt::Debug for RtypeBitmap<Octs> {
1956 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1957 f.write_str("RtypeBitmap(")?;
1958 fmt::Display::fmt(self, f)?;
1959 f.write_str(")")
1960 }
1961}
1962
1963#[cfg(feature = "serde")]
1966impl<Octs> serde::Serialize for RtypeBitmap<Octs>
1967where
1968 Octs: AsRef<[u8]> + SerializeOctets,
1969{
1970 fn serialize<S: serde::Serializer>(
1971 &self,
1972 serializer: S,
1973 ) -> Result<S::Ok, S::Error> {
1974 if serializer.is_human_readable() {
1975 struct Inner<'a>(&'a [u8]);
1976
1977 impl<'a> serde::Serialize for Inner<'a> {
1978 fn serialize<S: serde::Serializer>(
1979 &self,
1980 serializer: S,
1981 ) -> Result<S::Ok, S::Error> {
1982 use serde::ser::SerializeSeq;
1983
1984 let mut serializer = serializer.serialize_seq(None)?;
1985 for item in RtypeBitmapIter::new(self.0) {
1986 serializer.serialize_element(&item)?;
1987 }
1988 serializer.end()
1989 }
1990 }
1991
1992 serializer.serialize_newtype_struct(
1993 "RtypeBitmap",
1994 &Inner(self.0.as_ref()),
1995 )
1996 } else {
1997 serializer.serialize_newtype_struct(
1998 "RtypeBitmap",
1999 &self.0.as_serialized_octets(),
2000 )
2001 }
2002 }
2003}
2004
2005#[cfg(feature = "serde")]
2006impl<'de, Octs> serde::Deserialize<'de> for RtypeBitmap<Octs>
2007where
2008 Octs: FromBuilder + DeserializeOctets<'de>,
2009 <Octs as FromBuilder>::Builder:
2010 EmptyBuilder + Truncate + AsRef<[u8]> + AsMut<[u8]>,
2011{
2012 fn deserialize<D: serde::Deserializer<'de>>(
2013 deserializer: D,
2014 ) -> Result<Self, D::Error> {
2015 use core::marker::PhantomData;
2016
2017 struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
2018
2019 impl<'de, Octs> serde::de::Visitor<'de> for InnerVisitor<'de, Octs>
2020 where
2021 Octs: FromBuilder + DeserializeOctets<'de>,
2022 <Octs as FromBuilder>::Builder: OctetsBuilder
2023 + EmptyBuilder
2024 + Truncate
2025 + AsRef<[u8]>
2026 + AsMut<[u8]>,
2027 {
2028 type Value = RtypeBitmap<Octs>;
2029
2030 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
2031 f.write_str("a record type bitmap")
2032 }
2033
2034 fn visit_seq<A: serde::de::SeqAccess<'de>>(
2035 self,
2036 mut seq: A,
2037 ) -> Result<Self::Value, A::Error> {
2038 use serde::de::Error;
2039
2040 let mut builder = RtypeBitmap::<Octs>::builder();
2041 while let Some(element) = seq.next_element()? {
2042 builder.add(element).map_err(|_| {
2043 A::Error::custom(octseq::builder::ShortBuf)
2044 })?;
2045 }
2046
2047 Ok(builder.finalize())
2048 }
2049
2050 fn visit_borrowed_bytes<E: serde::de::Error>(
2051 self,
2052 value: &'de [u8],
2053 ) -> Result<Self::Value, E> {
2054 self.0.visit_borrowed_bytes(value).and_then(|octets| {
2055 RtypeBitmap::from_octets(octets).map_err(E::custom)
2056 })
2057 }
2058
2059 #[cfg(feature = "std")]
2060 fn visit_byte_buf<E: serde::de::Error>(
2061 self,
2062 value: std::vec::Vec<u8>,
2063 ) -> Result<Self::Value, E> {
2064 self.0.visit_byte_buf(value).and_then(|octets| {
2065 RtypeBitmap::from_octets(octets).map_err(E::custom)
2066 })
2067 }
2068 }
2069
2070 struct NewtypeVisitor<T>(PhantomData<T>);
2071
2072 impl<'de, Octs> serde::de::Visitor<'de> for NewtypeVisitor<Octs>
2073 where
2074 Octs: FromBuilder + DeserializeOctets<'de>,
2075 <Octs as FromBuilder>::Builder: OctetsBuilder
2076 + EmptyBuilder
2077 + Truncate
2078 + AsRef<[u8]>
2079 + AsMut<[u8]>,
2080 {
2081 type Value = RtypeBitmap<Octs>;
2082
2083 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
2084 f.write_str("a record type bitmap")
2085 }
2086
2087 fn visit_newtype_struct<D: serde::Deserializer<'de>>(
2088 self,
2089 deserializer: D,
2090 ) -> Result<Self::Value, D::Error> {
2091 if deserializer.is_human_readable() {
2092 deserializer
2093 .deserialize_seq(InnerVisitor(Octs::visitor()))
2094 } else {
2095 Octs::deserialize_with_visitor(
2096 deserializer,
2097 InnerVisitor(Octs::visitor()),
2098 )
2099 }
2100 }
2101 }
2102
2103 deserializer.deserialize_newtype_struct(
2104 "RtypeBitmap",
2105 NewtypeVisitor(PhantomData),
2106 )
2107 }
2108}
2109
2110#[derive(Clone, Debug)]
2122pub struct RtypeBitmapBuilder<Builder> {
2123 buf: Builder,
2124}
2125
2126impl<Builder: OctetsBuilder> RtypeBitmapBuilder<Builder> {
2127 #[must_use]
2128 pub fn new() -> Self
2129 where
2130 Builder: EmptyBuilder,
2131 {
2132 RtypeBitmapBuilder {
2133 buf: Builder::with_capacity(34),
2135 }
2136 }
2137
2138 pub fn with_builder(builder: Builder) -> Self {
2139 RtypeBitmapBuilder { buf: builder }
2140 }
2141}
2142
2143#[cfg(feature = "std")]
2144impl RtypeBitmapBuilder<Vec<u8>> {
2145 #[must_use]
2146 pub fn new_vec() -> Self {
2147 Self::new()
2148 }
2149}
2150
2151impl<Builder> RtypeBitmapBuilder<Builder>
2152where
2153 Builder: OctetsBuilder + AsRef<[u8]> + AsMut<[u8]>,
2154{
2155 pub fn add(&mut self, rtype: Rtype) -> Result<(), Builder::AppendError> {
2156 let (block, octet, bit) = split_rtype(rtype);
2157 let block = self.get_block(block)?;
2158 if (block[1] as usize) < (octet + 1) {
2159 block[1] = (octet + 1) as u8
2160 }
2161 block[octet + 2] |= bit;
2162 Ok(())
2163 }
2164
2165 fn get_block(
2166 &mut self,
2167 block: u8,
2168 ) -> Result<&mut [u8], Builder::AppendError> {
2169 let mut pos = 0;
2170 while pos < self.buf.as_ref().len() {
2171 match self.buf.as_ref()[pos].cmp(&block) {
2172 Ordering::Equal => {
2173 return Ok(&mut self.buf.as_mut()[pos..pos + 34])
2174 }
2175 Ordering::Greater => {
2176 let len = self.buf.as_ref().len() - pos;
2177 self.buf.append_slice(&[0; 34])?;
2178 let buf = self.buf.as_mut();
2179 unsafe {
2180 ptr::copy(
2181 buf.as_ptr().add(pos),
2182 buf.as_mut_ptr().add(pos + 34),
2183 len,
2184 );
2185 ptr::write_bytes(buf.as_mut_ptr().add(pos), 0, 34);
2186 }
2187 buf[pos] = block;
2188 return Ok(&mut buf[pos..pos + 34]);
2189 }
2190 Ordering::Less => pos += 34,
2191 }
2192 }
2193
2194 self.buf.append_slice(&[0; 34])?;
2195 self.buf.as_mut()[pos] = block;
2196 Ok(&mut self.buf.as_mut()[pos..pos + 34])
2197 }
2198
2199 pub fn finalize(mut self) -> RtypeBitmap<Builder::Octets>
2200 where
2201 Builder: FreezeBuilder + Truncate,
2202 {
2203 let mut src_pos = 0;
2204 let mut dst_pos = 0;
2205 while src_pos < self.buf.as_ref().len() {
2206 let len = (self.buf.as_ref()[src_pos + 1] as usize) + 2;
2207 if src_pos != dst_pos {
2208 let buf = self.buf.as_mut();
2209 unsafe {
2210 ptr::copy(
2211 buf.as_ptr().add(src_pos),
2212 buf.as_mut_ptr().add(dst_pos),
2213 len,
2214 )
2215 }
2216 }
2217 dst_pos += len;
2218 src_pos += 34;
2219 }
2220 self.buf.truncate(dst_pos);
2221 RtypeBitmap(self.buf.freeze())
2222 }
2223}
2224
2225impl<Builder> Default for RtypeBitmapBuilder<Builder>
2228where
2229 Builder: OctetsBuilder + EmptyBuilder,
2230{
2231 fn default() -> Self {
2232 Self::new()
2233 }
2234}
2235
2236pub struct RtypeBitmapIter<'a> {
2239 data: &'a [u8],
2244
2245 block: u16,
2247
2248 len: usize,
2250
2251 octet: usize,
2253
2254 bit: u16,
2256}
2257
2258impl<'a> RtypeBitmapIter<'a> {
2259 fn new(data: &'a [u8]) -> Self {
2260 if data.is_empty() {
2261 RtypeBitmapIter {
2262 data,
2263 block: 0,
2264 len: 0,
2265 octet: 0,
2266 bit: 0,
2267 }
2268 } else {
2269 let mut res = RtypeBitmapIter {
2270 data: &data[2..],
2271 block: u16::from(data[0]) << 8,
2272 len: usize::from(data[1]),
2273 octet: 0,
2274 bit: 0,
2275 };
2276 if res.data[0] & 0x80 == 0 {
2277 res.advance()
2278 }
2279 res
2280 }
2281 }
2282
2283 fn advance(&mut self) {
2284 loop {
2285 self.bit += 1;
2286 if self.bit == 8 {
2287 self.bit = 0;
2288 self.octet += 1;
2289 if self.octet == self.len {
2290 self.data = &self.data[self.len..];
2291 if self.data.is_empty() {
2292 return;
2293 }
2294 self.block = u16::from(self.data[0]) << 8;
2295 self.len = usize::from(self.data[1]);
2296 self.data = &self.data[2..];
2297 self.octet = 0;
2298 }
2299 }
2300 if self.data[self.octet] & (0x80 >> self.bit) != 0 {
2301 return;
2302 }
2303 }
2304 }
2305}
2306
2307impl<'a> Iterator for RtypeBitmapIter<'a> {
2308 type Item = Rtype;
2309
2310 fn next(&mut self) -> Option<Self::Item> {
2311 if self.data.is_empty() {
2312 return None;
2313 }
2314 let res =
2315 Rtype::from_int(self.block | (self.octet as u16) << 3 | self.bit);
2316 self.advance();
2317 Some(res)
2318 }
2319}
2320
2321#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2324pub enum RtypeBitmapError {
2325 ShortInput,
2326 BadRtypeBitmap,
2327}
2328
2329impl From<RtypeBitmapError> for ParseError {
2332 fn from(err: RtypeBitmapError) -> ParseError {
2333 match err {
2334 RtypeBitmapError::ShortInput => ParseError::ShortInput,
2335 RtypeBitmapError::BadRtypeBitmap => {
2336 FormError::new("invalid NSEC bitmap").into()
2337 }
2338 }
2339 }
2340}
2341
2342impl fmt::Display for RtypeBitmapError {
2345 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2346 match *self {
2347 RtypeBitmapError::ShortInput => ParseError::ShortInput.fmt(f),
2348 RtypeBitmapError::BadRtypeBitmap => {
2349 f.write_str("invalid record type bitmap")
2350 }
2351 }
2352 }
2353}
2354
2355#[cfg(feature = "std")]
2356impl std::error::Error for RtypeBitmapError {}
2357
2358fn split_rtype(rtype: Rtype) -> (u8, usize, u8) {
2362 let rtype = rtype.to_int();
2363 (
2364 (rtype >> 8) as u8,
2365 ((rtype & 0xFF) >> 3) as usize,
2366 0b1000_0000 >> (rtype & 0x07),
2367 )
2368}
2369
2370#[allow(clippy::type_complexity)]
2372fn read_window(data: &[u8]) -> Option<((u8, &[u8]), &[u8])> {
2373 data.split_first().and_then(|(n, data)| {
2374 data.split_first().and_then(|(l, data)| {
2375 if data.len() >= usize::from(*l) {
2376 let (window, data) = data.split_at(usize::from(*l));
2377 Some(((*n, window), data))
2378 } else {
2379 None
2380 }
2381 })
2382 })
2383}
2384
2385#[cfg(test)]
2388#[cfg(all(feature = "std", feature = "bytes"))]
2389mod test {
2390 use super::*;
2391 use crate::base::iana::Rtype;
2392 use crate::base::name::Dname;
2393 use crate::base::rdata::test::{
2394 test_compose_parse, test_rdlen, test_scan,
2395 };
2396 use core::str::FromStr;
2397 use std::vec::Vec;
2398
2399 #[test]
2402 #[allow(clippy::redundant_closure)] fn dnskey_compose_parse_scan() {
2404 let rdata = Dnskey::new(10, 11, SecAlg::RsaSha1, b"key0").unwrap();
2405 test_rdlen(&rdata);
2406 test_compose_parse(&rdata, |parser| Dnskey::parse(parser));
2407 test_scan(&["10", "11", "RSASHA1", "a2V5MA=="], Dnskey::scan, &rdata);
2408 }
2409
2410 #[test]
2413 #[allow(clippy::redundant_closure)] fn rrsig_compose_parse_scan() {
2415 let rdata = Rrsig::new(
2416 Rtype::A,
2417 SecAlg::RsaSha1,
2418 3,
2419 Ttl::from_secs(12),
2420 Serial::from(13),
2421 Serial::from(14),
2422 15,
2423 Dname::<Vec<u8>>::from_str("example.com.").unwrap(),
2424 b"key",
2425 )
2426 .unwrap();
2427 test_rdlen(&rdata);
2428 test_compose_parse(&rdata, |parser| Rrsig::parse(parser));
2429 test_scan(
2430 &[
2431 "A",
2432 "RSASHA1",
2433 "3",
2434 "12",
2435 "13",
2436 "14",
2437 "15",
2438 "example.com.",
2439 "a2V5",
2440 ],
2441 Rrsig::scan,
2442 &rdata,
2443 );
2444 }
2445
2446 #[test]
2449 #[allow(clippy::redundant_closure)] fn nsec_compose_parse_scan() {
2451 let mut rtype = RtypeBitmapBuilder::new_vec();
2452 rtype.add(Rtype::A).unwrap();
2453 rtype.add(Rtype::Srv).unwrap();
2454 let rdata = Nsec::new(
2455 Dname::<Vec<u8>>::from_str("example.com.").unwrap(),
2456 rtype.finalize(),
2457 );
2458 test_rdlen(&rdata);
2459 test_compose_parse(&rdata, |parser| Nsec::parse(parser));
2460 test_scan(&["example.com.", "A", "SRV"], Nsec::scan, &rdata);
2461 }
2462
2463 #[test]
2466 #[allow(clippy::redundant_closure)] fn ds_compose_parse_scan() {
2468 let rdata =
2469 Ds::new(10, SecAlg::RsaSha1, DigestAlg::Sha256, b"key").unwrap();
2470 test_rdlen(&rdata);
2471 test_compose_parse(&rdata, |parser| Ds::parse(parser));
2472 test_scan(&["10", "RSASHA1", "2", "6b6579"], Ds::scan, &rdata);
2473 }
2474
2475 #[test]
2478 fn rtype_split() {
2479 assert_eq!(split_rtype(Rtype::A), (0, 0, 0b01000000));
2480 assert_eq!(split_rtype(Rtype::Ns), (0, 0, 0b00100000));
2481 assert_eq!(split_rtype(Rtype::Caa), (1, 0, 0b01000000));
2482 }
2483
2484 #[test]
2485 fn rtype_bitmap_read_window() {
2486 let mut builder = RtypeBitmapBuilder::new_vec();
2487 builder.add(Rtype::A).unwrap();
2488 builder.add(Rtype::Caa).unwrap();
2489 let bitmap = builder.finalize();
2490
2491 let ((n, window), data) = read_window(bitmap.as_slice()).unwrap();
2492 assert_eq!((n, window), (0u8, b"\x40".as_ref()));
2493 let ((n, window), data) = read_window(data).unwrap();
2494 assert_eq!((n, window), (1u8, b"\x40".as_ref()));
2495 assert!(data.is_empty());
2496 assert!(read_window(data).is_none());
2497 }
2498
2499 #[test]
2500 fn rtype_bitmap_builder() {
2501 let mut builder = RtypeBitmapBuilder::new_vec();
2502 builder.add(Rtype::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();
2508 assert_eq!(
2509 bitmap.as_slice(),
2510 &b"\x00\x06\x40\x01\x00\x00\x00\x03\
2511 \x04\x1b\x00\x00\x00\x00\x00\x00\
2512 \x00\x00\x00\x00\x00\x00\x00\x00\
2513 \x00\x00\x00\x00\x00\x00\x00\x00\
2514 \x00\x00\x00\x00\x20"[..]
2515 );
2516
2517 assert!(bitmap.contains(Rtype::A));
2518 assert!(bitmap.contains(Rtype::Mx));
2519 assert!(bitmap.contains(Rtype::Rrsig));
2520 assert!(bitmap.contains(Rtype::Nsec));
2521 assert!(bitmap.contains(Rtype::Int(1234)));
2522 assert!(!bitmap.contains(Rtype::Int(1235)));
2523 assert!(!bitmap.contains(Rtype::Ns));
2524 }
2525
2526 #[test]
2527 fn rtype_bitmap_iter() {
2528 use std::vec::Vec;
2529
2530 let mut builder = RtypeBitmapBuilder::new_vec();
2531 let types = vec![
2532 Rtype::Ns,
2533 Rtype::Soa,
2534 Rtype::Mx,
2535 Rtype::Txt,
2536 Rtype::Rrsig,
2537 Rtype::Dnskey,
2538 Rtype::Nsec3param,
2539 Rtype::Spf,
2540 Rtype::Caa,
2541 ];
2542 for t in types.iter() {
2543 builder.add(*t).unwrap();
2544 }
2545
2546 let bitmap = builder.finalize();
2547 let bitmap_types: Vec<_> = bitmap.iter().collect();
2548 assert_eq!(types, bitmap_types);
2549 }
2550
2551 #[test]
2552 fn dnskey_key_tag() {
2553 assert_eq!(
2554 Dnskey::new(
2555 256,
2556 3,
2557 SecAlg::RsaSha256,
2558 base64::decode::<Vec<u8>>(
2559 "AwEAAcTQyaIe6nt3xSPOG2L/YfwBkOVTJN6mlnZ249O5Rtt3ZSRQHxQS\
2560 W61AODYw6bvgxrrGq8eeOuenFjcSYgNAMcBYoEYYmKDW6e9EryW4ZaT/\
2561 MCq+8Am06oR40xAA3fClOM6QjRcT85tP41Go946AicBGP8XOP/Aj1aI/\
2562 oPRGzRnboUPUok/AzTNnW5npBU69+BuiIwYE7mQOiNBFePyvjQBdoiuY\
2563 bmuD3Py0IyjlBxzZUXbqLsRL9gYFkCqeTY29Ik7usuzMTa+JRSLz6KGS\
2564 5RSJ7CTSMjZg8aNaUbN2dvGhakJPh92HnLvMA3TefFgbKJphFNPA3BWS\
2565 KLZ02cRWXqM="
2566 )
2567 .unwrap()
2568 ).unwrap()
2569 .key_tag(),
2570 59944
2571 );
2572 assert_eq!(
2573 Dnskey::new(
2574 257,
2575 3,
2576 SecAlg::RsaSha256,
2577 base64::decode::<Vec<u8>>(
2578 "AwEAAaz/tAm8yTn4Mfeh5eyI96WSVexTBAvkMgJzkKTO\
2579 iW1vkIbzxeF3+/4RgWOq7HrxRixHlFlExOLAJr5emLvN\
2580 7SWXgnLh4+B5xQlNVz8Og8kvArMtNROxVQuCaSnIDdD5\
2581 LKyWbRd2n9WGe2R8PzgCmr3EgVLrjyBxWezF0jLHwVN8\
2582 efS3rCj/EWgvIWgb9tarpVUDK/b58Da+sqqls3eNbuv7\
2583 pr+eoZG+SrDK6nWeL3c6H5Apxz7LjVc1uTIdsIXxuOLY\
2584 A4/ilBmSVIzuDWfdRUfhHdY6+cn8HFRm+2hM8AnXGXws\
2585 9555KrUB5qihylGa8subX2Nn6UwNR1AkUTV74bU="
2586 )
2587 .unwrap()
2588 )
2589 .unwrap()
2590 .key_tag(),
2591 20326
2592 );
2593 assert_eq!(
2594 Dnskey::new(
2595 257,
2596 3,
2597 SecAlg::RsaMd5,
2598 base64::decode::<Vec<u8>>(
2599 "AwEAAcVaA4jSBIGRrSzpecoJELvKE9+OMuFnL8mmUBsY\
2600 lB6epN1CqX7NzwjDpi6VySiEXr0C4uTYkU/L1uMv2mHE\
2601 AljThFDJ1GuozJ6gA7jf3lnaGppRg2IoVQ9IVmLORmjw\
2602 C+7Eoi12SqybMTicD3Ezwa9XbG1iPjmjhbMrLh7MSQpX"
2603 )
2604 .unwrap()
2605 )
2606 .unwrap()
2607 .key_tag(),
2608 18698
2609 );
2610 }
2611
2612 #[test]
2613 fn dnskey_flags() {
2614 let dnskey =
2615 Dnskey::new(257, 3, SecAlg::RsaSha256, bytes::Bytes::new())
2616 .unwrap();
2617 assert!(dnskey.is_zsk());
2618 assert!(dnskey.is_secure_entry_point());
2619 assert!(!dnskey.is_revoked());
2620 }
2621}