domain/base/opt/
padding.rs

1//! EDNS options for paddin message sizes.
2//!
3//! The option in this module – [`Padding<Octs>`] – allows to increase the
4//! size of a DNS message to any desired value. This can be helpful with
5//! confidentialty.
6//!
7//! Since this option does not have any meaning for the receiver of a message,
8//! you should generally just use the [`OptBuilder::padding`] and
9//! [`OptBuilder::random_padding`] methods when constructing a message.
10
11use core::{borrow, fmt, str};
12use super::super::iana::OptionCode;
13use super::super::message_builder::OptBuilder;
14use super::super::wire::{Compose, Composer, ParseError};
15use super::{LongOptData, OptData, ComposeOptData, ParseOptData};
16use octseq::builder::OctetsBuilder;
17use octseq::octets::Octets;
18use octseq::parse::Parser;
19
20
21//------------ Padding -------------------------------------------------------
22
23/// Option data for the padding option.
24///
25/// This option is used to increase the size of a DNS message to a fixed
26/// value so eavesdropper can’t dertermine information from the size.
27///
28/// Generally, you should not need to use this type. Instead, you can use
29/// the [`OptBuilder::padding`] and [`OptBuilder::random_padding`] methods to
30/// add padding to a message – and ignore it when receving one.
31///
32/// The option is defined in [RFC 7830](https://tools.ietf.org/html/rfc7830).
33#[derive(Clone, Copy)]
34pub struct Padding<Octs: ?Sized> {
35    /// The padding octets.
36    octets: Octs,
37}
38
39impl<Octs> Padding<Octs> {
40    /// Creates a value from the padding octets.
41    ///
42    /// Returns an error if `octets` are longer than 65,535 octets.
43    pub fn from_octets(octets: Octs) -> Result<Self, LongOptData>
44    where Octs: AsRef<[u8]> {
45        LongOptData::check_len(octets.as_ref().len())?;
46        Ok(unsafe { Self::from_octets_unchecked(octets) })
47    }
48
49    /// Creates a value from the padding octets without checking.
50    ///
51    /// # Safety
52    ///
53    /// The caller needs to ensure that `octets` are not longer than
54    /// 65,535 octets.
55    pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
56        Self { octets }
57    }
58
59    /// Parses a value from its wire formal.
60    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
61        parser: &mut Parser<'a, Src>
62    ) -> Result<Self, ParseError> {
63        let len = parser.remaining();
64        LongOptData::check_len(len)?;
65        Ok(unsafe { Self::from_octets_unchecked(
66            parser.parse_octets(len)?
67        )})
68    }
69}
70
71impl<Octs: ?Sized> Padding<Octs> {
72    /// Returns a reference to the padding octets.
73    pub fn as_octets(&self) -> &Octs {
74        &self.octets
75    }
76
77    /// Converts the value into the padding octets.
78    pub fn into_octets(self) -> Octs
79    where
80        Octs: Sized,
81    {
82        self.octets
83    }
84
85    /// Returns a slice of the padding octets.
86    pub fn as_slice(&self) -> &[u8]
87    where
88        Octs: AsRef<[u8]>,
89    {
90        self.octets.as_ref()
91    }
92}
93
94//--- AsRef and Borrow
95
96impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for Padding<Octs> {
97    fn as_ref(&self) -> &[u8] {
98        self.as_slice()
99    }
100}
101
102impl<Octs: AsRef<[u8]> + ?Sized> borrow::Borrow<[u8]> for Padding<Octs> {
103    fn borrow(&self) -> &[u8] {
104        self.as_slice()
105    }
106}
107
108//--- OptData
109
110impl<Octs> OptData for Padding<Octs> {
111    fn code(&self) -> OptionCode {
112        OptionCode::Padding
113    }
114}
115
116impl<'a, Octs: Octets> ParseOptData<'a, Octs> for Padding<Octs::Range<'a>> {
117    fn parse_option(
118        code: OptionCode,
119        parser: &mut Parser<'a, Octs>,
120    ) -> Result<Option<Self>, ParseError> {
121        if code == OptionCode::Padding {
122            Self::parse(parser).map(Some)
123        }
124        else {
125            Ok(None)
126        }
127    }
128}
129
130impl<Octs: AsRef<[u8]>> ComposeOptData for Padding<Octs> {
131    fn compose_len(&self) -> u16 {
132        self.octets.as_ref().len().try_into().expect("long option data")
133    }
134
135    fn compose_option<Target: OctetsBuilder + ?Sized>(
136        &self, target: &mut Target
137    ) -> Result<(), Target::AppendError> {
138        target.append_slice(self.octets.as_ref())
139    }
140}
141
142//--- Display and Debug
143
144impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Padding<Octs> {
145    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
146        for v in self.octets.as_ref() {
147            write!(f, "{:X} ", *v)?;
148        }
149        if let Ok(s) = str::from_utf8(self.octets.as_ref()) {
150            write!(f, "({})", s)?;
151        }
152        Ok(())
153    }
154}
155
156impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Padding<Octs> {
157    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158        write!(f, "Padding({})", self)
159    }
160}
161
162//--- Extended OptBuilder
163
164impl<'a, Target: Composer> OptBuilder<'a, Target> {
165    pub fn padding( &mut self, len: u16) -> Result<(), Target::AppendError> {
166        self.push_raw_option(
167            OptionCode::Padding,
168            len,
169            |target| {
170                for _ in 0..len {
171                    0u8.compose(target)?
172                }
173                Ok(())
174            }
175        )
176    }
177
178    #[cfg(feature = "rand")]
179    pub fn random_padding(
180        &mut self, len: u16
181    ) -> Result<(), Target::AppendError> {
182        self.push_raw_option(
183            OptionCode::Padding,
184            len,
185            |target| {
186                for _ in 0..len {
187                    rand::random::<u8>().compose(target)?
188                }
189                Ok(())
190            }
191        )
192    }
193}
194