1use std::net::IpAddr;
2
3use etherparse::{InternetSlice, SlicedPacket, TcpOptionElement, TransportSlice};
4use tracing::{debug, trace};
5
6use crate::{TcpFlags, TcpMeta};
7
8pub 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 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 ParseLayer::BsdLoopback => SlicedPacket::from_ip(&data[4..]),
31 };
32 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 _ => {}
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
114pub enum ParseLayer {
116 Link,
118 IP,
120 BsdLoopback,
122}