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::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//------------ 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)]
75pub struct Opt<Octs: ?Sized> {
76    octets: Octs,
77}
78
79impl<Octs: AsRef<[u8]>> Opt<Octs> {
80    /// Creates OPT record data from an octets sequence.
81    ///
82    /// The function checks whether the octets contain a sequence of
83    /// options. It does not check whether the options themselves are valid.
84    pub fn from_octets(octets: Octs) -> Result<Self, ParseError> {
85        Opt::check_slice(octets.as_ref())?;
86        Ok(Opt { octets })
87    }
88
89    /// Parses OPT record data from the beginning of a parser.
90    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    /// Creates OPT record data from an octets slice.
100    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    /// Creates OPT record data from an octets slice without checking.
106    ///
107    /// # Safety
108    ///
109    /// The caller needs to ensure that the slice contains correctly encoded
110    /// OPT record data. The data of the options themselves does not need to
111    /// be correct.
112    unsafe fn from_slice_unchecked(slice: &[u8]) -> &Self {
113        &*(slice as *const [u8] as *const Self)
114    }
115
116    /// Checks that the slice contains acceptable OPT record data.
117    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    /// Returns the length of the OPT record data.
133    pub fn len(&self) -> usize {
134        self.octets.as_ref().len()
135    }
136
137    /// Returns whether the OPT record data is empty.
138    pub fn is_empty(&self) -> bool {
139        self.octets.as_ref().is_empty()
140    }
141
142    /// Returns an iterator over options of a given type.
143    ///
144    /// The returned iterator will return only options represented by type
145    /// `D` and quietly skip over all the others.
146    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    /// Returns the first option of a given type if present.
155    ///
156    /// If trying to parse this first option fails, returns `None` as well.
157    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
166//--- OctetsFrom
167
168impl<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
179//--- PartialEq and Eq
180
181impl<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
193//--- PartialOrd and Ord
194
195impl<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
211//--- Hash
212
213impl<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
219//--- RecordData, ParseRecordData, and ComposeRecordData
220
221impl<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
263//--- Display
264
265impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Opt<Octs> {
266    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
267        // XXX TODO Print this properly.
268        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//------------ OptHeader -----------------------------------------------------
281
282/// The header of an OPT record.
283///
284/// The OPT record reappropriates the record header for encoding some
285/// basic information. This type provides access to this information. It
286/// consists of the record header accept for its `rdlen` field.
287///
288/// This is so that `OptBuilder` can safely deref to this type.
289///
290//    +------------+--------------+------------------------------+
291//    | Field Name | Field Type   | Description                  |
292//    +------------+--------------+------------------------------+
293//    | NAME       | domain name  | MUST be 0 (root domain)      |
294//    | TYPE       | u_int16_t    | OPT (41)                     |
295//    | CLASS      | u_int16_t    | requestor's UDP payload size |
296//    | TTL        | u_int32_t    | extended RCODE and flags     |
297//    | RDLEN      | u_int16_t    | length of all RDATA          |
298//    | RDATA      | octet stream | {attribute,value} pairs      |
299//    +------------+--------------+------------------------------+
300#[derive(Copy, Clone, Debug, Eq, PartialEq)]
301pub struct OptHeader {
302    /// The bytes of the header.
303    inner: [u8; 9],
304}
305
306impl OptHeader {
307    /// Returns a reference to an OPT header pointing into a record’s octets.
308    #[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    /// Returns a mutable reference pointing into a record’s octets.
315    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    /// Returns the UDP payload size.
321    ///
322    /// Through this field a sender of a message can signal the maximum size
323    /// of UDP payload the sender is able to handle when receiving messages.
324    /// This value refers to the abilities of the sender’s DNS implementation,
325    /// not such things as network MTUs. Which means that the largest UDP
326    /// payload that can actually be sent back to the sender may be smaller.
327    #[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    /// Sets the UDP payload size value.
333    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    /// Returns the extended rcode.
338    ///
339    /// Some of the bits of the rcode are stored in the regular message
340    /// header. Such a header needs to be passed to the method.
341    #[must_use]
342    pub fn rcode(&self, header: Header) -> OptRcode {
343        OptRcode::from_parts(header.rcode(), self.inner[5])
344    }
345
346    /// Sets the extend rcode of the OPT header.
347    ///
348    /// This method _only_ sets the upper bits of the rcode. The lower bits
349    /// need to be set in the message header.
350    pub fn set_rcode(&mut self, rcode: OptRcode) {
351        self.inner[5] = rcode.ext()
352    }
353
354    /// Returns the EDNS version of the OPT header.
355    ///
356    /// Only EDNS version 0 is currently defined.
357    #[must_use]
358    pub fn version(&self) -> u8 {
359        self.inner[6]
360    }
361
362    /// Sets the EDNS version of the OPT header.
363    pub fn set_version(&mut self, version: u8) {
364        self.inner[6] = version
365    }
366
367    /// Returns the value of the DNSSEC OK (DO) bit.
368    ///
369    /// By setting this bit, a resolver indicates that it is interested in
370    /// also receiving the DNSSEC-related resource records necessary to
371    /// validate an answer. The bit and the related procedures are defined in
372    /// [RFC 3225].
373    ///
374    /// [RFC 3225]: https://tools.ietf.org/html/rfc3225
375    #[must_use]
376    pub fn dnssec_ok(&self) -> bool {
377        self.inner[7] & 0x80 != 0
378    }
379
380    /// Sets the DNSSEC OK (DO) bit to the given value.
381    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//------------ OptRecord -----------------------------------------------------
406
407/// An entire OPT record.
408///
409/// Because the EDNS specificiation uses parts of the header of the OPT record
410/// to convey some information, a special record type is necessary for OPT
411/// records. You can convert a normal record with [`Opt`] record data into
412/// an `OptRecord` via the [`from_record`][OptRecord::from_record] function.
413#[derive(Clone)]
414pub struct OptRecord<Octs> {
415    /// The UDP payload size field from the record header.
416    udp_payload_size: u16,
417
418    /// The extended rcode.
419    ext_rcode: u8,
420
421    /// The EDNS version.
422    version: u8,
423
424    /// The EDNS flags.
425    flags: u16,
426
427    /// The record data.
428    data: Opt<Octs>,
429}
430
431impl<Octs> OptRecord<Octs> {
432    /// Converts a regular record into an OPT record
433    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    /// Returns the UDP payload size.
444    ///
445    /// Through this field a sender of a message can signal the maximum size
446    /// of UDP payload the sender is able to handle when receiving messages.
447    /// This value refers to the abilities of the sender’s DNS implementation,
448    /// not such things as network MTUs. Which means that the largest UDP
449    /// payload that can actually be sent back to the sender may be smaller.
450    pub fn udp_payload_size(&self) -> u16 {
451        self.udp_payload_size
452    }
453
454    /// Returns the extended rcode.
455    ///
456    /// Some of the bits of the rcode are stored in the regular message
457    /// header. Such a header needs to be passed to the method.
458    pub fn rcode(&self, header: Header) -> OptRcode {
459        OptRcode::from_parts(header.rcode(), self.ext_rcode)
460    }
461
462    /// Returns the EDNS version of the OPT header.
463    ///
464    /// Only EDNS version 0 is currently defined.
465    pub fn version(&self) -> u8 {
466        self.version
467    }
468
469    /// Returns the value of the DNSSEC OK (DO) bit.
470    ///
471    /// By setting this bit, a resolver indicates that it is interested in
472    /// also receiving the DNSSEC-related resource records necessary to
473    /// validate an answer. The bit and the related procedures are defined in
474    /// [RFC 3225].
475    ///
476    /// [RFC 3225]: https://tools.ietf.org/html/rfc3225
477    pub fn dnssec_ok(&self) -> bool {
478        self.flags & 0x8000 != 0
479    }
480
481    /// Returns a reference to the raw options.
482    pub fn opt(&self) -> &Opt<Octs> {
483        &self.data
484    }
485}
486
487//--- From
488
489impl<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
495//--- OctetsFrom
496
497impl<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
516//--- AsRef
517
518impl<Octs> AsRef<Opt<Octs>> for OptRecord<Octs> {
519    fn as_ref(&self) -> &Opt<Octs> {
520        &self.data
521    }
522}
523
524//------------ OptionHeader --------------------------------------------------
525
526/// The header of an OPT option.
527///
528/// This header contains a 16 bit option code identifying the kind of option
529/// we are dealing with and a 16 bit length describing the lenngth in octets
530/// of the option data.
531#[derive(Clone, Copy, Debug)]
532pub struct OptionHeader {
533    /// The option code.
534    code: u16,
535
536    /// The length of the option’s data in octets.
537    len: u16,
538}
539
540#[allow(clippy::len_without_is_empty)]
541impl OptionHeader {
542    /// Creates a new option header from code and length.
543    #[must_use]
544    pub fn new(code: u16, len: u16) -> Self {
545        OptionHeader { code, len }
546    }
547
548    /// Returns the option code.
549    #[must_use]
550    pub fn code(self) -> u16 {
551        self.code
552    }
553
554    /// Returns the length of the option data.
555    #[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//------------ OptIter -------------------------------------------------------
571
572/// An iterator over the options of an OPT record.
573///
574/// The iterator is generic over a specific option type. It skips over all
575/// options that this type does not want to parse. It returns a result that
576/// is either a parsed option or a parse error. These errors are only for the
577/// particular option. After such an error you can continue to iterate until
578/// `None` indicates that you’ve reached the end of the record.
579#[derive(Clone, Debug)]
580pub struct OptIter<'a, Octs: ?Sized, D> {
581    /// A parser for the OPT record data.
582    parser: Parser<'a, Octs>,
583
584    /// The marker to remember which record data we use.
585    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    /// Creates an iterator from a reference to the OPT record data.
594    fn new(octets: &'a Octs) -> Self {
595        OptIter {
596            parser: Parser::from_ref(octets),
597            marker: PhantomData,
598        }
599    }
600
601    /// Returns the next item from the parser.
602    ///
603    /// Expects there to be another option available and will return a
604    /// parse error otherwise. Return `Ok(None)` if the option type didn’t
605    /// want to parse this option.
606    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                    // Advance to end so we’ll return None from now on.
634                    self.parser.advance_to_end();
635                    return Some(Err(err));
636                }
637            }
638        }
639        None
640    }
641}
642
643//------------ OptData -------------------------------------------------------
644
645/// A type representing an OPT option.
646///
647/// The type needs to be able to report the option code to use for the
648/// encoding via the [`code`][Self::code] method.
649pub trait OptData {
650    /// Returns the option code associated with this option.
651    fn code(&self) -> OptionCode;
652}
653
654//------------ ParseOptData --------------------------------------------------
655
656/// An OPT option that can be parsed from the record data.
657pub trait ParseOptData<'a, Octs: ?Sized>: OptData + Sized {
658    /// Parses the option code data.
659    ///
660    /// The data is for an option of `code`. The function may decide whether
661    /// it wants to parse data for that type. It should return `Ok(None)` if
662    /// it doesn’t.
663    ///
664    /// The `parser` is positioned at the beginning of the option data and is
665    /// is limited to the length of the data. The method only needs to parse
666    /// as much data as it needs. The caller has to make sure to deal with
667    /// data remaining in the parser.
668    ///
669    /// If the function doesn’t want to process the data, it must not touch
670    /// the parser. In particual, it must not advance it.
671    fn parse_option(
672        code: OptionCode,
673        parser: &mut Parser<'a, Octs>,
674    ) -> Result<Option<Self>, ParseError>;
675}
676
677//------------ ComposeOptData ------------------------------------------------
678
679/// An OPT option that can be written to wire format.
680pub 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//------------ UnknownOptData ------------------------------------------------
690
691/// An OPT option in its raw form.
692///
693/// This type accepts any option type via its option code and raw data.
694#[derive(Clone, Debug)]
695pub struct UnknownOptData<Octs> {
696    /// The option code for the option.
697    code: OptionCode,
698
699    /// The raw option data.
700    data: Octs,
701}
702
703impl<Octs> UnknownOptData<Octs> {
704    /// Creates a new option from the code and data.
705    ///
706    /// The function returns an error if `data` is longer than 65,535 octets.
707    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    /// Creates a new option data value without checking.
716    ///
717    /// # Safety
718    ///
719    /// The caller needs to make sure that `data` is not longer than 65,535
720    /// octets.
721    pub unsafe fn new_unchecked(code: OptionCode, data: Octs) -> Self {
722        Self { code, data }
723    }
724
725    /// Returns the option code of the option.
726    pub fn code(&self) -> OptionCode {
727        self.code
728    }
729
730    /// Returns a reference for to the option data.
731    pub fn data(&self) -> &Octs {
732        &self.data
733    }
734
735    /// Returns a slice of the option data.
736    pub fn as_slice(&self) -> &[u8]
737    where
738        Octs: AsRef<[u8]>,
739    {
740        self.data.as_ref()
741    }
742
743    /// Returns a mutable slice of the option data.
744    pub fn as_slice_mut(&mut self) -> &mut [u8]
745    where
746        Octs: AsMut<[u8]>,
747    {
748        self.data.as_mut()
749    }
750}
751
752//--- AsRef and AsMut
753
754impl<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
772//--- OptData etc.
773
774impl<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
811//--- Display
812
813impl<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//============ Error Types ===================================================
820
821//------------ LongOptData ---------------------------------------------------
822
823/// The octets sequence to be used for option data is too long.
824#[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//------------ BuildDataError ------------------------------------------------
858
859/// An error happened while constructing an SVCB value.
860#[derive(Clone, Copy, Debug, Eq, PartialEq)]
861pub enum BuildDataError {
862    /// The value would exceed the allow length of a value.
863    LongOptData,
864
865    /// The underlying octets builder ran out of buffer space.
866    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
881//--- Display and Error
882
883impl 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//============ Tests =========================================================
896
897#[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)] // lifetimes ...
912    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        // Push two options and check that both are parseable
946        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        // Parse both into specialized types
963        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}