use std::io::Write;
use byteorder_slice::byteorder::WriteBytesExt;
use byteorder_slice::result::ReadSlice;
use byteorder_slice::{BigEndian, ByteOrder, LittleEndian};
use crate::pcap::{PcapParseError, PcapTsResolution, PcapValidationError, PcapWriteError};
use crate::{DataLink, Endianness};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct PcapHeader {
pub version_major: u16,
pub version_minor: u16,
pub ts_correction: i32,
pub ts_accuracy: u32,
pub snaplen: u32,
pub datalink: DataLink,
pub ts_resolution: PcapTsResolution,
pub endianness: Endianness,
}
impl PcapHeader {
pub fn from_slice(mut slice: &[u8]) -> Result<(&[u8], PcapHeader), PcapParseError> {
if slice.len() < 24 {
return Err(PcapParseError::IncompleteBuffer(24, slice.len()));
}
let magic_number = slice.read_u32::<BigEndian>().unwrap();
match magic_number {
0xA1B2C3D4 => return init_pcap_header::<BigEndian>(slice, PcapTsResolution::MicroSecond, Endianness::Big),
0xA1B23C4D => return init_pcap_header::<BigEndian>(slice, PcapTsResolution::NanoSecond, Endianness::Big),
0xD4C3B2A1 => {
return init_pcap_header::<LittleEndian>(slice, PcapTsResolution::MicroSecond, Endianness::Little);
}
0x4D3CB2A1 => {
return init_pcap_header::<LittleEndian>(slice, PcapTsResolution::NanoSecond, Endianness::Little);
}
_ => return Err(PcapValidationError::InvalidMagicNumber(magic_number).into()),
};
fn init_pcap_header<B: ByteOrder>(
mut src: &[u8],
ts_resolution: PcapTsResolution,
endianness: Endianness,
) -> Result<(&[u8], PcapHeader), PcapParseError> {
let header = PcapHeader {
version_major: src.read_u16::<B>().unwrap(),
version_minor: src.read_u16::<B>().unwrap(),
ts_correction: src.read_i32::<B>().unwrap(),
ts_accuracy: src.read_u32::<B>().unwrap(),
snaplen: src.read_u32::<B>().unwrap(),
datalink: DataLink::from(src.read_u32::<B>().unwrap()),
ts_resolution,
endianness,
};
Ok((src, header))
}
}
pub fn write_to<W: Write>(&self, writer: &mut W) -> Result<usize, PcapWriteError> {
return match self.endianness {
Endianness::Big => write_header::<_, BigEndian>(self, writer),
Endianness::Little => write_header::<_, LittleEndian>(self, writer),
};
fn write_header<W: Write, B: ByteOrder>(header: &PcapHeader, writer: &mut W) -> Result<usize, PcapWriteError> {
let magic_number = match header.ts_resolution {
PcapTsResolution::MicroSecond => 0xA1B2C3D4,
PcapTsResolution::NanoSecond => 0xA1B23C4D,
};
writer
.write_u32::<B>(magic_number)
.map_err(|e| PcapWriteError::FieldWriteFailed("magic_number", e))?;
writer
.write_u16::<B>(header.version_major)
.map_err(|e| PcapWriteError::FieldWriteFailed("version_major", e))?;
writer
.write_u16::<B>(header.version_minor)
.map_err(|e| PcapWriteError::FieldWriteFailed("version_minor", e))?;
writer
.write_i32::<B>(header.ts_correction)
.map_err(|e| PcapWriteError::FieldWriteFailed("ts_correction", e))?;
writer
.write_u32::<B>(header.ts_accuracy)
.map_err(|e| PcapWriteError::FieldWriteFailed("ts_accuracy", e))?;
writer
.write_u32::<B>(header.snaplen)
.map_err(|e| PcapWriteError::FieldWriteFailed("snaplen", e))?;
writer
.write_u32::<B>(header.datalink.into())
.map_err(|e| PcapWriteError::FieldWriteFailed("datalink", e))?;
Ok(24)
}
}
}
impl Default for PcapHeader {
fn default() -> Self {
PcapHeader {
version_major: 2,
version_minor: 4,
ts_correction: 0,
ts_accuracy: 0,
snaplen: 65535,
datalink: DataLink::ETHERNET,
ts_resolution: PcapTsResolution::MicroSecond,
endianness: Endianness::default(),
}
}
}