extern crate bytepack;
#[cfg(feature = "time")]
extern crate time;
mod def;
pub mod read;
pub mod write;
#[cfg(fuzzing)]
pub mod fuzz;
pub use def::Linktype;
#[cfg(not(feature = "time"))]
use std::time::SystemTime as Time;
#[cfg(feature = "time")]
use time::Timespec as Time;
use std::error;
use std::fmt;
use std::io;
#[derive(Eq,PartialEq,Debug)]
pub struct CapturedPacket<'a> {
pub time: Time,
pub data: &'a [u8],
pub orig_len: usize,
}
#[derive(Copy,Clone,PartialEq,Eq,Debug)]
pub struct FileOptions {
pub snaplen: usize,
pub linktype: u32,
pub high_res_timestamps: bool,
pub non_native_byte_order: bool,
}
#[derive(Debug)]
pub enum PcapError {
Io(io::Error),
InvalidPacketSize,
InvalidDate,
InvalidFileHeader,
}
impl From<io::Error> for PcapError {
fn from(err: io::Error) -> PcapError {
PcapError::Io(err)
}
}
impl From<std::time::SystemTimeError> for PcapError {
fn from(_: std::time::SystemTimeError) -> PcapError {
PcapError::InvalidDate
}
}
impl fmt::Display for PcapError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let desc = match *self {
PcapError::Io(ref err) => { return err.fmt(f); },
PcapError::InvalidPacketSize => "Parsed packet has an invalid size.",
PcapError::InvalidDate => "Parsed packet has an invalid date.",
PcapError::InvalidFileHeader => "The pcap file has an invalid/unknown file header.",
};
write!(f, "{}", desc)
}
}
impl error::Error for PcapError {
fn cause(&self) -> Option<&dyn error::Error> {
match *self {
PcapError::Io(ref err) => Some(err),
_ => None,
}
}
}
#[cfg(test)]
mod test {
use std::io::{Cursor, Write};
use super::write::{PcapWriter, WriteOptions};
use super::read::PcapReader;
use super::Time;
use super::{CapturedPacket, Linktype};
#[cfg(not(feature = "time"))]
use ::std::time::{Duration, UNIX_EPOCH};
extern crate rand;
use self::rand::Rng;
fn gen_packet_data() -> Vec<Vec<u8>> {
let mut rng = rand::thread_rng();
(0..10)
.map(|_| {
let size: usize = rng.gen_range(0..2000);
(0..size).map(|_| rng.gen()).collect()
})
.collect()
}
#[cfg(not(feature = "time"))]
fn make_time(secs: u64, nsecs: u32) -> Time {
UNIX_EPOCH + Duration::new(secs, nsecs)
}
#[cfg(feature = "time")]
fn make_time(secs: u64, nsecs: u32) -> Time {
Time::new(secs as i64, nsecs as i32)
}
fn gen_packets<'a>(contents: &'a Vec<Vec<u8>>, snaplen: usize) -> Vec<CapturedPacket<'a>> {
let mut rng = rand::thread_rng();
contents.iter()
.map(|data| {
let s = rng.gen_range(0..(u64::from(u32::max_value()) + 1));
let ns = rng.gen_range(0..1_000_000_000);
CapturedPacket {
time: make_time(s, ns),
data: &data[..usize::min(data.len(), snaplen)],
orig_len: data.len(),
}
})
.collect()
}
fn write_packets<W: Write>(mut writer: PcapWriter<W>, packets: &[CapturedPacket]) -> W {
for p in &packets[..packets.len()] {
writer.write(&p).unwrap();
}
writer.take_writer()
}
#[test]
fn read_write() {
const MAX_PACKET_SIZE : usize = 1000;
let contents = gen_packet_data();
let packets = gen_packets(&contents, MAX_PACKET_SIZE);
let opts = WriteOptions {
high_res_timestamps: true,
non_native_byte_order: false,
snaplen: MAX_PACKET_SIZE,
linktype: Linktype::NULL.into(),
};
let buf = write_packets(PcapWriter::new(Vec::new(), opts).unwrap(), &packets[..packets.len()/2]);
let buf = PcapWriter::append(Cursor::new(buf)).unwrap();
let buf = write_packets(buf, &packets[packets.len()/2..]).into_inner();
let (ropts, mut reader) = PcapReader::new(buf.as_slice()).unwrap();
assert_eq!(opts, ropts);
for expect in packets {
let actual = reader.next().unwrap().unwrap();
assert_eq!(actual, expect);
}
assert!(reader.next().unwrap().is_none());
}
}
#[doc = include_str!("../README.md")]
#[cfg(doctest)]
pub struct ReadmeDoctests;