pcap_parser/
traits.rs

1use crate::blocks::PcapBlockOwned;
2use crate::error::PcapError;
3use crate::read_u32_e;
4use rusticata_macros::align32;
5
6/// Common methods for PcapNG blocks
7pub trait PcapNGBlock {
8    /// Returns true if block is encoded as big-endian
9    fn big_endian(&self) -> bool;
10    /// Raw block data (including header)
11    fn raw_data(&self) -> &[u8];
12    /// The type of this block
13    #[inline]
14    fn block_type(&self) -> u32 {
15        read_u32_e!(&self.raw_data(), self.big_endian())
16    }
17    /// The block length from the block header
18    #[inline]
19    fn block_length(&self) -> u32 {
20        read_u32_e!(&self.raw_data()[4..8], self.big_endian())
21    }
22    /// The block length from the block footer
23    #[inline]
24    fn block_length2(&self) -> u32 {
25        let data = self.raw_data();
26        let data_len = data.len();
27        read_u32_e!(&data[data_len - 4..], self.big_endian())
28    }
29    /// The length of inner data, if any
30    fn data_len(&self) -> usize;
31    /// The inner data, if any
32    fn data(&self) -> &[u8];
33    /// The Header length (without options)
34    fn header_len(&self) -> usize;
35    /// Raw packet header (without options)
36    #[inline]
37    fn raw_header(&self) -> &[u8] {
38        let len = self.header_len();
39        &self.raw_data()[..len]
40    }
41    /// Return the declared offset of options.
42    /// *Warning: the offset can be out of bounds, caller must test value before accessing data*
43    #[inline]
44    fn offset_options(&self) -> usize {
45        let len = self.data_len();
46        self.header_len() + align32!(len)
47    }
48    /// Network packet options.
49    /// Can be empty if packet does not contain options
50    #[inline]
51    fn raw_options(&self) -> &[u8] {
52        let offset = self.offset_options();
53        let data_len = self.data_len();
54        // if requested length is too big, truncate
55        if offset + 4 >= data_len {
56            return &[];
57        }
58        &self.raw_data()[offset..data_len - 4]
59    }
60}
61
62/// Common methods for PcapNG Packet blocks
63pub trait PcapNGPacketBlock {
64    /// Return true if block is encoded as big-endian
65    fn big_endian(&self) -> bool;
66    /// Return true if block data was truncated (typically when snaplen < origlen)
67    fn truncated(&self) -> bool {
68        false
69    }
70    /// Return the original length of the packet
71    fn orig_len(&self) -> u32;
72    /// Return the raw captured packet data, with padding if present, and eventually truncated.
73    fn raw_packet_data(&self) -> &[u8];
74    /// Return the captured packet data without padding
75    ///
76    /// If packet was truncated, the truncated data field is returned.
77    fn packet_data(&self) -> &[u8];
78}
79
80/// Streaming Iterator over pcap files
81///
82/// Implementors of this trait are usually based on a circular buffer, which means memory
83/// usage is constant, and that it can be used to parse huge files or infinite streams.
84/// However, this also means some care must be taken so no reference (for ex a pcap block) is
85/// kept on the buffer before changing the buffer content.
86///
87/// Each call to `next` will return the next block,
88/// and must be followed by call to `consume` to avoid reading the same data.
89/// `consume` takes care of shifting data in the buffer if required, but does not refill it.
90///
91/// It is possible to read multiple blocks before consuming data.
92/// Call `consume_noshift` instead of `consume`. To refill the buffer, first ensures that you do
93/// not keep any reference over internal data (blocks or slices), and call `refill`.
94///
95/// To determine when a refill is needed, either test `next()` for an incomplete read. You can also
96/// use `position` to implement a heuristic refill (for ex, when `position > capacity / 2`.
97///
98/// **The blocks already read, and underlying data, must be discarded before calling
99/// `consume` or `refill`.** It is the caller's responsibility to call functions in the correct
100/// order.
101pub trait PcapReaderIterator {
102    /// Get the next pcap block, if possible. Returns the number of bytes read and the block.
103    ///
104    /// The returned object is valid until `consume` or `refill` is called.
105    fn next(&mut self) -> Result<(usize, PcapBlockOwned<'_>), PcapError<&[u8]>>;
106    /// Consume data, and shift buffer if needed.
107    ///
108    /// If the position gets past the buffer's half, this will move the remaining data to the
109    /// beginning of the buffer.
110    ///
111    /// **The blocks already read, and underlying data, must be discarded before calling
112    /// this function.**
113    fn consume(&mut self, offset: usize);
114    /// Consume date, but do not change the buffer. Blocks already read are still valid.
115    fn consume_noshift(&mut self, offset: usize);
116    /// Get the number of consumed bytes
117    fn consumed(&self) -> usize;
118    /// Refill the internal buffer, shifting it if necessary.
119    ///
120    /// **The blocks already read, and underlying data, must be discarded before calling
121    /// this function.**
122    fn refill(&mut self) -> Result<(), PcapError<&[u8]>>;
123    /// Get the position in the internal buffer. Can be used to determine if `refill` is required.
124    fn position(&self) -> usize;
125    /// Grow size of the internal buffer.
126    fn grow(&mut self, new_size: usize) -> bool;
127    /// Returns a slice with all the available data
128    fn data(&self) -> &[u8];
129    /// Returns true if underlying reader is exhausted
130    ///
131    /// Note that exhausted reader only means that next `refill` will not
132    /// add any data, but there can still be data not consumed in the current buffer.
133    fn reader_exhausted(&self) -> bool;
134}
135
136/* ******************* */
137
138#[cfg(test)]
139pub mod tests {
140    use crate::pcap::parse_pcap_frame;
141    use crate::pcapng::{parse_block_le, Block, SecretsType};
142    use crate::traits::PcapNGPacketBlock;
143    use crate::utils::Data;
144    use hex_literal::hex;
145    // tls12-23.pcap frame 0
146    pub const FRAME_PCAP: &[u8] = &hex!(
147        "
14834 4E 5B 5A E1 96 08 00 4A 00 00 00 4A 00 00 00
14972 4D 4A D1 13 0D 4E 9C AE DE CB 73 08 00 45 00
15000 3C DF 08 40 00 40 06 47 9F 0A 09 00 01 0A 09
15100 02 D1 F4 11 51 34 1B 5B 17 00 00 00 00 A0 02
15272 10 14 43 00 00 02 04 05 B4 04 02 08 0A E4 DB
1536B 7B 00 00 00 00 01 03 03 07"
154    );
155    // OpenVPN_UDP_tls-auth.pcapng EPB (first data block, file block 3)
156    pub const FRAME_PCAPNG_EPB: &[u8] = &hex!(
157        "
15806 00 00 00 74 00 00 00 01 00 00 00 E9 D3 04 00
15948 EE 39 44 54 00 00 00 54 00 00 00 08 00 27 4A
160BE 45 08 00 27 BB 22 84 08 00 45 00 00 46 00 00
16140 00 40 11 48 89 C0 A8 38 67 C0 A8 38 66 81 AE
16204 AA 00 32 53 B4 38 81 38 14 62 1D 67 46 2D DE
16386 73 4D 2C BF F1 51 B2 B1 23 1B 61 E4 23 08 A2
16472 81 8E 00 00 00 01 50 FF 26 2C 00 00 00 00 00
16574 00 00 00"
166    );
167    // test009.pcapng EPB (first data block)
168    pub const FRAME_PCAPNG_EPB_WITH_OPTIONS: &[u8] = &hex!(
169        "
17006 00 00 00 F4 01 00 00 00 00 00 00 97 C3 04 00
171AA 47 CA 64 3A 01 00 00 3A 01 00 00 FF FF FF FF
172FF FF 00 0B 82 01 FC 42 08 00 45 00 01 2C A8 36
17300 00 FA 11 17 8B 00 00 00 00 FF FF FF FF 00 44
17400 43 01 18 59 1F 01 01 06 00 00 00 3D 1D 00 00
17500 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
17600 00 00 0B 82 01 FC 42 00 00 00 00 00 00 00 00
17700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
17800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
17900 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18100 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18200 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18300 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18400 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18500 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18600 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18700 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18800 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
18900 00 63 82 53 63 35 01 01 3D 07 01 00 0B 82 01
190FC 42 32 04 00 00 00 00 37 04 01 03 06 2A FF 00
19100 00 00 00 00 00 00 00 01 00 09 00 74 65 73 74
19230 30 39 2D 31 00 00 00 02 00 04 00 00 00 00 00
19304 00 08 00 00 00 00 00 00 00 00 00 AC 0B 0D 00
19461 20 66 61 6B 65 20 73 74 72 69 6E 67 00 00 00
195AD 0B 0F 00 73 6F 6D 65 20 66 61 6B 65 20 62 79
19674 65 73 00 AC 4B 0E 00 6D 79 20 66 61 6B 65 20
19773 74 72 69 6E 67 00 00 AD 4B 0D 00 6D 79 20 66
19861 6B 65 20 62 79 74 65 73 00 00 00 23 01 0C 00
19974 72 79 20 74 68 69 73 20 6F 6E 65 23 81 0C 00
20061 6E 64 20 74 68 69 73 20 6F 6E 65 00 00 00 00
201F4 01 00 00"
202    );
203    // block 3 from file dtls12-aes128ccm8-dsb.pcapng (wireshark repo)
204    pub const FRAME_PCAPNG_DSB: &[u8] = &hex!(
205        "
2060a 00 00 00 c4 00 00 00 4b 53 4c 54 b0 00 00 00
20743 4c 49 45 4e 54 5f 52 41 4e 44 4f 4d 20 35 38
20838 65 35 66 39 64 63 37 37 38 63 65 66 32 32 34
20930 35 66 34 32 66 39 62 65 61 32 35 39 32 38 62
21064 30 33 31 32 63 65 31 34 64 36 34 32 64 30 33
21134 64 32 34 66 34 66 61 62 36 37 32 66 63 20 37
21230 35 37 66 33 64 37 30 36 63 66 30 36 38 30 61
21334 30 65 34 66 32 65 30 37 34 37 63 65 37 38 63
21465 39 38 64 61 32 36 32 32 65 62 39 61 39 35 34
21533 66 37 66 31 35 34 36 33 37 34 34 31 35 37 32
21635 36 61 37 39 36 64 62 35 30 62 62 65 36 35 63
21764 62 64 63 32 39 32 61 30 39 33 33 35 62 34 0a
218c4 00 00 00"
219    );
220    // SHB of test/captures/http-brotli.pcapng from wireshark repo
221    pub const FRAME_PCAPNG_SHB: &[u8] = &hex!(
222        "
2230a 0d 0d 0a c4 00 00 00 4d 3c 2b 1a 01 00 00 00
224ff ff ff ff ff ff ff ff 02 00 37 00 49 6e 74 65
2256c 28 52 29 20 43 6f 72 65 28 54 4d 29 20 69 37
2262d 36 37 30 30 48 51 20 43 50 55 20 40 20 32 2e
22736 30 47 48 7a 20 28 77 69 74 68 20 53 53 45 34
2282e 32 29 00 03 00 2a 00 4c 69 6e 75 78 20 34 2e
22932 30 2e 31 32 2d 67 65 6e 74 6f 6f 2d 61 6e 64
23072 6f 6d 65 64 61 2d 32 30 31 39 30 33 30 35 2d
23176 31 00 00 04 00 33 00 44 75 6d 70 63 61 70 20
23228 57 69 72 65 73 68 61 72 6b 29 20 33 2e 31 2e
23330 20 28 76 33 2e 31 2e 30 72 63 30 2d 34 36 38
2342d 67 65 33 65 34 32 32 32 62 29 00 00 00 00 00
235c4 00 00 00"
236    );
237
238    #[test]
239    fn test_data() {
240        let d = Data::Borrowed(&[0, 1, 2, 3]);
241        assert_eq!(d.as_ref()[1], 1);
242        assert_eq!(d[1], 1);
243        assert_eq!(&d[1..=2], &[1, 2]);
244    }
245    #[test]
246    fn test_pcap_packet_functions() {
247        let (_, pkt) = parse_pcap_frame(FRAME_PCAP).expect("packet creation failed");
248        assert_eq!(pkt.origlen, 74);
249        assert_eq!(pkt.ts_usec, 562_913);
250        assert_eq!(pkt.ts_sec, 1_515_933_236);
251    }
252    #[test]
253    fn test_pcapng_packet_functions() {
254        let (rem, pkt) = parse_block_le(FRAME_PCAPNG_EPB).expect("packet creation failed");
255        assert!(rem.is_empty());
256        if let Block::EnhancedPacket(epb) = pkt {
257            assert_eq!(epb.if_id, 1);
258            assert_eq!(epb.origlen, 84);
259            assert_eq!(epb.data.len(), 84);
260            assert!(epb.options.is_empty());
261        }
262    }
263    #[test]
264    fn test_pcapng_packet_epb_with_options() {
265        let (rem, pkt) =
266            parse_block_le(FRAME_PCAPNG_EPB_WITH_OPTIONS).expect("packet creation failed");
267        assert!(rem.is_empty());
268        if let Block::EnhancedPacket(epb) = pkt {
269            assert_eq!(epb.if_id, 0);
270            assert_eq!(epb.origlen, 314);
271            assert_eq!(epb.data.len(), 316); // with padding
272            assert_eq!(epb.packet_data().len(), 314); // without padding
273        }
274    }
275    #[test]
276    fn test_parse_enhancepacketblock() {
277        let (rem, pkt) =
278            parse_block_le(FRAME_PCAPNG_EPB_WITH_OPTIONS).expect("packet parsing failed");
279        assert!(rem.is_empty());
280        if let Block::EnhancedPacket(epb) = pkt {
281            assert_eq!(epb.if_id, 0);
282            assert_eq!(epb.origlen, 314);
283            assert_eq!(epb.data.len(), 316); // with padding
284            assert_eq!(epb.packet_data().len(), 314); // without padding
285            println!("options: {:?}", epb.options);
286        // use nom::HexDisplay;
287        // println!("raw_options:\n{}", pkt.raw_options().to_hex(16));
288        } else {
289            panic!("wrong packet type");
290        }
291    }
292
293    #[test]
294    fn test_pcapng_decryptionsecretsblock() {
295        let (rem, block) = parse_block_le(FRAME_PCAPNG_DSB).expect("could not parse DSB");
296        assert!(rem.is_empty());
297        if let Block::DecryptionSecrets(dsb) = block {
298            assert_eq!(dsb.secrets_type, SecretsType::TlsKeyLog);
299            assert!(std::str::from_utf8(dsb.data).is_ok());
300        } else {
301            unreachable!();
302        }
303    }
304}