Lines
100 %
Functions
69.44 %
//! pcap is a packet capture library available on Linux, Windows and Mac. This
//! crate supports creating and configuring capture contexts, sniffing packets,
//! sending packets to interfaces, listing devices, and recording packet captures
//! to pcap-format dump files.
//!
//! # Capturing packets
//! The easiest way to open an active capture handle and begin sniffing is to
//! use `.open()` on a `Device`. You can obtain the "default" device using
//! `Device::lookup()`, or you can obtain the device(s) you need via `Device::list()`.
//! ```no_run
//! use pcap::Device;
//! let mut cap = Device::lookup().unwrap().unwrap().open().unwrap();
//! while let Ok(packet) = cap.next_packet() {
//! println!("received packet! {:?}", packet);
//! }
//! ```
//! `Capture`'s `.next_packet()` will produce a `Packet` which can be dereferenced to access the
//! `&[u8]` packet contents.
//! # Custom configuration
//! You may want to configure the `timeout`, `snaplen` or other parameters for the capture
//! handle. In this case, use `Capture::from_device()` to obtain a `Capture<Inactive>`, and
//! proceed to configure the capture handle. When you're finished, run `.open()` on it to
//! turn it into a `Capture<Active>`.
//! use pcap::{Device, Capture};
//! let main_device = Device::lookup().unwrap().unwrap();
//! let mut cap = Capture::from_device(main_device).unwrap()
//! .promisc(true)
//! .snaplen(5000)
//! .open().unwrap();
//! # Abstracting over different capture types
//! You can abstract over live captures (`Capture<Active>`) and file captures
//! (`Capture<Offline>`) using generics and the [`Activated`] trait, for example:
//! use pcap::{Activated, Capture};
//! fn read_packets<T: Activated>(mut capture: Capture<T>) {
//! while let Ok(packet) = capture.next_packet() {
use std::ffi::{self, CStr};
use std::fmt;
use self::Error::*;
mod capture;
mod codec;
mod device;
mod linktype;
mod packet;
#[cfg(not(windows))]
pub use capture::activated::open_raw_fd;
pub use capture::{
activated::{iterator::PacketIter, BpfInstruction, BpfProgram, Direction, Savefile, Stat},
inactive::TimestampType,
{Activated, Active, Capture, Dead, Inactive, Offline, Precision, State},
};
pub use codec::PacketCodec;
pub use device::{Address, ConnectionStatus, Device, DeviceFlags, IfFlags};
pub use linktype::Linktype;
pub use packet::{Packet, PacketHeader};
#[deprecated(note = "Renamed to TimestampType")]
/// An old name for `TimestampType`, kept around for backward-compatibility.
pub type TstampType = TimestampType;
mod raw;
#[cfg(windows)]
pub mod sendqueue;
#[cfg(feature = "capture-stream")]
mod stream;
pub use stream::PacketStream;
/// An error received from pcap
#[derive(Debug, PartialEq, Eq)]
pub enum Error {
/// The underlying library returned invalid UTF-8
MalformedError(std::str::Utf8Error),
/// The underlying library returned a null string
InvalidString,
/// The unerlying library returned an error
PcapError(String),
/// The linktype was invalid or unknown
InvalidLinktype,
/// The timeout expired while reading from a live capture
TimeoutExpired,
/// No more packets to read from the file
NoMorePackets,
/// Must be in non-blocking mode to function
NonNonBlock,
/// There is not sufficent memory to create a dead capture
InsufficientMemory,
/// An invalid input string (internal null)
InvalidInputString,
/// An IO error occurred
IoError(std::io::ErrorKind),
/// An invalid raw file descriptor was provided
InvalidRawFd,
/// Errno error
ErrnoError(errno::Errno),
/// Buffer size overflows capacity
BufferOverflow,
}
impl Error {
unsafe fn new(ptr: *const libc::c_char) -> Error {
match cstr_to_string(ptr) {
Err(e) => e as Error,
Ok(string) => PcapError(string.unwrap_or_default()),
fn with_errbuf<T, F>(func: F) -> Result<T, Error>
where
F: FnOnce(*mut libc::c_char) -> Result<T, Error>,
{
let mut errbuf = [0i8; 256];
func(errbuf.as_mut_ptr() as _)
unsafe fn cstr_to_string(ptr: *const libc::c_char) -> Result<Option<String>, Error> {
let string = if ptr.is_null() {
None
} else {
Some(CStr::from_ptr(ptr as _).to_str()?.to_owned())
Ok(string)
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
MalformedError(ref e) => write!(f, "libpcap returned invalid UTF-8: {}", e),
InvalidString => write!(f, "libpcap returned a null string"),
PcapError(ref e) => write!(f, "libpcap error: {}", e),
InvalidLinktype => write!(f, "invalid or unknown linktype"),
TimeoutExpired => write!(f, "timeout expired while reading from a live capture"),
NonNonBlock => write!(f, "must be in non-blocking mode to function"),
NoMorePackets => write!(f, "no more packets to read from the file"),
InsufficientMemory => write!(f, "insufficient memory"),
InvalidInputString => write!(f, "invalid input string (internal null)"),
IoError(ref e) => write!(f, "io error occurred: {:?}", e),
InvalidRawFd => write!(f, "invalid raw file descriptor provided"),
ErrnoError(ref e) => write!(f, "libpcap os errno: {}", e),
BufferOverflow => write!(f, "buffer size too large"),
// Using description is deprecated. Remove in next version.
impl std::error::Error for Error {
fn description(&self) -> &str {
MalformedError(..) => "libpcap returned invalid UTF-8",
PcapError(..) => "libpcap FFI error",
InvalidString => "libpcap returned a null string",
InvalidLinktype => "invalid or unknown linktype",
TimeoutExpired => "timeout expired while reading from a live capture",
NonNonBlock => "must be in non-blocking mode to function",
NoMorePackets => "no more packets to read from the file",
InsufficientMemory => "insufficient memory",
InvalidInputString => "invalid input string (internal null)",
IoError(..) => "io error occurred",
InvalidRawFd => "invalid raw file descriptor provided",
ErrnoError(..) => "internal error, providing errno",
BufferOverflow => "buffer size too large",
fn cause(&self) -> Option<&dyn std::error::Error> {
MalformedError(ref e) => Some(e),
_ => None,
impl From<ffi::NulError> for Error {
fn from(_: ffi::NulError) -> Error {
InvalidInputString
impl From<std::str::Utf8Error> for Error {
fn from(obj: std::str::Utf8Error) -> Error {
MalformedError(obj)
impl From<std::io::Error> for Error {
fn from(obj: std::io::Error) -> Error {
obj.kind().into()
impl From<std::io::ErrorKind> for Error {
fn from(obj: std::io::ErrorKind) -> Error {
IoError(obj)
#[cfg(test)]
mod tests {
use std::error::Error as StdError;
use std::{ffi::CString, io};
use super::*;
#[test]
fn test_error_invalid_utf8() {
let bytes: [u8; 8] = [0x78, 0xfe, 0xe9, 0x89, 0x00, 0x00, 0xed, 0x4f];
let error = unsafe { Error::new(&bytes as *const _ as _) };
assert!(matches!(error, Error::MalformedError(_)));
fn test_error_null() {
let error = unsafe { Error::new(std::ptr::null()) };
assert_eq!(error, Error::PcapError("".to_string()));
#[allow(deprecated)]
fn test_errors() {
let mut errors: Vec<Error> = vec![];
let cstr = unsafe { CStr::from_ptr(&bytes as *const _ as _) };
errors.push(cstr.to_str().unwrap_err().into());
errors.push(Error::InvalidString);
errors.push(Error::PcapError("git rekt".to_string()));
errors.push(Error::InvalidLinktype);
errors.push(Error::TimeoutExpired);
errors.push(Error::NoMorePackets);
errors.push(Error::NonNonBlock);
errors.push(Error::InsufficientMemory);
errors.push(CString::new(b"f\0oo".to_vec()).unwrap_err().into());
errors.push(io::Error::new(io::ErrorKind::Interrupted, "error").into());
errors.push(Error::InvalidRawFd);
errors.push(Error::ErrnoError(errno::Errno(125)));
errors.push(Error::BufferOverflow);
for error in errors.iter() {
assert!(!error.to_string().is_empty());
assert!(!error.description().is_empty());
match error {
Error::MalformedError(_) => assert!(error.cause().is_some()),
_ => assert!(error.cause().is_none()),