pcapture/
pcap.rs

1#[cfg(feature = "pcap")]
2use bincode::Decode;
3#[cfg(feature = "pcap")]
4use bincode::Encode;
5#[cfg(feature = "pcap")]
6use byteorder::BigEndian;
7#[cfg(feature = "pcap")]
8use byteorder::LittleEndian;
9#[cfg(feature = "pcap")]
10use byteorder::ReadBytesExt;
11#[cfg(feature = "pcap")]
12use byteorder::WriteBytesExt;
13#[cfg(feature = "pcap")]
14use serde::Deserialize;
15#[cfg(feature = "pcap")]
16use serde::Serialize;
17#[cfg(feature = "pcap")]
18use std::fs::File;
19#[cfg(feature = "pcap")]
20use std::io::Read;
21#[cfg(feature = "pcap")]
22use std::io::Write;
23#[cfg(feature = "pcap")]
24use std::time::SystemTime;
25#[cfg(feature = "pcap")]
26use std::time::UNIX_EPOCH;
27#[cfg(feature = "pcap")]
28use strum::IntoEnumIterator;
29#[cfg(feature = "pcap")]
30use strum_macros::EnumIter;
31#[cfg(feature = "pcap")]
32use strum_macros::EnumString;
33
34#[cfg(feature = "pcap")]
35use crate::PcapByteOrder;
36#[cfg(feature = "pcap")]
37use crate::error::PcaptureError;
38
39#[cfg(feature = "pcap")]
40#[repr(u32)]
41#[derive(Debug, Clone, Copy, EnumString, EnumIter, Serialize, Deserialize, Encode, Decode)]
42pub enum LinkType {
43    NULL = 0,
44    ETHERNET = 1,
45    AX25 = 3,
46    IEEE8025 = 6,
47    ARCNETBSD = 7,
48    SLIP = 8,
49    PPP = 9,
50    FDDI = 10,
51    PPPHDLC = 50,
52    PPPETHER = 51,
53    ATMRFC1483 = 100,
54    RAW = 101,
55    CHDLC = 104,
56    IEEE80211 = 105,
57    FRELAY = 107,
58    LOOP = 108,
59    LINUXSLL = 113,
60    LTALK = 114,
61    PFLOG = 117,
62    IEEE80211PRISM = 119,
63    IPOVERFC = 122,
64    SUNATM = 123,
65    IEEE80211RADIOTAP = 127,
66    ARCNETLINUX = 129,
67    APPLEIPOVERIEEE1394 = 138,
68    MTP2WITHPHDR = 139,
69    MTP2 = 140,
70    MTP3 = 141,
71    SCCP = 142,
72    DOCSIS = 143,
73    LINUXIRDA = 144,
74    IEEE80211AVS = 163,
75    BACNETMSTP = 165,
76    PPPPPPD = 166,
77    GPRSLLC = 169,
78    GPFT = 170,
79    GPFF = 171,
80    LINUXLAPD = 177,
81    MFR = 182,
82    BLUETOOTHHCIH4 = 187,
83    USBLINUX = 189,
84    PPI = 192,
85    IEEE802154WITHFCS = 195,
86    SITA = 196,
87    ERF = 197,
88    BLUETOOTHHCIH4WITHPHDR = 201,
89    AX25KISS = 202,
90    LAPD = 203,
91    PPPWITHDIR = 204,
92    CHDLCWITHDIR = 205,
93    FRELAYWITHDIR = 206,
94    LAPBWITHDIR = 207,
95    IPMBLINUX = 209,
96    IEEE802154NONASKPHY = 215,
97    USBLINUXMMAPPED = 220,
98    FC2 = 224,
99    FC2WITHFRAMEDELIMS = 225,
100    IPNET = 226,
101    CANSOCKETCAN = 227,
102    IPV4 = 228,
103    IPV6 = 229,
104    IEEE802154NOFCS = 230,
105    DBUS = 231,
106    DVBCI = 235,
107    MUX27010 = 236,
108    STANAG5066DPDU = 237,
109    NFLOG = 239,
110    NETANALYZER = 240,
111    NETANALYZERTRANSPARENT = 241,
112    IPOIB = 242,
113    MPEG2TS = 243,
114    NG40 = 244,
115    NFCLLCP = 245,
116    INFINIBAND = 247,
117    SCTP = 248,
118    USBPCAP = 249,
119    RTACSERIAL = 250,
120    BLUETOOTHLELL = 251,
121    WIRESHARKUPPERPDU = 252,
122    NETLINK = 253,
123    BLUETOOTHLINUXMONITOR = 254,
124    BLUETOOTHBREDRBB = 255,
125    BLUETOOTHLELLWITHPHDR = 256,
126    PROFIBUSDL = 257,
127    PKTAP = 258,
128    EPON = 259,
129    IPMIHPM2 = 260,
130    ZWAVER1R2 = 261,
131    ZWAVER3 = 262,
132    WATTSTOPPERDLM = 263,
133    ISO14443 = 264,
134    RDS = 265,
135    USBDARWIN = 266,
136    SDLC = 268,
137    LORATAP = 270,
138    VSOCK = 271,
139    NORDICBLE = 272,
140    DOCSIS31XRA31 = 273,
141    ETHERNETMPACKET = 274,
142    DISPLAYPORTAUX = 275,
143    LINUXSLL2 = 276,
144    OPENVIZSLA = 278,
145    EBHSCR = 279,
146    VPPDISPATCH = 280,
147    DSATAGBRCM = 281,
148    DSATAGBRCMPREPEND = 282,
149    IEEE802154TAP = 283,
150    DSATAGDSA = 284,
151    DSATAGEDSA = 285,
152    ELEE = 286,
153    WAVESERIAL = 287,
154    USB20 = 288,
155    ATSCALP = 289,
156}
157
158#[cfg(feature = "pcap")]
159impl LinkType {
160    pub fn to_u32(self) -> u32 {
161        self as u32
162    }
163    pub fn from_u32(value: u32) -> Option<Self> {
164        LinkType::iter().find(|&e| e.to_u32() == value)
165    }
166}
167
168// File Header
169// from https://www.ietf.org/archive/id/draft-gharris-opsawg-pcap-01.html#name-file-header
170//
171//                         1                   2                   3
172//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
173//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
174//  0 |                          Magic Number                         |
175//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
176//  4 |          Major Version        |         Minor Version         |
177//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
178//  8 |                           Reserved1                           |
179//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
180// 12 |                           Reserved2                           |
181//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
182// 16 |                            SnapLen                            |
183//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
184// 20 | FCS |f|0 0 0 0 0 0 0 0 0 0 0 0|         LinkType              |
185//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
186
187#[cfg(feature = "pcap")]
188#[repr(C)]
189#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
190pub struct FileHeader {
191    /// Magic Number (32 bits):
192    /// An unsigned magic number, whose value is either the hexadecimal number 0xA1B2C3D4 or the hexadecimal number 0xA1B23C4D.
193    /// If the value is 0xA1B2C3D4, time stamps in Packet Records (see Figure 2) are in seconds and microseconds;
194    /// if it is 0xA1B23C4D, time stamps in Packet Records are in seconds and nanoseconds.
195    pub magic_number: u32,
196    /// Major Version (16 bits):
197    /// An unsigned value, giving the number of the current major version of the format.
198    /// The value for the current version of the format is 2.
199    pub major_version: u16,
200    /// Minor Version (16 bits):
201    /// An unsigned value, giving the number of the current minor version of the format.
202    /// The value is for the current version of the format is 4.
203    pub minor_version: u16,
204    /// Reserved1 (32 bits):
205    /// Not used - SHOULD be filled with 0 by pcap file writers, and MUST be ignored by pcap file readers.
206    reserved1: u32,
207    /// Reserved2 (32 bits):
208    /// Not used - SHOULD be filled with 0 by pcap file writers, and MUST be ignored by pcap file readers.
209    reserved2: u32,
210    /// SnapLen (32 bits):
211    /// An unsigned value indicating the maximum number of octets captured from each packet.
212    /// The portion of each packet that exceeds this value will not be stored in the file.
213    pub snaplen: u32,
214    /// !!! Note: for wireshark, the Frame Cyclic Sequence (FCS) part is not used, and LinkType is 32 bits.
215    /// LinkType (16 bits):
216    /// A 16-bit unsigned value that defines the link layer type of packets in the file.
217    /// This field is defined in the Section 8.1 IANA registry.
218    pub linktype: LinkType,
219}
220
221#[cfg(feature = "pcap")]
222impl Default for FileHeader {
223    fn default() -> Self {
224        FileHeader {
225            // native order
226            magic_number: 0xa1b2c3d4,
227            major_version: 2,
228            minor_version: 4,
229            reserved1: 0,
230            reserved2: 0,
231            // init value, change when packet recv
232            snaplen: 0,
233            linktype: LinkType::ETHERNET,
234        }
235    }
236}
237
238#[cfg(feature = "pcap")]
239impl FileHeader {
240    pub fn write(&self, fs: &mut File, pbo: PcapByteOrder) -> Result<(), PcaptureError> {
241        match pbo {
242            PcapByteOrder::LittleEndian | PcapByteOrder::WiresharkDefault => {
243                fs.write_u32::<LittleEndian>(self.magic_number)?;
244                fs.write_u16::<LittleEndian>(self.major_version)?;
245                fs.write_u16::<LittleEndian>(self.minor_version)?;
246                fs.write_u32::<LittleEndian>(self.reserved1)?;
247                fs.write_u32::<LittleEndian>(self.reserved2)?;
248                fs.write_u32::<LittleEndian>(self.snaplen)?;
249                fs.write_u32::<LittleEndian>(self.linktype.to_u32())?;
250            }
251            PcapByteOrder::BigEndian => {
252                fs.write_u32::<BigEndian>(self.magic_number)?;
253                fs.write_u16::<BigEndian>(self.major_version)?;
254                fs.write_u16::<BigEndian>(self.minor_version)?;
255                fs.write_u32::<BigEndian>(self.reserved1)?;
256                fs.write_u32::<BigEndian>(self.reserved2)?;
257                fs.write_u32::<BigEndian>(self.snaplen)?;
258                fs.write_u32::<BigEndian>(self.linktype.to_u32())?;
259            }
260        }
261        Ok(())
262    }
263    pub fn read(fs: &mut File, pbo: PcapByteOrder) -> Result<FileHeader, PcaptureError> {
264        match pbo {
265            PcapByteOrder::LittleEndian | PcapByteOrder::WiresharkDefault => {
266                let magic_number = fs.read_u32::<LittleEndian>()?;
267                let major_version = fs.read_u16::<LittleEndian>()?;
268                let minor_version = fs.read_u16::<LittleEndian>()?;
269                let reserved1 = fs.read_u32::<LittleEndian>()?;
270                let reserved2 = fs.read_u32::<LittleEndian>()?;
271                let snaplen = fs.read_u32::<LittleEndian>()?;
272                let linktype_value = fs.read_u32::<LittleEndian>()?;
273                let linktype = match LinkType::from_u32(linktype_value) {
274                    Some(l) => l,
275                    None => {
276                        return Err(PcaptureError::UnknownLinkType {
277                            linktype: linktype_value,
278                        });
279                    }
280                };
281                Ok(FileHeader {
282                    magic_number,
283                    major_version,
284                    minor_version,
285                    reserved1,
286                    reserved2,
287                    snaplen,
288                    linktype,
289                })
290            }
291            PcapByteOrder::BigEndian => {
292                let magic_number = fs.read_u32::<BigEndian>()?;
293                let major_version = fs.read_u16::<BigEndian>()?;
294                let minor_version = fs.read_u16::<BigEndian>()?;
295                let reserved1 = fs.read_u32::<BigEndian>()?;
296                let reserved2 = fs.read_u32::<BigEndian>()?;
297                let snaplen = fs.read_u32::<BigEndian>()?;
298                let linktype_value = fs.read_u32::<BigEndian>()?;
299                let linktype = match LinkType::from_u32(linktype_value) {
300                    Some(l) => l,
301                    None => {
302                        return Err(PcaptureError::UnknownLinkType {
303                            linktype: linktype_value,
304                        });
305                    }
306                };
307                Ok(FileHeader {
308                    magic_number,
309                    major_version,
310                    minor_version,
311                    reserved1,
312                    reserved2,
313                    snaplen,
314                    linktype,
315                })
316            }
317        }
318    }
319}
320
321// Packet Record
322// from https://www.ietf.org/archive/id/draft-gharris-opsawg-pcap-01.html#name-packet-record
323//                         1                   2                   3
324//     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
325//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326//  0 |                      Timestamp (Seconds)                      |
327//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
328//  4 |            Timestamp (Microseconds or nanoseconds)            |
329//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
330//  8 |                    Captured Packet Length                     |
331//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
332// 12 |                    Original Packet Length                     |
333//    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
334// 16 /                                                               /
335//    /                          Packet Data                          /
336//    /                        variable length                        /
337//    /                                                               /
338//    +---------------------------------------------------------------+
339
340#[cfg(feature = "pcap")]
341#[repr(C)]
342#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
343pub struct PacketRecord {
344    /// Timestamp (Seconds) and Timestamp (Microseconds or nanoseconds):
345    /// Seconds and fraction of a seconds values of a timestamp.
346    pub ts_sec: u32,
347    pub ts_usec: u32,
348    /// Captured Packet Length (32 bits):
349    /// An unsigned value that indicates the number of octets captured from the packet
350    /// (i.e. the length of the Packet Data field).
351    pub captured_packet_length: u32,
352    /// Original Packet Length (32 bits):
353    /// An unsigned value that indicates the actual length of the packet when it was transmitted on the network.
354    /// It can be different from the Captured Packet Length if the packet has been truncated by the capture process.
355    pub original_packet_length: u32,
356    /// Packet Data:
357    /// The data coming from the network, including link-layer headers.
358    /// The actual length of this field is Captured Packet Length.
359    pub packet_data: Vec<u8>,
360}
361
362#[cfg(feature = "pcap")]
363impl PacketRecord {
364    pub fn new(packet_data: &[u8], snaplen: usize) -> Result<PacketRecord, PcaptureError> {
365        let packet_slice = if packet_data.len() > snaplen {
366            &packet_data[..snaplen]
367        } else {
368            packet_data
369        };
370        let dura = SystemTime::now().duration_since(UNIX_EPOCH)?;
371        // let (ts_sec, ts_usec) = if magic_number == 0xa1b2c3d4 {
372        //     let ts_sec = dura.as_secs() as u32;
373        //     let ts_usec = dura.subsec_micros();
374        //     (ts_sec, ts_usec)
375        // } else {
376        //     let ts_sec = dura.as_secs() as u32;
377        //     let ts_usec = dura.subsec_nanos();
378        //     (ts_sec, ts_usec)
379        // };
380        let ts_sec = dura.as_secs() as u32;
381        let ts_usec = dura.subsec_micros();
382        let captured_packet_length = packet_slice.len() as u32;
383        let original_packet_length = packet_data.len() as u32;
384        Ok(PacketRecord {
385            ts_sec,
386            ts_usec,
387            captured_packet_length,
388            original_packet_length,
389            packet_data: packet_data.to_vec(),
390        })
391    }
392    pub fn write(&self, fs: &mut File, pbo: PcapByteOrder) -> Result<(), PcaptureError> {
393        match pbo {
394            PcapByteOrder::LittleEndian | PcapByteOrder::WiresharkDefault => {
395                fs.write_u32::<LittleEndian>(self.ts_sec)?;
396                fs.write_u32::<LittleEndian>(self.ts_usec)?;
397                fs.write_u32::<LittleEndian>(self.captured_packet_length)?;
398                fs.write_u32::<LittleEndian>(self.original_packet_length)?;
399                fs.write_all(&self.packet_data)?;
400            }
401            PcapByteOrder::BigEndian => {
402                fs.write_u32::<BigEndian>(self.ts_sec)?;
403                fs.write_u32::<BigEndian>(self.ts_usec)?;
404                fs.write_u32::<BigEndian>(self.captured_packet_length)?;
405                fs.write_u32::<BigEndian>(self.original_packet_length)?;
406                fs.write_all(&self.packet_data)?;
407            }
408        }
409        Ok(())
410    }
411    pub fn read(fs: &mut File, pbo: PcapByteOrder) -> Result<PacketRecord, PcaptureError> {
412        let (ts_sec, ts_usec, captured_packet_length, original_packet_length) = match pbo {
413            PcapByteOrder::LittleEndian | PcapByteOrder::WiresharkDefault => {
414                let ts_sec = fs.read_u32::<LittleEndian>()?;
415                let ts_usec = fs.read_u32::<LittleEndian>()?;
416                let captured_packet_length = fs.read_u32::<LittleEndian>()?;
417                let original_packet_length = fs.read_u32::<LittleEndian>()?;
418                (
419                    ts_sec,
420                    ts_usec,
421                    captured_packet_length,
422                    original_packet_length,
423                )
424            }
425            PcapByteOrder::BigEndian => {
426                let ts_sec = fs.read_u32::<BigEndian>()?;
427                let ts_usec = fs.read_u32::<BigEndian>()?;
428                let captured_packet_length = fs.read_u32::<BigEndian>()?;
429                let original_packet_length = fs.read_u32::<BigEndian>()?;
430                (
431                    ts_sec,
432                    ts_usec,
433                    captured_packet_length,
434                    original_packet_length,
435                )
436            }
437        };
438        let mut data = vec![0u8; captured_packet_length as usize]; // read only capt_len length
439        fs.read_exact(&mut data)?;
440        Ok(PacketRecord {
441            ts_sec,
442            ts_usec,
443            captured_packet_length,
444            original_packet_length,
445            packet_data: data,
446        })
447    }
448}
449
450#[cfg(feature = "pcap")]
451#[repr(C)]
452#[derive(Debug, Clone, Serialize, Deserialize, Encode, Decode)]
453pub struct Pcap {
454    pub pbo: PcapByteOrder,
455    pub header: FileHeader,
456    pub records: Vec<PacketRecord>,
457}
458
459#[cfg(feature = "pcap")]
460impl Pcap {
461    pub fn new(pbo: PcapByteOrder) -> Pcap {
462        Pcap {
463            pbo,
464            header: FileHeader::default(),
465            records: Vec::new(),
466        }
467    }
468    pub fn append(&mut self, record: PacketRecord) {
469        if record.packet_data.len() as u32 > self.header.snaplen {
470            self.header.snaplen = record.packet_data.len() as u32;
471        }
472        self.records.push(record);
473    }
474    pub fn write(&self, fs: &mut File) -> Result<(), PcaptureError> {
475        self.header.write(fs, self.pbo)?;
476        for r in &self.records {
477            r.write(fs, self.pbo)?;
478        }
479        Ok(())
480    }
481    pub fn write_all(&self, path: &str) -> Result<(), PcaptureError> {
482        let mut fs = File::create(path)?;
483        Self::write(self, &mut fs)?;
484        Ok(())
485    }
486    pub fn read_all(path: &str, pbo: PcapByteOrder) -> Result<Pcap, PcaptureError> {
487        let mut fs = File::open(path)?;
488        let header = FileHeader::read(&mut fs, pbo)?;
489        let mut record = Vec::new();
490        loop {
491            match PacketRecord::read(&mut fs, pbo) {
492                Ok(r) => record.push(r),
493                Err(e) => match e {
494                    PcaptureError::IOError(_) => break, // file end
495                    _ => return Err(e),
496                },
497            }
498        }
499        Ok(Pcap {
500            pbo,
501            header,
502            records: record,
503        })
504    }
505}