retina_core/protocols/stream/
mod.rs1pub mod dns;
8pub mod http;
9pub mod quic;
10pub mod tls;
11
12use self::dns::{parser::DnsParser, Dns};
13use self::http::{parser::HttpParser, Http};
14use self::quic::parser::QuicParser;
15use self::tls::{parser::TlsParser, Tls};
16use crate::conntrack::conn::conn_info::ConnState;
17use crate::conntrack::conn_id::FiveTuple;
18use crate::conntrack::pdu::L4Pdu;
19use crate::filter::Filter;
20use crate::subscription::*;
21
22use std::str::FromStr;
23
24use anyhow::{bail, Result};
25use quic::QuicConn;
26use strum_macros::EnumString;
27
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub(crate) enum ParseResult {
31 Done(usize),
33 Continue(usize),
36 Skipped,
38}
39
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub(crate) enum ProbeResult {
43 Certain,
45 Unsure,
47 NotForUs,
49 Error,
51}
52
53#[derive(Debug)]
55pub(crate) enum ProbeRegistryResult {
56 Some(ConnParser),
58 None,
60 Unsure,
62}
63
64#[derive(Debug)]
66pub(crate) struct ParserRegistry(Vec<ConnParser>);
67
68impl ParserRegistry {
69 pub(crate) fn build<T: Subscribable>(filter: &Filter) -> Result<ParserRegistry> {
71 let parsers = T::parsers();
72 if !parsers.is_empty() {
73 return Ok(ParserRegistry(parsers));
74 }
75
76 let mut stream_protocols = hashset! {};
77 for pattern in filter.get_patterns_flat().iter() {
78 for predicate in pattern.predicates.iter() {
79 if predicate.on_connection() {
80 stream_protocols.insert(predicate.get_protocol().to_owned());
81 }
82 }
83 }
84
85 let mut parsers = vec![];
86 for stream_protocol in stream_protocols.iter() {
87 if let Ok(parser) = ConnParser::from_str(stream_protocol.name()) {
88 parsers.push(parser);
89 } else {
90 bail!("Unknown application-layer protocol");
91 }
92 }
93 Ok(ParserRegistry(parsers))
94 }
95
96 pub(crate) fn probe_all(&self, pdu: &L4Pdu) -> ProbeRegistryResult {
98 if self.0.is_empty() {
99 return ProbeRegistryResult::None;
100 }
101 if pdu.length() == 0 {
102 return ProbeRegistryResult::Unsure;
103 }
104
105 let mut num_notmatched = 0;
106 for parser in self.0.iter() {
107 match parser.probe(pdu) {
108 ProbeResult::Certain => {
109 return ProbeRegistryResult::Some(parser.reset_new());
110 }
111 ProbeResult::NotForUs => {
112 num_notmatched += 1;
113 }
114 _ => (), }
116 }
117 if num_notmatched == self.0.len() {
118 ProbeRegistryResult::None
119 } else {
120 ProbeRegistryResult::Unsure
121 }
122 }
123}
124
125pub(crate) trait ConnParsable {
127 fn parse(&mut self, pdu: &L4Pdu) -> ParseResult;
129
130 fn probe(&self, pdu: &L4Pdu) -> ProbeResult;
132
133 fn remove_session(&mut self, session_id: usize) -> Option<Session>;
135
136 fn drain_sessions(&mut self) -> Vec<Session>;
138
139 fn session_match_state(&self) -> ConnState;
141
142 fn session_nomatch_state(&self) -> ConnState;
144}
145
146#[doc(hidden)]
154#[derive(Debug)]
155pub struct ConnData {
156 pub five_tuple: FiveTuple,
158 pub conn_parser: ConnParser,
160 pub pkt_term_node: usize,
162 pub conn_term_node: usize,
165}
166
167impl ConnData {
168 pub(crate) fn new(five_tuple: FiveTuple, pkt_term_node: usize) -> Self {
171 ConnData {
172 five_tuple,
173 conn_parser: ConnParser::Unknown,
174 pkt_term_node,
175 conn_term_node: pkt_term_node,
176 }
177 }
178
179 pub fn service(&self) -> &ConnParser {
181 &self.conn_parser
182 }
183}
184
185#[doc(hidden)]
193#[derive(Debug)]
194pub enum SessionData {
195 Tls(Box<Tls>),
197 Dns(Box<Dns>),
198 Http(Box<Http>),
199 Quic(Box<QuicConn>),
200 Null,
201}
202
203#[doc(hidden)]
211pub struct Session {
212 pub data: SessionData,
214 pub id: usize,
216}
217
218impl Default for Session {
219 fn default() -> Self {
220 Session {
221 data: SessionData::Null,
222 id: 0,
223 }
224 }
225}
226
227#[doc(hidden)]
235#[derive(Debug, EnumString)]
236#[strum(serialize_all = "snake_case")]
237pub enum ConnParser {
238 Tls(TlsParser),
240 Dns(DnsParser),
241 Http(HttpParser),
242 Quic(QuicParser),
243 Unknown,
244}
245
246impl ConnParser {
247 pub(crate) fn reset_new(&self) -> ConnParser {
249 match self {
250 ConnParser::Tls(_) => ConnParser::Tls(TlsParser::default()),
251 ConnParser::Dns(_) => ConnParser::Dns(DnsParser::default()),
252 ConnParser::Http(_) => ConnParser::Http(HttpParser::default()),
253 ConnParser::Quic(_) => ConnParser::Quic(QuicParser::default()),
254 ConnParser::Unknown => ConnParser::Unknown,
255 }
256 }
257
258 pub(crate) fn parse(&mut self, pdu: &L4Pdu) -> ParseResult {
260 match self {
261 ConnParser::Tls(parser) => parser.parse(pdu),
262 ConnParser::Dns(parser) => parser.parse(pdu),
263 ConnParser::Http(parser) => parser.parse(pdu),
264 ConnParser::Quic(parser) => parser.parse(pdu),
265 ConnParser::Unknown => ParseResult::Skipped,
266 }
267 }
268
269 pub(crate) fn probe(&self, pdu: &L4Pdu) -> ProbeResult {
271 match self {
272 ConnParser::Tls(parser) => parser.probe(pdu),
273 ConnParser::Dns(parser) => parser.probe(pdu),
274 ConnParser::Http(parser) => parser.probe(pdu),
275 ConnParser::Quic(parser) => parser.probe(pdu),
276 ConnParser::Unknown => ProbeResult::Error,
277 }
278 }
279
280 pub(crate) fn remove_session(&mut self, session_id: usize) -> Option<Session> {
283 match self {
284 ConnParser::Tls(parser) => parser.remove_session(session_id),
285 ConnParser::Dns(parser) => parser.remove_session(session_id),
286 ConnParser::Http(parser) => parser.remove_session(session_id),
287 ConnParser::Quic(parser) => parser.remove_session(session_id),
288 ConnParser::Unknown => None,
289 }
290 }
291
292 pub(crate) fn drain_sessions(&mut self) -> Vec<Session> {
294 match self {
295 ConnParser::Tls(parser) => parser.drain_sessions(),
296 ConnParser::Dns(parser) => parser.drain_sessions(),
297 ConnParser::Http(parser) => parser.drain_sessions(),
298 ConnParser::Quic(parser) => parser.drain_sessions(),
299 ConnParser::Unknown => vec![],
300 }
301 }
302
303 pub(crate) fn session_match_state(&self) -> ConnState {
305 match self {
306 ConnParser::Tls(parser) => parser.session_match_state(),
307 ConnParser::Dns(parser) => parser.session_match_state(),
308 ConnParser::Http(parser) => parser.session_match_state(),
309 ConnParser::Quic(parser) => parser.session_match_state(),
310 ConnParser::Unknown => ConnState::Remove,
311 }
312 }
313
314 pub(crate) fn session_nomatch_state(&self) -> ConnState {
316 match self {
317 ConnParser::Tls(parser) => parser.session_nomatch_state(),
318 ConnParser::Dns(parser) => parser.session_nomatch_state(),
319 ConnParser::Http(parser) => parser.session_nomatch_state(),
320 ConnParser::Quic(parser) => parser.session_nomatch_state(),
321 ConnParser::Unknown => ConnState::Remove,
322 }
323 }
324}