use crate::error::PcapError;
use crate::linktype::Linktype;
use crate::utils::array_ref4;
use nom::bytes::streaming::take;
use nom::number::streaming::{be_i32, be_u16, be_u32, le_i32, le_u16, le_u32};
use nom::IResult;
#[derive(Clone, Debug)]
pub struct PcapHeader {
pub magic_number: u32,
pub version_major: u16,
pub version_minor: u16,
pub thiszone: i32,
pub sigfigs: u32,
pub snaplen: u32,
pub network: Linktype,
}
impl PcapHeader {
pub fn new() -> PcapHeader {
PcapHeader {
magic_number: 0xa1b2_c3d4, version_major: 2,
version_minor: 4,
thiszone: 0,
sigfigs: 0,
snaplen: 0,
network: Linktype(1), }
}
pub const fn size(&self) -> usize {
24
}
pub fn is_bigendian(&self) -> bool {
(self.magic_number & 0xFFFF) == 0xb2a1 }
pub fn is_nanosecond_precision(&self) -> bool {
self.magic_number == 0xa1b2_3c4d || self.magic_number == 0x4d3c_b2a1
}
}
impl Default for PcapHeader {
fn default() -> Self {
PcapHeader::new()
}
}
#[derive(Debug)]
pub struct LegacyPcapBlock<'a> {
pub ts_sec: u32,
pub ts_usec: u32,
pub caplen: u32,
pub origlen: u32,
pub data: &'a [u8],
}
pub fn parse_pcap_frame(i: &[u8]) -> IResult<&[u8], LegacyPcapBlock, PcapError<&[u8]>> {
if i.len() < 16 {
return Err(nom::Err::Incomplete(nom::Needed::new(16 - i.len())));
}
let ts_sec = u32::from_le_bytes(*array_ref4(i, 0));
let ts_usec = u32::from_le_bytes(*array_ref4(i, 4));
let caplen = u32::from_le_bytes(*array_ref4(i, 8));
let origlen = u32::from_le_bytes(*array_ref4(i, 12));
let (i, data) = take(caplen as usize)(&i[16..])?;
let block = LegacyPcapBlock {
ts_sec,
ts_usec,
caplen,
origlen,
data,
};
Ok((i, block))
}
pub fn parse_pcap_frame_be(i: &[u8]) -> IResult<&[u8], LegacyPcapBlock, PcapError<&[u8]>> {
if i.len() < 16 {
return Err(nom::Err::Incomplete(nom::Needed::new(16 - i.len())));
}
let ts_sec = u32::from_be_bytes(*array_ref4(i, 0));
let ts_usec = u32::from_be_bytes(*array_ref4(i, 4));
let caplen = u32::from_be_bytes(*array_ref4(i, 8));
let origlen = u32::from_be_bytes(*array_ref4(i, 12));
let (i, data) = take(caplen as usize)(&i[16..])?;
let block = LegacyPcapBlock {
ts_sec,
ts_usec,
caplen,
origlen,
data,
};
Ok((i, block))
}
pub fn parse_pcap_header(i: &[u8]) -> IResult<&[u8], PcapHeader, PcapError<&[u8]>> {
let (i, magic_number) = le_u32(i)?;
match magic_number {
0xa1b2_c3d4 | 0xa1b2_3c4d => {
let (i, version_major) = le_u16(i)?;
let (i, version_minor) = le_u16(i)?;
let (i, thiszone) = le_i32(i)?;
let (i, sigfigs) = le_u32(i)?;
let (i, snaplen) = le_u32(i)?;
let (i, network) = le_i32(i)?;
let header = PcapHeader {
magic_number,
version_major,
version_minor,
thiszone,
sigfigs,
snaplen,
network: Linktype(network),
};
Ok((i, header))
}
0xd4c3_b2a1 | 0x4d3c_b2a1 => {
let (i, version_major) = be_u16(i)?;
let (i, version_minor) = be_u16(i)?;
let (i, thiszone) = be_i32(i)?;
let (i, sigfigs) = be_u32(i)?;
let (i, snaplen) = be_u32(i)?;
let (i, network) = be_i32(i)?;
let header = PcapHeader {
magic_number,
version_major,
version_minor,
thiszone,
sigfigs,
snaplen,
network: Linktype(network),
};
Ok((i, header))
}
_ => Err(nom::Err::Error(PcapError::HeaderNotRecognized)),
}
}
#[cfg(test)]
pub mod tests {
use crate::pcap::{parse_pcap_frame, parse_pcap_header};
use crate::traits::tests::FRAME_PCAP;
use hex_literal::hex;
pub const PCAP_HDR: &[u8] = &hex!(
"
D4 C3 B2 A1 02 00 04 00 00 00 00 00 00 00 00 00
00 00 04 00 01 00 00 00"
);
pub const PCAP_HDR_NSEC: &[u8] = &hex!(
"
4D 3C B2 A1 02 00 04 00 00 00 00 00 00 00 00 00
00 00 04 00 01 00 00 00"
);
#[test]
fn test_parse_pcap_header() {
let (rem, hdr) = parse_pcap_header(PCAP_HDR).expect("header parsing failed");
assert!(rem.is_empty());
assert_eq!(hdr.magic_number, 0xa1b2_c3d4);
assert_eq!(hdr.version_major, 2);
assert_eq!(hdr.version_minor, 4);
assert_eq!(hdr.snaplen, 262_144);
assert!(!hdr.is_nanosecond_precision());
}
#[test]
fn test_parse_nanosecond_precision_pcap_header() {
let (rem, hdr) = parse_pcap_header(PCAP_HDR_NSEC).expect("header parsing failed");
assert!(rem.is_empty());
assert_eq!(hdr.magic_number, 0xa1b2_3c4d);
assert_eq!(hdr.version_major, 2);
assert_eq!(hdr.version_minor, 4);
assert_eq!(hdr.snaplen, 262_144);
assert!(hdr.is_nanosecond_precision());
}
#[test]
fn test_parse_pcap_frame() {
let (rem, pkt) = parse_pcap_frame(FRAME_PCAP).expect("packet parsing failed");
assert!(rem.is_empty());
assert_eq!(pkt.origlen, 74);
assert_eq!(pkt.ts_usec, 562_913);
assert_eq!(pkt.ts_sec, 1_515_933_236);
}
}