use super::common::*;
use crate::protocol::ProtocolTypes;
use crate::variable_versions::ipfix_lookup::*;
use crate::{NetflowByteParserVariable, NetflowPacket, ParsedNetflow};
use log::error;
use nom::bytes::complete::take;
use nom::error::{Error as NomError, ErrorKind};
use nom::number::complete::{be_u128, be_u32};
use nom::Err as NomErr;
use nom::IResult;
use nom_derive::*;
use serde::Serialize;
use Nom;
use std::collections::BTreeMap;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::time::Duration;
const TEMPLATE_ID: u16 = 2;
const OPTIONS_TEMPLATE_ID: u16 = 3;
const SET_MIN_RANGE: u16 = 255;
type TemplateId = u16;
#[derive(Default, Debug)]
pub struct IPFixParser {
pub templates: BTreeMap<TemplateId, Template>,
pub options_templates: BTreeMap<TemplateId, OptionsTemplate>,
}
#[derive(Debug, PartialEq, Clone, Serialize)]
pub struct IPFix {
pub header: Header,
pub sets: Vec<Set>,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Nom)]
pub struct Header {
pub version: u16,
pub length: u16,
#[nom(Map = "|i| Duration::from_secs(i as u64)", Parse = "be_u32")]
pub export_time: Duration,
pub sequence_number: u32,
pub observation_domain_id: u32,
}
#[derive(Debug, PartialEq, Clone, Serialize, Nom)]
#[nom(ExtraArgs(parser: &mut IPFixParser))]
pub struct Set {
pub id: u16,
pub length: u16,
#[nom(
Cond = "id == TEMPLATE_ID",
PostExec = "if let Some(template) = template.clone() { parser.templates.insert(template.template_id, template); }"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub template: Option<Template>,
#[nom(
Cond = "id == OPTIONS_TEMPLATE_ID",
Parse = "{ |i| parse_options_template(i, length) }",
PostExec = "if let Some(options_template) = options_template.clone() { parser.options_templates.insert(options_template.template_id, options_template); }"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub options_template: Option<OptionsTemplate>,
#[nom(
Cond = "id > SET_MIN_RANGE && parser.templates.get(&id).is_some()",
Parse = "{ |i| Data::parse(i, parser, id) }"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub data: Option<Data>,
#[nom(
Cond = "id > SET_MIN_RANGE && parser.options_templates.get(&id).is_some()",
Parse = "{ |i| OptionsData::parse(i, parser, id) }"
)]
#[serde(skip_serializing_if = "Option::is_none")]
pub options_data: Option<OptionsData>,
}
#[derive(Debug, PartialEq, Clone, Serialize, Nom)]
#[nom(ExtraArgs(parser: &mut IPFixParser, set_id: u16))]
pub struct Data {
#[nom(
Parse = "{ |i| parse_fields::<Template>(i, parser.templates.get(&set_id).cloned()) }"
)]
pub data_fields: Vec<BTreeMap<IPFixField, FieldValue>>,
}
#[derive(Debug, PartialEq, Clone, Serialize, Nom)]
#[nom(ExtraArgs(parser: &mut IPFixParser, set_id: u16))]
pub struct OptionsData {
#[nom(
Parse = "{ |i| parse_fields::<OptionsTemplate>(i, parser.options_templates.get(&set_id).cloned()) }"
)]
pub data_fields: Vec<BTreeMap<IPFixField, FieldValue>>,
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Nom)]
pub struct OptionsTemplate {
pub template_id: u16,
pub field_count: u16,
pub scope_field_count: u16,
#[nom(Count = "scope_field_count")]
pub scope_field_specifiers: Vec<OptionsTemplateField>,
#[nom(
Count = "(field_count.checked_sub(scope_field_count).unwrap_or(field_count)) as usize"
)]
pub field_specifiers: Vec<OptionsTemplateField>,
#[nom(Cond = "!i.is_empty()")]
#[serde(skip_serializing)]
padding: Option<u16>,
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Nom)]
pub struct Template {
pub template_id: u16,
pub field_count: u16,
#[nom(Count = "field_count")]
pub fields: Vec<TemplateField>,
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, Nom)]
pub struct OptionsTemplateField {
pub field_type_number: u16,
#[nom(Value(IPFixField::from(field_type_number)))]
pub field_type: IPFixField,
field_length: u16,
#[nom(
Cond = "field_type_number > 32767",
PostExec = "let field_type_number = field_type_number.overflowing_sub(32768).0;",
PostExec = "let field_type = set_entperprise_field(field_type, enterprise_number);"
)]
#[serde(skip_serializing_if = "Option::is_none")]
enterprise_number: Option<u32>,
}
fn set_entperprise_field(field_type: IPFixField, enterprise_number: Option<u32>) -> IPFixField {
match enterprise_number {
Some(_) => IPFixField::Enterprise,
None => field_type,
}
}
#[derive(Debug, PartialEq, Eq, Clone, Serialize, PartialOrd, Ord, Nom)]
pub struct TemplateField {
pub field_type_number: u16,
#[nom(Value(IPFixField::from(field_type_number)))]
pub field_type: IPFixField,
pub field_length: u16,
}
fn parse_options_template(i: &[u8], length: u16) -> IResult<&[u8], OptionsTemplate> {
let (remaining, taken) = take(length.checked_sub(4).unwrap_or(length))(i)?;
let (_, option_template) = OptionsTemplate::parse(taken).unwrap();
Ok((remaining, option_template))
}
trait CommonTemplateFields {
fn get_fields(&self) -> Vec<OptionsTemplateField>;
}
impl CommonTemplateFields for Template {
fn get_fields(&self) -> Vec<OptionsTemplateField> {
self.fields
.iter()
.map(|f| OptionsTemplateField {
field_length: f.field_length,
field_type: f.field_type,
field_type_number: f.field_type_number,
enterprise_number: None,
})
.collect()
}
}
impl CommonTemplateFields for OptionsTemplate {
fn get_fields(&self) -> Vec<OptionsTemplateField> {
let mut temp = vec![];
temp.append(&mut self.scope_field_specifiers.clone());
temp.append(&mut self.field_specifiers.clone());
temp
}
}
fn parse_fields<T: CommonTemplateFields>(
i: &[u8],
template: Option<T>,
) -> IResult<&[u8], Vec<BTreeMap<IPFixField, FieldValue>>> {
let template = match template {
Some(t) => t,
None => {
error!("Could not fetch any v10 templates!");
return Err(NomErr::Error(NomError::new(i, ErrorKind::Fail)));
}
};
let mut fields = vec![];
let mut remaining = i;
while !remaining.is_empty() {
let mut data_field = BTreeMap::new();
for template_field in template.get_fields().iter() {
let field_type: FieldDataType = template_field.field_type.into();
if template_field.enterprise_number.is_some() {
let (i, data_number) = parse_data_number(remaining, 4, false)?;
remaining = i;
data_field.insert(
template_field.field_type,
FieldValue::DataNumber(data_number),
);
continue;
}
let field_value = match field_type {
FieldDataType::UnsignedDataNumber => {
let (i, data_number) =
parse_data_number(remaining, template_field.field_length, false)?;
remaining = i;
FieldValue::DataNumber(data_number)
}
FieldDataType::SignedDataNumber => {
let (i, data_number) =
parse_data_number(remaining, template_field.field_length, true)?;
remaining = i;
FieldValue::DataNumber(data_number)
}
FieldDataType::String => {
let (i, taken) = take(template_field.field_length)(remaining)?;
remaining = i;
FieldValue::String(String::from_utf8_lossy(taken).to_string())
}
FieldDataType::Ip4Addr => {
let (i, taken) = be_u32(remaining)?;
remaining = i;
let ip_addr = Ipv4Addr::from(taken);
FieldValue::Ip4Addr(ip_addr)
}
FieldDataType::Ip6Addr => {
let (i, taken) = be_u128(remaining)?;
remaining = i;
let ip_addr = Ipv6Addr::from(taken);
FieldValue::Ip6Addr(ip_addr)
}
FieldDataType::DurationSeconds => {
let (i, data_number) =
parse_data_number(remaining, template_field.field_length, false)?;
remaining = i;
FieldValue::Duration(Duration::from_secs(data_number.get_value() as u64))
}
FieldDataType::DurationMillis => {
let (i, data_number) =
parse_data_number(remaining, template_field.field_length, false)?;
remaining = i;
FieldValue::Duration(Duration::from_millis(data_number.get_value() as u64))
}
FieldDataType::DurationMicros => {
let (i, data_number) =
parse_data_number(remaining, template_field.field_length, false)?;
remaining = i;
FieldValue::Duration(Duration::from_micros(data_number.get_value() as u64))
}
FieldDataType::DurationNanos => {
let (i, data_number) =
parse_data_number(remaining, template_field.field_length, false)?;
remaining = i;
FieldValue::Duration(Duration::from_nanos(data_number.get_value() as u64))
}
FieldDataType::ProtocolType => {
let (i, protocol) = ProtocolTypes::parse(remaining)?;
remaining = i;
FieldValue::ProtocolType(protocol)
}
FieldDataType::Float64 => {
let (i, f) = f64::parse(remaining)?;
remaining = i;
FieldValue::Float64(f)
}
FieldDataType::Vec => {
let (i, taken) = take(template_field.field_length)(remaining)?;
remaining = i;
FieldValue::Vec(taken.to_vec())
}
FieldDataType::Unknown => {
let (i, taken) = take(template_field.field_length)(remaining)?;
remaining = i;
FieldValue::Vec(taken.to_vec())
}
};
data_field.insert(template_field.field_type, field_value);
}
fields.push(data_field);
}
Ok((remaining, fields))
}
impl NetflowByteParserVariable for IPFixParser {
#[inline]
fn parse_bytes<'a>(
&'a mut self,
packet: &'a [u8],
) -> Result<ParsedNetflow, Box<dyn std::error::Error>> {
let mut sets = vec![];
let (mut remaining, v10_header) =
Header::parse(packet).map_err(|_| "Could not parse v10_packet".to_string())?;
let mut total_left = v10_header.length as usize;
dbg!("remaining: {}", remaining);
while total_left != 0 {
let (left_remaining, v10_set) = Set::parse(remaining, self)
.map_err(|e| format!("Could not parse v10_set: {e}"))?;
dbg!("left remaining: {}", left_remaining);
remaining = left_remaining;
let parsed = total_left
.checked_sub(remaining.len())
.unwrap_or(total_left);
total_left -= parsed;
sets.push(v10_set.clone());
}
let v10_parsed = IPFix {
header: v10_header,
sets,
};
Ok(ParsedNetflow {
remaining: remaining.to_vec(),
netflow_packet: NetflowPacket::IPFix(v10_parsed),
})
}
}