AggregateInterface can be used to gather multiple libpcap interfaces together in order to listen to all simultaneously and also selectively send on different interfaces
120 lines
3.6 KiB
Rust
120 lines
3.6 KiB
Rust
// Copyright (C) 2023 Andrew Rioux
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
use errno::Errno;
|
|
use std::{
|
|
convert::From,
|
|
ffi::{self, CStr, CString}, fmt::Display, error,
|
|
};
|
|
|
|
#[derive(Debug)]
|
|
pub enum Error {
|
|
PcapError(CString),
|
|
PcapErrorIf(String, CString),
|
|
StringParse,
|
|
UnknownPacketType(u16),
|
|
PacketLengthInvalid,
|
|
InvalidPcapFd,
|
|
Io(std::io::Error),
|
|
Libc(Errno),
|
|
}
|
|
|
|
pub type Result<T> = std::result::Result<T, Error>;
|
|
|
|
impl Display for Error {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
match self {
|
|
Error::PcapError(err) => {
|
|
if let Ok(err_str) = std::str::from_utf8(err.as_bytes()) {
|
|
return write!(f, "pcap error: {err_str}");
|
|
}
|
|
|
|
write!(f, "unknown pcap error")
|
|
},
|
|
Error::PcapErrorIf(ifname, err) => {
|
|
if let Ok(err_str) = std::str::from_utf8(err.as_bytes()) {
|
|
return write!(f, "pcap error on interface {ifname}: {err_str}");
|
|
}
|
|
|
|
write!(f, "unknown pcap error with interface {ifname}")
|
|
},
|
|
Error::StringParse => write!(f, "unable to parse a string from pcap"),
|
|
Error::UnknownPacketType(ptype) => write!(f, "unknown packet type ({ptype})"),
|
|
Error::PacketLengthInvalid => write!(f, "received a packet with a length that mismatched the header"),
|
|
Error::InvalidPcapFd => write!(f, "internal pcap file descriptor error"),
|
|
Error::Io(io) => write!(f, "std::io error ({io})"),
|
|
Error::Libc(err) => write!(f, "libc error ({err})"),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Error {
|
|
pub fn add_ifname(self, ifname: &str) -> Self {
|
|
match self {
|
|
Error::PcapError(err) => Error::PcapErrorIf(ifname.to_string(), err),
|
|
other => other
|
|
}
|
|
}
|
|
}
|
|
|
|
impl error::Error for Error {
|
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
|
match self {
|
|
Error::Io(err) => Some(err),
|
|
Error::Libc(err) => Some(err),
|
|
_ => None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&[i8; 256]> for Error {
|
|
fn from(buf: &[i8; 256]) -> Error {
|
|
match CString::new(
|
|
buf.iter()
|
|
.take_while(|&&v| v != 0)
|
|
.map(|&v| v as u8)
|
|
.collect::<Vec<_>>(),
|
|
) {
|
|
Ok(s) => Error::PcapError(s),
|
|
Err(_) => Error::StringParse,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<*const i8> for Error {
|
|
#[allow(clippy::not_unsafe_ptr_arg_deref)]
|
|
fn from(buf: *const i8) -> Error {
|
|
Error::PcapError(unsafe { CStr::from_ptr(buf) }.to_owned())
|
|
}
|
|
}
|
|
|
|
impl From<ffi::NulError> for Error {
|
|
fn from(_err: ffi::NulError) -> Error {
|
|
Error::StringParse
|
|
}
|
|
}
|
|
|
|
impl From<std::io::Error> for Error {
|
|
fn from(err: std::io::Error) -> Error {
|
|
Error::Io(err)
|
|
}
|
|
}
|
|
|
|
impl From<Errno> for Error {
|
|
fn from(err: Errno) -> Error {
|
|
Error::Libc(err)
|
|
}
|
|
}
|