pcap_file/pcap/
header.rs

1use std::io::Write;
2
3use byteorder_slice::byteorder::WriteBytesExt;
4use byteorder_slice::result::ReadSlice;
5use byteorder_slice::{BigEndian, ByteOrder, LittleEndian};
6
7use crate::errors::*;
8use crate::{DataLink, Endianness, TsResolution};
9
10
11/// Pcap Global Header
12#[derive(Copy, Clone, Debug, Eq, PartialEq)]
13pub struct PcapHeader {
14    /// Major version number
15    pub version_major: u16,
16
17    /// Minor version number
18    pub version_minor: u16,
19
20    /// GMT to local timezone correction, should always be 0
21    pub ts_correction: i32,
22
23    /// Timestamp accuracy, should always be 0
24    pub ts_accuracy: u32,
25
26    /// Max length of captured packet, typically 65535
27    pub snaplen: u32,
28
29    /// DataLink type (first layer in the packet)
30    pub datalink: DataLink,
31
32    /// Timestamp resolution of the pcap (microsecond or nanosecond)
33    pub ts_resolution: TsResolution,
34
35    /// Endianness of the pcap (excluding the packet data)
36    pub endianness: Endianness,
37}
38
39impl PcapHeader {
40    /// Creates a new [`PcapHeader`] from a slice of bytes.
41    ///
42    /// Returns an error if the reader doesn't contain a valid pcap
43    /// or if there is a reading error.
44    ///
45    /// [`PcapError::IncompleteBuffer`] indicates that there is not enough data in the buffer.
46    pub fn from_slice(mut slice: &[u8]) -> PcapResult<(&[u8], PcapHeader)> {
47        // Check that slice.len() > PcapHeader length
48        if slice.len() < 24 {
49            return Err(PcapError::IncompleteBuffer);
50        }
51
52        let magic_number = slice.read_u32::<BigEndian>().unwrap();
53
54        match magic_number {
55            0xA1B2C3D4 => return init_pcap_header::<BigEndian>(slice, TsResolution::MicroSecond, Endianness::Big),
56            0xA1B23C4D => return init_pcap_header::<BigEndian>(slice, TsResolution::NanoSecond, Endianness::Big),
57            0xD4C3B2A1 => return init_pcap_header::<LittleEndian>(slice, TsResolution::MicroSecond, Endianness::Little),
58            0x4D3CB2A1 => return init_pcap_header::<LittleEndian>(slice, TsResolution::NanoSecond, Endianness::Little),
59            _ => return Err(PcapError::InvalidField("PcapHeader: wrong magic number")),
60        };
61
62        // Inner function used for the initialisation of the PcapHeader.
63        // Must check the srcclength before calling it.
64        fn init_pcap_header<B: ByteOrder>(
65            mut src: &[u8],
66            ts_resolution: TsResolution,
67            endianness: Endianness,
68        ) -> PcapResult<(&[u8], PcapHeader)> {
69            let header = PcapHeader {
70                version_major: src.read_u16::<B>().unwrap(),
71                version_minor: src.read_u16::<B>().unwrap(),
72                ts_correction: src.read_i32::<B>().unwrap(),
73                ts_accuracy: src.read_u32::<B>().unwrap(),
74                snaplen: src.read_u32::<B>().unwrap(),
75                datalink: DataLink::from(src.read_u32::<B>().unwrap()),
76                ts_resolution,
77                endianness,
78            };
79
80            Ok((src, header))
81        }
82    }
83
84    /// Writes a [`PcapHeader`] to a writer.
85    ///
86    /// Uses the endianness of the header.
87    pub fn write_to<W: Write>(&self, writer: &mut W) -> PcapResult<usize> {
88        return match self.endianness {
89            Endianness::Big => write_header::<_, BigEndian>(self, writer),
90            Endianness::Little => write_header::<_, LittleEndian>(self, writer),
91        };
92
93        fn write_header<W: Write, B: ByteOrder>(header: &PcapHeader, writer: &mut W) -> PcapResult<usize> {
94            let magic_number = match header.ts_resolution {
95                TsResolution::MicroSecond => 0xA1B2C3D4,
96                TsResolution::NanoSecond => 0xA1B23C4D,
97            };
98
99            writer.write_u32::<B>(magic_number).map_err(PcapError::IoError)?;
100            writer.write_u16::<B>(header.version_major).map_err(PcapError::IoError)?;
101            writer.write_u16::<B>(header.version_minor).map_err(PcapError::IoError)?;
102            writer.write_i32::<B>(header.ts_correction).map_err(PcapError::IoError)?;
103            writer.write_u32::<B>(header.ts_accuracy).map_err(PcapError::IoError)?;
104            writer.write_u32::<B>(header.snaplen).map_err(PcapError::IoError)?;
105            writer.write_u32::<B>(header.datalink.into()).map_err(PcapError::IoError)?;
106
107            Ok(24)
108        }
109    }
110}
111
112/// Creates a new [`PcapHeader`] with these parameters:
113///
114/// ```rust,ignore
115/// PcapHeader {
116///     version_major: 2,
117///     version_minor: 4,
118///     ts_correction: 0,
119///     ts_accuracy: 0,
120///     snaplen: 65535,
121///     datalink: DataLink::ETHERNET,
122///     ts_resolution: TsResolution::MicroSecond,
123///     endianness: Endianness::Big
124/// };
125/// ```
126impl Default for PcapHeader {
127    fn default() -> Self {
128        PcapHeader {
129            version_major: 2,
130            version_minor: 4,
131            ts_correction: 0,
132            ts_accuracy: 0,
133            snaplen: 65535,
134            datalink: DataLink::ETHERNET,
135            ts_resolution: TsResolution::MicroSecond,
136            endianness: Endianness::Big,
137        }
138    }
139}