Skip to main content

iris_core/protocols/packet/
tcp.rs

1//! TCP packet.
2
3use crate::memory::mbuf::Mbuf;
4use crate::protocols::packet::{Packet, PacketHeader, PacketParseError};
5use crate::utils::types::*;
6
7/// TCP assigned protocol number.
8pub const TCP_PROTOCOL: usize = 6;
9
10// TCP flags.
11pub const CWR: u8 = 0b1000_0000;
12pub const ECE: u8 = 0b0100_0000;
13pub const URG: u8 = 0b0010_0000;
14pub const ACK: u8 = 0b0001_0000;
15pub const PSH: u8 = 0b0000_1000;
16pub const RST: u8 = 0b0000_0100;
17pub const SYN: u8 = 0b0000_0010;
18pub const FIN: u8 = 0b0000_0001;
19
20/// A TCP packet.
21///
22/// TCP options are not parsed by default.
23#[derive(Debug)]
24pub struct Tcp<'a> {
25    /// Fixed header.
26    header: TcpHeader,
27    /// Offset to `header` from the start of `mbuf`.
28    offset: usize,
29    /// Packet buffer.
30    mbuf: &'a Mbuf,
31}
32
33impl Tcp<'_> {
34    /// Returns the sending port.
35    #[inline]
36    pub fn src_port(&self) -> u16 {
37        self.header.src_port.into()
38    }
39
40    /// Returns the receiving port.
41    #[inline]
42    pub fn dst_port(&self) -> u16 {
43        self.header.dst_port.into()
44    }
45
46    /// Returns the sequence number.
47    #[inline]
48    pub fn seq_no(&self) -> u32 {
49        self.header.seq_no.into()
50    }
51
52    /// Returns the acknowledgment number.
53    #[inline]
54    pub fn ack_no(&self) -> u32 {
55        self.header.ack_no.into()
56    }
57
58    /// Returns the header length measured in 32-bit words.
59    #[inline]
60    pub fn data_offset(&self) -> u8 {
61        (self.header.data_offset_to_ns & 0xf0) >> 4
62    }
63
64    /// Returns the reserved bits.
65    #[inline]
66    pub fn reserved(&self) -> u8 {
67        self.header.data_offset_to_ns & 0x0f
68    }
69
70    /// Returns the 8-bit field containing the data offset, 3 reserved bits, and the nonce sum bit.
71    #[inline]
72    pub fn data_offset_to_ns(&self) -> u8 {
73        self.header.data_offset_to_ns
74    }
75
76    /// Returns the 8-bit TCP flags.
77    #[inline]
78    pub fn flags(&self) -> u8 {
79        self.header.flags
80    }
81
82    /// Returns the size of the receive window in window size units.
83    #[inline]
84    pub fn window(&self) -> u16 {
85        self.header.window.into()
86    }
87
88    /// Returns the 16-bit checksum field.
89    #[inline]
90    pub fn checksum(&self) -> u16 {
91        self.header.checksum.into()
92    }
93
94    /// Returns the urgent pointer.
95    #[inline]
96    pub fn urgent_pointer(&self) -> u16 {
97        self.header.urgent_pointer.into()
98    }
99
100    // ------------------------------------------------
101
102    /// Returns `true` if the (historical) nonce sum flag is set.
103    #[inline]
104    pub fn ns(&self) -> u8 {
105        ((self.header.data_offset_to_ns & 0x01) != 0) as u8
106    }
107
108    /// Returns `true` if the congestion window reduced flag is set.
109    #[inline]
110    pub fn cwr(&self) -> u8 {
111        ((self.flags() & CWR) != 0) as u8
112    }
113
114    /// Returns `true` if the ECN-Echo flag is set.
115    #[inline]
116    pub fn ece(&self) -> u8 {
117        ((self.flags() & ECE) != 0) as u8
118    }
119
120    /// Returns `true` if the urgent pointer flag is set.
121    #[inline]
122    pub fn urg(&self) -> u8 {
123        ((self.flags() & URG) != 0) as u8
124    }
125
126    /// Returns `true` if the acknowledgment flag is set.
127    #[inline]
128    pub fn ack(&self) -> u8 {
129        ((self.flags() & ACK) != 0) as u8
130    }
131
132    /// Returns `true` if the push flag is set.
133    #[inline]
134    pub fn psh(&self) -> u8 {
135        ((self.flags() & PSH) != 0) as u8
136    }
137
138    /// Returns `true` if the reset flag is set.
139    #[inline]
140    pub fn rst(&self) -> u8 {
141        ((self.flags() & RST) != 0) as u8
142    }
143
144    /// Returns `true` if the synchronize flag is set.
145    #[inline]
146    pub fn syn(&self) -> u8 {
147        ((self.flags() & SYN) != 0) as u8
148    }
149
150    /// Returns `true` if the FIN flag is set.
151    #[inline]
152    pub fn fin(&self) -> u8 {
153        ((self.flags() & FIN) != 0) as u8
154    }
155
156    /// Returns `true` if both `SYN` and `ACK` flags are set.
157    #[inline]
158    pub fn synack(&self) -> u8 {
159        ((self.flags() & (ACK | SYN)) != 0) as u8
160    }
161}
162
163impl<'a> Packet<'a> for Tcp<'a> {
164    fn mbuf(&self) -> &Mbuf {
165        self.mbuf
166    }
167
168    fn header_len(&self) -> usize {
169        self.header.length()
170    }
171
172    fn next_header_offset(&self) -> usize {
173        self.offset + self.header_len()
174    }
175
176    fn next_header(&self) -> Option<usize> {
177        None
178    }
179
180    fn parse_from(outer: &'a impl Packet<'a>) -> Result<Self, PacketParseError>
181    where
182        Self: Sized,
183    {
184        let offset = outer.next_header_offset();
185        if let Ok(header) = outer.mbuf().get_data(offset) {
186            match outer.next_header() {
187                Some(TCP_PROTOCOL) => Ok(Tcp {
188                    header: unsafe { *header },
189                    offset,
190                    mbuf: outer.mbuf(),
191                }),
192                _ => Err(PacketParseError::InvalidProtocol),
193            }
194        } else {
195            Err(PacketParseError::InvalidRead)
196        }
197    }
198}
199
200/// Fixed portion of a TCP header.
201#[derive(Debug, Clone, Copy)]
202#[repr(C, packed)]
203struct TcpHeader {
204    src_port: u16be,
205    dst_port: u16be,
206    seq_no: u32be,
207    ack_no: u32be,
208    data_offset_to_ns: u8,
209    flags: u8,
210    window: u16be,
211    checksum: u16be,
212    urgent_pointer: u16be,
213}
214
215impl PacketHeader for TcpHeader {
216    /// Header length measured in bytes. Equivalent to the payload offset.
217    ///
218    /// This differs from the value of the `Data Offset` field, which measures header length in
219    /// 32-bit words.
220    fn length(&self) -> usize {
221        ((self.data_offset_to_ns & 0xf0) >> 2).into()
222    }
223}