Skip to content

Commit 9a25a04

Browse files
mikemiles-devmikemiles-dev
andauthored
chore: V9/Ipfix cleanup (#97)
Co-authored-by: mikemiles-dev <michaelmileusnich@Michaels-MacBook-Air-2.local>
1 parent bc92640 commit 9a25a04

File tree

6 files changed

+82
-78
lines changed

6 files changed

+82
-78
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "netflow_parser"
33
description = "Parser for Netflow Cisco V5, V7, V9, IPFIX"
4-
version = "0.5.0"
4+
version = "0.5.1"
55
edition = "2021"
66
authors = ["michael.mileusnich@gmail.com"]
77
license = "MIT OR Apache-2.0"

RELEASES.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
# 0.5.1
2+
* V9, IPFix Code cleanup.
3+
14
# 0.5.0
25
* Typos in documentation fixed.
36
* Added cargo-fuzz for fuzzing.

SECURITY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
| Version | Supported |
66
|---------| ------------------ |
7+
| 0.5.1 | :white_check_mark: |
78
| 0.5.0 | :white_check_mark: |
89
| 0.4.9 | :white_check_mark: |
910
| 0.4.8 | :white_check_mark: |

src/variable_versions/data_number.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -117,15 +117,15 @@ fn parse_unknown_fields(
117117
impl DataNumber {
118118
/// Parse bytes into DataNumber Type
119119
pub fn parse(i: &[u8], field_length: u16, signed: bool) -> IResult<&[u8], DataNumber> {
120-
match field_length {
121-
1 if !signed => Ok(u8::parse(i)?).map(|(i, j)| (i, Self::U8(j))),
122-
2 if !signed => Ok(u16::parse(i)?).map(|(i, j)| (i, Self::U16(j))),
123-
3 if !signed => Ok(be_u24(i).map(|(i, j)| (i, Self::U24(j)))?),
124-
3 if signed => Ok(be_i24(i).map(|(i, j)| (i, Self::I24(j)))?),
125-
4 if signed => Ok(i32::parse(i)?).map(|(i, j)| (i, Self::I32(j))),
126-
4 if !signed => Ok(u32::parse(i)?).map(|(i, j)| (i, Self::U32(j))),
127-
8 if !signed => Ok(u64::parse(i)?).map(|(i, j)| (i, Self::U64(j))),
128-
16 if !signed => Ok(u128::parse(i)?).map(|(i, j)| (i, Self::U128(j))),
120+
match (field_length, signed) {
121+
(1, false) => Ok(u8::parse(i)?).map(|(i, j)| (i, Self::U8(j))),
122+
(2, false) => Ok(u16::parse(i)?).map(|(i, j)| (i, Self::U16(j))),
123+
(3, false) => Ok(be_u24(i).map(|(i, j)| (i, Self::U24(j)))?),
124+
(3, true) => Ok(be_i24(i).map(|(i, j)| (i, Self::I24(j)))?),
125+
(4, true) => Ok(i32::parse(i)?).map(|(i, j)| (i, Self::I32(j))),
126+
(4, false) => Ok(u32::parse(i)?).map(|(i, j)| (i, Self::U32(j))),
127+
(8, false) => Ok(u64::parse(i)?).map(|(i, j)| (i, Self::U64(j))),
128+
(16, false) => Ok(u128::parse(i)?).map(|(i, j)| (i, Self::U128(j))),
129129
_ => Err(NomErr::Error(NomError::new(i, ErrorKind::Fail))),
130130
}
131131
}

src/variable_versions/ipfix.rs

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -278,71 +278,66 @@ fn parse_fields<'a, T: CommonTemplate>(
278278
i: &'a [u8],
279279
template: Option<&T>,
280280
) -> IResult<&'a [u8], Vec<BTreeMap<usize, IPFixFieldPair>>> {
281-
fn parse_field<'a>(
282-
i: &'a [u8],
283-
template_field: &TemplateField,
284-
) -> IResult<&'a [u8], FieldValue> {
285-
// Enterprise Number
286-
if template_field.enterprise_number.is_some() {
287-
let (remaining, data_number) = DataNumber::parse(i, 4, false)?;
288-
Ok((remaining, FieldValue::DataNumber(data_number)))
289-
// Type matching
290-
} else {
291-
Ok(DataNumber::from_field_type(
292-
i,
293-
template_field.field_type.into(),
294-
template_field.field_length,
295-
))?
296-
}
297-
}
298-
299281
// If no fields there are no fields to parse, return an error.
300282
let template_fields = template
301-
.ok_or(NomErr::Error(NomError::new(i, ErrorKind::Fail)))?
283+
.filter(|t| !t.get_fields().is_empty())
284+
.ok_or_else(|| NomErr::Error(NomError::new(i, ErrorKind::Fail)))?
302285
.get_fields();
303286

304-
if template_fields.is_empty() {
305-
// dbg!("Template without fields!");
306-
return Err(NomErr::Error(NomError::new(i, ErrorKind::Fail)));
307-
};
308-
309-
let mut fields = vec![];
310-
let mut remaining = i;
311-
312287
let total_size = template_fields
313288
.iter()
314289
.map(|m| m.field_length as usize)
315290
.sum::<usize>();
316291

317292
if total_size == 0 {
318-
return Ok((&[], fields));
293+
return Ok((&[], vec![]));
319294
}
320-
let count: usize = i.len() / total_size;
321295

322-
let mut error = false;
296+
let record_count: usize = i.len() / total_size;
297+
let mut fields = vec![];
298+
let mut remaining = i;
323299

324300
// Iter through template fields and push them to a vec. If we encouter any zero length fields we return an error.
325-
for _ in 0..count {
301+
for _ in 0..record_count {
326302
let mut data_field = BTreeMap::new();
327303
for (c, template_field) in template_fields.iter().enumerate() {
328304
let (i, field_value) = parse_field(remaining, template_field)?;
329305
if i.len() == remaining.len() {
330-
error = true;
331-
break;
306+
return Err(NomErr::Error(NomError::new(remaining, ErrorKind::Fail)));
332307
}
333308
remaining = i;
334309
data_field.insert(c, (template_field.field_type, field_value));
335310
}
336311
fields.push(data_field);
337312
}
338313

339-
if error {
340-
Err(NomErr::Error(NomError::new(remaining, ErrorKind::Fail)))
314+
Ok((&[], fields))
315+
}
316+
317+
fn parse_field<'a>(
318+
i: &'a [u8],
319+
template_field: &TemplateField,
320+
) -> IResult<&'a [u8], FieldValue> {
321+
let has_enterprise_number = template_field.enterprise_number.is_some();
322+
323+
if has_enterprise_number {
324+
// Simplified parsing when `enterprise_number` is present
325+
parse_enterprise_field(i)
341326
} else {
342-
Ok((&[], fields))
327+
// Parse field based on its type and length
328+
DataNumber::from_field_type(
329+
i,
330+
template_field.field_type.into(),
331+
template_field.field_length,
332+
)
343333
}
344334
}
345335

