retina_core/conntrack/conn/
mod.rs1pub(crate) mod conn_info;
7pub(crate) mod tcp_conn;
8pub(crate) mod udp_conn;
9
10use self::conn_info::{ConnInfo, ConnState};
11use self::tcp_conn::TcpConn;
12use self::udp_conn::UdpConn;
13use crate::conntrack::conn_id::FiveTuple;
14use crate::conntrack::pdu::{L4Context, L4Pdu};
15use crate::filter::FilterResult;
16use crate::protocols::packet::tcp::{ACK, RST, SYN};
17use crate::protocols::stream::ParserRegistry;
18use crate::subscription::{Subscription, Trackable};
19
20use anyhow::{bail, Result};
21use std::time::Instant;
22
23pub(crate) enum L4Conn {
27 Tcp(TcpConn),
28 Udp(UdpConn),
29}
30
31pub(crate) struct Conn<T>
33where
34 T: Trackable,
35{
36 pub(crate) last_seen_ts: Instant,
38 pub(crate) inactivity_window: usize,
40 pub(crate) l4conn: L4Conn,
42 pub(crate) info: ConnInfo<T>,
44}
45
46impl<T> Conn<T>
47where
48 T: Trackable,
49{
50 pub(super) fn new_tcp(ctxt: L4Context, initial_timeout: usize, max_ooo: usize) -> Result<Self> {
55 let five_tuple = FiveTuple::from_ctxt(ctxt);
56 let tcp_conn = if ctxt.flags & SYN != 0 && ctxt.flags & ACK == 0 && ctxt.flags & RST == 0 {
57 TcpConn::new_on_syn(ctxt, max_ooo)
58 } else {
59 bail!("Not SYN")
60 };
61 Ok(Conn {
62 last_seen_ts: Instant::now(),
63 inactivity_window: initial_timeout,
64 l4conn: L4Conn::Tcp(tcp_conn),
65 info: ConnInfo::new(five_tuple, ctxt.idx),
66 })
67 }
68
69 #[allow(clippy::unnecessary_wraps)]
72 pub(super) fn new_udp(ctxt: L4Context, initial_timeout: usize) -> Result<Self> {
73 let five_tuple = FiveTuple::from_ctxt(ctxt);
74 let udp_conn = UdpConn;
75 Ok(Conn {
76 last_seen_ts: Instant::now(),
77 inactivity_window: initial_timeout,
78 l4conn: L4Conn::Udp(udp_conn),
79 info: ConnInfo::new(five_tuple, ctxt.idx),
80 })
81 }
82
83 pub(super) fn update(
85 &mut self,
86 pdu: L4Pdu,
87 subscription: &Subscription<T::Subscribed>,
88 registry: &ParserRegistry,
89 ) {
90 match &mut self.l4conn {
91 L4Conn::Tcp(tcp_conn) => {
92 if self.info.state == ConnState::Tracking {
93 if tcp_conn.ctos.ooo_buf.len() != 0 {
94 tcp_conn.ctos.ooo_buf.buf.clear();
95 }
96 if tcp_conn.stoc.ooo_buf.len() != 0 {
97 tcp_conn.stoc.ooo_buf.buf.clear();
98 }
99 tcp_conn.update_term_condition(pdu.flags(), pdu.dir);
100 self.info.sdata.post_match(pdu, subscription);
101 } else {
102 tcp_conn.reassemble(pdu, &mut self.info, subscription, registry);
103 }
104 }
105 L4Conn::Udp(_udp_conn) => self.info.consume_pdu(pdu, subscription, registry),
106 }
107 }
108
109 pub(super) fn five_tuple(&self) -> FiveTuple {
111 self.info.cdata.five_tuple
112 }
113
114 pub(super) fn state(&self) -> ConnState {
116 self.info.state
117 }
118
119 pub(super) fn terminated(&self) -> bool {
121 match &self.l4conn {
122 L4Conn::Tcp(tcp_conn) => tcp_conn.is_terminated(),
123 L4Conn::Udp(_udp_conn) => false,
124 }
125 }
126
127 pub(super) fn packet_dir(&self, ctxt: &L4Context) -> bool {
130 self.five_tuple().orig == ctxt.src
131 }
132
133 pub(crate) fn terminate(&mut self, subscription: &Subscription<T::Subscribed>) {
139 match self.info.state {
140 ConnState::Probing => {
141 if let FilterResult::MatchTerminal(_) = subscription.filter_conn(&self.info.cdata) {
142 self.info.sdata.on_terminate(subscription);
143 }
144 }
145 ConnState::Parsing => {
146 let mut first_session_matched = false;
148 for session in self.info.cdata.conn_parser.drain_sessions() {
149 if subscription.filter_session(&session, self.info.cdata.conn_term_node) {
150 if session.id == 0 {
151 first_session_matched = true;
152 }
153 self.info.sdata.on_match(session, subscription);
154 }
155 }
156 if first_session_matched {
157 self.info.sdata.on_terminate(subscription);
158 }
159 }
160 ConnState::Tracking => {
161 self.info.sdata.on_terminate(subscription);
162 }
163 ConnState::Remove | ConnState::Dropped => {
164 }
166 }
167 }
168}