1use super::dnssec::RtypeBitmap;
8use crate::base::cmp::CanonicalOrd;
9use crate::base::iana::{Nsec3HashAlg, Rtype};
10use crate::base::rdata::{ComposeRecordData, ParseRecordData, RecordData};
11use crate::base::scan::{
12 ConvertSymbols, EntrySymbol, Scan, Scanner, ScannerError,
13};
14use crate::base::wire::{Compose, Composer, Parse, ParseError};
15use crate::utils::{base16, base32};
16#[cfg(feature = "bytes")]
17use bytes::Bytes;
18use core::cmp::Ordering;
19use core::{fmt, hash, str};
20use octseq::builder::{
21 EmptyBuilder, FreezeBuilder, FromBuilder, OctetsBuilder,
22};
23use octseq::octets::{Octets, OctetsFrom, OctetsInto};
24use octseq::parse::Parser;
25#[cfg(feature = "serde")]
26use octseq::serde::{DeserializeOctets, SerializeOctets};
27
28#[derive(Clone)]
31#[cfg_attr(
32 feature = "serde",
33 derive(serde::Serialize, serde::Deserialize),
34 serde(bound(
35 serialize = "
36 Octs: octseq::serde::SerializeOctets + AsRef<[u8]>,
37 ",
38 deserialize = "
39 Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
40 <Octs as FromBuilder>::Builder:
41 EmptyBuilder + octseq::builder::Truncate
42 + AsRef<[u8]> + AsMut<[u8]>,
43 ",
44 ))
45)]
46pub struct Nsec3<Octs> {
47 hash_algorithm: Nsec3HashAlg,
48 flags: u8,
49 iterations: u16,
50 salt: Nsec3Salt<Octs>,
51 next_owner: OwnerHash<Octs>,
52 types: RtypeBitmap<Octs>,
53}
54
55impl<Octs> Nsec3<Octs> {
56 pub fn new(
57 hash_algorithm: Nsec3HashAlg,
58 flags: u8,
59 iterations: u16,
60 salt: Nsec3Salt<Octs>,
61 next_owner: OwnerHash<Octs>,
62 types: RtypeBitmap<Octs>,
63 ) -> Self {
64 Nsec3 {
65 hash_algorithm,
66 flags,
67 iterations,
68 salt,
69 next_owner,
70 types,
71 }
72 }
73
74 pub fn hash_algorithm(&self) -> Nsec3HashAlg {
75 self.hash_algorithm
76 }
77
78 pub fn flags(&self) -> u8 {
79 self.flags
80 }
81
82 pub fn opt_out(&self) -> bool {
83 self.flags & 0x01 != 0
84 }
85
86 pub fn iterations(&self) -> u16 {
87 self.iterations
88 }
89
90 pub fn salt(&self) -> &Nsec3Salt<Octs> {
91 &self.salt
92 }
93
94 pub fn next_owner(&self) -> &OwnerHash<Octs> {
95 &self.next_owner
96 }
97
98 pub fn types(&self) -> &RtypeBitmap<Octs> {
99 &self.types
100 }
101
102 pub(super) fn convert_octets<Target>(
103 self,
104 ) -> Result<Nsec3<Target>, Target::Error>
105 where
106 Target: OctetsFrom<Octs>,
107 {
108 Ok(Nsec3::new(
109 self.hash_algorithm,
110 self.flags,
111 self.iterations,
112 self.salt.try_octets_into()?,
113 self.next_owner.try_octets_into()?,
114 self.types.try_octets_into()?,
115 ))
116 }
117
118 pub(super) fn flatten<Target: OctetsFrom<Octs>>(
119 self,
120 ) -> Result<Nsec3<Target>, Target::Error> {
121 self.convert_octets()
122 }
123
124 pub fn scan<S: Scanner<Octets = Octs>>(
125 scanner: &mut S,
126 ) -> Result<Self, S::Error> {
127 Ok(Self::new(
128 Nsec3HashAlg::scan(scanner)?,
129 u8::scan(scanner)?,
130 u16::scan(scanner)?,
131 Nsec3Salt::scan(scanner)?,
132 OwnerHash::scan(scanner)?,
133 RtypeBitmap::scan(scanner)?,
134 ))
135 }
136}
137
138impl<Octs: AsRef<[u8]>> Nsec3<Octs> {
139 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
140 parser: &mut Parser<'a, Src>,
141 ) -> Result<Self, ParseError> {
142 let hash_algorithm = Nsec3HashAlg::parse(parser)?;
143 let flags = u8::parse(parser)?;
144 let iterations = u16::parse(parser)?;
145 let salt = Nsec3Salt::parse(parser)?;
146 let next_owner = OwnerHash::parse(parser)?;
147 let types = RtypeBitmap::parse(parser)?;
148 Ok(Self::new(
149 hash_algorithm,
150 flags,
151 iterations,
152 salt,
153 next_owner,
154 types,
155 ))
156 }
157}
158
159impl<Octs, SrcOcts> OctetsFrom<Nsec3<SrcOcts>> for Nsec3<Octs>
162where
163 Octs: OctetsFrom<SrcOcts>,
164{
165 type Error = Octs::Error;
166
167 fn try_octets_from(source: Nsec3<SrcOcts>) -> Result<Self, Self::Error> {
168 Ok(Nsec3::new(
169 source.hash_algorithm,
170 source.flags,
171 source.iterations,
172 Nsec3Salt::try_octets_from(source.salt)?,
173 OwnerHash::try_octets_from(source.next_owner)?,
174 RtypeBitmap::try_octets_from(source.types)?,
175 ))
176 }
177}
178
179impl<Octs, Other> PartialEq<Nsec3<Other>> for Nsec3<Octs>
182where
183 Octs: AsRef<[u8]>,
184 Other: AsRef<[u8]>,
185{
186 fn eq(&self, other: &Nsec3<Other>) -> bool {
187 self.hash_algorithm == other.hash_algorithm
188 && self.flags == other.flags
189 && self.iterations == other.iterations
190 && self.salt == other.salt
191 && self.next_owner == other.next_owner
192 && self.types == other.types
193 }
194}
195
196impl<Octs: AsRef<[u8]>> Eq for Nsec3<Octs> {}
197
198impl<Octs, Other> PartialOrd<Nsec3<Other>> for Nsec3<Octs>
201where
202 Octs: AsRef<[u8]>,
203 Other: AsRef<[u8]>,
204{
205 fn partial_cmp(&self, other: &Nsec3<Other>) -> Option<Ordering> {
206 match self.hash_algorithm.partial_cmp(&other.hash_algorithm) {
207 Some(Ordering::Equal) => {}
208 other => return other,
209 }
210 match self.flags.partial_cmp(&other.flags) {
211 Some(Ordering::Equal) => {}
212 other => return other,
213 }
214 match self.iterations.partial_cmp(&other.iterations) {
215 Some(Ordering::Equal) => {}
216 other => return other,
217 }
218 match self.salt.partial_cmp(&other.salt) {
219 Some(Ordering::Equal) => {}
220 other => return other,
221 }
222 match self.next_owner.partial_cmp(&other.next_owner) {
223 Some(Ordering::Equal) => {}
224 other => return other,
225 }
226 self.types.partial_cmp(&other.types)
227 }
228}
229
230impl<Octs, Other> CanonicalOrd<Nsec3<Other>> for Nsec3<Octs>
231where
232 Octs: AsRef<[u8]>,
233 Other: AsRef<[u8]>,
234{
235 fn canonical_cmp(&self, other: &Nsec3<Other>) -> Ordering {
236 match self.hash_algorithm.cmp(&other.hash_algorithm) {
237 Ordering::Equal => {}
238 other => return other,
239 }
240 match self.flags.cmp(&other.flags) {
241 Ordering::Equal => {}
242 other => return other,
243 }
244 match self.iterations.cmp(&other.iterations) {
245 Ordering::Equal => {}
246 other => return other,
247 }
248 match self.salt.canonical_cmp(&other.salt) {
249 Ordering::Equal => {}
250 other => return other,
251 }
252 match self.next_owner.canonical_cmp(&other.next_owner) {
253 Ordering::Equal => {}
254 other => return other,
255 }
256 self.types.canonical_cmp(&other.types)
257 }
258}
259
260impl<Octs: AsRef<[u8]>> Ord for Nsec3<Octs> {
261 fn cmp(&self, other: &Self) -> Ordering {
262 self.canonical_cmp(other)
263 }
264}
265
266impl<Octs: AsRef<[u8]>> hash::Hash for Nsec3<Octs> {
269 fn hash<H: hash::Hasher>(&self, state: &mut H) {
270 self.hash_algorithm.hash(state);
271 self.flags.hash(state);
272 self.iterations.hash(state);
273 self.salt.hash(state);
274 self.next_owner.hash(state);
275 self.types.hash(state);
276 }
277}
278
279impl<Octs> RecordData for Nsec3<Octs> {
282 fn rtype(&self) -> Rtype {
283 Rtype::Nsec3
284 }
285}
286
287impl<'a, Octs> ParseRecordData<'a, Octs> for Nsec3<Octs::Range<'a>>
288where
289 Octs: Octets + ?Sized,
290{
291 fn parse_rdata(
292 rtype: Rtype,
293 parser: &mut Parser<'a, Octs>,
294 ) -> Result<Option<Self>, ParseError> {
295 if rtype == Rtype::Nsec3 {
296 Self::parse(parser).map(Some)
297 } else {
298 Ok(None)
299 }
300 }
301}
302
303impl<Octs: AsRef<[u8]>> ComposeRecordData for Nsec3<Octs> {
304 fn rdlen(&self, _compress: bool) -> Option<u16> {
305 Some(
306 u16::checked_add(
307 Nsec3HashAlg::COMPOSE_LEN
308 + u8::COMPOSE_LEN
309 + u16::COMPOSE_LEN,
310 self.salt.compose_len(),
311 )
312 .expect("long NSEC3")
313 .checked_add(self.next_owner.compose_len())
314 .expect("long NSEC3")
315 .checked_add(self.types.compose_len())
316 .expect("long NSEC3"),
317 )
318 }
319
320 fn compose_rdata<Target: Composer + ?Sized>(
321 &self,
322 target: &mut Target,
323 ) -> Result<(), Target::AppendError> {
324 self.hash_algorithm.compose(target)?;
325 self.flags.compose(target)?;
326 self.iterations.compose(target)?;
327 self.salt.compose(target)?;
328 self.next_owner.compose(target)?;
329 self.types.compose(target)
330 }
331
332 fn compose_canonical_rdata<Target: Composer + ?Sized>(
333 &self,
334 target: &mut Target,
335 ) -> Result<(), Target::AppendError> {
336 self.compose_rdata(target)
337 }
338}
339
340impl<Octs: AsRef<[u8]>> fmt::Display for Nsec3<Octs> {
343 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
344 write!(
345 f,
346 "{} {} {} {} ",
347 self.hash_algorithm, self.flags, self.iterations, self.salt
348 )?;
349 base32::display_hex(&self.next_owner, f)?;
350 write!(f, " {}", self.types)
351 }
352}
353
354impl<Octs: AsRef<[u8]>> fmt::Debug for Nsec3<Octs> {
355 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
356 f.debug_struct("Nsec3")
357 .field("hash_algorithm", &self.hash_algorithm)
358 .field("flags", &self.flags)
359 .field("iterations", &self.iterations)
360 .field("salt", &self.salt)
361 .field("next_owner", &self.next_owner)
362 .field("types", &self.types)
363 .finish()
364 }
365}
366
367#[derive(Clone)]
370#[cfg_attr(
371 feature = "serde",
372 derive(serde::Serialize, serde::Deserialize),
373 serde(bound(
374 serialize = "
375 Octs: octseq::serde::SerializeOctets + AsRef<[u8]>,
376 ",
377 deserialize = "
378 Octs: FromBuilder + octseq::serde::DeserializeOctets<'de>,
379 <Octs as FromBuilder>::Builder: OctetsBuilder + EmptyBuilder,
380 ",
381 ))
382)]
383pub struct Nsec3param<Octs> {
384 hash_algorithm: Nsec3HashAlg,
385 flags: u8,
386 iterations: u16,
387 salt: Nsec3Salt<Octs>,
388}
389
390impl<Octs> Nsec3param<Octs> {
391 pub fn new(
392 hash_algorithm: Nsec3HashAlg,
393 flags: u8,
394 iterations: u16,
395 salt: Nsec3Salt<Octs>,
396 ) -> Self {
397 Nsec3param {
398 hash_algorithm,
399 flags,
400 iterations,
401 salt,
402 }
403 }
404
405 pub fn hash_algorithm(&self) -> Nsec3HashAlg {
406 self.hash_algorithm
407 }
408
409 pub fn flags(&self) -> u8 {
410 self.flags
411 }
412
413 pub fn iterations(&self) -> u16 {
414 self.iterations
415 }
416
417 pub fn salt(&self) -> &Nsec3Salt<Octs> {
418 &self.salt
419 }
420
421 pub(super) fn convert_octets<Target>(
422 self,
423 ) -> Result<Nsec3param<Target>, Target::Error>
424 where
425 Target: OctetsFrom<Octs>,
426 {
427 Ok(Nsec3param::new(
428 self.hash_algorithm,
429 self.flags,
430 self.iterations,
431 self.salt.try_octets_into()?,
432 ))
433 }
434
435 pub(super) fn flatten<Target: OctetsFrom<Octs>>(
436 self,
437 ) -> Result<Nsec3param<Target>, Target::Error> {
438 self.convert_octets()
439 }
440
441 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
442 parser: &mut Parser<'a, Src>,
443 ) -> Result<Self, ParseError> {
444 Ok(Self::new(
445 Nsec3HashAlg::parse(parser)?,
446 u8::parse(parser)?,
447 u16::parse(parser)?,
448 Nsec3Salt::parse(parser)?,
449 ))
450 }
451
452 pub fn scan<S: Scanner<Octets = Octs>>(
453 scanner: &mut S,
454 ) -> Result<Self, S::Error> {
455 Ok(Self::new(
456 Nsec3HashAlg::scan(scanner)?,
457 u8::scan(scanner)?,
458 u16::scan(scanner)?,
459 Nsec3Salt::scan(scanner)?,
460 ))
461 }
462}
463
464impl<Octs, SrcOcts> OctetsFrom<Nsec3param<SrcOcts>> for Nsec3param<Octs>
467where
468 Octs: OctetsFrom<SrcOcts>,
469{
470 type Error = Octs::Error;
471
472 fn try_octets_from(
473 source: Nsec3param<SrcOcts>,
474 ) -> Result<Self, Self::Error> {
475 Ok(Nsec3param::new(
476 source.hash_algorithm,
477 source.flags,
478 source.iterations,
479 Nsec3Salt::try_octets_from(source.salt)?,
480 ))
481 }
482}
483
484impl<Octs, Other> PartialEq<Nsec3param<Other>> for Nsec3param<Octs>
487where
488 Octs: AsRef<[u8]>,
489 Other: AsRef<[u8]>,
490{
491 fn eq(&self, other: &Nsec3param<Other>) -> bool {
492 self.hash_algorithm == other.hash_algorithm
493 && self.flags == other.flags
494 && self.iterations == other.iterations
495 && self.salt == other.salt
496 }
497}
498
499impl<Octs: AsRef<[u8]>> Eq for Nsec3param<Octs> {}
500
501impl<Octs, Other> PartialOrd<Nsec3param<Other>> for Nsec3param<Octs>
504where
505 Octs: AsRef<[u8]>,
506 Other: AsRef<[u8]>,
507{
508 fn partial_cmp(&self, other: &Nsec3param<Other>) -> Option<Ordering> {
509 match self.hash_algorithm.partial_cmp(&other.hash_algorithm) {
510 Some(Ordering::Equal) => {}
511 other => return other,
512 }
513 match self.flags.partial_cmp(&other.flags) {
514 Some(Ordering::Equal) => {}
515 other => return other,
516 }
517 match self.iterations.partial_cmp(&other.iterations) {
518 Some(Ordering::Equal) => {}
519 other => return other,
520 }
521 self.salt.partial_cmp(&other.salt)
522 }
523}
524
525impl<Octs, Other> CanonicalOrd<Nsec3param<Other>> for Nsec3param<Octs>
526where
527 Octs: AsRef<[u8]>,
528 Other: AsRef<[u8]>,
529{
530 fn canonical_cmp(&self, other: &Nsec3param<Other>) -> Ordering {
531 match self.hash_algorithm.cmp(&other.hash_algorithm) {
532 Ordering::Equal => {}
533 other => return other,
534 }
535 match self.flags.cmp(&other.flags) {
536 Ordering::Equal => {}
537 other => return other,
538 }
539 match self.iterations.cmp(&other.iterations) {
540 Ordering::Equal => {}
541 other => return other,
542 }
543 self.salt.canonical_cmp(&other.salt)
544 }
545}
546
547impl<Octs: AsRef<[u8]>> Ord for Nsec3param<Octs> {
548 fn cmp(&self, other: &Self) -> Ordering {
549 match self.hash_algorithm.cmp(&other.hash_algorithm) {
550 Ordering::Equal => {}
551 other => return other,
552 }
553 match self.flags.cmp(&other.flags) {
554 Ordering::Equal => {}
555 other => return other,
556 }
557 match self.iterations.cmp(&other.iterations) {
558 Ordering::Equal => {}
559 other => return other,
560 }
561 self.salt.cmp(&other.salt)
562 }
563}
564
565impl<Octs: AsRef<[u8]>> hash::Hash for Nsec3param<Octs> {
568 fn hash<H: hash::Hasher>(&self, state: &mut H) {
569 self.hash_algorithm.hash(state);
570 self.flags.hash(state);
571 self.iterations.hash(state);
572 self.salt.hash(state);
573 }
574}
575
576impl<Octs> RecordData for Nsec3param<Octs> {
579 fn rtype(&self) -> Rtype {
580 Rtype::Nsec3param
581 }
582}
583
584impl<'a, Octs> ParseRecordData<'a, Octs> for Nsec3param<Octs::Range<'a>>
585where
586 Octs: Octets + ?Sized,
587{
588 fn parse_rdata(
589 rtype: Rtype,
590 parser: &mut Parser<'a, Octs>,
591 ) -> Result<Option<Self>, ParseError> {
592 if rtype == Rtype::Nsec3param {
593 Self::parse(parser).map(Some)
594 } else {
595 Ok(None)
596 }
597 }
598}
599
600impl<Octs: AsRef<[u8]>> ComposeRecordData for Nsec3param<Octs> {
601 fn rdlen(&self, _compress: bool) -> Option<u16> {
602 Some(
603 u16::checked_add(
604 Nsec3HashAlg::COMPOSE_LEN
605 + u8::COMPOSE_LEN
606 + u16::COMPOSE_LEN,
607 self.salt.compose_len(),
608 )
609 .expect("long NSEC3"),
610 )
611 }
612
613 fn compose_rdata<Target: Composer + ?Sized>(
614 &self,
615 target: &mut Target,
616 ) -> Result<(), Target::AppendError> {
617 self.hash_algorithm.compose(target)?;
618 self.flags.compose(target)?;
619 self.iterations.compose(target)?;
620 self.salt.compose(target)
621 }
622
623 fn compose_canonical_rdata<Target: Composer + ?Sized>(
624 &self,
625 target: &mut Target,
626 ) -> Result<(), Target::AppendError> {
627 self.compose_rdata(target)
628 }
629}
630
631impl<Octs: AsRef<[u8]>> fmt::Display for Nsec3param<Octs> {
634 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
635 write!(
636 f,
637 "{} {} {} {}",
638 self.hash_algorithm, self.flags, self.iterations, self.salt
639 )
640 }
641}
642
643impl<Octs: AsRef<[u8]>> fmt::Debug for Nsec3param<Octs> {
644 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
645 f.debug_struct("Nsec3param")
646 .field("hash_algorithm", &self.hash_algorithm)
647 .field("flags", &self.flags)
648 .field("iterations", &self.iterations)
649 .field("salt", &self.salt)
650 .finish()
651 }
652}
653
654#[derive(Clone)]
664pub struct Nsec3Salt<Octs: ?Sized>(Octs);
665
666impl Nsec3Salt<()> {
667 pub const MAX_LEN: usize = 255;
670}
671
672impl<Octs: ?Sized> Nsec3Salt<Octs> {
673 #[must_use]
675 pub fn empty() -> Self
676 where
677 Octs: From<&'static [u8]>,
678 {
679 Self(b"".as_ref().into())
680 }
681
682 pub fn from_octets(octets: Octs) -> Result<Self, Nsec3SaltError>
687 where
688 Octs: AsRef<[u8]> + Sized,
689 {
690 if octets.as_ref().len() > Nsec3Salt::MAX_LEN {
691 Err(Nsec3SaltError)
692 } else {
693 Ok(unsafe { Self::from_octets_unchecked(octets) })
694 }
695 }
696
697 unsafe fn from_octets_unchecked(octets: Octs) -> Self
701 where
702 Octs: Sized,
703 {
704 Self(octets)
705 }
706
707 pub fn into_octets(self) -> Octs
709 where
710 Octs: Sized,
711 {
712 self.0
713 }
714
715 pub fn as_slice(&self) -> &[u8]
717 where
718 Octs: AsRef<[u8]>,
719 {
720 self.0.as_ref()
721 }
722
723 fn salt_len(&self) -> u8
724 where
725 Octs: AsRef<[u8]>,
726 {
727 self.0.as_ref().len().try_into().expect("long salt")
728 }
729
730 fn compose_len(&self) -> u16
731 where
732 Octs: AsRef<[u8]>,
733 {
734 u16::from(self.salt_len()) + 1
735 }
736
737 fn compose<Target: Composer + ?Sized>(
738 &self,
739 target: &mut Target,
740 ) -> Result<(), Target::AppendError>
741 where
742 Octs: AsRef<[u8]>,
743 {
744 self.salt_len().compose(target)?;
745 target.append_slice(self.0.as_ref())
746 }
747}
748
749#[cfg(feature = "bytes")]
750#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))]
751impl Nsec3Salt<Bytes> {
752 pub fn from_bytes(bytes: Bytes) -> Result<Self, Nsec3SaltError> {
754 Self::from_octets(bytes)
755 }
756}
757
758impl Nsec3Salt<[u8]> {
759 pub fn from_slice(slice: &[u8]) -> Result<&Self, Nsec3SaltError> {
761 if slice.len() > Nsec3Salt::MAX_LEN {
762 Err(Nsec3SaltError)
763 } else {
764 Ok(unsafe { &*(slice as *const [u8] as *const Nsec3Salt<[u8]>) })
765 }
766 }
767}
768
769impl<Octs> Nsec3Salt<Octs> {
770 pub fn scan<S: Scanner<Octets = Octs>>(
771 scanner: &mut S,
772 ) -> Result<Self, S::Error> {
773 #[derive(Default)]
774 struct Converter(Option<Option<base16::SymbolConverter>>);
775
776 impl<Sym, Error> ConvertSymbols<Sym, Error> for Converter
777 where
778 Sym: Into<EntrySymbol>,
779 Error: ScannerError,
780 {
781 fn process_symbol(
782 &mut self,
783 symbol: Sym,
784 ) -> Result<Option<&[u8]>, Error> {
785 let symbol = symbol.into();
786 if self.0.is_none() {
789 match symbol {
790 EntrySymbol::Symbol(symbol)
791 if symbol.into_char() == Ok('-') =>
792 {
793 self.0 = Some(None);
794 return Ok(None);
795 }
796 _ => {
797 self.0 =
798 Some(Some(base16::SymbolConverter::new()));
799 }
800 }
801 }
802
803 match self.0.as_mut() {
804 None => unreachable!(),
805 Some(None) => Err(Error::custom("illegal NSEC3 salt")),
806 Some(Some(ref mut base16)) => {
807 base16.process_symbol(symbol)
808 }
809 }
810 }
811
812 fn process_tail(&mut self) -> Result<Option<&[u8]>, Error> {
813 if let Some(Some(ref mut base16)) = self.0 {
814 <base16::SymbolConverter
815 as ConvertSymbols<Sym, Error>
816 >::process_tail(base16)
817 } else {
818 Ok(None)
819 }
820 }
821 }
822
823 scanner
824 .convert_token(Converter::default())
825 .map(|res| unsafe { Self::from_octets_unchecked(res) })
826 }
827
828 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
829 parser: &mut Parser<'a, Src>,
830 ) -> Result<Self, ParseError> {
831 let len = parser.parse_u8()? as usize;
832 parser
833 .parse_octets(len)
834 .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
835 .map_err(Into::into)
836 }
837}
838
839impl<Octs, SrcOcts> OctetsFrom<Nsec3Salt<SrcOcts>> for Nsec3Salt<Octs>
842where
843 Octs: OctetsFrom<SrcOcts>,
844{
845 type Error = Octs::Error;
846
847 fn try_octets_from(
848 source: Nsec3Salt<SrcOcts>,
849 ) -> Result<Self, Self::Error> {
850 Octs::try_octets_from(source.0)
851 .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
852 }
853}
854
855impl<Octs> str::FromStr for Nsec3Salt<Octs>
856where
857 Octs: FromBuilder,
858 <Octs as FromBuilder>::Builder: EmptyBuilder,
859{
860 type Err = base16::DecodeError;
861
862 fn from_str(s: &str) -> Result<Self, Self::Err> {
863 if s == "-" {
864 Ok(unsafe {
865 Self::from_octets_unchecked(Octs::Builder::empty().freeze())
866 })
867 } else {
868 base16::decode(s)
869 .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
870 }
871 }
872}
873
874impl<Octs: AsRef<U> + ?Sized, U: ?Sized> AsRef<U> for Nsec3Salt<Octs> {
877 fn as_ref(&self) -> &U {
878 self.0.as_ref()
879 }
880}
881
882impl<T, U> PartialEq<U> for Nsec3Salt<T>
885where
886 T: AsRef<[u8]> + ?Sized,
887 U: AsRef<[u8]> + ?Sized,
888{
889 fn eq(&self, other: &U) -> bool {
890 self.as_slice().eq(other.as_ref())
891 }
892}
893
894impl<T: AsRef<[u8]> + ?Sized> Eq for Nsec3Salt<T> {}
895
896impl<T, U> PartialOrd<U> for Nsec3Salt<T>
899where
900 T: AsRef<[u8]> + ?Sized,
901 U: AsRef<[u8]> + ?Sized,
902{
903 fn partial_cmp(&self, other: &U) -> Option<Ordering> {
904 self.0.as_ref().partial_cmp(other.as_ref())
905 }
906}
907
908impl<T: AsRef<[u8]> + ?Sized> Ord for Nsec3Salt<T> {
909 fn cmp(&self, other: &Self) -> Ordering {
910 self.0.as_ref().cmp(other.as_ref())
911 }
912}
913
914impl<T, U> CanonicalOrd<Nsec3Salt<U>> for Nsec3Salt<T>
915where
916 T: AsRef<[u8]> + ?Sized,
917 U: AsRef<[u8]> + ?Sized,
918{
919 fn canonical_cmp(&self, other: &Nsec3Salt<U>) -> Ordering {
920 match self.0.as_ref().len().cmp(&other.0.as_ref().len()) {
921 Ordering::Equal => {}
922 other => return other,
923 }
924 self.as_slice().cmp(other.as_slice())
925 }
926}
927
928impl<T: AsRef<[u8]> + ?Sized> hash::Hash for Nsec3Salt<T> {
931 fn hash<H: hash::Hasher>(&self, state: &mut H) {
932 self.0.as_ref().hash(state)
933 }
934}
935
936impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Nsec3Salt<Octs> {
939 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
940 base16::display(self.as_slice(), f)
941 }
942}
943
944impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Nsec3Salt<Octs> {
945 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
946 f.debug_tuple("Nsec3Salt")
947 .field(&format_args!("{}", self))
948 .finish()
949 }
950}
951
952#[cfg(feature = "serde")]
955impl<T: AsRef<[u8]> + SerializeOctets> serde::Serialize for Nsec3Salt<T> {
956 fn serialize<S: serde::Serializer>(
957 &self,
958 serializer: S,
959 ) -> Result<S::Ok, S::Error> {
960 if serializer.is_human_readable() {
961 serializer.serialize_newtype_struct(
962 "Nsec3Salt",
963 &format_args!("{}", self),
964 )
965 } else {
966 serializer.serialize_newtype_struct(
967 "Nsec3Salt",
968 &self.0.as_serialized_octets(),
969 )
970 }
971 }
972}
973
974#[cfg(feature = "serde")]
975impl<'de, Octs> serde::Deserialize<'de> for Nsec3Salt<Octs>
976where
977 Octs: FromBuilder + DeserializeOctets<'de>,
978 <Octs as FromBuilder>::Builder: OctetsBuilder + EmptyBuilder,
979{
980 fn deserialize<D: serde::Deserializer<'de>>(
981 deserializer: D,
982 ) -> Result<Self, D::Error> {
983 use core::marker::PhantomData;
984 use core::str::FromStr;
985
986 struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
987
988 impl<'de, Octs> serde::de::Visitor<'de> for InnerVisitor<'de, Octs>
989 where
990 Octs: FromBuilder + DeserializeOctets<'de>,
991 <Octs as FromBuilder>::Builder: OctetsBuilder + EmptyBuilder,
992 {
993 type Value = Nsec3Salt<Octs>;
994
995 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
996 f.write_str("an NSEC3 salt value")
997 }
998
999 fn visit_str<E: serde::de::Error>(
1000 self,
1001 v: &str,
1002 ) -> Result<Self::Value, E> {
1003 Nsec3Salt::from_str(v).map_err(E::custom)
1004 }
1005
1006 fn visit_borrowed_bytes<E: serde::de::Error>(
1007 self,
1008 value: &'de [u8],
1009 ) -> Result<Self::Value, E> {
1010 self.0.visit_borrowed_bytes(value).and_then(|octets| {
1011 Nsec3Salt::from_octets(octets).map_err(E::custom)
1012 })
1013 }
1014
1015 #[cfg(feature = "std")]
1016 fn visit_byte_buf<E: serde::de::Error>(
1017 self,
1018 value: std::vec::Vec<u8>,
1019 ) -> Result<Self::Value, E> {
1020 self.0.visit_byte_buf(value).and_then(|octets| {
1021 Nsec3Salt::from_octets(octets).map_err(E::custom)
1022 })
1023 }
1024 }
1025
1026 struct NewtypeVisitor<T>(PhantomData<T>);
1027
1028 impl<'de, Octs> serde::de::Visitor<'de> for NewtypeVisitor<Octs>
1029 where
1030 Octs: FromBuilder + DeserializeOctets<'de>,
1031 <Octs as FromBuilder>::Builder: OctetsBuilder + EmptyBuilder,
1032 {
1033 type Value = Nsec3Salt<Octs>;
1034
1035 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
1036 f.write_str("an NSEC3 salt value")
1037 }
1038
1039 fn visit_newtype_struct<D: serde::Deserializer<'de>>(
1040 self,
1041 deserializer: D,
1042 ) -> Result<Self::Value, D::Error> {
1043 if deserializer.is_human_readable() {
1044 deserializer
1045 .deserialize_str(InnerVisitor(Octs::visitor()))
1046 } else {
1047 Octs::deserialize_with_visitor(
1048 deserializer,
1049 InnerVisitor(Octs::visitor()),
1050 )
1051 }
1052 }
1053 }
1054
1055 deserializer.deserialize_newtype_struct(
1056 "Nsec3Salt",
1057 NewtypeVisitor(PhantomData),
1058 )
1059 }
1060}
1061
1062#[derive(Clone)]
1074pub struct OwnerHash<Octs: ?Sized>(Octs);
1075
1076impl OwnerHash<()> {
1077 pub const MAX_LEN: usize = 255;
1080}
1081
1082impl<Octs> OwnerHash<Octs> {
1083 pub fn from_octets(octets: Octs) -> Result<Self, OwnerHashError>
1088 where
1089 Octs: AsRef<[u8]>,
1090 {
1091 if octets.as_ref().len() > OwnerHash::MAX_LEN {
1092 Err(OwnerHashError)
1093 } else {
1094 Ok(unsafe { Self::from_octets_unchecked(octets) })
1095 }
1096 }
1097
1098 unsafe fn from_octets_unchecked(octets: Octs) -> Self {
1102 Self(octets)
1103 }
1104
1105 pub fn scan<S: Scanner<Octets = Octs>>(
1106 scanner: &mut S,
1107 ) -> Result<Self, S::Error> {
1108 scanner
1109 .convert_token(base32::SymbolConverter::new())
1110 .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
1111 }
1112
1113 pub fn into_octets(self) -> Octs
1115 where
1116 Octs: Sized,
1117 {
1118 self.0
1119 }
1120}
1121
1122impl<Octs: ?Sized> OwnerHash<Octs> {
1123 pub fn as_slice(&self) -> &[u8]
1125 where
1126 Octs: AsRef<[u8]>,
1127 {
1128 self.0.as_ref()
1129 }
1130
1131 fn hash_len(&self) -> u8
1132 where
1133 Octs: AsRef<[u8]>,
1134 {
1135 self.0.as_ref().len().try_into().expect("long hash")
1136 }
1137
1138 fn compose_len(&self) -> u16
1139 where
1140 Octs: AsRef<[u8]>,
1141 {
1142 u16::from(self.hash_len()) + 1
1143 }
1144
1145 fn compose<Target: Composer + ?Sized>(
1146 &self,
1147 target: &mut Target,
1148 ) -> Result<(), Target::AppendError>
1149 where
1150 Octs: AsRef<[u8]>,
1151 {
1152 self.hash_len().compose(target)?;
1153 target.append_slice(self.0.as_ref())
1154 }
1155}
1156
1157#[cfg(feature = "bytes")]
1158#[cfg_attr(docsrs, doc(cfg(feature = "bytes")))]
1159impl OwnerHash<Bytes> {
1160 pub fn from_bytes(bytes: Bytes) -> Result<Self, OwnerHashError> {
1162 Self::from_octets(bytes)
1163 }
1164}
1165
1166impl OwnerHash<[u8]> {
1167 pub fn from_slice(slice: &[u8]) -> Result<&Self, OwnerHashError> {
1169 if slice.len() > OwnerHash::MAX_LEN {
1170 Err(OwnerHashError)
1171 } else {
1172 Ok(unsafe { &*(slice as *const [u8] as *const OwnerHash<[u8]>) })
1173 }
1174 }
1175}
1176
1177impl<Octs> OwnerHash<Octs> {
1178 fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
1179 parser: &mut Parser<'a, Src>,
1180 ) -> Result<Self, ParseError> {
1181 let len = parser.parse_u8()? as usize;
1182 parser
1183 .parse_octets(len)
1184 .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
1185 .map_err(Into::into)
1186 }
1187}
1188
1189impl<Octs, SrcOcts> OctetsFrom<OwnerHash<SrcOcts>> for OwnerHash<Octs>
1192where
1193 Octs: OctetsFrom<SrcOcts>,
1194{
1195 type Error = Octs::Error;
1196
1197 fn try_octets_from(
1198 source: OwnerHash<SrcOcts>,
1199 ) -> Result<Self, Self::Error> {
1200 Octs::try_octets_from(source.0)
1201 .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
1202 }
1203}
1204
1205impl<Octs> str::FromStr for OwnerHash<Octs>
1206where
1207 Octs: FromBuilder,
1208 <Octs as FromBuilder>::Builder: OctetsBuilder + EmptyBuilder,
1209{
1210 type Err = base32::DecodeError;
1211
1212 fn from_str(s: &str) -> Result<Self, Self::Err> {
1213 base32::decode_hex(s)
1214 .map(|octets| unsafe { Self::from_octets_unchecked(octets) })
1215 }
1216}
1217
1218impl<Octs: AsRef<U> + ?Sized, U: ?Sized> AsRef<U> for OwnerHash<Octs> {
1221 fn as_ref(&self) -> &U {
1222 self.0.as_ref()
1223 }
1224}
1225
1226impl<T, U> PartialEq<U> for OwnerHash<T>
1229where
1230 T: AsRef<[u8]> + ?Sized,
1231 U: AsRef<[u8]> + ?Sized,
1232{
1233 fn eq(&self, other: &U) -> bool {
1234 self.as_slice().eq(other.as_ref())
1235 }
1236}
1237
1238impl<T: AsRef<[u8]> + ?Sized> Eq for OwnerHash<T> {}
1239
1240impl<T, U> PartialOrd<U> for OwnerHash<T>
1243where
1244 T: AsRef<[u8]> + ?Sized,
1245 U: AsRef<[u8]> + ?Sized,
1246{
1247 fn partial_cmp(&self, other: &U) -> Option<Ordering> {
1248 self.0.as_ref().partial_cmp(other.as_ref())
1249 }
1250}
1251
1252impl<T: AsRef<[u8]> + ?Sized> Ord for OwnerHash<T> {
1253 fn cmp(&self, other: &Self) -> Ordering {
1254 self.0.as_ref().cmp(other.as_ref())
1255 }
1256}
1257
1258impl<T, U> CanonicalOrd<OwnerHash<U>> for OwnerHash<T>
1259where
1260 T: AsRef<[u8]> + ?Sized,
1261 U: AsRef<[u8]> + ?Sized,
1262{
1263 fn canonical_cmp(&self, other: &OwnerHash<U>) -> Ordering {
1264 match self.0.as_ref().len().cmp(&other.0.as_ref().len()) {
1265 Ordering::Equal => {}
1266 other => return other,
1267 }
1268 self.as_slice().cmp(other.as_slice())
1269 }
1270}
1271
1272impl<T: AsRef<[u8]> + ?Sized> hash::Hash for OwnerHash<T> {
1275 fn hash<H: hash::Hasher>(&self, state: &mut H) {
1276 self.0.as_ref().hash(state)
1277 }
1278}
1279
1280impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for OwnerHash<Octs> {
1283 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1284 base32::display_hex(self.as_slice(), f)
1285 }
1286}
1287
1288impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for OwnerHash<Octs> {
1289 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1290 f.debug_tuple("OwnerHash")
1291 .field(&format_args!("{}", self))
1292 .finish()
1293 }
1294}
1295
1296#[cfg(feature = "serde")]
1299impl<T: AsRef<[u8]> + SerializeOctets> serde::Serialize for OwnerHash<T> {
1300 fn serialize<S: serde::Serializer>(
1301 &self,
1302 serializer: S,
1303 ) -> Result<S::Ok, S::Error> {
1304 if serializer.is_human_readable() {
1305 serializer.serialize_newtype_struct(
1306 "OwnerHash",
1307 &format_args!("{}", self),
1308 )
1309 } else {
1310 serializer.serialize_newtype_struct(
1311 "OwnerHash",
1312 &self.0.as_serialized_octets(),
1313 )
1314 }
1315 }
1316}
1317
1318#[cfg(feature = "serde")]
1319impl<'de, Octs> serde::Deserialize<'de> for OwnerHash<Octs>
1320where
1321 Octs: FromBuilder + DeserializeOctets<'de>,
1322 <Octs as FromBuilder>::Builder: OctetsBuilder + EmptyBuilder,
1323{
1324 fn deserialize<D: serde::Deserializer<'de>>(
1325 deserializer: D,
1326 ) -> Result<Self, D::Error> {
1327 use core::marker::PhantomData;
1328 use core::str::FromStr;
1329
1330 struct InnerVisitor<'de, T: DeserializeOctets<'de>>(T::Visitor);
1331
1332 impl<'de, Octs> serde::de::Visitor<'de> for InnerVisitor<'de, Octs>
1333 where
1334 Octs: FromBuilder + DeserializeOctets<'de>,
1335 <Octs as FromBuilder>::Builder: OctetsBuilder + EmptyBuilder,
1336 {
1337 type Value = OwnerHash<Octs>;
1338
1339 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
1340 f.write_str("an owner name hash value")
1341 }
1342
1343 fn visit_str<E: serde::de::Error>(
1344 self,
1345 v: &str,
1346 ) -> Result<Self::Value, E> {
1347 OwnerHash::from_str(v).map_err(E::custom)
1348 }
1349
1350 fn visit_borrowed_bytes<E: serde::de::Error>(
1351 self,
1352 value: &'de [u8],
1353 ) -> Result<Self::Value, E> {
1354 self.0.visit_borrowed_bytes(value).and_then(|octets| {
1355 OwnerHash::from_octets(octets).map_err(E::custom)
1356 })
1357 }
1358
1359 #[cfg(feature = "std")]
1360 fn visit_byte_buf<E: serde::de::Error>(
1361 self,
1362 value: std::vec::Vec<u8>,
1363 ) -> Result<Self::Value, E> {
1364 self.0.visit_byte_buf(value).and_then(|octets| {
1365 OwnerHash::from_octets(octets).map_err(E::custom)
1366 })
1367 }
1368 }
1369
1370 struct NewtypeVisitor<T>(PhantomData<T>);
1371
1372 impl<'de, Octs> serde::de::Visitor<'de> for NewtypeVisitor<Octs>
1373 where
1374 Octs: FromBuilder + DeserializeOctets<'de>,
1375 <Octs as FromBuilder>::Builder: OctetsBuilder + EmptyBuilder,
1376 {
1377 type Value = OwnerHash<Octs>;
1378
1379 fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
1380 f.write_str("an owner name hash value")
1381 }
1382
1383 fn visit_newtype_struct<D: serde::Deserializer<'de>>(
1384 self,
1385 deserializer: D,
1386 ) -> Result<Self::Value, D::Error> {
1387 if deserializer.is_human_readable() {
1388 deserializer
1389 .deserialize_str(InnerVisitor(Octs::visitor()))
1390 } else {
1391 Octs::deserialize_with_visitor(
1392 deserializer,
1393 InnerVisitor(Octs::visitor()),
1394 )
1395 }
1396 }
1397 }
1398
1399 deserializer.deserialize_newtype_struct(
1400 "OwnerHash",
1401 NewtypeVisitor(PhantomData),
1402 )
1403 }
1404}
1405
1406#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1414pub struct Nsec3SaltError;
1415
1416impl fmt::Display for Nsec3SaltError {
1417 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1418 f.write_str("illegal NSEC3 salt")
1419 }
1420}
1421
1422#[cfg(feature = "std")]
1423impl std::error::Error for Nsec3SaltError {}
1424
1425#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1431pub struct OwnerHashError;
1432
1433impl fmt::Display for OwnerHashError {
1434 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1435 f.write_str("illegal owner name hash")
1436 }
1437}
1438
1439#[cfg(feature = "std")]
1440impl std::error::Error for OwnerHashError {}
1441
1442#[cfg(test)]
1445#[cfg(all(feature = "std", feature = "bytes"))]
1446mod test {
1447 use super::super::dnssec::RtypeBitmapBuilder;
1448 use super::*;
1449 use crate::base::rdata::test::{
1450 test_compose_parse, test_rdlen, test_scan,
1451 };
1452 use std::vec::Vec;
1453
1454 #[test]
1455 #[allow(clippy::redundant_closure)] fn nsec3_compose_parse_scan() {
1457 let mut rtype = RtypeBitmapBuilder::new_vec();
1458 rtype.add(Rtype::A).unwrap();
1459 rtype.add(Rtype::Srv).unwrap();
1460 let rdata = Nsec3::new(
1461 Nsec3HashAlg::Sha1,
1462 10,
1463 11,
1464 Nsec3Salt::from_octets(Vec::from("bar")).unwrap(),
1465 OwnerHash::from_octets(Vec::from("foo")).unwrap(),
1466 rtype.finalize(),
1467 );
1468 test_rdlen(&rdata);
1469 test_compose_parse(&rdata, |parser| Nsec3::parse(parser));
1470 test_scan(
1471 &["1", "10", "11", "626172", "CPNMU", "A", "SRV"],
1472 Nsec3::scan,
1473 &rdata,
1474 );
1475 }
1476
1477 #[test]
1478 #[allow(clippy::redundant_closure)] fn nsec3param_compose_parse_scan() {
1480 let rdata = Nsec3param::new(
1481 Nsec3HashAlg::Sha1,
1482 10,
1483 11,
1484 Nsec3Salt::from_octets(Vec::from("bar")).unwrap(),
1485 );
1486 test_rdlen(&rdata);
1487 test_compose_parse(&rdata, |parser| Nsec3param::parse(parser));
1488 test_scan(&["1", "10", "11", "626172"], Nsec3param::scan, &rdata);
1489 }
1490}