rusty_pcap/pcap_ng/
mod.rs

1//! This module provides pcap-ng parsing functionality
2//!
3//! [Source](https://www.ietf.org/archive/id/draft-tuexen-opsawg-pcapng-03.html)
4//!
5//! Currently, only supports reading files from beginning to end and does not support reverse reading.
6use thiserror::Error;
7
8use crate::{byte_order::Endianness, link_type::InvalidLinkType};
9pub mod blocks;
10pub mod options;
11pub mod sync;
12/// Magic number for pcap-ng files
13///
14/// All pcap-ng files should start with this magic number
15pub const PCAP_NG_MAGIC: [u8; 4] = [0x0A, 0x0D, 0x0D, 0x0A];
16#[derive(Debug, Error)]
17pub enum PcapNgParseError {
18    #[error("Invalid block ID: expected {expected_be:?} or {expected_le:?}, got {got:?}")]
19    UnexpectedBlockId {
20        expected_be: [u8; 4],
21        expected_le: [u8; 4],
22        got: [u8; 4],
23    },
24    #[error("Invalid endianness: got {got:?}")]
25    InvalidEndianness { got: [u8; 4] },
26    /// This should never happen. But preventing panics
27    #[error(transparent)]
28    TryFromSliceError(#[from] std::array::TryFromSliceError),
29    #[error(transparent)]
30    IO(#[from] std::io::Error),
31    #[error("Minimum size for this block is {0} bytes, but got {1} bytes")]
32    MinimumSizeNotMet(usize, usize),
33    #[error(transparent)]
34    UnexpectedSize(#[from] crate::byte_order::UnexpectedSize),
35    #[error("Error parsing options: {0}")]
36    OptionParseError(#[from] options::OptionParseError),
37    #[error(transparent)]
38    InvalidLinkType(#[from] InvalidLinkType),
39    #[error(transparent)]
40    UndeterminedByteOrder(#[from] crate::byte_order::UndertminedByteOrder),
41}
42
43impl Endianness {
44    pub fn from_pcap_ng_bytes(bytes: &[u8; 4]) -> Result<Self, PcapNgParseError> {
45        match bytes {
46            [0x1A, 0x2B, 0x3C, 0x4D] => Ok(Self::BigEndian),
47            [0x4D, 0x3C, 0x2B, 0x1A] => Ok(Self::LittleEndian),
48            _ => Err(PcapNgParseError::InvalidEndianness { got: *bytes }),
49        }
50    }
51}
52
53/// Pads the length to the next multiple of 32 bytes
54pub(crate) fn pad_length_to_32_bytes(length: usize) -> usize {
55    if length.is_multiple_of(4) {
56        length
57    } else {
58        length + (4 - (length % 4))
59    }
60}
61
62#[cfg(test)]
63mod tests {
64    use super::*;
65    #[test]
66    fn test_pad_length_to_32_bytes() {
67        assert_eq!(pad_length_to_32_bytes(0), 0);
68        assert_eq!(pad_length_to_32_bytes(1), 4);
69        assert_eq!(pad_length_to_32_bytes(3), 4);
70        assert_eq!(pad_length_to_32_bytes(4), 4);
71        assert_eq!(pad_length_to_32_bytes(5), 8);
72        assert_eq!(pad_length_to_32_bytes(7), 8);
73        assert_eq!(pad_length_to_32_bytes(8), 8);
74        assert_eq!(pad_length_to_32_bytes(9), 12);
75    }
76}