Skip to content

Commit

Permalink
Refactor: split capture and reader
Browse files Browse the repository at this point in the history
  • Loading branch information
chifflier committed Apr 23, 2024
1 parent 5a5da8f commit e7ed2ef
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 256 deletions.
3 changes: 1 addition & 2 deletions src/capture.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use crate::blocks::PcapBlock;
use crate::capture_pcap::LegacyPcapReader;
use crate::capture_pcapng::PcapNGReader;
use crate::error::PcapError;
use crate::linktype::Linktype;
use crate::pcap::parse_pcap_header;
use crate::pcapng::parse_sectionheaderblock;
use crate::traits::PcapReaderIterator;
use crate::{LegacyPcapReader, PcapNGReader};
use circular::Buffer;
use nom::Needed;
use std::io::Read;
Expand Down
9 changes: 2 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,12 @@ mod utils;
pub use utils::{Data, MutableData};

mod blocks;
mod capture;
mod endianness;
mod error;
mod linktype;
pub use blocks::*;
pub use capture::*;
pub use error::*;
pub use linktype::*;

Expand All @@ -143,13 +145,6 @@ pub use pcapng::*;

pub mod traits;

mod capture;
mod capture_pcap;
mod capture_pcapng;
pub use capture::*;
pub use capture_pcap::*;
pub use capture_pcapng::*;

#[cfg(feature = "serialize")]
#[cfg_attr(docsrs, doc(cfg(feature = "serialize")))]
mod serialize;
Expand Down
4 changes: 4 additions & 0 deletions src/pcap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@
//! loop over [`parse_pcap_frame`](fn.parse_pcap_frame.html) to get the data.
//! This can be used in a streaming parser.
mod capture;
mod frame;
mod header;
mod reader;

pub use capture::*;
pub use frame::*;
pub use header::*;
pub use reader::*;

#[cfg(test)]
pub mod tests {
Expand Down
126 changes: 126 additions & 0 deletions src/pcap/capture.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use crate::blocks::{PcapBlock, PcapBlockOwned};
use crate::capture::Capture;
use crate::error::PcapError;
use crate::linktype::Linktype;
use crate::pcap::{parse_pcap_frame, parse_pcap_header, LegacyPcapBlock, PcapHeader};
use nom::combinator::complete;
use nom::multi::many0;
use nom::{IResult, Needed};
use std::fmt;

/// Parsing iterator over legacy pcap data (requires data to be loaded into memory)
///
/// ```rust
/// use pcap_parser::*;
/// use std::fs::File;
/// use std::io::Read;
///
/// # let path = "assets/ntp.pcap";
/// let mut file = File::open(path).unwrap();
/// let mut buffer = Vec::new();
/// file.read_to_end(&mut buffer).unwrap();
/// let mut num_blocks = 0;
/// match LegacyPcapSlice::from_slice(&buffer) {
/// Ok(iter) => {
/// println!("Format: PCAP");
/// for _block in iter {
/// num_blocks += 1;
/// }
/// return;
/// },
/// _ => ()
/// }
/// ```
pub struct LegacyPcapSlice<'a> {
pub header: PcapHeader,
// remaining (unparsed) data
rem: &'a [u8],
}

impl<'a> LegacyPcapSlice<'a> {
pub fn from_slice(i: &[u8]) -> Result<LegacyPcapSlice, nom::Err<PcapError<&[u8]>>> {
let (rem, header) = parse_pcap_header(i)?;
Ok(LegacyPcapSlice { header, rem })
}
}

/// Iterator for LegacyPcapSlice. Returns a result so parsing errors are not
/// silently ignored
impl<'a> Iterator for LegacyPcapSlice<'a> {
type Item = Result<PcapBlockOwned<'a>, nom::Err<PcapError<&'a [u8]>>>;

fn next(&mut self) -> Option<Self::Item> {
if self.rem.is_empty() {
return None;
}
let r = parse_pcap_frame(self.rem).map(|(rem, b)| {
self.rem = rem;
PcapBlockOwned::from(b)
});
Some(r)
}
}

/// Generic interface for PCAP file access
pub struct PcapCapture<'a> {
pub header: PcapHeader,

pub blocks: Vec<LegacyPcapBlock<'a>>,
}

impl<'a> PcapCapture<'a> {
pub fn from_file(i: &[u8]) -> Result<PcapCapture, PcapError<&[u8]>> {
match parse_pcap(i) {
Ok((_, pcap)) => Ok(pcap),
Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e),
Err(nom::Err::Incomplete(Needed::Size(n))) => Err(PcapError::Incomplete(n.into())),
Err(nom::Err::Incomplete(Needed::Unknown)) => Err(PcapError::Incomplete(0)),
}
}
}

impl<'a> fmt::Debug for PcapCapture<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
writeln!(f, "PcapCapture:")
}
}

/// Iterator over `PcapCapture`
pub struct LegacyPcapIterator<'a> {
cap: &'a PcapCapture<'a>,
idx: usize,
}

impl<'a> Iterator for LegacyPcapIterator<'a> {
type Item = PcapBlock<'a>;

fn next(&mut self) -> Option<PcapBlock<'a>> {
self.cap.blocks.get(self.idx).map(|b| {
self.idx += 1;
PcapBlock::from(b)
})
}
}

impl<'a> Capture for PcapCapture<'a> {
fn get_datalink(&self) -> Linktype {
self.header.network
}

fn get_snaplen(&self) -> u32 {
self.header.snaplen
}

fn iter<'b>(&'b self) -> Box<dyn Iterator<Item = PcapBlock> + 'b> {
Box::new(LegacyPcapIterator { cap: self, idx: 0 })
}
}

