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}