pcap_file/pcap/
packet.rs

1use std::borrow::Cow;
2use std::io::Write;
3use std::time::Duration;
4
5use byteorder_slice::byteorder::WriteBytesExt;
6use byteorder_slice::result::ReadSlice;
7use byteorder_slice::ByteOrder;
8use derive_into_owned::IntoOwned;
9
10use crate::errors::*;
11use crate::TsResolution;
12
13/// Pcap packet.
14///
15/// The payload can be owned or borrowed.
16#[derive(Clone, Debug, IntoOwned)]
17pub struct PcapPacket<'a> {
18    /// Timestamp EPOCH of the packet with a nanosecond resolution
19    pub timestamp: Duration,
20    /// Original length of the packet when captured on the wire
21    pub orig_len: u32,
22    /// Payload, owned or borrowed, of the packet
23    pub data: Cow<'a, [u8]>,
24}
25
26impl<'a> PcapPacket<'a> {
27    /// Creates a new borrowed [`PcapPacket`] with the given parameters.
28    pub fn new(timestamp: Duration, orig_len: u32, data: &'a [u8]) -> PcapPacket<'a> {
29        PcapPacket { timestamp, orig_len, data: Cow::Borrowed(data) }
30    }
31
32    /// Creates a new owned [`PcapPacket`] with the given parameters.
33    pub fn new_owned(timestamp: Duration, orig_len: u32, data: Vec<u8>) -> PcapPacket<'static> {
34        PcapPacket { timestamp, orig_len, data: Cow::Owned(data) }
35    }
36
37    /// Parses a new borrowed [`PcapPacket`] from a slice.
38    pub fn from_slice<B: ByteOrder>(slice: &'a [u8], ts_resolution: TsResolution, snap_len: u32) -> PcapResult<(&'a [u8], PcapPacket<'a>)> {
39        let (rem, raw_packet) = RawPcapPacket::from_slice::<B>(slice)?;
40        let s = Self::try_from_raw_packet(raw_packet, ts_resolution, snap_len)?;
41
42        Ok((rem, s))
43    }
44
45    /// Writes a [`PcapPacket`] to a writer.
46    pub fn write_to<W: Write, B: ByteOrder>(&self, writer: &mut W, ts_resolution: TsResolution, snap_len: u32) -> PcapResult<usize> {
47        // Transforms PcapPacket::ts into ts_sec and ts_frac //
48        let ts_sec = self
49            .timestamp
50            .as_secs()
51            .try_into()
52            .map_err(|_| PcapError::InvalidField("PcapPacket: timestamp_secs > u32::MAX"))?;
53
54        let mut ts_frac = self.timestamp.subsec_nanos();
55        if ts_resolution == TsResolution::MicroSecond {
56            ts_frac /= 1000;
57        }
58
59        // Validate the packet length //
60        let incl_len = self.data.len().try_into().map_err(|_| PcapError::InvalidField("PcapPacket: incl_len > u32::MAX"))?;
61        let orig_len = self.orig_len;
62
63        if incl_len > snap_len {
64            return Err(PcapError::InvalidField("PcapPacket: incl_len > snap_len"));
65        }
66
67        if incl_len > orig_len {
68            return Err(PcapError::InvalidField("PcapPacket: incl_len > orig_len"));
69        }
70
71        let raw_packet = RawPcapPacket { ts_sec, ts_frac, incl_len, orig_len, data: Cow::Borrowed(&self.data[..]) };
72
73        raw_packet.write_to::<_, B>(writer)
74    }
75
76    /// Tries to create a [`PcapPacket`] from a [`RawPcapPacket`].
77    pub fn try_from_raw_packet(raw: RawPcapPacket<'a>, ts_resolution: TsResolution, snap_len: u32) -> PcapResult<Self> {
78        // Validate timestamps //
79        let ts_sec = raw.ts_sec;
80        let mut ts_nsec = raw.ts_frac;
81        if ts_resolution == TsResolution::MicroSecond {
82            ts_nsec = ts_nsec.checked_mul(1000).ok_or(PcapError::InvalidField("PacketHeader ts_nanosecond is invalid"))?;
83        }
84        if ts_nsec >= 1_000_000_000 {
85            return Err(PcapError::InvalidField("PacketHeader ts_nanosecond >= 1_000_000_000"));
86        }
87
88        // Validate lengths //
89        let incl_len = raw.incl_len;
90        let orig_len = raw.orig_len;
91
92        if incl_len > snap_len {
93            return Err(PcapError::InvalidField("PacketHeader incl_len > snap_len"));
94        }
95
96        if orig_len > snap_len {
97            return Err(PcapError::InvalidField("PacketHeader orig_len > snap_len"));
98        }
99
100        if incl_len > orig_len {
101            return Err(PcapError::InvalidField("PacketHeader incl_len > orig_len"));
102        }
103
104        Ok(PcapPacket { timestamp: Duration::new(ts_sec as u64, ts_nsec), orig_len, data: raw.data })
105    }
106}
107
108
109/// Raw Pcap packet with its header and data.
110/// The fields of the packet are not validated.
111/// The payload can be owned or borrowed.
112#[derive(Clone, Debug, IntoOwned)]
113pub struct RawPcapPacket<'a> {
114    /// Timestamp in seconds
115    pub ts_sec: u32,
116    /// Nanosecond or microsecond part of the timestamp
117    pub ts_frac: u32,
118    /// Number of octets of the packet saved in file
119    pub incl_len: u32,
120    /// Original length of the packet on the wire
121    pub orig_len: u32,
122    /// Payload, owned or borrowed, of the packet
123    pub data: Cow<'a, [u8]>,
124}
125
126impl<'a> RawPcapPacket<'a> {
127    /// Parses a new borrowed [`RawPcapPacket`] from a slice.
128    pub fn from_slice<B: ByteOrder>(mut slice: &'a [u8]) -> PcapResult<(&'a [u8], Self)> {
129        // Check header length
130        if slice.len() < 16 {
131            return Err(PcapError::IncompleteBuffer);
132        }
133
134        // Read packet header  //
135        // Can unwrap because the length check is done before
136        let ts_sec = slice.read_u32::<B>().unwrap();
137        let ts_frac = slice.read_u32::<B>().unwrap();
138        let incl_len = slice.read_u32::<B>().unwrap();
139        let orig_len = slice.read_u32::<B>().unwrap();
140
141        let pkt_len = incl_len as usize;
142        if slice.len() < pkt_len {
143            return Err(PcapError::IncompleteBuffer);
144        }
145
146        let packet = RawPcapPacket { ts_sec, ts_frac, incl_len, orig_len, data: Cow::Borrowed(&slice[..pkt_len]) };
147        let rem = &slice[pkt_len..];
148
149        Ok((rem, packet))
150    }
151
152    /// Writes a [`RawPcapPacket`] to a writer.
153    /// The fields of the packet are not validated.
154    pub fn write_to<W: Write, B: ByteOrder>(&self, writer: &mut W) -> PcapResult<usize> {
155        writer.write_u32::<B>(self.ts_sec).map_err(PcapError::IoError)?;
156        writer.write_u32::<B>(self.ts_frac).map_err(PcapError::IoError)?;
157        writer.write_u32::<B>(self.incl_len).map_err(PcapError::IoError)?;
158        writer.write_u32::<B>(self.orig_len).map_err(PcapError::IoError)?;
159        writer.write_all(&self.data).map_err(PcapError::IoError)?;
160
161        Ok(16 + self.data.len())
162    }
163
164    /// Tries to convert a [`RawPcapPacket`] into a [`PcapPacket`].
165    pub fn try_into_pcap_packet(self, ts_resolution: TsResolution, snap_len: u32) -> PcapResult<PcapPacket<'a>> {
166        PcapPacket::try_from_raw_packet(self, ts_resolution, snap_len)
167    }
168}