use crate::icmp::parser;
use crate::icmp::types::{IcmpFamily, IcmpMessage};
use crate::{DatagramParser, FlowSide, Timestamp};
#[derive(Debug, Default, Clone)]
pub struct IcmpParser {
only: Option<IcmpFamily>,
}
impl IcmpParser {
pub fn new() -> Self {
Self::default()
}
pub fn v4_only(mut self) -> Self {
self.only = Some(IcmpFamily::V4);
self
}
pub fn v6_only(mut self) -> Self {
self.only = Some(IcmpFamily::V6);
self
}
}
impl DatagramParser for IcmpParser {
type Message = IcmpMessage;
fn parse(
&mut self,
payload: &[u8],
_side: FlowSide,
_ts: Timestamp,
out: &mut Vec<IcmpMessage>,
) {
let Some(detected) = detect_family(payload) else {
return;
};
if let Some(want) = self.only
&& want != detected
{
return;
}
let parsed = match detected {
IcmpFamily::V4 => parser::parse_v4(payload),
IcmpFamily::V6 => parser::parse_v6(payload),
};
if let Ok(m) = parsed {
out.push(m);
}
}
fn parser_kind(&self) -> crate::ParserKind {
crate::ParserKind::Icmp
}
}
fn detect_family(payload: &[u8]) -> Option<IcmpFamily> {
let ty = *payload.first()?;
if ty >= 128 {
return Some(IcmpFamily::V6);
}
if (1..=4).contains(&ty)
&& let Some(&inner0) = payload.get(8)
{
return Some(if inner0 >> 4 == 6 {
IcmpFamily::V6
} else {
IcmpFamily::V4
});
}
Some(IcmpFamily::V4)
}