chore: run cargo fmt
This commit is contained in:
parent
798eda764f
commit
978d7cb089
@ -1,12 +1,12 @@
|
|||||||
use std::process::Stdio;
|
|
||||||
use std::{sync::Arc, ffi::OsStr};
|
|
||||||
use std::os::unix::ffi::OsStrExt;
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
use std::process::Stdio;
|
||||||
|
use std::{ffi::OsStr, sync::Arc};
|
||||||
|
|
||||||
use tokio::{self, sync::mpsc, process, io::AsyncReadExt};
|
use anyhow::{anyhow, bail, Context};
|
||||||
use tokio_stream::StreamExt;
|
use ed25519_dalek::{PublicKey, Signature, Verifier};
|
||||||
use pcap_sys::{self, packets::EthernetPacket};
|
use pcap_sys::{self, packets::EthernetPacket};
|
||||||
use anyhow::{Context, anyhow, bail};
|
use tokio::{self, io::AsyncReadExt, process, sync::mpsc};
|
||||||
use ed25519_dalek::{PublicKey, Verifier, Signature};
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
const PUBKEY: &[u8] = include_bytes!("../../key-generator/pubkey");
|
const PUBKEY: &[u8] = include_bytes!("../../key-generator/pubkey");
|
||||||
|
|
||||||
@ -14,7 +14,8 @@ const PUBKEY: &[u8] = include_bytes!("../../key-generator/pubkey");
|
|||||||
async fn main() -> anyhow::Result<()> {
|
async fn main() -> anyhow::Result<()> {
|
||||||
simple_logger::SimpleLogger::new().init()?;
|
simple_logger::SimpleLogger::new().init()?;
|
||||||
|
|
||||||
let pubkey = Arc::new(PublicKey::from_bytes(PUBKEY).context("could not parse generated public key")?);
|
let pubkey =
|
||||||
|
Arc::new(PublicKey::from_bytes(PUBKEY).context("could not parse generated public key")?);
|
||||||
|
|
||||||
log::info!("Pubkey is good");
|
log::info!("Pubkey is good");
|
||||||
|
|
||||||
@ -41,7 +42,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
enum EventType {
|
enum EventType {
|
||||||
Packet(Result<EthernetPacket, pcap_sys::error::Error>),
|
Packet(Result<EthernetPacket, pcap_sys::error::Error>),
|
||||||
Send(EthernetPacket)
|
Send(EthernetPacket),
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut packets = interface.stream()?;
|
let mut packets = interface.stream()?;
|
||||||
@ -57,7 +58,8 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
let packet_sender_clone = packet_sender.clone();
|
let packet_sender_clone = packet_sender.clone();
|
||||||
let pubkey_clone = pubkey.clone();
|
let pubkey_clone = pubkey.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
if let Err(e) = handle_command(pubkey_clone, pkt, packet_sender_clone).await {
|
if let Err(e) = handle_command(pubkey_clone, pkt, packet_sender_clone).await
|
||||||
|
{
|
||||||
log::warn!("Error handling packet: {e}");
|
log::warn!("Error handling packet: {e}");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -75,7 +77,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
async fn handle_command(
|
async fn handle_command(
|
||||||
pubkey: Arc<PublicKey>,
|
pubkey: Arc<PublicKey>,
|
||||||
eth: EthernetPacket,
|
eth: EthernetPacket,
|
||||||
send_response: mpsc::Sender<EthernetPacket>
|
send_response: mpsc::Sender<EthernetPacket>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
use pcap_sys::packets::*;
|
use pcap_sys::packets::*;
|
||||||
let eth_pkt = eth.pkt();
|
let eth_pkt = eth.pkt();
|
||||||
@ -96,7 +98,9 @@ async fn handle_command(
|
|||||||
|
|
||||||
let cmd = &data[64..];
|
let cmd = &data[64..];
|
||||||
|
|
||||||
pubkey.verify(cmd, &signature).context("message provided was unauthenticated")?;
|
pubkey
|
||||||
|
.verify(cmd, &signature)
|
||||||
|
.context("message provided was unauthenticated")?;
|
||||||
|
|
||||||
let cmd = OsStr::from_bytes(cmd);
|
let cmd = OsStr::from_bytes(cmd);
|
||||||
|
|
||||||
@ -110,12 +114,16 @@ async fn handle_command(
|
|||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()?;
|
.spawn()?;
|
||||||
|
|
||||||
let mut stdout = child.stdout.ok_or(anyhow!("could not get child process stdout"))?;
|
let mut stdout = child
|
||||||
let mut stderr = child.stderr.ok_or(anyhow!("could not get child process stdout"))?;
|
.stdout
|
||||||
|
.ok_or(anyhow!("could not get child process stdout"))?;
|
||||||
|
let mut stderr = child
|
||||||
|
.stderr
|
||||||
|
.ok_or(anyhow!("could not get child process stdout"))?;
|
||||||
|
|
||||||
enum Output {
|
enum Output {
|
||||||
Out,
|
Out,
|
||||||
Err
|
Err,
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut stdout_buffer = [0u8; 1024];
|
let mut stdout_buffer = [0u8; 1024];
|
||||||
@ -133,16 +141,24 @@ async fn handle_command(
|
|||||||
|
|
||||||
let msg = &match out_type {
|
let msg = &match out_type {
|
||||||
Output::Err => stderr_buffer,
|
Output::Err => stderr_buffer,
|
||||||
Output::Out => stdout_buffer
|
Output::Out => stdout_buffer,
|
||||||
}[..len];
|
}[..len];
|
||||||
let port = match out_type {
|
let port = match out_type {
|
||||||
Output::Err => 54249,
|
Output::Err => 54249,
|
||||||
Output::Out => 54248
|
Output::Out => 54248,
|
||||||
};
|
};
|
||||||
|
|
||||||
let udp_packet = UDPPacket::construct(54248, port, msg);
|
let udp_packet = UDPPacket::construct(54248, port, msg);
|
||||||
let ip_packet = IPv4Packet::construct(ip_pkt.dest_ip(), ip_pkt.source_ip(), &Layer4Packet::UDP(udp_packet));
|
let ip_packet = IPv4Packet::construct(
|
||||||
let eth_packet = EthernetPacket::construct(*eth_pkt.destination_address(), *eth_pkt.source_address(), &Layer3Packet::IPv4(ip_packet));
|
ip_pkt.dest_ip(),
|
||||||
|
ip_pkt.source_ip(),
|
||||||
|
&Layer4Packet::UDP(udp_packet),
|
||||||
|
);
|
||||||
|
let eth_packet = EthernetPacket::construct(
|
||||||
|
*eth_pkt.destination_address(),
|
||||||
|
*eth_pkt.source_address(),
|
||||||
|
&Layer3Packet::IPv4(ip_packet),
|
||||||
|
);
|
||||||
|
|
||||||
if let Err(e) = send_response.send(eth_packet).await {
|
if let Err(e) = send_response.send(eth_packet).await {
|
||||||
log::warn!("Could not send response packet: {e:?}");
|
log::warn!("Could not send response packet: {e:?}");
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use std::{io::prelude::*, net::UdpSocket, thread};
|
use std::{io::prelude::*, net::UdpSocket, thread};
|
||||||
|
|
||||||
use ed25519_dalek::{Keypair, Signer};
|
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
|
use ed25519_dalek::{Keypair, Signer};
|
||||||
|
|
||||||
const PUBKEY: &[u8] = include_bytes!("../../key-generator/pubkey");
|
const PUBKEY: &[u8] = include_bytes!("../../key-generator/pubkey");
|
||||||
const PRIVKEY: &[u8] = include_bytes!("../../key-generator/privkey");
|
const PRIVKEY: &[u8] = include_bytes!("../../key-generator/privkey");
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use std::{io::prelude::*, net::Ipv4Addr, collections::HashMap};
|
use std::{collections::HashMap, io::prelude::*, net::Ipv4Addr};
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use tokio::time::{Duration, interval};
|
use tokio::time::{interval, Duration};
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
|
||||||
use nl_sys::{netlink, route};
|
use nl_sys::{netlink, route};
|
||||||
@ -26,15 +26,17 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
let addrs = socket.get_addrs()?;
|
let addrs = socket.get_addrs()?;
|
||||||
|
|
||||||
routes_inner.sort_by(|r1, r2| {
|
routes_inner.sort_by(|r1, r2| {
|
||||||
r2.dst().map(|a| a.cidrlen())
|
r2.dst()
|
||||||
|
.map(|a| a.cidrlen())
|
||||||
.partial_cmp(&r1.dst().map(|a| a.cidrlen()))
|
.partial_cmp(&r1.dst().map(|a| a.cidrlen()))
|
||||||
.unwrap_or(std::cmp::Ordering::Equal)
|
.unwrap_or(std::cmp::Ordering::Equal)
|
||||||
});
|
});
|
||||||
|
|
||||||
let (ifname, srcip, srcmac, dstmac) = route::get_macs_and_src_for_ip(&addrs, &routes, &neighs, &links, target)
|
let (ifname, srcip, srcmac, dstmac) =
|
||||||
|
route::get_macs_and_src_for_ip(&addrs, &routes, &neighs, &links, target)
|
||||||
.ok_or(anyhow!("unable to find a route to the IP"))?;
|
.ok_or(anyhow!("unable to find a route to the IP"))?;
|
||||||
|
|
||||||
( ifname, srcmac, dstmac, srcip )
|
(ifname, srcmac, dstmac, srcip)
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut interface = pcap_sys::new_aggregate_interface(false)?;
|
let mut interface = pcap_sys::new_aggregate_interface(false)?;
|
||||||
@ -52,7 +54,7 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
enum EventType {
|
enum EventType {
|
||||||
Packet((String, Result<EthernetPacket, pcap_sys::error::Error>)),
|
Packet((String, Result<EthernetPacket, pcap_sys::error::Error>)),
|
||||||
Update
|
Update,
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut packets = interface.stream()?;
|
let mut packets = interface.stream()?;
|
||||||
@ -86,9 +88,12 @@ async fn main() -> anyhow::Result<()> {
|
|||||||
current_packet_id += 1;
|
current_packet_id += 1;
|
||||||
sent_updates.insert(current_packet_id, false);
|
sent_updates.insert(current_packet_id, false);
|
||||||
|
|
||||||
let udp_packet = UDPPacket::construct(54248, 54248, current_packet_id.to_be_bytes().to_vec());
|
let udp_packet =
|
||||||
let ip_packet = IPv4Packet::construct(srcip, target, &Layer4Packet::UDP(udp_packet));
|
UDPPacket::construct(54248, 54248, current_packet_id.to_be_bytes().to_vec());
|
||||||
let eth_packet = EthernetPacket::construct(src_mac, dst_mac, &Layer3Packet::IPv4(ip_packet));
|
let ip_packet =
|
||||||
|
IPv4Packet::construct(srcip, target, &Layer4Packet::UDP(udp_packet));
|
||||||
|
let eth_packet =
|
||||||
|
EthernetPacket::construct(src_mac, dst_mac, &Layer3Packet::IPv4(ip_packet));
|
||||||
|
|
||||||
packets.sendpacket(&ifname, eth_packet.pkt())?;
|
packets.sendpacket(&ifname, eth_packet.pkt())?;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,13 +14,9 @@
|
|||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
cc::Build::new()
|
cc::Build::new().file("src/bridge.c").compile("bridge");
|
||||||
.file("src/bridge.c")
|
|
||||||
.compile("bridge");
|
|
||||||
|
|
||||||
let dst = autotools::Config::new("libnl")
|
let dst = autotools::Config::new("libnl").reconf("-vi").build();
|
||||||
.reconf("-vi")
|
|
||||||
.build();
|
|
||||||
|
|
||||||
println!("cargo:rustc-link-search=native={}/lib", dst.display());
|
println!("cargo:rustc-link-search=native={}/lib", dst.display());
|
||||||
println!("cargo:rustc-link-lib=static=nl-3");
|
println!("cargo:rustc-link-lib=static=nl-3");
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{fmt::Display, ffi::CStr};
|
use std::{ffi::CStr, fmt::Display};
|
||||||
|
|
||||||
use libc::c_int;
|
use libc::c_int;
|
||||||
|
|
||||||
|
|||||||
@ -13,10 +13,10 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
pub mod nl_ffi;
|
|
||||||
pub mod netlink;
|
|
||||||
pub mod route;
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
pub mod netlink;
|
||||||
|
pub mod nl_ffi;
|
||||||
|
pub mod route;
|
||||||
|
|
||||||
// from bridge.c
|
// from bridge.c
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@ -13,22 +13,28 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{ptr, marker::PhantomData};
|
use std::{marker::PhantomData, ptr};
|
||||||
|
|
||||||
use libc::{AF_UNSPEC, AF_INET};
|
use libc::{AF_INET, AF_UNSPEC};
|
||||||
|
|
||||||
use crate::{nl_ffi::*, error, route::{Link, Neigh, Route, RtAddr}};
|
use crate::{
|
||||||
|
error,
|
||||||
|
nl_ffi::*,
|
||||||
|
route::{Link, Neigh, Route, RtAddr},
|
||||||
|
};
|
||||||
|
|
||||||
/// A netlink socket used to communicate with the kernel
|
/// A netlink socket used to communicate with the kernel
|
||||||
pub struct Socket {
|
pub struct Socket {
|
||||||
pub(crate) sock: *mut nl_sock
|
pub(crate) sock: *mut nl_sock,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Socket {
|
impl Socket {
|
||||||
/// Establish a new connection with the Linux kernel
|
/// Establish a new connection with the Linux kernel
|
||||||
pub fn new() -> error::Result<Self> {
|
pub fn new() -> error::Result<Self> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let sock = Socket { sock: nl_socket_alloc() };
|
let sock = Socket {
|
||||||
|
sock: nl_socket_alloc(),
|
||||||
|
};
|
||||||
|
|
||||||
let ret = nl_connect(sock.sock, crate::netlink_route());
|
let ret = nl_connect(sock.sock, crate::netlink_route());
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
@ -51,7 +57,7 @@ impl Socket {
|
|||||||
|
|
||||||
Ok(Cache {
|
Ok(Cache {
|
||||||
cache: link_cache,
|
cache: link_cache,
|
||||||
dt: PhantomData
|
dt: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -68,7 +74,7 @@ impl Socket {
|
|||||||
|
|
||||||
Ok(Cache {
|
Ok(Cache {
|
||||||
cache: neigh_cache,
|
cache: neigh_cache,
|
||||||
dt: PhantomData
|
dt: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -85,7 +91,7 @@ impl Socket {
|
|||||||
|
|
||||||
Ok(Cache {
|
Ok(Cache {
|
||||||
cache: route_cache,
|
cache: route_cache,
|
||||||
dt: PhantomData
|
dt: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,7 +108,7 @@ impl Socket {
|
|||||||
|
|
||||||
Ok(Cache {
|
Ok(Cache {
|
||||||
cache: addr_cache,
|
cache: addr_cache,
|
||||||
dt: PhantomData
|
dt: PhantomData,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,23 +139,21 @@ pub fn get_link_by_index(cache: &Cache<Link>, index: i32) -> Option<Link> {
|
|||||||
/// collection of nl_objects
|
/// collection of nl_objects
|
||||||
pub struct Cache<T>
|
pub struct Cache<T>
|
||||||
where
|
where
|
||||||
T: From<*mut nl_object>
|
T: From<*mut nl_object>,
|
||||||
{
|
{
|
||||||
pub(crate) cache: *mut nl_cache,
|
pub(crate) cache: *mut nl_cache,
|
||||||
dt: PhantomData<T>
|
dt: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: From<*mut nl_object>> Cache<T> {
|
impl<T: From<*mut nl_object>> Cache<T> {
|
||||||
pub fn iter(&self) -> CacheIter<'_, T> {
|
pub fn iter(&self) -> CacheIter<'_, T> {
|
||||||
let cache_size = unsafe {
|
let cache_size = unsafe { nl_cache_nitems(self.cache) } as usize;
|
||||||
nl_cache_nitems(self.cache)
|
|
||||||
} as usize;
|
|
||||||
|
|
||||||
CacheIter {
|
CacheIter {
|
||||||
obj: unsafe { nl_cache_get_first(self.cache) },
|
obj: unsafe { nl_cache_get_first(self.cache) },
|
||||||
cache_size,
|
cache_size,
|
||||||
index: 0,
|
index: 0,
|
||||||
item_type: PhantomData {}
|
item_type: PhantomData {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use libc::{c_int, c_void, c_char, c_uint};
|
use libc::{c_char, c_int, c_uint, c_void};
|
||||||
|
|
||||||
macro_rules! nl_obj {
|
macro_rules! nl_obj {
|
||||||
($name:ident) => {
|
($name:ident) => {
|
||||||
@ -23,7 +23,7 @@ macro_rules! nl_obj {
|
|||||||
_data: [u8; 0],
|
_data: [u8; 0],
|
||||||
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
|
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
nl_obj!(nl_sock);
|
nl_obj!(nl_sock);
|
||||||
@ -56,7 +56,11 @@ extern "C" {
|
|||||||
pub fn nl_addr_get_family(addr: *mut nl_addr) -> c_int;
|
pub fn nl_addr_get_family(addr: *mut nl_addr) -> c_int;
|
||||||
pub fn nl_addr_get_prefixlen(addr: *mut nl_addr) -> c_uint;
|
pub fn nl_addr_get_prefixlen(addr: *mut nl_addr) -> c_uint;
|
||||||
|
|
||||||
pub fn nl_cache_foreach(cache: *mut nl_cache, cb: extern "C" fn(*mut nl_object, *mut c_void), arg: *mut c_void) -> c_void;
|
pub fn nl_cache_foreach(
|
||||||
|
cache: *mut nl_cache,
|
||||||
|
cb: extern "C" fn(*mut nl_object, *mut c_void),
|
||||||
|
arg: *mut c_void,
|
||||||
|
) -> c_void;
|
||||||
pub fn nl_cache_put(cache: *mut nl_cache) -> c_void;
|
pub fn nl_cache_put(cache: *mut nl_cache) -> c_void;
|
||||||
pub fn nl_cache_nitems(cache: *mut nl_cache) -> c_int;
|
pub fn nl_cache_nitems(cache: *mut nl_cache) -> c_int;
|
||||||
pub fn nl_cache_get_first(cache: *mut nl_cache) -> *mut nl_object;
|
pub fn nl_cache_get_first(cache: *mut nl_cache) -> *mut nl_object;
|
||||||
@ -69,19 +73,32 @@ extern "C" {
|
|||||||
pub fn rtnl_addr_get_local(addr: *mut rtnl_addr) -> *mut nl_addr;
|
pub fn rtnl_addr_get_local(addr: *mut rtnl_addr) -> *mut nl_addr;
|
||||||
|
|
||||||
pub fn rtnl_neigh_alloc_cache(sock: *mut nl_sock, result: *mut *mut nl_cache) -> c_int;
|
pub fn rtnl_neigh_alloc_cache(sock: *mut nl_sock, result: *mut *mut nl_cache) -> c_int;
|
||||||
pub fn rtnl_neigh_get(cache: *mut nl_cache, ifindex: c_int, dst: *mut nl_addr) -> *mut rtnl_neigh;
|
pub fn rtnl_neigh_get(
|
||||||
|
cache: *mut nl_cache,
|
||||||
|
ifindex: c_int,
|
||||||
|
dst: *mut nl_addr,
|
||||||
|
) -> *mut rtnl_neigh;
|
||||||
pub fn rtnl_neigh_get_dst(neigh: *mut rtnl_neigh) -> *mut nl_addr;
|
pub fn rtnl_neigh_get_dst(neigh: *mut rtnl_neigh) -> *mut nl_addr;
|
||||||
pub fn rtnl_neigh_get_lladdr(neigh: *mut rtnl_neigh) -> *mut nl_addr;
|
pub fn rtnl_neigh_get_lladdr(neigh: *mut rtnl_neigh) -> *mut nl_addr;
|
||||||
pub fn rtnl_neigh_get_ifindex(neigh: *mut rtnl_neigh) -> c_int;
|
pub fn rtnl_neigh_get_ifindex(neigh: *mut rtnl_neigh) -> c_int;
|
||||||
|
|
||||||
pub fn rtnl_link_get(cache: *mut nl_cache, index: c_int) -> *mut rtnl_link;
|
pub fn rtnl_link_get(cache: *mut nl_cache, index: c_int) -> *mut rtnl_link;
|
||||||
pub fn rtnl_link_alloc_cache(sock: *mut nl_sock, family: c_int, result: *mut *mut nl_cache) -> c_int;
|
pub fn rtnl_link_alloc_cache(
|
||||||
|
sock: *mut nl_sock,
|
||||||
|
family: c_int,
|
||||||
|
result: *mut *mut nl_cache,
|
||||||
|
) -> c_int;
|
||||||
pub fn rtnl_link_get_addr(link: *mut rtnl_link) -> *mut nl_addr;
|
pub fn rtnl_link_get_addr(link: *mut rtnl_link) -> *mut nl_addr;
|
||||||
pub fn rtnl_link_get_name(link: *mut rtnl_link) -> *const c_char;
|
pub fn rtnl_link_get_name(link: *mut rtnl_link) -> *const c_char;
|
||||||
pub fn rtnl_link_get_ifindex(link: *mut rtnl_link) -> c_int;
|
pub fn rtnl_link_get_ifindex(link: *mut rtnl_link) -> c_int;
|
||||||
pub fn rtnl_link_get_type(link: *mut rtnl_link) -> *const c_char;
|
pub fn rtnl_link_get_type(link: *mut rtnl_link) -> *const c_char;
|
||||||
|
|
||||||
pub fn rtnl_route_alloc_cache(sock: *mut nl_sock, family: c_int, flags: c_int, result: *mut *mut nl_cache) -> c_int;
|
pub fn rtnl_route_alloc_cache(
|
||||||
|
sock: *mut nl_sock,
|
||||||
|
family: c_int,
|
||||||
|
flags: c_int,
|
||||||
|
result: *mut *mut nl_cache,
|
||||||
|
) -> c_int;
|
||||||
pub fn rtnl_route_get_src(route: *mut rtnl_route) -> *mut nl_addr;
|
pub fn rtnl_route_get_src(route: *mut rtnl_route) -> *mut nl_addr;
|
||||||
pub fn rtnl_route_get_dst(route: *mut rtnl_route) -> *mut nl_addr;
|
pub fn rtnl_route_get_dst(route: *mut rtnl_route) -> *mut nl_addr;
|
||||||
pub fn rtnl_route_get_iif(route: *mut rtnl_route) -> c_int;
|
pub fn rtnl_route_get_iif(route: *mut rtnl_route) -> c_int;
|
||||||
|
|||||||
@ -13,17 +13,24 @@
|
|||||||
// You should have received a copy of the GNU Affero General Public License
|
// 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/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
use std::{ffi::{CStr, CString}, net::Ipv4Addr, fmt::Debug};
|
use std::{
|
||||||
|
ffi::{CStr, CString},
|
||||||
|
fmt::Debug,
|
||||||
|
net::Ipv4Addr,
|
||||||
|
};
|
||||||
|
|
||||||
use libc::{c_int, AF_INET, c_uint};
|
use libc::{c_int, c_uint, AF_INET};
|
||||||
|
|
||||||
use crate::{error, netlink::{Cache, self}};
|
use crate::{
|
||||||
|
error,
|
||||||
|
netlink::{self, Cache},
|
||||||
|
};
|
||||||
|
|
||||||
use super::nl_ffi::*;
|
use super::nl_ffi::*;
|
||||||
|
|
||||||
/// Represents an address assigned to a link
|
/// Represents an address assigned to a link
|
||||||
pub struct RtAddr {
|
pub struct RtAddr {
|
||||||
addr: *mut rtnl_addr
|
addr: *mut rtnl_addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RtAddr {
|
impl RtAddr {
|
||||||
@ -50,14 +57,15 @@ impl RtAddr {
|
|||||||
|
|
||||||
impl From<*mut nl_object> for RtAddr {
|
impl From<*mut nl_object> for RtAddr {
|
||||||
fn from(value: *mut nl_object) -> Self {
|
fn from(value: *mut nl_object) -> Self {
|
||||||
RtAddr { addr: value as *mut _ }
|
RtAddr {
|
||||||
|
addr: value as *mut _,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Represents a network link, which can represent a network device
|
/// Represents a network link, which can represent a network device
|
||||||
pub struct Link {
|
pub struct Link {
|
||||||
pub(crate) link: *mut rtnl_link
|
pub(crate) link: *mut rtnl_link,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Link {
|
impl Link {
|
||||||
@ -74,7 +82,9 @@ impl Link {
|
|||||||
/// representing MAC addresses or IP addresses
|
/// representing MAC addresses or IP addresses
|
||||||
pub fn addr(&self) -> Addr {
|
pub fn addr(&self) -> Addr {
|
||||||
unsafe {
|
unsafe {
|
||||||
Addr { addr: rtnl_link_get_addr(self.link) }
|
Addr {
|
||||||
|
addr: rtnl_link_get_addr(self.link),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -92,9 +102,7 @@ impl Link {
|
|||||||
|
|
||||||
/// Determines the index of the interface in the kernel table
|
/// Determines the index of the interface in the kernel table
|
||||||
pub fn ifindex(&self) -> c_int {
|
pub fn ifindex(&self) -> c_int {
|
||||||
unsafe {
|
unsafe { rtnl_link_get_ifindex(self.link) }
|
||||||
rtnl_link_get_ifindex(self.link)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tries to get the neighbor for this link, which can provide the destination address and the
|
/// Tries to get the neighbor for this link, which can provide the destination address and the
|
||||||
@ -114,39 +122,44 @@ impl Link {
|
|||||||
|
|
||||||
impl Debug for Link {
|
impl Debug for Link {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
f
|
f.debug_struct("Link").field("name", &self.name()).finish()
|
||||||
.debug_struct("Link")
|
|
||||||
.field("name", &self.name())
|
|
||||||
.finish()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<*mut nl_object> for Link {
|
impl From<*mut nl_object> for Link {
|
||||||
fn from(value: *mut nl_object) -> Self {
|
fn from(value: *mut nl_object) -> Self {
|
||||||
Self {
|
Self {
|
||||||
link: value as *mut _
|
link: value as *mut _,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_macs_and_src_for_ip(addrs: &Cache<RtAddr>, routes: &Cache<Route>, neighs: &Cache<Neigh>, links: &Cache<Link>, addr: Ipv4Addr) -> Option<(String, Ipv4Addr, [u8; 6], [u8; 6])> {
|
pub fn get_macs_and_src_for_ip(
|
||||||
|
addrs: &Cache<RtAddr>,
|
||||||
|
routes: &Cache<Route>,
|
||||||
|
neighs: &Cache<Neigh>,
|
||||||
|
links: &Cache<Link>,
|
||||||
|
addr: Ipv4Addr,
|
||||||
|
) -> Option<(String, Ipv4Addr, [u8; 6], [u8; 6])> {
|
||||||
let mut sorted_routes = routes.iter().collect::<Vec<_>>();
|
let mut sorted_routes = routes.iter().collect::<Vec<_>>();
|
||||||
|
|
||||||
sorted_routes.sort_by(|r1, r2| {
|
sorted_routes.sort_by(|r1, r2| {
|
||||||
r2.dst().map(|a| a.cidrlen())
|
r2.dst()
|
||||||
|
.map(|a| a.cidrlen())
|
||||||
.partial_cmp(&r1.dst().map(|a| a.cidrlen()))
|
.partial_cmp(&r1.dst().map(|a| a.cidrlen()))
|
||||||
.unwrap_or(std::cmp::Ordering::Equal)
|
.unwrap_or(std::cmp::Ordering::Equal)
|
||||||
});
|
});
|
||||||
|
|
||||||
let ip_int = u32::from(addr);
|
let ip_int = u32::from(addr);
|
||||||
|
|
||||||
let route = sorted_routes
|
let route = sorted_routes.iter().find(|route| {
|
||||||
.iter()
|
|
||||||
.find(|route| {
|
|
||||||
let Some(dst) = route.dst() else { return false };
|
let Some(dst) = route.dst() else { return false };
|
||||||
|
|
||||||
let mask = if dst.cidrlen() != 0 {
|
let mask = if dst.cidrlen() != 0 {
|
||||||
(0xFFFFFFFFu32.overflowing_shr(32 - dst.cidrlen())).0.overflowing_shl(32 - dst.cidrlen()).0
|
(0xFFFFFFFFu32.overflowing_shr(32 - dst.cidrlen()))
|
||||||
|
.0
|
||||||
|
.overflowing_shl(32 - dst.cidrlen())
|
||||||
|
.0
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
@ -157,31 +170,29 @@ pub fn get_macs_and_src_for_ip(addrs: &Cache<RtAddr>, routes: &Cache<Route>, nei
|
|||||||
(mask & dst_addr) == (mask & ip_int)
|
(mask & dst_addr) == (mask & ip_int)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let link_ind = route
|
let link_ind = route.hop_iter().next()?.ifindex();
|
||||||
.hop_iter()
|
|
||||||
.next()?
|
|
||||||
.ifindex();
|
|
||||||
|
|
||||||
let link = netlink::get_link_by_index(links, link_ind)?;
|
let link = netlink::get_link_by_index(links, link_ind)?;
|
||||||
|
|
||||||
let neigh = neighs
|
let neigh = neighs.iter().find(|n| n.ifindex() == link.ifindex())?;
|
||||||
.iter()
|
|
||||||
.find(|n| n.ifindex() == link.ifindex())?;
|
|
||||||
|
|
||||||
let srcip = addrs
|
let srcip = addrs.iter().find(|a| a.ifindex() == link.ifindex())?;
|
||||||
.iter()
|
|
||||||
.find(|a| a.ifindex() == link.ifindex())?;
|
|
||||||
|
|
||||||
Some((
|
Some((
|
||||||
link.name(),
|
link.name(),
|
||||||
(&srcip.local()?).try_into().ok()?,
|
(&srcip.local()?).try_into().ok()?,
|
||||||
link.addr().hw_address().try_into().ok()?,
|
link.addr().hw_address().try_into().ok()?,
|
||||||
neigh.lladdr().hw_address().try_into().ok()?
|
neigh.lladdr().hw_address().try_into().ok()?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the neighbor record for the source IP specified, or get the default address
|
/// Gets the neighbor record for the source IP specified, or get the default address
|
||||||
pub fn get_neigh_for_addr(routes: &Cache<Route>, neighs: &Cache<Neigh>, links: &Cache<Link>, addr: &Addr) -> Option<(Ipv4Addr, Link, [u8; 6])> {
|
pub fn get_neigh_for_addr(
|
||||||
|
routes: &Cache<Route>,
|
||||||
|
neighs: &Cache<Neigh>,
|
||||||
|
links: &Cache<Link>,
|
||||||
|
addr: &Addr,
|
||||||
|
) -> Option<(Ipv4Addr, Link, [u8; 6])> {
|
||||||
for link in links.iter() {
|
for link in links.iter() {
|
||||||
let Some(neigh) = link.get_neigh(&neighs, addr) else { continue; };
|
let Some(neigh) = link.get_neigh(&neighs, addr) else { continue; };
|
||||||
return Some((addr.try_into().ok()?, link, neigh));
|
return Some((addr.try_into().ok()?, link, neigh));
|
||||||
@ -207,8 +218,9 @@ pub fn get_neigh_for_addr(routes: &Cache<Route>, neighs: &Cache<Neigh>, links: &
|
|||||||
|
|
||||||
Some(((&first_hop.gateway()?).try_into().ok()?, link, n.lladdr()))
|
Some(((&first_hop.gateway()?).try_into().ok()?, link, n.lladdr()))
|
||||||
})
|
})
|
||||||
.next() {
|
.next()
|
||||||
return Some((laddr, link, neigh.hw_address().try_into().ok()?))
|
{
|
||||||
|
return Some((laddr, link, neigh.hw_address().try_into().ok()?));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,17 +231,12 @@ pub fn get_neigh_for_addr(routes: &Cache<Route>, neighs: &Cache<Neigh>, links: &
|
|||||||
pub fn get_default_route(routes: &Cache<Route>) -> Option<Route> {
|
pub fn get_default_route(routes: &Cache<Route>) -> Option<Route> {
|
||||||
routes
|
routes
|
||||||
.iter()
|
.iter()
|
||||||
.find(|r|
|
.find(|r| r.dst().map(|a| a.cidrlen()).unwrap_or(33) == 0)
|
||||||
r
|
|
||||||
.dst()
|
|
||||||
.map(|a| a.cidrlen())
|
|
||||||
.unwrap_or(33) == 0
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A struct representing the neighbor of a link
|
/// A struct representing the neighbor of a link
|
||||||
pub struct Neigh {
|
pub struct Neigh {
|
||||||
neigh: *mut rtnl_neigh
|
neigh: *mut rtnl_neigh,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Neigh {
|
impl Neigh {
|
||||||
@ -250,16 +257,14 @@ impl Neigh {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn ifindex(&self) -> i32 {
|
pub fn ifindex(&self) -> i32 {
|
||||||
unsafe {
|
unsafe { rtnl_neigh_get_ifindex(self.neigh) }
|
||||||
rtnl_neigh_get_ifindex(self.neigh)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<*mut nl_object> for Neigh {
|
impl From<*mut nl_object> for Neigh {
|
||||||
fn from(value: *mut nl_object) -> Self {
|
fn from(value: *mut nl_object) -> Self {
|
||||||
Self {
|
Self {
|
||||||
neigh: value as *mut _
|
neigh: value as *mut _,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,15 +272,13 @@ impl From<*mut nl_object> for Neigh {
|
|||||||
/// Represents "an address"
|
/// Represents "an address"
|
||||||
/// IPv4? IPv6? MAC? Whatever the "any" or "lo" devices use? Yes!
|
/// IPv4? IPv6? MAC? Whatever the "any" or "lo" devices use? Yes!
|
||||||
pub struct Addr {
|
pub struct Addr {
|
||||||
addr: *mut nl_addr
|
addr: *mut nl_addr,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Addr {
|
impl Addr {
|
||||||
/// Returns the number of bytes that are in the address
|
/// Returns the number of bytes that are in the address
|
||||||
pub fn len(&self) -> u32 {
|
pub fn len(&self) -> u32 {
|
||||||
unsafe {
|
unsafe { nl_addr_get_len(self.addr) }
|
||||||
nl_addr_get_len(self.addr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the address, which can be interpreted based on the results of [`Addr::atype`]
|
/// Returns the address, which can be interpreted based on the results of [`Addr::atype`]
|
||||||
@ -290,16 +293,12 @@ impl Addr {
|
|||||||
|
|
||||||
// Determines the type of data in [`Addr::hw_address`]
|
// Determines the type of data in [`Addr::hw_address`]
|
||||||
pub fn atype(&self) -> c_int {
|
pub fn atype(&self) -> c_int {
|
||||||
unsafe {
|
unsafe { nl_addr_get_family(self.addr) }
|
||||||
nl_addr_get_family(self.addr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the length of the subnet mask applying to this address
|
/// Returns the length of the subnet mask applying to this address
|
||||||
pub fn cidrlen(&self) -> c_uint {
|
pub fn cidrlen(&self) -> c_uint {
|
||||||
unsafe {
|
unsafe { nl_addr_get_prefixlen(self.addr) }
|
||||||
nl_addr_get_prefixlen(self.addr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,18 +307,25 @@ impl Debug for Addr {
|
|||||||
match self.atype() {
|
match self.atype() {
|
||||||
AF_INET => {
|
AF_INET => {
|
||||||
let octets = self.hw_address();
|
let octets = self.hw_address();
|
||||||
f
|
f.debug_struct("Addr")
|
||||||
.debug_struct("Addr")
|
.field(
|
||||||
.field("addr", &format!("{}.{}.{}.{}/{}", octets[0], octets[1], octets[2], octets[3], self.cidrlen()))
|
"addr",
|
||||||
|
&format!(
|
||||||
|
"{}.{}.{}.{}/{}",
|
||||||
|
octets[0],
|
||||||
|
octets[1],
|
||||||
|
octets[2],
|
||||||
|
octets[3],
|
||||||
|
self.cidrlen()
|
||||||
|
),
|
||||||
|
)
|
||||||
.finish()
|
.finish()
|
||||||
},
|
}
|
||||||
_ => {
|
_ => f
|
||||||
f
|
|
||||||
.debug_struct("Addr")
|
.debug_struct("Addr")
|
||||||
.field("addr", &self.hw_address())
|
.field("addr", &self.hw_address())
|
||||||
.field("atype", &self.atype())
|
.field("atype", &self.atype())
|
||||||
.finish()
|
.finish(),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -353,7 +359,7 @@ impl TryFrom<&Addr> for Ipv4Addr {
|
|||||||
|
|
||||||
/// Represents a route in the kernel routing table
|
/// Represents a route in the kernel routing table
|
||||||
pub struct Route {
|
pub struct Route {
|
||||||
route: *mut rtnl_route
|
route: *mut rtnl_route,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Route {
|
impl Route {
|
||||||
@ -385,9 +391,7 @@ impl Route {
|
|||||||
|
|
||||||
/// Returns the amount of hops are in this route
|
/// Returns the amount of hops are in this route
|
||||||
pub fn nexthop_len(&self) -> c_int {
|
pub fn nexthop_len(&self) -> c_int {
|
||||||
unsafe {
|
unsafe { rtnl_route_get_nnexthops(self.route) }
|
||||||
rtnl_route_get_nnexthops(self.route)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the hop at the index specify
|
/// Gets the hop at the index specify
|
||||||
@ -403,21 +407,24 @@ impl Route {
|
|||||||
|
|
||||||
/// Returns an iterator representing all the hops for this route
|
/// Returns an iterator representing all the hops for this route
|
||||||
pub fn hop_iter(&self) -> NexthopIter<'_> {
|
pub fn hop_iter(&self) -> NexthopIter<'_> {
|
||||||
NexthopIter { route: &self, index: 0 }
|
NexthopIter {
|
||||||
|
route: &self,
|
||||||
|
index: 0,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<*mut nl_object> for Route {
|
impl From<*mut nl_object> for Route {
|
||||||
fn from(value: *mut nl_object) -> Self {
|
fn from(value: *mut nl_object) -> Self {
|
||||||
Route {
|
Route {
|
||||||
route: value as *mut _
|
route: value as *mut _,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents the hops of a network route
|
/// Represents the hops of a network route
|
||||||
pub struct Nexthop {
|
pub struct Nexthop {
|
||||||
nexthop: *mut rtnl_nexthop
|
nexthop: *mut rtnl_nexthop,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Nexthop {
|
impl Nexthop {
|
||||||
@ -436,16 +443,14 @@ impl Nexthop {
|
|||||||
|
|
||||||
/// Returns the interface index for this network hop
|
/// Returns the interface index for this network hop
|
||||||
pub fn ifindex(&self) -> i32 {
|
pub fn ifindex(&self) -> i32 {
|
||||||
unsafe {
|
unsafe { rtnl_route_nh_get_ifindex(self.nexthop) }
|
||||||
rtnl_route_nh_get_ifindex(self.nexthop)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An iterator for working with route hops
|
/// An iterator for working with route hops
|
||||||
pub struct NexthopIter<'a> {
|
pub struct NexthopIter<'a> {
|
||||||
route: &'a Route,
|
route: &'a Route,
|
||||||
index: i32
|
index: i32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Iterator for NexthopIter<'_> {
|
impl Iterator for NexthopIter<'_> {
|
||||||
@ -464,7 +469,10 @@ impl Iterator for NexthopIter<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||||
(self.route.nexthop_len() as usize, Some(self.route.nexthop_len() as usize))
|
(
|
||||||
|
self.route.nexthop_len() as usize,
|
||||||
|
Some(self.route.nexthop_len() as usize),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,7 +481,8 @@ pub fn get_srcip_for_dstip(routes: &Cache<Route>, ip: Ipv4Addr) -> Option<Ipv4Ad
|
|||||||
let mut sorted_routes = routes.iter().collect::<Vec<_>>();
|
let mut sorted_routes = routes.iter().collect::<Vec<_>>();
|
||||||
|
|
||||||
sorted_routes.sort_by(|r1, r2| {
|
sorted_routes.sort_by(|r1, r2| {
|
||||||
r2.dst().map(|a| a.cidrlen())
|
r2.dst()
|
||||||
|
.map(|a| a.cidrlen())
|
||||||
.partial_cmp(&r1.dst().map(|a| a.cidrlen()))
|
.partial_cmp(&r1.dst().map(|a| a.cidrlen()))
|
||||||
.unwrap_or(std::cmp::Ordering::Equal)
|
.unwrap_or(std::cmp::Ordering::Equal)
|
||||||
});
|
});
|
||||||
@ -486,7 +495,10 @@ pub fn get_srcip_for_dstip(routes: &Cache<Route>, ip: Ipv4Addr) -> Option<Ipv4Ad
|
|||||||
let Some(dst) = route.dst() else { return false };
|
let Some(dst) = route.dst() else { return false };
|
||||||
|
|
||||||
let mask = if dst.cidrlen() != 0 {
|
let mask = if dst.cidrlen() != 0 {
|
||||||
(0xFFFFFFFFu32.overflowing_shr(32 - dst.cidrlen())).0.overflowing_shl(32 - dst.cidrlen()).0
|
(0xFFFFFFFFu32.overflowing_shr(32 - dst.cidrlen()))
|
||||||
|
.0
|
||||||
|
.overflowing_shl(32 - dst.cidrlen())
|
||||||
|
.0
|
||||||
} else {
|
} else {
|
||||||
0
|
0
|
||||||
};
|
};
|
||||||
|
|||||||
@ -16,7 +16,9 @@
|
|||||||
use errno::Errno;
|
use errno::Errno;
|
||||||
use std::{
|
use std::{
|
||||||
convert::From,
|
convert::From,
|
||||||
ffi::{self, CStr, CString}, fmt::Display, error,
|
error,
|
||||||
|
ffi::{self, CStr, CString},
|
||||||
|
fmt::Display,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -42,17 +44,20 @@ impl Display for Error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "unknown pcap error")
|
write!(f, "unknown pcap error")
|
||||||
},
|
}
|
||||||
Error::PcapErrorIf(ifname, err) => {
|
Error::PcapErrorIf(ifname, err) => {
|
||||||
if let Ok(err_str) = std::str::from_utf8(err.as_bytes()) {
|
if let Ok(err_str) = std::str::from_utf8(err.as_bytes()) {
|
||||||
return write!(f, "pcap error on interface {ifname}: {err_str}");
|
return write!(f, "pcap error on interface {ifname}: {err_str}");
|
||||||
}
|
}
|
||||||
|
|
||||||
write!(f, "unknown pcap error with interface {ifname}")
|
write!(f, "unknown pcap error with interface {ifname}")
|
||||||
},
|
}
|
||||||
Error::StringParse => write!(f, "unable to parse a string from pcap"),
|
Error::StringParse => write!(f, "unable to parse a string from pcap"),
|
||||||
Error::UnknownPacketType(ptype) => write!(f, "unknown packet type ({ptype})"),
|
Error::UnknownPacketType(ptype) => write!(f, "unknown packet type ({ptype})"),
|
||||||
Error::PacketLengthInvalid => write!(f, "received a packet with a length that mismatched the header"),
|
Error::PacketLengthInvalid => write!(
|
||||||
|
f,
|
||||||
|
"received a packet with a length that mismatched the header"
|
||||||
|
),
|
||||||
Error::InvalidPcapFd => write!(f, "internal pcap file descriptor error"),
|
Error::InvalidPcapFd => write!(f, "internal pcap file descriptor error"),
|
||||||
Error::Io(io) => write!(f, "std::io error ({io})"),
|
Error::Io(io) => write!(f, "std::io error ({io})"),
|
||||||
Error::Libc(err) => write!(f, "libc error ({err})"),
|
Error::Libc(err) => write!(f, "libc error ({err})"),
|
||||||
@ -64,7 +69,7 @@ impl Error {
|
|||||||
pub fn add_ifname(self, ifname: &str) -> Self {
|
pub fn add_ifname(self, ifname: &str) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Error::PcapError(err) => Error::PcapErrorIf(ifname.to_string(), err),
|
Error::PcapError(err) => Error::PcapErrorIf(ifname.to_string(), err),
|
||||||
other => other
|
other => other,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -74,7 +79,7 @@ impl error::Error for Error {
|
|||||||
match self {
|
match self {
|
||||||
Error::Io(err) => Some(err),
|
Error::Io(err) => Some(err),
|
||||||
Error::Libc(err) => Some(err),
|
Error::Libc(err) => Some(err),
|
||||||
_ => None
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,11 +14,12 @@
|
|||||||
// 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},
|
os::fd::{AsRawFd, RawFd},
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
ptr, slice,
|
ptr, slice,
|
||||||
task::{self, Poll}, collections::HashMap,
|
task::{self, Poll},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub mod error;
|
pub mod error;
|
||||||
@ -470,9 +471,12 @@ impl<T: Activated> futures::Stream for InterfaceStream<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_aggregate_interface_filtered<F>(crash: bool, mut f: F) -> error::Result<AggregateInterface<DevDisabled>>
|
pub fn new_aggregate_interface_filtered<F>(
|
||||||
|
crash: bool,
|
||||||
|
mut f: F,
|
||||||
|
) -> error::Result<AggregateInterface<DevDisabled>>
|
||||||
where
|
where
|
||||||
F: FnMut(&str) -> bool
|
F: FnMut(&str) -> bool,
|
||||||
{
|
{
|
||||||
let interfaces = if crash {
|
let interfaces = if crash {
|
||||||
PcapDevIterator::new()?
|
PcapDevIterator::new()?
|
||||||
@ -500,10 +504,7 @@ where
|
|||||||
.collect::<HashMap<_, _>>()
|
.collect::<HashMap<_, _>>()
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(AggregateInterface {
|
Ok(AggregateInterface { interfaces, crash })
|
||||||
interfaces,
|
|
||||||
crash
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_aggregate_interface(crash: bool) -> error::Result<AggregateInterface<DevDisabled>> {
|
pub fn new_aggregate_interface(crash: bool) -> error::Result<AggregateInterface<DevDisabled>> {
|
||||||
@ -512,14 +513,13 @@ pub fn new_aggregate_interface(crash: bool) -> error::Result<AggregateInterface<
|
|||||||
|
|
||||||
pub struct AggregateInterface<T: State> {
|
pub struct AggregateInterface<T: State> {
|
||||||
interfaces: HashMap<String, Interface<T>>,
|
interfaces: HashMap<String, Interface<T>>,
|
||||||
crash: bool
|
crash: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: State> AggregateInterface<T> {
|
impl<T: State> AggregateInterface<T> {
|
||||||
pub fn set_non_blocking(&mut self, nonblocking: bool) -> error::Result<()> {
|
pub fn set_non_blocking(&mut self, nonblocking: bool) -> error::Result<()> {
|
||||||
for (n, i) in self.interfaces.iter_mut() {
|
for (n, i) in self.interfaces.iter_mut() {
|
||||||
i
|
i.set_non_blocking(nonblocking)
|
||||||
.set_non_blocking(nonblocking)
|
|
||||||
.map_err(|e| e.add_ifname(n))?;
|
.map_err(|e| e.add_ifname(n))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -597,7 +597,7 @@ impl<T: Disabled> AggregateInterface<T> {
|
|||||||
})
|
})
|
||||||
.collect::<_>()
|
.collect::<_>()
|
||||||
},
|
},
|
||||||
crash: self.crash
|
crash: self.crash,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -606,25 +606,18 @@ impl<T: Activated> AggregateInterface<T> {
|
|||||||
pub fn datalinks(&self) -> HashMap<&str, i32> {
|
pub fn datalinks(&self) -> HashMap<&str, i32> {
|
||||||
self.interfaces
|
self.interfaces
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(name, interface)| {
|
.map(|(name, interface)| (&**name, interface.datalink()))
|
||||||
(&**name, interface.datalink())
|
|
||||||
})
|
|
||||||
.collect::<_>()
|
.collect::<_>()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn prune<F>(&mut self, mut f: F)
|
pub fn prune<F>(&mut self, mut f: F)
|
||||||
where
|
where
|
||||||
F: FnMut(&str, &mut Interface<T>) -> bool
|
F: FnMut(&str, &mut Interface<T>) -> bool,
|
||||||
{
|
{
|
||||||
let to_prune = self.interfaces
|
let to_prune = self
|
||||||
|
.interfaces
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter_map(|(k,v)| {
|
.filter_map(|(k, v)| if (f)(k, v) { Some(k.clone()) } else { None })
|
||||||
if (f)(k, v) {
|
|
||||||
Some(k.clone())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
for name in to_prune {
|
for name in to_prune {
|
||||||
@ -636,23 +629,26 @@ impl<T: Activated> AggregateInterface<T> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
filter: &str,
|
filter: &str,
|
||||||
optimize: bool,
|
optimize: bool,
|
||||||
mask: Option<u32>
|
mask: Option<u32>,
|
||||||
) -> error::Result<HashMap<&str, Box<ffi::BpfProgram>>> {
|
) -> error::Result<HashMap<&str, Box<ffi::BpfProgram>>> {
|
||||||
if self.crash {
|
if self.crash {
|
||||||
self.interfaces
|
self.interfaces
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.map(|(name, interface)| {
|
.map(|(name, interface)| {
|
||||||
interface.set_filter(filter, optimize, mask)
|
interface
|
||||||
|
.set_filter(filter, optimize, mask)
|
||||||
.map(|bpf| (&**name, bpf))
|
.map(|bpf| (&**name, bpf))
|
||||||
.map_err(|e| e.add_ifname(&name))
|
.map_err(|e| e.add_ifname(&name))
|
||||||
})
|
})
|
||||||
.collect::<error::Result<_>>()
|
.collect::<error::Result<_>>()
|
||||||
} else {
|
} else {
|
||||||
Ok(self.interfaces
|
Ok(self
|
||||||
|
.interfaces
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.filter_map(|(name, interface)| {
|
.filter_map(|(name, interface)| {
|
||||||
let name_clone = name.clone();
|
let name_clone = name.clone();
|
||||||
interface.set_filter(filter, optimize, mask)
|
interface
|
||||||
|
.set_filter(filter, optimize, mask)
|
||||||
.map(|bpf| (&**name, bpf))
|
.map(|bpf| (&**name, bpf))
|
||||||
.ok()
|
.ok()
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
@ -666,7 +662,9 @@ impl<T: Activated> AggregateInterface<T> {
|
|||||||
|
|
||||||
pub fn sendpacket(&self, ifname: &str, packet: packets::EthernetPkt) -> error::Result<()> {
|
pub fn sendpacket(&self, ifname: &str, packet: packets::EthernetPkt) -> error::Result<()> {
|
||||||
if let Some(interface) = self.interfaces.get(ifname) {
|
if let Some(interface) = self.interfaces.get(ifname) {
|
||||||
interface.sendpacket(packet).map_err(|e| e.add_ifname(ifname))?;
|
interface
|
||||||
|
.sendpacket(packet)
|
||||||
|
.map_err(|e| e.add_ifname(ifname))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -676,7 +674,8 @@ impl<T: Activated> AggregateInterface<T> {
|
|||||||
impl<T: NotListening> AggregateInterface<T> {
|
impl<T: NotListening> AggregateInterface<T> {
|
||||||
pub fn stream(self) -> error::Result<AggregateInterfaceStream<DevActivated>> {
|
pub fn stream(self) -> error::Result<AggregateInterfaceStream<DevActivated>> {
|
||||||
Ok(AggregateInterfaceStream {
|
Ok(AggregateInterfaceStream {
|
||||||
streams: self.interfaces
|
streams: self
|
||||||
|
.interfaces
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(ifname, interface)| {
|
.map(|(ifname, interface)| {
|
||||||
let new_name = ifname.clone();
|
let new_name = ifname.clone();
|
||||||
@ -685,13 +684,13 @@ impl<T: NotListening> AggregateInterface<T> {
|
|||||||
.map(|stream| (ifname, stream))
|
.map(|stream| (ifname, stream))
|
||||||
.map_err(|e| e.add_ifname(&new_name))
|
.map_err(|e| e.add_ifname(&new_name))
|
||||||
})
|
})
|
||||||
.collect::<error::Result<_>>()?
|
.collect::<error::Result<_>>()?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct AggregateInterfaceStream<T: Activated> {
|
pub struct AggregateInterfaceStream<T: Activated> {
|
||||||
streams: StreamMap<String, InterfaceStream<T>>
|
streams: StreamMap<String, InterfaceStream<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Activated> AggregateInterfaceStream<T> {
|
impl<T: Activated> AggregateInterfaceStream<T> {
|
||||||
@ -700,14 +699,8 @@ impl<T: Activated> AggregateInterfaceStream<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn sendpacket(&mut self, ifname: &str, packet: packets::EthernetPkt) -> error::Result<()> {
|
pub fn sendpacket(&mut self, ifname: &str, packet: packets::EthernetPkt) -> error::Result<()> {
|
||||||
if let Some(interface) = self.streams
|
if let Some(interface) = self.streams.values_mut().find(|interface| {
|
||||||
.values_mut()
|
interface.inner.get_ref().interface.dev_name.as_bytes() == ifname.as_bytes()
|
||||||
.find(|interface| {
|
|
||||||
interface.inner
|
|
||||||
.get_ref()
|
|
||||||
.interface
|
|
||||||
.dev_name
|
|
||||||
.as_bytes() == ifname.as_bytes()
|
|
||||||
}) {
|
}) {
|
||||||
interface.sendpacket(packet)?;
|
interface.sendpacket(packet)?;
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user