Skip to main content

retina_core/conntrack/
pdu.rs

1use crate::memory::mbuf::Mbuf;
2use crate::protocols::packet::ethernet::Ethernet;
3use crate::protocols::packet::ipv4::Ipv4;
4use crate::protocols::packet::ipv6::Ipv6;
5use crate::protocols::packet::tcp::{Tcp, TCP_PROTOCOL};
6use crate::protocols::packet::udp::{Udp, UDP_PROTOCOL};
7use crate::protocols::packet::Packet;
8
9use anyhow::{bail, Result};
10
11use std::net::{IpAddr, SocketAddr};
12
13/// Transport-layer protocol data unit for stream reassembly and application-layer protocol parsing.
14#[derive(Debug)]
15pub struct L4Pdu {
16    /// Internal packet buffer containing frame data.
17    pub(crate) mbuf: Mbuf,
18    /// Transport layer context.
19    pub(crate) ctxt: L4Context,
20    /// `true` if segment is in the direction of orig -> resp.
21    pub(crate) dir: bool,
22}
23
24impl L4Pdu {
25    pub(crate) fn new(mbuf: Mbuf, ctxt: L4Context, dir: bool) -> Self {
26        L4Pdu { mbuf, ctxt, dir }
27    }
28
29    #[inline]
30    pub(crate) fn mbuf_own(self) -> Mbuf {
31        self.mbuf
32    }
33
34    #[inline]
35    pub(crate) fn mbuf_ref(&self) -> &Mbuf {
36        &self.mbuf
37    }
38
39    #[inline]
40    pub(crate) fn offset(&self) -> usize {
41        self.ctxt.offset
42    }
43
44    #[inline]
45    pub(crate) fn length(&self) -> usize {
46        self.ctxt.length
47    }
48
49    #[inline]
50    pub(crate) fn seq_no(&self) -> u32 {
51        self.ctxt.seq_no
52    }
53
54    #[inline]
55    pub(crate) fn flags(&self) -> u8 {
56        self.ctxt.flags
57    }
58}
59
60/// Parsed transport-layer context from the packet used for connection tracking.
61#[derive(Debug, Clone, Copy)]
62pub struct L4Context {
63    /// Source socket address.
64    pub(crate) src: SocketAddr,
65    /// Destination socket address.
66    pub(crate) dst: SocketAddr,
67    /// L4 protocol.
68    pub(crate) proto: usize,
69    /// Index of the predicate that was last matched in the packet filter.
70    pub(crate) idx: usize,
71    /// Offset into the mbuf where payload begins.
72    pub(crate) offset: usize,
73    /// Length of the payload in bytes.
74    pub(crate) length: usize,
75    /// Raw sequence number of segment.
76    pub(crate) seq_no: u32,
77    /// TCP flags.
78    pub(crate) flags: u8,
79}
80
81impl L4Context {
82    pub(crate) fn new(mbuf: &Mbuf, idx: usize) -> Result<Self> {
83        if let Ok(eth) = mbuf.parse_to::<Ethernet>() {
84            if let Ok(ipv4) = eth.parse_to::<Ipv4>() {
85                if let Ok(tcp) = ipv4.parse_to::<Tcp>() {
86                    if let Some(payload_size) = (ipv4.total_length() as usize)
87                        .checked_sub(ipv4.header_len() + tcp.header_len())
88                    {
89                        Ok(L4Context {
90                            src: SocketAddr::new(IpAddr::V4(ipv4.src_addr()), tcp.src_port()),
91                            dst: SocketAddr::new(IpAddr::V4(ipv4.dst_addr()), tcp.dst_port()),
92                            proto: TCP_PROTOCOL,
93                            idx,
94                            offset: tcp.next_header_offset(),
95                            length: payload_size,
96                            seq_no: tcp.seq_no(),
97                            flags: tcp.flags(),
98                        })
99                    } else {
100                        bail!("Malformed Packet");
101                    }
102                } else if let Ok(udp) = ipv4.parse_to::<Udp>() {
103                    if let Some(payload_size) = (ipv4.total_length() as usize)
104                        .checked_sub(ipv4.header_len() + udp.header_len())
105                    {
106                        Ok(L4Context {
107                            src: SocketAddr::new(IpAddr::V4(ipv4.src_addr()), udp.src_port()),
108                            dst: SocketAddr::new(IpAddr::V4(ipv4.dst_addr()), udp.dst_port()),
109                            proto: UDP_PROTOCOL,
110                            idx,
111                            offset: udp.next_header_offset(),
112                            length: payload_size,
113                            seq_no: 0,
114                            flags: 0,
115                        })
116                    } else {
117                        bail!("Malformed Packet");
118                    }
119                } else {
120                    bail!("Not TCP or UDP");
121                }
122            } else if let Ok(ipv6) = eth.parse_to::<Ipv6>() {
123                if let Ok(tcp) = ipv6.parse_to::<Tcp>() {
124                    if let Some(payload_size) =
125                        (ipv6.payload_length() as usize).checked_sub(tcp.header_len())
126                    {
127                        Ok(L4Context {
128                            src: SocketAddr::new(IpAddr::V6(ipv6.src_addr()), tcp.src_port()),
129                            dst: SocketAddr::new(IpAddr::V6(ipv6.dst_addr()), tcp.dst_port()),
130                            proto: TCP_PROTOCOL,
131                            idx,
132                            offset: tcp.next_header_offset(),
133                            length: payload_size,
134                            seq_no: tcp.seq_no(),
135                            flags: tcp.flags(),
136                        })
137                    } else {
138                        bail!("Malformed Packet");
139                    }
140                } else if let Ok(udp) = ipv6.parse_to::<Udp>() {
141                    if let Some(payload_size) =
142                        (ipv6.payload_length() as usize).checked_sub(udp.header_len())
143                    {
144                        Ok(L4Context {
145                            src: SocketAddr::new(IpAddr::V6(ipv6.src_addr()), udp.src_port()),
146                            dst: SocketAddr::new(IpAddr::V6(ipv6.dst_addr()), udp.dst_port()),
147                            proto: UDP_PROTOCOL,
148                            idx,
149                            offset: udp.next_header_offset(),
150                            length: payload_size,
151                            seq_no: 0,
152                            flags: 0,
153                        })
154                    } else {
155                        bail!("Malformed Packet");
156                    }
157                } else {
158                    bail!("Not TCP or UDP");
159                }
160            } else {
161                bail!("Not IP");
162            }
163        } else {
164            bail!("Not Ethernet");
165        }
166    }
167}