Skip to content
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.6.3"
version = "0.6.4"
edition = "2024"
authors = ["michael.mileusnich@gmail.com"]
license = "MIT OR Apache-2.0"
Expand Down
4 changes: 4 additions & 0 deletions RELEASES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# 0.6.4
* Removed uneeded DataNumber Parsing for Durations.
* Explicity rename methods DurationMicros and DurationNanos into DurationMicrosNTP and DurationNanosNTP

# 0.6.3
* Ipfix dateTimeNanoseconds and dateTimeMicroseconds use the NTP 64 bit time format #15
* Added NetEvent and ObservationTimeMilliseconds for V9.
Expand Down
113 changes: 55 additions & 58 deletions src/variable_versions/data_number.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
use crate::protocol::ProtocolTypes;

use byteorder::{BigEndian, WriteBytesExt};
use nom::Err as NomErr;
use nom::IResult;
use nom::bytes::complete::take;
use nom::error::{Error as NomError, ErrorKind};
use nom::number::complete::{be_i24, be_u24, be_u32, be_u128};
use nom_derive::*;
use nom::{
Err as NomErr, IResult,
bytes::complete::take,
error::{Error as NomError, ErrorKind},
number::complete::{be_i24, be_u24, be_u32, be_u128},
};
use nom_derive::Parse;
use serde::Serialize;

use std::convert::Into;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::time::Duration;
use std::{
net::{IpAddr, Ipv4Addr, Ipv6Addr},
time::Duration,
};

