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 crate::utils::base16;
50use core::cmp::Ordering;
51use core::marker::PhantomData;
52use core::{fmt, hash, mem};
53use octseq::builder::{EmptyBuilder, OctetsBuilder, ShortBuf};
54use octseq::octets::{Octets, OctetsFrom};
55use octseq::parse::Parser;
56
57//------------ Opt -----------------------------------------------------------
58
59/// OPT record data.
60///
61/// This is the record data type for OPT records and can be used as the data
62/// type parameter in [`Record`]. It simply wraps an octets sequence with all
63/// the record data. It guarantees that the data contains a correctly
64/// formatted sequence of options but doesn’t guarantee that the options
65/// themselves are correct. You can iterate over options via the [`iter`]
66/// method.
67///
68/// Since some of the information of the OPT record is transmitted in the
69/// record header, a special type [`OptRecord`] exists, that contains all
70/// the OPT data which is the preferred way of accessing this data.
71///
72/// [`iter`]: #method.iter
73/// [`OptRecord`]: struct.OptRecord.html
74#[derive(Clone)]
75#[repr(transparent)]
76pub struct Opt<Octs: ?Sized> {
77    octets: Octs,
78}
79
80#[cfg(feature = "serde")]
81impl<O: AsRef<[u8]>> serde::Serialize for Opt<O> {
82    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
83    where
84        S: serde::Serializer,
85    {
86        use serde::ser::SerializeSeq;
87        let mut list = serializer.serialize_seq(None)?;
88
89        for rec in self.for_slice_ref().iter::<AllOptData<_, _>>() {
90            let Ok(rec) = rec else {
91                continue;
92            };
93            list.serialize_element(&rec)?;
94        }
95
96        list.end()
97    }
98}
99
100impl Opt<()> {
101    /// The rtype of this record data type.
102    pub(crate) const RTYPE: Rtype = Rtype::OPT;
103}
104
105impl<Octs: EmptyBuilder> Opt<Octs> {
106    /// Creates empty OPT record data.
107    pub fn empty() -> Self {
108        Self {
109            octets: Octs::empty(),
110        }
111    }
112}
113
114impl<Octs: AsRef<[u8]>> Opt<Octs> {
115    /// Creates OPT record data from an octets sequence.
116    ///
117    /// The function checks whether the octets contain a sequence of
118    /// options. It does not check whether the options themselves are valid.
119    pub fn from_octets(octets: Octs) -> Result<Self, ParseError> {
120        Opt::check_slice(octets.as_ref())?;
121        Ok(unsafe { Self::from_octets_unchecked(octets) })
122    }
123
124    /// Creates OPT record data from octets without checking.
125    ///
126    /// # Safety
127    ///
128    /// The caller needs to ensure that the slice contains correctly encoded
129    /// OPT record data. The data of the options themselves does not need to
130    /// be correct.
131    unsafe fn from_octets_unchecked(octets: Octs) -> Self {
132        Self { octets }
133    }
134
135    /// Parses OPT record data from the beginning of a parser.
136    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
137        parser: &mut Parser<'a, Src>,
138    ) -> Result<Self, ParseError> {
139        let len = parser.remaining();
140        Self::from_octets(parser.parse_octets(len)?)
141    }
142}
143
144impl Opt<[u8]> {
145    /// Creates OPT record data from an octets slice.
146    pub fn from_slice(slice: &[u8]) -> Result<&Self, ParseError> {
147        Self::check_slice(slice)?;
148        Ok(unsafe { Self::from_slice_unchecked(slice) })
149    }
150
151    /// Creates OPT record data from an octets slice without checking.
152    ///
153    /// # Safety
154    ///
155    /// The caller needs to ensure that the slice contains correctly encoded
156    /// OPT record data. The data of the options themselves does not need to
157    /// be correct.
158    unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
159        // SAFETY: Opt has repr(transparent)
160        mem::transmute(slice)
161    }
162
163    /// Checks that the slice contains acceptable OPT record data.
164    fn check_slice(slice: &[u8]) -> Result<(), ParseError> {
165        if slice.len() > usize::from(u16::MAX) {
166            return Err(FormError::new("long record data").into());
167        }
168        let mut parser = Parser::from_ref(slice);
169        while parser.remaining() > 0 {
170            parser.advance(2)?;
171            let len = parser.parse_u16_be()?;
172            parser.advance(len as usize)?;
173        }
174        Ok(())
175    }
176}
177
178impl<Octs: AsRef<[u8]> + ?Sized> Opt<Octs> {
179    pub fn for_slice_ref(&self) -> Opt<&[u8]> {
180        unsafe { Opt::from_octets_unchecked(self.octets.as_ref()) }
181    }
182}
183
184impl<Octs: AsRef<[u8]> + ?Sized> Opt<Octs> {
185    /// Returns the length of the OPT record data.
186    pub fn len(&self) -> usize {
187        self.octets.as_ref().len()
188    }
189
190    /// Returns whether the OPT record data is empty.
191    pub fn is_empty(&self) -> bool {
192        self.octets.as_ref().is_empty()
193    }
194
195    /// Returns an iterator over options of a given type.
196    ///
197    /// The returned iterator will return only options represented by type
198    /// `D` and quietly skip over all the others.
199    pub fn iter<'s, Data>(&'s self) -> OptIter<'s, Octs, Data>
200    where
201        Octs: Octets,
202        Data: ParseOptData<'s, Octs>,
203    {
204        OptIter::new(&self.octets)
205    }
206
207    /// Returns the first option of a given type if present.
208    ///
209    /// If trying to parse this first option fails, returns `None` as well.
210    pub fn first<'s, Data>(&'s self) -> Option<Data>
211    where
212        Octs: Octets,
213        Data: ParseOptData<'s, Octs>,
214    {
215        self.iter::<Data>().next()?.ok()
216    }
217}
218
219impl<Octs: Composer> Opt<Octs> {
220    /// Appends a new option to the OPT data.
221    pub fn push<Opt: ComposeOptData + ?Sized>(
222        &mut self,
223        option: &Opt,
224    ) -> Result<(), BuildDataError> {
225        self.push_raw_option(option.code(), option.compose_len(), |target| {
226            option.compose_option(target)
227        })
228    }
229
230    /// Appends a raw option to the OPT data.
231    ///
232    /// The method will append an option with the given option code. The data
233    /// of the option will be written via the closure `op`.
234    pub fn push_raw_option<F>(
235        &mut self,
236        code: OptionCode,
237        option_len: u16,
238        op: F,
239    ) -> Result<(), BuildDataError>
240    where
241        F: FnOnce(&mut Octs) -> Result<(), Octs::AppendError>,
242    {
243        LongOptData::check_len(
244            self.octets
245                .as_ref()
246                .len()
247                .saturating_add(usize::from(option_len)),
248        )?;
249
250        code.compose(&mut self.octets)?;
251        option_len.compose(&mut self.octets)?;
252        op(&mut self.octets)?;
253        Ok(())
254    }
255}
256
257//--- OctetsFrom
258
259impl<Octs, SrcOcts> OctetsFrom<Opt<SrcOcts>> for Opt<Octs>
260where
261    Octs: OctetsFrom<SrcOcts>,
262{
263    type Error = Octs::Error;
264
265    fn try_octets_from(source: Opt<SrcOcts>) -> Result<Self, Self::Error> {
266        Octs::try_octets_from(source.octets).map(|octets| Opt { octets })
267    }
268}
269
270//--- PartialEq and Eq
271
272impl<Octs, Other> PartialEq<Opt<Other>> for Opt<Octs>
273where
274    Octs: AsRef<[u8]> + ?Sized,
275    Other: AsRef<[u8]> + ?Sized,
276{
277    fn eq(&self, other: &Opt<Other>) -> bool {
278        self.octets.as_ref().eq(other.octets.as_ref())
279    }
280}
281
282impl<Octs: AsRef<[u8]> + ?Sized> Eq for Opt<Octs> {}
283
284//--- PartialOrd, Ord, and CanonicalOrd
285
286impl<Octs, Other> PartialOrd<Opt<Other>> for Opt<Octs>
287where
288    Octs: AsRef<[u8]> + ?Sized,
289    Other: AsRef<[u8]> + ?Sized,
290{
291    fn partial_cmp(&self, other: &Opt<Other>) -> Option<Ordering> {
292        self.octets.as_ref().partial_cmp(other.octets.as_ref())
293    }
294}
295
296impl<Octs: AsRef<[u8]> + ?Sized> Ord for Opt<Octs> {
297    fn cmp(&self, other: &Self) -> Ordering {
298        self.octets.as_ref().cmp(other.octets.as_ref())
299    }
300}
301
302impl<Octs, Other> CanonicalOrd<Opt<Other>> for Opt<Octs>
303where
304    Octs: AsRef<[u8]> + ?Sized,
305    Other: AsRef<[u8]> + ?Sized,
306{
307    fn canonical_cmp(&self, other: &Opt<Other>) -> Ordering {
308        self.octets.as_ref().cmp(other.octets.as_ref())
309    }
310}
311
312//--- Hash
313
314impl<Octs: AsRef<[u8]> + ?Sized> hash::Hash for Opt<Octs> {
315    fn hash<H: hash::Hasher>(&self, state: &mut H) {
316        self.octets.as_ref().hash(state)
317    }
318}
319
320//--- RecordData, ParseRecordData, and ComposeRecordData
321
322impl<Octs: ?Sized> RecordData for Opt<Octs> {
323    fn rtype(&self) -> Rtype {
324        Rtype::OPT
325    }
326}
327
328impl<'a, Octs> ParseRecordData<'a, Octs> for Opt<Octs::Range<'a>>
329where
330    Octs: Octets + ?Sized,
331{
332    fn parse_rdata(
333        rtype: Rtype,
334        parser: &mut Parser<'a, Octs>,
335    ) -> Result<Option<Self>, ParseError> {
336        if rtype == Rtype::OPT {
337            Self::parse(parser).map(Some)
338        } else {
339            Ok(None)
340        }
341    }
342}
343
344impl<Octs: AsRef<[u8]> + ?Sized> ComposeRecordData for Opt<Octs> {
345    fn rdlen(&self, _compress: bool) -> Option<u16> {
346        Some(u16::try_from(self.octets.as_ref().len()).expect("long OPT"))
347    }
348
349    fn compose_rdata<Target: Composer + ?Sized>(
350        &self,
351        target: &mut Target,
352    ) -> Result<(), Target::AppendError> {
353        target.append_slice(self.octets.as_ref())
354    }
355
356    fn compose_canonical_rdata<Target: Composer + ?Sized>(
357        &self,
358        target: &mut Target,
359    ) -> Result<(), Target::AppendError> {
360        self.compose_rdata(target)
361    }
362}
363
364//--- Display
365
366impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Opt<Octs> {
367    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
368        // XXX TODO Print this properly.
369        f.write_str("OPT ...")
370    }
371}
372
373impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Opt<Octs> {
374    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
375        f.write_str("Opt(")?;
376        fmt::Display::fmt(self, f)?;
377        f.write_str(")")
378    }
379}
380
381//------------ OptHeader -----------------------------------------------------
382
383/// The header of an OPT record.
384///
385/// The OPT record reappropriates the record header for encoding some
386/// basic information. This type provides access to this information. It
387/// consists of the record header with the exception of the final `rdlen`
388/// field.
389///
390/// This is so that [`OptBuilder`] can safely deref to this type.
391///
392/// [`OptBuilder`]: crate::base::message_builder::OptBuilder
393//    +------------+--------------+------------------------------+
394//    | Field Name | Field Type   | Description                  |
395//    +------------+--------------+------------------------------+
396//    | NAME       | domain name  | MUST be 0 (root domain)      |
397//    | TYPE       | u_int16_t    | OPT (41)                     |
398//    | CLASS      | u_int16_t    | requestor's UDP payload size |
399//    | TTL        | u_int32_t    | extended RCODE and flags     |
400//    | RDLEN      | u_int16_t    | length of all RDATA          |
401//    | RDATA      | octet stream | {attribute,value} pairs      |
402//    +------------+--------------+------------------------------+
403#[derive(Copy, Clone, Debug, Eq, PartialEq)]
404#[repr(transparent)]
405pub struct OptHeader {
406    /// The bytes of the header.
407    inner: [u8; 9],
408}
409
410impl OptHeader {
411    /// Returns a reference to an OPT header pointing into a record’s octets.
412    #[must_use]
413    pub fn for_record_slice(slice: &[u8]) -> &OptHeader {
414        assert!(slice.len() >= mem::size_of::<Self>());
415
416        // SAFETY: the pointer cast is sound because
417        //   - OptHeader has repr(transparent) and
418        //   - the size of the slice is large enough
419        unsafe { &*(slice.as_ptr() as *const OptHeader) }
420    }
421
422    /// Returns a mutable reference pointing into a record’s octets.
423    pub fn for_record_slice_mut(slice: &mut [u8]) -> &mut 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 { &mut *(slice.as_mut_ptr() as *mut OptHeader) }
430    }
431
432    /// Returns the UDP payload size.
433    ///
434    /// Through this field a sender of a message can signal the maximum size
435    /// of UDP payload the sender is able to handle when receiving messages.
436    /// This value refers to the abilities of the sender’s DNS implementation,
437    /// not such things as network MTUs. Which means that the largest UDP
438    /// payload that can actually be sent back to the sender may be smaller.
439    #[must_use]
440    pub fn udp_payload_size(&self) -> u16 {
441        u16::from_be_bytes(self.inner[3..5].try_into().unwrap())
442    }
443
444    /// Sets the UDP payload size value.
445    pub fn set_udp_payload_size(&mut self, value: u16) {
446        self.inner[3..5].copy_from_slice(&value.to_be_bytes())
447    }
448
449    /// Returns the extended rcode.
450    ///
451    /// Some of the bits of the rcode are stored in the regular message
452    /// header. Such a header needs to be passed to the method.
453    #[must_use]
454    pub fn rcode(&self, header: Header) -> OptRcode {
455        OptRcode::from_parts(header.rcode(), self.inner[5])
456    }
457
458    /// Sets the extend rcode of the OPT header.
459    ///
460    /// This method _only_ sets the upper bits of the rcode. The lower bits
461    /// need to be set in the message header.
462    pub fn set_rcode(&mut self, rcode: OptRcode) {
463        self.inner[5] = rcode.ext()
464    }
465
466    /// Returns the EDNS version of the OPT header.
467    ///
468    /// Only EDNS version 0 is currently defined.
469    #[must_use]
470    pub fn version(&self) -> u8 {
471        self.inner[6]
472    }
473
474    /// Sets the EDNS version of the OPT header.
475    pub fn set_version(&mut self, version: u8) {
476        self.inner[6] = version
477    }
478
479    /// Returns the value of the DNSSEC OK (DO) bit.
480    ///
481    /// By setting this bit, a resolver indicates that it is interested in
482    /// also receiving the DNSSEC-related resource records necessary to
483    /// validate an answer. The bit and the related procedures are defined in
484    /// [RFC 3225].
485    ///
486    /// [RFC 3225]: https://tools.ietf.org/html/rfc3225
487    #[must_use]
488    pub fn dnssec_ok(&self) -> bool {
489        self.inner[7] & 0x80 != 0
490    }
491
492    /// Sets the DNSSEC OK (DO) bit to the given value.
493    pub fn set_dnssec_ok(&mut self, value: bool) {
494        if value {
495            self.inner[7] |= 0x80
496        } else {
497            self.inner[7] &= 0x7F
498        }
499    }
500
501    pub fn compose<Target: OctetsBuilder + ?Sized>(
502        self,
503        target: &mut Target,
504    ) -> Result<(), Target::AppendError> {
505        target.append_slice(&self.inner)
506    }
507}
508
509impl Default for OptHeader {
510    fn default() -> Self {
511        OptHeader {
512            inner: [0, 0, 41, 0, 0, 0, 0, 0, 0],
513        }
514    }
515}
516
517//------------ OptRecord -----------------------------------------------------
518
519/// An entire OPT record.
520///
521/// Because the EDNS specificiation uses parts of the header of the OPT record
522/// to convey some information, a special record type is necessary for OPT
523/// records. You can convert a normal record with [`Opt`] record data into
524/// an `OptRecord` via the [`from_record`][OptRecord::from_record] function.
525#[derive(Clone)]
526pub struct OptRecord<Octs> {
527    /// The UDP payload size field from the record header.
528    udp_payload_size: u16,
529
530    /// The extended rcode.
531    ext_rcode: u8,
532
533    /// The EDNS version.
534    version: u8,
535
536    /// The EDNS flags.
537    flags: u16,
538
539    /// The record data.
540    data: Opt<Octs>,
541}
542
543impl<Octs> OptRecord<Octs> {
544    /// Converts a regular record into an OPT record
545    pub fn from_record<N: ToName>(record: Record<N, Opt<Octs>>) -> Self {
546        OptRecord {
547            udp_payload_size: record.class().to_int(),
548            ext_rcode: (record.ttl().as_secs() >> 24) as u8,
549            version: (record.ttl().as_secs() >> 16) as u8,
550            flags: record.ttl().as_secs() as u16,
551            data: record.into_data(),
552        }
553    }
554
555    /// Converts the OPT record into a regular record.
556    pub fn as_record(&self) -> Record<&'static Name<[u8]>, Opt<&[u8]>>
557    where
558        Octs: AsRef<[u8]>,
559    {
560        Record::new(
561            Name::root_slice(),
562            Class::from_int(self.udp_payload_size),
563            Ttl::from_secs(
564                u32::from(self.ext_rcode) << 24
565                    | u32::from(self.version) << 16
566                    | u32::from(self.flags),
567            ),
568            self.data.for_slice_ref(),
569        )
570    }
571
572    /// Returns the UDP payload size.
573    ///
574    /// Through this field a sender of a message can signal the maximum size
575    /// of UDP payload the sender is able to handle when receiving messages.
576    /// This value refers to the abilities of the sender’s DNS implementation,
577    /// not such things as network MTUs. Which means that the largest UDP
578    /// payload that can actually be sent back to the sender may be smaller.
579    pub fn udp_payload_size(&self) -> u16 {
580        self.udp_payload_size
581    }
582
583    /// Sets the UDP payload size.
584    pub fn set_udp_payload_size(&mut self, value: u16) {
585        self.udp_payload_size = value
586    }
587
588    /// Returns the extended rcode.
589    ///
590    /// Some of the bits of the rcode are stored in the regular message
591    /// header. Such a header needs to be passed to the method.
592    pub fn rcode(&self, header: Header) -> OptRcode {
593        OptRcode::from_parts(header.rcode(), self.ext_rcode)
594    }
595
596    /// Returns the EDNS version of the OPT header.
597    ///
598    /// Only EDNS version 0 is currently defined.
599    pub fn version(&self) -> u8 {
600        self.version
601    }
602
603    /// Returns the value of the DNSSEC OK (DO) bit.
604    ///
605    /// By setting this bit, a resolver indicates that it is interested in
606    /// also receiving the DNSSEC-related resource records necessary to
607    /// validate an answer. The bit and the related procedures are defined in
608    /// [RFC 3225].
609    ///
610    /// [RFC 3225]: https://tools.ietf.org/html/rfc3225
611    pub fn dnssec_ok(&self) -> bool {
612        self.flags & 0x8000 != 0
613    }
614
615    pub fn set_dnssec_ok(&mut self, value: bool) {
616        if value {
617            self.flags |= 0x8000;
618        } else {
619            self.flags &= !0x8000;
620        }
621    }
622
623    /// Returns a reference to the raw options.
624    pub fn opt(&self) -> &Opt<Octs> {
625        &self.data
626    }
627}
628
629impl<Octs: Composer> OptRecord<Octs> {
630    /// Appends a new option to the OPT data.
631    pub fn push<Opt: ComposeOptData + ?Sized>(
632        &mut self,
633        option: &Opt,
634    ) -> Result<(), BuildDataError> {
635        self.data.push(option)
636    }
637
638    /// Appends a raw option to the OPT data.
639    ///
640    /// The method will append an option with the given option code. The data
641    /// of the option will be written via the closure `op`.
642    pub fn push_raw_option<F>(
643        &mut self,
644        code: OptionCode,
645        option_len: u16,
646        op: F,
647    ) -> Result<(), BuildDataError>
648    where
649        F: FnOnce(&mut Octs) -> Result<(), Octs::AppendError>,
650    {
651        self.data.push_raw_option(code, option_len, op)
652    }
653}
654
655impl<Octs: EmptyBuilder> Default for OptRecord<Octs> {
656    fn default() -> Self {
657        Self {
658            udp_payload_size: 0,
659            ext_rcode: 0,
660            version: 0,
661            flags: 0,
662            data: Opt::empty(),
663        }
664    }
665}
666
667//--- From
668
669impl<Octs, N: ToName> From<Record<N, Opt<Octs>>> for OptRecord<Octs> {
670    fn from(record: Record<N, Opt<Octs>>) -> Self {
671        Self::from_record(record)
672    }
673}
674
675//--- OctetsFrom
676
677impl<Octs, SrcOcts> OctetsFrom<OptRecord<SrcOcts>> for OptRecord<Octs>
678where
679    Octs: OctetsFrom<SrcOcts>,
680{
681    type Error = Octs::Error;
682
683    fn try_octets_from(
684        source: OptRecord<SrcOcts>,
685    ) -> Result<Self, Self::Error> {
686        Ok(OptRecord {
687            udp_payload_size: source.udp_payload_size,
688            ext_rcode: source.ext_rcode,
689            version: source.version,
690            flags: source.flags,
691            data: Opt::try_octets_from(source.data)?,
692        })
693    }
694}
695
696//--- AsRef
697
698impl<Octs> AsRef<Opt<Octs>> for OptRecord<Octs> {
699    fn as_ref(&self) -> &Opt<Octs> {
700        &self.data
701    }
702}
703
704//--- Debug
705
706impl<Octs: AsRef<[u8]>> fmt::Debug for OptRecord<Octs> {
707    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
708        f.debug_struct("OptRecord")
709            .field("udp_payload_size", &self.udp_payload_size)
710            .field("ext_rcord", &self.ext_rcode)
711            .field("version", &self.version)
712            .field("flags", &self.flags)
713            .field("data", &self.data)
714            .finish()
715    }
716}
717
718//------------ OptionHeader --------------------------------------------------
719
720/// The header of an OPT option.
721///
722/// This header contains a 16 bit option code identifying the kind of option
723/// we are dealing with and a 16 bit length describing the lenngth in octets
724/// of the option data.
725#[derive(Clone, Copy, Debug)]
726pub struct OptionHeader {
727    /// The option code.
728    code: u16,
729
730    /// The length of the option’s data in octets.
731    len: u16,
732}
733
734#[allow(clippy::len_without_is_empty)]
735impl OptionHeader {
736    /// Creates a new option header from code and length.
737    #[must_use]
738    pub fn new(code: u16, len: u16) -> Self {
739        OptionHeader { code, len }
740    }
741
742    /// Returns the option code.
743    #[must_use]
744    pub fn code(self) -> u16 {
745        self.code
746    }
747
748    /// Returns the length of the option data.
749    #[must_use]
750    pub fn len(self) -> u16 {
751        self.len
752    }
753
754    pub fn parse<Octs: AsRef<[u8]> + ?Sized>(
755        parser: &mut Parser<Octs>,
756    ) -> Result<Self, ParseError> {
757        Ok(OptionHeader::new(
758            parser.parse_u16_be()?,
759            parser.parse_u16_be()?,
760        ))
761    }
762}
763
764//------------ OptIter -------------------------------------------------------
765
766/// An iterator over the options of an OPT record.
767///
768/// The iterator is generic over a specific option type. It skips over all
769/// options that this type does not want to parse. It returns a result that
770/// is either a parsed option or a parse error. These errors are only for the
771/// particular option. After such an error you can continue to iterate until
772/// `None` indicates that you’ve reached the end of the record.
773#[derive(Clone, Debug)]
774pub struct OptIter<'a, Octs: ?Sized, D> {
775    /// A parser for the OPT record data.
776    parser: Parser<'a, Octs>,
777
778    /// The marker to remember which record data we use.
779    marker: PhantomData<D>,
780}
781
782impl<'a, Octs, D> OptIter<'a, Octs, D>
783where
784    Octs: Octets + ?Sized,
785    D: ParseOptData<'a, Octs>,
786{
787    /// Creates an iterator from a reference to the OPT record data.
788    fn new(octets: &'a Octs) -> Self {
789        OptIter {
790            parser: Parser::from_ref(octets),
791            marker: PhantomData,
792        }
793    }
794
795    /// Returns the next item from the parser.
796    ///
797    /// Expects there to be another option available and will return a
798    /// parse error otherwise. Return `Ok(None)` if the option type didn’t
799    /// want to parse this option.
800    fn next_step(&mut self) -> Result<Option<D>, ParseError> {
801        let code = self.parser.parse_u16_be()?.into();
802        let len = self.parser.parse_u16_be()? as usize;
803        let mut parser = self.parser.parse_parser(len)?;
804        let res = D::parse_option(code, &mut parser)?;
805        if res.is_some() && parser.remaining() > 0 {
806            return Err(ParseError::Form(FormError::new(
807                "trailing data in option",
808            )));
809        }
810        Ok(res)
811    }
812}
813
814impl<'a, Octs, Data> Iterator for OptIter<'a, Octs, Data>
815where
816    Octs: Octets + ?Sized,
817    Data: ParseOptData<'a, Octs>,
818{
819    type Item = Result<Data, ParseError>;
820
821    fn next(&mut self) -> Option<Self::Item> {
822        while self.parser.remaining() > 0 {
823            match self.next_step() {
824                Ok(Some(res)) => return Some(Ok(res)),
825                Ok(None) => {}
826                Err(err) => {
827                    // Advance to end so we’ll return None from now on.
828                    self.parser.advance_to_end();
829                    return Some(Err(err));
830                }
831            }
832        }
833        None
834    }
835}
836
837//------------ OptData -------------------------------------------------------
838
839/// A type representing an OPT option.
840///
841/// The type needs to be able to report the option code to use for the
842/// encoding via the [`code`][Self::code] method.
843pub trait OptData {
844    /// Returns the option code associated with this option.
845    fn code(&self) -> OptionCode;
846}
847
848//------------ ParseOptData --------------------------------------------------
849
850/// An OPT option that can be parsed from the record data.
851pub trait ParseOptData<'a, Octs: ?Sized>: OptData + Sized {
852    /// Parses the option code data.
853    ///
854    /// The data is for an option of `code`. The function may decide whether
855    /// it wants to parse data for that type. It should return `Ok(None)` if
856    /// it doesn’t.
857    ///
858    /// The `parser` is positioned at the beginning of the option data and is
859    /// is limited to the length of the data. The method only needs to parse
860    /// as much data as it needs. The caller has to make sure to deal with
861    /// data remaining in the parser.
862    ///
863    /// If the function doesn’t want to process the data, it must not touch
864    /// the parser. In particual, it must not advance it.
865    fn parse_option(
866        code: OptionCode,
867        parser: &mut Parser<'a, Octs>,
868    ) -> Result<Option<Self>, ParseError>;
869}
870
871//------------ ComposeOptData ------------------------------------------------
872
873/// An OPT option that can be written to wire format.
874pub trait ComposeOptData: OptData {
875    fn compose_len(&self) -> u16;
876
877    fn compose_option<Target: OctetsBuilder + ?Sized>(
878        &self,
879        target: &mut Target,
880    ) -> Result<(), Target::AppendError>;
881}
882
883//------------ UnknownOptData ------------------------------------------------
884
885/// An OPT option in its raw form.
886///
887/// This type accepts any option type via its option code and raw data.
888#[derive(Clone)]
889#[cfg_attr(feature = "serde", derive(serde::Serialize))]
890pub struct UnknownOptData<Octs> {
891    /// The option code for the option.
892    code: OptionCode,
893
894    /// The raw option data.
895    #[cfg_attr(
896        feature = "serde",
897        serde(
898            serialize_with = "crate::utils::base16::serde::serialize",
899            bound(
900                serialize = "Octs: AsRef<[u8]> + octseq::serde::SerializeOctets",
901            )
902        )
903    )]
904    data: Octs,
905}
906
907impl<Octs> UnknownOptData<Octs> {
908    /// Creates a new option from the code and data.
909    ///
910    /// The function returns an error if `data` is longer than 65,535 octets.
911    pub fn new(code: OptionCode, data: Octs) -> Result<Self, LongOptData>
912    where
913        Octs: AsRef<[u8]>,
914    {
915        LongOptData::check_len(data.as_ref().len())?;
916        Ok(unsafe { Self::new_unchecked(code, data) })
917    }
918
919    /// Creates a new option data value without checking.
920    ///
921    /// # Safety
922    ///
923    /// The caller needs to make sure that `data` is not longer than 65,535
924    /// octets.
925    pub unsafe fn new_unchecked(code: OptionCode, data: Octs) -> Self {
926        Self { code, data }
927    }
928
929    /// Returns the option code of the option.
930    pub fn code(&self) -> OptionCode {
931        self.code
932    }
933
934    /// Returns a reference for to the option data.
935    pub fn data(&self) -> &Octs {
936        &self.data
937    }
938
939    /// Returns a slice of the option data.
940    pub fn as_slice(&self) -> &[u8]
941    where
942        Octs: AsRef<[u8]>,
943    {
944        self.data.as_ref()
945    }
946
947    /// Returns a mutable slice of the option data.
948    pub fn as_slice_mut(&mut self) -> &mut [u8]
949    where
950        Octs: AsMut<[u8]>,
951    {
952        self.data.as_mut()
953    }
954}
955
956//--- OctetsFrom
957
958impl<Octs, SrcOcts> OctetsFrom<UnknownOptData<SrcOcts>>
959    for UnknownOptData<Octs>
960where
961    Octs: OctetsFrom<SrcOcts>,
962{
963    type Error = Octs::Error;
964
965    fn try_octets_from(
966        src: UnknownOptData<SrcOcts>,
967    ) -> Result<Self, Self::Error> {
968        Ok(unsafe {
969            Self::new_unchecked(src.code, Octs::try_octets_from(src.data)?)
970        })
971    }
972}
973//--- AsRef and AsMut
974
975impl<Octs> AsRef<Octs> for UnknownOptData<Octs> {
976    fn as_ref(&self) -> &Octs {
977        self.data()
978    }
979}
980
981impl<Octs: AsRef<[u8]>> AsRef<[u8]> for UnknownOptData<Octs> {
982    fn as_ref(&self) -> &[u8] {
983        self.as_slice()
984    }
985}
986
987impl<Octs: AsMut<[u8]>> AsMut<[u8]> for UnknownOptData<Octs> {
988    fn as_mut(&mut self) -> &mut [u8] {
989        self.as_slice_mut()
990    }
991}
992
993//--- OptData etc.
994
995impl<Octs: AsRef<[u8]>> OptData for UnknownOptData<Octs> {
996    fn code(&self) -> OptionCode {
997        self.code
998    }
999}
1000
1001impl<'a, Octs> ParseOptData<'a, Octs> for UnknownOptData<Octs::Range<'a>>
1002where
1003    Octs: Octets + ?Sized,
1004{
1005    fn parse_option(
1006        code: OptionCode,
1007        parser: &mut Parser<'a, Octs>,
1008    ) -> Result<Option<Self>, ParseError> {
1009        Self::new(code, parser.parse_octets(parser.remaining())?)
1010            .map(Some)
1011            .map_err(Into::into)
1012    }
1013}
1014
1015impl<Octs: AsRef<[u8]>> ComposeOptData for UnknownOptData<Octs> {
1016    fn compose_len(&self) -> u16 {
1017        self.data
1018            .as_ref()
1019            .len()
1020            .try_into()
1021            .expect("long option data")
1022    }
1023
1024    fn compose_option<Target: OctetsBuilder + ?Sized>(
1025        &self,
1026        target: &mut Target,
1027    ) -> Result<(), Target::AppendError> {
1028        target.append_slice(self.data.as_ref())
1029    }
1030}
1031
1032//--- Display and Debug
1033
1034impl<Octs: AsRef<[u8]>> fmt::Display for UnknownOptData<Octs> {
1035    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1036        base16::display(self.data.as_ref(), f)
1037    }
1038}
1039
1040impl<Octs: AsRef<[u8]>> fmt::Debug for UnknownOptData<Octs> {
1041    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1042        f.debug_struct("UnknownOptData")
1043            .field("code", &self.code)
1044            .field("data", &format_args!("{}", self))
1045            .finish()
1046    }
1047}
1048
1049//============ Error Types ===================================================
1050
1051//------------ LongOptData ---------------------------------------------------
1052
1053/// The octets sequence to be used for option data is too long.
1054#[derive(Clone, Copy, Debug)]
1055pub struct LongOptData(());
1056
1057impl LongOptData {
1058    #[must_use]
1059    pub fn as_str(self) -> &'static str {
1060        "option data too long"
1061    }
1062
1063    pub fn check_len(len: usize) -> Result<(), Self> {
1064        if len > usize::from(u16::MAX) {
1065            Err(Self(()))
1066        } else {
1067            Ok(())
1068        }
1069    }
1070}
1071
1072impl From<LongOptData> for ParseError {
1073    fn from(src: LongOptData) -> Self {
1074        ParseError::form_error(src.as_str())
1075    }
1076}
1077
1078impl fmt::Display for LongOptData {
1079    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1080        f.write_str(self.as_str())
1081    }
1082}
1083
1084#[cfg(feature = "std")]
1085impl std::error::Error for LongOptData {}
1086
1087//------------ BuildDataError ------------------------------------------------
1088
1089/// An error happened while constructing an SVCB value.
1090#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1091pub enum BuildDataError {
1092    /// The value would exceed the allowed length of a value.
1093    LongOptData,
1094
1095    /// The underlying octets builder ran out of buffer space.
1096    ShortBuf,
1097}
1098
1099impl BuildDataError {
1100    /// Converts the error into a [`LongOptData`] error for ‘endless’ buffers.
1101    ///
1102    /// # Panics
1103    ///
1104    /// This method will panic if the error is of the `ShortBuf` variant.
1105    pub fn unlimited_buf(self) -> LongOptData {
1106        match self {
1107            Self::LongOptData => LongOptData(()),
1108            Self::ShortBuf => panic!("ShortBuf on unlimited buffer"),
1109        }
1110    }
1111}
1112
1113impl From<LongOptData> for BuildDataError {
1114    fn from(_: LongOptData) -> Self {
1115        Self::LongOptData
1116    }
1117}
1118
1119impl<T: Into<ShortBuf>> From<T> for BuildDataError {
1120    fn from(_: T) -> Self {
1121        Self::ShortBuf
1122    }
1123}
1124
1125//--- Display and Error
1126
1127impl fmt::Display for BuildDataError {
1128    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1129        match self {
1130            Self::LongOptData => f.write_str("long option data"),
1131            Self::ShortBuf => ShortBuf.fmt(f),
1132        }
1133    }
1134}
1135
1136#[cfg(feature = "std")]
1137impl std::error::Error for BuildDataError {}
1138
1139//============ Tests =========================================================
1140
1141#[cfg(test)]
1142#[cfg(all(feature = "std", feature = "bytes"))]
1143pub(super) mod test {
1144    use super::*;
1145    use crate::base::rdata::test::{test_compose_parse, test_rdlen};
1146    use crate::base::record::ParsedRecord;
1147    use crate::base::{opt, MessageBuilder};
1148    use bytes::{Bytes, BytesMut};
1149    use core::fmt::Debug;
1150    use octseq::builder::infallible;
1151    use std::vec::Vec;
1152
1153    #[test]
1154    #[allow(clippy::redundant_closure)] // lifetimes ...
1155    fn opt_compose_parse_scan() {
1156        let rdata = Opt::from_octets("fo\x00\x03foo").unwrap();
1157        test_rdlen(&rdata);
1158        test_compose_parse(&rdata, |parser| Opt::parse(parser));
1159    }
1160
1161    #[test]
1162    fn opt_record_header() {
1163        let mut header = OptHeader::default();
1164        header.set_udp_payload_size(0x1234);
1165        header.set_rcode(OptRcode::BADVERS);
1166        header.set_version(0xbd);
1167        header.set_dnssec_ok(true);
1168        let mut buf = Vec::with_capacity(11);
1169        infallible(header.compose(&mut buf));
1170        infallible(0u16.compose(&mut buf));
1171        let mut buf = Parser::from_ref(buf.as_slice());
1172        let record = ParsedRecord::parse(&mut buf)
1173            .unwrap()
1174            .into_record::<Opt<_>>()
1175            .unwrap()
1176            .unwrap();
1177        let record = OptRecord::from_record(record);
1178        assert_eq!(record.udp_payload_size(), 0x1234);
1179        assert_eq!(record.ext_rcode, OptRcode::BADVERS.ext());
1180        assert_eq!(record.version(), 0xbd);
1181        assert!(record.dnssec_ok());
1182    }
1183
1184    #[test]
1185    fn opt_iter() {
1186        use self::opt::cookie::{ClientCookie, Cookie};
1187
1188        // Push two options and check that both are parseable
1189        let nsid = opt::Nsid::from_octets(&b"example"[..]).unwrap();
1190        let cookie = Cookie::new(
1191            ClientCookie::from_octets(1234u64.to_be_bytes()),
1192            None,
1193        );
1194        let msg = {
1195            let mut mb = MessageBuilder::new_vec().additional();
1196            mb.opt(|mb| {
1197                mb.push(&nsid)?;
1198                mb.push(&cookie)?;
1199                Ok(())
1200            })
1201            .unwrap();
1202            mb.into_message()
1203        };
1204
1205        // Parse both into specialized types
1206        let opt = msg.opt().unwrap();
1207        assert_eq!(Some(Ok(nsid)), opt.opt().iter::<opt::Nsid<_>>().next());
1208        assert_eq!(Some(Ok(cookie)), opt.opt().iter::<opt::Cookie>().next());
1209    }
1210
1211    pub fn test_option_compose_parse<In, F, Out>(data: &In, parse: F)
1212    where
1213        In: ComposeOptData + PartialEq<Out> + Debug,
1214        F: FnOnce(&mut Parser<Bytes>) -> Result<Out, ParseError>,
1215        Out: Debug,
1216    {
1217        let mut buf = BytesMut::new();
1218        infallible(data.compose_option(&mut buf));
1219        let buf = buf.freeze();
1220        assert_eq!(buf.len(), usize::from(data.compose_len()));
1221        let mut parser = Parser::from_ref(&buf);
1222        let parsed = (parse)(&mut parser).unwrap();
1223        assert_eq!(parser.remaining(), 0);
1224        assert_eq!(*data, parsed);
1225    }
1226}