336+
fn parse_enterprise_field(i: &[u8]) -> IResult<&[u8], FieldValue> {
337+
let (remaining, data_number) = DataNumber::parse(i, 4, false)?;
338+
Ok((remaining, FieldValue::DataNumber(data_number)))
339+
}
340+
346341
impl IPFix {
347342
/// Convert the IPFix to a `Vec<u8>` of bytes in big-endian order for exporting
348343
pub fn to_be_bytes(&self) -> Vec<u8> {

src/variable_versions/v9.rs

Lines changed: 37 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -362,48 +362,53 @@ fn parse_options_template_vec(i: &[u8]) -> IResult<&[u8], Vec<OptionsTemplate>>
362362
}
363363

364364
fn parse_fields<'a>(
365-
i: &'a [u8],
365+
input: &'a [u8],
366366
template: Option<&Template>,
367367
) -> IResult<&'a [u8], Vec<BTreeMap<usize, V9FieldPair>>> {
368-
let template = match template {
369-
Some(t) => t,
370-
None => {
371-
// dbg!("Could not fetch any v9 templates!");
372-
return Err(NomErr::Error(NomError::new(i, ErrorKind::Fail)));
373-
}
374-
};
368+
let template = template
369+
.filter(|t| !t.fields.is_empty() && t.get_total_size() > 0)
370+
.ok_or_else(|| NomErr::Error(NomError::new(input, ErrorKind::Fail)))?;
375371

376372
let mut fields = vec![];
377-
// If no fields there are no fields to parse
378-
if template.fields.is_empty() {
379-
// dbg!("Template without fields!");
380-
return Err(NomErr::Error(NomError::new(i, ErrorKind::Fail)));
381-
};
382-
let mut remaining = i;
383-
384-
if template.get_total_size() == 0 {
385-
return Ok((&[], fields));
386-
}
373+
let mut remaining = input;
374+
let record_count = input.len() as u16 / template.get_total_size();
387375

388-
let count = i.len() as u16 / template.get_total_size();
389-
390-
for _ in 0..count {
391-
let mut data_field = BTreeMap::new();
392-
for (c, template_field) in template.fields.iter().enumerate() {
393-
let field_type: FieldDataType = template_field.field_type.into();
394-
let (i, field_value) = DataNumber::from_field_type(
395-
remaining,
396-
field_type,
397-
template_field.field_length,
398-
)?;
399-
remaining = i;
400-
data_field.insert(c, (template_field.field_type, field_value));
401-
}
376+
for _ in 0..record_count {
377+
// Fields
378+
let (new_remaining, data_field) = parse_data_field(remaining, template)?;
379+
remaining = new_remaining;
402380
fields.push(data_field);
403381
}
382+
404383
Ok((remaining, fields))
405384
}
406385

386+
fn parse_data_field<'a>(
387+
mut input: &'a [u8],
388+
template: &Template,
389+
) -> IResult<&'a [u8], BTreeMap<usize, V9FieldPair>> {
390+
let mut data_field = BTreeMap::new();
391+
392+
for (field_index, template_field) in template.fields.iter().enumerate() {
393+
let (new_input, field_value) = parse_field(input, template_field)?;
394+
input = new_input;
395+
data_field.insert(field_index, (template_field.field_type, field_value));
396+
}
397+
398+
Ok((input, data_field))
399+
}
400+
401+
fn parse_field<'a>(
402+
input: &'a [u8],
403+
template_field: &TemplateField,
404+
) -> IResult<&'a [u8], FieldValue> {
405+
DataNumber::from_field_type(
406+
input,
407+
template_field.field_type.into(),
408+
template_field.field_length,
409+
)
410+
}
411+
407412
fn parse_options_data_fields(
408413
i: &[u8],
409414
flowset_id: u16,

0 commit comments

Comments
 (0)