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::{self, complete, do_parse, many0, IResult, Offset};
use std::fmt;
use std::io::Read;
pub struct LegacyPcapReader<R>
where
R: Read,
{
header: PcapHeader,
reader: R,
buffer: Buffer,
header_sent: bool,
reader_exhausted: bool,
parse: LegacyParseFn,
}
type LegacyParseFn = fn(&[u8]) -> IResult<&[u8], LegacyPcapBlock, PcapError>;
impl<R> LegacyPcapReader<R>
where
R: Read,
{
pub fn new(capacity: usize, mut reader: R) -> Result<LegacyPcapReader<R>, PcapError> {
let mut buffer = Buffer::with_capacity(capacity);
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),
Err(_) => Err(PcapError::Incomplete),
}?;
let parse = if header.is_bigendian() {
parse_pcap_frame_be
} else {
parse_pcap_frame
};
Ok(LegacyPcapReader {
header,
reader,
buffer,
header_sent: false,
reader_exhausted: false,
parse,
})
}
pub fn from_buffer(
mut buffer: Buffer,
mut reader: R,
) -> Result<LegacyPcapReader<R>, PcapError> {
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),
Err(_) => Err(PcapError::Incomplete),
}?;
let parse = if header.is_bigendian() {
parse_pcap_frame_be
} else {
parse_pcap_frame
};
Ok(LegacyPcapReader {
header,
reader,
buffer,
header_sent: false,
reader_exhausted: false,
parse,
})
}
}
impl<R> PcapReaderIterator<R> for LegacyPcapReader<R>
where
R: Read,
{
fn next(&mut self) -> Result<(usize, PcapBlockOwned), PcapError> {
if !self.header_sent {
self.header_sent = true;
return Ok((
self.header.size(),
PcapBlockOwned::from(self.header.clone()),
));
}
if self.buffer.position() == 0 && self.buffer.available_data() == 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.buffer.consume(offset);
}
fn consume_noshift(&mut self, offset: usize) {
self.buffer.consume_noshift(offset);
}
fn refill(&mut self) -> Result<(), PcapError> {
self.buffer.shift();
let sz = self
.reader
.read(self.buffer.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()
}
}
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>> {
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>>;
fn next(&mut self) -> Option<Result<PcapBlockOwned<'a>, nom::Err<PcapError>>> {
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> {
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> {
do_parse! {
i,
header: parse_pcap_header >>
blocks: many0!(complete!(parse_pcap_frame)) >>
(
PcapCapture{ header, blocks }
)
}
}