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