macro_rules! impl_try_from {
($($t:ty => $v:ident),*; $($s:ty => $sv:ident),*) => {
Expand Down Expand Up @@ -173,26 +173,6 @@ impl DataNumber {
}
}

/// Convert into usize, mainly for serialization purposes
impl From<DataNumber> for usize {
fn from(val: DataNumber) -> Self {
match val {
DataNumber::U8(i) => usize::from(i),
DataNumber::I8(i) => i as usize,
DataNumber::U16(i) => i as usize,
DataNumber::I16(i) => i as usize,
DataNumber::I24(i) => i as usize,
DataNumber::U24(i) => i as usize,
DataNumber::U32(i) => i as usize,
DataNumber::I32(i) => i as usize,
DataNumber::U64(i) => i as usize,
DataNumber::I64(i) => i as usize,
DataNumber::U128(i) => i as usize,
DataNumber::I128(i) => i as usize,
}
}
}

#[derive(Debug, PartialEq, PartialOrd, Clone, Serialize)]
pub struct ApplicationId {
pub classification_engine_id: u8,
Expand Down Expand Up @@ -240,6 +220,12 @@ impl FieldValue {
}
}

fn make_ntp_time_with_unit(seconds: u32, fraction: u32, unit: u64) -> Duration {
Duration::from_secs(u64::from(seconds)).saturating_add(Duration::from_micros(
((u64::from(fraction)).saturating_mul(unit)) >> 32,
))
}

pub fn from_field_type(
remaining: &[u8],
field_type: FieldDataType,
Expand Down Expand Up @@ -297,40 +283,51 @@ impl FieldValue {
(i, FieldValue::MacAddr(mac_addr))
}
FieldDataType::DurationSeconds => {
let (i, data_number) = DataNumber::parse(remaining, field_length, false)?;
(
i,
FieldValue::Duration(Duration::from_secs(
<DataNumber as Into<usize>>::into(data_number) as u64,
)),
)
let (i, value) = match field_length {
4 => {
let (i, seconds) = u32::parse_be(remaining)?;
let dur = Duration::from_secs(seconds.into());
(i, FieldValue::Duration(dur))
}
8 => {
let (i, seconds) = u64::parse_be(remaining)?;
let dur = Duration::from_secs(seconds);
(i, FieldValue::Duration(dur))
}
_ => {
return Err(NomErr::Error(NomError::new(remaining, ErrorKind::Fail)));
}
};
(i, value)
}
FieldDataType::DurationMillis => {
let (i, data_number) = DataNumber::parse(remaining, field_length, false)?;
(
i,
FieldValue::Duration(Duration::from_millis(
<DataNumber as Into<usize>>::into(data_number) as u64,
)),
)
let (i, value) = match field_length {
4 => {
let (i, seconds) = u32::parse_be(remaining)?;
let dur = Duration::from_millis(u64::from(seconds));
(i, FieldValue::Duration(dur))
}
8 => {
let (i, seconds) = u64::parse_be(remaining)?;
let dur = Duration::from_millis(seconds);
(i, FieldValue::Duration(dur))
}
_ => {
return Err(NomErr::Error(NomError::new(remaining, ErrorKind::Fail)));
}
};
(i, value)
}
FieldDataType::DurationMicros => {
FieldDataType::DurationMicrosNTP => {
let (i, seconds) = u32::parse_be(remaining)?;
let (i, fraction) = u32::parse_be(i)?;
let dur =
Duration::from_secs(seconds as u64).saturating_add(Duration::from_micros(
((u64::from(fraction)).saturating_mul(1_000_000)) >> 32,
));
let dur = Self::make_ntp_time_with_unit(seconds, fraction, 1_000_000);
(i, FieldValue::Duration(dur))
}
FieldDataType::DurationNanos => {
FieldDataType::DurationNanosNTP => {
let (i, seconds) = u32::parse_be(remaining)?;
let (i, fraction) = u32::parse_be(i)?;
let dur = Duration::from_secs(u64::from(seconds)).saturating_add(
Duration::from_nanos(
(u64::from(fraction).saturating_mul(1_000_000_000)) >> 32,
),
);
let dur = Self::make_ntp_time_with_unit(seconds, fraction, 1_000_000_000);
(i, FieldValue::Duration(dur))
}
FieldDataType::ProtocolType => {
Expand Down Expand Up @@ -361,8 +358,8 @@ pub enum FieldDataType {
Float64,
DurationSeconds,
DurationMillis,
DurationMicros,
DurationNanos,
DurationMicrosNTP,
DurationNanosNTP,
Ip4Addr,
Ip6Addr,
MacAddr,
Expand Down
20 changes: 10 additions & 10 deletions src/variable_versions/ipfix_lookup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1101,10 +1101,10 @@ FlowStartSeconds = 150 => FieldDataType::DurationSeconds,
FlowEndSeconds = 151 => FieldDataType::DurationSeconds,
FlowStartMilliseconds = 152 => FieldDataType::DurationMillis,
FlowEndMilliseconds = 153 => FieldDataType::DurationMillis,
FlowStartMicroseconds = 154 => FieldDataType::DurationMicros,
FlowEndMicroseconds = 155 => FieldDataType::DurationMicros,
FlowStartNanoseconds = 156 => FieldDataType::DurationNanos,
FlowEndNanoseconds = 157 => FieldDataType::DurationNanos,
FlowStartMicroseconds = 154 => FieldDataType::DurationMicrosNTP,
FlowEndMicroseconds = 155 => FieldDataType::DurationMicrosNTP,
FlowStartNanoseconds = 156 => FieldDataType::DurationNanosNTP,
FlowEndNanoseconds = 157 => FieldDataType::DurationNanosNTP,
FlowStartDeltaMicroseconds = 158 => FieldDataType::UnsignedDataNumber,
FlowEndDeltaMicroseconds = 159 => FieldDataType::UnsignedDataNumber,
SystemInitTimeMilliseconds = 160 => FieldDataType::DurationMillis,
Expand Down Expand Up @@ -1215,12 +1215,12 @@ MinExportSeconds = 264 => FieldDataType::DurationSeconds,
MinFlowStartSeconds = 265 => FieldDataType::DurationSeconds,
OpaqueOctets = 266 => FieldDataType::String,
SessionScope = 267 => FieldDataType::UnsignedDataNumber,
MaxFlowEndMicroseconds = 268 => FieldDataType::DurationMicros,
MaxFlowEndMicroseconds = 268 => FieldDataType::DurationMicrosNTP,
MaxFlowEndMilliseconds = 269 => FieldDataType::DurationMillis,
MaxFlowEndNanoseconds = 270 => FieldDataType::DurationNanos,
MinFlowStartMicroseconds = 271 => FieldDataType::DurationMicros,
MaxFlowEndNanoseconds = 270 => FieldDataType::DurationNanosNTP,
MinFlowStartMicroseconds = 271 => FieldDataType::DurationMicrosNTP,
MinFlowStartMilliseconds = 272 => FieldDataType::DurationMillis,
MinFlowStartNanoseconds = 273 => FieldDataType::DurationNanos,
MinFlowStartNanoseconds = 273 => FieldDataType::DurationNanosNTP,
CollectorCertificate = 274 => FieldDataType::String,
ExporterCertificate = 275 => FieldDataType::String,
DataRecordsReliability = 276 => FieldDataType::UnsignedDataNumber,
Expand Down Expand Up @@ -1271,8 +1271,8 @@ AbsoluteError = 320 => FieldDataType::Float64,
RelativeError = 321 => FieldDataType::Float64,
ObservationTimeSeconds = 322 => FieldDataType::DurationSeconds,
ObservationTimeMilliseconds = 323 => FieldDataType::DurationMillis,
ObservationTimeMicroseconds = 324 => FieldDataType::DurationMicros,
ObservationTimeNanoseconds = 325 => FieldDataType::DurationNanos,
ObservationTimeMicroseconds = 324 => FieldDataType::DurationMicrosNTP,
ObservationTimeNanoseconds = 325 => FieldDataType::DurationNanosNTP,
DigestHashValue = 326 => FieldDataType::UnsignedDataNumber,
HashIppayloadOffset = 327 => FieldDataType::UnsignedDataNumber,
HashIppayloadSize = 328 => FieldDataType::UnsignedDataNumber,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -156,10 +156,10 @@ expression: lookup
- DurationSeconds
- DurationMillis
- DurationMillis
- DurationMicros
- DurationMicros
- DurationNanos
- DurationNanos
- DurationMicrosNTP
- DurationMicrosNTP
- DurationNanosNTP
- DurationNanosNTP
- UnsignedDataNumber
- UnsignedDataNumber
- DurationMillis
Expand Down Expand Up @@ -270,12 +270,12 @@ expression: lookup
- DurationSeconds
- String
- UnsignedDataNumber
- DurationMicros
- DurationMicrosNTP
- DurationMillis
- DurationNanos
- DurationMicros
- DurationNanosNTP
- DurationMicrosNTP
- DurationMillis
- DurationNanos
- DurationNanosNTP
- String
- String
- UnsignedDataNumber
Expand Down Expand Up @@ -326,8 +326,8 @@ expression: lookup
- Float64
- DurationSeconds
- DurationMillis
- DurationMicros
- DurationNanos
- DurationMicrosNTP
- DurationNanosNTP
- UnsignedDataNumber
- UnsignedDataNumber
- UnsignedDataNumber
Expand Down
4 changes: 2 additions & 2 deletions src/variable_versions/v9.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,10 +250,10 @@ pub struct OptionsTemplate {
/// This field gives the length (in bytes) of any Options field definitions that are contained in this options template
pub options_length: u16,
/// Options Scope Fields
#[nom(Count = "(options_scope_length / 4) as usize")]
#[nom(Count = "usize::from((options_scope_length.saturating_div(4)))")]
pub scope_fields: Vec<OptionsTemplateScopeField>,
/// Options Fields
#[nom(Count = "(options_length / 4) as usize")]
#[nom(Count = "usize::from((options_length.saturating_div(4)))")]
pub option_fields: Vec<TemplateField>,
}

Expand Down