Files
arya dradjicaandarya dradjica e8e40c6641 Disallow elided lifetimes in paths
This language feature is deprecated, but the lint for it is not
enabled by default.  Enabling the lint and fixing all occurrences also
resolves some new Clippy lints.  This does not affect the API or
behaviour of the code in any way.
2025-06-24 11:59:06 +00:00

222 lines
6.0 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! EDNS options for paddin message sizes.
//!
//! The option in this module [`Padding<Octs>`] allows to increase the
//! size of a DNS message to any desired value. This can be helpful with
//! confidentialty.
//!
//! Since this option does not have any meaning for the receiver of a message,
//! you should generally just use the [`OptBuilder::padding`] and
//! [`OptBuilder::random_padding`] methods when constructing a message.
use super::super::iana::OptionCode;
use super::super::message_builder::OptBuilder;
use super::super::wire::{Compose, Composer, ParseError};
use super::{ComposeOptData, LongOptData, OptData, ParseOptData};
use core::{borrow, fmt, str};
use octseq::builder::OctetsBuilder;
use octseq::octets::{Octets, OctetsFrom};
use octseq::parse::Parser;
//------------ Padding -------------------------------------------------------
/// Option data for the padding option.
///
/// This option is used to increase the size of a DNS message to a fixed
/// value so eavesdropper cant dertermine information from the size.
///
/// Generally, you should not need to use this type. Instead, you can use
/// the [`OptBuilder::padding`] and [`OptBuilder::random_padding`] methods to
/// add padding to a message and ignore it when receving one.
///
/// The option is defined in [RFC 7830](https://tools.ietf.org/html/rfc7830).
#[derive(Clone, Copy)]
pub struct Padding<Octs: ?Sized> {
/// The padding octets.
octets: Octs,
}
impl Padding<()> {
/// The option code for this option.
pub const CODE: OptionCode = OptionCode::PADDING;
}
impl<Octs> Padding<Octs> {
/// Creates a value from the padding octets.
///
/// Returns an error if `octets` are longer than 65,535 octets.
pub fn from_octets(octets: Octs) -> Result<Self, LongOptData>
where
Octs: AsRef<[u8]>,
{
LongOptData::check_len(octets.as_ref().len())?;
Ok(unsafe { Self::from_octets_unchecked(octets) })
}
/// Creates a value from the padding octets without checking.
///
/// # Safety
///
/// The caller needs to ensure that `octets` are not longer than
/// 65,535 octets.
pub unsafe fn from_octets_unchecked(octets: Octs) -> Self {
Self { octets }
}
/// Parses a value from its wire formal.
pub fn parse<'a, Src: Octets<Range<'a> = Octs> + ?Sized>(
parser: &mut Parser<'a, Src>,
) -> Result<Self, ParseError> {
let len = parser.remaining();
LongOptData::check_len(len)?;
Ok(unsafe { Self::from_octets_unchecked(parser.parse_octets(len)?) })
}
}
impl<Octs: ?Sized> Padding<Octs> {
/// Returns a reference to the padding octets.
pub fn as_octets(&self) -> &Octs {
&self.octets
}
/// Converts the value into the padding octets.
pub fn into_octets(self) -> Octs
where
Octs: Sized,
{
self.octets
}
/// Returns a slice of the padding octets.
pub fn as_slice(&self) -> &[u8]
where
Octs: AsRef<[u8]>,
{
self.octets.as_ref()
}
}
//--- OctetsFrom
impl<Octs, SrcOcts> OctetsFrom<Padding<SrcOcts>> for Padding<Octs>
where
Octs: OctetsFrom<SrcOcts>,
{
type Error = Octs::Error;
fn try_octets_from(src: Padding<SrcOcts>) -> Result<Self, Self::Error> {
Octs::try_octets_from(src.octets)
.map(|octets| unsafe { Self::from_octets_unchecked(octets) })
}
}
//--- AsRef and Borrow
impl<Octs: AsRef<[u8]> + ?Sized> AsRef<[u8]> for Padding<Octs> {
fn as_ref(&self) -> &[u8] {
self.as_slice()
}
}
impl<Octs: AsRef<[u8]> + ?Sized> borrow::Borrow<[u8]> for Padding<Octs> {
fn borrow(&self) -> &[u8] {
self.as_slice()
}
}
//--- OptData
impl<Octs> OptData for Padding<Octs> {
fn code(&self) -> OptionCode {
OptionCode::PADDING
}
}
impl<'a, Octs: Octets> ParseOptData<'a, Octs> for Padding<Octs::Range<'a>> {
fn parse_option(
code: OptionCode,
parser: &mut Parser<'a, Octs>,
) -> Result<Option<Self>, ParseError> {
if code == OptionCode::PADDING {
Self::parse(parser).map(Some)
} else {
Ok(None)
}
}
}
impl<Octs: AsRef<[u8]>> ComposeOptData for Padding<Octs> {
fn compose_len(&self) -> u16 {
self.octets
.as_ref()
.len()
.try_into()
.expect("long option data")
}
fn compose_option<Target: OctetsBuilder + ?Sized>(
&self,
target: &mut Target,
) -> Result<(), Target::AppendError> {
target.append_slice(self.octets.as_ref())
}
}
//--- Display and Debug
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Display for Padding<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
for v in self.octets.as_ref() {
write!(f, "{:X} ", *v)?;
}
if let Ok(s) = str::from_utf8(self.octets.as_ref()) {
write!(f, "({})", s)?;
}
Ok(())
}
}
impl<Octs: AsRef<[u8]> + ?Sized> fmt::Debug for Padding<Octs> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Padding({})", self)
}
}
//--- Extended OptBuilder
impl<Target: Composer> OptBuilder<'_, Target> {
pub fn padding(&mut self, len: u16) -> Result<(), Target::AppendError> {
self.push_raw_option(OptionCode::PADDING, len, |target| {
for _ in 0..len {
0u8.compose(target)?
}
Ok(())
})
}
#[cfg(feature = "rand")]
pub fn random_padding(
&mut self,
len: u16,
) -> Result<(), Target::AppendError> {
self.push_raw_option(OptionCode::PADDING, len, |target| {
for _ in 0..len {
rand::random::<u8>().compose(target)?
}
Ok(())
})
}
}
//--- Serialize
#[cfg(feature = "serde")]
impl<Octs: AsRef<[u8]>> serde::Serialize for Padding<Octs> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
use octseq::serde::SerializeOctets;
self.octets.as_ref().serialize_octets(serializer)
}
}