use nom::bytes::streaming::take;
use nom::error::{ErrorKind, ParseError};
use nom::{Err, IResult};
use rusticata_macros::align32;
use crate::endianness::{PcapBE, PcapEndianness, PcapLE};
use crate::traits::PcapNGPacketBlock;
use crate::utils::array_ref4;
use crate::{build_ts, build_ts_f64, opt_parse_options, PcapError, PcapNGOption, EPB_MAGIC};
use super::*;
#[derive(Debug)]
pub struct EnhancedPacketBlock<'a> {
pub block_type: u32,
pub block_len1: u32,
pub if_id: u32,
pub ts_high: u32,
pub ts_low: u32,
pub caplen: u32,
pub origlen: u32,
pub data: &'a [u8],
pub options: Vec<PcapNGOption<'a>>,
pub block_len2: u32,
}
impl EnhancedPacketBlock<'_> {
#[inline]
pub fn decode_ts(&self, ts_offset: u64, resolution: u64) -> (u32, u32) {
build_ts(self.ts_high, self.ts_low, ts_offset, resolution)
}
#[inline]
pub fn decode_ts_f64(&self, ts_offset: u64, resolution: u64) -> f64 {
build_ts_f64(self.ts_high, self.ts_low, ts_offset, resolution)
}
}
impl PcapNGPacketBlock for EnhancedPacketBlock<'_> {
fn big_endian(&self) -> bool {
self.block_type != EPB_MAGIC
}
fn truncated(&self) -> bool {
self.origlen != self.caplen
}
fn orig_len(&self) -> u32 {
self.origlen
}
fn raw_packet_data(&self) -> &[u8] {
self.data
}
fn packet_data(&self) -> &[u8] {
let caplen = self.caplen as usize;
if caplen < self.data.len() {
&self.data[..caplen]
} else {
self.data
}
}
}
impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, EnhancedPacketBlock<'a>>
for EnhancedPacketBlock<'a>
{
const HDR_SZ: usize = 32;
const MAGIC: u32 = EPB_MAGIC;
fn inner_parse<E: ParseError<&'a [u8]>>(
block_type: u32,
block_len1: u32,
i: &'a [u8],
block_len2: u32,
) -> IResult<&'a [u8], EnhancedPacketBlock<'a>, E> {
let (b_hdr, packet_data) = i.split_at(20);
let if_id = En::u32_from_bytes(*array_ref4(b_hdr, 0));
let ts_high = En::u32_from_bytes(*array_ref4(b_hdr, 4));
let ts_low = En::u32_from_bytes(*array_ref4(b_hdr, 8));
let caplen = En::u32_from_bytes(*array_ref4(b_hdr, 12));
let origlen = En::u32_from_bytes(*array_ref4(b_hdr, 16));
if caplen >= u32::MAX - 4 {
return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
}
let padded_length = align32!(caplen);
let (i, data) = take(padded_length)(packet_data)?;
let current_offset = (32 + padded_length) as usize;
let (i, options) = opt_parse_options::<En, E>(i, block_len1 as usize, current_offset)?;
if block_len2 != block_len1 {
return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
}
let block = EnhancedPacketBlock {
block_type,
block_len1,
if_id,
ts_high,
ts_low,
caplen,
origlen,
data,
options,
block_len2,
};
Ok((i, block))
}
}
pub fn parse_enhancedpacketblock_le(
i: &[u8],
) -> IResult<&[u8], EnhancedPacketBlock<'_>, PcapError<&[u8]>> {
ng_block_parser::<EnhancedPacketBlock, PcapLE, _, _>()(i)
}
pub fn parse_enhancedpacketblock_be(
i: &[u8],
) -> IResult<&[u8], EnhancedPacketBlock<'_>, PcapError<&[u8]>> {
ng_block_parser::<EnhancedPacketBlock, PcapBE, _, _>()(i)
}