net_parser_rs/
global_header.rs

1use crate::Error;
2use nom::*;
3
4const MAGIC_NUMBER: u32 = 0xA1B2C3D4u32;
5#[cfg(target_endian = "little")]
6pub const NATIVE_ENDIAN: Endianness = Endianness::Little;
7#[cfg(target_endian = "big")]
8pub const NATIVE_ENDIAN: Endianness = Endianness::Big;
9
10///
11/// Global header associated with libpcap capture files
12///
13#[allow(unused)]
14#[derive(Clone, Copy, Debug)]
15pub struct GlobalHeader {
16    pub endianness: Endianness,
17    pub version_major: u16,
18    pub version_minor: u16,
19    pub zone: i32,
20    pub sig_figs: i32,
21    pub snap_length: u32,
22    pub network: u32,
23}
24
25impl Default for GlobalHeader {
26    fn default() -> Self {
27        Self {
28            endianness: NATIVE_ENDIAN,
29            version_major: 2,
30            version_minor: 4,
31            zone: 0,
32            sig_figs: 0,
33            snap_length: 1500,
34            network: 1,
35        }
36    }
37}
38
39impl GlobalHeader {
40    pub fn parse<'a>(input: &'a [u8]) -> Result<(&'a [u8], GlobalHeader), Error> {
41        do_parse!(
42            input,
43            endianness: map!(u32!(NATIVE_ENDIAN), |e| {
44                let res = if e == MAGIC_NUMBER {
45                    NATIVE_ENDIAN
46                } else if NATIVE_ENDIAN == Endianness::Little {
47                    Endianness::Big
48                } else {
49                    Endianness::Little
50                };
51                #[cfg(feature = "log-errors")]
52                debug!("Using endianness {:?} read {:02x} compared to magic number {:02x}, setting endianness to {:?}", NATIVE_ENDIAN, e, MAGIC_NUMBER, res);
53                res
54            }) >> version_major: u16!(endianness)
55                >> version_minor: u16!(endianness)
56                >> zone: i32!(endianness)
57                >> sig_figs: i32!(endianness)
58                >> snap_length: u32!(endianness)
59                >> network: u32!(endianness)
60                >> (GlobalHeader {
61                    endianness: endianness,
62                    version_major: version_major,
63                    version_minor: version_minor,
64                    zone: zone,
65                    sig_figs: sig_figs,
66                    snap_length: snap_length,
67                    network: network
68                })
69        ).map_err(Error::from)
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[cfg(target_endian = "little")]
78    const RAW_DATA: &'static [u8] = &[
79        0xD4u8, 0xC3u8, 0xB2u8, 0xA1u8, //magic number
80        0x04u8, 0x00u8, //version major, 4
81        0x02u8, 0x00u8, //version minor, 2
82        0x00u8, 0x00u8, 0x00u8, 0x00u8, //zone, 0
83        0x04u8, 0x00u8, 0x00u8, 0x00u8, //sig figs, 4
84        0x13u8, 0x06u8, 0x00u8, 0x00u8, //snap length, 1555
85        0x02u8, 0x00u8, 0x00u8, 0x00u8, //network, 2
86    ];
87    #[cfg(target_endian = "little")]
88    const RAW_DATA_REVERSED: &'static [u8] = &[
89        0x1Au8, 0x2Bu8, 0x3Cu8, 0x4Du8, //magic number
90        0x00u8, 0x04u8, //version major, 4
91        0x00u8, 0x02u8, //version minor, 2
92        0x00u8, 0x00u8, 0x00u8, 0x00u8, //zone, 0
93        0x00u8, 0x00u8, 0x00u8, 0x04u8, //sig figs, 4
94        0x00u8, 0x00u8, 0x06u8, 0x13u8, //snap length, 1555
95        0x00u8, 0x00u8, 0x00u8, 0x02u8, //network, 2
96    ];
97    #[cfg(target_endian = "big")]
98    const RAW_DATA: &'static [u8] = &[
99        0x1Au8, 0x2Bu8, 0x3Cu8, 0x4Du8, //magic number
100        0x00u8, 0x04u8, //version major, 4
101        0x00u8, 0x02u8, //version minor, 2
102        0x00u8, 0x00u8, 0x00u8, 0x00u8, //zone, 0
103        0x00u8, 0x00u8, 0x00u8, 0x04u8, //sig figs, 4
104        0x00u8, 0x00u8, 0x06u8, 0x13u8, //snap length, 1555
105        0x00u8, 0x00u8, 0x00u8, 0x02u8, //network, 2
106    ];
107    #[cfg(target_endian = "big")]
108    const RAW_DATA_REVERSED: &'static [u8] = &[
109        0xD4u8, 0xC3u8, 0xB2u8, 0xA1u8, //magic number
110        0x04u8, 0x00u8, //version major, 4
111        0x02u8, 0x00u8, //version minor, 2
112        0x00u8, 0x00u8, 0x00u8, 0x00u8, //zone, 0
113        0x04u8, 0x00u8, 0x00u8, 0x00u8, //sig figs, 4
114        0x13u8, 0x06u8, 0x00u8, 0x00u8, //snap length, 1555
115        0x02u8, 0x00u8, 0x00u8, 0x00u8, //network, 2
116    ];
117
118    #[test]
119    fn global_header_native_endian() {
120        let _ = env_logger::try_init();
121
122        let (rem, gh) = GlobalHeader::parse(RAW_DATA).expect("Failed to parse header");
123
124        assert!(rem.is_empty());
125        assert_eq!(gh.version_major, 4);
126        assert_eq!(gh.version_minor, 2);
127        assert_eq!(gh.endianness, NATIVE_ENDIAN);
128        assert_eq!(gh.snap_length, 1555);
129    }
130
131    #[test]
132    fn global_header_not_native_endian() {
133        let (rem, gh) = GlobalHeader::parse(RAW_DATA_REVERSED).expect("Failed to parse header");
134
135        let expected_endianness = match NATIVE_ENDIAN {
136            Endianness::Little => Endianness::Big,
137            Endianness::Big => Endianness::Little,
138        };
139
140        assert!(rem.is_empty());
141        assert_eq!(gh.version_major, 4);
142        assert_eq!(gh.version_minor, 2);
143        assert_eq!(gh.endianness, expected_endianness);
144        assert_eq!(gh.snap_length, 1555);
145    }
146}