1use crate::Error;
2use log::*;
3use nom::*;
4
5#[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 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#[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 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, 0x00u8, 0x02u8, 0x51u8, 0xF5u8, 0x00u8, 0x00u8, 0x00u8,
151 0x56u8, 0x00u8, 0x00u8, 0x04u8, 0xD0u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x05u8, 0x06u8, 0xFFu8, 0xFEu8, 0xFDu8, 0xFCu8, 0xFBu8, 0xFAu8, 0x08u8, 0x00u8, 0x45u8, 0x00u8, 0x00u8, 0x48u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x64u8, 0x06u8, 0x00u8, 0x00u8, 0x01u8, 0x02u8, 0x03u8, 0x04u8, 0x0Au8, 0x0Bu8, 0x0Cu8, 0x0Du8, 0xC6u8, 0xB7u8, 0x00u8, 0x50u8, 0x00u8, 0x00u8, 0x00u8, 0x01u8, 0x00u8, 0x00u8, 0x00u8, 0x02u8, 0x50u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 0x00u8, 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, ];
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}