pub struct PcapNGReader<R>
where R: Read,
{ /* private fields */ }
Expand description

Parsing iterator over pcap-ng data (streaming version)

§Pcap-NG Reader

This reader is a streaming parser based on a circular buffer, which means memory usage is constant, and that it can be used to parse huge files or infinite streams. It creates an abstraction over any input providing the Read trait, and takes care of managing the circular buffer to provide an iterator-like interface.

The first call to next should return the a Section Header Block (SHB), marking the start of a new section. For each section, calls to next will return blocks, some of them containing data (SPB, EPB), and others containing information (IDB, NRB, etc.).

Some information must be stored (for ex. the data link type from the IDB) to be able to parse following block contents. Usually, a list of interfaces must be stored, with the data link type and capture length, for each section. These values are used when parsing Enhanced Packet Blocks (which gives an interface ID - the index, starting from 0) and Simple Packet Blocks (which assume an interface index of 0).

The size of the circular buffer has to be big enough for at least one complete block. Using a larger value (at least 65k) is advised to avoid frequent reads and buffer shifts.

There are precautions to take when reading multiple blocks before consuming data. See PcapReaderIterator for details.

§Example

use pcap_parser::*;
use pcap_parser::traits::PcapReaderIterator;
use std::fs::File;

let file = File::open(path).unwrap();
let mut num_blocks = 0;
let mut reader = PcapNGReader::new(65536, file).expect("PcapNGReader");
let mut if_linktypes = Vec::new();
let mut last_incomplete_index = 0;
loop {
    match reader.next() {
        Ok((offset, block)) => {
            println!("got new block");
            num_blocks += 1;
            match block {
            PcapBlockOwned::NG(Block::SectionHeader(ref _shb)) => {
                // starting a new section, clear known interfaces
                if_linktypes = Vec::new();
            },
            PcapBlockOwned::NG(Block::InterfaceDescription(ref idb)) => {
                if_linktypes.push(idb.linktype);
            },
            PcapBlockOwned::NG(Block::EnhancedPacket(ref epb)) => {
                assert!((epb.if_id as usize) < if_linktypes.len());
                let linktype = if_linktypes[epb.if_id as usize];
                #[cfg(feature="data")]
                let res = pcap_parser::data::get_packetdata(epb.data, linktype, epb.caplen as usize);
            },
            PcapBlockOwned::NG(Block::SimplePacket(ref spb)) => {
                assert!(if_linktypes.len() > 0);
                let linktype = if_linktypes[0];
                let blen = (spb.block_len1 - 16) as usize;
                #[cfg(feature="data")]
                let res = pcap_parser::data::get_packetdata(spb.data, linktype, blen);
            },
            PcapBlockOwned::NG(_) => {
                // can be statistics (ISB), name resolution (NRB), etc.
                eprintln!("unsupported block");
            },
            PcapBlockOwned::Legacy(_)
            | PcapBlockOwned::LegacyHeader(_) => unreachable!(),
            }
            reader.consume(offset);
        },
        Err(PcapError::Eof) => break,
        Err(PcapError::Incomplete(_)) => {
            if last_incomplete_index == num_blocks {
                eprintln!("Could not read complete data block.");
                eprintln!("Hint: the reader buffer size may be too small, or the input file nay be truncated.");
                break;
            }
            last_incomplete_index = num_blocks;
            reader.refill().expect("Could not refill reader");
            continue;
        },
        Err(e) => panic!("error while reading: {:?}", e),
    }
}
println!("num_blocks: {}", num_blocks);

Implementations§

source§

impl<R> PcapNGReader<R>
where R: Read,

source

pub fn new( capacity: usize, reader: R ) -> Result<PcapNGReader<R>, PcapError<&'static [u8]>>

Creates a new PcapNGReader<R> with the provided buffer capacity.

source

pub fn from_buffer( buffer: Buffer, reader: R ) -> Result<PcapNGReader<R>, PcapError<&'static [u8]>>

Creates a new PcapNGReader<R> using the provided Buffer.

Trait Implementations§

source§

impl<R> PcapReaderIterator for PcapNGReader<R>
where R: Read,

source§

fn next(&mut self) -> Result<(usize, PcapBlockOwned<'_>), PcapError<&[u8]>>

Get the next pcap block, if possible. Returns the number of bytes read and the block. Read more
source§

fn consume(&mut self, offset: usize)

Consume data, and shift buffer if needed. Read more
source§

fn consume_noshift(&mut self, offset: usize)

Consume date, but do not change the buffer. Blocks already read are still valid.
source§

fn consumed(&self) -> usize

Get the number of consumed bytes
source§

fn refill(&mut self) -> Result<(), PcapError<&[u8]>>

Refill the internal buffer, shifting it if necessary. Read more
source§

fn position(&self) -> usize

Get the position in the internal buffer. Can be used to determine if refill is required.
source§

fn grow(&mut self, new_size: usize) -> bool

Grow size of the internal buffer.
source§

fn data(&self) -> &[u8]

Returns a slice with all the available data
source§

fn reader_exhausted(&self) -> bool

Returns true if underlying reader is exhausted Read more

Auto Trait Implementations§

§

impl<R> RefUnwindSafe for PcapNGReader<R>
where R: RefUnwindSafe,

§

impl<R> Send for PcapNGReader<R>
where R: Send,

§

impl<R> Sync for PcapNGReader<R>
where R: Sync,

§

impl<R> Unpin for PcapNGReader<R>
where R: Unpin,

§

impl<R> UnwindSafe for PcapNGReader<R>
where R: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.