chore: run cargo fmt

This commit is contained in:
Andrew Rioux
2023-05-04 00:47:20 -04:00
parent 798eda764f
commit 978d7cb089
14 changed files with 317 additions and 269 deletions

View File

@@ -1,19 +1,19 @@
// 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::{fmt::Display, ffi::CStr};
use std::{ffi::CStr, fmt::Display};
use libc::c_int;
@@ -45,4 +45,4 @@ impl Display for Error {
impl std::error::Error for Error {}
pub type Result<T> = std::result::Result<T, Error>;
pub type Result<T> = std::result::Result<T, Error>;

View File

@@ -1,22 +1,22 @@
// 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/>.
pub mod nl_ffi;
pub mod netlink;
pub mod route;
pub mod error;
pub mod netlink;
pub mod nl_ffi;
pub mod route;
// from bridge.c
extern "C" {
@@ -92,4 +92,4 @@ extern "C" {
}
Ok(())
} */
} */

View File

@@ -1,34 +1,40 @@
// 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::{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
pub struct Socket {
pub(crate) sock: *mut nl_sock
pub(crate) sock: *mut nl_sock,
}
impl Socket {
/// Establish a new connection with the Linux kernel
pub fn new() -> error::Result<Self> {
unsafe {
let sock = Socket { sock: nl_socket_alloc() };
let sock = Socket {
sock: nl_socket_alloc(),
};
let ret = nl_connect(sock.sock, crate::netlink_route());
if ret < 0 {
@@ -51,7 +57,7 @@ impl Socket {
Ok(Cache {
cache: link_cache,
dt: PhantomData
dt: PhantomData,
})
}
}
@@ -68,7 +74,7 @@ impl Socket {
Ok(Cache {
cache: neigh_cache,
dt: PhantomData
dt: PhantomData,
})
}
}
@@ -76,7 +82,7 @@ impl Socket {
pub fn get_routes(&self) -> error::Result<Cache<Route>> {
unsafe {
let mut route_cache = ptr::null_mut::<nl_cache>();
let ret = rtnl_route_alloc_cache(self.sock, AF_INET, 0, &mut route_cache as *mut _);
if ret < 0 {
@@ -85,7 +91,7 @@ impl Socket {
Ok(Cache {
cache: route_cache,
dt: PhantomData
dt: PhantomData,
})
}
}
@@ -93,7 +99,7 @@ impl Socket {
pub fn get_addrs(&self) -> error::Result<Cache<RtAddr>> {
unsafe {
let mut addr_cache = ptr::null_mut::<nl_cache>();
let ret = rtnl_addr_alloc_cache(self.sock, &mut addr_cache as *mut _);
if ret < 0 {
@@ -102,7 +108,7 @@ impl Socket {
Ok(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
pub struct Cache<T>
where
T: From<*mut nl_object>
T: From<*mut nl_object>,
{
pub(crate) cache: *mut nl_cache,
dt: PhantomData<T>
dt: PhantomData<T>,
}
impl<T: From<*mut nl_object>> Cache<T> {
pub fn iter(&self) -> CacheIter<'_, T> {
let cache_size = unsafe {
nl_cache_nitems(self.cache)
} as usize;
let cache_size = unsafe { nl_cache_nitems(self.cache) } as usize;
CacheIter {
obj: unsafe { nl_cache_get_first(self.cache) },
cache_size,
index: 0,
item_type: PhantomData {}
item_type: PhantomData {},
}
}
}
@@ -182,7 +186,7 @@ impl<T: From<*mut nl_object>> Iterator for CacheIter<'_, T> {
let obj = self.obj;
self.obj = unsafe { nl_cache_get_next(obj) };
Some(T::from(obj))
}

View File

@@ -1,19 +1,19 @@
// 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 libc::{c_int, c_void, c_char, c_uint};
use libc::{c_char, c_int, c_uint, c_void};
macro_rules! nl_obj {
($name:ident) => {
@@ -23,7 +23,7 @@ macro_rules! nl_obj {
_data: [u8; 0],
_marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
}
}
};
}
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_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_nitems(cache: *mut nl_cache) -> c_int;
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_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_lladdr(neigh: *mut rtnl_neigh) -> *mut nl_addr;
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_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_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_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_dst(route: *mut rtnl_route) -> *mut nl_addr;
pub fn rtnl_route_get_iif(route: *mut rtnl_route) -> c_int;

View File

@@ -1,29 +1,36 @@
// 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::{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::*;
/// Represents an address assigned to a link
pub struct RtAddr {
addr: *mut rtnl_addr
addr: *mut rtnl_addr,
}
impl RtAddr {
@@ -50,14 +57,15 @@ impl RtAddr {
impl From<*mut nl_object> for RtAddr {
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
pub struct Link {
pub(crate) link: *mut rtnl_link
pub(crate) link: *mut rtnl_link,
}
impl Link {
@@ -74,7 +82,9 @@ impl Link {
/// representing MAC addresses or IP addresses
pub fn addr(&self) -> Addr {
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
pub fn ifindex(&self) -> c_int {
unsafe {
rtnl_link_get_ifindex(self.link)
}
unsafe { rtnl_link_get_ifindex(self.link) }
}
/// Tries to get the neighbor for this link, which can provide the destination address and the
@@ -103,7 +111,7 @@ impl Link {
unsafe {
let neigh = rtnl_neigh_get(neigh_table.cache, self.ifindex(), addr.addr);
if neigh.is_null() {
if neigh.is_null() {
return None;
}
@@ -114,74 +122,77 @@ impl Link {
impl Debug for Link {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f
.debug_struct("Link")
.field("name", &self.name())
.finish()
f.debug_struct("Link").field("name", &self.name()).finish()
}
}
impl From<*mut nl_object> for Link {
fn from(value: *mut nl_object) -> 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<_>>();
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()))
.unwrap_or(std::cmp::Ordering::Equal)
});
let ip_int = u32::from(addr);
let route = sorted_routes
.iter()
.find(|route| {
let Some(dst) = route.dst() else { return false };
let route = sorted_routes.iter().find(|route| {
let Some(dst) = route.dst() else { return false };
let mask = if dst.cidrlen() != 0 {
(0xFFFFFFFFu32.overflowing_shr(32 - dst.cidrlen())).0.overflowing_shl(32 - dst.cidrlen()).0
} else {
0
};
let mask = if dst.cidrlen() != 0 {
(0xFFFFFFFFu32.overflowing_shr(32 - dst.cidrlen()))
.0
.overflowing_shl(32 - dst.cidrlen())
.0
} else {
0
};
let Ok(dst_addr): Result<Ipv4Addr, _> = (&dst).try_into() else { return false };
let dst_addr: u32 = dst_addr.into();
let Ok(dst_addr): Result<Ipv4Addr, _> = (&dst).try_into() else { return false };
let dst_addr: u32 = dst_addr.into();
(mask & dst_addr) == (mask & ip_int)
})?;
(mask & dst_addr) == (mask & ip_int)
})?;
let link_ind = route
.hop_iter()
.next()?
.ifindex();
let link_ind = route.hop_iter().next()?.ifindex();
let link = netlink::get_link_by_index(links, link_ind)?;
let neigh = neighs
.iter()
.find(|n| n.ifindex() == link.ifindex())?;
let neigh = neighs.iter().find(|n| n.ifindex() == link.ifindex())?;
let srcip = addrs
.iter()
.find(|a| a.ifindex() == link.ifindex())?;
let srcip = addrs.iter().find(|a| a.ifindex() == link.ifindex())?;
Some((
link.name(),
(&srcip.local()?).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
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() {
let Some(neigh) = link.get_neigh(&neighs, addr) else { continue; };
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()))
})
.next() {
return Some((laddr, link, neigh.hw_address().try_into().ok()?))
.next()
{
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> {
routes
.iter()
.find(|r|
r
.dst()
.map(|a| a.cidrlen())
.unwrap_or(33) == 0
)
.find(|r| r.dst().map(|a| a.cidrlen()).unwrap_or(33) == 0)
}
/// A struct representing the neighbor of a link
pub struct Neigh {
neigh: *mut rtnl_neigh
neigh: *mut rtnl_neigh,
}
impl Neigh {
@@ -250,16 +257,14 @@ impl Neigh {
}
pub fn ifindex(&self) -> i32 {
unsafe {
rtnl_neigh_get_ifindex(self.neigh)
}
unsafe { rtnl_neigh_get_ifindex(self.neigh) }
}
}
impl From<*mut nl_object> for Neigh {
fn from(value: *mut nl_object) -> Self {
Self {
neigh: value as *mut _
neigh: value as *mut _,
}
}
}
@@ -267,15 +272,13 @@ impl From<*mut nl_object> for Neigh {
/// Represents "an address"
/// IPv4? IPv6? MAC? Whatever the "any" or "lo" devices use? Yes!
pub struct Addr {
addr: *mut nl_addr
addr: *mut nl_addr,
}
impl Addr {
/// Returns the number of bytes that are in the address
pub fn len(&self) -> u32 {
unsafe {
nl_addr_get_len(self.addr)
}
unsafe { nl_addr_get_len(self.addr) }
}
/// 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`]
pub fn atype(&self) -> c_int {
unsafe {
nl_addr_get_family(self.addr)
}
unsafe { nl_addr_get_family(self.addr) }
}
/// Returns the length of the subnet mask applying to this address
pub fn cidrlen(&self) -> c_uint {
unsafe {
nl_addr_get_prefixlen(self.addr)
}
unsafe { nl_addr_get_prefixlen(self.addr) }
}
}
@@ -308,18 +307,25 @@ impl Debug for Addr {
match self.atype() {
AF_INET => {
let octets = self.hw_address();
f
.debug_struct("Addr")
.field("addr", &format!("{}.{}.{}.{}/{}", octets[0], octets[1], octets[2], octets[3], self.cidrlen()))
.finish()
},
_ => {
f
.debug_struct("Addr")
.field("addr", &self.hw_address())
.field("atype", &self.atype())
f.debug_struct("Addr")
.field(
"addr",
&format!(
"{}.{}.{}.{}/{}",
octets[0],
octets[1],
octets[2],
octets[3],
self.cidrlen()
),
)
.finish()
}
_ => f
.debug_struct("Addr")
.field("addr", &self.hw_address())
.field("atype", &self.atype())
.finish(),
}
}
}
@@ -353,7 +359,7 @@ impl TryFrom<&Addr> for Ipv4Addr {
/// Represents a route in the kernel routing table
pub struct Route {
route: *mut rtnl_route
route: *mut rtnl_route,
}
impl Route {
@@ -385,9 +391,7 @@ impl Route {
/// Returns the amount of hops are in this route
pub fn nexthop_len(&self) -> c_int {
unsafe {
rtnl_route_get_nnexthops(self.route)
}
unsafe { rtnl_route_get_nnexthops(self.route) }
}
/// Gets the hop at the index specify
@@ -403,21 +407,24 @@ impl Route {
/// Returns an iterator representing all the hops for this route
pub fn hop_iter(&self) -> NexthopIter<'_> {
NexthopIter { route: &self, index: 0 }
NexthopIter {
route: &self,
index: 0,
}
}
}
impl From<*mut nl_object> for Route {
fn from(value: *mut nl_object) -> Self {
Route {
route: value as *mut _
route: value as *mut _,
}
}
}
/// Represents the hops of a network route
pub struct Nexthop {
nexthop: *mut rtnl_nexthop
nexthop: *mut rtnl_nexthop,
}
impl Nexthop {
@@ -425,7 +432,7 @@ impl Nexthop {
pub fn gateway(&self) -> Option<Addr> {
unsafe {
let addr = rtnl_route_nh_get_gateway(self.nexthop);
if addr.is_null() {
return None;
}
@@ -436,16 +443,14 @@ impl Nexthop {
/// Returns the interface index for this network hop
pub fn ifindex(&self) -> i32 {
unsafe {
rtnl_route_nh_get_ifindex(self.nexthop)
}
unsafe { rtnl_route_nh_get_ifindex(self.nexthop) }
}
}
/// An iterator for working with route hops
pub struct NexthopIter<'a> {
route: &'a Route,
index: i32
index: i32,
}
impl Iterator for NexthopIter<'_> {
@@ -464,7 +469,10 @@ impl Iterator for NexthopIter<'_> {
}
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<_>>();
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()))
.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 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 {
0
};
@@ -496,7 +508,7 @@ pub fn get_srcip_for_dstip(routes: &Cache<Route>, ip: Ipv4Addr) -> Option<Ipv4Ad
(mask & dst_addr) == (mask & ip_int)
})
.filter_map(|route| {
.filter_map(|route| {
route
.hop_iter()
.next()