Compare commits

..

1 Commits

Author SHA1 Message Date
Michal Humpula
d0a9262cd8 simplify netlink operations 2026-03-01 08:27:16 +01:00

View File

@@ -2,6 +2,10 @@ use anyhow::Result;
use libc::if_nametoindex; use libc::if_nametoindex;
use log::{debug, info}; use log::{debug, info};
use netlink_packet_route::route::RouteAddress; use netlink_packet_route::route::RouteAddress;
use netlink_packet_route::{
AddressFamily, RouteNetlinkMessage,
route::{RouteAttribute, RouteHeader, RouteMessage, RouteProtocol, RouteScope, RouteType},
};
use std::ffi::CString; use std::ffi::CString;
use std::net::Ipv4Addr; use std::net::Ipv4Addr;
@@ -123,36 +127,16 @@ impl RouteManager {
use netlink_packet_core::{ use netlink_packet_core::{
NLM_F_ACK, NLM_F_CREATE, NLM_F_REQUEST, NetlinkHeader, NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_CREATE, NLM_F_REQUEST, NetlinkHeader, NetlinkMessage, NetlinkPayload,
}; };
use netlink_packet_route::{
AddressFamily, RouteNetlinkMessage,
route::RouteProtocol,
route::RouteScope,
route::{RouteAttribute, RouteHeader, RouteMessage, RouteType},
};
use netlink_sys::{Socket, SocketAddr, protocols::NETLINK_ROUTE}; use netlink_sys::{Socket, SocketAddr, protocols::NETLINK_ROUTE};
let mut socket = Socket::new(NETLINK_ROUTE)?; let mut socket = Socket::new(NETLINK_ROUTE)?;
let _port_number = socket.bind_auto()?.port_number(); let _port_number = socket.bind_auto()?.port_number();
socket.connect(&SocketAddr::new(0, 0))?; socket.connect(&SocketAddr::new(0, 0))?;
let route_msg_hdr = RouteHeader {
address_family: AddressFamily::Inet,
table: MAIN_TABLE_ID,
destination_prefix_length: 0, // Default route
protocol: RouteProtocol::Boot,
scope: RouteScope::Universe,
kind: RouteType::Unicast,
..Default::default()
};
let mut route_msg = RouteMessage::default(); let route_msg = create_route_message(route_info.gateway, index, route_info.metric);
route_msg.header = route_msg_hdr;
route_msg.attributes = vec![
RouteAttribute::Gateway(RouteAddress::Inet(route_info.gateway)),
RouteAttribute::Oif(index),
RouteAttribute::Priority(route_info.metric),
];
let mut nl_hdr = NetlinkHeader::default(); let mut nl_hdr = NetlinkHeader::default();
nl_hdr.flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK; // Remove NLM_F_EXCL to allow updates nl_hdr.flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
let mut msg = NetlinkMessage::new( let mut msg = NetlinkMessage::new(
nl_hdr, nl_hdr,
@@ -161,11 +145,8 @@ impl RouteManager {
msg.finalize(); msg.finalize();
let mut buf = vec![0; 1024 * 8]; let mut buf = vec![0; 1024 * 8];
msg.serialize(&mut buf[..msg.buffer_len()]); msg.serialize(&mut buf[..msg.buffer_len()]);
// Debug: Log the netlink message being sent
debug!("Netlink message being sent: {:?}", &buf[..msg.buffer_len()]);
debug!( debug!(
"Route addition attempt: gateway={}, interface={}, metric={}, interface_index={}", "Route addition attempt: gateway={}, interface={}, metric={}, interface_index={}",
route_info.gateway, route_info.interface, route_info.metric, index route_info.gateway, route_info.interface, route_info.metric, index
@@ -198,35 +179,20 @@ impl RouteManager {
route_info.metric route_info.metric
); );
} else { } else {
let error_str = match error_code { return handle_netlink_error(error_code);
-1 => "EPERM - Operation not permitted (need root privileges)",
-2 => "ENOENT - No such file or directory",
-13 => "EACCES - Permission denied",
-22 => "EINVAL - Invalid argument",
_ => "Unknown error",
};
return Err(anyhow::anyhow!(
"Failed to add route: {} (code: {}): {:?}",
error_str,
error_code,
error_msg
));
} }
} }
debug!("Route added successfully"); debug!("Route added successfully");
} }
Ok(())
} }
Err(e) => { Err(e) => Err(anyhow::anyhow!(
return Err(anyhow::anyhow!(
"Failed to deserialize netlink message: {}", "Failed to deserialize netlink message: {}",
e e
)); )),
} }
} }
Ok(())
}
fn delete_default_route_internal( fn delete_default_route_internal(
&self, &self,
gateway: Ipv4Addr, gateway: Ipv4Addr,
@@ -242,35 +208,13 @@ impl RouteManager {
use netlink_packet_core::{ use netlink_packet_core::{
NLM_F_ACK, NLM_F_REQUEST, NetlinkHeader, NetlinkMessage, NetlinkPayload, NLM_F_ACK, NLM_F_REQUEST, NetlinkHeader, NetlinkMessage, NetlinkPayload,
}; };
use netlink_packet_route::{
AddressFamily, RouteNetlinkMessage,
route::RouteProtocol,
route::RouteScope,
route::{RouteAttribute, RouteHeader, RouteMessage, RouteType},
};
use netlink_sys::{Socket, SocketAddr, protocols::NETLINK_ROUTE}; use netlink_sys::{Socket, SocketAddr, protocols::NETLINK_ROUTE};
let mut socket = Socket::new(NETLINK_ROUTE)?; let mut socket = Socket::new(NETLINK_ROUTE)?;
let _port_number = socket.bind_auto()?.port_number(); let _port_number = socket.bind_auto()?.port_number();
socket.connect(&SocketAddr::new(0, 0))?; socket.connect(&SocketAddr::new(0, 0))?;
let route_msg_hdr = RouteHeader { let route_msg = create_route_message(gateway, index, metric);
address_family: AddressFamily::Inet,
table: MAIN_TABLE_ID,
destination_prefix_length: 0, // Default route
protocol: RouteProtocol::Boot,
scope: RouteScope::Universe,
kind: RouteType::Unicast,
..Default::default()
};
let mut route_msg = RouteMessage::default();
route_msg.header = route_msg_hdr;
route_msg.attributes = vec![
RouteAttribute::Gateway(RouteAddress::Inet(gateway)),
RouteAttribute::Oif(index),
RouteAttribute::Priority(metric),
];
let mut nl_hdr = NetlinkHeader::default(); let mut nl_hdr = NetlinkHeader::default();
nl_hdr.flags = NLM_F_REQUEST | NLM_F_ACK; nl_hdr.flags = NLM_F_REQUEST | NLM_F_ACK;
@@ -282,14 +226,8 @@ impl RouteManager {
msg.finalize(); msg.finalize();
let mut buf = vec![0; 1024 * 8]; let mut buf = vec![0; 1024 * 8];
msg.serialize(&mut buf[..msg.buffer_len()]); msg.serialize(&mut buf[..msg.buffer_len()]);
// Debug: Log the netlink message being sent
debug!(
"Netlink delete message being sent: {:?}",
&buf[..msg.buffer_len()]
);
debug!( debug!(
"Route deletion attempt: gateway={}, interface={}, metric={}, interface_index={}", "Route deletion attempt: gateway={}, interface={}, metric={}, interface_index={}",
gateway, interface, metric, index gateway, interface, metric, index
@@ -315,17 +253,14 @@ impl RouteManager {
} }
debug!("Route deleted successfully"); debug!("Route deleted successfully");
} }
Ok(())
} }
Err(e) => { Err(e) => Err(anyhow::anyhow!(
return Err(anyhow::anyhow!(
"Failed to deserialize netlink message: {}", "Failed to deserialize netlink message: {}",
e e
)); )),
} }
} }
Ok(())
}
} }
fn get_interface_index(iface_name: &str) -> Result<u32> { fn get_interface_index(iface_name: &str) -> Result<u32> {
@@ -338,3 +273,44 @@ fn get_interface_index(iface_name: &str) -> Result<u32> {
Ok(index) Ok(index)
} }
} }
fn create_route_header() -> RouteHeader {
RouteHeader {
address_family: AddressFamily::Inet,
table: MAIN_TABLE_ID,
destination_prefix_length: 0, // Default route
protocol: RouteProtocol::Boot,
scope: RouteScope::Universe,
kind: RouteType::Unicast,
..Default::default()
}
}
fn handle_netlink_error(error_code: i32) -> Result<()> {
if error_code == -17 {
// EEXIST - Route already exists, treat as success
return Ok(());
}
let error_str = match error_code {
-1 => "EPERM - Operation not permitted (need root privileges)",
-2 => "ENOENT - No such file or directory",
-13 => "EACCES - Permission denied",
-22 => "EINVAL - Invalid argument",
_ => "Unknown error",
};
Err(anyhow::anyhow!("Netlink operation failed: {}", error_str))
}
fn create_route_message(gateway: Ipv4Addr, interface_index: u32, metric: u32) -> RouteMessage {
let route_msg_hdr = create_route_header();
let mut route_msg = RouteMessage::default();
route_msg.header = route_msg_hdr;
route_msg.attributes = vec![
RouteAttribute::Gateway(RouteAddress::Inet(gateway)),
RouteAttribute::Oif(interface_index),
RouteAttribute::Priority(metric),
];
route_msg
}