rusty_pcap/pcap/sync/
mod.rs

1//! Synchronous PCAP reader and writer
2use std::io::Read;
3pub mod writer;
4use crate::{
5    pcap::PcapParseError, pcap::file_header::PcapFileHeader, pcap::packet_header::PacketHeader,
6};
7#[derive(Debug)]
8pub struct SyncPcapReader<R: Read> {
9    reader: R,
10    /// Buffer for packet data
11    ///
12    /// Allocated to the snap length in the file header
13    buffer: Box<[u8]>,
14    header_buffer: [u8; 16],
15    file_header: PcapFileHeader,
16}
17impl<R: Read> SyncPcapReader<R> {
18    /// Creates a new `SyncPcapReader` from a reader
19    /// Returns `Ok(Self)` on success, or `Err` if there was an error
20    /// reading the file header
21    ///
22    /// A buffer is allocated based on the snap length in the file header
23    pub fn new(mut reader: R) -> Result<Self, PcapParseError> {
24        let file_header = PcapFileHeader::read(&mut reader)?;
25        let buffer = vec![0u8; file_header.snap_length as usize].into_boxed_slice();
26        Ok(Self {
27            reader,
28            buffer,
29            file_header,
30            header_buffer: [0; 16],
31        })
32    }
33    /// Returns the file header of the pcap file
34    pub fn file_header(&self) -> &PcapFileHeader {
35        &self.file_header
36    }
37    pub fn next_packet(&mut self) -> Result<Option<(PacketHeader, &[u8])>, PcapParseError> {
38        if let Err(err) = self.reader.read_exact(&mut self.header_buffer) {
39            if err.kind() == std::io::ErrorKind::UnexpectedEof {
40                return Ok(None); // No more packets
41            } else {
42                return Err(PcapParseError::IO(err));
43            }
44        }
45        let packet_header = PacketHeader::parse_bytes(
46            &self.header_buffer,
47            self.file_header.magic_number_and_endianness.endianness,
48            &self.file_header.version,
49        )?;
50        if packet_header.include_len > self.file_header.snap_length {
51            return Err(PcapParseError::InvalidPacketLength {
52                snap_length: self.file_header.snap_length,
53                incl_len: packet_header.include_len,
54            });
55        }
56        let mut_buffer: &mut [u8] = &mut self.buffer;
57        self.reader
58            .read_exact(&mut mut_buffer[0..(packet_header.include_len as usize)])?;
59
60        Ok(Some((
61            packet_header,
62            &self.buffer[..(packet_header.include_len as usize)],
63        )))
64    }
65}
66#[cfg(test)]
67mod tests {
68    use etherparse::{NetSlice, SlicedPacket};
69
70    use super::*;
71    #[test]
72    fn read_packets_from_file() {
73        let file = std::fs::File::open("test_data/test.pcap").expect("Failed to open test.pcap");
74        let mut reader = SyncPcapReader::new(file).expect("Failed to create SyncPcapReader");
75
76        while let Ok(Some((header, data))) = reader.next_packet() {
77            println!("Packet Header: {:?}", header);
78            let parse = SlicedPacket::from_ethernet(data).expect("Failed to parse packet");
79            let Some(net_slice) = parse.net else {
80                panic!("Expected a network layer slice, got: {:?}", parse);
81            };
82
83            match net_slice {
84                NetSlice::Ipv4(ipv4) => {
85                    println!("IPv4 Packet: {:?}", ipv4.header());
86                    println!("IPv4 Destin: {:?}", ipv4.header().destination_addr());
87                    println!("IPv4 Source: {:?}", ipv4.header().source_addr());
88                }
89                NetSlice::Ipv6(ipv6) => {
90                    println!("IPv6 Packet: {:?}", ipv6.header());
91                }
92                NetSlice::Arp(arp) => {
93                    println!("ARP Packet: {:?}", arp);
94                }
95            }
96        }
97    }
98}