use byteorder::ReadBytesExt;
use byteorder::{BigEndian, ByteOrder, LittleEndian};
#[cfg(feature = "tokio")]
use tokio_byteorder::AsyncReadBytesExt;
use crate::DataLink;
use crate::{errors::*, Endianness};
const CAPTUREFILE_HEADER_SIZE: usize = 128;
const OLD_NETXRAY_MAGIC: u32 = 0x564C0000;
const NETXRAY_MAGIC: u32 = 0x58435000;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct CapHeader {
pub version_major: u32,
pub version_minor: u32,
pub start_time: u32,
pub nframes: u32,
pub start_offset: u32,
pub end_offset: u32,
pub datalink: DataLink,
pub network_plus: u8,
pub captype: u8,
pub endianness: Endianness,
}
impl CapHeader {
pub fn from_slice(mut slice: &[u8]) -> PcapResult<(&[u8], CapHeader)> {
if slice.len() < CAPTUREFILE_HEADER_SIZE {
return Err(PcapError::IncompleteBuffer);
}
let magic_number = ReadBytesExt::read_u32::<BigEndian>(&mut slice).unwrap();
match magic_number {
NETXRAY_MAGIC => return init_cap_header::<LittleEndian>(slice, Endianness::Little),
OLD_NETXRAY_MAGIC => return Err(PcapError::UnsupportedVersion(magic_number.to_string())),
_ => return Err(PcapError::InvalidField("CapHeader: wrong magic number")),
};
fn init_cap_header<B: ByteOrder>(mut src: &[u8], endianness: Endianness) -> PcapResult<(&[u8], CapHeader)> {
let version_major = match src[0..3] {
[0x30, 0x30, 0x32] => 2,
_ => return Err(PcapError::UnsupportedVersion(String::from_utf8_lossy(&src[0..3]).to_string())),
};
src = &src[4..];
let version_minor = match String::from_utf8_lossy(&src[0..3]).parse::<u32>() {
Ok(v) => v,
Err(_e) => return Err(PcapError::InvalidField("CapHeader: invalid minor version")),
};
src = &src[4..];
let start_time = ReadBytesExt::read_u32::<B>(&mut src).unwrap();
let nframes = ReadBytesExt::read_u32::<B>(&mut src).unwrap();
src = &src[4..];
let start_offset = ReadBytesExt::read_u32::<B>(&mut src).unwrap();
let end_offset = ReadBytesExt::read_u32::<B>(&mut src).unwrap();
src = &src[12..];
let network = ReadBytesExt::read_u8(&mut src).unwrap();
let network_plus = ReadBytesExt::read_u8(&mut src).unwrap();
src = &src[2..];
src = &src[32..];
src = &src[4..];
let captype = ReadBytesExt::read_u8(&mut src).unwrap();
src = &src[11..];
src = &src[32..];
let mut _network_type;
match network_plus {
0 => _network_type = network + 1,
2 => _network_type = network,
_ => return Err(PcapError::InvalidField("CapHeader: invalid network plus code")),
}
let header = CapHeader {
version_major,
version_minor,
start_time,
nframes,
datalink: DataLink::ETHERNET,
network_plus,
captype,
start_offset,
end_offset,
endianness,
};
Ok((src, header))
}
}
#[cfg(feature = "tokio")]
pub async fn async_from_slice(mut slice: &[u8]) -> PcapResult<(&[u8], CapHeader)> {
if slice.len() < CAPTUREFILE_HEADER_SIZE {
return Err(PcapError::IncompleteBuffer);
}
let magic_number = AsyncReadBytesExt::read_u32::<BigEndian>(&mut slice).await.unwrap();
match magic_number {
NETXRAY_MAGIC => return init_cap_header::<LittleEndian>(slice, Endianness::Little).await,
OLD_NETXRAY_MAGIC => return Err(PcapError::UnsupportedVersion(magic_number.to_string())),
_ => return Err(PcapError::InvalidField("CapHeader: wrong magic number")),
};
async fn init_cap_header<B: ByteOrder>(mut src: &[u8], endianness: Endianness) -> PcapResult<(&[u8], CapHeader)> {
let version_major = match src[0..3] {
[0x30, 0x30, 0x32] => 2,
_ => return Err(PcapError::UnsupportedVersion(String::from_utf8_lossy(&src[0..3]).to_string())),
};
src = &src[4..];
let version_minor = match String::from_utf8_lossy(&src[0..3]).parse::<u32>() {
Ok(v) => v,
Err(_e) => return Err(PcapError::InvalidField("CapHeader: invalid minor version")),
};
src = &src[4..];
let start_time = AsyncReadBytesExt::read_u32::<B>(&mut src).await.unwrap();
let nframes = AsyncReadBytesExt::read_u32::<B>(&mut src).await.unwrap();
src = &src[4..];
let start_offset = AsyncReadBytesExt::read_u32::<B>(&mut src).await.unwrap();
let end_offset = AsyncReadBytesExt::read_u32::<B>(&mut src).await.unwrap();
src = &src[12..];
let network = AsyncReadBytesExt::read_u8(&mut src).await.unwrap();
let network_plus = AsyncReadBytesExt::read_u8(&mut src).await.unwrap();
src = &src[2..];
src = &src[32..];
src = &src[4..];
let captype = AsyncReadBytesExt::read_u8(&mut src).await.unwrap();
src = &src[11..];
src = &src[32..];
let mut _network_type;
match network_plus {
0 => _network_type = network + 1,
2 => _network_type = network,
_ => return Err(PcapError::InvalidField("CapHeader: invalid network plus code")),
}
let header = CapHeader {
version_major,
version_minor,
start_time,
nframes,
datalink: DataLink::ETHERNET,
network_plus,
captype,
start_offset,
end_offset,
endianness,
};
Ok((src, header))
}
}
}