pub mod builtin;
pub mod event_typed;
pub use event_typed::{
AnyFlowAnomaly, Event, FlowEnded, FlowEstablished, FlowPacket, FlowStarted, FlowTick,
ParserClosed, Side, Tick,
};
#[cfg(feature = "dhcp")]
pub use builtin::Dhcp;
#[cfg(feature = "dnp3")]
pub use builtin::Dnp3;
#[cfg(feature = "dns")]
pub use builtin::Dns;
#[cfg(feature = "ftp")]
pub use builtin::Ftp;
#[cfg(feature = "http")]
pub use builtin::Http;
#[cfg(feature = "kerberos")]
pub use builtin::Kerberos;
#[cfg(feature = "ldap")]
pub use builtin::Ldap;
#[cfg(feature = "modbus")]
pub use builtin::Modbus;
#[cfg(feature = "netbios-ns")]
pub use builtin::Nbns;
#[cfg(feature = "ntp")]
pub use builtin::Ntp;
#[cfg(feature = "quic")]
pub use builtin::Quic;
#[cfg(feature = "radius")]
pub use builtin::Radius;
#[cfg(feature = "rdp")]
pub use builtin::Rdp;
#[cfg(feature = "smb")]
pub use builtin::Smb;
#[cfg(feature = "smtp")]
pub use builtin::Smtp;
#[cfg(feature = "snmp")]
pub use builtin::Snmp;
#[cfg(feature = "ssdp")]
pub use builtin::Ssdp;
#[cfg(feature = "ssh")]
pub use builtin::Ssh;
#[cfg(feature = "stun")]
pub use builtin::Stun;
#[cfg(feature = "tftp")]
pub use builtin::Tftp;
#[cfg(feature = "wireguard")]
pub use builtin::WireGuard;
pub use builtin::{Icmp, Tcp, Udp};
#[cfg(feature = "tls")]
pub use builtin::{Tls, TlsHandshake};
pub trait Protocol: Send + Sync + 'static {
type Message: Send + Sync + 'static;
const NAME: &'static str;
fn dispatch() -> Dispatch;
fn register(
builder: &mut flowscope::driver::DriverBuilder<flowscope::extract::FiveTuple>,
) -> Result<
flowscope::driver::SlotHandle<Self::Message, flowscope::extract::FiveTupleKey>,
ProtocolInitError,
>;
fn register_broadcast(
_builder: &mut flowscope::driver::DriverBuilder<flowscope::extract::FiveTuple>,
) -> Result<
flowscope::driver::BroadcastSlotHandle<Self::Message, flowscope::extract::FiveTupleKey>,
ProtocolInitError,
>
where
Self::Message: Send + Sync + Clone + 'static,
{
Err(ProtocolInitError(format!(
"{} does not support broadcast (only session-shaped L7 protocols do today)",
Self::NAME
)))
}
fn make_slot(
handle: flowscope::driver::SlotHandle<Self::Message, flowscope::extract::FiveTupleKey>,
) -> Box<dyn crate::monitor::ProtocolSlot>
where
Self: Sized,
{
Box::new(crate::monitor::TypedProtocolSlot::<Self>::new(handle))
}
}
pub trait FlowProtocol: Protocol {}
pub trait MessageProtocol: Protocol {}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum Dispatch {
Tcp(Vec<u16>),
Udp(Vec<u16>),
Icmp,
AllTcp,
AllUdp,
Signature(fn(&[u8]) -> SignatureMatch),
}
#[derive(Debug, Clone)]
#[non_exhaustive]
pub enum TrafficClass {
Any,
Dispatch(Dispatch),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SignatureMatch {
Match,
NoMatch,
NeedMoreData,
}
impl From<flowscope::detect::signatures::SignatureMatch> for SignatureMatch {
fn from(s: flowscope::detect::signatures::SignatureMatch) -> Self {
use flowscope::detect::signatures::SignatureMatch as Fs;
match s {
Fs::Match => SignatureMatch::Match,
Fs::NoMatch => SignatureMatch::NoMatch,
Fs::NeedMoreData => SignatureMatch::NeedMoreData,
}
}
}
#[derive(Debug, thiserror::Error)]
#[error("protocol parser init failed: {0}")]
pub struct ProtocolInitError(pub String);
pub type FlowKey = flowscope::extract::FiveTupleKey;
#[cfg(test)]
mod plugin_tests {
use super::*;
#[test]
fn signature_match_from_flowscope_roundtrip() {
use flowscope::detect::signatures::SignatureMatch as Fs;
assert_eq!(SignatureMatch::from(Fs::Match), SignatureMatch::Match);
assert_eq!(SignatureMatch::from(Fs::NoMatch), SignatureMatch::NoMatch);
assert_eq!(
SignatureMatch::from(Fs::NeedMoreData),
SignatureMatch::NeedMoreData
);
}
#[test]
fn dispatch_is_clone_and_debug() {
let d = Dispatch::Tcp(vec![80, 8080]);
let _ = format!("{d:?}");
let _ = d.clone();
}
#[test]
fn protocol_init_error_displays() {
let e = ProtocolInitError("config missing".into());
assert!(format!("{e}").contains("config missing"));
}
}