pcap_parser/pcap/
header.rs

1use nom::number::streaming::{be_i32, be_u16, be_u32, le_i32, le_u16, le_u32};
2use nom::IResult;
3
4use crate::linktype::Linktype;
5use crate::PcapError;
6
7/// PCAP global header
8#[derive(Clone, Debug)]
9pub struct PcapHeader {
10    /// File format and byte ordering. If equal to `0xa1b2c3d4` or `0xa1b23c4d` then the rest of
11    /// the file uses native byte ordering. If `0xd4c3b2a1` or `0x4d3cb2a1` (swapped), then all
12    /// following fields will have to be swapped too.
13    pub magic_number: u32,
14    /// Version major number (currently 2)
15    pub version_major: u16,
16    /// Version minor number (currently 4)
17    pub version_minor: u16,
18    /// The correction time in seconds between GMT (UTC) and the local timezone of the following packet header timestamps
19    pub thiszone: i32,
20    /// In theory, the accuracy of time stamps in the capture; in practice, all tools set it to 0
21    pub sigfigs: u32,
22    /// max len of captured packets, in octets
23    pub snaplen: u32,
24    /// Data link type
25    pub network: Linktype,
26}
27
28impl PcapHeader {
29    pub fn new() -> PcapHeader {
30        PcapHeader {
31            magic_number: 0xa1b2_c3d4, // native order
32            version_major: 2,
33            version_minor: 4,
34            thiszone: 0,
35            sigfigs: 0,
36            snaplen: 0,
37            network: Linktype(1), // default: LINKTYPE_ETHERNET
38        }
39    }
40
41    pub const fn size(&self) -> usize {
42        24
43    }
44
45    pub fn is_bigendian(&self) -> bool {
46        (self.magic_number & 0xFFFF) == 0xb2a1 // works for both nanosecond and microsecond resolution timestamps
47    }
48
49    pub fn is_modified_format(&self) -> bool {
50        self.magic_number == 0xa1b2_cd34
51    }
52
53    pub fn is_nanosecond_precision(&self) -> bool {
54        self.magic_number == 0xa1b2_3c4d || self.magic_number == 0x4d3c_b2a1
55    }
56}
57
58impl Default for PcapHeader {
59    fn default() -> Self {
60        PcapHeader::new()
61    }
62}
63
64/// Read the PCAP global header
65///
66/// The global header contains the PCAP description and options
67pub fn parse_pcap_header(i: &[u8]) -> IResult<&[u8], PcapHeader, PcapError<&[u8]>> {
68    let (i, magic_number) = le_u32(i)?;
69    match magic_number {
70        0xa1b2_c3d4 | 0xa1b2_3c4d | 0xa1b2_cd34 => {
71            let (i, version_major) = le_u16(i)?;
72            let (i, version_minor) = le_u16(i)?;
73            let (i, thiszone) = le_i32(i)?;
74            let (i, sigfigs) = le_u32(i)?;
75            let (i, snaplen) = le_u32(i)?;
76            let (i, network) = le_i32(i)?;
77            let header = PcapHeader {
78                magic_number,
79                version_major,
80                version_minor,
81                thiszone,
82                sigfigs,
83                snaplen,
84                network: Linktype(network),
85            };
86            Ok((i, header))
87        }
88        0xd4c3_b2a1 | 0x4d3c_b2a1 => {
89            let (i, version_major) = be_u16(i)?;
90            let (i, version_minor) = be_u16(i)?;
91            let (i, thiszone) = be_i32(i)?;
92            let (i, sigfigs) = be_u32(i)?;
93            let (i, snaplen) = be_u32(i)?;
94            let (i, network) = be_i32(i)?;
95            let header = PcapHeader {
96                magic_number,
97                version_major,
98                version_minor,
99                thiszone,
100                sigfigs,
101                snaplen,
102                network: Linktype(network),
103            };
104            Ok((i, header))
105        }
106        _ => Err(nom::Err::Error(PcapError::HeaderNotRecognized)),
107    }
108}