More flakes work
Removed old git submodules Started adding Windows cross compilation support
This commit is contained in:
parent
4475d23d1d
commit
862dc3e743
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,6 +0,0 @@
|
|||||||
[submodule "pcap-sys/libpcap"]
|
|
||||||
path = pcap-sys/libpcap
|
|
||||||
url = https://github.com/the-tcpdump-group/libpcap
|
|
||||||
[submodule "nl-sys/libnl"]
|
|
||||||
path = nl-sys/libnl
|
|
||||||
url = https://github.com/thom311/libnl
|
|
||||||
61
flake.lock
generated
61
flake.lock
generated
@ -20,6 +20,27 @@
|
|||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fenix": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"rust-analyzer-src": "rust-analyzer-src"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1705991032,
|
||||||
|
"narHash": "sha256-C+ePPXLMOxkJfJMqihUC1XbNr9Xy2F6BpWrmGDsgzXk=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "fenix",
|
||||||
|
"rev": "2189a3d994aaee6f83d3fc92deb13c458dd03dbd",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "fenix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
@ -107,11 +128,30 @@
|
|||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"crane": "crane",
|
"crane": "crane",
|
||||||
|
"fenix": "fenix",
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"libnl": "libnl",
|
"libnl": "libnl",
|
||||||
"libpcap-src": "libpcap-src",
|
"libpcap-src": "libpcap-src",
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"rust-overlay": "rust-overlay"
|
"rust-overlay": "rust-overlay",
|
||||||
|
"winpcap": "winpcap"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"rust-analyzer-src": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1705864945,
|
||||||
|
"narHash": "sha256-ZATChFWHToTZQFLlzrzDUX8fjEbMHHBIyPaZU1JGmjI=",
|
||||||
|
"owner": "rust-lang",
|
||||||
|
"repo": "rust-analyzer",
|
||||||
|
"rev": "d410d4a2baf9e99b37b03dd42f06238b14374bf7",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "rust-lang",
|
||||||
|
"ref": "nightly",
|
||||||
|
"repo": "rust-analyzer",
|
||||||
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rust-overlay": {
|
"rust-overlay": {
|
||||||
@ -122,11 +162,11 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1705976279,
|
"lastModified": 1706062676,
|
||||||
"narHash": "sha256-Zx97bJ3+O8IP70uJPD//rRsr8bcxICISMTZUT/L9eFk=",
|
"narHash": "sha256-aIgYdyQyKRHZ8gSmke3DE09D5ypK4tP+XYqrKPAd/3M=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "f889dc31ef97835834bdc3662394ebdb3c96b974",
|
"rev": "81eb4bdb219d97d749f152eb4de6a081b088b08d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
@ -164,6 +204,19 @@
|
|||||||
"repo": "default",
|
"repo": "default",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"winpcap": {
|
||||||
|
"flake": false,
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1277475016,
|
||||||
|
"narHash": "sha256-lea+6c9obTpxWosi2xRXUxV4+whsCTWMJ7wxZNASRz8=",
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"type": "tarball",
|
||||||
|
"url": "https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|||||||
33
flake.nix
33
flake.nix
@ -12,6 +12,10 @@
|
|||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
};
|
};
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
flake-utils.url = "github:numtide/flake-utils";
|
||||||
|
fenix = {
|
||||||
|
url = "github:nix-community/fenix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
|
|
||||||
libpcap-src = {
|
libpcap-src = {
|
||||||
url = "git+https://github.com/the-tcpdump-group/libpcap";
|
url = "git+https://github.com/the-tcpdump-group/libpcap";
|
||||||
@ -21,15 +25,19 @@
|
|||||||
url = "git+https://github.com/thom311/libnl";
|
url = "git+https://github.com/thom311/libnl";
|
||||||
flake = false;
|
flake = false;
|
||||||
};
|
};
|
||||||
|
winpcap = {
|
||||||
|
url = "https://www.winpcap.org/install/bin/WpdPack_4_1_2.zip";
|
||||||
|
flake = false;
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs =
|
outputs = { self, nixpkgs, flake-utils, crane, fenix, rust-overlay
|
||||||
{ self, nixpkgs, flake-utils, crane, rust-overlay, libpcap-src, libnl }:
|
, libpcap-src, libnl, winpcap }:
|
||||||
flake-utils.lib.eachDefaultSystem (system:
|
flake-utils.lib.eachDefaultSystem (system:
|
||||||
let
|
let
|
||||||
pkgs = import nixpkgs {
|
pkgs = import nixpkgs {
|
||||||
inherit system;
|
inherit system;
|
||||||
overlays = [ (import rust-overlay) ];
|
overlays = [ (import rust-overlay) fenix.overlays.default ];
|
||||||
};
|
};
|
||||||
|
|
||||||
buildTools = with pkgs; [
|
buildTools = with pkgs; [
|
||||||
@ -104,33 +112,20 @@
|
|||||||
cargoExtraArgs = "-p sparse-c2-beacon --locked";
|
cargoExtraArgs = "-p sparse-c2-beacon --locked";
|
||||||
});
|
});
|
||||||
in with pkgs; {
|
in with pkgs; {
|
||||||
devShells.default = craneLib.devShell rec {
|
devShells.default = craneLib.devShell {
|
||||||
name = "sparse";
|
name = "sparse";
|
||||||
|
|
||||||
buildInputs = buildTools;
|
buildInputs = windowsBuildTools ++ [ rust-analyzer ];
|
||||||
|
|
||||||
SPARSE_BUILD_LIBPCAP = "${libpcap-src}";
|
SPARSE_BUILD_LIBPCAP = "${libpcap-src}";
|
||||||
SPARSE_BUILD_LIBNL = "${libnl}";
|
SPARSE_BUILD_LIBNL = "${libnl}";
|
||||||
};
|
};
|
||||||
|
|
||||||
packages = rec {
|
packages = {
|
||||||
inherit sparse-05-linux-server sparse-05-windows-server;
|
inherit sparse-05-linux-server sparse-05-windows-server;
|
||||||
inherit sparse-c2-linux-beacon;
|
inherit sparse-c2-linux-beacon;
|
||||||
|
|
||||||
default = sparse-c2-linux-beacon;
|
default = sparse-c2-linux-beacon;
|
||||||
|
|
||||||
windows = craneLib.buildPackage (commonArgs // {
|
|
||||||
doCheck = false;
|
|
||||||
|
|
||||||
CARGO_BUILD_TARGET = "x86_64-pc-windows-gnu";
|
|
||||||
|
|
||||||
depsBuildBuild = [
|
|
||||||
pkgsCross.mingwW64.stdenv.cc
|
|
||||||
pkgsCross.mingwW64.windows.pthreads
|
|
||||||
];
|
|
||||||
|
|
||||||
artifacts = windowsArtifacts;
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,7 +22,8 @@ fn main() -> std::io::Result<()> {
|
|||||||
|
|
||||||
let mut options = CopyOptions::new();
|
let mut options = CopyOptions::new();
|
||||||
options.copy_inside = true;
|
options.copy_inside = true;
|
||||||
copy(std::env!("SPARSE_BUILD_LIBNL"), &libnl_src, &options);
|
options.skip_exist = true;
|
||||||
|
copy(std::env!("SPARSE_BUILD_LIBNL"), &libnl_src, &options).expect("could not copy nl");
|
||||||
|
|
||||||
let dst = autotools::Config::new(libnl_src).reconf("-vi").build();
|
let dst = autotools::Config::new(libnl_src).reconf("-vi").build();
|
||||||
|
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
Subproject commit cbafad9ddf24caef5230fef715d34f0539603be0
|
|
||||||
@ -23,7 +23,8 @@ fn main() {
|
|||||||
|
|
||||||
let mut options = CopyOptions::new();
|
let mut options = CopyOptions::new();
|
||||||
options.copy_inside = true;
|
options.copy_inside = true;
|
||||||
copy(std::env!("SPARSE_BUILD_LIBPCAP"), &libpcap_src, &options);
|
options.skip_exist = true;
|
||||||
|
copy(std::env!("SPARSE_BUILD_LIBPCAP"), &libpcap_src, &options).expect("could not copy libpcap source code to build");
|
||||||
|
|
||||||
let dst = cmake::Config::new(&libpcap_src)
|
let dst = cmake::Config::new(&libpcap_src)
|
||||||
.define("BUILD_SHARED_LIBS", "OFF")
|
.define("BUILD_SHARED_LIBS", "OFF")
|
||||||
|
|||||||
@ -1 +0,0 @@
|
|||||||
Subproject commit ab3f6a677ba66a9679c6f3412f0320a5776842d0
|
|
||||||
@ -14,17 +14,15 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
ffi::{CStr, CString},
|
ffi::{CStr, CString},
|
||||||
os::fd::{AsRawFd, RawFd},
|
ptr, slice
|
||||||
pin::Pin,
|
|
||||||
ptr, slice,
|
|
||||||
task::{self, Poll},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
mod ffi;
|
mod ffi;
|
||||||
pub use packets;
|
pub use packets;
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub mod stream;
|
||||||
|
|
||||||
pub mod consts {
|
pub mod consts {
|
||||||
pub use super::ffi::{
|
pub use super::ffi::{
|
||||||
@ -51,9 +49,6 @@ pub mod consts {
|
|||||||
}
|
}
|
||||||
|
|
||||||
use ffi::PcapDevIf;
|
use ffi::PcapDevIf;
|
||||||
use futures::{ready, StreamExt};
|
|
||||||
use tokio::io::unix::AsyncFd;
|
|
||||||
use tokio_stream::StreamMap;
|
|
||||||
|
|
||||||
pub struct PcapDevIterator {
|
pub struct PcapDevIterator {
|
||||||
dev_if: *const PcapDevIf,
|
dev_if: *const PcapDevIf,
|
||||||
@ -409,327 +404,15 @@ impl<T: NotListening> Interface<T> {
|
|||||||
(info.fail_error, count)
|
(info.fail_error, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stream(mut self) -> error::Result<InterfaceStream<DevActivated>> {
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn stream(mut self) -> error::Result<stream::InterfaceStream<DevActivated>> {
|
||||||
self.set_non_blocking(true)?;
|
self.set_non_blocking(true)?;
|
||||||
|
|
||||||
Ok(InterfaceStream {
|
Ok(stream::InterfaceStream {
|
||||||
inner: AsyncFd::with_interest(
|
inner: tokio::io::unix::AsyncFd::with_interest(
|
||||||
InternalInterfaceStream::<DevActivated>::new(unsafe { std::mem::transmute(self) })?,
|
stream::InternalInterfaceStream::<DevActivated>::new(unsafe { std::mem::transmute(self) })?,
|
||||||
tokio::io::Interest::READABLE,
|
tokio::io::Interest::READABLE,
|
||||||
)?,
|
)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct InternalInterfaceStream<T: Activated> {
|
|
||||||
interface: Interface<T>,
|
|
||||||
fd: RawFd,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Activated> InternalInterfaceStream<T> {
|
|
||||||
fn new(interface: Interface<T>) -> error::Result<InternalInterfaceStream<T>> {
|
|
||||||
let fd = unsafe { ffi::pcap_get_selectable_fd(interface.dev) };
|
|
||||||
if fd == -1 {
|
|
||||||
return Err(error::Error::InvalidPcapFd);
|
|
||||||
}
|
|
||||||
Ok(Self { interface, fd })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Activated> AsRawFd for InternalInterfaceStream<T> {
|
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
|
||||||
self.fd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct InterfaceStream<T: Activated> {
|
|
||||||
inner: AsyncFd<InternalInterfaceStream<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Activated> InterfaceStream<T> {
|
|
||||||
pub fn sendpacket(&mut self, packet: packets::EthernetPkt) -> error::Result<()> {
|
|
||||||
self.inner.get_mut().interface.sendpacket(packet)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_filter(
|
|
||||||
&mut self,
|
|
||||||
filter: &str,
|
|
||||||
optimize: bool,
|
|
||||||
mask: Option<u32>,
|
|
||||||
) -> error::Result<Box<ffi::BpfProgram>> {
|
|
||||||
self.inner
|
|
||||||
.get_mut()
|
|
||||||
.interface
|
|
||||||
.set_filter(filter, optimize, mask)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Activated> Unpin for InterfaceStream<T> {}
|
|
||||||
|
|
||||||
impl<T: Activated> futures::Stream for InterfaceStream<T> {
|
|
||||||
type Item = error::Result<packets::EthernetPacket>;
|
|
||||||
|
|
||||||
fn poll_next(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Option<Self::Item>> {
|
|
||||||
let stream = Pin::into_inner(self);
|
|
||||||
|
|
||||||
loop {
|
|
||||||
let mut guard = ready!(stream.inner.poll_read_ready_mut(cx))?;
|
|
||||||
|
|
||||||
match guard.try_io(|inner| match inner.get_mut().interface.next_packet() {
|
|
||||||
Ok(p) => Ok(Ok(p)),
|
|
||||||
Err(e) => Ok(Err(e)),
|
|
||||||
}) {
|
|
||||||
Ok(result) => {
|
|
||||||
return Poll::Ready(Some(result?));
|
|
||||||
}
|
|
||||||
Err(_would_block) => continue,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_aggregate_interface_filtered<F>(
|
|
||||||
crash: bool,
|
|
||||||
mut f: F,
|
|
||||||
) -> error::Result<AggregateInterface<DevDisabled>>
|
|
||||||
where
|
|
||||||
F: FnMut(&str) -> bool,
|
|
||||||
{
|
|
||||||
let interfaces = if crash {
|
|
||||||
PcapDevIterator::new()?
|
|
||||||
.filter(|s| (f)(s))
|
|
||||||
.map(|if_name| {
|
|
||||||
let new_name = if_name.clone();
|
|
||||||
Interface::<DevDisabled>::new(&if_name)
|
|
||||||
.map(|interface| (if_name, interface))
|
|
||||||
.map_err(|e| e.add_ifname(&new_name))
|
|
||||||
})
|
|
||||||
.collect::<error::Result<HashMap<_, _>>>()?
|
|
||||||
} else {
|
|
||||||
PcapDevIterator::new()?
|
|
||||||
.filter(|s| (f)(s))
|
|
||||||
.filter_map(|if_name| {
|
|
||||||
let new_name = if_name.clone();
|
|
||||||
Interface::<DevDisabled>::new(&if_name)
|
|
||||||
.map(|interface| (if_name, interface))
|
|
||||||
.ok()
|
|
||||||
.or_else(|| {
|
|
||||||
println!("{} failed to create device", new_name);
|
|
||||||
None
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<HashMap<_, _>>()
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(AggregateInterface { interfaces, crash })
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_aggregate_interface(crash: bool) -> error::Result<AggregateInterface<DevDisabled>> {
|
|
||||||
new_aggregate_interface_filtered(crash, |_| true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AggregateInterface<T: State> {
|
|
||||||
interfaces: HashMap<String, Interface<T>>,
|
|
||||||
crash: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: State> AggregateInterface<T> {
|
|
||||||
pub fn set_non_blocking(&mut self, nonblocking: bool) -> error::Result<()> {
|
|
||||||
for (n, i) in self.interfaces.iter_mut() {
|
|
||||||
i.set_non_blocking(nonblocking)
|
|
||||||
.map_err(|e| e.add_ifname(n))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn lookupnets(&self) -> error::Result<HashMap<&str, (u32, u32)>> {
|
|
||||||
self.interfaces
|
|
||||||
.iter()
|
|
||||||
.map(|(name, interface)| {
|
|
||||||
interface
|
|
||||||
.lookupnet()
|
|
||||||
.map(|net| (&**name, net))
|
|
||||||
.map_err(|e| e.add_ifname(&name))
|
|
||||||
})
|
|
||||||
.collect::<error::Result<_>>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_ifnames(&self) -> Vec<&str> {
|
|
||||||
self.interfaces.keys().map(|n| &**n).collect::<_>()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Disabled> AggregateInterface<T> {
|
|
||||||
pub fn set_promisc(&mut self, promisc: bool) -> error::Result<()> {
|
|
||||||
for (n, i) in self.interfaces.iter_mut() {
|
|
||||||
i.set_promisc(promisc).map_err(|e| e.add_ifname(n))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_buffer_size(&mut self, bufsize: i32) -> error::Result<()> {
|
|
||||||
for (n, i) in self.interfaces.iter_mut() {
|
|
||||||
i.set_buffer_size(bufsize).map_err(|e| e.add_ifname(n))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_timeout(&mut self, timeout: i32) -> error::Result<()> {
|
|
||||||
for (n, i) in self.interfaces.iter_mut() {
|
|
||||||
i.set_timeout(timeout).map_err(|e| e.add_ifname(n))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn activate(self) -> error::Result<AggregateInterface<DevActivated>> {
|
|
||||||
Ok(AggregateInterface {
|
|
||||||
interfaces: if self.crash {
|
|
||||||
self.interfaces
|
|
||||||
.into_iter()
|
|
||||||
.map(|(name, interface)| {
|
|
||||||
let new_name = name.clone();
|
|
||||||
interface
|
|
||||||
.activate()
|
|
||||||
.map(|interface| (name, interface))
|
|
||||||
.map_err(|e| e.add_ifname(&new_name))
|
|
||||||
})
|
|
||||||
.collect::<error::Result<_>>()?
|
|
||||||
} else {
|
|
||||||
self.interfaces
|
|
||||||
.into_iter()
|
|
||||||
.filter_map(|(name, interface)| {
|
|
||||||
let name_clone = name.clone();
|
|
||||||
interface
|
|
||||||
.activate()
|
|
||||||
.map(|interface| (name, interface))
|
|
||||||
.ok()
|
|
||||||
.or_else(|| {
|
|
||||||
println!("{} failed to activate", name_clone);
|
|
||||||
None
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<_>()
|
|
||||||
},
|
|
||||||
crash: self.crash,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Activated> AggregateInterface<T> {
|
|
||||||
pub fn datalinks(&self) -> HashMap<&str, i32> {
|
|
||||||
self.interfaces
|
|
||||||
.iter()
|
|
||||||
.map(|(name, interface)| (&**name, interface.datalink()))
|
|
||||||
.collect::<_>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn prune<F>(&mut self, mut f: F)
|
|
||||||
where
|
|
||||||
F: FnMut(&str, &mut Interface<T>) -> bool,
|
|
||||||
{
|
|
||||||
let to_prune = self
|
|
||||||
.interfaces
|
|
||||||
.iter_mut()
|
|
||||||
.filter_map(|(k, v)| if (f)(k, v) { Some(k.clone()) } else { None })
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
for name in to_prune {
|
|
||||||
self.interfaces.remove(&name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_filter(
|
|
||||||
&mut self,
|
|
||||||
filter: &str,
|
|
||||||
optimize: bool,
|
|
||||||
mask: Option<u32>,
|
|
||||||
) -> error::Result<HashMap<&str, Box<ffi::BpfProgram>>> {
|
|
||||||
if self.crash {
|
|
||||||
self.interfaces
|
|
||||||
.iter_mut()
|
|
||||||
.map(|(name, interface)| {
|
|
||||||
interface
|
|
||||||
.set_filter(filter, optimize, mask)
|
|
||||||
.map(|bpf| (&**name, bpf))
|
|
||||||
.map_err(|e| e.add_ifname(&name))
|
|
||||||
})
|
|
||||||
.collect::<error::Result<_>>()
|
|
||||||
} else {
|
|
||||||
Ok(self
|
|
||||||
.interfaces
|
|
||||||
.iter_mut()
|
|
||||||
.filter_map(|(name, interface)| {
|
|
||||||
let name_clone = name.clone();
|
|
||||||
interface
|
|
||||||
.set_filter(filter, optimize, mask)
|
|
||||||
.map(|bpf| (&**name, bpf))
|
|
||||||
.ok()
|
|
||||||
.or_else(|| {
|
|
||||||
println!("{} failed to set filter", name_clone);
|
|
||||||
None
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<_>())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sendpacket(&self, ifname: &str, packet: packets::EthernetPkt) -> error::Result<()> {
|
|
||||||
if let Some(interface) = self.interfaces.get(ifname) {
|
|
||||||
interface
|
|
||||||
.sendpacket(packet)
|
|
||||||
.map_err(|e| e.add_ifname(ifname))?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: NotListening> AggregateInterface<T> {
|
|
||||||
pub fn stream(self) -> error::Result<AggregateInterfaceStream<DevActivated>> {
|
|
||||||
Ok(AggregateInterfaceStream {
|
|
||||||
streams: self
|
|
||||||
.interfaces
|
|
||||||
.into_iter()
|
|
||||||
.map(|(ifname, interface)| {
|
|
||||||
let new_name = ifname.clone();
|
|
||||||
interface
|
|
||||||
.stream()
|
|
||||||
.map(|stream| (ifname, stream))
|
|
||||||
.map_err(|e| e.add_ifname(&new_name))
|
|
||||||
})
|
|
||||||
.collect::<error::Result<_>>()?,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AggregateInterfaceStream<T: Activated> {
|
|
||||||
streams: StreamMap<String, InterfaceStream<T>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Activated> AggregateInterfaceStream<T> {
|
|
||||||
pub fn get_ifnames(&self) -> Vec<&str> {
|
|
||||||
self.streams.keys().map(|n| &**n).collect::<_>()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn sendpacket(&mut self, ifname: &str, packet: packets::EthernetPkt) -> error::Result<()> {
|
|
||||||
if let Some(interface) = self.streams.values_mut().find(|interface| {
|
|
||||||
interface.inner.get_ref().interface.dev_name.as_bytes() == ifname.as_bytes()
|
|
||||||
}) {
|
|
||||||
interface.sendpacket(packet)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Activated> futures::Stream for AggregateInterfaceStream<T> {
|
|
||||||
type Item = (String, error::Result<packets::EthernetPacket>);
|
|
||||||
|
|
||||||
fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
|
|
||||||
self.streams.poll_next_unpin(cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
340
pcap-sys/src/stream.rs
Normal file
340
pcap-sys/src/stream.rs
Normal file
@ -0,0 +1,340 @@
|
|||||||
|
// 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 std::{
|
||||||
|
collections::HashMap,
|
||||||
|
os::fd::{AsRawFd, RawFd},
|
||||||
|
pin::Pin,
|
||||||
|
task::{self, Poll},
|
||||||
|
};
|
||||||
|
|
||||||
|
use futures::{ready, StreamExt};
|
||||||
|
use tokio::io::unix::AsyncFd;
|
||||||
|
use tokio_stream::StreamMap;
|
||||||
|
|
||||||
|
use super::{error, ffi, packets, Activated, NotListening, Disabled, State, Interface, DevActivated, DevDisabled, PcapDevIterator};
|
||||||
|
|
||||||
|
pub(crate) struct InternalInterfaceStream<T: Activated> {
|
||||||
|
interface: Interface<T>,
|
||||||
|
fd: RawFd,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Activated> InternalInterfaceStream<T> {
|
||||||
|
pub(crate) fn new(interface: Interface<T>) -> error::Result<InternalInterfaceStream<T>> {
|
||||||
|
let fd = unsafe { ffi::pcap_get_selectable_fd(interface.dev) };
|
||||||
|
if fd == -1 {
|
||||||
|
return Err(error::Error::InvalidPcapFd);
|
||||||
|
}
|
||||||
|
Ok(Self { interface, fd })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Activated> AsRawFd for InternalInterfaceStream<T> {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.fd
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InterfaceStream<T: Activated> {
|
||||||
|
pub(crate) inner: AsyncFd<InternalInterfaceStream<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Activated> InterfaceStream<T> {
|
||||||
|
pub fn sendpacket(&mut self, packet: packets::EthernetPkt) -> error::Result<()> {
|
||||||
|
self.inner.get_mut().interface.sendpacket(packet)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_filter(
|
||||||
|
&mut self,
|
||||||
|
filter: &str,
|
||||||
|
optimize: bool,
|
||||||
|
mask: Option<u32>,
|
||||||
|
) -> error::Result<Box<ffi::BpfProgram>> {
|
||||||
|
self.inner
|
||||||
|
.get_mut()
|
||||||
|
.interface
|
||||||
|
.set_filter(filter, optimize, mask)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Activated> Unpin for InterfaceStream<T> {}
|
||||||
|
|
||||||
|
impl<T: Activated> futures::Stream for InterfaceStream<T> {
|
||||||
|
type Item = error::Result<packets::EthernetPacket>;
|
||||||
|
|
||||||
|
fn poll_next(self: Pin<&mut Self>, cx: &mut task::Context) -> Poll<Option<Self::Item>> {
|
||||||
|
let stream = Pin::into_inner(self);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut guard = ready!(stream.inner.poll_read_ready_mut(cx))?;
|
||||||
|
|
||||||
|
match guard.try_io(|inner| match inner.get_mut().interface.next_packet() {
|
||||||
|
Ok(p) => Ok(Ok(p)),
|
||||||
|
Err(e) => Ok(Err(e)),
|
||||||
|
}) {
|
||||||
|
Ok(result) => {
|
||||||
|
return Poll::Ready(Some(result?));
|
||||||
|
}
|
||||||
|
Err(_would_block) => continue,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_aggregate_interface_filtered<F>(
|
||||||
|
crash: bool,
|
||||||
|
mut f: F,
|
||||||
|
) -> error::Result<AggregateInterface<DevDisabled>>
|
||||||
|
where
|
||||||
|
F: FnMut(&str) -> bool,
|
||||||
|
{
|
||||||
|
let interfaces = if crash {
|
||||||
|
PcapDevIterator::new()?
|
||||||
|
.filter(|s| (f)(s))
|
||||||
|
.map(|if_name| {
|
||||||
|
let new_name = if_name.clone();
|
||||||
|
Interface::<DevDisabled>::new(&if_name)
|
||||||
|
.map(|interface| (if_name, interface))
|
||||||
|
.map_err(|e| e.add_ifname(&new_name))
|
||||||
|
})
|
||||||
|
.collect::<error::Result<HashMap<_, _>>>()?
|
||||||
|
} else {
|
||||||
|
PcapDevIterator::new()?
|
||||||
|
.filter(|s| (f)(s))
|
||||||
|
.filter_map(|if_name| {
|
||||||
|
let new_name = if_name.clone();
|
||||||
|
Interface::<DevDisabled>::new(&if_name)
|
||||||
|
.map(|interface| (if_name, interface))
|
||||||
|
.ok()
|
||||||
|
.or_else(|| {
|
||||||
|
println!("{} failed to create device", new_name);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<HashMap<_, _>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(AggregateInterface { interfaces, crash })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_aggregate_interface(crash: bool) -> error::Result<AggregateInterface<DevDisabled>> {
|
||||||
|
new_aggregate_interface_filtered(crash, |_| true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AggregateInterface<T: State> {
|
||||||
|
interfaces: HashMap<String, Interface<T>>,
|
||||||
|
crash: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: State> AggregateInterface<T> {
|
||||||
|
pub fn set_non_blocking(&mut self, nonblocking: bool) -> error::Result<()> {
|
||||||
|
for (n, i) in self.interfaces.iter_mut() {
|
||||||
|
i.set_non_blocking(nonblocking)
|
||||||
|
.map_err(|e| e.add_ifname(n))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lookupnets(&self) -> error::Result<HashMap<&str, (u32, u32)>> {
|
||||||
|
self.interfaces
|
||||||
|
.iter()
|
||||||
|
.map(|(name, interface)| {
|
||||||
|
interface
|
||||||
|
.lookupnet()
|
||||||
|
.map(|net| (&**name, net))
|
||||||
|
.map_err(|e| e.add_ifname(&name))
|
||||||
|
})
|
||||||
|
.collect::<error::Result<_>>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_ifnames(&self) -> Vec<&str> {
|
||||||
|
self.interfaces.keys().map(|n| &**n).collect::<_>()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Disabled> AggregateInterface<T> {
|
||||||
|
pub fn set_promisc(&mut self, promisc: bool) -> error::Result<()> {
|
||||||
|
for (n, i) in self.interfaces.iter_mut() {
|
||||||
|
i.set_promisc(promisc).map_err(|e| e.add_ifname(n))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_buffer_size(&mut self, bufsize: i32) -> error::Result<()> {
|
||||||
|
for (n, i) in self.interfaces.iter_mut() {
|
||||||
|
i.set_buffer_size(bufsize).map_err(|e| e.add_ifname(n))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_timeout(&mut self, timeout: i32) -> error::Result<()> {
|
||||||
|
for (n, i) in self.interfaces.iter_mut() {
|
||||||
|
i.set_timeout(timeout).map_err(|e| e.add_ifname(n))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn activate(self) -> error::Result<AggregateInterface<DevActivated>> {
|
||||||
|
Ok(AggregateInterface {
|
||||||
|
interfaces: if self.crash {
|
||||||
|
self.interfaces
|
||||||
|
.into_iter()
|
||||||
|
.map(|(name, interface)| {
|
||||||
|
let new_name = name.clone();
|
||||||
|
interface
|
||||||
|
.activate()
|
||||||
|
.map(|interface| (name, interface))
|
||||||
|
.map_err(|e| e.add_ifname(&new_name))
|
||||||
|
})
|
||||||
|
.collect::<error::Result<_>>()?
|
||||||
|
} else {
|
||||||
|
self.interfaces
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(name, interface)| {
|
||||||
|
let name_clone = name.clone();
|
||||||
|
interface
|
||||||
|
.activate()
|
||||||
|
.map(|interface| (name, interface))
|
||||||
|
.ok()
|
||||||
|
.or_else(|| {
|
||||||
|
println!("{} failed to activate", name_clone);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<_>()
|
||||||
|
},
|
||||||
|
crash: self.crash,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Activated> AggregateInterface<T> {
|
||||||
|
pub fn datalinks(&self) -> HashMap<&str, i32> {
|
||||||
|
self.interfaces
|
||||||
|
.iter()
|
||||||
|
.map(|(name, interface)| (&**name, interface.datalink()))
|
||||||
|
.collect::<_>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prune<F>(&mut self, mut f: F)
|
||||||
|
where
|
||||||
|
F: FnMut(&str, &mut Interface<T>) -> bool,
|
||||||
|
{
|
||||||
|
let to_prune = self
|
||||||
|
.interfaces
|
||||||
|
.iter_mut()
|
||||||
|
.filter_map(|(k, v)| if (f)(k, v) { Some(k.clone()) } else { None })
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
for name in to_prune {
|
||||||
|
self.interfaces.remove(&name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_filter(
|
||||||
|
&mut self,
|
||||||
|
filter: &str,
|
||||||
|
optimize: bool,
|
||||||
|
mask: Option<u32>,
|
||||||
|
) -> error::Result<HashMap<&str, Box<ffi::BpfProgram>>> {
|
||||||
|
if self.crash {
|
||||||
|
self.interfaces
|
||||||
|
.iter_mut()
|
||||||
|
.map(|(name, interface)| {
|
||||||
|
interface
|
||||||
|
.set_filter(filter, optimize, mask)
|
||||||
|
.map(|bpf| (&**name, bpf))
|
||||||
|
.map_err(|e| e.add_ifname(&name))
|
||||||
|
})
|
||||||
|
.collect::<error::Result<_>>()
|
||||||
|
} else {
|
||||||
|
Ok(self
|
||||||
|
.interfaces
|
||||||
|
.iter_mut()
|
||||||
|
.filter_map(|(name, interface)| {
|
||||||
|
let name_clone = name.clone();
|
||||||
|
interface
|
||||||
|
.set_filter(filter, optimize, mask)
|
||||||
|
.map(|bpf| (&**name, bpf))
|
||||||
|
.ok()
|
||||||
|
.or_else(|| {
|
||||||
|
println!("{} failed to set filter", name_clone);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<_>())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sendpacket(&self, ifname: &str, packet: packets::EthernetPkt) -> error::Result<()> {
|
||||||
|
if let Some(interface) = self.interfaces.get(ifname) {
|
||||||
|
interface
|
||||||
|
.sendpacket(packet)
|
||||||
|
.map_err(|e| e.add_ifname(ifname))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: NotListening> AggregateInterface<T> {
|
||||||
|
pub fn stream(self) -> error::Result<AggregateInterfaceStream<DevActivated>> {
|
||||||
|
Ok(AggregateInterfaceStream {
|
||||||
|
streams: self
|
||||||
|
.interfaces
|
||||||
|
.into_iter()
|
||||||
|
.map(|(ifname, interface)| {
|
||||||
|
let new_name = ifname.clone();
|
||||||
|
interface
|
||||||
|
.stream()
|
||||||
|
.map(|stream| (ifname, stream))
|
||||||
|
.map_err(|e| e.add_ifname(&new_name))
|
||||||
|
})
|
||||||
|
.collect::<error::Result<_>>()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct AggregateInterfaceStream<T: Activated> {
|
||||||
|
streams: StreamMap<String, InterfaceStream<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Activated> AggregateInterfaceStream<T> {
|
||||||
|
pub fn get_ifnames(&self) -> Vec<&str> {
|
||||||
|
self.streams.keys().map(|n| &**n).collect::<_>()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sendpacket(&mut self, ifname: &str, packet: packets::EthernetPkt) -> error::Result<()> {
|
||||||
|
if let Some(interface) = self.streams.values_mut().find(|interface| {
|
||||||
|
interface.inner.get_ref().interface.dev_name.as_bytes() == ifname.as_bytes()
|
||||||
|
}) {
|
||||||
|
interface.sendpacket(packet)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Activated> futures::Stream for AggregateInterfaceStream<T> {
|
||||||
|
type Item = (String, error::Result<packets::EthernetPacket>);
|
||||||
|
|
||||||
|
fn poll_next(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll<Option<Self::Item>> {
|
||||||
|
self.streams.poll_next_unpin(cx)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
[toolchain]
|
[toolchain]
|
||||||
channel = "stable"
|
channel = "stable"
|
||||||
components = [ "rustfmt", "rust-std", "rustc-dev" ]
|
components = []
|
||||||
targets = [ "x86_64-pc-windows-gnu", "x86_64-unknown-linux-musl" ]
|
targets = [ "x86_64-pc-windows-gnu", "x86_64-unknown-linux-musl" ]
|
||||||
profile = "minimal"
|
profile = "minimal"
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
|
use std::net::{Ipv4Addr, SocketAddrV4, UdpSocket};
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "pcap")]
|
||||||
use std::{sync::Arc, thread};
|
use std::{sync::Arc, thread};
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "pcap")]
|
||||||
use anyhow::{anyhow, bail};
|
use anyhow::{anyhow, bail};
|
||||||
|
|
||||||
use packets::{self, EthernetPkt};
|
use packets::{self, EthernetPkt};
|
||||||
@ -17,7 +17,7 @@ pub enum Interface {
|
|||||||
impl Interface {
|
impl Interface {
|
||||||
pub fn new(ttype: TransportType, port: u16) -> anyhow::Result<Interface> {
|
pub fn new(ttype: TransportType, port: u16) -> anyhow::Result<Interface> {
|
||||||
match ttype {
|
match ttype {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "pcap")]
|
||||||
TransportType::RawUdp => {
|
TransportType::RawUdp => {
|
||||||
let mut interfaces = pcap_sys::PcapDevIterator::new()?;
|
let mut interfaces = pcap_sys::PcapDevIterator::new()?;
|
||||||
let interface_name = interfaces
|
let interface_name = interfaces
|
||||||
@ -52,7 +52,7 @@ impl Interface {
|
|||||||
retry!(interface.set_promisc(false));
|
retry!(interface.set_promisc(false));
|
||||||
retry!(interface.set_timeout(10));
|
retry!(interface.set_timeout(10));
|
||||||
|
|
||||||
let mut interface = retry!(interface.activate());
|
let interface = retry!(interface.activate());
|
||||||
|
|
||||||
retry!(interface.set_filter(&format!("inbound and port {port}"), true, None));
|
retry!(interface.set_filter(&format!("inbound and port {port}"), true, None));
|
||||||
|
|
||||||
@ -65,7 +65,7 @@ impl Interface {
|
|||||||
|
|
||||||
Ok(Interface::RawUdp(interface, port))
|
Ok(Interface::RawUdp(interface, port))
|
||||||
}
|
}
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(not(feature = "pcap"))]
|
||||||
TransportType::RawUdp => {
|
TransportType::RawUdp => {
|
||||||
panic!("transport not available!");
|
panic!("transport not available!");
|
||||||
}
|
}
|
||||||
@ -78,7 +78,7 @@ impl Interface {
|
|||||||
|
|
||||||
pub fn split(self) -> anyhow::Result<(InterfaceSender, InterfaceReceiver)> {
|
pub fn split(self) -> anyhow::Result<(InterfaceSender, InterfaceReceiver)> {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "pcap")]
|
||||||
Self::RawUdp(interface, _) => {
|
Self::RawUdp(interface, _) => {
|
||||||
let arc = Arc::new(interface);
|
let arc = Arc::new(interface);
|
||||||
Ok((
|
Ok((
|
||||||
@ -98,7 +98,7 @@ impl Interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum InterfaceSender {
|
pub enum InterfaceSender {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "pcap")]
|
||||||
RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>),
|
RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>),
|
||||||
Udp(UdpSocket),
|
Udp(UdpSocket),
|
||||||
}
|
}
|
||||||
@ -106,7 +106,7 @@ pub enum InterfaceSender {
|
|||||||
impl InterfaceSender {
|
impl InterfaceSender {
|
||||||
pub fn sendpacket(&self, packet: EthernetPkt) -> anyhow::Result<()> {
|
pub fn sendpacket(&self, packet: EthernetPkt) -> anyhow::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "pcap")]
|
||||||
Self::RawUdp(interf) => Ok(interf.sendpacket(packet)?),
|
Self::RawUdp(interf) => Ok(interf.sendpacket(packet)?),
|
||||||
Self::Udp(interf) => {
|
Self::Udp(interf) => {
|
||||||
use packets::*;
|
use packets::*;
|
||||||
@ -128,7 +128,7 @@ impl InterfaceSender {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum InterfaceReceiver {
|
pub enum InterfaceReceiver {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "pcap")]
|
||||||
RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>),
|
RawUdp(Arc<pcap_sys::Interface<pcap_sys::DevActivated>>),
|
||||||
Udp(UdpSocket, u16),
|
Udp(UdpSocket, u16),
|
||||||
}
|
}
|
||||||
@ -139,7 +139,7 @@ impl InterfaceReceiver {
|
|||||||
F: FnMut(packets::EthernetPacket) -> anyhow::Result<()>,
|
F: FnMut(packets::EthernetPacket) -> anyhow::Result<()>,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "pcap")]
|
||||||
Self::RawUdp(interf) => interf.listen(
|
Self::RawUdp(interf) => interf.listen(
|
||||||
move |_, packet| {
|
move |_, packet| {
|
||||||
let _ = (f)(packet.to_owned());
|
let _ = (f)(packet.to_owned());
|
||||||
@ -176,7 +176,7 @@ impl InterfaceReceiver {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(feature = "pcap")]
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user