pcap_parser/pcapng/
block.rs

1use nom::bytes::streaming::take;
2use nom::combinator::map;
3use nom::error::*;
4use nom::number::streaming::{be_u32, le_u32};
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<'a> Block<'a> {
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)(i),
60            IDB_MAGIC => map(
61                parse_interfacedescriptionblock_le,
62                Block::InterfaceDescription,
63            )(i),
64            SPB_MAGIC => map(parse_simplepacketblock_le, Block::SimplePacket)(i),
65            EPB_MAGIC => map(parse_enhancedpacketblock_le, Block::EnhancedPacket)(i),
66            NRB_MAGIC => map(parse_nameresolutionblock_le, Block::NameResolution)(i),
67            ISB_MAGIC => map(
68                parse_interfacestatisticsblock_le,
69                Block::InterfaceStatistics,
70            )(i),
71            SJE_MAGIC => map(
72                parse_systemdjournalexportblock_le,
73                Block::SystemdJournalExport,
74            )(i),
75            DSB_MAGIC => map(parse_decryptionsecretsblock_le, Block::DecryptionSecrets)(i),
76            CB_MAGIC => map(parse_customblock_le, Block::Custom)(i),
77            DCB_MAGIC => map(parse_dcb_le, Block::Custom)(i),
78            PIB_MAGIC => map(parse_processinformationblock_le, Block::ProcessInformation)(i),
79            _ => map(parse_unknownblock_le, Block::Unknown)(i),
80        },
81        Err(e) => Err(e),
82    }
83}
84
85/// Parse any block, as big-endian
86///
87/// To find which endianess to use, read the section header
88/// using `parse_sectionheaderblock`
89pub fn parse_block_be(i: &[u8]) -> IResult<&[u8], Block, PcapError<&[u8]>> {
90    match be_u32(i) {
91        Ok((_, id)) => match id {
92            SHB_MAGIC => map(parse_sectionheaderblock, Block::SectionHeader)(i),
93            IDB_MAGIC => map(
94                parse_interfacedescriptionblock_be,
95                Block::InterfaceDescription,
96            )(i),
97            SPB_MAGIC => map(parse_simplepacketblock_be, Block::SimplePacket)(i),
98            EPB_MAGIC => map(parse_enhancedpacketblock_be, Block::EnhancedPacket)(i),
99            NRB_MAGIC => map(parse_nameresolutionblock_be, Block::NameResolution)(i),
100            ISB_MAGIC => map(
101                parse_interfacestatisticsblock_be,
102                Block::InterfaceStatistics,
103            )(i),
104            SJE_MAGIC => map(
105                parse_systemdjournalexportblock_be,
106                Block::SystemdJournalExport,
107            )(i),
108            DSB_MAGIC => map(parse_decryptionsecretsblock_be, Block::DecryptionSecrets)(i),
109            CB_MAGIC => map(parse_customblock_be, Block::Custom)(i),
110            DCB_MAGIC => map(parse_dcb_be, Block::Custom)(i),
111            PIB_MAGIC => map(parse_processinformationblock_be, Block::ProcessInformation)(i),
112            _ => map(parse_unknownblock_be, Block::Unknown)(i),
113        },
114        Err(e) => Err(e),
115    }
116}
117
118pub(crate) trait PcapNGBlockParser<'a, En: PcapEndianness, O: 'a> {
119    /// Minimum header size, in bytes
120    const HDR_SZ: usize;
121    /// Little-endian magic number for this block type
122    const MAGIC: u32;
123
124    // caller function must have tested header type(magic) and length
125    fn inner_parse<E: ParseError<&'a [u8]>>(
126        block_type: u32,
127        block_len1: u32,
128        i: &'a [u8],
129        block_len2: u32,
130    ) -> IResult<&'a [u8], O, E>;
131}
132
133/// Create a block parser function, given the parameters (block object and endianness)
134pub(crate) fn ng_block_parser<'a, P, En, O, E>() -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], O, E>
135where
136    P: PcapNGBlockParser<'a, En, O>,
137    En: PcapEndianness,
138    O: 'a,
139    E: ParseError<&'a [u8]>,
140{
141    move |i: &[u8]| {
142        // read generic block layout
143        //
144        if i.len() < P::HDR_SZ {
145            return Err(Err::Incomplete(nom::Needed::new(P::HDR_SZ - i.len())));
146        }
147        let (i, block_type) = le_u32(i)?;
148        let (i, block_len1) = En::parse_u32(i)?;
149        if block_len1 < P::HDR_SZ as u32 {
150            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
151        }
152        if P::MAGIC != 0 && En::native_u32(block_type) != P::MAGIC {
153            return Err(Err::Error(E::from_error_kind(i, ErrorKind::Verify)));
154        }
155        // 12 is block_type (4) + block_len1 (4) + block_len2 (4)
156        let (i, block_content) = take(block_len1 - 12)(i)?;
157        let (i, block_len2) = En::parse_u32(i)?;
158        // call block content parsing function
159        let (_, b) = P::inner_parse(block_type, block_len1, block_content, block_len2)?;
160        // return the remaining bytes from the container, not content
161        Ok((i, b))
162    }
163}