Skip to content

Commit

Permalink
feat(Fix Readme example packets.) (#83)
Browse files Browse the repository at this point in the history
feat(Fix Readme example packets.)
feat(Optimized IPFix, V9 NetflowCommon lookup.)
feat(DataNumber down converters and netflowcommon cleanup)

---------

Co-authored-by: mikemiles-dev <michaelmileusnich@Michaels-MacBook-Air-2.local>
  • Loading branch information
mikemiles-dev and mikemiles-dev authored Sep 19, 2024
1 parent 0373ad3 commit 1dc9a09
Show file tree
Hide file tree
Showing 6 changed files with 245 additions and 137 deletions.
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.4.3"
version = "0.4.4"
edition = "2021"
author = "michael.mileusnich@gmail.com"
license = "MIT OR Apache-2.0"
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ See: <https://en.wikipedia.org/wiki/NetFlow>
```rust
use netflow_parser::{NetflowParser, NetflowPacket};

let v5_packet = [0, 5, 2, 0, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
let v5_packet = [0, 5, 0, 1, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
match NetflowParser::default().parse_bytes(&v5_packet).first() {
Some(NetflowPacket::V5(v5)) => assert_eq!(v5.header.version, 5),
Some(NetflowPacket::Error(e)) => println!("{:?}", e),
Expand All @@ -29,7 +29,7 @@ Structures fully support serialization. Below is an example using the serde_jso
use serde_json::json;
use netflow_parser::NetflowParser;

let v5_packet = [0, 5, 2, 0, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
let v5_packet = [0, 5, 0, 1, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
println!("{}", json!(NetflowParser::default().parse_bytes(&v5_packet)).to_string());
```

Expand All @@ -42,7 +42,7 @@ println!("{}", json!(NetflowParser::default().parse_bytes(&v5_packet)).to_string
```rust
use netflow_parser::{NetflowParser, NetflowPacket};

let v5_packet = [0, 5, 2, 0, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
let v5_packet = [0, 5, 0, 1, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
let parsed = NetflowParser::default().parse_bytes(&v5_packet);

let v5_parsed: Vec<NetflowPacket> = parsed.into_iter().filter(|p| p.is_v5()).collect();
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.4.4
* Fix Readme example packets.
* Optimized IPFix, V9 NetflowCommon lookup.
* DataNumbers can now be downcast into actual data types: (u8, u16, i32, u32, u64, u128).

# 0.4.3
* Fixed bug in NetflowCommon where ProtocolType was never set.
* Minor Readme Changes.
Expand Down
6 changes: 3 additions & 3 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
//! ```rust
//! use netflow_parser::{NetflowParser, NetflowPacket};
//!
//! let v5_packet = [0, 5, 2, 0, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
//! let v5_packet = [0, 5, 0, 1, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
//! match NetflowParser::default().parse_bytes(&v5_packet).first() {
//! Some(NetflowPacket::V5(v5)) => assert_eq!(v5.header.version, 5),
//! Some(NetflowPacket::Error(e)) => println!("{:?}", e),
Expand All @@ -29,7 +29,7 @@
//! use serde_json::json;
//! use netflow_parser::NetflowParser;
//!
//! let v5_packet = [0, 5, 2, 0, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
//! let v5_packet = [0, 5, 0, 1, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
//! println!("{}", json!(NetflowParser::default().parse_bytes(&v5_packet)).to_string());
//! ```
//!
Expand All @@ -42,7 +42,7 @@
//! ```rust
//! use netflow_parser::{NetflowParser, NetflowPacket};
//!
//! let v5_packet = [0, 5, 2, 0, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
//! let v5_packet = [0, 5, 0, 1, 3, 0, 4, 0, 5, 0, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7,];
//! let parsed = NetflowParser::default().parse_bytes(&v5_packet);
//!
//! let v5_parsed: Vec<NetflowPacket> = parsed.into_iter().filter(|p| p.is_v5()).collect();
Expand Down
189 changes: 60 additions & 129 deletions src/netflow_common.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use std::collections::BTreeMap;
use std::net::IpAddr;

use crate::protocol::ProtocolTypes;
use crate::static_versions::{v5::V5, v7::V7};
use crate::variable_versions::data_number::{DataNumber, FieldValue};
use crate::variable_versions::data_number::FieldValue;
use crate::variable_versions::ipfix_lookup::IPFixField;
use crate::variable_versions::v9_lookup::V9Field;
use crate::variable_versions::{ipfix::IPFix, v9::V9};
Expand Down Expand Up @@ -112,71 +113,35 @@ impl From<&V9> for NetflowCommon {
for flowset in &value.flowsets {
if let Some(data) = &flowset.body.data {
for data_field in &data.data_fields {
let values: Vec<(V9Field, FieldValue)> =
let value_map: BTreeMap<V9Field, FieldValue> =
data_field.values().cloned().collect();
flowsets.push(NetflowCommonFlowSet {
src_addr: values
.iter()
.find(|(k, _)| {
*k == V9Field::Ipv4SrcAddr || *k == V9Field::Ipv6SrcAddr
})
.and_then(|(_, v)| match v {
FieldValue::Ip4Addr(ip) => Some((*ip).into()),
_ => None,
}),
dst_addr: values
.iter()
.find(|(k, _)| {
*k == V9Field::Ipv4DstAddr || *k == V9Field::Ipv6DstAddr
})
.and_then(|(_, v)| match v {
FieldValue::Ip4Addr(ip) => Some((*ip).into()),
_ => None,
}),
src_port: values
.iter()
.find(|(k, _)| *k == V9Field::L4SrcPort)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U16(port)) => Some(*port),
_ => None,
}),
dst_port: values
.iter()
.find(|(k, _)| *k == V9Field::L4DstPort)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U16(port)) => Some(*port),
_ => None,
}),
protocol_number: values
.iter()
.find(|(k, _)| *k == V9Field::Protocol)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U8(proto)) => Some(*proto),
_ => None,
}),
first_seen: values
.iter()
.find(|(k, _)| *k == V9Field::FirstSwitched)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U32(seen)) => Some(*seen),
_ => None,
}),
last_seen: values
.iter()
.find(|(k, _)| *k == V9Field::LastSwitched)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U32(seen)) => Some(*seen),
_ => None,
}),
protocol_type: values
.iter()
.find(|(k, _)| *k == V9Field::Protocol)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U8(proto)) => {
Some(ProtocolTypes::from(*proto))
}
_ => None,
}),
src_addr: value_map
.get(&V9Field::Ipv4SrcAddr)
.and_then(|v| v.try_into().ok()),
dst_addr: value_map
.get(&V9Field::Ipv4DstAddr)
.and_then(|v| v.try_into().ok()),
src_port: value_map
.get(&V9Field::L4SrcPort)
.and_then(|v| v.try_into().ok()),
dst_port: value_map
.get(&V9Field::L4DstPort)
.and_then(|v| v.try_into().ok()),
protocol_number: value_map
.get(&V9Field::Protocol)
.and_then(|v| v.try_into().ok()),
protocol_type: value_map.get(&V9Field::Protocol).and_then(|v| {
v.try_into()
.ok()
.map(|proto: u8| ProtocolTypes::from(proto))
}),
first_seen: value_map
.get(&V9Field::FirstSwitched)
.and_then(|v| v.try_into().ok()),
last_seen: value_map
.get(&V9Field::LastSwitched)
.and_then(|v| v.try_into().ok()),
});
}
}
Expand All @@ -199,73 +164,39 @@ impl From<&IPFix> for NetflowCommon {
for flowset in &value.flowsets {
if let Some(data) = &flowset.body.data {
for data_field in &data.data_fields {
let values: Vec<(IPFixField, FieldValue)> =
let value_map: BTreeMap<IPFixField, FieldValue> =
data_field.values().cloned().collect();
flowsets.push(NetflowCommonFlowSet {
src_addr: values
.iter()
.find(|(k, _)| {
*k == IPFixField::SourceIpv4address
|| *k == IPFixField::SourceIpv6address
})
.and_then(|(_, v)| match v {
FieldValue::Ip4Addr(ip) => Some((*ip).into()),
_ => None,
}),
dst_addr: values
.iter()
.find(|(k, _)| {
*k == IPFixField::DestinationIpv4address
|| *k == IPFixField::DestinationIpv6address
})
.and_then(|(_, v)| match v {
FieldValue::Ip4Addr(ip) => Some((*ip).into()),
_ => None,
}),
src_port: values
.iter()
.find(|(k, _)| *k == IPFixField::SourceTransportPort)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U16(port)) => Some(*port),
_ => None,
}),
dst_port: values
.iter()
.find(|(k, _)| *k == IPFixField::DestinationTransportPort)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U16(port)) => Some(*port),
_ => None,
}),
protocol_number: values
.iter()
.find(|(k, _)| *k == IPFixField::ProtocolIdentifier)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U8(proto)) => Some(*proto),
_ => None,
}),
first_seen: values
.iter()
.find(|(k, _)| *k == IPFixField::FlowStartSysUpTime)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U32(seen)) => Some(*seen),
_ => None,
}),
last_seen: values
.iter()
.find(|(k, _)| *k == IPFixField::FlowEndSysUpTime)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U32(seen)) => Some(*seen),
_ => None,
}),
protocol_type: values
.iter()
.find(|(k, _)| *k == IPFixField::ProtocolIdentifier)
.and_then(|(_, v)| match v {
FieldValue::DataNumber(DataNumber::U8(proto)) => {
Some(ProtocolTypes::from(*proto))
}
_ => None,
}),
src_addr: value_map
.get(&IPFixField::SourceIpv4address)
.or_else(|| value_map.get(&IPFixField::SourceIpv6address))
.and_then(|v| v.try_into().ok()),
dst_addr: value_map
.get(&IPFixField::DestinationIpv4address)
.or_else(|| value_map.get(&IPFixField::DestinationIpv6address))
.and_then(|v| v.try_into().ok()),
src_port: value_map
.get(&IPFixField::SourceTransportPort)
.and_then(|v| v.try_into().ok()),
dst_port: value_map
.get(&IPFixField::DestinationTransportPort)
.and_then(|v| v.try_into().ok()),
protocol_number: value_map
.get(&IPFixField::ProtocolIdentifier)
.and_then(|v| v.try_into().ok()),
protocol_type: value_map.get(&IPFixField::ProtocolIdentifier).and_then(
|v| {
v.try_into()
.ok()
.map(|proto: u8| ProtocolTypes::from(proto))
},
),
first_seen: value_map
.get(&IPFixField::FlowStartSysUpTime)
.and_then(|v| v.try_into().ok()),
last_seen: value_map
.get(&IPFixField::FlowEndSysUpTime)
.and_then(|v| v.try_into().ok()),
});
}
}
Expand Down
Loading

0 comments on commit 1dc9a09

Please sign in to comment.