internet 0.0.5

Network library for rust
Documentation
//! TCP Options encoding.
//!
//! [RFC 9293]: https://datatracker.ietf.org/doc/html/rfc9293

use crate::{Buf, BufError, BufMut, BufResult, Codec, Cursor};

/// TCP Option enum.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Option {
    /// End of Option List.
    EndOfOptionList(EndOfOptionList),
    /// No-Operation.
    NoOperation(NoOperation),
    /// Maximum Segment Size.
    MaximumSegmentSize(MaximumSegmentSize),
    /// Window Scale.
    WindowScale(WindowScale),
    /// SACK Permitted.
    SackPermitted(SackPermitted),
    /// Selective Acknowledgment.
    Sack(Sack),
    /// Timestamps.
    Timestamps(Timestamps),
    /// MD5 Signature.
    Md5Signature(Md5Signature),
}

impl Codec for Option {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        match self {
            Option::EndOfOptionList(opt) => opt.encode(writer, ()),
            Option::NoOperation(opt) => opt.encode(writer, ()),
            Option::MaximumSegmentSize(opt) => opt.encode(writer, ()),
            Option::WindowScale(opt) => opt.encode(writer, ()),
            Option::SackPermitted(opt) => opt.encode(writer, ()),
            Option::Sack(opt) => opt.encode(writer, ()),
            Option::Timestamps(opt) => opt.encode(writer, ()),
            Option::Md5Signature(opt) => opt.encode(writer, ()),
        }
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        let byte = reader.peek_u8()?;
        let kind = Kind::try_from(byte).map_err(|_| BufError::UnexpectedValue)?;
        match kind {
            Kind::EndOfOptionList => Ok(Option::EndOfOptionList(EndOfOptionList::decode(
                reader,
                (),
            )?)),
            Kind::NoOperation => Ok(Option::NoOperation(NoOperation::decode(reader, ())?)),
            Kind::MaximumSegmentSize => Ok(Option::MaximumSegmentSize(MaximumSegmentSize::decode(
                reader,
                (),
            )?)),
            Kind::WindowScale => Ok(Option::WindowScale(WindowScale::decode(reader, ())?)),
            Kind::SackPermitted => Ok(Option::SackPermitted(SackPermitted::decode(reader, ())?)),
            Kind::Sack => Ok(Option::Sack(Sack::decode(reader, ())?)),
            Kind::Timestamps => Ok(Option::Timestamps(Timestamps::decode(reader, ())?)),
            Kind::Md5Signature => Ok(Option::Md5Signature(Md5Signature::decode(reader, ())?)),
        }
    }
}

/// TCP Option Kind.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(u8)]
pub enum Kind {
    /// End of Option List.
    EndOfOptionList = 0,
    /// No-Operation.
    NoOperation = 1,
    /// Maximum Segment Size.
    MaximumSegmentSize = 2,
    /// Window Scale.
    WindowScale = 3,
    /// SACK Permitted.
    SackPermitted = 4,
    /// Selective Acknowledgment.
    Sack = 5,
    /// Timestamps.
    Timestamps = 8,
    /// MD5 Signature.
    Md5Signature = 19,
}

impl TryFrom<u8> for Kind {
    type Error = ();

    fn try_from(value: u8) -> Result<Self, Self::Error> {
        match value {
            0 => Ok(Kind::EndOfOptionList),
            1 => Ok(Kind::NoOperation),
            2 => Ok(Kind::MaximumSegmentSize),
            3 => Ok(Kind::WindowScale),
            4 => Ok(Kind::SackPermitted),
            5 => Ok(Kind::Sack),
            8 => Ok(Kind::Timestamps),
            19 => Ok(Kind::Md5Signature),
            _ => Err(()),
        }
    }
}

impl Codec for Kind {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        (*self as u8).encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        let byte = u8::decode(reader, ())?;
        Self::try_from(byte).map_err(|_| BufError::UnexpectedValue)
    }
}

/// End of Option List.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct EndOfOptionList;

impl EndOfOptionList {
    /// Kind field.
    pub const KIND: Kind = Kind::EndOfOptionList;
}

impl Codec for EndOfOptionList {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::KIND.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if Kind::decode(reader, ())? != Self::KIND {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self)
    }
}

/// No-Operation.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct NoOperation;

impl NoOperation {
    /// Kind field.
    pub const KIND: Kind = Kind::NoOperation;
}

impl Codec for NoOperation {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::KIND.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if Kind::decode(reader, ())? != Self::KIND {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self)
    }
}

/// Maximum Segment Size.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MaximumSegmentSize {
    /// MSS value.
    pub mss: u16,
}

impl MaximumSegmentSize {
    /// Kind field.
    pub const KIND: Kind = Kind::MaximumSegmentSize;
    /// Fixed length.
    pub const LEN: u8 = 4;
}

