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, OctetsFrom};
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 Padding<()> {
40    /// The option code for this option.
41    pub const CODE: OptionCode = OptionCode::PADDING;
42}
43
44impl<Octs> Padding<Octs> {
45    /// Creates a value from the padding octets.
46    ///
47    /// Returns an error if `octets` are longer than 65,535 octets.
48    pub fn from_octets(octets: Octs) -> Result<Self, LongOptData>
49    where Octs: AsRef<[u8]> {
50        LongOptData::check_len(octets.as_ref().len())?;
51        Ok(unsafe { Self::from_octets_unchecked(octets) })
52    }
53
54    /// Creates a value from the padding octets without checking.
55    ///
56    /// # Safety
57    ///
58    /// The caller needs to ensure that `octets` are not longer than
59    /// 65,535 octets.
60    pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
61        Self { octets }
62    }
63
64    /// Parses a value from its wire formal.
65    pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
66        parser: &mut Parser<'a, Src>
67    ) -> Result<Self, ParseError> {
68        let len = parser.remaining();
69        LongOptData::check_len(len)?;
70        Ok(unsafe { Self::from_octets_unchecked(
71            parser.parse_octets(len)?
72        )})
73    }
74}
75
76impl<Octs: ?Sized> Padding<Octs> {
77    /// Returns a reference to the padding octets.
78    pub fn as_octets(&self) -> &Octs {
79        &self.octets
80    }
81
82    /// Converts the value into the padding octets.
83    pub fn into_octets(self) -> Octs
84    where
85        Octs: Sized,
86    {
87        self.octets
88    }
89
90    /// Returns a slice of the padding octets.
91    pub fn as_slice(&self) -> &[u8]
92    where
93        Octs: AsRef<[u8]>,
94    {
95        self.octets.as_ref()
96    }
97}
98
99//--- OctetsFrom
100
101impl<Octs, SrcOcts> OctetsFrom<Padding<SrcOcts>> for Padding<Octs>
102where Octs: OctetsFrom<SrcOcts> {
103    type Error = Octs::Error;
104
105    fn try_octets_from(src: Padding<SrcOcts>) -> Result<Self, Self::Error> {
106        Octs::try_octets_from(src.octets).map(|octets| unsafe {
107            Self::from_octets_unchecked(octets)
108        })
109    }
110}
111
112//--- AsRef and Borrow
113
114impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for Padding<Octs> {
115    fn as_ref(&self) -> &[u8] {
116        self.as_slice()
117    }
118}
119
120impl<Octs: AsRef<[u8]> + ?Sized> borrow::Borrow<[u8]> for Padding<Octs> {
121    fn borrow(&self) -> &[u8] {
122        self.as_slice()
123    }
124}
125
126//--- OptData
127
128impl<Octs> OptData for Padding<Octs> {
129    fn code(&self) -> OptionCode {
130        OptionCode::PADDING
131    }
132}
133
134impl<'a, Octs: Octets> ParseOptData<'a, Octs> for Padding<Octs::Range<'a>> {
135    fn parse_option(
136        code: OptionCode,
137        parser: &mut Parser<'a, Octs>,
138    ) -> Result<Option<Self>, ParseError> {
139        if code == OptionCode::PADDING {
140            Self::parse(parser).map(Some)
141        }
142        else {
143            Ok(None)
144        }
145    }
146}
147
148impl<Octs: AsRef<[u8]>> ComposeOptData for Padding<Octs> {
149    fn compose_len(&self) -> u16 {
150        self.octets.as_ref().len().try_into().expect("long option data")
151    }
152
153    fn compose_option<Target: OctetsBuilder + ?Sized>(
154        &self, target: &mut Target
155    ) -> Result<(), Target::AppendError> {
156        target.append_slice(self.octets.as_ref())
157    }
158}
159
160//--- Display and Debug
161
162impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Padding<Octs> {
163    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
164        for v in self.octets.as_ref() {
165            write!(f, "{:X} ", *v)?;
166        }
167        if let Ok(s) = str::from_utf8(self.octets.as_ref()) {
168            write!(f, "({})", s)?;
169        }
170        Ok(())
171    }
172}
173
174impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Padding<Octs> {
175    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176        write!(f, "Padding({})", self)
177    }
178}
179
180//--- Extended OptBuilder
181
182impl<Target: Composer> OptBuilder<'_, Target> {
183    pub fn padding( &mut self, len: u16) -> Result<(), Target::AppendError> {
184        self.push_raw_option(
185            OptionCode::PADDING,
186            len,
187            |target| {
188                for _ in 0..len {
189                    0u8.compose(target)?
190                }
191                Ok(())
192            }
193        )
194    }
195
196    #[cfg(feature = "rand")]
197    pub fn random_padding(
198        &mut self, len: u16
199    ) -> Result<(), Target::AppendError> {
200        self.push_raw_option(
201            OptionCode::PADDING,
202            len,
203            |target| {
204                for _ in 0..len {
205                    rand::random::<u8>().compose(target)?
206                }
207                Ok(())
208            }
209        )
210    }
211}
212
213
214//--- Serialize
215
216#[cfg(feature = "serde")]
217impl<Octs: AsRef<[u8]>> serde::Serialize for Padding<Octs> {
218    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
219    where
220        S: serde::Serializer {
221        use octseq::serde::SerializeOctets;
222        self.octets.as_ref().serialize_octets(serializer)
223    }
224}