use crate::pcapng::blocks::opts_from_slice;
use crate::errors::PcapError;
use byteorder::{ByteOrder, ReadBytesExt};
use crate::pcapng::{CustomUtf8Option, CustomBinaryOption, UnknownOption};
use std::borrow::Cow;
use derive_into_owned::IntoOwned;
#[derive(Clone, Debug, IntoOwned)]
pub struct EnhancedPacketBlock<'a> {
pub interface_id: u32,
pub timestamp: u64,
pub captured_len: u32,
pub original_len: u32,
pub data: Cow<'a, [u8]>,
pub options: Vec<EnhancedPacketOption<'a>>
}
impl<'a> EnhancedPacketBlock<'a> {
pub fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapError> {
if slice.len() < 20 {
return Err(PcapError::InvalidField("EnhancedPacketBlock: block length length < 20"));
}
let interface_id = slice.read_u32::<B>()?;
let timestamp = slice.read_u64::<B>()?;
let captured_len = slice.read_u32::<B>()?;
let original_len = slice.read_u32::<B>()?;
let pad_len = (4 - (captured_len as usize % 4)) % 4;
let tot_len = captured_len as usize + pad_len;
if slice.len() < tot_len {
return Err(PcapError::InvalidField("EnhancedPacketBlock: captured_len + padding > block length"));
}
let data = &slice[..captured_len as usize];
slice = &slice[tot_len..];
let (slice, options) = EnhancedPacketOption::from_slice::<B>(slice)?;
let block = EnhancedPacketBlock {
interface_id,
timestamp,
captured_len,
original_len,
data: Cow::Borrowed(data),
options
};
Ok((slice, block))
}
}
#[derive(Clone, Debug, IntoOwned)]
pub enum EnhancedPacketOption<'a> {
Comment(Cow<'a, str>),
Flags(u32),
Hash(Cow<'a, [u8]>),
DropCount(u64),
CustomBinary(CustomBinaryOption<'a>),
CustomUtf8(CustomUtf8Option<'a>),
Unknown(UnknownOption<'a>)
}
impl<'a> EnhancedPacketOption<'a> {
pub fn from_slice<B:ByteOrder>(slice: &'a [u8]) -> Result<(&'a[u8], Vec<Self>), PcapError> {
opts_from_slice::<B, _, _>(slice, |mut slice, code, length| {
let opt = match code {
1 => EnhancedPacketOption::Comment(Cow::Borrowed(std::str::from_utf8(slice)?)),
2 => {
if slice.len() != 4 {
return Err(PcapError::InvalidField("EnhancedPacketOption: Flags length != 4"))
}
EnhancedPacketOption::Flags(slice.read_u32::<B>()?)
},
3 => EnhancedPacketOption::Hash(Cow::Borrowed(slice)),
4 => {
if slice.len() != 8 {
return Err(PcapError::InvalidField("EnhancedPacketOption: DropCount length != 8"))
}
EnhancedPacketOption::DropCount(slice.read_u64::<B>()?)
},
2988 | 19372 => EnhancedPacketOption::CustomUtf8(CustomUtf8Option::from_slice::<B>(code, slice)?),
2989 | 19373 => EnhancedPacketOption::CustomBinary(CustomBinaryOption::from_slice::<B>(code, slice)?),
_ => EnhancedPacketOption::Unknown(UnknownOption::new(code, length, slice))
};
Ok(opt)
})
}
}