parse_tcp/
parser.rs

1use std::net::IpAddr;
2
3use etherparse::{InternetSlice, SlicedPacket, TcpOptionElement, TransportSlice};
4use tracing::{debug, trace};
5
6use crate::{TcpFlags, TcpMeta};
7
8/// parses only TCP packets with etherparse
9pub struct TcpParser {
10    pub layer: ParseLayer,
11    pub failed_parse: usize,
12    pub ignored: usize,
13}
14
15impl TcpParser {
16    pub fn new() -> Self {
17        Self {
18            layer: ParseLayer::Link,
19            failed_parse: 0,
20            ignored: 0,
21        }
22    }
23
24    /// parse tcp packets into TcpMeta and data
25    pub fn parse_packet<'a>(&mut self, data: &'a [u8]) -> Option<(TcpMeta, &'a [u8])> {
26        let parse_result = match self.layer {
27            ParseLayer::Link => SlicedPacket::from_ethernet(data),
28            ParseLayer::IP => SlicedPacket::from_ip(data),
29            // BSD loopback has 4 byte header before IP, remove it
30            ParseLayer::BsdLoopback => SlicedPacket::from_ip(&data[4..]),
31        };
32        // ignore errors
33        let Ok(parsed) = parse_result else {
34            debug!("packet failed parse: {:?}", parse_result.unwrap_err());
35            self.failed_parse += 1;
36            return None;
37        };
38        let Some(internet_slice) = parsed.net else {
39            trace!("ignoring packet: no IP layer");
40            self.ignored += 1;
41            return None;
42        };
43        let Some(transport_slice) = parsed.transport else {
44            trace!("ignoring packet: no transport layer");
45            self.ignored += 1;
46            return None;
47        };
48        let TransportSlice::Tcp(tcp_slice) = transport_slice else {
49            trace!("ignoring packet: not tcp");
50            self.ignored += 1;
51            return None;
52        };
53
54        let (src_addr, dst_addr): (IpAddr, IpAddr) = match internet_slice {
55            InternetSlice::Ipv4(v4) => {
56                let header = v4.header();
57                (
58                    header.source_addr().into(),
59                    header.destination_addr().into(),
60                )
61            }
62            InternetSlice::Ipv6(v6) => {
63                let header = v6.header();
64                (
65                    header.source_addr().into(),
66                    header.destination_addr().into(),
67                )
68            }
69        };
70
71        let mut option_window_scale = None;
72        let mut option_timestamp = None;
73        for opt in tcp_slice.options_iterator() {
74            match opt {
75                Ok(TcpOptionElement::WindowScale(scale)) => {
76                    option_window_scale = Some(scale);
77                }
78                Ok(TcpOptionElement::Timestamp(a, b)) => {
79                    option_timestamp = Some((a, b));
80                }
81                // ignore all other options
82                _ => {}
83            }
84        }
85
86        let meta = TcpMeta {
87            src_addr,
88            src_port: tcp_slice.source_port(),
89            dst_addr,
90            dst_port: tcp_slice.destination_port(),
91            seq_number: tcp_slice.sequence_number(),
92            ack_number: tcp_slice.acknowledgment_number(),
93            flags: TcpFlags {
94                syn: tcp_slice.syn(),
95                ack: tcp_slice.ack(),
96                fin: tcp_slice.fin(),
97                rst: tcp_slice.rst(),
98            },
99            window: tcp_slice.window_size(),
100            option_window_scale,
101            option_timestamp,
102        };
103
104        Some((meta, tcp_slice.payload()))
105    }
106}
107
108impl Default for TcpParser {
109    fn default() -> Self {
110        Self::new()
111    }
112}
113
114/// layer of input packets
115pub enum ParseLayer {
116    /// link layer (layer 2)
117    Link,
118    /// IP layer (layer 3)
119    IP,
120    /// BSD loopback (linktype 0/NULL)
121    BsdLoopback,
122}