Skip to content

removed some clones #35

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
name = "netflow_parser"
description = "Parser for Netflow Cisco V5, V7, V9, IPFIX"
version = "0.2.1"
version = "0.2.2"
edition = "2021"
author = "[email protected]"
license = "MIT OR Apache-2.0"
Expand Down
5 changes: 5 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
# 0.2.2
* Optimizations in V9/IPFIX, removed some clone/cloned.
* Reworked Template Fields/Option Template Fields into single struct.
This avoids having to make an additional clone for each parse.

# 0.2.1
* Fixed issue where v9/ipfix template fields can infinite loop.

Expand Down
1 change: 1 addition & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

| Version | Supported |
| ------- | ------------------ |
| 0.2.2 | :white_check_mark: |
| 0.2.1 | :white_check_mark: |
| 0.2.0 | :white_check_mark: |
| 0.1.9 | :white_check_mark: |
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -390,12 +390,14 @@ mod tests {
field_type:
super::variable_versions::ipfix_lookup::IPFixField::PacketDeltaCount,
field_length: 2,
enterprise_number: None,
},
IPFixTemplateField {
field_type_number: 8,
field_type:
super::variable_versions::ipfix_lookup::IPFixField::SourceIpv4address,
field_length: 4,
enterprise_number: None,
},
];
let template = IPFixTemplate {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ expression: "NetflowParser::default().parse_bytes(&packet)"
template_id: 260
field_count: 3
scope_field_count: 1
scope_field_specifiers:
fields:
- field_type_number: 123
field_type: Enterprise
field_length: 4
enterprise_number: 2
field_specifiers:
- field_type_number: 32809
field_type: ExportedMessageTotalCount
field_length: 2
- field_type_number: 32810
field_type: ExportedFlowRecordTotalCount
field_length: 2

Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,11 @@ expression: "NetflowParser::default().parse_bytes(&packet)"
template_id: 260
field_count: 3
scope_field_count: 1
scope_field_specifiers:
fields:
- field_type_number: 123
field_type: Enterprise
field_length: 4
enterprise_number: 2
field_specifiers:
- field_type_number: 32809
field_type: ExportedMessageTotalCount
field_length: 2
Expand All @@ -46,4 +45,3 @@ expression: "NetflowParser::default().parse_bytes(&packet)"
DataNumber: 7710
Enterprise:
DataNumber: 2

84 changes: 35 additions & 49 deletions src/variable_versions/ipfix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use crate::{NetflowByteParserVariable, NetflowPacketResult, ParsedNetflow};

use nom::bytes::complete::take;
use nom::error::{Error as NomError, ErrorKind};
use nom::multi::count;
use nom::number::complete::{be_u128, be_u32};
use nom::Err as NomErr;
use nom::IResult;
Expand Down Expand Up @@ -100,17 +101,15 @@ pub struct Set {
#[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()) }"
)]
#[nom(Parse = "{ |i| parse_fields::<Template>(i, parser.templates.get(&set_id)) }")]
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()) }"
Parse = "{ |i| parse_fields::<OptionsTemplate>(i, parser.options_templates.get(&set_id)) }"
)]
pub data_fields: Vec<BTreeMap<IPFixField, FieldValue>>,
}
Expand All @@ -120,12 +119,12 @@ 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"
PreExec = "let combined_count = scope_field_count as usize +
field_count.checked_sub(scope_field_count).unwrap_or(field_count) as usize;",
Parse = "count(|i| TemplateField::parse(i, true), combined_count)"
)]
pub field_specifiers: Vec<OptionsTemplateField>,
pub fields: Vec<TemplateField>,
#[nom(Cond = "!i.is_empty()")]
#[serde(skip_serializing)]
padding: Option<u16>,
Expand All @@ -135,23 +134,28 @@ pub struct OptionsTemplate {
pub struct Template {
pub template_id: u16,
pub field_count: u16,
#[nom(Count = "field_count")]
#[nom(Parse = "count(|i| TemplateField::parse(i, false), field_count as usize)")]
pub fields: Vec<TemplateField>,
}

#[derive(Debug, PartialEq, Eq, Clone, Serialize, Nom)]
pub struct OptionsTemplateField {
#[nom(ExtraArgs(options_template: bool))]
pub struct TemplateField {
pub field_type_number: u16,
#[nom(Value(IPFixField::from(field_type_number)))]
pub field_type: IPFixField,
field_length: u16,
pub 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);"
Cond = "options_template && field_type_number > 32767",
PostExec = "let field_type_number = if options_template {
field_type_number.overflowing_sub(32768).0
} else { field_type_number };",
PostExec = "let field_type = if options_template {
set_entperprise_field(field_type, enterprise_number)
} else { field_type };"
)]
#[serde(skip_serializing_if = "Option::is_none")]
enterprise_number: Option<u32>,
pub enterprise_number: Option<u32>,
}

fn set_entperprise_field(field_type: IPFixField, enterprise_number: Option<u32>) -> IPFixField {
Expand All @@ -161,14 +165,6 @@ fn set_entperprise_field(field_type: IPFixField, enterprise_number: Option<u32>)
}
}

#[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,
}

