use crate::view::PacketView;
use bitflags::bitflags;
pub trait FlowExtractor: Send + Sync + 'static {
type Key: Eq + std::hash::Hash + Clone + Send + Sync + 'static;
fn extract(&self, view: PacketView<'_>) -> Option<Extracted<Self::Key>>;
}
#[derive(Debug, Clone)]
pub struct Extracted<K> {
pub key: K,
pub orientation: Orientation,
pub l4: Option<L4Proto>,
pub tcp: Option<TcpInfo>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Orientation {
Forward,
Reverse,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum L4Proto {
Tcp,
Udp,
Icmp,
IcmpV6,
Sctp,
Other(u8),
}
#[derive(Debug, Clone, Copy)]
pub struct TcpInfo {
pub flags: TcpFlags,
pub seq: u32,
pub ack: u32,
pub payload_offset: usize,
pub payload_len: usize,
}
bitflags! {
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TcpFlags: u8 {
const FIN = 0b0000_0001;
const SYN = 0b0000_0010;
const RST = 0b0000_0100;
const PSH = 0b0000_1000;
const ACK = 0b0001_0000;
const URG = 0b0010_0000;
const ECE = 0b0100_0000;
const CWR = 0b1000_0000;
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tcp_flags_basic() {
let f = TcpFlags::SYN | TcpFlags::ACK;
assert!(f.contains(TcpFlags::SYN));
assert!(f.contains(TcpFlags::ACK));
assert!(!f.contains(TcpFlags::FIN));
}
#[test]
fn extracted_clone() {
let e: Extracted<u32> = Extracted {
key: 42,
orientation: Orientation::Forward,
l4: Some(L4Proto::Tcp),
tcp: Some(TcpInfo {
flags: TcpFlags::SYN,
seq: 1,
ack: 0,
payload_offset: 54,
payload_len: 0,
}),
};
let cloned = e.clone();
assert_eq!(cloned.key, 42);
assert_eq!(cloned.orientation, Orientation::Forward);
}
#[test]
fn l4_proto_eq() {
assert_eq!(L4Proto::Tcp, L4Proto::Tcp);
assert_ne!(L4Proto::Tcp, L4Proto::Udp);
assert_eq!(L4Proto::Other(1), L4Proto::Other(1));
assert_ne!(L4Proto::Other(1), L4Proto::Other(2));
}
}