domain/base/opt/
mod.rs

1// XXX TODO: Easier access to individual options.
2// XXX TODO: Documentation and tests.
3//
4//! Record data for OPT records.
5//!
6//! Since DNS message headers are relatively short, the amount of information
7//! that can be conveyed through them is very limited. In order to provide an
8//! extensible means to transmit additional information, [RFC 6891] introduces
9//! a resource record called OPT that can be added to the additional section
10//! of a message. The record data in turn consists of a sequence of options.
11//!
12//! This module contains the types for working with both the OPT record and
13//! its record data. It defines types for each of the currently defined
14//! options. As with record data types in the [rdata] module, these are
15//! arranged in sub-modules according to the RFC that defined them and then
16//! re-exported here.
17//!
18//! [RFC 6891]: https://tools.ietf.org/html/rfc6891
19//! [rdata]: ../../rdata/index.html
20
21//============ Sub-modules and Re-exports ====================================
22//
23// All of these are in a macro. The macro also defines `AllOptData`.
24
25#[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
40//============ Module Content ================================================
41
42use 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//------------ Opt -----------------------------------------------------------
59
60/// OPT record data.
61///
62/// This is the record data type for OPT records and can be used as the data
63/// type parameter in [`Record`]. It simply wraps an octets sequence with all
64/// the record data. It guarantees that the data contains a correctly
65/// formatted sequence of options but doesn’t guarantee that the options
66/// themselves are correct. You can iterate over options via the [`iter`]
67/// method.
68///
69/// Since some of the information of the OPT record is transmitted in the
70/// record header, a special type [`OptRecord`] exists, that contains all
71/// the OPT data which is the preferred way of accessing this data.
72///
73/// [`iter`]: #method.iter
74/// [`OptRecord`]: struct.OptRecord.html
75#[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    /// The rtype of this record data type.
103    pub(crate) const RTYPE: Rtype = Rtype::OPT;
104}
105
106impl<Octs: EmptyBuilder> Opt<Octs> {
107    /// Creates empty OPT record data.
108    pub fn empty() -> Self {
109        Self {
110            octets: Octs::empty(),
111        }
112    }
113}
114
115impl<Octs: AsRef<[u8]>> Opt<Octs> {
116    /// Creates OPT record data from an octets sequence.
117    ///
118    /// The function checks whether the octets contain a sequence of
119    /// options. It does not check whether the options themselves are valid.
120    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    /// Creates OPT record data from octets without checking.
126    ///
127    /// # Safety
128    ///
129    /// The caller needs to ensure that the slice contains correctly encoded
130    /// OPT record data. The data of the options themselves does not need to
131    /// be correct.
132    unsafe fn from_octets_unchecked(octets: Octs) -> Self {
133        Self { octets }
134    }
135
136    /// Parses OPT record data from the beginning of a parser.
137    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    /// Creates OPT record data from an octets slice.
147    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    /// Creates OPT record data from an octets slice without checking.
153    ///
154    /// # Safety
155    ///
156    /// The caller needs to ensure that the slice contains correctly encoded
157    /// OPT record data. The data of the options themselves does not need to
158    /// be correct.
159    unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
160        // SAFETY: Opt has repr(transparent)
161        mem::transmute(slice)
162    }
163
164    /// Checks that the slice contains acceptable OPT record data.
165    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    /// Returns the length of the OPT record data.
187    pub fn len(&self) -> usize {
188        self.octets.as_ref().len()
189    }
190
191    /// Returns whether the OPT record data is empty.
192    pub fn is_empty(&self) -> bool {
193        self.octets.as_ref().is_empty()
194    }
195
196    /// Returns an iterator over options of a given type.
197    ///
198    /// The returned iterator will return only options represented by type
199    /// `D` and quietly skip over all the others.
200    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    /// Returns the first option of a given type if present.
209    ///
210    /// If trying to parse this first option fails, returns `None` as well.
211    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    /// Appends a new option to the OPT data.
222    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    /// Appends a raw option to the OPT data.
232    ///
233    /// The method will append an option with the given option code. The data
234    /// of the option will be written via the closure `op`.
235    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
258//--- OctetsFrom
259
260impl<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
271//--- PartialEq and Eq
272
273impl<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
285//--- PartialOrd, Ord, and CanonicalOrd
286
287impl<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
313//--- Hash
314
315impl<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
321//--- RecordData, ParseRecordData, and ComposeRecordData
322
323impl<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
365//--- Display
366
367impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Opt<Octs> {
368    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
369        // XXX TODO Print this properly.
370        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
382//--- ZonefileFmt
383
384impl<Octs: AsRef<[u8]> + ?Sized> ZonefileFmt for Opt<Octs> {
385    fn fmt(&self, p: &mut impl Formatter) -> zonefile_fmt::Result {
386        // XXX TODO Print this properly.
387        p.write_token("OPT ...")
388    }
389}
390
391//------------ OptHeader -----------------------------------------------------
392
393/// The header of an OPT record.
394///
395/// The OPT record reappropriates the record header for encoding some
396/// basic information. This type provides access to this information. It
397/// consists of the record header with the exception of the final `rdlen`
398/// field.
399///
400/// This is so that [`OptBuilder`] can safely deref to this type.
401///
402/// [`OptBuilder`]: crate::base::message_builder::OptBuilder
403//    +------------+--------------+------------------------------+
404//    | Field Name | Field Type   | Description                  |
405//    +------------+--------------+------------------------------+
406//    | NAME       | domain name  | MUST be 0 (root domain)      |
407//    | TYPE       | u_int16_t    | OPT (41)                     |
408//    | CLASS      | u_int16_t    | requestor's UDP payload size |
409//    | TTL        | u_int32_t    | extended RCODE and flags     |
410//    | RDLEN      | u_int16_t    | length of all RDATA          |
411//    | RDATA      | octet stream | {attribute,value} pairs      |
412//    +------------+--------------+------------------------------+
413#[derive(Copy, Clone, Debug, Eq, PartialEq)]
414#[repr(transparent)]
415pub struct OptHeader {
416    /// The bytes of the header.
417    inner: [u8; 9],
418}
419
420impl OptHeader {
421    /// Returns a reference to an OPT header pointing into a record’s octets.
422    #[must_use]
423    pub fn for_record_slice(slice: &[u8]) -> &OptHeader {
424        assert!(slice.len() >= mem::size_of::<Self>());
425
426        // SAFETY: the pointer cast is sound because
427        //   - OptHeader has repr(transparent) and
428        //   - the size of the slice is large enough
429        unsafe { &*(slice.as_ptr() as *const OptHeader) }
430    }
431
432    /// Returns a mutable reference pointing into a record’s octets.
433    pub fn for_record_slice_mut(slice: &mut [u8]) -> &mut OptHeader {
434        assert!(slice.len() >= mem::size_of::<Self>());
435
436        // SAFETY: the pointer cast is sound because
437        //   - OptHeader has repr(transparent) and
438        //   - the size of the slice is large enough
439        unsafe { &mut *(slice.as_mut_ptr() as *mut OptHeader) }
440    }
441
442    /// Returns the UDP payload size.
443    ///
444    /// Through this field a sender of a message can signal the maximum size
445    /// of UDP payload the sender is able to handle when receiving messages.
446    /// This value refers to the abilities of the sender’s DNS implementation,
447    /// not such things as network MTUs. Which means that the largest UDP
448    /// payload that can actually be sent back to the sender may be smaller.
449    #[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    /// Sets the UDP payload size value.
455    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    /// Returns the extended rcode.
460    ///
461    /// Some of the bits of the rcode are stored in the regular message
462    /// header. Such a header needs to be passed to the method.
463    #[must_use]
464    pub fn rcode(&self, header: Header) -> OptRcode {
465        OptRcode::from_parts(header.rcode(), self.inner[5])
466    }
467
468    /// Sets the extend rcode of the OPT header.
469    ///
470    /// This method _only_ sets the upper bits of the rcode. The lower bits
471    /// need to be set in the message header.
472    pub fn set_rcode(&mut self, rcode: OptRcode) {
473        self.inner[5] = rcode.ext()
474    }
475
476    /// Returns the EDNS version of the OPT header.
477    ///
478    /// Only EDNS version 0 is currently defined.
479    #[must_use]
480    pub fn version(&self) -> u8 {
481        self.inner[6]
482    }
483
484    /// Sets the EDNS version of the OPT header.
485    pub fn set_version(&mut self, version: u8) {
486        self.inner[6] = version
487    }
488
489    /// Returns the value of the DNSSEC OK (DO) bit.
490    ///
491    /// By setting this bit, a resolver indicates that it is interested in
492    /// also receiving the DNSSEC-related resource records necessary to
493    /// validate an answer. The bit and the related procedures are defined in
494    /// [RFC 3225].
495    ///
496    /// [RFC 3225]: https://tools.ietf.org/html/rfc3225
497    #[must_use]
498    pub fn dnssec_ok(&self) -> bool {
499        self.inner[7] & 0x80 != 0
500    }
501
502    /// Sets the DNSSEC OK (DO) bit to the given value.
503    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//------------ OptRecord -----------------------------------------------------
528
529/// An entire OPT record.
530///
531/// Because the EDNS specificiation uses parts of the header of the OPT record
532/// to convey some information, a special record type is necessary for OPT
533/// records. You can convert a normal record with [`Opt`] record data into
534/// an `OptRecord` via the [`from_record`][OptRecord::from_record] function.
535#[derive(Clone)]
536pub struct OptRecord<Octs> {
537    /// The UDP payload size field from the record header.
538    udp_payload_size: u16,
539
540    /// The extended rcode.
541    ext_rcode: u8,
542
543    /// The EDNS version.
544    version: u8,
545
546    /// The EDNS flags.
547    flags: u16,
548
549    /// The record data.
550    data: Opt<Octs>,
551}
552
553impl<Octs> OptRecord<Octs> {
554    /// Converts a regular record into an OPT record
555    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    /// Converts the OPT record into a regular record.
566    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    /// Returns the UDP payload size.
583    ///
584    /// Through this field a sender of a message can signal the maximum size
585    /// of UDP payload the sender is able to handle when receiving messages.
586    /// This value refers to the abilities of the sender’s DNS implementation,
587    /// not such things as network MTUs. Which means that the largest UDP
588    /// payload that can actually be sent back to the sender may be smaller.
589    pub fn udp_payload_size(&self) -> u16 {
590        self.udp_payload_size
591    }
592
593    /// Sets the UDP payload size.
594    pub fn set_udp_payload_size(&mut self, value: u16) {
595        self.udp_payload_size = value
596    }
597
598    /// Returns the extended rcode.
599    ///
600    /// Some of the bits of the rcode are stored in the regular message
601    /// header. Such a header needs to be passed to the method.
602    pub fn rcode(&self, header: Header) -> OptRcode {
603        OptRcode::from_parts(header.rcode(), self.ext_rcode)
604    }
605
606    /// Returns the EDNS version of the OPT header.
607    ///
608    /// Only EDNS version 0 is currently defined.
609    pub fn version(&self) -> u8 {
610        self.version
611    }
612
613    /// Returns the value of the DNSSEC OK (DO) bit.
614    ///
615    /// By setting this bit, a resolver indicates that it is interested in
616    /// also receiving the DNSSEC-related resource records necessary to
617    /// validate an answer. The bit and the related procedures are defined in
618    /// [RFC 3225].
619    ///
620    /// [RFC 3225]: https://tools.ietf.org/html/rfc3225
621    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    /// Returns a reference to the raw options.
634    pub fn opt(&self) -> &Opt<Octs> {
635        &self.data
636    }
637}
638
639impl<Octs: Composer> OptRecord<Octs> {
640    /// Appends a new option to the OPT data.
641    pub fn push<Opt: ComposeOptData + ?Sized>(
642        &mut self,
643        option: &Opt,
644    ) -> Result<(), BuildDataError> {
645        self.data.push(option)
646    }
647
648    /// Appends a raw option to the OPT data.
649    ///
650    /// The method will append an option with the given option code. The data
651    /// of the option will be written via the closure `op`.
652    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
677//--- From
678
679impl<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
685//--- OctetsFrom
686
687impl<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
706//--- AsRef
707
708impl<Octs> AsRef<Opt<Octs>> for OptRecord<Octs> {
709    fn as_ref(&self) -> &Opt<Octs> {
710        &self.data
711    }
712}
713
714//--- Debug
715
716impl<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//------------ OptionHeader --------------------------------------------------
729
730/// The header of an OPT option.
731///
732/// This header contains a 16 bit option code identifying the kind of option
733/// we are dealing with and a 16 bit length describing the lenngth in octets
734/// of the option data.
735#[derive(Clone, Copy, Debug)]
736pub struct OptionHeader {
737    /// The option code.
738    code: u16,
739
740    /// The length of the option’s data in octets.
741    len: u16,
742}
743
744#[allow(clippy::len_without_is_empty)]
745impl OptionHeader {
746    /// Creates a new option header from code and length.
747    #[must_use]
748    pub fn new(code: u16, len: u16) -> Self {
749        OptionHeader { code, len }
750    }
751
752    /// Returns the option code.
753    #[must_use]
754    pub fn code(self) -> u16 {
755        self.code
756    }
757
758    /// Returns the length of the option data.
759    #[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//------------ OptIter -------------------------------------------------------
775
776/// An iterator over the options of an OPT record.
777///
778/// The iterator is generic over a specific option type. It skips over all
779/// options that this type does not want to parse. It returns a result that
780/// is either a parsed option or a parse error. These errors are only for the
781/// particular option. After such an error you can continue to iterate until
782/// `None` indicates that you’ve reached the end of the record.
783#[derive(Clone, Debug)]
784pub struct OptIter<'a, Octs: ?Sized, D> {
785    /// A parser for the OPT record data.
786    parser: Parser<'a, Octs>,
787
788    /// The marker to remember which record data we use.
789    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    /// Creates an iterator from a reference to the OPT record data.
798    fn new(octets: &'a Octs) -> Self {
799        OptIter {
800            parser: Parser::from_ref(octets),
801            marker: PhantomData,
802        }
803    }
804
805    /// Returns the next item from the parser.
806    ///
807    /// Expects there to be another option available and will return a
808    /// parse error otherwise. Return `Ok(None)` if the option type didn’t
809    /// want to parse this option.
810    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                    // Advance to end so we’ll return None from now on.
838                    self.parser.advance_to_end();
839                    return Some(Err(err));
840                }
841            }
842        }
843        None
844    }
845}
846
847//------------ OptData -------------------------------------------------------
848
849/// A type representing an OPT option.
850///
851/// The type needs to be able to report the option code to use for the
852/// encoding via the [`code`][Self::code] method.
853pub trait OptData {
854    /// Returns the option code associated with this option.
855    fn code(&self) -> OptionCode;
856}
857
858//------------ ParseOptData --------------------------------------------------
859
860/// An OPT option that can be parsed from the record data.
861pub trait ParseOptData<'a, Octs: ?Sized>: OptData + Sized {
862    /// Parses the option code data.
863    ///
864    /// The data is for an option of `code`. The function may decide whether
865    /// it wants to parse data for that type. It should return `Ok(None)` if
866    /// it doesn’t.
867    ///
868    /// The `parser` is positioned at the beginning of the option data and is
869    /// is limited to the length of the data. The method only needs to parse
870    /// as much data as it needs. The caller has to make sure to deal with
871    /// data remaining in the parser.
872    ///
873    /// If the function doesn’t want to process the data, it must not touch
874    /// the parser. In particual, it must not advance it.
875    fn parse_option(
876        code: OptionCode,
877        parser: &mut Parser<'a, Octs>,
878    ) -> Result<Option<Self>, ParseError>;
879}
880
881//------------ ComposeOptData ------------------------------------------------
882
883/// An OPT option that can be written to wire format.
884pub 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//------------ UnknownOptData ------------------------------------------------
894
895/// An OPT option in its raw form.
896///
897/// This type accepts any option type via its option code and raw data.
898#[derive(Clone)]
899#[cfg_attr(feature = "serde", derive(serde::Serialize))]
900pub struct UnknownOptData<Octs> {
901    /// The option code for the option.
902    code: OptionCode,
903
904    /// The raw option data.
905    #[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    /// Creates a new option from the code and data.
919    ///
920    /// The function returns an error if `data` is longer than 65,535 octets.
921    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    /// Creates a new option data value without checking.
930    ///
931    /// # Safety
932    ///
933    /// The caller needs to make sure that `data` is not longer than 65,535
934    /// octets.
935    pub unsafe fn new_unchecked(code: OptionCode, data: Octs) -> Self {
936        Self { code, data }
937    }
938
939    /// Returns the option code of the option.
940    pub fn code(&self) -> OptionCode {
941        self.code
942    }
943
944    /// Returns a reference for to the option data.
945    pub fn data(&self) -> &Octs {
946        &self.data
947    }
948
949    /// Returns a slice of the option data.
950    pub fn as_slice(&self) -> &[u8]
951    where
952        Octs: AsRef<[u8]>,
953    {
954        self.data.as_ref()
955    }
956
957    /// Returns a mutable slice of the option data.
958    pub fn as_slice_mut(&mut self) -> &mut [u8]
959    where
960        Octs: AsMut<[u8]>,
961    {
962        self.data.as_mut()
963    }
964}
965
966//--- OctetsFrom
967
968impl<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}
983//--- AsRef and AsMut
984
985impl<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
1003//--- OptData etc.
1004
1005impl<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
1042//--- Display and Debug
1043
1044impl<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//============ Error Types ===================================================
1060
1061//------------ LongOptData ---------------------------------------------------
1062
1063/// The octets sequence to be used for option data is too long.
1064#[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//------------ BuildDataError ------------------------------------------------
1098
1099/// An error happened while constructing an SVCB value.
1100#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1101pub enum BuildDataError {
1102    /// The value would exceed the allowed length of a value.
1103    LongOptData,
1104
1105    /// The underlying octets builder ran out of buffer space.
1106    ShortBuf,
1107}
1108
1109impl BuildDataError {
1110    /// Converts the error into a [`LongOptData`] error for ‘endless’ buffers.
1111    ///
1112    /// # Panics
1113    ///
1114    /// This method will panic if the error is of the `ShortBuf` variant.
1115    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
1135//--- Display and Error
1136
1137impl 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//============ Tests =========================================================
1150
1151#[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)] // lifetimes ...
1165    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        // Push two options and check that both are parseable
1199        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        // Parse both into specialized types
1216        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}