/// Parses options template
fn parse_options_template(i: &[u8], length: u16) -> IResult<&[u8], OptionsTemplate> {
let (remaining, taken) = take(length.checked_sub(4).unwrap_or(length))(i)?;
Expand All @@ -179,57 +175,47 @@ fn parse_options_template(i: &[u8], length: u16) -> IResult<&[u8], OptionsTempla
// Hacky way when using Template as generic T to cast to a common field type.
// We use OptionsTemplateField as it is the same as type Template Field but
// with enterprise_field. In TemplateField tpe enterprise_field is just None.
trait CommonTemplateFields {
fn get_fields(&self) -> Vec<OptionsTemplateField>;
trait CommonTemplate {
fn get_fields(&self) -> &Vec<TemplateField>;
}

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 CommonTemplate for Template {
fn get_fields(&self) -> &Vec<TemplateField> {
&self.fields
}
}

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
impl CommonTemplate for OptionsTemplate {
fn get_fields(&self) -> &Vec<TemplateField> {
&self.fields
}
}

/// Takes a byte stream and a cached template.
/// Fields get matched to static types.
/// Returns BTree of IPFix Types & Fields or IResult Error.
fn parse_fields<T: CommonTemplateFields>(
i: &[u8],
template: Option<T>,
) -> IResult<&[u8], Vec<BTreeMap<IPFixField, FieldValue>>> {
fn parse_fields<'a, T: CommonTemplate>(
i: &'a [u8],
template: Option<&T>,
) -> IResult<&'a [u8], Vec<BTreeMap<IPFixField, FieldValue>>> {
let template = match template {
Some(t) => t,
None => {
// dbg!("Could not fetch any v10 templates!");
return Err(NomErr::Error(NomError::new(i, ErrorKind::Fail)));
}
};
let template_fields = template.get_fields();
// If no fields there are no fields to parse
if template.get_fields().is_empty() {
if template_fields.is_empty() {
// dbg!("Template without fields!");
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() {
for template_field in template_fields.iter() {
let field_type: FieldDataType = template_field.field_type.into();
// Enterprise Number
if template_field.enterprise_number.is_some() {
Expand Down Expand Up @@ -349,7 +335,7 @@ impl NetflowByteParserVariable for IPFixParser {
.checked_sub(remaining.len())
.unwrap_or(total_left);
total_left -= parsed;
sets.push(v10_set.clone());
sets.push(v10_set);
}

let v10_parsed = IPFix {
Expand Down
28 changes: 14 additions & 14 deletions src/variable_versions/v9.rs
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ pub struct OptionsData {
pub length: u16,
// Scope Data
#[nom(
Parse = "{ |i| parse_scope_data_fields(i, flow_set_id, parser.options_templates.clone()) }"
Parse = "{ |i| parse_scope_data_fields(i, flow_set_id, &parser.options_templates) }"
)]
pub scope_fields: Vec<ScopeDataField>,
// Options Data Fields
Expand Down Expand Up @@ -276,7 +276,7 @@ fn get_total_options_length(flow_set_id: u16, length: u16, parser: &mut V9Parser
}

#[derive(Debug, PartialEq, Clone, Serialize, Nom)]
#[nom(ExtraArgs(field: OptionsTemplateScopeField))]
#[nom(ExtraArgs(field: &OptionsTemplateScopeField))]
pub struct ScopeDataField {
/// System
#[nom(
Expand Down Expand Up @@ -328,23 +328,23 @@ pub struct Data {
/// themselves, as well as the combined lengths of any included data records.
pub length: u16,
// Data Fields
#[nom(Parse = "{ |i| parse_fields(i, parser.templates.get(&flow_set_id).cloned()) }")]
#[nom(Parse = "{ |i| parse_fields(i, parser.templates.get(&flow_set_id)) }")]
pub data_fields: Vec<BTreeMap<V9Field, FieldValue>>,
}

#[derive(Debug, PartialEq, Clone, Serialize, Nom)]
#[nom(ExtraArgs(field: TemplateField))]
#[nom(ExtraArgs(field: &TemplateField))]
pub struct OptionDataField {
#[nom(Value(field.field_type))]
pub field_type: V9Field,
#[nom(Map = "|i: &[u8]| i.to_vec()", Take = "field.field_length")]
pub field_value: Vec<u8>,
}

fn parse_fields(
i: &[u8],
template: Option<Template>,
) -> IResult<&[u8], Vec<BTreeMap<V9Field, FieldValue>>> {
fn parse_fields<'a>(
i: &'a [u8],
template: Option<&Template>,
) -> IResult<&'a [u8], Vec<BTreeMap<V9Field, FieldValue>>> {
let template = match template {
Some(t) => t,
None => {
Expand Down Expand Up @@ -457,26 +457,26 @@ fn parse_options_data_fields(
let mut fields = vec![];
let mut remaining = i;
for field in template.option_fields.iter() {
let (i, v9_data_field) = OptionDataField::parse(remaining, field.clone())?;
let (i, v9_data_field) = OptionDataField::parse(remaining, field)?;
remaining = i;
fields.push(v9_data_field)
}
Ok((remaining, fields))
}

fn parse_scope_data_fields(
i: &[u8],
fn parse_scope_data_fields<'a>(
i: &'a [u8],
flow_set_id: u16,
templates: HashMap<u16, OptionsTemplate>,
) -> IResult<&[u8], Vec<ScopeDataField>> {
templates: &HashMap<u16, OptionsTemplate>,
) -> IResult<&'a [u8], Vec<ScopeDataField>> {
let template = templates.get(&flow_set_id).ok_or_else(|| {
// dbg!("Could not fetch any v9 options templates!");
NomErr::Error(NomError::new(i, ErrorKind::Fail))
})?;
let mut fields = vec![];
let mut remaining = i;
for field in template.scope_fields.iter() {
let (i, v9_data_field) = ScopeDataField::parse(remaining, field.clone())?;
let (i, v9_data_field) = ScopeDataField::parse(remaining, field)?;
remaining = i;
fields.push(v9_data_field)
}
Expand Down