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_frame_be, parse_pcap_header, LegacyPcapBlock, PcapHeader,
};
use crate::traits::PcapReaderIterator;
use circular::Buffer;
use nom::combinator::complete;
use nom::multi::many0;
use nom::{self, IResult, Offset};
use std::fmt;
use std::io::Read;
pub struct LegacyPcapReader<R>
where
R: Read,
{
header: PcapHeader,
reader: R,
buffer: Buffer,
consumed: usize,
header_sent: bool,
reader_exhausted: bool,
parse: LegacyParseFn,
}
type LegacyParseFn = fn(&[u8]) -> IResult<&[u8], LegacyPcapBlock, PcapError<&[u8]>>;
impl<R> LegacyPcapReader<R>
where
R: Read,
{
pub fn new(
capacity: usize,
reader: R,
) -> Result<LegacyPcapReader<R>, PcapError<&'static [u8]>> {
let buffer = Buffer::with_capacity(capacity);
Self::from_buffer(buffer, reader)
}
pub fn from_buffer(
mut buffer: Buffer,
mut reader: R,
) -> Result<LegacyPcapReader<R>, PcapError<&'static [u8]>> {
let sz = reader.read(buffer.space()).or(Err(PcapError::ReadError))?;
buffer.fill(sz);
let (_rem, header) = match parse_pcap_header(buffer.data()) {
Ok((r, h)) => Ok((r, h)),
Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e.to_owned_vec()),
Err(_) => Err(PcapError::Incomplete),
}?;
let parse = if header.is_bigendian() {
parse_pcap_frame_be
} else {
parse_pcap_frame
};
Ok(LegacyPcapReader {
header,
reader,
buffer,
consumed: 0,
header_sent: false,
reader_exhausted: false,
parse,
})
}
}
impl<R> PcapReaderIterator for LegacyPcapReader<R>
where
R: Read,
{
fn next(&mut self) -> Result<(usize, PcapBlockOwned), PcapError<&'_ [u8]>> {
if !self.header_sent {
self.header_sent = true;
return Ok((
self.header.size(),
PcapBlockOwned::from(self.header.clone()),
));
}
if self.buffer.available_data() == 0
&& (self.buffer.position() == 0 || self.reader_exhausted)
{
return Err(PcapError::Eof);
}
let data = self.buffer.data();
match (self.parse)(data) {
Ok((rem, b)) => {
let offset = data.offset(rem);
Ok((offset, PcapBlockOwned::from(b)))
}
Err(nom::Err::Error(e)) | Err(nom::Err::Failure(e)) => Err(e),
Err(_) => Err(PcapError::Incomplete),
}
}
fn consume(&mut self, offset: usize) {
self.consumed += offset;
self.buffer.consume(offset);
}
fn consume_noshift(&mut self, offset: usize) {
self.consumed += offset;
self.buffer.consume_noshift(offset);
}
fn consumed(&self) -> usize {
self.consumed
}
fn refill(&mut self) -> Result<(), PcapError<&[u8]>> {
self.buffer.shift();
let space = self.buffer.space();
if space.is_empty() {
return Ok(());
}
let sz = self.reader.read(space).or(Err(PcapError::ReadError))?;
self.reader_exhausted = sz == 0;
self.buffer.fill(sz);
Ok(())
}
fn position(&self) -> usize {
self.buffer.position()
}
fn grow(&mut self, new_size: usize) -> bool {
self.buffer.grow(new_size)
}
fn data(&self) -> &[u8] {
self.buffer.data()
}
fn reader_exhausted(&self) -> bool {
self.reader_exhausted
}
}
pub struct LegacyPcapSlice<'a> {
pub header: PcapHeader,
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 })
}
}
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)
}
}
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(_) => Err(PcapError::Incomplete),
}
}
}
impl<'a> fmt::Debug for PcapCapture<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
writeln!(f, "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 })
}
}
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 }))
}