use crate::flow::Flow;
use crate::flow::errors::Error;
use crate::flow::info::layer2::{Id, Info};
use crate::flow::layer2::FlowExtraction;
use crate::flow::layer2::errors::{Error as L2Error};
use crate::flow::layer3::{FlowExtraction as Layer3Extraction};
use crate::layer2::ethernet::{Ethernet, EthernetTypeId, Layer3Id};
use crate::layer3::{IPv4, IPv6, Arp};
use log::*;
pub mod errors {
use crate::layer2::ethernet::EthernetTypeId;
use crate::errors::Error as NetParserError;
use thiserror::{Error as ThisError};
#[derive(Debug, ThisError)]
pub enum Error {
#[error("Failed parse of {:?}: {}", l3, err)]
NetParser {
l3: EthernetTypeId,
err: NetParserError
},
#[error("Incomplete parse of {:?}: {}", l3, size)]
Incomplete {
l3: EthernetTypeId,
size: usize
},
#[error("Unknown Ethernet Type: {:?}", etype)]
EthernetType {
etype: EthernetTypeId
},
}
unsafe impl Sync for Error {}
unsafe impl Send for Error {}
}
impl<'a> FlowExtraction for Ethernet<'a> {
fn extract_flow(&self) -> Result<Flow, Error> {
let l2 = Info {
id: Id::Ethernet,
src_mac: self.src_mac.clone(),
dst_mac: self.dst_mac.clone(),
vlan: self.vlan(),
};
let ether_type = self.ether_type.clone();
debug!(
"Creating from layer 3 type {:?} using payload of {}B",
ether_type,
self.payload.len()
);
match ether_type {
EthernetTypeId::L3(Layer3Id::IPv4) => {
IPv4::parse(&self.payload)
.map_err(|e| {
error!("Error parsing ipv4 {:?}", e);
let e: L2Error = errors::Error::NetParser {
l3: ether_type.clone(),
err: e
}.into();
e.into()
})
.and_then(|r| {
let (rem, l3) = r;
if rem.is_empty() {
l3.extract_flow(l2)
} else {
let e: L2Error = errors::Error::Incomplete {
l3: ether_type.clone(),
size: rem.len()
}.into();
Err(e.into())
}
})
}
EthernetTypeId::L3(Layer3Id::IPv6) => {
IPv6::parse(&self.payload)
.map_err(|e| {
error!("Error parsing ipv6 {:?}", e);
let e: L2Error = errors::Error::NetParser {
l3: ether_type.clone(),
err: e
}.into();
e.into()
})
.and_then(|r| {
let (rem, l3) = r;
if rem.is_empty() {
l3.extract_flow(l2)
} else {
let e: L2Error = errors::Error::Incomplete {
l3: ether_type.clone(),
size: rem.len()
}.into();
Err(e.into())
}
})
}
EthernetTypeId::L3(Layer3Id::Arp) => {
Arp::parse(&self.payload)
.map_err(|e| {
error!("Error parsing arp {:?}", e);
let e: L2Error = errors::Error::NetParser {
l3: ether_type.clone(),
err: e
}.into();
e.into()
})
.and_then(|r| {
let (rem, l3) = r;
if rem.is_empty() {
l3.extract_flow(l2)
} else {
let e: L2Error = errors::Error::Incomplete {
l3: ether_type.clone(),
size: rem.len()
}.into();
Err(e.into())
}
})
}
_ => {
let e: L2Error = errors::Error::EthernetType {
etype: ether_type
}.into();
Err(e.into())
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::flow::info::layer2::{Id as L2Id};
use crate::layer2::ethernet::Ethernet;
use crate::layer2::ethernet::tests::TCP_RAW_DATA;
#[test]
fn convert_ethernet_tcp() {
let _ = env_logger::try_init();
let (rem, l2) = Ethernet::parse(TCP_RAW_DATA).expect("Could not parse");
assert!(rem.is_empty());
let info = l2.extract_flow().expect("Could not convert to layer 2 stream info");
assert_eq!(info.layer2, L2Id::Ethernet);
assert_eq!(info.source.port, 50871);
assert_eq!(info.destination.port, 80);
}
}