net_parser_rs/
record.rs

1use crate::Error;
2use log::*;
3use nom::*;
4
5///
6/// Collection of pcap records associated with a libpcap capture
7#[derive(Clone, Debug)]
8pub struct PcapRecords<'a> {
9    inner: Vec<PcapRecord<'a>>,
10}
11
12impl<'a> PcapRecords<'a> {
13    pub fn len(&self) -> usize { self.inner.len() }
14
15    pub fn into_inner(self) -> Vec<PcapRecord<'a>> { self.inner }
16    ///
17    /// Parse a slice of bytes that correspond to a set of records, without libcap file format
18    /// header (https://wiki.wireshark.org/Development/LibpcapFileFormat). Endianness of the byte
19    /// slice must be known.
20    ///
21    pub fn parse<'b>(
22        input: &'b [u8],
23        endianness: Endianness,
24    ) -> Result<(&'b [u8], PcapRecords<'b>), Error> {
25        let mut records: std::vec::Vec<PcapRecord> = vec![];
26        let mut current = input;
27
28        trace!("{} bytes left for record parsing", current.len());
29
30        loop {
31            match PcapRecord::parse(current, endianness) {
32                Ok((rem, r)) => {
33                    current = rem;
34                    trace!("{} bytes left for record parsing", current.len());
35                    records.push(r);
36                }
37                Err(Error::Incomplete { size: opt_size }) => {
38                    match opt_size {
39                        None => debug!(
40                            "Needed unknown number of bytes for parsing, only had {}",
41                            current.len()
42                        ),
43                        Some(s) => debug!("Needed {} bytes for parsing, only had {:?}", s, current.len()),
44                    }
45                    break;
46                }
47                Err(e) => return Err(e),
48            }
49        }
50
51        Ok((current, PcapRecords {
52            inner: records
53        }))
54    }
55}
56///
57/// Pcap record associated with a libpcap capture
58///
59#[derive(Clone, Copy, Debug)]
60pub struct PcapRecord<'a> {
61    pub timestamp: std::time::SystemTime,
62    pub actual_length: u32,
63    pub original_length: u32,
64    pub payload: &'a [u8],
65}
66
67impl<'a> Default for PcapRecord<'a> {
68    fn default() -> Self {
69        PcapRecord {
70            timestamp: std::time::SystemTime::UNIX_EPOCH,
71            actual_length: 0,
72            original_length: 0,
73            payload: &[0u8; 0],
74        }
75    }
76}
77
78impl<'a> PcapRecord<'a> {
79    ///
80    /// Convert a packet time (seconds and partial second microseconds) to a system time (offset from epoch)
81    ///
82    pub fn convert_packet_time(ts_seconds: u32, ts_microseconds: u32) -> std::time::SystemTime {
83        let offset = std::time::Duration::from_secs(ts_seconds as u64)
84            + std::time::Duration::from_micros(ts_microseconds as u64);
85        std::time::UNIX_EPOCH + offset
86    }
87
88    pub fn new(
89        timestamp: std::time::SystemTime,
90        actual_length: u32,
91        original_length: u32,
92        payload: &'a [u8],
93    ) -> PcapRecord<'a> {
94        PcapRecord {
95            timestamp: timestamp,
96            actual_length: actual_length,
97            original_length: original_length,
98            payload: payload,
99        }
100    }
101
102    pub fn parse<'b>(
103        input: &'b [u8],
104        endianness: nom::Endianness,
105    ) -> Result<(&'b [u8], PcapRecord<'b>), Error> {
106        do_parse!(
107            input,
108            ts_seconds: u32!(endianness)
109                >> ts_microseconds: u32!(endianness)
110                >> actual_length: u32!(endianness)
111                >> original_length: u32!(endianness)
112                >> payload: take!(actual_length)
113                >> (PcapRecord {
114                    timestamp: PcapRecord::convert_packet_time(ts_seconds, ts_microseconds),
115                    actual_length: actual_length,
116                    original_length: original_length,
117                    payload: payload
118                })
119        ).map_err(Error::from)
120    }
121}
122
123impl<'a> std::fmt::Display for PcapRecord<'a> {
124    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
125        self.timestamp
126            .duration_since(std::time::UNIX_EPOCH)
127            .map_err(|_e| std::fmt::Error)
128            .and_then(|d| {
129                write!(
130                    f,
131                    "Timestamp={}{}   Length={}   Original Length={}",
132                    d.as_secs(),
133                    d.subsec_millis(),
134                    self.actual_length,
135                    self.original_length
136                )
137            })
138    }
139}
140
141#[cfg(test)]
142mod tests {
143    use super::*;
144
145    use crate::flow::FlowExtraction;
146
147    const RAW_DATA: &'static [u8] = &[
148        0x5Bu8, 0x11u8, 0x6Du8, 0xE3u8, //seconds, 1527868899
149        0x00u8, 0x02u8, 0x51u8, 0xF5u8, //microseconds, 152053
150        0x00u8, 0x00u8, 0x00u8,
151        0x56u8, //actual length, 86: 14 (ethernet) + 20 (ipv4 header) + 20 (tcp header) + 32 (tcp payload)
152        0x00u8, 0x00u8, 0x04u8, 0xD0u8, //original length, 1232
153        //ethernet
154        0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, //dst mac 01:02:03:04:05:06
155        0xFFu8, 0xFEu8, 0xFDu8, 0xFCu8, 0xFBu8, 0xFAu8, //src mac FF:FE:FD:FC:FB:FA
156        0x08u8, 0x00u8, //ipv4
157        //ipv4
158        0x45u8, //version and header length
159        0x00u8, //tos
160        0x00u8, 0x48u8, //length, 20 bytes for header, 52 bytes for ethernet
161        0x00u8, 0x00u8, //id
162        0x00u8, 0x00u8, //flags
163        0x64u8, //ttl
164        0x06u8, //protocol, tcp
165        0x00u8, 0x00u8, //checksum
166        0x01u8, 0x02u8, 0x03u8, 0x04u8, //src ip 1.2.3.4
167        0x0Au8, 0x0Bu8, 0x0Cu8, 0x0Du8, //dst ip 10.11.12.13
168        //tcp
169        0xC6u8, 0xB7u8, //src port, 50871
170        0x00u8, 0x50u8, //dst port, 80
171        0x00u8, 0x00u8, 0x00u8, 0x01u8, //sequence number, 1
172        0x00u8, 0x00u8, 0x00u8, 0x02u8, //acknowledgement number, 2
173        0x50u8, 0x00u8, //header and flags, 0
174        0x00u8, 0x00u8, //window
175        0x00u8, 0x00u8, //check
176        0x00u8, 0x00u8, //urgent
177        //no options
178        //payload
179        0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
180        0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8,
181        0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0xfcu8, 0xfdu8, 0xfeu8,
182        0xffu8, //payload, 8 words
183    ];
184
185    #[test]
186    fn display_record() {
187        let _ = env_logger::try_init();
188
189        let record = PcapRecord::parse(RAW_DATA, nom::Endianness::Big)
190            .expect("Could not parse")
191            .1;
192
193        assert_eq!(
194            format!("{}", record),
195            "Timestamp=1527868899152   Length=86   Original Length=1232"
196        );
197    }
198
199    #[test]
200    fn convert_timestamp() {
201        let _ = env_logger::try_init();
202
203        let ts = PcapRecord::convert_packet_time(1527868899, 152053);
204
205        let offset =
206            std::time::Duration::from_secs(1527868899) + std::time::Duration::from_micros(152053);
207        assert_eq!(ts, std::time::UNIX_EPOCH + offset);
208    }
209
210    #[test]
211    fn parse_record() {
212        let _ = env_logger::try_init();
213
214        let (rem, record) =
215            PcapRecord::parse(RAW_DATA, nom::Endianness::Big).expect("Could not parse");
216
217        assert!(rem.is_empty());
218
219        let offset =
220            std::time::Duration::from_secs(1527868899) + std::time::Duration::from_micros(152053);
221        assert_eq!(record.timestamp, std::time::UNIX_EPOCH + offset);
222        assert_eq!(record.actual_length, 86);
223        assert_eq!(record.original_length, 1232);
224    }
225
226    #[test]
227    fn convert_record() {
228        let _ = env_logger::try_init();
229
230        let (rem, record) =
231            PcapRecord::parse(RAW_DATA, nom::Endianness::Big).expect("Could not parse");
232
233        assert!(rem.is_empty());
234
235        let flow = record.extract_flow().expect("Could not extract stream");
236        assert_eq!(flow.source.port, 50871);
237        assert_eq!(flow.destination.port, 80);
238    }
239}