impl Codec for MaximumSegmentSize {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::KIND.encode(writer, ())?;
        Self::LEN.encode(writer, ())?;
        self.mss.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if Kind::decode(reader, ())? != Self::KIND {
            return Err(BufError::UnexpectedValue);
        }
        if u8::decode(reader, ())? != Self::LEN {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self {
            mss: u16::decode(reader, ())?,
        })
    }
}

/// Window Scale.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct WindowScale {
    /// Shift count.
    pub shift_count: u8,
}

impl WindowScale {
    /// Kind field.
    pub const KIND: Kind = Kind::WindowScale;
    /// Fixed length.
    pub const LEN: u8 = 3;
}

impl Codec for WindowScale {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::KIND.encode(writer, ())?;
        Self::LEN.encode(writer, ())?;
        self.shift_count.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if Kind::decode(reader, ())? != Self::KIND {
            return Err(BufError::UnexpectedValue);
        }
        if u8::decode(reader, ())? != Self::LEN {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self {
            shift_count: u8::decode(reader, ())?,
        })
    }
}

/// SACK Permitted.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SackPermitted;

impl SackPermitted {
    /// Kind field.
    pub const KIND: Kind = Kind::SackPermitted;
    /// Fixed length.
    pub const LEN: u8 = 2;
}

impl Codec for SackPermitted {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::KIND.encode(writer, ())?;
        Self::LEN.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if Kind::decode(reader, ())? != Self::KIND {
            return Err(BufError::UnexpectedValue);
        }
        if u8::decode(reader, ())? != Self::LEN {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self)
    }
}

/// SACK block (left edge, right edge).
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SackBlock {
    /// Left edge of the block.
    pub left_edge: u32,
    /// Right edge of the block.
    pub right_edge: u32,
}

impl Codec for SackBlock {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        self.left_edge.encode(writer, ())?;
        self.right_edge.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        Ok(Self {
            left_edge: u32::decode(reader, ())?,
            right_edge: u32::decode(reader, ())?,
        })
    }
}

/// Selective Acknowledgment.
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Sack {
    /// SACK blocks (1 to 4).
    pub blocks: Vec<SackBlock>,
}

impl Sack {
    /// Kind field.
    pub const KIND: Kind = Kind::Sack;
    /// Minimum length (kind + length).
    pub const MIN_LEN: u8 = 2;

    /// Calculates the encoded length.
    pub fn encoded_len(&self) -> u8 {
        (2 + self.blocks.len() * 8) as u8
    }
}

impl Codec for Sack {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::KIND.encode(writer, ())?;
        self.encoded_len().encode(writer, ())?;
        for block in &self.blocks {
            block.encode(writer, ())?;
        }
        Ok(())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if Kind::decode(reader, ())? != Self::KIND {
            return Err(BufError::UnexpectedValue);
        }
        let length = u8::decode(reader, ())?;
        if length < Self::MIN_LEN || (length - Self::MIN_LEN) % 8 != 0 {
            return Err(BufError::InvalidLength);
        }
        let block_count = ((length - Self::MIN_LEN) / 8) as usize;
        let mut blocks = Vec::with_capacity(block_count);
        for _ in 0..block_count {
            blocks.push(SackBlock::decode(reader, ())?);
        }
        Ok(Self { blocks })
    }
}

/// Timestamps.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Timestamps {
    /// Timestamp value.
    pub tsval: u32,
    /// Timestamp echo reply.
    pub tsecr: u32,
}

impl Timestamps {
    /// Kind field.
    pub const KIND: Kind = Kind::Timestamps;
    /// Fixed length.
    pub const LEN: u8 = 10;
}

impl Codec for Timestamps {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::KIND.encode(writer, ())?;
        Self::LEN.encode(writer, ())?;
        self.tsval.encode(writer, ())?;
        self.tsecr.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if Kind::decode(reader, ())? != Self::KIND {
            return Err(BufError::UnexpectedValue);
        }
        if u8::decode(reader, ())? != Self::LEN {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self {
            tsval: u32::decode(reader, ())?,
            tsecr: u32::decode(reader, ())?,
        })
    }
}

/// MD5 Signature.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Md5Signature {
    /// MD5 digest (always 16 bytes).
    pub digest: [u8; 16],
}

impl Md5Signature {
    /// Kind field.
    pub const KIND: Kind = Kind::Md5Signature;
    /// Fixed length.
    pub const LEN: u8 = 18;
}

impl Codec for Md5Signature {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        Self::KIND.encode(writer, ())?;
        Self::LEN.encode(writer, ())?;
        self.digest.encode(writer, ())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        if Kind::decode(reader, ())? != Self::KIND {
            return Err(BufError::UnexpectedValue);
        }
        if u8::decode(reader, ())? != Self::LEN {
            return Err(BufError::UnexpectedValue);
        }
        Ok(Self {
            digest: reader.read_array::<16>()?,
        })
    }
}