retina_core/conntrack/
mod.rs1pub(crate) mod conn;
8pub mod conn_id;
9pub(crate) mod pdu;
10mod timerwheel;
11
12use self::conn::conn_info::ConnState;
13use self::conn::{Conn, L4Conn};
14use self::conn_id::ConnId;
15use self::pdu::{L4Context, L4Pdu};
16use self::timerwheel::TimerWheel;
17use crate::config::ConnTrackConfig;
18use crate::memory::mbuf::Mbuf;
19use crate::protocols::packet::tcp::TCP_PROTOCOL;
20use crate::protocols::packet::udp::UDP_PROTOCOL;
21use crate::protocols::stream::ParserRegistry;
22use crate::subscription::{Subscription, Trackable};
23
24use std::cmp;
25use std::time::Instant;
26
27use anyhow::anyhow;
28use hashlink::linked_hash_map::{LinkedHashMap, RawEntryMut};
29
30pub struct ConnTracker<T>
37where
38 T: Trackable,
39{
40 config: TrackerConfig,
42 registry: ParserRegistry,
44 table: LinkedHashMap<ConnId, Conn<T>>,
46 timerwheel: TimerWheel,
48}
49
50impl<T> ConnTracker<T>
51where
52 T: Trackable,
53{
54 pub(crate) fn new(config: TrackerConfig, registry: ParserRegistry) -> Self {
56 let table = LinkedHashMap::with_capacity(config.max_connections);
57 let timerwheel = TimerWheel::new(
58 cmp::max(config.tcp_inactivity_timeout, config.udp_inactivity_timeout),
59 config.timeout_resolution,
60 );
61 ConnTracker {
62 config,
63 registry,
64 table,
65 timerwheel,
66 }
67 }
68
69 #[inline]
71 pub(crate) fn size(&self) -> usize {
72 self.table.len()
73 }
74
75 pub(crate) fn process(
77 &mut self,
78 mbuf: Mbuf,
79 ctxt: L4Context,
80 subscription: &Subscription<T::Subscribed>,
81 ) {
82 let conn_id = ConnId::new(ctxt.src, ctxt.dst, ctxt.proto);
83 match self.table.raw_entry_mut().from_key(&conn_id) {
84 RawEntryMut::Occupied(mut occupied) => {
85 let conn = occupied.get_mut();
86 conn.last_seen_ts = Instant::now();
87 if conn.state() == ConnState::Dropped {
88 return;
92 }
93 let dir = conn.packet_dir(&ctxt);
94 conn.inactivity_window = match &conn.l4conn {
95 L4Conn::Tcp(_) => self.config.tcp_inactivity_timeout,
96 L4Conn::Udp(_) => self.config.udp_inactivity_timeout,
97 };
98 if conn.state() == ConnState::Remove {
99 log::error!("Conn in Remove state when occupied in table");
100 }
101 let pdu = L4Pdu::new(mbuf, ctxt, dir);
102 conn.update(pdu, subscription, &self.registry);
103 if conn.state() == ConnState::Remove {
104 occupied.remove();
105 return;
106 }
107
108 if conn.terminated() {
109 conn.terminate(subscription);
110 occupied.remove();
111 }
112 }
113 RawEntryMut::Vacant(_) => {
114 if self.size() < self.config.max_connections {
115 let conn = match ctxt.proto {
116 TCP_PROTOCOL => Conn::new_tcp(
117 ctxt,
118 self.config.tcp_establish_timeout,
119 self.config.max_out_of_order,
120 ),
121 UDP_PROTOCOL => Conn::new_udp(ctxt, self.config.udp_inactivity_timeout),
122 _ => Err(anyhow!("Invalid L4 Protocol")),
123 };
124 if let Ok(mut conn) = conn {
125 let pdu = L4Pdu::new(mbuf, ctxt, true);
126 conn.info.consume_pdu(pdu, subscription, &self.registry);
127 if conn.state() != ConnState::Remove {
128 self.timerwheel.insert(
129 &conn_id,
130 conn.last_seen_ts,
131 conn.inactivity_window,
132 );
133 self.table.insert(conn_id, conn);
134 }
135 }
136 } else {
137 log::error!("Table full. Dropping packet.");
138 }
139 }
140 }
141 }
142
143 pub(crate) fn drain(&mut self, subscription: &Subscription<T::Subscribed>) {
145 log::info!("Draining Connection table");
146 for (_, mut conn) in self.table.drain() {
147 conn.terminate(subscription);
148 }
149 }
150
151 pub(crate) fn check_inactive(&mut self, subscription: &Subscription<T::Subscribed>) {
153 self.timerwheel
154 .check_inactive(&mut self.table, subscription);
155 }
156}
157
158#[derive(Debug)]
160pub(crate) struct TrackerConfig {
161 pub(super) max_connections: usize,
163 pub(super) max_out_of_order: usize,
165 pub(super) udp_inactivity_timeout: usize,
167 pub(super) tcp_inactivity_timeout: usize,
169 pub(super) tcp_establish_timeout: usize,
171 pub(super) timeout_resolution: usize,
173}
174
175impl From<&ConnTrackConfig> for TrackerConfig {
176 fn from(config: &ConnTrackConfig) -> Self {
177 TrackerConfig {
178 max_connections: config.max_connections,
179 max_out_of_order: config.max_out_of_order,
180 udp_inactivity_timeout: config.udp_inactivity_timeout,
181 tcp_inactivity_timeout: config.tcp_inactivity_timeout,
182 tcp_establish_timeout: config.tcp_establish_timeout,
183 timeout_resolution: config.timeout_resolution,
184 }
185 }
186}