use crate::Error;
use log::*;
use nom::*;
#[derive(Clone, Debug)]
pub struct PcapRecords<'a> {
inner: Vec<PcapRecord<'a>>,
}
impl<'a> PcapRecords<'a> {
pub fn len(&self) -> usize { self.inner.len() }
pub fn into_inner(self) -> Vec<PcapRecord<'a>> { self.inner }
pub fn parse<'b>(
input: &'b [u8],
endianness: Endianness,
) -> Result<(&'b [u8], PcapRecords<'b>), Error> {
let mut records: std::vec::Vec<PcapRecord> = vec![];
let mut current = input;
trace!("{} bytes left for record parsing", current.len());
loop {
match PcapRecord::parse(current, endianness) {
Ok((rem, r)) => {
current = rem;
trace!("{} bytes left for record parsing", current.len());
records.push(r);
}
Err(Error::Incomplete { size: opt_size }) => {
match opt_size {
None => debug!(
"Needed unknown number of bytes for parsing, only had {}",
current.len()
),
Some(s) => debug!("Needed {} bytes for parsing, only had {:?}", s, current.len()),
}
break;
}
Err(e) => return Err(e),
}
}
Ok((current, PcapRecords {
inner: records
}))
}
}
#[derive(Clone, Copy, Debug)]
pub struct PcapRecord<'a> {
pub timestamp: std::time::SystemTime,
pub actual_length: u32,
pub original_length: u32,
pub payload: &'a [u8],
}
impl<'a> Default for PcapRecord<'a> {
fn default() -> Self {
PcapRecord {
timestamp: std::time::SystemTime::UNIX_EPOCH,
actual_length: 0,
original_length: 0,
payload: &[0u8; 0],
}
}
}
impl<'a> PcapRecord<'a> {
pub fn convert_packet_time(ts_seconds: u32, ts_microseconds: u32) -> std::time::SystemTime {
let offset = std::time::Duration::from_secs(ts_seconds as u64)
+ std::time::Duration::from_micros(ts_microseconds as u64);
std::time::UNIX_EPOCH + offset
}
pub fn new(
timestamp: std::time::SystemTime,
actual_length: u32,
original_length: u32,
payload: &'a [u8],
) -> PcapRecord<'a> {
PcapRecord {
timestamp: timestamp,
actual_length: actual_length,
original_length: original_length,
payload: payload,
}
}
pub fn parse<'b>(
input: &'b [u8],
endianness: nom::Endianness,
) -> Result<(&'b [u8], PcapRecord<'b>), Error> {
do_parse!(
input,
ts_seconds: u32!(endianness)
>> ts_microseconds: u32!(endianness)
>> actual_length: u32!(endianness)
>> original_length: u32!(endianness)
>> payload: take!(actual_length)
>> (PcapRecord {
timestamp: PcapRecord::convert_packet_time(ts_seconds, ts_microseconds),
actual_length: actual_length,
original_length: original_length,
payload: payload
})
).map_err(Error::from)
}
}
impl<'a> std::fmt::Display for PcapRecord<'a> {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
self.timestamp
.duration_since(std::time::UNIX_EPOCH)
.map_err(|_e| std::fmt::Error)
.and_then(|d| {
write!(
f,
"Timestamp={}{} Length={} Original Length={}",
d.as_secs(),
d.subsec_millis(),
self.actual_length,
self.original_length
)
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::flow::FlowExtraction;
const RAW_DATA: &'static [u8] = &[
0x5Bu8, 0x11u8, 0x6Du8, 0xE3u8,
0x00u8, 0x02u8, 0x51u8, 0xF5u8,
0x00u8, 0x00u8, 0x00u8,
0x56u8,
0x00u8, 0x00u8, 0x04u8, 0xD0u8,
0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8,
0xFFu8, 0xFEu8, 0xFDu8, 0xFCu8, 0xFBu8, 0xFAu8,
0x08u8, 0x00u8,
0x45u8,
0x00u8,
0x00u8, 0x48u8,
0x00u8, 0x00u8,
0x00u8, 0x00u8,
0x64u8,
0x06u8,
0x00u8, 0x00u8,
0x01u8, 0x02u8, 0x03u8, 0x04u8,
0x0Au8, 0x0Bu8, 0x0Cu8, 0x0Du8,
0xC6u8, 0xB7u8,
0x00u8, 0x50u8,
0x00u8, 0x00u8, 0x00u8, 0x01u8,
0x00u8, 0x00u8, 0x00u8, 0x02u8,
0x50u8, 0x00u8,
0x00u8, 0x00u8,
0x00u8, 0x00u8,
0x00u8, 0x00u8,
0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0xfcu8, 0xfdu8, 0xfeu8,
0xffu8,
];
#[test]
fn display_record() {
let _ = env_logger::try_init();
let record = PcapRecord::parse(RAW_DATA, nom::Endianness::Big)
.expect("Could not parse")
.1;
assert_eq!(
format!("{}", record),
"Timestamp=1527868899152 Length=86 Original Length=1232"
);
}
#[test]
fn convert_timestamp() {
let _ = env_logger::try_init();
let ts = PcapRecord::convert_packet_time(1527868899, 152053);
let offset =
std::time::Duration::from_secs(1527868899) + std::time::Duration::from_micros(152053);
assert_eq!(ts, std::time::UNIX_EPOCH + offset);
}
#[test]
fn parse_record() {
let _ = env_logger::try_init();
let (rem, record) =
PcapRecord::parse(RAW_DATA, nom::Endianness::Big).expect("Could not parse");
assert!(rem.is_empty());
let offset =
std::time::Duration::from_secs(1527868899) + std::time::Duration::from_micros(152053);
assert_eq!(record.timestamp, std::time::UNIX_EPOCH + offset);
assert_eq!(record.actual_length, 86);
assert_eq!(record.original_length, 1232);
}
#[test]
fn convert_record() {
let _ = env_logger::try_init();
let (rem, record) =
PcapRecord::parse(RAW_DATA, nom::Endianness::Big).expect("Could not parse");
assert!(rem.is_empty());
let flow = record.extract_flow().expect("Could not extract stream");
assert_eq!(flow.source.port, 50871);
assert_eq!(flow.destination.port, 80);
}
}