use std::borrow::Cow;
use std::time::Duration;
use byteorder::ByteOrder;
use byteorder::ReadBytesExt;
use derive_into_owned::IntoOwned;
#[cfg(feature = "tokio")]
use tokio_byteorder::AsyncReadBytesExt;
use tracing::warn;
use crate::errors::*;
#[derive(Clone, Debug, IntoOwned)]
pub struct CapPacket<'a> {
pub timestamp: Duration,
pub orig_len: u16,
pub data: Cow<'a, [u8]>,
}
impl<'a> CapPacket<'a> {
pub fn from_slice<B: ByteOrder>(slice: &'a [u8], start_time: u32) -> PcapResult<(&'a [u8], CapPacket<'a>)> {
let (rem, raw_packet) = RawCapPacket::from_slice::<B>(slice)?;
let s = Self::try_from_raw_packet(raw_packet, start_time)?;
Ok((rem, s))
}
#[cfg(feature = "tokio")]
pub async fn async_from_slice<B: ByteOrder>(slice: &'a [u8], start_time: u32) -> PcapResult<(&'a [u8], CapPacket<'a>)> {
let (rem, raw_packet) = RawCapPacket::async_from_slice::<B>(slice).await?;
let s = Self::try_from_raw_packet(raw_packet, start_time)?;
Ok((rem, s))
}
pub fn try_from_raw_packet(raw: RawCapPacket<'a>, start_time: u32) -> PcapResult<Self> {
let mut t = (raw.timelo as u64 + raw.timehi as u64 * 4294967296) as f64;
t /= 1000000.0;
let ts_sec = start_time + t as u32;
let ts_nsec = ((t - (t as u32) as f64) * 1.0e9) as u32;
if ts_nsec >= 1_000_000_000 {
return Err(PcapError::InvalidField("PacketHeader ts_nanosecond >= 1_000_000_000"));
}
let incl_len = raw.incl_len;
let orig_len = raw.orig_len;
if incl_len > orig_len {
warn!("PacketHeader incl_len > orig_len");
}
Ok(CapPacket { timestamp: Duration::new(ts_sec as u64, ts_nsec), orig_len, data: raw.data })
}
}
#[derive(Clone, Debug, IntoOwned)]
pub struct RawCapPacket<'a> {
pub timelo: u32,
pub timehi: u32,
pub orig_len: u16,
pub incl_len: u16,
pub data: Cow<'a, [u8]>,
}
impl<'a> RawCapPacket<'a> {
pub fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> PcapResult<(&'a [u8], Self)> {
if slice.len() < 40 {
return Err(PcapError::IncompleteBuffer);
}
let timelo = ReadBytesExt::read_u32::<B>(&mut slice).unwrap();
let timehi = ReadBytesExt::read_u32::<B>(&mut slice).unwrap();
let orig_len = ReadBytesExt::read_u16::<B>(&mut slice).unwrap();
let incl_len = ReadBytesExt::read_u16::<B>(&mut slice).unwrap();
slice = &slice[28..];
let pkt_len = incl_len as usize;
if slice.len() < pkt_len {
return Err(PcapError::IncompleteBuffer);
}
let packet = RawCapPacket { timelo, timehi, incl_len, orig_len, data: Cow::Borrowed(&slice[..pkt_len]) };
let rem = &slice[pkt_len..];
Ok((rem, packet))
}
#[cfg(feature = "tokio")]
pub async fn async_from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> PcapResult<(&'a [u8], RawCapPacket<'a>)> {
if slice.len() < 40 {
return Err(PcapError::IncompleteBuffer);
}
let timelo = AsyncReadBytesExt::read_u32::<B>(&mut slice).await.unwrap();
let timehi = AsyncReadBytesExt::read_u32::<B>(&mut slice).await.unwrap();
let orig_len = AsyncReadBytesExt::read_u16::<B>(&mut slice).await.unwrap();
let incl_len = AsyncReadBytesExt::read_u16::<B>(&mut slice).await.unwrap();
slice = &slice[28..];
let pkt_len = incl_len as usize;
if slice.len() < pkt_len {
return Err(PcapError::IncompleteBuffer);
}
let packet = RawCapPacket { timelo, timehi, incl_len, orig_len, data: Cow::Borrowed(&slice[..pkt_len]) };
let rem = &slice[pkt_len..];
Ok((rem, packet))
}
pub fn try_into_cap_packet(self, start_time: u32) -> PcapResult<CapPacket<'a>> {
CapPacket::try_from_raw_packet(self, start_time)
}
}