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::header::Header;
43use super::iana::{OptRcode, OptionCode, Rtype};
44use super::name::{Dname, ToDname};
45use super::rdata::{ComposeRecordData, ParseRecordData, RecordData};
46use super::record::Record;
47use super::wire::{Composer, FormError, ParseError};
48use crate::utils::base16;
49use core::cmp::Ordering;
50use core::convert::TryInto;
51use core::marker::PhantomData;
52use core::{fmt, hash, mem};
53use octseq::builder::{OctetsBuilder, ShortBuf};
54use octseq::octets::{Octets, OctetsFrom};
55use octseq::parse::Parser;
56
57#[derive(Clone)]
75pub struct Opt<Octs: ?Sized> {
76 octets: Octs,
77}
78
79impl<Octs: AsRef<[u8]>> Opt<Octs> {
80 pub fn from_octets(octets: Octs) -> Result<Self, ParseError> {
85 Opt::check_slice(octets.as_ref())?;
86 Ok(Opt { octets })
87 }
88
89 pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
91 parser: &mut Parser<'a, Src>,
92 ) -> Result<Self, ParseError> {
93 let len = parser.remaining();
94 Self::from_octets(parser.parse_octets(len)?)
95 }
96}
97
98impl Opt<[u8]> {
99 pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
101 Self::check_slice(slice)?;
102 Ok(unsafe { Self::from_slice_unchecked(slice) })
103 }
104
105 unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
113 &*(slice as *const [u8] as *const Self)
114 }
115
116 fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
118 if slice.len() > usize::from(u16::MAX) {
119 return Err(FormError::new("long record data").into());
120 }
121 let mut parser = Parser::from_ref(slice);
122 while parser.remaining() > 0 {
123 parser.advance(2)?;
124 let len = parser.parse_u16_be()?;
125 parser.advance(len as usize)?;
126 }
127 Ok(())
128 }
129}
130
131impl<Octs: AsRef<[u8]> + ?Sized> Opt<Octs> {
132 pub fn len(&self) -> usize {
134 self.octets.as_ref().len()
135 }
136
137 pub fn is_empty(&self) -> bool {
139 self.octets.as_ref().is_empty()
140 }
141
142 pub fn iter<'s, Data>(&'s self) -> OptIter<'s, Octs, Data>
147 where
148 Octs: Octets,
149 Data: ParseOptData<'s, Octs>,
150 {
151 OptIter::new(&self.octets)
152 }
153
154 pub fn first<'s, Data>(&'s self) -> Option<Data>
158 where
159 Octs: Octets,
160 Data: ParseOptData<'s, Octs>,
161 {
162 self.iter::<Data>().next()?.ok()
163 }
164}
165
166impl<Octs, SrcOcts> OctetsFrom<Opt<SrcOcts>> for Opt<Octs>
169where
170 Octs: OctetsFrom<SrcOcts>,
171{
172 type Error = Octs::Error;
173
174 fn try_octets_from(source: Opt<SrcOcts>) -> Result<Self, Self::Error> {
175 Octs::try_octets_from(source.octets).map(|octets| Opt { octets })
176 }
177}
178
179impl<Octs, Other> PartialEq<Opt<Other>> for Opt<Octs>
182where
183 Octs: AsRef<[u8]> + ?Sized,
184 Other: AsRef<[u8]> + ?Sized,
185{
186 fn eq(&self, other: &Opt<Other>) -> bool {
187 self.octets.as_ref().eq(other.octets.as_ref())
188 }
189}
190
191impl<Octs: AsRef<[u8]> + ?Sized> Eq for Opt<Octs> {}
192
193impl<Octs, Other> PartialOrd<Opt<Other>> for Opt<Octs>
196where
197 Octs: AsRef<[u8]> + ?Sized,
198 Other: AsRef<[u8]> + ?Sized,
199{
200 fn partial_cmp(&self, other: &Opt<Other>) -> Option<Ordering> {
201 self.octets.as_ref().partial_cmp(other.octets.as_ref())
202 }
203}
204
205impl<Octs: AsRef<[u8]> + ?Sized> Ord for Opt<Octs> {
206 fn cmp(&self, other: &Self) -> Ordering {
207 self.octets.as_ref().cmp(other.octets.as_ref())
208 }
209}
210
211impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for Opt<Octs> {
214 fn hash<H: hash::Hasher>(&self, state: &mut H) {
215 self.octets.as_ref().hash(state)
216 }
217}
218
219impl<Octs: ?Sized> RecordData for Opt<Octs> {
222 fn rtype(&self) -> Rtype {
223 Rtype::Opt
224 }
225}
226
227impl<'a, Octs> ParseRecordData<'a, Octs> for Opt<Octs::Range<'a>>
228where
229 Octs: Octets + ?Sized,
230{
231 fn parse_rdata(
232 rtype: Rtype,
233 parser: &mut Parser<'a, Octs>,
234 ) -> Result<Option<Self>, ParseError> {
235 if rtype == Rtype::Opt {
236 Self::parse(parser).map(Some)
237 } else {
238 Ok(None)
239 }
240 }
241}
242
243impl<Octs: AsRef<[u8]> + ?Sized> ComposeRecordData for Opt<Octs> {
244 fn rdlen(&self, _compress: bool) -> Option<u16> {
245 Some(u16::try_from(self.octets.as_ref().len()).expect("long OPT"))
246 }
247
248 fn compose_rdata<Target: Composer + ?Sized>(
249 &self,
250 target: &mut Target,
251 ) -> Result<(), Target::AppendError> {
252 target.append_slice(self.octets.as_ref())
253 }
254
255 fn compose_canonical_rdata<Target: Composer + ?Sized>(
256 &self,
257 target: &mut Target,
258 ) -> Result<(), Target::AppendError> {
259 self.compose_rdata(target)
260 }
261}
262
263impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Opt<Octs> {
266 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267 f.write_str("OPT ...")
269 }
270}
271
272impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Opt<Octs> {
273 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
274 f.write_str("Opt(")?;
275 fmt::Display::fmt(self, f)?;
276 f.write_str(")")
277 }
278}
279
280#[derive(Copy, Clone, Debug, Eq, PartialEq)]
301pub struct OptHeader {
302 inner: [u8; 9],
304}
305
306impl OptHeader {
307 #[must_use]
309 pub fn for_record_slice(slice: &[u8]) -> &OptHeader {
310 assert!(slice.len() >= mem::size_of::<Self>());
311 unsafe { &*(slice.as_ptr() as *const OptHeader) }
312 }
313
314 pub fn for_record_slice_mut(slice: &mut [u8]) -> &mut OptHeader {
316 assert!(slice.len() >= mem::size_of::<Self>());
317 unsafe { &mut *(slice.as_mut_ptr() as *mut OptHeader) }
318 }
319
320 #[must_use]
328 pub fn udp_payload_size(&self) -> u16 {
329 u16::from_be_bytes(self.inner[3..5].try_into().unwrap())
330 }
331
332 pub fn set_udp_payload_size(&mut self, value: u16) {
334 self.inner[3..5].copy_from_slice(&value.to_be_bytes())
335 }
336
337 #[must_use]
342 pub fn rcode(&self, header: Header) -> OptRcode {
343 OptRcode::from_parts(header.rcode(), self.inner[5])
344 }
345
346 pub fn set_rcode(&mut self, rcode: OptRcode) {
351 self.inner[5] = rcode.ext()
352 }
353
354 #[must_use]
358 pub fn version(&self) -> u8 {
359 self.inner[6]
360 }
361
362 pub fn set_version(&mut self, version: u8) {
364 self.inner[6] = version
365 }
366
367 #[must_use]
376 pub fn dnssec_ok(&self) -> bool {
377 self.inner[7] & 0x80 != 0
378 }
379
380 pub fn set_dnssec_ok(&mut self, value: bool) {
382 if value {
383 self.inner[7] |= 0x80
384 } else {
385 self.inner[7] &= 0x7F
386 }
387 }
388
389 pub fn compose<Target: OctetsBuilder + ?Sized>(
390 self,
391 target: &mut Target,
392 ) -> Result<(), Target::AppendError> {
393 target.append_slice(&self.inner)
394 }
395}
396
397impl Default for OptHeader {
398 fn default() -> Self {
399 OptHeader {
400 inner: [0, 0, 41, 0, 0, 0, 0, 0, 0],
401 }
402 }
403}
404
405#[derive(Clone)]
414pub struct OptRecord<Octs> {
415 udp_payload_size: u16,
417
418 ext_rcode: u8,
420
421 version: u8,
423
424 flags: u16,
426
427 data: Opt<Octs>,
429}
430
431impl<Octs> OptRecord<Octs> {
432 pub fn from_record<N: ToDname>(record: Record<N, Opt<Octs>>) -> Self {
434 OptRecord {
435 udp_payload_size: record.class().to_int(),
436 ext_rcode: (record.ttl().as_secs() >> 24) as u8,
437 version: (record.ttl().as_secs() >> 16) as u8,
438 flags: record.ttl().as_secs() as u16,
439 data: record.into_data(),
440 }
441 }
442
443 pub fn udp_payload_size(&self) -> u16 {
451 self.udp_payload_size
452 }
453
454 pub fn rcode(&self, header: Header) -> OptRcode {
459 OptRcode::from_parts(header.rcode(), self.ext_rcode)
460 }
461
462 pub fn version(&self) -> u8 {
466 self.version
467 }
468
469 pub fn dnssec_ok(&self) -> bool {
478 self.flags & 0x8000 != 0
479 }
480
481 pub fn opt(&self) -> &Opt<Octs> {
483 &self.data
484 }
485}
486
487impl<Octs, N: ToDname> From<Record<N, Opt<Octs>>> for OptRecord<Octs> {
490 fn from(record: Record<N, Opt<Octs>>) -> Self {
491 Self::from_record(record)
492 }
493}
494
495impl<Octs, SrcOcts> OctetsFrom<OptRecord<SrcOcts>> for OptRecord<Octs>
498where
499 Octs: OctetsFrom<SrcOcts>,
500{
501 type Error = Octs::Error;
502
503 fn try_octets_from(
504 source: OptRecord<SrcOcts>,
505 ) -> Result<Self, Self::Error> {
506 Ok(OptRecord {
507 udp_payload_size: source.udp_payload_size,
508 ext_rcode: source.ext_rcode,
509 version: source.version,
510 flags: source.flags,
511 data: Opt::try_octets_from(source.data)?,
512 })
513 }
514}
515
516impl<Octs> AsRef<Opt<Octs>> for OptRecord<Octs> {
519 fn as_ref(&self) -> &Opt<Octs> {
520 &self.data
521 }
522}
523
524#[derive(Clone, Copy, Debug)]
532pub struct OptionHeader {
533 code: u16,
535
536 len: u16,
538}
539
540#[allow(clippy::len_without_is_empty)]
541impl OptionHeader {
542 #[must_use]
544 pub fn new(code: u16, len: u16) -> Self {
545 OptionHeader { code, len }
546 }
547
548 #[must_use]
550 pub fn code(self) -> u16 {
551 self.code
552 }
553
554 #[must_use]
556 pub fn len(self) -> u16 {
557 self.len
558 }
559
560 pub fn parse<Octs: AsRef<[u8]> + ?Sized>(
561 parser: &mut Parser<Octs>,
562 ) -> Result<Self, ParseError> {
563 Ok(OptionHeader::new(
564 parser.parse_u16_be()?,
565 parser.parse_u16_be()?,
566 ))
567 }
568}
569
570#[derive(Clone, Debug)]
580pub struct OptIter<'a, Octs: ?Sized, D> {
581 parser: Parser<'a, Octs>,
583
584 marker: PhantomData<D>,
586}
587
588impl<'a, Octs, D> OptIter<'a, Octs, D>
589where
590 Octs: Octets + ?Sized,
591 D: ParseOptData<'a, Octs>,
592{
593 fn new(octets: &'a Octs) -> Self {
595 OptIter {
596 parser: Parser::from_ref(octets),
597 marker: PhantomData,
598 }
599 }
600
601 fn next_step(&mut self) -> Result<Option<D>, ParseError> {
607 let code = self.parser.parse_u16_be()?.into();
608 let len = self.parser.parse_u16_be()? as usize;
609 let mut parser = self.parser.parse_parser(len)?;
610 let res = D::parse_option(code, &mut parser)?;
611 if res.is_some() && parser.remaining() > 0 {
612 return Err(ParseError::Form(FormError::new(
613 "trailing data in option",
614 )));
615 }
616 Ok(res)
617 }
618}
619
620impl<'a, Octs, Data> Iterator for OptIter<'a, Octs, Data>
621where
622 Octs: Octets + ?Sized,
623 Data: ParseOptData<'a, Octs>,
624{
625 type Item = Result<Data, ParseError>;
626
627 fn next(&mut self) -> Option<Self::Item> {
628 while self.parser.remaining() > 0 {
629 match self.next_step() {
630 Ok(Some(res)) => return Some(Ok(res)),
631 Ok(None) => {}
632 Err(err) => {
633 self.parser.advance_to_end();
635 return Some(Err(err));
636 }
637 }
638 }
639 None
640 }
641}
642
643pub trait OptData {
650 fn code(&self) -> OptionCode;
652}
653
654pub trait ParseOptData<'a, Octs: ?Sized>: OptData + Sized {
658 fn parse_option(
672 code: OptionCode,
673 parser: &mut Parser<'a, Octs>,
674 ) -> Result<Option<Self>, ParseError>;
675}
676
677pub trait ComposeOptData: OptData {
681 fn compose_len(&self) -> u16;
682
683 fn compose_option<Target: OctetsBuilder + ?Sized>(
684 &self,
685 target: &mut Target,
686 ) -> Result<(), Target::AppendError>;
687}
688
689#[derive(Clone, Debug)]
695pub struct UnknownOptData<Octs> {
696 code: OptionCode,
698
699 data: Octs,
701}
702
703impl<Octs> UnknownOptData<Octs> {
704 pub fn new(code: OptionCode, data: Octs) -> Result<Self, LongOptData>
708 where
709 Octs: AsRef<[u8]>,
710 {
711 LongOptData::check_len(data.as_ref().len())?;
712 Ok(unsafe { Self::new_unchecked(code, data) })
713 }
714
715 pub unsafe fn new_unchecked(code: OptionCode, data: Octs) -> Self {
722 Self { code, data }
723 }
724
725 pub fn code(&self) -> OptionCode {
727 self.code
728 }
729
730 pub fn data(&self) -> &Octs {
732 &self.data
733 }
734
735 pub fn as_slice(&self) -> &[u8]
737 where
738 Octs: AsRef<[u8]>,
739 {
740 self.data.as_ref()
741 }
742
743 pub fn as_slice_mut(&mut self) -> &mut [u8]
745 where
746 Octs: AsMut<[u8]>,
747 {
748 self.data.as_mut()
749 }
750}
751
752impl<Octs> AsRef<Octs> for UnknownOptData<Octs> {
755 fn as_ref(&self) -> &Octs {
756 self.data()
757 }
758}
759
760impl<Octs: AsRef<[u8]>> AsRef<[u8]> for UnknownOptData<Octs> {
761 fn as_ref(&self) -> &[u8] {
762 self.as_slice()
763 }
764}
765
766impl<Octs: AsMut<[u8]>> AsMut<[u8]> for UnknownOptData<Octs> {
767 fn as_mut(&mut self) -> &mut [u8] {
768 self.as_slice_mut()
769 }
770}
771
772impl<Octs: AsRef<[u8]>> OptData for UnknownOptData<Octs> {
775 fn code(&self) -> OptionCode {
776 self.code
777 }
778}
779
780impl<'a, Octs> ParseOptData<'a, Octs> for UnknownOptData<Octs::Range<'a>>
781where
782 Octs: Octets + ?Sized,
783{
784 fn parse_option(
785 code: OptionCode,
786 parser: &mut Parser<'a, Octs>,
787 ) -> Result<Option<Self>, ParseError> {
788 Self::new(code, parser.parse_octets(parser.remaining())?)
789 .map(Some)
790 .map_err(Into::into)
791 }
792}
793
794impl<Octs: AsRef<[u8]>> ComposeOptData for UnknownOptData<Octs> {
795 fn compose_len(&self) -> u16 {
796 self.data
797 .as_ref()
798 .len()
799 .try_into()
800 .expect("long option data")
801 }
802
803 fn compose_option<Target: OctetsBuilder + ?Sized>(
804 &self,
805 target: &mut Target,
806 ) -> Result<(), Target::AppendError> {
807 target.append_slice(self.data.as_ref())
808 }
809}
810
811impl<Octs: AsRef<[u8]>> fmt::Display for UnknownOptData<Octs> {
814 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
815 base16::display(self.data.as_ref(), f)
816 }
817}
818
819#[derive(Clone, Copy, Debug)]
825pub struct LongOptData(());
826
827impl LongOptData {
828 #[must_use]
829 pub fn as_str(self) -> &'static str {
830 "option data too long"
831 }
832
833 pub fn check_len(len: usize) -> Result<(), Self> {
834 if len > usize::from(u16::MAX) {
835 Err(Self(()))
836 } else {
837 Ok(())
838 }
839 }
840}
841
842impl From<LongOptData> for ParseError {
843 fn from(src: LongOptData) -> Self {
844 ParseError::form_error(src.as_str())
845 }
846}
847
848impl fmt::Display for LongOptData {
849 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
850 f.write_str(self.as_str())
851 }
852}
853
854#[cfg(feature = "std")]
855impl std::error::Error for LongOptData {}
856
857#[derive(Clone, Copy, Debug, Eq, PartialEq)]
861pub enum BuildDataError {
862 LongOptData,
864
865 ShortBuf,
867}
868
869impl From<LongOptData> for BuildDataError {
870 fn from(_: LongOptData) -> Self {
871 Self::LongOptData
872 }
873}
874
875impl<T: Into<ShortBuf>> From<T> for BuildDataError {
876 fn from(_: T) -> Self {
877 Self::ShortBuf
878 }
879}
880
881impl fmt::Display for BuildDataError {
884 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
885 match self {
886 Self::LongOptData => f.write_str("long option data"),
887 Self::ShortBuf => ShortBuf.fmt(f),
888 }
889 }
890}
891
892#[cfg(feature = "std")]
893impl std::error::Error for BuildDataError {}
894
895#[cfg(test)]
898#[cfg(all(feature = "std", feature = "bytes"))]
899pub(super) mod test {
900 use super::*;
901 use crate::base::rdata::test::{test_compose_parse, test_rdlen};
902 use crate::base::record::ParsedRecord;
903 use crate::base::wire::Compose;
904 use crate::base::{opt, MessageBuilder};
905 use bytes::{Bytes, BytesMut};
906 use core::fmt::Debug;
907 use octseq::builder::infallible;
908 use std::vec::Vec;
909
910 #[test]
911 #[allow(clippy::redundant_closure)] fn opt_compose_parse_scan() {
913 let rdata = Opt::from_octets("fo\x00\x03foo").unwrap();
914 test_rdlen(&rdata);
915 test_compose_parse(&rdata, |parser| Opt::parse(parser));
916 }
917
918 #[test]
919 fn opt_record_header() {
920 let mut header = OptHeader::default();
921 header.set_udp_payload_size(0x1234);
922 header.set_rcode(OptRcode::BadVers);
923 header.set_version(0xbd);
924 header.set_dnssec_ok(true);
925 let mut buf = Vec::with_capacity(11);
926 infallible(header.compose(&mut buf));
927 infallible(0u16.compose(&mut buf));
928 let mut buf = Parser::from_ref(buf.as_slice());
929 let record = ParsedRecord::parse(&mut buf)
930 .unwrap()
931 .into_record::<Opt<_>>()
932 .unwrap()
933 .unwrap();
934 let record = OptRecord::from_record(record);
935 assert_eq!(record.udp_payload_size(), 0x1234);
936 assert_eq!(record.ext_rcode, OptRcode::BadVers.ext());
937 assert_eq!(record.version(), 0xbd);
938 assert!(record.dnssec_ok());
939 }
940
941 #[test]
942 fn opt_iter() {
943 use self::opt::cookie::{ClientCookie, Cookie};
944
945 let nsid = opt::Nsid::from_octets(&b"example"[..]).unwrap();
947 let cookie = Cookie::new(
948 ClientCookie::from_octets(1234u64.to_be_bytes()),
949 None,
950 );
951 let msg = {
952 let mut mb = MessageBuilder::new_vec().additional();
953 mb.opt(|mb| {
954 mb.push(&nsid)?;
955 mb.push(&cookie)?;
956 Ok(())
957 })
958 .unwrap();
959 mb.into_message()
960 };
961
962 let opt = msg.opt().unwrap();
964 assert_eq!(Some(Ok(nsid)), opt.opt().iter::<opt::Nsid<_>>().next());
965 assert_eq!(Some(Ok(cookie)), opt.opt().iter::<opt::Cookie>().next());
966 }
967
968 pub fn test_option_compose_parse<In, F, Out>(data: &In, parse: F)
969 where
970 In: ComposeOptData + PartialEq<Out> + Debug,
971 F: FnOnce(&mut Parser<Bytes>) -> Result<Out, ParseError>,
972 Out: Debug,
973 {
974 let mut buf = BytesMut::new();
975 infallible(data.compose_option(&mut buf));
976 let buf = buf.freeze();
977 assert_eq!(buf.len(), usize::from(data.compose_len()));
978 let mut parser = Parser::from_ref(&buf);
979 let parsed = (parse)(&mut parser).unwrap();
980 assert_eq!(parser.remaining(), 0);
981 assert_eq!(*data, parsed);
982 }
983}