Skip to main content

hickory_proto/rr/rdata/
opt.rs

1// Copyright 2015-2023 Benjamin Fry <benjaminfry@me.com>
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// https://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// https://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! option record for passing protocol options between the client and server
9#![allow(clippy::use_self)]
10
11use alloc::vec::Vec;
12use core::fmt;
13use core::hash::{Hash, Hasher};
14use core::net::{IpAddr, Ipv4Addr, Ipv6Addr};
15use core::str::FromStr;
16
17#[cfg(feature = "serde")]
18use serde::{Deserialize, Serialize};
19use tracing::warn;
20
21use crate::{
22    error::{ProtoError, ProtoResult},
23    rr::{RData, RecordData, RecordDataDecodable, RecordType},
24    serialize::binary::{
25        BinDecodable, BinDecoder, BinEncodable, BinEncoder, DecodeError, RDataEncoding, Restrict,
26    },
27};
28
29#[cfg(feature = "__dnssec")]
30use crate::dnssec::SupportedAlgorithms;
31
32/// The OPT record type is used for ExtendedDNS records.
33///
34/// These allow for additional information to be associated with the DNS request that otherwise
35/// would require changes to the DNS protocol.
36///
37/// Multiple options with the same code are allowed to appear in this record
38///
39/// [RFC 6891, EDNS(0) Extensions, April 2013](https://tools.ietf.org/html/rfc6891#section-6)
40///
41/// ```text
42/// 6.1.  OPT Record Definition
43///
44/// 6.1.1.  Basic Elements
45///
46///    An OPT pseudo-RR (sometimes called a meta-RR) MAY be added to the
47///    additional data section of a request.
48///
49///    The OPT RR has RR type 41.
50///
51///    If an OPT record is present in a received request, compliant
52///    responders MUST include an OPT record in their respective responses.
53///
54///    An OPT record does not carry any DNS data.  It is used only to
55///    contain control information pertaining to the question-and-answer
56///    sequence of a specific transaction.  OPT RRs MUST NOT be cached,
57///    forwarded, or stored in or loaded from Zone Files.
58///
59///    The OPT RR MAY be placed anywhere within the additional data section.
60///    When an OPT RR is included within any DNS message, it MUST be the
61///    only OPT RR in that message.  If a query message with more than one
62///    OPT RR is received, a FORMERR (RCODE=1) MUST be returned.  The
63///    placement flexibility for the OPT RR does not override the need for
64///    the TSIG or SIG(0) RRs to be the last in the additional section
65///    whenever they are present.
66///
67/// 6.1.2.  Wire Format
68///
69///    An OPT RR has a fixed part and a variable set of options expressed as
70///    {attribute, value} pairs.  The fixed part holds some DNS metadata,
71///    and also a small collection of basic extension elements that we
72///    expect to be so popular that it would be a waste of wire space to
73///    encode them as {attribute, value} pairs.
74///
75///    The fixed part of an OPT RR is structured as follows:
76///
77///        +------------+--------------+------------------------------+
78///        | Field Name | Field Type   | Description                  |
79///        +------------+--------------+------------------------------+
80///        | NAME       | domain name  | MUST be 0 (root domain)      |
81///        | TYPE       | u_int16_t    | OPT (41)                     |
82///        | CLASS      | u_int16_t    | requestor's UDP payload size |
83///        | TTL        | u_int32_t    | extended RCODE and flags     |
84///        | RDLEN      | u_int16_t    | length of all RDATA          |
85///        | RDATA      | octet stream | {attribute,value} pairs      |
86///        +------------+--------------+------------------------------+
87///
88///                                OPT RR Format
89///
90///    The variable part of an OPT RR may contain zero or more options in
91///    the RDATA.  Each option MUST be treated as a bit field.  Each option
92///    is encoded as:
93///
94///                   +0 (MSB)                            +1 (LSB)
95///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
96///     0: |                          OPTION-CODE                          |
97///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
98///     2: |                         OPTION-LENGTH                         |
99///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
100///     4: |                                                               |
101///        /                          OPTION-DATA                          /
102///        /                                                               /
103///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
104///
105///    OPTION-CODE
106///       Assigned by the Expert Review process as defined by the DNSEXT
107///       working group and the IESG.
108///
109///    OPTION-LENGTH
110///       Size (in octets) of OPTION-DATA.
111///
112///    OPTION-DATA
113///       Varies per OPTION-CODE.  MUST be treated as a bit field.
114///
115///    The order of appearance of option tuples is not defined.  If one
116///    option modifies the behaviour of another or multiple options are
117///    related to one another in some way, they have the same effect
118///    regardless of ordering in the RDATA wire encoding.
119///
120///    Any OPTION-CODE values not understood by a responder or requestor
121///    MUST be ignored.  Specifications of such options might wish to
122///    include some kind of signaled acknowledgement.  For example, an
123///    option specification might say that if a responder sees and supports
124///    option XYZ, it MUST include option XYZ in its response.
125///
126/// 6.1.3.  OPT Record TTL Field Use
127///
128///    The extended RCODE and flags, which OPT stores in the RR Time to Live
129///    (TTL) field, are structured as follows:
130///
131///                   +0 (MSB)                            +1 (LSB)
132///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
133///     0: |         EXTENDED-RCODE        |            VERSION            |
134///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
135///     2: | DO|                           Z                               |
136///        +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
137///
138///    EXTENDED-RCODE
139///       Forms the upper 8 bits of extended 12-bit RCODE (together with the
140///       4 bits defined in [RFC1035].  Note that EXTENDED-RCODE value 0
141///       indicates that an unextended RCODE is in use (values 0 through
142///       15).
143///
144///    VERSION
145///       Indicates the implementation level of the setter.  Full
146///       conformance with this specification is indicated by version '0'.
147///       Requestors are encouraged to set this to the lowest implemented
148///       level capable of expressing a transaction, to minimise the
149///       responder and network load of discovering the greatest common
150///       implementation level between requestor and responder.  A
151///       requestor's version numbering strategy MAY ideally be a run-time
152///       configuration option.
153///       If a responder does not implement the VERSION level of the
154///       request, then it MUST respond with RCODE=BADVERS.  All responses
155///       MUST be limited in format to the VERSION level of the request, but
156///       the VERSION of each response SHOULD be the highest implementation
157///       level of the responder.  In this way, a requestor will learn the
158///       implementation level of a responder as a side effect of every
159///       response, including error responses and including RCODE=BADVERS.
160///
161/// 6.1.4.  Flags
162///
163///    DO
164///       DNSSEC OK bit as defined by [RFC3225].
165///
166///    Z
167///       Set to zero by senders and ignored by receivers, unless modified
168///       in a subsequent specification.
169/// ```
170#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
171#[derive(Default, Debug, Clone, Ord, PartialOrd)]
172#[non_exhaustive]
173pub struct OPT {
174    /// List of code and record type tuples
175    pub options: Vec<(EdnsCode, EdnsOption)>,
176}
177
178impl OPT {
179    /// Creates a new OPT record data.
180    ///
181    /// # Arguments
182    ///
183    /// * `options` - List of code and record type tuples
184    ///
185    /// # Return value
186    ///
187    /// The newly created OPT data
188    pub fn new(options: Vec<(EdnsCode, EdnsOption)>) -> Self {
189        Self { options }
190    }
191
192    /// Get a single option based on the code
193    pub fn get(&self, code: EdnsCode) -> Option<&EdnsOption> {
194        self.options
195            .iter()
196            .find_map(|(c, option)| if code == *c { Some(option) } else { None })
197    }
198
199    /// Get all options based on the code
200    pub fn get_all(&self, code: EdnsCode) -> Vec<&EdnsOption> {
201        self.options
202            .iter()
203            .filter_map(|(c, option)| if code == *c { Some(option) } else { None })
204            .collect()
205    }
206
207    /// Insert a new option, the key is derived from the `EdnsOption`
208    pub fn insert(&mut self, option: EdnsOption) {
209        self.options.push(((&option).into(), option));
210    }
211
212    /// Removes all options based on the code
213    pub fn remove(&mut self, option: EdnsCode) {
214        self.options.retain(|(c, _)| *c != option)
215    }
216}
217
218impl PartialEq for OPT {
219    fn eq(&self, other: &Self) -> bool {
220        let matching_elements_count = self
221            .options
222            .iter()
223            .filter(|entry| other.options.contains(entry))
224            .count();
225        matching_elements_count == self.options.len()
226            && matching_elements_count == other.options.len()
227    }
228}
229
230impl Eq for OPT {}
231
232impl Hash for OPT {
233    fn hash<H: Hasher>(&self, state: &mut H) {
234        let mut sorted = self.options.clone();
235        sorted.sort();
236        sorted.hash(state);
237    }
238}
239
240impl AsMut<Vec<(EdnsCode, EdnsOption)>> for OPT {
241    fn as_mut(&mut self) -> &mut Vec<(EdnsCode, EdnsOption)> {
242        &mut self.options
243    }
244}
245
246impl AsRef<[(EdnsCode, EdnsOption)]> for OPT {
247    fn as_ref(&self) -> &[(EdnsCode, EdnsOption)] {
248        &self.options
249    }
250}
251
252impl BinEncodable for OPT {
253    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
254        let mut encoder = encoder.with_rdata_behavior(RDataEncoding::Other);
255        for (edns_code, edns_option) in self.as_ref().iter() {
256            encoder.emit_u16(u16::from(*edns_code))?;
257            encoder.emit_u16(edns_option.len())?;
258            edns_option.emit(&mut encoder)?
259        }
260        Ok(())
261    }
262}
263
264impl<'r> RecordDataDecodable<'r> for OPT {
265    fn read_data(decoder: &mut BinDecoder<'r>, length: Restrict<u16>) -> Result<Self, DecodeError> {
266        let mut state: OptReadState = OptReadState::ReadCode;
267        let mut options: Vec<(EdnsCode, EdnsOption)> = Vec::new();
268        let start_idx = decoder.index();
269
270        // There is no unsafe direct use of the rdata length after this point
271        let rdata_length = length.map(|u| u as usize).unverified(/*rdata length usage is bounded*/);
272        while rdata_length > decoder.index() - start_idx {
273            match state {
274                OptReadState::ReadCode => {
275                    state = OptReadState::Code {
276                        code: EdnsCode::from(
277                            decoder.read_u16()?.unverified(/*EdnsCode is verified as safe*/),
278                        ),
279                    };
280                }
281                OptReadState::Code { code } => {
282                    let length = decoder
283                        .read_u16()?
284                        .map(|u| u as usize)
285                        .verify_unwrap(|u| *u <= rdata_length)
286                        .map_err(|opt_len| DecodeError::IncorrectRDataLengthRead {
287                            read: rdata_length,
288                            len: opt_len,
289                        })?;
290                    // If we know that the length is 0, we can avoid the `OptReadState::Data` state
291                    // and directly add the option to the map.
292                    // The data state does not process 0-length correctly, since it always reads at
293                    // least 1 byte, thus making the length check fail.
294                    state = if length == 0 {
295                        options.push((code, (code, &[] as &[u8]).try_into()?));
296                        OptReadState::ReadCode
297                    } else {
298                        OptReadState::Data {
299                            code,
300                            length,
301                            // TODO: this can be replaced with decoder.read_vec(), right?
302                            //  the current version allows for malformed opt to be skipped...
303                            collected: Vec::<u8>::with_capacity(length),
304                        }
305                    };
306                }
307                OptReadState::Data {
308                    code,
309                    length,
310                    mut collected,
311                } => {
312                    // TODO: can this be replaced by read_slice()?
313                    collected.push(decoder.pop()?.unverified(/*byte array is safe*/));
314                    if length == collected.len() {
315                        options.push((code, (code, &collected as &[u8]).try_into()?));
316                        state = OptReadState::ReadCode;
317                    } else {
318                        state = OptReadState::Data {
319                            code,
320                            length,
321                            collected,
322                        };
323                    }
324                }
325            }
326        }
327
328        if state != OptReadState::ReadCode {
329            // there was some problem parsing the data for the options, ignoring them
330            // TODO: should we ignore all of the EDNS data in this case?
331            warn!("incomplete or poorly formatted EDNS options: {:?}", state);
332            options.clear();
333        }
334
335        // the record data is stored as unstructured data, the expectation is that this will be processed after initial parsing.
336        Ok(Self::new(options))
337    }
338}
339
340impl RecordData for OPT {
341    fn try_borrow(data: &RData) -> Option<&Self> {
342        match data {
343            RData::OPT(csync) => Some(csync),
344            _ => None,
345        }
346    }
347
348    fn record_type(&self) -> RecordType {
349        RecordType::OPT
350    }
351
352    fn into_rdata(self) -> RData {
353        RData::OPT(self)
354    }
355}
356
357impl fmt::Display for OPT {
358    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
359        fmt::Debug::fmt(self, f)
360    }
361}
362
363#[derive(Debug, PartialEq, Eq)]
364enum OptReadState {
365    ReadCode,
366    Code {
367        code: EdnsCode,
368    }, // expect LSB for the opt code, store the high byte
369    Data {
370        code: EdnsCode,
371        length: usize,
372        collected: Vec<u8>,
373    }, // expect the data for the option
374}
375
376/// The code of the EDNS data option
377#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
378#[derive(Hash, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
379#[non_exhaustive]
380pub enum EdnsCode {
381    /// [RFC 6891, Reserved](https://tools.ietf.org/html/rfc6891)
382    Zero,
383
384    /// [RFC 8764, Apple's Long-Lived Queries, Optional](https://tools.ietf.org/html/rfc8764)
385    LLQ,
386
387    /// [UL On-hold](https://files.dns-sd.org/draft-sekar-dns-ul.txt)
388    UL,
389
390    /// [RFC 5001, NSID](https://tools.ietf.org/html/rfc5001)
391    NSID,
392    // 4 Reserved [draft-cheshire-edns0-owner-option] -EXPIRED-
393    /// [RFC 6975, DNSSEC Algorithm Understood](https://tools.ietf.org/html/rfc6975)
394    DAU,
395
396    /// [RFC 6975, DS Hash Understood](https://tools.ietf.org/html/rfc6975)
397    DHU,
398
399    /// [RFC 6975, NSEC3 Hash Understood](https://tools.ietf.org/html/rfc6975)
400    N3U,
401
402    /// [RFC 7871, Client Subnet, Optional](https://tools.ietf.org/html/rfc7871)
403    Subnet,
404
405    /// [RFC 7314, EDNS EXPIRE, Optional](https://tools.ietf.org/html/rfc7314)
406    Expire,
407
408    /// [RFC 7873, DNS Cookies](https://tools.ietf.org/html/rfc7873)
409    Cookie,
410
411    /// [RFC 7828, edns-tcp-keepalive](https://tools.ietf.org/html/rfc7828)
412    Keepalive,
413
414    /// [RFC 7830, The EDNS(0) Padding](https://tools.ietf.org/html/rfc7830)
415    Padding,
416
417    /// [RFC 7901, CHAIN Query Requests in DNS, Optional](https://tools.ietf.org/html/rfc7901)
418    Chain,
419
420    /// Unknown, used to deal with unknown or unsupported codes
421    Unknown(u16),
422}
423
424// TODO: implement a macro to perform these inversions
425impl From<u16> for EdnsCode {
426    fn from(value: u16) -> Self {
427        match value {
428            0 => Self::Zero,
429            1 => Self::LLQ,
430            2 => Self::UL,
431            3 => Self::NSID,
432            // 4 Reserved [draft-cheshire-edns0-owner-option] -EXPIRED-
433            5 => Self::DAU,
434            6 => Self::DHU,
435            7 => Self::N3U,
436            8 => Self::Subnet,
437            9 => Self::Expire,
438            10 => Self::Cookie,
439            11 => Self::Keepalive,
440            12 => Self::Padding,
441            13 => Self::Chain,
442            _ => Self::Unknown(value),
443        }
444    }
445}
446
447impl From<EdnsCode> for u16 {
448    fn from(value: EdnsCode) -> Self {
449        match value {
450            EdnsCode::Zero => 0,
451            EdnsCode::LLQ => 1,
452            EdnsCode::UL => 2,
453            EdnsCode::NSID => 3,
454            // 4 Reserved [draft-cheshire-edns0-owner-option] -EXPIRED-
455            EdnsCode::DAU => 5,
456            EdnsCode::DHU => 6,
457            EdnsCode::N3U => 7,
458            EdnsCode::Subnet => 8,
459            EdnsCode::Expire => 9,
460            EdnsCode::Cookie => 10,
461            EdnsCode::Keepalive => 11,
462            EdnsCode::Padding => 12,
463            EdnsCode::Chain => 13,
464            EdnsCode::Unknown(value) => value,
465        }
466    }
467}
468
469/// options used to pass information about capabilities between client and server
470///
471/// `note: Not all EdnsOptions are supported at this time.`
472///
473/// <https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-13>
474#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
475#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Hash, Ord)]
476#[non_exhaustive]
477pub enum EdnsOption {
478    /// [RFC 6975, DNSSEC Algorithm Understood](https://tools.ietf.org/html/rfc6975)
479    #[cfg(feature = "__dnssec")]
480    DAU(SupportedAlgorithms),
481
482    /// [RFC 7871, Client Subnet, Optional](https://tools.ietf.org/html/rfc7871)
483    Subnet(ClientSubnet),
484
485    /// [RFC 5001, DNS Name Server Identifier (NSID) Option](https://tools.ietf.org/html/rfc5001)
486    NSID(NSIDPayload),
487
488    /// Unknown, used to deal with unknown or unsupported codes
489    Unknown(u16, Vec<u8>),
490}
491
492impl EdnsOption {
493    /// Returns the length in bytes of the EdnsOption
494    pub fn len(&self) -> u16 {
495        match self {
496            #[cfg(feature = "__dnssec")]
497            EdnsOption::DAU(algorithms) => algorithms.len(),
498            EdnsOption::Subnet(subnet) => subnet.len(),
499            EdnsOption::NSID(payload) => payload.as_ref().len() as u16, // cast safety: NSIDPayload size is constrained.
500            EdnsOption::Unknown(_, data) => data.len() as u16,          // TODO: should we verify?
501        }
502    }
503
504    /// Returns `true` if the length in bytes of the EdnsOption is 0
505    pub fn is_empty(&self) -> bool {
506        match self {
507            #[cfg(feature = "__dnssec")]
508            EdnsOption::DAU(algorithms) => algorithms.is_empty(),
509            EdnsOption::Subnet(subnet) => subnet.is_empty(),
510            EdnsOption::NSID(payload) => payload.as_ref().is_empty(),
511            EdnsOption::Unknown(_, data) => data.is_empty(),
512        }
513    }
514}
515
516impl BinEncodable for EdnsOption {
517    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
518        match self {
519            #[cfg(feature = "__dnssec")]
520            EdnsOption::DAU(algorithms) => algorithms.emit(encoder),
521            EdnsOption::Subnet(subnet) => subnet.emit(encoder),
522            EdnsOption::NSID(payload) => encoder.emit_vec(payload.as_ref()),
523            EdnsOption::Unknown(_, data) => encoder.emit_vec(data), // gah, clone needed or make a crazy api.
524        }
525    }
526}
527
528/// only the supported extensions are listed right now.
529impl<'a> TryFrom<(EdnsCode, &'a [u8])> for EdnsOption {
530    type Error = DecodeError;
531
532    fn try_from(value: (EdnsCode, &'a [u8])) -> Result<Self, Self::Error> {
533        Ok(match value.0 {
534            #[cfg(feature = "__dnssec")]
535            EdnsCode::DAU => Self::DAU(value.1.into()),
536            EdnsCode::Subnet => Self::Subnet(value.1.try_into()?),
537            EdnsCode::NSID => Self::NSID(value.1.try_into()?),
538            _ => Self::Unknown(value.0.into(), value.1.to_vec()),
539        })
540    }
541}
542
543impl<'a> TryFrom<&'a EdnsOption> for Vec<u8> {
544    type Error = ProtoError;
545
546    fn try_from(value: &'a EdnsOption) -> Result<Self, Self::Error> {
547        Ok(match value {
548            #[cfg(feature = "__dnssec")]
549            EdnsOption::DAU(algorithms) => algorithms.into(),
550            EdnsOption::Subnet(subnet) => subnet.try_into()?,
551            EdnsOption::NSID(payload) => payload.as_ref().to_vec(),
552            EdnsOption::Unknown(_, data) => data.clone(), // gah, clone needed or make a crazy api.
553        })
554    }
555}
556
557impl<'a> From<&'a EdnsOption> for EdnsCode {
558    fn from(value: &'a EdnsOption) -> Self {
559        match value {
560            #[cfg(feature = "__dnssec")]
561            EdnsOption::DAU(..) => Self::DAU,
562            EdnsOption::Subnet(..) => Self::Subnet,
563            EdnsOption::NSID(..) => Self::NSID,
564            EdnsOption::Unknown(code, _) => (*code).into(),
565        }
566    }
567}
568
569/// [RFC 7871, Client Subnet, Optional](https://tools.ietf.org/html/rfc7871)
570///
571/// ```text
572/// +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
573/// 0: |                            FAMILY                             |
574///    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
575/// 2: |     SOURCE PREFIX-LENGTH      |     SCOPE PREFIX-LENGTH       |
576///    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
577/// 4: |                           ADDRESS...                          /
578///    +---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+---+
579///
580/// o  FAMILY, 2 octets, indicates the family of the address contained in
581///    the option, using address family codes as assigned by IANA in
582///    Address Family Numbers [Address_Family_Numbers].
583/// o  SOURCE PREFIX-LENGTH, an unsigned octet representing the leftmost
584///    number of significant bits of ADDRESS to be used for the lookup.
585///    In responses, it mirrors the same value as in the queries.
586/// o  SCOPE PREFIX-LENGTH, an unsigned octet representing the leftmost
587///    number of significant bits of ADDRESS that the response covers.
588///    In queries, it MUST be set to 0.
589/// o  ADDRESS, variable number of octets, contains either an IPv4 or
590///    IPv6 address, depending on FAMILY, which MUST be truncated to the
591///    number of bits indicated by the SOURCE PREFIX-LENGTH field,
592///    padding with 0 bits to pad to the end of the last octet needed.
593/// o  A server receiving an ECS option that uses either too few or too
594///    many ADDRESS octets, or that has non-zero ADDRESS bits set beyond
595///    SOURCE PREFIX-LENGTH, SHOULD return FORMERR to reject the packet,
596///    as a signal to the software developer making the request to fix
597///    their implementation.
598/// ```
599#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
600#[derive(Debug, PartialOrd, PartialEq, Eq, Clone, Copy, Hash, Ord)]
601pub struct ClientSubnet {
602    address: IpAddr,
603    source_prefix: u8,
604    scope_prefix: u8,
605}
606
607impl ClientSubnet {
608    /// Construct a new EcsOption with the address, source_prefix and scope_prefix.
609    pub fn new(address: IpAddr, source_prefix: u8, scope_prefix: u8) -> Self {
610        Self {
611            address,
612            source_prefix,
613            scope_prefix,
614        }
615    }
616
617    /// Returns the length in bytes of the EdnsOption
618    pub fn len(&self) -> u16 {
619        // FAMILY: 2 octets
620        // SOURCE PREFIX-LENGTH: 1 octets
621        // SCOPE PREFIX-LENGTH: 1 octets
622        // ADDRESS: runcated to the number of bits indicated by the SOURCE PREFIX-LENGTH field
623        2 + 1 + 1 + self.addr_len()
624    }
625
626    /// Returns `true` if the length in bytes of the EcsOption is 0
627    #[inline]
628    pub fn is_empty(&self) -> bool {
629        false
630    }
631
632    /// returns the ip address
633    pub fn addr(&self) -> IpAddr {
634        self.address
635    }
636
637    /// set the ip address
638    pub fn set_addr(&mut self, addr: IpAddr) {
639        self.address = addr;
640    }
641
642    /// returns the source prefix
643    pub fn source_prefix(&self) -> u8 {
644        self.source_prefix
645    }
646
647    /// returns the source prefix
648    pub fn set_source_prefix(&mut self, source_prefix: u8) {
649        self.source_prefix = source_prefix;
650    }
651
652    /// returns the scope prefix
653    pub fn scope_prefix(&self) -> u8 {
654        self.scope_prefix
655    }
656    /// returns the scope prefix
657    pub fn set_scope_prefix(&mut self, scope_prefix: u8) {
658        self.scope_prefix = scope_prefix;
659    }
660
661    fn addr_len(&self) -> u16 {
662        let source_prefix = self.source_prefix as u16;
663        source_prefix / 8
664            + if !source_prefix.is_multiple_of(8) {
665                1
666            } else {
667                0
668            }
669    }
670}
671
672impl BinEncodable for ClientSubnet {
673    fn emit(&self, encoder: &mut BinEncoder<'_>) -> ProtoResult<()> {
674        let address = self.address;
675        let source_prefix = self.source_prefix;
676        let scope_prefix = self.scope_prefix;
677
678        let addr_len = self.addr_len();
679
680        match address {
681            IpAddr::V4(ip) => {
682                encoder.emit_u16(1)?; // FAMILY: IPv4
683                encoder.emit_u8(source_prefix)?;
684                encoder.emit_u8(scope_prefix)?;
685                let octets = ip.octets();
686                let addr_len = addr_len as usize;
687                if addr_len <= octets.len() {
688                    encoder.emit_vec(&octets[0..addr_len])?
689                } else {
690                    return Err(ProtoError::Message(
691                        "Invalid addr length for encode EcsOption",
692                    ));
693                }
694            }
695            IpAddr::V6(ip) => {
696                encoder.emit_u16(2)?; // FAMILY: IPv6
697                encoder.emit_u8(source_prefix)?;
698                encoder.emit_u8(scope_prefix)?;
699                let octets = ip.octets();
700                let addr_len = addr_len as usize;
701                if addr_len <= octets.len() {
702                    encoder.emit_vec(&octets[0..addr_len])?
703                } else {
704                    return Err(ProtoError::Message(
705                        "Invalid addr length for encode EcsOption",
706                    ));
707                }
708            }
709        }
710        Ok(())
711    }
712}
713
714impl<'a> BinDecodable<'a> for ClientSubnet {
715    fn read(decoder: &mut BinDecoder<'a>) -> Result<Self, DecodeError> {
716        let family = decoder.read_u16()?.unverified();
717
718        match family {
719            1 => {
720                // ipv4
721                let source_prefix = decoder.read_u8()?.unverified();
722                let scope_prefix = decoder.read_u8()?.unverified();
723                let addr_len =
724                    (source_prefix / 8 + if source_prefix % 8 > 0 { 1 } else { 0 }) as usize;
725                let mut octets = Ipv4Addr::UNSPECIFIED.octets();
726                if addr_len > octets.len() {
727                    return Err(DecodeError::IncorrectRDataLengthRead {
728                        read: octets.len(),
729                        len: addr_len,
730                    });
731                }
732                for octet in octets.iter_mut().take(addr_len) {
733                    *octet = decoder.read_u8()?.unverified();
734                }
735                Ok(Self {
736                    address: IpAddr::from(octets),
737                    source_prefix,
738                    scope_prefix,
739                })
740            }
741            2 => {
742                // ipv6
743                let source_prefix = decoder.read_u8()?.unverified();
744                let scope_prefix = decoder.read_u8()?.unverified();
745                let addr_len =
746                    (source_prefix / 8 + if source_prefix % 8 > 0 { 1 } else { 0 }) as usize;
747                let mut octets = Ipv6Addr::UNSPECIFIED.octets();
748                if addr_len > octets.len() {
749                    return Err(DecodeError::IncorrectRDataLengthRead {
750                        read: octets.len(),
751                        len: addr_len,
752                    });
753                }
754                for octet in octets.iter_mut().take(addr_len) {
755                    *octet = decoder.read_u8()?.unverified();
756                }
757
758                Ok(Self {
759                    address: IpAddr::from(octets),
760                    source_prefix,
761                    scope_prefix,
762                })
763            }
764            _ => Err(DecodeError::UnknownAddressFamily(family)),
765        }
766    }
767}
768
769impl<'a> TryFrom<&'a ClientSubnet> for Vec<u8> {
770    type Error = ProtoError;
771
772    fn try_from(value: &'a ClientSubnet) -> Result<Self, Self::Error> {
773        let mut bytes = Self::with_capacity(value.len() as usize); // today this is less than 8
774        let mut encoder = BinEncoder::new(&mut bytes);
775        value.emit(&mut encoder)?;
776        bytes.shrink_to_fit();
777        Ok(bytes)
778    }
779}
780
781impl<'a> TryFrom<&'a [u8]> for ClientSubnet {
782    type Error = DecodeError;
783
784    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
785        let mut decoder = BinDecoder::new(value);
786        Self::read(&mut decoder)
787    }
788}
789
790impl From<ipnet::IpNet> for ClientSubnet {
791    fn from(net: ipnet::IpNet) -> Self {
792        Self {
793            address: net.addr(),
794            source_prefix: net.prefix_len(),
795            scope_prefix: Default::default(),
796        }
797    }
798}
799
800impl FromStr for ClientSubnet {
801    type Err = ipnet::AddrParseError;
802
803    fn from_str(s: &str) -> Result<Self, Self::Err> {
804        ipnet::IpNet::from_str(s).map(ClientSubnet::from)
805    }
806}
807
808/// A raw binary NSID payload
809///
810/// Constrained to u16::MAX bytes.
811#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
812#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
813pub struct NSIDPayload(Vec<u8>);
814
815impl NSIDPayload {
816    /// Construct a new NSID payload from the provided binary data
817    ///
818    /// A `ProtoError` is returned if the provided data is too large to be
819    /// expressed as an EDNS option value.
820    pub fn new(data: impl Into<Vec<u8>>) -> Result<Self, ProtoError> {
821        let data = data.into();
822        if data.len() > u16::MAX as usize {
823            return Err(ProtoError::from("NSID EDNS payload too large"));
824        }
825        Ok(Self(data))
826    }
827}
828
829impl<'a> TryFrom<&'a [u8]> for NSIDPayload {
830    type Error = DecodeError;
831
832    fn try_from(value: &'a [u8]) -> Result<Self, Self::Error> {
833        if value.len() > u16::MAX as usize {
834            return Err(DecodeError::IncorrectRDataLengthRead {
835                read: value.len(),
836                len: u16::MAX as usize,
837            });
838        }
839        Ok(Self(value.to_vec()))
840    }
841}
842
843impl AsRef<[u8]> for NSIDPayload {
844    fn as_ref(&self) -> &[u8] {
845        &self.0
846    }
847}
848
849#[cfg(test)]
850mod tests {
851    #![allow(clippy::dbg_macro, clippy::print_stdout)]
852
853    use core::hash::{Hash, Hasher};
854    #[cfg(feature = "std")]
855    use std::{hash::DefaultHasher, println};
856
857    use super::*;
858
859    #[test]
860    #[cfg(feature = "__dnssec")]
861    fn test() {
862        let mut rdata = OPT::default();
863        rdata.insert(EdnsOption::DAU(SupportedAlgorithms::all()));
864
865        let mut bytes = Vec::new();
866        let mut encoder: BinEncoder<'_> = BinEncoder::new(&mut bytes);
867        assert!(rdata.emit(&mut encoder).is_ok());
868        let bytes = encoder.into_bytes();
869
870        #[cfg(feature = "std")]
871        println!("bytes: {bytes:?}");
872
873        let mut decoder: BinDecoder<'_> = BinDecoder::new(bytes);
874        let restrict = Restrict::new(bytes.len() as u16);
875        let read_rdata = OPT::read_data(&mut decoder, restrict).expect("Decoding error");
876        assert_eq!(rdata, read_rdata);
877    }
878
879    #[test]
880    fn test_read_empty_option_at_end_of_opt() {
881        let bytes: Vec<u8> = vec![
882            0x00, 0x0a, 0x00, 0x08, 0x0b, 0x64, 0xb4, 0xdc, 0xd7, 0xb0, 0xcc, 0x8f, 0x00, 0x08,
883            0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00,
884        ];
885
886        let mut decoder: BinDecoder<'_> = BinDecoder::new(&bytes);
887        let read_rdata = OPT::read_data(&mut decoder, Restrict::new(bytes.len() as u16));
888        assert!(
889            read_rdata.is_ok(),
890            "error decoding: {:?}",
891            read_rdata.unwrap_err()
892        );
893
894        let opt = read_rdata.unwrap();
895        let options = vec![
896            (
897                EdnsCode::Subnet,
898                EdnsOption::Subnet("0.0.0.0/0".parse().unwrap()),
899            ),
900            (
901                EdnsCode::Cookie,
902                EdnsOption::Unknown(10, vec![0x0b, 0x64, 0xb4, 0xdc, 0xd7, 0xb0, 0xcc, 0x8f]),
903            ),
904            (EdnsCode::Keepalive, EdnsOption::Unknown(11, vec![])),
905        ];
906        let options = OPT::new(options);
907        assert_eq!(opt, options);
908    }
909
910    #[test]
911    fn test_multiple_options_with_same_code() {
912        let bytes: Vec<u8> = vec![
913            0x00, 0x0f, 0x00, 0x02, 0x00, 0x06, 0x00, 0x0f, 0x00, 0x0f, 0x00, 0x09, 0x55, 0x6E,
914            0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72,
915        ];
916
917        let mut decoder: BinDecoder<'_> = BinDecoder::new(&bytes);
918        let read_rdata = OPT::read_data(&mut decoder, Restrict::new(bytes.len() as u16));
919        assert!(
920            read_rdata.is_ok(),
921            "error decoding: {:?}",
922            read_rdata.unwrap_err()
923        );
924
925        let opt = read_rdata.unwrap();
926        let options = vec![
927            (
928                EdnsCode::Unknown(15u16),
929                EdnsOption::Unknown(15u16, vec![0x00, 0x06]),
930            ),
931            (
932                EdnsCode::Unknown(15u16),
933                EdnsOption::Unknown(
934                    15u16,
935                    vec![
936                        0x00, 0x09, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x20, 0x65, 0x72,
937                        0x72, 0x6F, 0x72,
938                    ],
939                ),
940            ),
941        ];
942        let options = OPT::new(options);
943        assert_eq!(opt, options);
944    }
945
946    #[test]
947    fn test_write_client_subnet() {
948        let expected_bytes: Vec<u8> = vec![0x00, 0x01, 0x18, 0x00, 0xac, 0x01, 0x01];
949        let ecs: ClientSubnet = "172.1.1.1/24".parse().unwrap();
950        let bytes = Vec::<u8>::try_from(&ecs).unwrap();
951        #[cfg(feature = "std")]
952        println!("bytes: {bytes:?}");
953        assert_eq!(bytes, expected_bytes);
954    }
955
956    #[test]
957    fn test_read_client_subnet() {
958        let bytes: Vec<u8> = vec![0x00, 0x01, 0x18, 0x00, 0xac, 0x01, 0x01];
959        let ecs = ClientSubnet::try_from(bytes.as_slice()).unwrap();
960        assert_eq!(ecs, "172.1.1.0/24".parse().unwrap());
961    }
962
963    #[test]
964    fn test_nsid_payload_too_large() {
965        let err = NSIDPayload::try_from([0x00; (u16::MAX as usize) + 1].as_slice()).unwrap_err();
966        assert!(
967            matches!(err, DecodeError::IncorrectRDataLengthRead { .. }),
968            "expected IncorrectRDataLengthRead, got {err}"
969        );
970    }
971
972    #[test]
973    fn test_nsid_payload_roundtrip() {
974        let payload_in = EdnsOption::NSID([0xC0, 0xFF, 0xEE].as_slice().try_into().unwrap());
975        let mut buf = Vec::new();
976        let mut encoder = BinEncoder::new(&mut buf);
977        payload_in.emit(&mut encoder).unwrap();
978
979        let payload_out = EdnsOption::try_from((EdnsCode::NSID, buf.as_ref())).unwrap();
980        assert_eq!(payload_in, payload_out);
981    }
982
983    #[test]
984    fn test_eq_and_hash() {
985        let options_1 = OPT::new(vec![
986            (
987                EdnsCode::Unknown(15u16),
988                EdnsOption::Unknown(15u16, vec![0x00, 0x06]),
989            ),
990            (
991                EdnsCode::Unknown(15u16),
992                EdnsOption::Unknown(
993                    15u16,
994                    vec![
995                        0x00, 0x09, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x20, 0x65, 0x72,
996                        0x72, 0x6F, 0x72,
997                    ],
998                ),
999            ),
1000        ]);
1001
1002        let options_2 = OPT::new(vec![
1003            (
1004                EdnsCode::Unknown(15u16),
1005                EdnsOption::Unknown(
1006                    15u16,
1007                    vec![
1008                        0x00, 0x09, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x20, 0x65, 0x72,
1009                        0x72, 0x6F, 0x72,
1010                    ],
1011                ),
1012            ),
1013            (
1014                EdnsCode::Unknown(15u16),
1015                EdnsOption::Unknown(15u16, vec![0x00, 0x06]),
1016            ),
1017        ]);
1018
1019        // Leading byte changed in the vec
1020        let options_3 = OPT::new(vec![
1021            (
1022                EdnsCode::Unknown(15u16),
1023                EdnsOption::Unknown(
1024                    15u16,
1025                    vec![
1026                        0xff, 0x09, 0x55, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x20, 0x65, 0x72,
1027                        0x72, 0x6F, 0x72,
1028                    ],
1029                ),
1030            ),
1031            (
1032                EdnsCode::Unknown(15u16),
1033                EdnsOption::Unknown(15u16, vec![0x00, 0x06]),
1034            ),
1035        ]);
1036
1037        let mut hasher_1 = DefaultHasher::new();
1038        options_1.hash(&mut hasher_1);
1039        let hash_1 = hasher_1.finish();
1040
1041        let mut hasher_2 = DefaultHasher::new();
1042        options_2.hash(&mut hasher_2);
1043        let hash_2 = hasher_2.finish();
1044
1045        let mut hasher_3 = DefaultHasher::new();
1046        options_3.hash(&mut hasher_3);
1047        let hash_3 = hasher_3.finish();
1048
1049        assert_eq!(options_1, options_2);
1050        assert_eq!(hash_1, hash_2);
1051
1052        assert!(options_1 != options_3);
1053        assert!(hash_1 != hash_3);
1054    }
1055}