net_parser_rs/flow/
mod.rs1pub mod device;
2pub mod errors;
3pub mod info;
4pub mod layer2;
5pub mod layer3;
6pub mod layer4;
7
8use crate::common::Vlan;
9use crate::layer2::ethernet::Ethernet;
10use crate::PcapRecord;
11
12use device::Device;
13use errors::Error;
14use layer2::{FlowExtraction as Layer2Extraction};
15use log::*;
16
17pub trait FlowExtraction {
21 fn payload(&self) -> &[u8];
22
23 fn extract_flow(&self) -> Result<Flow, Error> {
24 trace!("Creating stream from payload of {}B", self.payload().len());
25
26 let payload_ref = self.payload();
27
28 Ethernet::parse(payload_ref)
29 .map_err(|e| {
30 error!("Error parsing ethernet {:?}", e);
31 Error::NetParser(e)
32 })
33 .and_then(|r| {
34 let (rem, l2) = r;
35 if rem.is_empty() {
36 l2.extract_flow()
37 } else {
38 Err(Error::Incomplete { size: rem.len() })
39 }
40 })
41 }
42}
43
44impl<'a> FlowExtraction for PcapRecord<'a> {
45 fn payload(&self) -> &[u8] {
46 self.payload
47 }
48}
49
50#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
54pub struct Flow {
55 pub source: Device,
56 pub destination: Device,
57 pub layer2: info::layer2::Id,
58 pub layer3: info::layer3::Id,
59 pub layer4: info::layer4::Id,
60 pub vlan: Vlan,
61}
62
63impl Flow {
64 pub fn new(
65 l2: info::layer2::Info,
66 l3: info::layer3::Info,
67 l4: info::layer4::Info
68 ) -> Flow {
69 Flow {
70 source: Device {
71 mac: l2.src_mac,
72 ip: l3.src_ip,
73 port: l4.src_port
74 },
75 destination: Device {
76 mac: l2.dst_mac,
77 ip: l3.dst_ip,
78 port: l4.dst_port
79 },
80 layer2: l2.id,
81 layer3: l3.id,
82 layer4: l4.id,
83 vlan: l2.vlan
84 }
85 }
86}
87
88impl std::fmt::Display for Flow {
89 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
90 write!(
91 f,
92 "Source=[{}] Destination=[{}] Vlan={}",
93 self.source, self.destination, self.vlan
94 )
95 }
96}
97
98pub fn convert_records<'b>(
102 records: Vec<PcapRecord<'b>>,
103) -> Vec<(PcapRecord<'b>, Flow)> {
104 let mut records = records;
105 let mut results = vec![];
106
107 loop {
108 if let Some(r) = records.pop() {
109 match r.extract_flow() {
110 Ok(f) => {
111 results.push( (r, f) );
112 }
113 Err(e) => {
114 debug!("Failed to extract stream: {}", e);
115 }
116 }
117 } else {
118 break;
119 }
120 }
121
122 results
123}
124
125#[cfg(test)]
126mod tests {
127 use crate::common::MacAddress;
128 use crate::flow::info::layer2::{Id as L2Id};
129 use crate::flow::info::layer3::{Id as L3Id};
130 use crate::flow::info::layer4::{Id as L4Id};
131 use super::*;
132
133 use std::io::Read;
134 use std::path::PathBuf;
135
136 #[test]
137 fn format_flow() {
138 let flow = Flow {
139 layer2: L2Id::Ethernet,
140 layer3: L3Id::IPv4,
141 layer4: L4Id::Tcp,
142 source: Device {
143 ip: std::net::IpAddr::V4(std::net::Ipv4Addr::new(0, 1, 2, 3)),
144 mac: MacAddress([0u8, 1u8, 2u8, 3u8, 4u8, 5u8]),
145 port: 80,
146 },
147 destination: Device {
148 ip: std::net::IpAddr::V4(std::net::Ipv4Addr::new(100, 99, 98, 97)),
149 mac: MacAddress([11u8, 10u8, 9u8, 8u8, 7u8, 6u8]),
150 port: 52436,
151 },
152 vlan: 0,
153 };
154
155 assert_eq!(format!("{}", flow), "Source=[Mac=00:01:02:03:04:05 Ip=0.1.2.3 Port=80] Destination=[Mac=0b:0a:09:08:07:06 Ip=100.99.98.97 Port=52436] Vlan=0")
156 }
157
158 #[test]
159 fn file_convert() {
160 let _ = env_logger::try_init();
161
162 let pcap_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
163 .join("resources")
164 .join("4SICS-GeekLounge-151020.pcap");
165
166 let pcap_reader = std::fs::File::open(pcap_path.clone())
167 .expect(&format!("Failed to open pcap path {:?}", pcap_path));
168
169 let bytes = pcap_reader
170 .bytes()
171 .map(|b| b.unwrap())
172 .collect::<std::vec::Vec<u8>>();
173
174 let (_, f) =
175 crate::CaptureFile::parse(&bytes).expect("Failed to parse");
176
177 assert_eq!(f.global_header.endianness, nom::Endianness::Little);
178 assert_eq!(f.records.len(), 246137);
179
180 let converted_records = convert_records(f.records.into_inner());
181
182 assert_eq!(converted_records.len(), 236527);
183 }
184}