1#[macro_use]
26mod macros;
27opt_types! {
28 algsig::{Dau<Octs>, Dhu<Octs>, N3u<Octs>};
29 chain::{Chain<Name>};
30 cookie::{Cookie};
31 expire::{Expire};
32 exterr::{ExtendedError<Octs>};
33 keepalive::{TcpKeepalive};
34 keytag::{KeyTag<Octs>};
35 nsid::{Nsid<Octs>};
36 padding::{Padding<Octs>};
37 subnet::{ClientSubnet};
38}
39
40use super::cmp::CanonicalOrd;
43use super::header::Header;
44use super::iana::{Class, OptRcode, OptionCode, Rtype};
45use super::name::{Name, ToName};
46use super::rdata::{ComposeRecordData, ParseRecordData, RecordData};
47use super::record::{Record, Ttl};
48use super::wire::{Compose, Composer, FormError, ParseError};
49use super::zonefile_fmt::{self, Formatter, ZonefileFmt};
50use crate::utils::base16;
51use core::cmp::Ordering;
52use core::marker::PhantomData;
53use core::{fmt, hash, mem};
54use octseq::builder::{EmptyBuilder, OctetsBuilder, ShortBuf};
55use octseq::octets::{Octets, OctetsFrom};
56use octseq::parse::Parser;
57
58#[derive(Clone)]
76#[repr(transparent)]
77pub struct Opt<Octs: ?Sized> {
78 octets: Octs,
79}
80
81#[cfg(feature = "serde")]
82impl<O: AsRef<[u8]>> serde::Serialize for Opt<O> {
83 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
84 where
85 S: serde::Serializer,
86 {
87 use serde::ser::SerializeSeq;
88 let mut list = serializer.serialize_seq(None)?;
89
90 for rec in self.for_slice_ref().iter::<AllOptData<_, _>>() {
91 let Ok(rec) = rec else {
92 continue;
93 };
94 list.serialize_element(&rec)?;
95 }
96
97 list.end()
98 }
99}
100
101impl Opt<()> {
102 pub(crate) const RTYPE: Rtype = Rtype::OPT;
104}
105
106impl<Octs: EmptyBuilder> Opt<Octs> {
107 pub fn empty() -> Self {
109 Self {
110 octets: Octs::empty(),
111 }
112 }
113}
114
115impl<Octs: AsRef<[u8]>> Opt<Octs> {
116 pub fn from_octets(octets: Octs) -> Result<Self, ParseError> {
121 Opt::check_slice(octets.as_ref())?;
122 Ok(unsafe { Self::from_octets_unchecked(octets) })
123 }
124
125 unsafe fn from_octets_unchecked(octets: Octs) -> Self {
133 Self { octets }
134 }
135
136 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
138 parser: &mut Parser<'a, Src>,
139 ) -> Result<Self, ParseError> {
140 let len = parser.remaining();
141 Self::from_octets(parser.parse_octets(len)?)
142 }
143}
144
145impl Opt<[u8]> {
146 pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
148 Self::check_slice(slice)?;
149 Ok(unsafe { Self::from_slice_unchecked(slice) })
150 }
151
152 unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
160 mem::transmute(slice)
162 }
163
164 fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
166 if slice.len() > usize::from(u16::MAX) {
167 return Err(FormError::new("long record data").into());
168 }
169 let mut parser = Parser::from_ref(slice);
170 while parser.remaining() > 0 {
171 parser.advance(2)?;
172 let len = parser.parse_u16_be()?;
173 parser.advance(len as usize)?;
174 }
175 Ok(())
176 }
177}
178
179impl<Octs: AsRef<[u8]> + ?Sized> Opt<Octs> {
180 pub fn for_slice_ref(&self) -> Opt<&[u8]> {
181 unsafe { Opt::from_octets_unchecked(self.octets.as_ref()) }
182 }
183}
184
185impl<Octs: AsRef<[u8]> + ?Sized> Opt<Octs> {
186 pub fn len(&self) -> usize {
188 self.octets.as_ref().len()
189 }
190
191 pub fn is_empty(&self) -> bool {
193 self.octets.as_ref().is_empty()
194 }
195
196 pub fn iter<'s, Data>(&'s self) -> OptIter<'s, Octs, Data>
201 where
202 Octs: Octets,
203 Data: ParseOptData<'s, Octs>,
204 {
205 OptIter::new(&self.octets)
206 }
207
208 pub fn first<'s, Data>(&'s self) -> Option<Data>
212 where
213 Octs: Octets,
214 Data: ParseOptData<'s, Octs>,
215 {
216 self.iter::<Data>().next()?.ok()
217 }
218}
219
220impl<Octs: Composer> Opt<Octs> {
221 pub fn push<Opt: ComposeOptData + ?Sized>(
223 &mut self,
224 option: &Opt,
225 ) -> Result<(), BuildDataError> {
226 self.push_raw_option(option.code(), option.compose_len(), |target| {
227 option.compose_option(target)
228 })
229 }
230
231 pub fn push_raw_option<F>(
236 &mut self,
237 code: OptionCode,
238 option_len: u16,
239 op: F,
240 ) -> Result<(), BuildDataError>
241 where
242 F: FnOnce(&mut Octs) -> Result<(), Octs::AppendError>,
243 {
244 LongOptData::check_len(
245 self.octets
246 .as_ref()
247 .len()
248 .saturating_add(usize::from(option_len)),
249 )?;
250
251 code.compose(&mut self.octets)?;
252 option_len.compose(&mut self.octets)?;
253 op(&mut self.octets)?;
254 Ok(())
255 }
256}
257
258impl<Octs, SrcOcts> OctetsFrom<Opt<SrcOcts>> for Opt<Octs>
261where
262 Octs: OctetsFrom<SrcOcts>,
263{
264 type Error = Octs::Error;
265
266 fn try_octets_from(source: Opt<SrcOcts>) -> Result<Self, Self::Error> {
267 Octs::try_octets_from(source.octets).map(|octets| Opt { octets })
268 }
269}
270
271impl<Octs, Other> PartialEq<Opt<Other>> for Opt<Octs>
274where
275 Octs: AsRef<[u8]> + ?Sized,
276 Other: AsRef<[u8]> + ?Sized,
277{
278 fn eq(&self, other: &Opt<Other>) -> bool {
279 self.octets.as_ref().eq(other.octets.as_ref())
280 }
281}
282
283impl<Octs: AsRef<[u8]> + ?Sized> Eq for Opt<Octs> {}
284
285impl<Octs, Other> PartialOrd<Opt<Other>> for Opt<Octs>
288where
289 Octs: AsRef<[u8]> + ?Sized,
290 Other: AsRef<[u8]> + ?Sized,
291{
292 fn partial_cmp(&self, other: &Opt<Other>) -> Option<Ordering> {
293 self.octets.as_ref().partial_cmp(other.octets.as_ref())
294 }
295}
296
297impl<Octs: AsRef<[u8]> + ?Sized> Ord for Opt<Octs> {
298 fn cmp(&self, other: &Self) -> Ordering {
299 self.octets.as_ref().cmp(other.octets.as_ref())
300 }
301}
302
303impl<Octs, Other> CanonicalOrd<Opt<Other>> for Opt<Octs>
304where
305 Octs: AsRef<[u8]> + ?Sized,
306 Other: AsRef<[u8]> + ?Sized,
307{
308 fn canonical_cmp(&self, other: &Opt<Other>) -> Ordering {
309 self.octets.as_ref().cmp(other.octets.as_ref())
310 }
311}
312
313impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for Opt<Octs> {
316 fn hash<H: hash::Hasher>(&self, state: &mut H) {
317 self.octets.as_ref().hash(state)
318 }
319}
320
321impl<Octs: ?Sized> RecordData for Opt<Octs> {
324 fn rtype(&self) -> Rtype {
325 Rtype::OPT
326 }
327}
328
329impl<'a, Octs> ParseRecordData<'a, Octs> for Opt<Octs::Range<'a>>
330where
331 Octs: Octets + ?Sized,
332{
333 fn parse_rdata(
334 rtype: Rtype,
335 parser: &mut Parser<'a, Octs>,
336 ) -> Result<Option<Self>, ParseError> {
337 if rtype == Rtype::OPT {
338 Self::parse(parser).map(Some)
339 } else {
340 Ok(None)
341 }
342 }
343}
344
345impl<Octs: AsRef<[u8]> + ?Sized> ComposeRecordData for Opt<Octs> {
346 fn rdlen(&self, _compress: bool) -> Option<u16> {
347 Some(u16::try_from(self.octets.as_ref().len()).expect("long OPT"))
348 }
349
350 fn compose_rdata<Target: Composer + ?Sized>(
351 &self,
352 target: &mut Target,
353 ) -> Result<(), Target::AppendError> {
354 target.append_slice(self.octets.as_ref())
355 }
356
357 fn compose_canonical_rdata<Target: Composer + ?Sized>(
358 &self,
359 target: &mut Target,
360 ) -> Result<(), Target::AppendError> {
361 self.compose_rdata(target)
362 }
363}
364
365impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Opt<Octs> {
368 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
369 f.write_str("OPT ...")
371 }
372}
373
374impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Opt<Octs> {
375 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
376 f.write_str("Opt(")?;
377 fmt::Display::fmt(self, f)?;
378 f.write_str(")")
379 }
380}
381
382impl<Octs: AsRef<[u8]> + ?Sized> ZonefileFmt for Opt<Octs> {
385 fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
386 p.write_token("OPT ...")
388 }
389}
390
391#[derive(Copy, Clone, Debug, Eq, PartialEq)]
414#[repr(transparent)]
415pub struct OptHeader {
416 inner: [u8; 9],
418}
419
420impl OptHeader {
421 #[must_use]
423 pub fn for_record_slice(slice: &[u8]) -> &OptHeader {
424 assert!(slice.len() >= mem::size_of::<Self>());
425
426 unsafe { &*(slice.as_ptr() as *const OptHeader) }
430 }
431
432 pub fn for_record_slice_mut(slice: &mut [u8]) -> &mut OptHeader {
434 assert!(slice.len() >= mem::size_of::<Self>());
435
436 unsafe { &mut *(slice.as_mut_ptr() as *mut OptHeader) }
440 }
441
442 #[must_use]
450 pub fn udp_payload_size(&self) -> u16 {
451 u16::from_be_bytes(self.inner[3..5].try_into().unwrap())
452 }
453
454 pub fn set_udp_payload_size(&mut self, value: u16) {
456 self.inner[3..5].copy_from_slice(&value.to_be_bytes())
457 }
458
459 #[must_use]
464 pub fn rcode(&self, header: Header) -> OptRcode {
465 OptRcode::from_parts(header.rcode(), self.inner[5])
466 }
467
468 pub fn set_rcode(&mut self, rcode: OptRcode) {
473 self.inner[5] = rcode.ext()
474 }
475
476 #[must_use]
480 pub fn version(&self) -> u8 {
481 self.inner[6]
482 }
483
484 pub fn set_version(&mut self, version: u8) {
486 self.inner[6] = version
487 }
488
489 #[must_use]
498 pub fn dnssec_ok(&self) -> bool {
499 self.inner[7] & 0x80 != 0
500 }
501
502 pub fn set_dnssec_ok(&mut self, value: bool) {
504 if value {
505 self.inner[7] |= 0x80
506 } else {
507 self.inner[7] &= 0x7F
508 }
509 }
510
511 pub fn compose<Target: OctetsBuilder + ?Sized>(
512 self,
513 target: &mut Target,
514 ) -> Result<(), Target::AppendError> {
515 target.append_slice(&self.inner)
516 }
517}
518
519impl Default for OptHeader {
520 fn default() -> Self {
521 OptHeader {
522 inner: [0, 0, 41, 0, 0, 0, 0, 0, 0],
523 }
524 }
525}
526
527#[derive(Clone)]
536pub struct OptRecord<Octs> {
537 udp_payload_size: u16,
539
540 ext_rcode: u8,
542
543 version: u8,
545
546 flags: u16,
548
549 data: Opt<Octs>,
551}
552
553impl<Octs> OptRecord<Octs> {
554 pub fn from_record<N: ToName>(record: Record<N, Opt<Octs>>) -> Self {
556 OptRecord {
557 udp_payload_size: record.class().to_int(),
558 ext_rcode: (record.ttl().as_secs() >> 24) as u8,
559 version: (record.ttl().as_secs() >> 16) as u8,
560 flags: record.ttl().as_secs() as u16,
561 data: record.into_data(),
562 }
563 }
564
565 pub fn as_record(&self) -> Record<&'static Name<[u8]>, Opt<&[u8]>>
567 where
568 Octs: AsRef<[u8]>,
569 {
570 Record::new(
571 Name::root_slice(),
572 Class::from_int(self.udp_payload_size),
573 Ttl::from_secs(
574 (u32::from(self.ext_rcode) << 24)
575 | (u32::from(self.version) << 16)
576 | u32::from(self.flags),
577 ),
578 self.data.for_slice_ref(),
579 )
580 }
581
582 pub fn udp_payload_size(&self) -> u16 {
590 self.udp_payload_size
591 }
592
593 pub fn set_udp_payload_size(&mut self, value: u16) {
595 self.udp_payload_size = value
596 }
597
598 pub fn rcode(&self, header: Header) -> OptRcode {
603 OptRcode::from_parts(header.rcode(), self.ext_rcode)
604 }
605
606 pub fn version(&self) -> u8 {
610 self.version
611 }
612
613 pub fn dnssec_ok(&self) -> bool {
622 self.flags & 0x8000 != 0
623 }
624
625 pub fn set_dnssec_ok(&mut self, value: bool) {
626 if value {
627 self.flags |= 0x8000;
628 } else {
629 self.flags &= !0x8000;
630 }
631 }
632
633 pub fn opt(&self) -> &Opt<Octs> {
635 &self.data
636 }
637}
638
639impl<Octs: Composer> OptRecord<Octs> {
640 pub fn push<Opt: ComposeOptData + ?Sized>(
642 &mut self,
643 option: &Opt,
644 ) -> Result<(), BuildDataError> {
645 self.data.push(option)
646 }
647
648 pub fn push_raw_option<F>(
653 &mut self,
654 code: OptionCode,
655 option_len: u16,
656 op: F,
657 ) -> Result<(), BuildDataError>
658 where
659 F: FnOnce(&mut Octs) -> Result<(), Octs::AppendError>,
660 {
661 self.data.push_raw_option(code, option_len, op)
662 }
663}
664
665impl<Octs: EmptyBuilder> Default for OptRecord<Octs> {
666 fn default() -> Self {
667 Self {
668 udp_payload_size: 0,
669 ext_rcode: 0,
670 version: 0,
671 flags: 0,
672 data: Opt::empty(),
673 }
674 }
675}
676
677impl<Octs, N: ToName> From<Record<N, Opt<Octs>>> for OptRecord<Octs> {
680 fn from(record: Record<N, Opt<Octs>>) -> Self {
681 Self::from_record(record)
682 }
683}
684
685impl<Octs, SrcOcts> OctetsFrom<OptRecord<SrcOcts>> for OptRecord<Octs>
688where
689 Octs: OctetsFrom<SrcOcts>,
690{
691 type Error = Octs::Error;
692
693 fn try_octets_from(
694 source: OptRecord<SrcOcts>,
695 ) -> Result<Self, Self::Error> {
696 Ok(OptRecord {
697 udp_payload_size: source.udp_payload_size,
698 ext_rcode: source.ext_rcode,
699 version: source.version,
700 flags: source.flags,
701 data: Opt::try_octets_from(source.data)?,
702 })
703 }
704}
705
706impl<Octs> AsRef<Opt<Octs>> for OptRecord<Octs> {
709 fn as_ref(&self) -> &Opt<Octs> {
710 &self.data
711 }
712}
713
714impl<Octs: AsRef<[u8]>> fmt::Debug for OptRecord<Octs> {
717 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
718 f.debug_struct("OptRecord")
719 .field("udp_payload_size", &self.udp_payload_size)
720 .field("ext_rcord", &self.ext_rcode)
721 .field("version", &self.version)
722 .field("flags", &self.flags)
723 .field("data", &self.data)
724 .finish()
725 }
726}
727
728#[derive(Clone, Copy, Debug)]
736pub struct OptionHeader {
737 code: u16,
739
740 len: u16,
742}
743
744#[allow(clippy::len_without_is_empty)]
745impl OptionHeader {
746 #[must_use]
748 pub fn new(code: u16, len: u16) -> Self {
749 OptionHeader { code, len }
750 }
751
752 #[must_use]
754 pub fn code(self) -> u16 {
755 self.code
756 }
757
758 #[must_use]
760 pub fn len(self) -> u16 {
761 self.len
762 }
763
764 pub fn parse<Octs: AsRef<[u8]> + ?Sized>(
765 parser: &mut Parser<Octs>,
766 ) -> Result<Self, ParseError> {
767 Ok(OptionHeader::new(
768 parser.parse_u16_be()?,
769 parser.parse_u16_be()?,
770 ))
771 }
772}
773
774#[derive(Clone, Debug)]
784pub struct OptIter<'a, Octs: ?Sized, D> {
785 parser: Parser<'a, Octs>,
787
788 marker: PhantomData<D>,
790}
791
792impl<'a, Octs, D> OptIter<'a, Octs, D>
793where
794 Octs: Octets + ?Sized,
795 D: ParseOptData<'a, Octs>,
796{
797 fn new(octets: &'a Octs) -> Self {
799 OptIter {
800 parser: Parser::from_ref(octets),
801 marker: PhantomData,
802 }
803 }
804
805 fn next_step(&mut self) -> Result<Option<D>, ParseError> {
811 let code = self.parser.parse_u16_be()?.into();
812 let len = self.parser.parse_u16_be()? as usize;
813 let mut parser = self.parser.parse_parser(len)?;
814 let res = D::parse_option(code, &mut parser)?;
815 if res.is_some() && parser.remaining() > 0 {
816 return Err(ParseError::Form(FormError::new(
817 "trailing data in option",
818 )));
819 }
820 Ok(res)
821 }
822}
823
824impl<'a, Octs, Data> Iterator for OptIter<'a, Octs, Data>
825where
826 Octs: Octets + ?Sized,
827 Data: ParseOptData<'a, Octs>,
828{
829 type Item = Result<Data, ParseError>;
830
831 fn next(&mut self) -> Option<Self::Item> {
832 while self.parser.remaining() > 0 {
833 match self.next_step() {
834 Ok(Some(res)) => return Some(Ok(res)),
835 Ok(None) => {}
836 Err(err) => {
837 self.parser.advance_to_end();
839 return Some(Err(err));
840 }
841 }
842 }
843 None
844 }
845}
846
847pub trait OptData {
854 fn code(&self) -> OptionCode;
856}
857
858pub trait ParseOptData<'a, Octs: ?Sized>: OptData + Sized {
862 fn parse_option(
876 code: OptionCode,
877 parser: &mut Parser<'a, Octs>,
878 ) -> Result<Option<Self>, ParseError>;
879}
880
881pub trait ComposeOptData: OptData {
885 fn compose_len(&self) -> u16;
886
887 fn compose_option<Target: OctetsBuilder + ?Sized>(
888 &self,
889 target: &mut Target,
890 ) -> Result<(), Target::AppendError>;
891}
892
893#[derive(Clone)]
899#[cfg_attr(feature = "serde", derive(serde::Serialize))]
900pub struct UnknownOptData<Octs> {
901 code: OptionCode,
903
904 #[cfg_attr(
906 feature = "serde",
907 serde(
908 serialize_with = "crate::utils::base16::serde::serialize",
909 bound(
910 serialize = "Octs: AsRef<[u8]> + octseq::serde::SerializeOctets",
911 )
912 )
913 )]
914 data: Octs,
915}
916
917impl<Octs> UnknownOptData<Octs> {
918 pub fn new(code: OptionCode, data: Octs) -> Result<Self, LongOptData>
922 where
923 Octs: AsRef<[u8]>,
924 {
925 LongOptData::check_len(data.as_ref().len())?;
926 Ok(unsafe { Self::new_unchecked(code, data) })
927 }
928
929 pub unsafe fn new_unchecked(code: OptionCode, data: Octs) -> Self {
936 Self { code, data }
937 }
938
939 pub fn code(&self) -> OptionCode {
941 self.code
942 }
943
944 pub fn data(&self) -> &Octs {
946 &self.data
947 }
948
949 pub fn as_slice(&self) -> &[u8]
951 where
952 Octs: AsRef<[u8]>,
953 {
954 self.data.as_ref()
955 }
956
957 pub fn as_slice_mut(&mut self) -> &mut [u8]
959 where
960 Octs: AsMut<[u8]>,
961 {
962 self.data.as_mut()
963 }
964}
965
966impl<Octs, SrcOcts> OctetsFrom<UnknownOptData<SrcOcts>>
969 for UnknownOptData<Octs>
970where
971 Octs: OctetsFrom<SrcOcts>,
972{
973 type Error = Octs::Error;
974
975 fn try_octets_from(
976 src: UnknownOptData<SrcOcts>,
977 ) -> Result<Self, Self::Error> {
978 Ok(unsafe {
979 Self::new_unchecked(src.code, Octs::try_octets_from(src.data)?)
980 })
981 }
982}
983impl<Octs> AsRef<Octs> for UnknownOptData<Octs> {
986 fn as_ref(&self) -> &Octs {
987 self.data()
988 }
989}
990
991impl<Octs: AsRef<[u8]>> AsRef<[u8]> for UnknownOptData<Octs> {
992 fn as_ref(&self) -> &[u8] {
993 self.as_slice()
994 }
995}
996
997impl<Octs: AsMut<[u8]>> AsMut<[u8]> for UnknownOptData<Octs> {
998 fn as_mut(&mut self) -> &mut [u8] {
999 self.as_slice_mut()
1000 }
1001}
1002
1003impl<Octs: AsRef<[u8]>> OptData for UnknownOptData<Octs> {
1006 fn code(&self) -> OptionCode {
1007 self.code
1008 }
1009}
1010
1011impl<'a, Octs> ParseOptData<'a, Octs> for UnknownOptData<Octs::Range<'a>>
1012where
1013 Octs: Octets + ?Sized,
1014{
1015 fn parse_option(
1016 code: OptionCode,
1017 parser: &mut Parser<'a, Octs>,
1018 ) -> Result<Option<Self>, ParseError> {
1019 Self::new(code, parser.parse_octets(parser.remaining())?)
1020 .map(Some)
1021 .map_err(Into::into)
1022 }
1023}
1024
1025impl<Octs: AsRef<[u8]>> ComposeOptData for UnknownOptData<Octs> {
1026 fn compose_len(&self) -> u16 {
1027 self.data
1028 .as_ref()
1029 .len()
1030 .try_into()
1031 .expect("long option data")
1032 }
1033
1034 fn compose_option<Target: OctetsBuilder + ?Sized>(
1035 &self,
1036 target: &mut Target,
1037 ) -> Result<(), Target::AppendError> {
1038 target.append_slice(self.data.as_ref())
1039 }
1040}
1041
1042impl<Octs: AsRef<[u8]>> fmt::Display for UnknownOptData<Octs> {
1045 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1046 base16::display(self.data.as_ref(), f)
1047 }
1048}
1049
1050impl<Octs: AsRef<[u8]>> fmt::Debug for UnknownOptData<Octs> {
1051 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1052 f.debug_struct("UnknownOptData")
1053 .field("code", &self.code)
1054 .field("data", &format_args!("{}", self))
1055 .finish()
1056 }
1057}
1058
1059#[derive(Clone, Copy, Debug)]
1065pub struct LongOptData(());
1066
1067impl LongOptData {
1068 #[must_use]
1069 pub fn as_str(self) -> &'static str {
1070 "option data too long"
1071 }
1072
1073 pub fn check_len(len: usize) -> Result<(), Self> {
1074 if len > usize::from(u16::MAX) {
1075 Err(Self(()))
1076 } else {
1077 Ok(())
1078 }
1079 }
1080}
1081
1082impl From<LongOptData> for ParseError {
1083 fn from(src: LongOptData) -> Self {
1084 ParseError::form_error(src.as_str())
1085 }
1086}
1087
1088impl fmt::Display for LongOptData {
1089 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1090 f.write_str(self.as_str())
1091 }
1092}
1093
1094#[cfg(feature = "std")]
1095impl std::error::Error for LongOptData {}
1096
1097#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1101pub enum BuildDataError {
1102 LongOptData,
1104
1105 ShortBuf,
1107}
1108
1109impl BuildDataError {
1110 pub fn unlimited_buf(self) -> LongOptData {
1116 match self {
1117 Self::LongOptData => LongOptData(()),
1118 Self::ShortBuf => panic!("ShortBuf on unlimited buffer"),
1119 }
1120 }
1121}
1122
1123impl From<LongOptData> for BuildDataError {
1124 fn from(_: LongOptData) -> Self {
1125 Self::LongOptData
1126 }
1127}
1128
1129impl<T: Into<ShortBuf>> From<T> for BuildDataError {
1130 fn from(_: T) -> Self {
1131 Self::ShortBuf
1132 }
1133}
1134
1135impl fmt::Display for BuildDataError {
1138 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1139 match self {
1140 Self::LongOptData => f.write_str("long option data"),
1141 Self::ShortBuf => ShortBuf.fmt(f),
1142 }
1143 }
1144}
1145
1146#[cfg(feature = "std")]
1147impl std::error::Error for BuildDataError {}
1148
1149#[cfg(test)]
1152#[cfg(all(feature = "std", feature = "bytes"))]
1153pub(super) mod test {
1154 use super::*;
1155 use crate::base::rdata::test::{test_compose_parse, test_rdlen};
1156 use crate::base::record::ParsedRecord;
1157 use crate::base::{opt, MessageBuilder};
1158 use bytes::{Bytes, BytesMut};
1159 use core::fmt::Debug;
1160 use octseq::builder::infallible;
1161 use std::vec::Vec;
1162
1163 #[test]
1164 #[allow(clippy::redundant_closure)] fn opt_compose_parse_scan() {
1166 let rdata = Opt::from_octets("fo\x00\x03foo").unwrap();
1167 test_rdlen(&rdata);
1168 test_compose_parse(&rdata, |parser| Opt::parse(parser));
1169 }
1170
1171 #[test]
1172 fn opt_record_header() {
1173 let mut header = OptHeader::default();
1174 header.set_udp_payload_size(0x1234);
1175 header.set_rcode(OptRcode::BADVERS);
1176 header.set_version(0xbd);
1177 header.set_dnssec_ok(true);
1178 let mut buf = Vec::with_capacity(11);
1179 infallible(header.compose(&mut buf));
1180 infallible(0u16.compose(&mut buf));
1181 let mut buf = Parser::from_ref(buf.as_slice());
1182 let record = ParsedRecord::parse(&mut buf)
1183 .unwrap()
1184 .into_record::<Opt<_>>()
1185 .unwrap()
1186 .unwrap();
1187 let record = OptRecord::from_record(record);
1188 assert_eq!(record.udp_payload_size(), 0x1234);
1189 assert_eq!(record.ext_rcode, OptRcode::BADVERS.ext());
1190 assert_eq!(record.version(), 0xbd);
1191 assert!(record.dnssec_ok());
1192 }
1193
1194 #[test]
1195 fn opt_iter() {
1196 use self::opt::cookie::{ClientCookie, Cookie};
1197
1198 let nsid = opt::Nsid::from_octets(&b"example"[..]).unwrap();
1200 let cookie = Cookie::new(
1201 ClientCookie::from_octets(1234u64.to_be_bytes()),
1202 None,
1203 );
1204 let msg = {
1205 let mut mb = MessageBuilder::new_vec().additional();
1206 mb.opt(|mb| {
1207 mb.push(&nsid)?;
1208 mb.push(&cookie)?;
1209 Ok(())
1210 })
1211 .unwrap();
1212 mb.into_message()
1213 };
1214
1215 let opt = msg.opt().unwrap();
1217 assert_eq!(Some(Ok(nsid)), opt.opt().iter::<opt::Nsid<_>>().next());
1218 assert_eq!(Some(Ok(cookie)), opt.opt().iter::<opt::Cookie>().next());
1219 }
1220
1221 pub fn test_option_compose_parse<In, F, Out>(data: &In, parse: F)
1222 where
1223 In: ComposeOptData + PartialEq<Out> + Debug,
1224 F: FnOnce(&mut Parser<Bytes>) -> Result<Out, ParseError>,
1225 Out: Debug,
1226 {
1227 let mut buf = BytesMut::new();
1228 infallible(data.compose_option(&mut buf));
1229 let buf = buf.freeze();
1230 assert_eq!(buf.len(), usize::from(data.compose_len()));
1231 let mut parser = Parser::from_ref(&buf);
1232 let parsed = (parse)(&mut parser).unwrap();
1233 assert_eq!(parser.remaining(), 0);
1234 assert_eq!(*data, parsed);
1235 }
1236}