#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "kind", rename_all = "snake_case"))]
#[non_exhaustive]
pub enum IeAbstractType {
Unsigned8,
Unsigned16,
Unsigned32,
Unsigned64,
Signed8,
Signed16,
Signed32,
Signed64,
Float32,
Float64,
Boolean,
MacAddress,
OctetArray,
String,
DateTimeSeconds,
DateTimeMilliseconds,
DateTimeMicroseconds,
DateTimeNanoseconds,
Ipv4Address,
Ipv6Address,
BasicList,
SubTemplateList,
SubTemplateMultiList,
}
impl IeAbstractType {
pub fn as_str(&self) -> &'static str {
match self {
IeAbstractType::Unsigned8 => "unsigned8",
IeAbstractType::Unsigned16 => "unsigned16",
IeAbstractType::Unsigned32 => "unsigned32",
IeAbstractType::Unsigned64 => "unsigned64",
IeAbstractType::Signed8 => "signed8",
IeAbstractType::Signed16 => "signed16",
IeAbstractType::Signed32 => "signed32",
IeAbstractType::Signed64 => "signed64",
IeAbstractType::Float32 => "float32",
IeAbstractType::Float64 => "float64",
IeAbstractType::Boolean => "boolean",
IeAbstractType::MacAddress => "macAddress",
IeAbstractType::OctetArray => "octetArray",
IeAbstractType::String => "string",
IeAbstractType::DateTimeSeconds => "dateTimeSeconds",
IeAbstractType::DateTimeMilliseconds => "dateTimeMilliseconds",
IeAbstractType::DateTimeMicroseconds => "dateTimeMicroseconds",
IeAbstractType::DateTimeNanoseconds => "dateTimeNanoseconds",
IeAbstractType::Ipv4Address => "ipv4Address",
IeAbstractType::Ipv6Address => "ipv6Address",
IeAbstractType::BasicList => "basicList",
IeAbstractType::SubTemplateList => "subTemplateList",
IeAbstractType::SubTemplateMultiList => "subTemplateMultiList",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub struct InformationElement {
pub id: u16,
pub name: &'static str,
pub abstract_type: IeAbstractType,
pub units: Option<&'static str>,
pub description: &'static str,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "serde", serde(tag = "kind", rename_all = "snake_case"))]
#[non_exhaustive]
pub enum FlowEndReason {
IdleTimeout,
ActiveTimeout,
EndOfFlowDetected,
ForcedEnd,
LackOfResources,
}
impl FlowEndReason {
pub fn as_u8(self) -> u8 {
match self {
FlowEndReason::IdleTimeout => 1,
FlowEndReason::ActiveTimeout => 2,
FlowEndReason::EndOfFlowDetected => 3,
FlowEndReason::ForcedEnd => 4,
FlowEndReason::LackOfResources => 5,
}
}
pub fn from_u8(v: u8) -> Option<Self> {
Some(match v {
1 => FlowEndReason::IdleTimeout,
2 => FlowEndReason::ActiveTimeout,
3 => FlowEndReason::EndOfFlowDetected,
4 => FlowEndReason::ForcedEnd,
5 => FlowEndReason::LackOfResources,
_ => return None,
})
}
}
#[cfg(feature = "tracker")]
impl From<crate::EndReason> for FlowEndReason {
fn from(r: crate::EndReason) -> Self {
use crate::EndReason as E;
match r {
E::Fin | E::Rst => FlowEndReason::EndOfFlowDetected,
E::IdleTimeout => FlowEndReason::IdleTimeout,
E::Evicted => FlowEndReason::LackOfResources,
E::BufferOverflow | E::ParseError | E::ParserDone | E::ForceClosed => {
FlowEndReason::ForcedEnd
}
}
}
}
#[allow(clippy::too_many_arguments)]
pub fn encode_tcp_control_bits(
fin: bool,
syn: bool,
rst: bool,
psh: bool,
ack: bool,
urg: bool,
ece: bool,
cwr: bool,
) -> u16 {
let mut bits: u16 = 0;
if fin {
bits |= 1 << 0;
}
if syn {
bits |= 1 << 1;
}
if rst {
bits |= 1 << 2;
}
if psh {
bits |= 1 << 3;
}
if ack {
bits |= 1 << 4;
}
if urg {
bits |= 1 << 5;
}
if ece {
bits |= 1 << 6;
}
if cwr {
bits |= 1 << 7;
}
bits
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn abstract_type_slugs_locked() {
assert_eq!(IeAbstractType::Unsigned32.as_str(), "unsigned32");
assert_eq!(IeAbstractType::Ipv4Address.as_str(), "ipv4Address");
assert_eq!(
IeAbstractType::DateTimeMilliseconds.as_str(),
"dateTimeMilliseconds"
);
}
#[test]
fn flow_end_reason_round_trip_u8() {
for r in [
FlowEndReason::IdleTimeout,
FlowEndReason::ActiveTimeout,
FlowEndReason::EndOfFlowDetected,
FlowEndReason::ForcedEnd,
FlowEndReason::LackOfResources,
] {
assert_eq!(FlowEndReason::from_u8(r.as_u8()), Some(r));
}
assert_eq!(FlowEndReason::from_u8(0), None);
assert_eq!(FlowEndReason::from_u8(99), None);
}
#[test]
fn flow_end_reason_iana_numeric_values() {
assert_eq!(FlowEndReason::IdleTimeout.as_u8(), 1);
assert_eq!(FlowEndReason::ActiveTimeout.as_u8(), 2);
assert_eq!(FlowEndReason::EndOfFlowDetected.as_u8(), 3);
assert_eq!(FlowEndReason::ForcedEnd.as_u8(), 4);
assert_eq!(FlowEndReason::LackOfResources.as_u8(), 5);
}
#[cfg(feature = "tracker")]
#[test]
fn end_reason_maps_to_ipfix_canonical() {
use crate::EndReason;
assert_eq!(
FlowEndReason::from(EndReason::Fin),
FlowEndReason::EndOfFlowDetected
);
assert_eq!(
FlowEndReason::from(EndReason::Rst),
FlowEndReason::EndOfFlowDetected
);
assert_eq!(
FlowEndReason::from(EndReason::IdleTimeout),
FlowEndReason::IdleTimeout
);
assert_eq!(
FlowEndReason::from(EndReason::Evicted),
FlowEndReason::LackOfResources
);
assert_eq!(
FlowEndReason::from(EndReason::ForceClosed),
FlowEndReason::ForcedEnd
);
assert_eq!(
FlowEndReason::from(EndReason::BufferOverflow),
FlowEndReason::ForcedEnd
);
}
#[test]
fn encode_tcp_control_bits_layout() {
assert_eq!(
encode_tcp_control_bits(false, false, false, false, false, false, false, false),
0
);
assert_eq!(
encode_tcp_control_bits(false, true, false, false, false, false, false, false),
0x02
);
assert_eq!(
encode_tcp_control_bits(false, true, false, false, true, false, false, false),
0x12
);
assert_eq!(
encode_tcp_control_bits(true, true, true, true, true, true, true, true),
0xff
);
}
}