use std::borrow::Cow;
use std::io::Write;
use std::time::Duration;
use byteorder_slice::ByteOrder;
use byteorder_slice::byteorder::WriteBytesExt;
use byteorder_slice::result::ReadSlice;
use derive_into_owned::IntoOwned;
use crate::pcap::{PcapParseError, PcapTsResolution, PcapValidationError, PcapWriteError};
#[derive(Clone, Debug)]
pub struct PcapPacket<'a> {
timestamp: Duration,
orig_len: u32,
data: Cow<'a, [u8]>,
}
impl<'a> PcapPacket<'a> {
pub fn new(
timestamp: Duration,
orig_len: u32,
data: impl Into<Cow<'a, [u8]>>,
) -> Result<Self, PcapValidationError> {
let data = data.into();
if timestamp.as_secs() > u32::MAX as u64 {
return Err(PcapValidationError::TimestampTooBig(timestamp));
}
let Ok(incl_len): Result<u32, _> = data.len().try_into() else {
return Err(PcapValidationError::DataTooBig(data.len()));
};
if incl_len > orig_len {
return Err(PcapValidationError::OriginLenTooSmall(orig_len, incl_len));
}
Ok(PcapPacket {
timestamp,
orig_len,
data,
})
}
pub fn timestamp(&self) -> Duration {
self.timestamp
}
pub fn orig_len(&self) -> u32 {
self.orig_len
}
pub fn len(&self) -> u32 {
self.data
.len()
.try_into()
.expect("PcapPacket::data_len > u32::MAX, should have been validated on PcapPacket creation")
}
pub fn is_empty(&self) -> bool {
self.data.is_empty()
}
pub fn data(&self) -> &[u8] {
&self.data
}
pub fn into_data(self) -> Cow<'a, [u8]> {
self.data
}
pub fn to_owned(&self) -> PcapPacket<'static> {
self.clone().into_owned()
}
pub fn into_owned(self) -> PcapPacket<'static> {
PcapPacket {
timestamp: self.timestamp,
orig_len: self.orig_len,
data: Cow::Owned(self.data.into_owned()),
}
}
pub fn try_from_raw_packet(
raw: RawPcapPacket<'a>,
ts_resolution: PcapTsResolution,
snap_len: u32,
) -> Result<Self, PcapValidationError> {
let ts_sec = raw.ts_sec;
let ts_nsec = if ts_resolution == PcapTsResolution::MicroSecond {
let ts_usec = raw.ts_frac;
if ts_usec >= 1_000_000 {
return Err(PcapValidationError::TsFracMicroTooBig(ts_usec));
}
ts_usec
.checked_mul(1000)
.expect("ts_usec * 1000 overflow, should have been validated just before")
} else {
let ts_nsec = raw.ts_frac;
if ts_nsec >= 1_000_000_000 {
return Err(PcapValidationError::TsFracNanoTooBig(raw.ts_frac));
}
ts_nsec
};
let timestamp = Duration::new(ts_sec as u64, ts_nsec);
if raw.incl_len > snap_len {
return Err(PcapValidationError::IncludedLenTooBig(raw.incl_len, snap_len));
}
Self::new(timestamp, raw.orig_len, raw.data)
}
pub fn into_raw_packet(self, ts_resolution: PcapTsResolution) -> RawPcapPacket<'a> {
let (ts_sec, ts_frac, incl_len, orig_len) = self.build_raw_header(ts_resolution);
RawPcapPacket {
ts_sec,
ts_frac,
incl_len,
orig_len,
data: self.data,
}
}
pub fn as_raw_packet<'pkt>(&'pkt self, ts_resolution: PcapTsResolution) -> RawPcapPacket<'pkt> {
let (ts_sec, ts_frac, incl_len, orig_len) = self.build_raw_header(ts_resolution);
RawPcapPacket {
ts_sec,
ts_frac,
incl_len,
orig_len,
data: Cow::Borrowed(&self.data),
}
}
fn build_raw_header(&self, ts_resolution: PcapTsResolution) -> (u32, u32, u32, u32) {
let ts_sec: u32 = self
.timestamp
.as_secs()
.try_into()
.expect("PcapPacket::timestamp_secs > u32::MAX, should have been validated on PcapPacket creation");
let mut ts_frac = self.timestamp.subsec_nanos();
if ts_resolution == PcapTsResolution::MicroSecond {
ts_frac /= 1000;
}
let incl_len: u32 = self
.data
.len()
.try_into()
.expect("PcapPacket::data_len > u32::MAX, should have been validated on PcapPacket creation");
let orig_len = self.orig_len;
(ts_sec, ts_frac, incl_len, orig_len)
}
}
#[derive(Clone, Debug, IntoOwned)]
pub struct RawPcapPacket<'a> {
pub ts_sec: u32,
pub ts_frac: u32,
pub incl_len: u32,
pub orig_len: u32,
pub data: Cow<'a, [u8]>,
}
impl<'a> RawPcapPacket<'a> {
pub fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> Result<(&'a [u8], Self), PcapParseError> {
if slice.len() < 16 {
return Err(PcapParseError::IncompleteBuffer(16, slice.len()));
}
let ts_sec = slice.read_u32::<B>().expect("slice length checked above");
let ts_frac = slice.read_u32::<B>().expect("slice length checked above");
let incl_len = slice.read_u32::<B>().expect("slice length checked above");
let orig_len = slice.read_u32::<B>().expect("slice length checked above");
let pkt_len = incl_len as usize;
if slice.len() < pkt_len {
return Err(PcapParseError::IncompleteBuffer(pkt_len, slice.len()));
}
let packet = RawPcapPacket {
ts_sec,
ts_frac,
incl_len,
orig_len,
data: Cow::Borrowed(&slice[..pkt_len]),
};
let rem = &slice[pkt_len..];
Ok((rem, packet))
}
pub fn write_to<W: Write, B: ByteOrder>(&self, writer: &mut W) -> Result<usize, PcapWriteError> {
writer
.write_u32::<B>(self.ts_sec)
.map_err(|e| PcapWriteError::FieldWriteFailed("ts_sec", e))?;
writer
.write_u32::<B>(self.ts_frac)
.map_err(|e| PcapWriteError::FieldWriteFailed("ts_frac", e))?;
writer
.write_u32::<B>(self.incl_len)
.map_err(|e| PcapWriteError::FieldWriteFailed("incl_len", e))?;
writer
.write_u32::<B>(self.orig_len)
.map_err(|e| PcapWriteError::FieldWriteFailed("orig_len", e))?;
writer
.write_all(&self.data)
.map_err(|e| PcapWriteError::FieldWriteFailed("data", e))?;
Ok(16 + self.data.len())
}
pub fn try_into_pcap_packet(
self,
ts_resolution: PcapTsResolution,
snap_len: u32,
) -> Result<PcapPacket<'a>, PcapValidationError> {
PcapPacket::try_from_raw_packet(self, ts_resolution, snap_len)
}
}