docs: added basic documentation to libnl
This commit is contained in:
parent
113a43ac41
commit
1165d687ff
@ -19,11 +19,13 @@ use libc::{AF_UNSPEC, AF_INET};
|
|||||||
|
|
||||||
use crate::{nl_ffi::*, error, route::{Link, Neigh, Route}};
|
use crate::{nl_ffi::*, error, route::{Link, Neigh, Route}};
|
||||||
|
|
||||||
|
/// 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
|
||||||
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() };
|
||||||
@ -89,6 +91,15 @@ impl Socket {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Drop for Socket {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
nl_close(self.sock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Tries to get a link by the specified ifindex
|
||||||
pub fn get_link_by_index(cache: &Cache<Link>, index: i32) -> Option<Link> {
|
pub fn get_link_by_index(cache: &Cache<Link>, index: i32) -> Option<Link> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let link = rtnl_link_get(cache.cache, index);
|
let link = rtnl_link_get(cache.cache, index);
|
||||||
@ -101,6 +112,8 @@ pub fn get_link_by_index(cache: &Cache<Link>, index: i32) -> Option<Link> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents the nl_cache in the libnl library, which is itself a general
|
||||||
|
/// collection of nl_objects
|
||||||
pub struct Cache<T>
|
pub struct Cache<T>
|
||||||
where
|
where
|
||||||
T: From<*mut nl_object>
|
T: From<*mut nl_object>
|
||||||
@ -132,6 +145,7 @@ impl<T: From<*mut nl_object>> Drop for Cache<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Iterates over caches and provides an easy way to work with them
|
||||||
pub struct CacheIter<'a, T> {
|
pub struct CacheIter<'a, T> {
|
||||||
obj: *mut nl_object,
|
obj: *mut nl_object,
|
||||||
cache_size: usize,
|
cache_size: usize,
|
||||||
|
|||||||
@ -43,6 +43,7 @@ extern "C" {
|
|||||||
pub fn nl_socket_free(sock: *mut nl_sock);
|
pub fn nl_socket_free(sock: *mut nl_sock);
|
||||||
pub fn nl_socket_get_local_port(sock: *const nl_sock) -> u32;
|
pub fn nl_socket_get_local_port(sock: *const nl_sock) -> u32;
|
||||||
pub fn nl_connect(sock: *mut nl_sock, protocol: c_int) -> c_int;
|
pub fn nl_connect(sock: *mut nl_sock, protocol: c_int) -> c_int;
|
||||||
|
pub fn nl_close(sock: *mut nl_sock) -> c_void;
|
||||||
pub fn nl_geterror(error: c_int) -> *const c_char;
|
pub fn nl_geterror(error: c_int) -> *const c_char;
|
||||||
|
|
||||||
pub fn nl_object_put(obj: *mut nl_object) -> c_void;
|
pub fn nl_object_put(obj: *mut nl_object) -> c_void;
|
||||||
|
|||||||
@ -21,11 +21,14 @@ use crate::{error, netlink::Cache};
|
|||||||
|
|
||||||
use super::nl_ffi::*;
|
use super::nl_ffi::*;
|
||||||
|
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
/// Returns the network link name, e.g. eth0
|
||||||
pub fn name(&self) -> String {
|
pub fn name(&self) -> String {
|
||||||
unsafe {
|
unsafe {
|
||||||
let name = rtnl_link_get_name(self.link);
|
let name = rtnl_link_get_name(self.link);
|
||||||
@ -34,12 +37,15 @@ impl Link {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Provides the address of the link. Can change based on the type of link,
|
||||||
|
/// 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) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines the type of link. Ethernet devices are "veth"
|
||||||
pub fn ltype(&self) -> Option<String> {
|
pub fn ltype(&self) -> Option<String> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ltype = rtnl_link_get_type(self.link);
|
let ltype = rtnl_link_get_type(self.link);
|
||||||
@ -51,12 +57,15 @@ impl Link {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
/// link layer address (lladdr)
|
||||||
pub fn get_neigh(&self, neigh_table: &Cache<Neigh>, addr: &Addr) -> Option<Neigh> {
|
pub fn get_neigh(&self, neigh_table: &Cache<Neigh>, addr: &Addr) -> Option<Neigh> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let neigh = rtnl_neigh_get(neigh_table.cache, self.ifindex(), addr.addr);
|
let neigh = rtnl_neigh_get(neigh_table.cache, self.ifindex(), addr.addr);
|
||||||
@ -78,6 +87,7 @@ impl From<*mut nl_object> for Link {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets the neighbor record for the source IP specified
|
||||||
pub fn get_neigh_for_addr(neighs: &Cache<Neigh>, links: &Cache<Link>, addr: &Addr) -> Option<(Link, Neigh)> {
|
pub fn get_neigh_for_addr(neighs: &Cache<Neigh>, links: &Cache<Link>, addr: &Addr) -> Option<(Link, Neigh)> {
|
||||||
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; };
|
||||||
@ -87,11 +97,13 @@ pub fn get_neigh_for_addr(neighs: &Cache<Neigh>, links: &Cache<Link>, addr: &Add
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
|
/// Pull up the destination address for this neighbor record
|
||||||
pub fn dst(&self) -> Addr {
|
pub fn dst(&self) -> Addr {
|
||||||
unsafe {
|
unsafe {
|
||||||
let addr = rtnl_neigh_get_dst(self.neigh);
|
let addr = rtnl_neigh_get_dst(self.neigh);
|
||||||
@ -99,6 +111,7 @@ impl Neigh {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Bring up the link local address for the neighbor link
|
||||||
pub fn lladdr(&self) -> Addr {
|
pub fn lladdr(&self) -> Addr {
|
||||||
unsafe {
|
unsafe {
|
||||||
let addr = rtnl_neigh_get_lladdr(self.neigh);
|
let addr = rtnl_neigh_get_lladdr(self.neigh);
|
||||||
@ -115,17 +128,21 @@ impl From<*mut nl_object> for Neigh {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Represents "an address"
|
||||||
|
/// 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
|
||||||
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`]
|
||||||
pub fn hw_address(&self) -> Vec<u8> {
|
pub fn hw_address(&self) -> Vec<u8> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let hw_address_ptr = nl_addr_get_binary_addr(self.addr) as *const u8;
|
let hw_address_ptr = nl_addr_get_binary_addr(self.addr) as *const u8;
|
||||||
@ -135,12 +152,14 @@ impl Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
||||||
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)
|
||||||
@ -175,23 +194,13 @@ impl TryFrom<Addr> for Ipv4Addr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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 {
|
||||||
pub fn src(&self) -> Option<Addr> {
|
/// Represents the destination of the route
|
||||||
unsafe {
|
|
||||||
let addr = rtnl_route_get_src(self.route);
|
|
||||||
|
|
||||||
if addr.is_null() {
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(Addr { addr })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dst(&self) -> Option<Addr> {
|
pub fn dst(&self) -> Option<Addr> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let addr = rtnl_route_get_dst(self.route);
|
let addr = rtnl_route_get_dst(self.route);
|
||||||
@ -204,18 +213,21 @@ impl Route {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines which interface is affected by this route
|
||||||
pub fn ifindex(&self) -> c_int {
|
pub fn ifindex(&self) -> c_int {
|
||||||
unsafe {
|
unsafe {
|
||||||
rtnl_route_get_iif(self.route)
|
rtnl_route_get_iif(self.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
|
||||||
pub fn nexthop(&self, ind: i32) -> Option<Nexthop> {
|
pub fn nexthop(&self, ind: i32) -> Option<Nexthop> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let nexthop = rtnl_route_nexthop_n(self.route, ind);
|
let nexthop = rtnl_route_nexthop_n(self.route, ind);
|
||||||
@ -226,6 +238,7 @@ impl 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 }
|
||||||
}
|
}
|
||||||
@ -239,11 +252,13 @@ impl From<*mut nl_object> for 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 {
|
||||||
|
/// Returns the gateway used for this network hop
|
||||||
pub fn gateway(&self) -> Option<Addr> {
|
pub fn gateway(&self) -> Option<Addr> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let addr = rtnl_route_nh_get_gateway(self.nexthop);
|
let addr = rtnl_route_nh_get_gateway(self.nexthop);
|
||||||
@ -256,6 +271,7 @@ impl Nexthop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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)
|
||||||
@ -263,6 +279,7 @@ impl Nexthop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
@ -288,7 +305,8 @@ impl Iterator for NexthopIter<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_route_for_ip(routes: &Cache<Route>, ip: Ipv4Addr) -> Option<Ipv4Addr> {
|
/// Determines the source IP address to use in order to make a network request
|
||||||
|
pub fn get_srcip_for_dstip(routes: &Cache<Route>, ip: Ipv4Addr) -> Option<Ipv4Addr> {
|
||||||
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| {
|
||||||
@ -325,4 +343,5 @@ pub fn get_route_for_ip(routes: &Cache<Route>, ip: Ipv4Addr) -> Option<Ipv4Addr>
|
|||||||
.flatten()
|
.flatten()
|
||||||
.map(|gateway| gateway.try_into().ok())
|
.map(|gateway| gateway.try_into().ok())
|
||||||
.flatten()
|
.flatten()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user