internet 0.0.3

Network library for rust
Documentation
use crate::{Buf, BufMut, BufResult, Codec, Cursor};

/// A TCP header.
///
/// [RFC 9293]: https://datatracker.ietf.org/doc/html/rfc9293#section-3.1
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Tcp {
    ///
    pub source_port: Port,
    ///
    pub destination_port: Port,
    ///
    pub sequence_number: u32,
    ///
    pub acknowledgment_number: u32,
    ///
    pub data_offset: u8,
    ///
    pub ns: bool,
    ///
    pub cwr: bool,
    ///
    pub ece: bool,
    ///
    pub urg: bool,
    ///
    pub ack: bool,
    ///
    pub psh: bool,
    ///
    pub rst: bool,
    ///
    pub syn: bool,
    ///
    pub fin: bool,
    ///
    pub window: u16,
    ///
    pub checksum: u16,
    ///
    pub urgent_pointer: u16,
}

impl Codec for Tcp {
    fn encode<W: BufMut>(&self, writer: &mut Cursor<W>, _: ()) -> BufResult<()> {
        self.source_port.encode(writer, ())?;
        self.destination_port.encode(writer, ())?;
        self.sequence_number.encode(writer, ())?;
        self.acknowledgment_number.encode(writer, ())?;

        // We'll take care about this..

        // Byte 12: Data Offset (4 bits) | Reserved (3 bits) | NS (1 bit)
        let byte12 = ((self.data_offset & 0x0F) << 4) | (if self.ns { 0b0000_0001 } else { 0 });

        // Byte 13: CWR ECE URG ACK PSH RST SYN FIN
        let byte13 = (if self.cwr { 0b1000_0000 } else { 0 })
            | (if self.ece { 0b0100_0000 } else { 0 })
            | (if self.urg { 0b0010_0000 } else { 0 })
            | (if self.ack { 0b0001_0000 } else { 0 })
            | (if self.psh { 0b0000_1000 } else { 0 })
            | (if self.rst { 0b0000_0100 } else { 0 })
            | (if self.syn { 0b0000_0010 } else { 0 })
            | (if self.fin { 0b0000_0001 } else { 0 });

        writer.write_u8(byte12)?;
        writer.write_u8(byte13)?;

        self.window.encode(writer, ())?;
        self.checksum.encode(writer, ())?;
        self.urgent_pointer.encode(writer, ())?;

        Ok(())
    }

    fn decode<R: Buf>(reader: &mut Cursor<R>, _: ()) -> BufResult<Self> {
        let source_port = Port::decode(reader, ())?;
        let destination_port = Port::decode(reader, ())?;
        let sequence_number = u32::decode(reader, ())?;
        let acknowledgment_number = u32::decode(reader, ())?;

        let byte12 = reader.read_u8()?;
        let byte13 = reader.read_u8()?;

        let data_offset = (byte12 >> 4) & 0x0F;
        let ns = (byte12 & 0b0000_0001) != 0;
        let cwr = (byte13 & 0b1000_0000) != 0;
        let ece = (byte13 & 0b0100_0000) != 0;
        let urg = (byte13 & 0b0010_0000) != 0;
        let ack = (byte13 & 0b0001_0000) != 0;
        let psh = (byte13 & 0b0000_1000) != 0;
        let rst = (byte13 & 0b0000_0100) != 0;
        let syn = (byte13 & 0b0000_0010) != 0;
        let fin = (byte13 & 0b0000_0001) != 0;

        let window = u16::decode(reader, ())?;
        let checksum = u16::decode(reader, ())?;
        let urgent_pointer = u16::decode(reader, ())?;

        Ok(Self {
            source_port,
            destination_port,
            sequence_number,
            acknowledgment_number,
            data_offset,
            ns,
            cwr,
            ece,
            urg,
            ack,
            psh,
            rst,
            syn,
            fin,
            window,
            checksum,
            urgent_pointer,
        })
    }
}

///
#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Port(pub u16);

impl Port {
    ///
    pub const UNDEFINED: Port = Port(0);
    ///
    pub const FTP: Port = Port(21);
    ///
    pub const SSH: Port = Port(22);
    ///
    pub const TELNET: Port = Port(23);
    ///
    pub const SMTP: Port = Port(25);
    ///
    pub const DNS: Port = Port(53);
    ///
    pub const HTTP: Port = Port(80);
    ///
    pub const POP3: Port = Port(110);
    ///
    pub const NTP: Port = Port(123);
    ///
    pub const IMAP: Port = Port(143);
    ///
    pub const HTTPS: Port = Port(443);
    ///
    pub const SMB: Port = Port(445);
    ///
    pub const SYSLOG: Port = Port(514);
    ///
    pub const RTSP: Port = Port(554);
    ///
    pub const MYSQL: Port = Port(3306);
    ///
    pub const POSTGRES: Port = Port(5432);
}

impl From<u16> for Port {
    fn from(port: u16) -> Self {
        Self(port)
    }
}

impl From<Port> for u16 {
    fn from(port: Port) -> Self {
        port.0
    }
}

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

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

impl std::fmt::Display for Port {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}