/// Parse the entire file
///
/// Note: this requires the file to be fully loaded to memory.
pub fn parse_pcap(i: &[u8]) -> IResult<&[u8], PcapCapture, PcapError<&[u8]>> {
let (i, header) = parse_pcap_header(i)?;
let (i, blocks) = many0(complete(parse_pcap_frame))(i)?;
Ok((i, PcapCapture { header, blocks }))
}
124 changes: 1 addition & 123 deletions src/capture_pcap.rs → src/pcap/reader.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
use crate::blocks::{PcapBlock, PcapBlockOwned};
use crate::capture::Capture;
use crate::blocks::PcapBlockOwned;
use crate::error::PcapError;
use crate::linktype::Linktype;
use crate::pcap::{
parse_pcap_frame, parse_pcap_frame_be, parse_pcap_frame_modified, parse_pcap_header,
LegacyPcapBlock, PcapHeader,
};
use crate::traits::PcapReaderIterator;
use circular::Buffer;
use nom::combinator::complete;
use nom::multi::many0;
use nom::{IResult, Needed, Offset};
use std::fmt;
use std::io::Read;

/// Parsing iterator over legacy pcap data (streaming version)
Expand Down Expand Up @@ -216,120 +211,3 @@ where
self.reader_exhausted
}
}

/// Parsing iterator over legacy pcap data (requires data to be loaded into memory)
///
/// ```rust
/// use pcap_parser::*;
/// use std::fs::File;
/// use std::io::Read;
///
/// # let path = "assets/ntp.pcap";
/// let mut file = File::open(path).unwrap();
/// let mut buffer = Vec::new();
/// file.read_to_end(&mut buffer).unwrap();
/// let mut num_blocks = 0;
/// match LegacyPcapSlice::from_slice(&buffer) {
/// Ok(iter) => {
/// println!("Format: PCAP");
/// for _block in iter {
/// num_blocks += 1;
/// }
/// return;
/// },
/// _ => ()
/// }
/// ```
pub struct LegacyPcapSlice<'a> {
pub header: PcapHeader,
// remaining (unparsed) data
rem: &'a [u8],
}

impl<'a> LegacyPcapSlice<'a> {
pub fn from_slice(i: &[u8]) -> Result<LegacyPcapSlice, nom::Err<PcapError<&[u8]>>> {
let (rem, header) = parse_pcap_header(i)?;
Ok(LegacyPcapSlice { header, rem })
}
}

/// Iterator for LegacyPcapSlice. Returns a result so parsing errors are not
/// silently ignored
impl<'a> Iterator for LegacyPcapSlice<'a> {
type Item = Result<PcapBlockOwned<'a>, nom::Err<PcapError<&'a [u8]>>>;

fn next(&mut self) -> Option<Self::Item> {
if self.rem.is_empty() {
return None;
}
let r = parse_pcap_frame(self.rem).map(|(rem, b)| {
self.rem = rem;
PcapBlockOwned::from(b)
});
Some(r)
}
}

/// Generic interface for PCAP file access
pub struct PcapCapture<'a> {
pub header: PcapHeader,

pub blocks: Vec<LegacyPcapBlock<'a>>,
}

impl<'a> PcapCapture<'a> {
pub fn from_file(i: &[u8]) -> Result<PcapCapture, PcapError<&[u8]>> {
match parse_pcap(i) {
Ok((_, pcap)) => Ok(pcap),
Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e),
Err(nom::Err::Incomplete(Needed::Size(n))) => Err(PcapError::Incomplete(n.into())),
Err(nom::Err::Incomplete(Needed::Unknown)) => Err(PcapError::Incomplete(0)),
}
}
}

impl<'a> fmt::Debug for PcapCapture<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
writeln!(f, "PcapCapture:")
}
}

/// Iterator over `PcapCapture`
pub struct LegacyPcapIterator<'a> {
cap: &'a PcapCapture<'a>,
idx: usize,
}

impl<'a> Iterator for LegacyPcapIterator<'a> {
type Item = PcapBlock<'a>;

fn next(&mut self) -> Option<PcapBlock<'a>> {
self.cap.blocks.get(self.idx).map(|b| {
self.idx += 1;
PcapBlock::from(b)
})
}
}

impl<'a> Capture for PcapCapture<'a> {
fn get_datalink(&self) -> Linktype {
self.header.network
}

fn get_snaplen(&self) -> u32 {
self.header.snaplen
}

fn iter<'b>(&'b self) -> Box<dyn Iterator<Item = PcapBlock> + 'b> {
Box::new(LegacyPcapIterator { cap: self, idx: 0 })
}
}

/// Parse the entire file
///
/// Note: this requires the file to be fully loaded to memory.
pub fn parse_pcap(i: &[u8]) -> IResult<&[u8], PcapCapture, PcapError<&[u8]>> {
let (i, header) = parse_pcap_header(i)?;
let (i, blocks) = many0(complete(parse_pcap_frame))(i)?;
Ok((i, PcapCapture { header, blocks }))
}
4 changes: 4 additions & 0 deletions src/pcapng.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,18 @@
// helpers and common modules
mod block;
mod capture;
mod header;
mod option;
mod reader;
mod section;
mod time;

pub use block::*;
pub use capture::*;
pub use header::*;
pub use option::*;
pub use reader::*;
pub use section::*;
pub use time::*;

Expand Down
Loading

0 comments on commit e7ed2ef

Please sign in to comment.