#pcap-parser #pcap #cap #networking #read-write #pcapng #write

pcaparse

A crate to parse, read and write Cap(NA Sniffer 2.x), Pcap and PcapNg

8 releases

0.2.0-alpha Dec 22, 2024
0.1.6 Apr 19, 2024
0.1.5 Nov 24, 2023

#500 in Parser implementations

Download history 20/week @ 2024-09-21 12/week @ 2024-09-28 20/week @ 2024-10-05 6/week @ 2024-10-12 21/week @ 2024-11-02 1/week @ 2024-11-09 3/week @ 2024-11-16 4/week @ 2024-11-23 15/week @ 2024-11-30 4/week @ 2024-12-07 82/week @ 2024-12-21 5/week @ 2024-12-28 2/week @ 2025-01-04

89 downloads per month

MIT license

275KB
5K SLoC

pcaparse

This is a combination of awesome pcap-file crate and pcap-file-tokio crate with some issues fixed and new features added.

Provides parsers, readers and writers for Cap(Network Associates Sniffer 2.x), Pcap and PcapNg files.

Crates.io rustdoc Crates.io

Why this crate

  • The sync and async processing share similar logic but divided into two crates, which will increase the difficulty of fixing problems.

Crate Features

tokio enables async reading and writing via tokio crate.

Installation

This crate is on crates.io. Add it to your Cargo.toml:

[dependencies]
pcaparse = "0.2"

Examples

Unified reader for cap/pcap/pcapng

use std::fs::File;
use pcaparse::Reader;

let file_in = File::open("test.pcap").expect("Error opening file");
let mut reader = Reader::new(file_in).unwrap();

// Read test.pcap
while let Some(pkt) = reader.next_packet() {
    //Check if there is no error
    let pkt = pkt.unwrap();

    //Do something
 }

PcapReader

use std::fs::File;
use pcaparse::pcap::PcapReader;

let file_in = File::open("test.pcap").expect("Error opening file");
let mut pcap_reader = PcapReader::new(file_in).unwrap();

// Read test.pcap
while let Some(pkt) = pcap_reader.next_packet() {
    //Check if there is no error
    let pkt = pkt.unwrap();

    //Do something
 }

Async PcapReader

enable tokio feature first

use tokio::fs::File;
use pcaparse::pcap::PcapReader;

#[tokio::main]
async fn main() {
    let file_in = File::open("test.pcap").await.expect("Error opening file");
    let mut pcap_reader = PcapReader::async_new(file_in).await.unwrap();
    let datalink = pcap_reader.header().datalink;

    // Read test.pcap
    while let Some(pkt) = pcap_reader.async_next_packet().await {
        //Check if there is no error
        let pkt = pkt.unwrap();

        //Do something
    }
}

Async PcapReader from tokio's TcpStream (AKA pcap-over-ip)

enable tokio feature first

use tokio::net::{TcpListener, TcpStream};
use pcaparse::pcap::PcapReader;

#[tokio::main]
async fn main() {
    let listener = TcpListener::bind("0.0.0.0:12345").await.unwrap();
    println!("start listen 12345");
    loop {
        let (stream, _) = listener.accept().await.unwrap();
        tokio::spawn(async move {
            process(stream).await;
        });
    }
}

async fn process(stream: TcpStream) {
    let mut pcap_reader = PcapReader::async_new(stream).await.unwrap();
    // Read test.pcap
    while let Some(pkt) = pcap_reader.async_next_packet().await {
        //Check if there is no error
        let pkt = pkt.unwrap();
        //Do something
    }
}

PcapNgReader

use std::fs::File;
use pcaparse::pcapng::PcapNgReader;

let file_in = File::open("test.pcapng").expect("Error opening file");
let mut pcapng_reader = PcapNgReader::new(file_in).unwrap();

// Read test.pcapng
while let Some(block) = pcapng_reader.next_block() {
    // Check if there is no error
    let block = block.unwrap();

    //  Do something
}

Async PcapNgReader from tokio's File

enable tokio feature first

use tokio::fs::File;
use pcaparse::pcapng::PcapNgReader;

#[tokio::main]
async fn main() {
    let file_in = File::open("test.pcapng").await.expect("Error opening file");
    let mut pcapng_reader = PcapNgReader::async_new(file_in).await.unwrap();

    // Read test.pcapng
    while let Some(block) = pcapng_reader.async_next_block().await {
        // Check if there is no error
        let block = block.unwrap();

        //  Do something
    }
}

CapReader

use std::fs::File;
use pcaparse::cap::CapReader;

let file_in = File::open("test.cap").expect("Error opening file");
let mut cap_reader = CapReader::new(file_in).unwrap();
let datalink = cap_reader.header().datalink;

// Read test.cap
while let Some(pkt) = cap_reader.next_packet() {
    //Check if there is no error
    let pkt = pkt.unwrap();

    //Do something
 }

Async CapReader

enable tokio feature first

use tokio::fs::File;
use pcaparse::cap::CapReader;

#[tokio::main]
async fn main() {
    let file_in = File::open("test.cap").await.expect("Error opening file");
    let mut cap_reader = CapReader::async_new(file_in).await.unwrap();
    let datalink = cap_reader.header().datalink;

    // Read test.cap
    while let Some(pkt) = cap_reader.async_next_packet().await {
        //Check if there is no error
        let pkt = pkt.unwrap();

        //Do something
    }
}

Fuzzing

Currently there are 4 crude harnesses to check that the parser won't panic in any situation. To start fuzzing you must install cargo-fuzz with the command:

$ cargo install cargo-fuzz

And then, in the root of the repository, you can run the harnesses as:

$ cargo fuzz run pcap_reader
$ cargo fuzz run pcap_ng_reader
$ cargo fuzz run pcap_parser
$ cargo fuzz run pcap_ng_parser

Keep in mind that libfuzzer by default uses only one core, so you can either run all the harnesses in different terminals, or you can pass the -jobs and -workers attributes. More info can be found in its documentation here. To get better crash reports add to you rust flags: -Zsanitizer=address. E.g.

RUSTFLAGS="-Zsanitizer=address" cargo fuzz run pcap_reader

License

Licensed under MIT.

Disclaimer

To test the library I used the excellent PcapNg testing suite provided by hadrielk.

Dependencies

~2.6–8.5MB
~70K SLoC