Skip to main content

iris_core/conntrack/
pdu.rs

1//! Transport-layer protocol data unit.
2//! Directly exposed to users as a primitive data type.
3
4use crate::memory::mbuf::Mbuf;
5use crate::protocols::packet::ethernet::Ethernet;
6use crate::protocols::packet::ipv4::Ipv4;
7use crate::protocols::packet::ipv6::Ipv6;
8use crate::protocols::packet::tcp::{Tcp, TCP_PROTOCOL};
9use crate::protocols::packet::udp::{Udp, UDP_PROTOCOL};
10use crate::protocols::packet::Packet;
11
12use std::time::Instant;
13
14use anyhow::{bail, Result};
15
16use std::net::{IpAddr, SocketAddr};
17
18/// Transport-layer protocol data unit for stream reassembly and application-layer protocol parsing.
19/// As a primitive Iris data type, this can be reassembled (InL4Stream) or not reassembled (InL4Conn).
20#[derive(Debug, Clone)]
21pub struct L4Pdu {
22    /// Internal packet buffer containing frame data.
23    pub mbuf: Mbuf,
24    /// Transport layer context.
25    pub ctxt: L4Context,
26    /// `true` if segment is in the direction of orig -> resp.
27    pub dir: bool,
28    /// Time observed from timerwheel.
29    pub ts: Instant,
30}
31
32impl L4Pdu {
33    pub(crate) fn new(mbuf: Mbuf, ctxt: L4Context, dir: bool, ts: Instant) -> Self {
34        L4Pdu {
35            mbuf,
36            ctxt,
37            dir,
38            ts,
39        }
40    }
41
42    #[inline]
43    pub fn mbuf_own(self) -> Mbuf {
44        self.mbuf
45    }
46
47    #[inline]
48    pub fn mbuf_ref(&self) -> &Mbuf {
49        &self.mbuf
50    }
51
52    #[inline]
53    pub fn offset(&self) -> usize {
54        self.ctxt.offset
55    }
56
57    #[inline]
58    pub fn app_body_offset(&self) -> Option<usize> {
59        self.ctxt.app_offset
60    }
61
62    #[inline]
63    pub(crate) fn mark_no_payload(&mut self) {
64        self.ctxt.offset = self.mbuf.data_len();
65        self.ctxt.length = 0;
66    }
67
68    #[inline]
69    pub fn length(&self) -> usize {
70        self.ctxt.length
71    }
72
73    #[inline]
74    pub fn seq_no(&self) -> u32 {
75        self.ctxt.seq_no
76    }
77
78    #[inline]
79    pub fn ack_no(&self) -> u32 {
80        self.ctxt.ack_no
81    }
82
83    #[inline]
84    pub fn flags(&self) -> u8 {
85        self.ctxt.flags
86    }
87}
88
89/// Parsed transport-layer context from the packet used for connection tracking.
90#[derive(Debug, Clone, Copy)]
91pub struct L4Context {
92    /// Source socket address.
93    pub src: SocketAddr,
94    /// Destination socket address.
95    pub dst: SocketAddr,
96    /// L4 protocol.
97    pub proto: usize,
98    /// Offset into mbuf where L4 payload begins.
99    /// If this segment is reassembled, this is the offset where
100    /// *new* payload begins. None indicates that no new data.
101    /// If segment has not been reassembled, this is offset after
102    /// TCP header.
103    pub offset: usize,
104    /// Length of the payload in bytes.
105    pub length: usize,
106    /// Raw sequence number of segment.
107    pub seq_no: u32,
108    /// Raw acknowledgment number of segment.
109    pub ack_no: u32,
110    /// TCP flags.
111    pub flags: u8,
112    /// True if packet has been reassembled, with corresponding
113    /// possible updates to `offset`.
114    pub reassembled: bool,
115    /// If segment contains application-layer body, its offset
116    /// into the payload (after `offset`, i.e. L4 headers).
117    /// None indicates no application-layer body.
118    pub app_offset: Option<usize>,
119}
120
121impl L4Context {
122    pub fn new(mbuf: &Mbuf) -> Result<Self> {
123        if let Ok(eth) = mbuf.parse_to::<Ethernet>() {
124            if let Ok(ipv4) = eth.parse_to::<Ipv4>() {
125                if let Ok(tcp) = ipv4.parse_to::<Tcp>() {
126                    if let Some(payload_size) = (ipv4.total_length() as usize)
127                        .checked_sub(ipv4.header_len() + tcp.header_len())
128                    {
129                        Ok(L4Context {
130                            src: SocketAddr::new(IpAddr::V4(ipv4.src_addr()), tcp.src_port()),
131                            dst: SocketAddr::new(IpAddr::V4(ipv4.dst_addr()), tcp.dst_port()),
132                            proto: TCP_PROTOCOL,
133                            offset: tcp.next_header_offset(),
134                            length: payload_size,
135                            seq_no: tcp.seq_no(),
136                            ack_no: tcp.ack_no(),
137                            flags: tcp.flags(),
138                            reassembled: false,
139                            app_offset: None,
140                        })
141                    } else {
142                        bail!("Malformed Packet");
143                    }
144                } else if let Ok(udp) = ipv4.parse_to::<Udp>() {
145                    if let Some(payload_size) = (ipv4.total_length() as usize)
146                        .checked_sub(ipv4.header_len() + udp.header_len())
147                    {
148                        Ok(L4Context {
149                            src: SocketAddr::new(IpAddr::V4(ipv4.src_addr()), udp.src_port()),
150                            dst: SocketAddr::new(IpAddr::V4(ipv4.dst_addr()), udp.dst_port()),
151                            proto: UDP_PROTOCOL,
152                            offset: udp.next_header_offset(),
153                            length: payload_size,
154                            seq_no: 0,
155                            ack_no: 0,
156                            flags: 0,
157                            reassembled: false,
158                            app_offset: None,
159                        })
160                    } else {
161                        bail!("Malformed Packet");
162                    }
163                } else {
164                    bail!("Not TCP or UDP");
165                }
166            } else if let Ok(ipv6) = eth.parse_to::<Ipv6>() {
167                if let Ok(tcp) = ipv6.parse_to::<Tcp>() {
168                    if let Some(payload_size) =
169                        (ipv6.payload_length() as usize).checked_sub(tcp.header_len())
170                    {
171                        Ok(L4Context {
172                            src: SocketAddr::new(IpAddr::V6(ipv6.src_addr()), tcp.src_port()),
173                            dst: SocketAddr::new(IpAddr::V6(ipv6.dst_addr()), tcp.dst_port()),
174                            proto: TCP_PROTOCOL,
175                            offset: tcp.next_header_offset(),
176                            length: payload_size,
177                            seq_no: tcp.seq_no(),
178                            ack_no: tcp.ack_no(),
179                            flags: tcp.flags(),
180                            reassembled: false,
181                            app_offset: None,
182                        })
183                    } else {
184                        bail!("Malformed Packet");
185                    }
186                } else if let Ok(udp) = ipv6.parse_to::<Udp>() {
187                    if let Some(payload_size) =
188                        (ipv6.payload_length() as usize).checked_sub(udp.header_len())
189                    {
190                        Ok(L4Context {
191                            src: SocketAddr::new(IpAddr::V6(ipv6.src_addr()), udp.src_port()),
192                            dst: SocketAddr::new(IpAddr::V6(ipv6.dst_addr()), udp.dst_port()),
193                            proto: UDP_PROTOCOL,
194                            offset: udp.next_header_offset(),
195                            length: payload_size,
196                            seq_no: 0,
197                            ack_no: 0,
198                            flags: 0,
199                            reassembled: false,
200                            app_offset: None,
201                        })
202                    } else {
203                        bail!("Malformed Packet");
204                    }
205                } else {
206                    bail!("Not TCP or UDP");
207                }
208            } else {
209                bail!("Not IP");
210            }
211        } else {
212            bail!("Not Ethernet");
213        }
214    }
215}