From d0a9262cd879a4f246fdafb722f3abc937a1ddeb Mon Sep 17 00:00:00 2001 From: Michal Humpula Date: Sun, 1 Mar 2026 08:27:16 +0100 Subject: [PATCH] simplify netlink operations --- src/routing.rs | 144 +++++++++++++++++++++---------------------------- 1 file changed, 60 insertions(+), 84 deletions(-) diff --git a/src/routing.rs b/src/routing.rs index c1dd2e8..0c87b7e 100644 --- a/src/routing.rs +++ b/src/routing.rs @@ -2,6 +2,10 @@ use anyhow::Result; use libc::if_nametoindex; use log::{debug, info}; 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::net::Ipv4Addr; @@ -123,36 +127,16 @@ impl RouteManager { use netlink_packet_core::{ 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}; let mut socket = Socket::new(NETLINK_ROUTE)?; let _port_number = socket.bind_auto()?.port_number(); 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(); - 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 route_msg = create_route_message(route_info.gateway, index, route_info.metric); + 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( nl_hdr, @@ -161,11 +145,8 @@ impl RouteManager { msg.finalize(); let mut buf = vec![0; 1024 * 8]; - msg.serialize(&mut buf[..msg.buffer_len()]); - // Debug: Log the netlink message being sent - debug!("Netlink message being sent: {:?}", &buf[..msg.buffer_len()]); debug!( "Route addition attempt: gateway={}, interface={}, metric={}, interface_index={}", route_info.gateway, route_info.interface, route_info.metric, index @@ -198,33 +179,18 @@ impl RouteManager { route_info.metric ); } else { - 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", - }; - return Err(anyhow::anyhow!( - "Failed to add route: {} (code: {}): {:?}", - error_str, - error_code, - error_msg - )); + return handle_netlink_error(error_code); } } debug!("Route added successfully"); } + Ok(()) } - Err(e) => { - return Err(anyhow::anyhow!( - "Failed to deserialize netlink message: {}", - e - )); - } + Err(e) => Err(anyhow::anyhow!( + "Failed to deserialize netlink message: {}", + e + )), } - - Ok(()) } fn delete_default_route_internal( @@ -242,35 +208,13 @@ impl RouteManager { use netlink_packet_core::{ 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}; let mut socket = Socket::new(NETLINK_ROUTE)?; let _port_number = socket.bind_auto()?.port_number(); 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(); - route_msg.header = route_msg_hdr; - route_msg.attributes = vec![ - RouteAttribute::Gateway(RouteAddress::Inet(gateway)), - RouteAttribute::Oif(index), - RouteAttribute::Priority(metric), - ]; + let route_msg = create_route_message(gateway, index, metric); let mut nl_hdr = NetlinkHeader::default(); nl_hdr.flags = NLM_F_REQUEST | NLM_F_ACK; @@ -282,14 +226,8 @@ impl RouteManager { msg.finalize(); let mut buf = vec![0; 1024 * 8]; - 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!( "Route deletion attempt: gateway={}, interface={}, metric={}, interface_index={}", gateway, interface, metric, index @@ -315,16 +253,13 @@ impl RouteManager { } debug!("Route deleted successfully"); } + Ok(()) } - Err(e) => { - return Err(anyhow::anyhow!( - "Failed to deserialize netlink message: {}", - e - )); - } + Err(e) => Err(anyhow::anyhow!( + "Failed to deserialize netlink message: {}", + e + )), } - - Ok(()) } } @@ -338,3 +273,44 @@ fn get_interface_index(iface_name: &str) -> Result { 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 +}