pcap_parser/pcapng/
enhanced_packet.rs

1use nom::bytes::streaming::take;
2use nom::error::{ErrorKind, ParseError};
3use nom::{Err, IResult};
4use rusticata_macros::align32;
5
6use crate::endianness::{PcapBE, PcapEndianness, PcapLE};
7use crate::traits::PcapNGPacketBlock;
8use crate::utils::array_ref4;
9use crate::{build_ts, build_ts_f64, opt_parse_options, PcapError, PcapNGOption, EPB_MAGIC};
10
11use super::*;
12
13/// An Enhanced Packet Block (EPB) is the standard container for storing
14/// the packets coming from the network.
15///
16/// This struct is a thin abstraction layer, and stores the raw block data.
17/// For ex the `data` field is stored with the padding.
18/// It implements the `PcapNGPacketBlock` trait, which provides helper functions.
19///
20/// ## Examples
21///
22/// ```rust
23/// use pcap_parser::pcapng::parse_enhancedpacketblock_le;
24/// use pcap_parser::traits::PcapNGPacketBlock;
25///
26/// # let input_data = include_bytes!("../../assets/test001-le.pcapng");
27/// # let pcap_data = &input_data[148..=495];
28/// let (i, epb) = parse_enhancedpacketblock_le(pcap_data).unwrap();
29/// let packet_data = epb.packet_data();
30/// if packet_data.len() < epb.orig_len() as usize {
31///     // packet was truncated
32/// } else {
33///     // we have a full packet
34/// }
35/// ```
36#[derive(Debug)]
37pub struct EnhancedPacketBlock<'a> {
38    // Block type, read as little-endian.
39    // If block value is the reverse the the expected magic, this means block is encoded as big-endian
40    pub block_type: u32,
41    pub block_len1: u32,
42    pub if_id: u32,
43    pub ts_high: u32,
44    pub ts_low: u32,
45    /// Captured packet length
46    pub caplen: u32,
47    /// Original packet length
48    pub origlen: u32,
49    /// Raw data from packet (with padding)
50    pub data: &'a [u8],
51    pub options: Vec<PcapNGOption<'a>>,
52    pub block_len2: u32,
53}
54
55impl EnhancedPacketBlock<'_> {
56    /// Decode the packet timestamp
57    ///
58    /// To decode the timestamp, the raw values if_tsresol and if_tsoffset are required.
59    /// These values are stored as options in the [`InterfaceDescriptionBlock`]
60    /// matching the interface ID.
61    ///
62    /// Return the timestamp seconds and fractional part (in resolution units)
63    #[inline]
64    pub fn decode_ts(&self, ts_offset: u64, resolution: u64) -> (u32, u32) {
65        build_ts(self.ts_high, self.ts_low, ts_offset, resolution)
66    }
67
68    /// Decode the packet timestamp as `f64`
69    ///
70    /// To decode the timestamp, the resolution and offset are required.
71    /// These values are stored as options in the [`InterfaceDescriptionBlock`]
72    /// matching the interface ID.
73    #[inline]
74    pub fn decode_ts_f64(&self, ts_offset: u64, resolution: u64) -> f64 {
75        build_ts_f64(self.ts_high, self.ts_low, ts_offset, resolution)
76    }
77}
78
79impl PcapNGPacketBlock for EnhancedPacketBlock<'_> {
80    fn big_endian(&self) -> bool {
81        self.block_type != EPB_MAGIC
82    }
83    fn truncated(&self) -> bool {
84        self.origlen != self.caplen
85    }
86    fn orig_len(&self) -> u32 {
87        self.origlen
88    }
89    fn raw_packet_data(&self) -> &[u8] {
90        self.data
91    }
92    fn packet_data(&self) -> &[u8] {
93        let caplen = self.caplen as usize;
94        if caplen < self.data.len() {
95            &self.data[..caplen]
96        } else {
97            self.data
98        }
99    }
100}
101
102impl<'a, En: PcapEndianness> PcapNGBlockParser<'a, En, EnhancedPacketBlock<'a>>
103    for EnhancedPacketBlock<'a>
104{
105    const HDR_SZ: usize = 32;
106    const MAGIC: u32 = EPB_MAGIC;
107
108    fn inner_parse<E: ParseError<&'a [u8]>>(
109        block_type: u32,
110        block_len1: u32,
111        i: &'a [u8],
112        block_len2: u32,
113    ) -> IResult<&'a [u8], EnhancedPacketBlock<'a>, E> {
114        // caller function already tested header type(magic) and length
115        // read end of header
116        let (b_hdr, packet_data) = i.split_at(20);
117        let if_id = En::u32_from_bytes(*array_ref4(b_hdr, 0));
118        let ts_high = En::u32_from_bytes(*array_ref4(b_hdr, 4));
119        let ts_low = En::u32_from_bytes(*array_ref4(b_hdr, 8));
120        let caplen = En::u32_from_bytes(*array_ref4(b_hdr, 12));
121        let origlen = En::u32_from_bytes(*array_ref4(b_hdr, 16));
122        // read packet data
123        // align32 can overflow
124        if caplen >= u32::MAX - 4 {
125            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
126        }
127        let padded_length = align32!(caplen);
128        let (i, data) = take(padded_length)(packet_data)?;
129        // read options
130        let current_offset = (32 + padded_length) as usize;
131        let (i, options) = opt_parse_options::<En, E>(i, block_len1 as usize, current_offset)?;
132        if block_len2 != block_len1 {
133            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
134        }
135        let block = EnhancedPacketBlock {
136            block_type,
137            block_len1,
138            if_id,
139            ts_high,
140            ts_low,
141            caplen,
142            origlen,
143            data,
144            options,
145            block_len2,
146        };
147        Ok((i, block))
148    }
149}
150
151/// Parse an Enhanced Packet Block (little-endian)
152pub fn parse_enhancedpacketblock_le(
153    i: &[u8],
154) -> IResult<&[u8], EnhancedPacketBlock<'_>, PcapError<&[u8]>> {
155    ng_block_parser::<EnhancedPacketBlock, PcapLE, _, _>()(i)
156}
157
158/// Parse an Enhanced Packet Block (big-endian)
159pub fn parse_enhancedpacketblock_be(
160    i: &[u8],
161) -> IResult<&[u8], EnhancedPacketBlock<'_>, PcapError<&[u8]>> {
162    ng_block_parser::<EnhancedPacketBlock, PcapBE, _, _>()(i)
163}