pcap_parser/pcapng/
block.rs

1use nom::bytes::streaming::take;
2use nom::combinator::map;
3use nom::number::streaming::{be_u32, le_u32};
4use nom::{error::*, Parser as _};
5use nom::{Err, IResult};
6
7use crate::endianness::PcapEndianness;
8use crate::PcapError;
9
10use super::*;
11
12/// A block from a PcapNG file
13#[derive(Debug)]
14pub enum Block<'a> {
15    SectionHeader(SectionHeaderBlock<'a>),
16    InterfaceDescription(InterfaceDescriptionBlock<'a>),
17    EnhancedPacket(EnhancedPacketBlock<'a>),
18    SimplePacket(SimplePacketBlock<'a>),
19    NameResolution(NameResolutionBlock<'a>),
20    InterfaceStatistics(InterfaceStatisticsBlock<'a>),
21    SystemdJournalExport(SystemdJournalExportBlock<'a>),
22    DecryptionSecrets(DecryptionSecretsBlock<'a>),
23    ProcessInformation(ProcessInformationBlock<'a>),
24    Custom(CustomBlock<'a>),
25    Unknown(UnknownBlock<'a>),
26}
27
28impl Block<'_> {
29    /// Returns true if blocks contains a network packet
30    pub fn is_data_block(&self) -> bool {
31        matches!(self, &Block::EnhancedPacket(_) | &Block::SimplePacket(_))
32    }
33
34    /// Return the normalized magic number of the block
35    pub fn magic(&self) -> u32 {
36        match self {
37            Block::SectionHeader(_) => SHB_MAGIC,
38            Block::InterfaceDescription(_) => IDB_MAGIC,
39            Block::EnhancedPacket(_) => EPB_MAGIC,
40            Block::SimplePacket(_) => SPB_MAGIC,
41            Block::NameResolution(_) => NRB_MAGIC,
42            Block::InterfaceStatistics(_) => ISB_MAGIC,
43            Block::SystemdJournalExport(_) => SJE_MAGIC,
44            Block::DecryptionSecrets(_) => DSB_MAGIC,
45            Block::ProcessInformation(_) => PIB_MAGIC,
46            Block::Custom(cb) => cb.block_type,
47            Block::Unknown(ub) => ub.block_type,
48        }
49    }
50}
51
52/// Parse any block, as little-endian
53///
54/// To find which endianess to use, read the section header
55/// using `parse_sectionheaderblock`
56pub fn parse_block_le(i: &[u8]) -> IResult<&[u8], Block<'_>, PcapError<&[u8]>> {
57    match le_u32(i) {
58        Ok((_, id)) => match id {
59            SHB_MAGIC => map(parse_sectionheaderblock, Block::SectionHeader).parse(i),
60            IDB_MAGIC => map(
61                parse_interfacedescriptionblock_le,
62                Block::InterfaceDescription,
63            )
64            .parse(i),
65            SPB_MAGIC => map(parse_simplepacketblock_le, Block::SimplePacket).parse(i),
66            EPB_MAGIC => map(parse_enhancedpacketblock_le, Block::EnhancedPacket).parse(i),
67            NRB_MAGIC => map(parse_nameresolutionblock_le, Block::NameResolution).parse(i),
68            ISB_MAGIC => map(
69                parse_interfacestatisticsblock_le,
70                Block::InterfaceStatistics,
71            )
72            .parse(i),
73            SJE_MAGIC => map(
74                parse_systemdjournalexportblock_le,
75                Block::SystemdJournalExport,
76            )
77            .parse(i),
78            DSB_MAGIC => map(parse_decryptionsecretsblock_le, Block::DecryptionSecrets).parse(i),
79            CB_MAGIC => map(parse_customblock_le, Block::Custom).parse(i),
80            DCB_MAGIC => map(parse_dcb_le, Block::Custom).parse(i),
81            PIB_MAGIC => map(parse_processinformationblock_le, Block::ProcessInformation).parse(i),
82            _ => map(parse_unknownblock_le, Block::Unknown).parse(i),
83        },
84        Err(e) => Err(e),
85    }
86}
87
88/// Parse any block, as big-endian
89///
90/// To find which endianess to use, read the section header
91/// using `parse_sectionheaderblock`
92pub fn parse_block_be(i: &[u8]) -> IResult<&[u8], Block<'_>, PcapError<&[u8]>> {
93    match be_u32(i) {
94        Ok((_, id)) => match id {
95            SHB_MAGIC => map(parse_sectionheaderblock, Block::SectionHeader).parse(i),
96            IDB_MAGIC => map(
97                parse_interfacedescriptionblock_be,
98                Block::InterfaceDescription,
99            )
100            .parse(i),
101            SPB_MAGIC => map(parse_simplepacketblock_be, Block::SimplePacket).parse(i),
102            EPB_MAGIC => map(parse_enhancedpacketblock_be, Block::EnhancedPacket).parse(i),
103            NRB_MAGIC => map(parse_nameresolutionblock_be, Block::NameResolution).parse(i),
104            ISB_MAGIC => map(
105                parse_interfacestatisticsblock_be,
106                Block::InterfaceStatistics,
107            )
108            .parse(i),
109            SJE_MAGIC => map(
110                parse_systemdjournalexportblock_be,
111                Block::SystemdJournalExport,
112            )
113            .parse(i),
114            DSB_MAGIC => map(parse_decryptionsecretsblock_be, Block::DecryptionSecrets).parse(i),
115            CB_MAGIC => map(parse_customblock_be, Block::Custom).parse(i),
116            DCB_MAGIC => map(parse_dcb_be, Block::Custom).parse(i),
117            PIB_MAGIC => map(parse_processinformationblock_be, Block::ProcessInformation).parse(i),
118            _ => map(parse_unknownblock_be, Block::Unknown).parse(i),
119        },
120        Err(e) => Err(e),
121    }
122}
123
124pub(crate) trait PcapNGBlockParser<'a, En: PcapEndianness, O: 'a> {
125    /// Minimum header size, in bytes
126    const HDR_SZ: usize;
127    /// Little-endian magic number for this block type
128    const MAGIC: u32;
129
130    // caller function must have tested header type(magic) and length
131    fn inner_parse<E: ParseError<&'a [u8]>>(
132        block_type: u32,
133        block_len1: u32,
134        i: &'a [u8],
135        block_len2: u32,
136    ) -> IResult<&'a [u8], O, E>;
137}
138
139/// Create a block parser function, given the parameters (block object and endianness)
140pub(crate) fn ng_block_parser<'a, P, En, O, E>() -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E>
141where
142    P: PcapNGBlockParser<'a, En, O>,
143    En: PcapEndianness,
144    O: 'a,
145    E: ParseError<&'a [u8]>,
146{
147    move |i: &[u8]| {
148        // read generic block layout
149        //
150        if i.len() < P::HDR_SZ {
151            return Err(Err::Incomplete(nom::Needed::new(P::HDR_SZ - i.len())));
152        }
153        let (i, block_type) = le_u32(i)?;
154        let (i, block_len1) = En::parse_u32(i)?;
155        if block_len1 < P::HDR_SZ as u32 {
156            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
157        }
158        if P::MAGIC != 0 && En::native_u32(block_type) != P::MAGIC {
159            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
160        }
161        // 12 is block_type (4) + block_len1 (4) + block_len2 (4)
162        let (i, block_content) = take(block_len1 - 12)(i)?;
163        let (i, block_len2) = En::parse_u32(i)?;
164        // call block content parsing function
165        let (_, b) = P::inner_parse(block_type, block_len1, block_content, block_len2)?;
166        // return the remaining bytes from the container, not content
167        Ok((i, b))
168    }
169}