From 7162395593ee9c013d36f284754a5fb3a331cb4f Mon Sep 17 00:00:00 2001 From: Adam Date: Wed, 24 Sep 2025 11:20:17 +0200 Subject: [PATCH] Always add route to endpoint through default gateway (#97) --- Cargo.lock | 18 ++--- Cargo.toml | 2 +- src/bsd/mod.rs | 8 +- src/utils.rs | 215 ++++++++++++++++++++++++------------------------- 4 files changed, 117 insertions(+), 126 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 435d3c1..ff93d8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -146,7 +146,7 @@ dependencies = [ [[package]] name = "defguard_wireguard_rs" -version = "0.7.7" +version = "0.7.8" dependencies = [ "base64", "env_logger", @@ -237,9 +237,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.175" +version = "0.2.176" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "58f929b4d672ea937a23a1ab494143d968337a5f47e56d0815df1e0890ddf174" [[package]] name = "log" @@ -445,9 +445,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.225" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +checksum = "0dca6411025b24b60bfa7ec1fe1f8e710ac09782dca409ee8237ba74b51295fd" dependencies = [ "serde_core", "serde_derive", @@ -455,18 +455,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.225" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +checksum = "ba2ba63999edb9dac981fb34b3e5c0d111a69b0924e253ed29d83f7c99e966a4" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.225" +version = "1.0.226" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +checksum = "8db53ae22f34573731bafa1db20f04027b2d25e02d8205921b569171699cdb33" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 44c8d24..a763629 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "defguard_wireguard_rs" -version = "0.7.7" +version = "0.7.8" edition = "2024" rust-version = "1.85" description = "A unified multi-platform high-level API for managing WireGuard interfaces" diff --git a/src/bsd/mod.rs b/src/bsd/mod.rs index 2b479c3..31c9512 100644 --- a/src/bsd/mod.rs +++ b/src/bsd/mod.rs @@ -458,9 +458,7 @@ pub fn get_gateway(ip_version: IpVersion) -> Result, IoError> { /// Add routing gateway. pub fn add_gateway(dest: &IpAddrMask, gateway: IpAddr, is_blackhole: bool) -> Result<(), IoError> { - debug!( - "Adding gateway, destination: {dest}, gateway: {gateway}, is blackhole: {is_blackhole}..." - ); + debug!("Adding gateway: destination {dest}, gateway {gateway}, is blackhole {is_blackhole}."); match (dest.ip, dest.mask(), gateway) { (IpAddr::V4(ip), IpAddr::V4(mask), IpAddr::V4(gw)) => { let payload = DestAddrMask::::new(ip.into(), mask.into(), gw.into()); @@ -481,7 +479,7 @@ pub fn add_gateway(dest: &IpAddrMask, gateway: IpAddr, is_blackhole: bool) -> Re /// Remove routing gateway. pub fn delete_gateway(dest: &IpAddrMask) -> Result<(), IoError> { - debug!("Deleting gateway with destination {dest}..."); + debug!("Deleting gateway with destination {dest}."); match (dest.ip, dest.mask()) { (IpAddr::V4(ip), IpAddr::V4(mask)) => { let payload = @@ -504,7 +502,7 @@ pub fn delete_gateway(dest: &IpAddrMask) -> Result<(), IoError> { /// Add link layer address gateway. pub fn add_linked_route(dest: &IpAddrMask, if_name: &str) -> Result<(), IoError> { - debug!("Adding link layer gateway, destination: {dest}, interface: {if_name}"); + debug!("Adding link layer gateway: destination {dest}, interface {if_name}"); let name = CString::new(if_name).unwrap(); let if_index = unsafe { libc::if_nametoindex(name.as_ptr()) as u16 }; if if_index == 0 { diff --git a/src/utils.rs b/src/utils.rs index 758e29b..52c96da 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -323,13 +323,18 @@ pub(crate) fn add_peer_routing( use crate::bsd::{IoError, delete_gateway}; + let gateway_v4 = get_gateway(IpVersion::IPv4); + if let Ok(Some(gateway)) = gateway_v4 { + debug!("Default gateway for IPv4: {gateway}"); + } + let gateway_v6 = get_gateway(IpVersion::IPv6); + if let Ok(Some(gateway)) = gateway_v6 { + debug!("Default gateway for IPv4: {gateway}"); + } + debug!("Adding peer routing for interface: {ifname}"); for peer in peers { debug!("Processing peer: {}", peer.public_key); - let mut default_route_v4 = false; - let mut default_route_v6 = false; - let mut gateway_v4 = Ok(None); - let mut gateway_v6 = Ok(None); for addr in &peer.allowed_ips { debug!("Processing route for allowed IP: {addr}, interface: {ifname}"); // FIXME: currently it is impossible to add another default route, so use the hack from @@ -337,7 +342,7 @@ pub(crate) fn add_peer_routing( if addr.ip.is_unspecified() && addr.cidr == 0 { debug!( "Found following default route in the allowed IPs: {addr}, interface: \ - {ifname}, proceeding with default route initial setup..." + {ifname}, proceeding with default route initial setup." ); let default1; let default2; @@ -346,36 +351,29 @@ pub(crate) fn add_peer_routing( default1 = IpAddrMask::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 1); // 128.0.0.0/1 default2 = IpAddrMask::new(IpAddr::V4(Ipv4Addr::new(128, 0, 0, 0)), 1); - gateway_v4 = get_gateway(IpVersion::IPv4); - debug!("Default gateway for IPv4 value: {gateway_v4:?}"); - default_route_v4 = true; } else { // ::/1 default1 = IpAddrMask::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 1); // 8000::/1 default2 = IpAddrMask::new(IpAddr::V6(Ipv6Addr::new(0x8000, 0, 0, 0, 0, 0, 0, 0)), 1); - gateway_v6 = get_gateway(IpVersion::IPv6); - debug!("Default gateway for IPv6 value: {gateway_v6:?}"); - default_route_v6 = true; } match add_linked_route(&default1, ifname) { Ok(()) => debug!("Route to {default1} has been added for interface {ifname}"), Err(err) => match err { IoError::WriteIo(Errno::ENETUNREACH) => { warn!( - "Failed to add default route {default1} for interface \ - {ifname}: Network is unreachable. This may happen if your \ - interface's IP address is not the same IP version as the \ - default gateway ({default1}) that was tried to be set, in this \ - case this warning can be ignored. Otherwise, there may be some \ - other issues with your network configuration." + "Failed to add default route {default1} for interface {ifname}: \ + Network is unreachable. This may happen if interface's IP address \ + is not the same IP version as the default gateway ({default1}) \ + that was tried to be set, in this case this warning can be \ + ignored. Otherwise, there may be some other issues with network \ + configuration." ); } _ => { error!( - "Failed to add route to {default1} for interface {ifname}: \ - {err}" + "Failed to add route to {default1} for interface {ifname}: {err}" ); } }, @@ -385,18 +383,17 @@ pub(crate) fn add_peer_routing( Err(err) => match err { IoError::WriteIo(Errno::ENETUNREACH) => { warn!( - "Failed to add default route {default2} for interface \ - {ifname}: Network is unreachable. This may happen if your \ - interface's IP address is not the same IP version as the \ - default gateway ({default2}) that was tried to be set, in this \ - case this warning can be ignored. Otherwise, there may be some \ - other issues with your network configuration." + "Failed to add default route {default2} for interface {ifname}: \ + Network is unreachable. This may happen if interface's IP address \ + is not the same IP version as the default gateway ({default2}) \ + that was tried to be set, in this case this warning can be \ + ignored. Otherwise, there may be some other issues with network \ + configuration." ); } _ => { error!( - "Failed to add route to {default2} for interface {ifname}: \ - {err}" + "Failed to add route to {default2} for interface {ifname}: {err}" ); } }, @@ -412,107 +409,103 @@ pub(crate) fn add_peer_routing( } } - if default_route_v4 || default_route_v6 { - if let Some(endpoint) = peer.endpoint { - debug!("Default routes have been set, proceeding with further configuration..."); - let host = IpAddrMask::host(endpoint.ip()); - let localhost = if endpoint.is_ipv4() { - IpAddr::V4(Ipv4Addr::LOCALHOST) - } else { - IpAddr::V6(Ipv6Addr::LOCALHOST) - }; - debug!("Cleaning up old route to {host}, if it exists..."); - match delete_gateway(&host) { - Ok(()) => { - debug!( - "Previously existing route to {host} has been removed, if it existed" - ); - } - Err(err) => { - debug!("Previously existing route to {host} has not been removed: {err}"); - } - } - if endpoint.is_ipv6() && default_route_v6 { + // Logic below is valid only in case an endpoint has been configured for the peer. + let Some(endpoint) = peer.endpoint else { + continue; + }; + + let endpoint_ip = IpAddrMask::host(endpoint.ip()); + let localhost = if endpoint.is_ipv4() { + IpAddr::V4(Ipv4Addr::LOCALHOST) + } else { + IpAddr::V6(Ipv6Addr::LOCALHOST) + }; + + match delete_gateway(&endpoint_ip) { + Ok(()) => { + debug!("Former route to {endpoint_ip} has been removed, if it existed."); + } + Err(err) => { + debug!("Former route to {endpoint_ip} has not been removed: {err}"); + } + } + + debug!("Default routes have been set, proceeding with further configuration."); + if endpoint.is_ipv6() { + debug!( + "Endpoint is an IPv6 address and a default IPv6 route is present in the allowed \ + IPs; proceeding with further configuration." + ); + match gateway_v6 { + Ok(Some(gateway)) => { debug!( - "Endpoint is an IPv6 address and a default route (IPv6) is present in \ - the alloweds IPs, proceeding with further configuration..." + "Default gateway for IPv6 has been found before: {gateway}, routing the \ + traffic destined to {endpoint_ip} through it." ); - match gateway_v6 { - Ok(Some(gateway)) => { - debug!( - "Default gateway for IPv4 has been found before: {gateway}, \ - routing the traffic destined to {host} through it..." - ); - match add_gateway(&host, gateway, false) { - Ok(()) => { - debug!("Route to {host} has been added for gateway {gateway}"); - } - Err(err) => { - error!( - "Failed to add route to {host} for gateway {gateway}: \ - {err}" - ); - } - } + match add_gateway(&endpoint_ip, gateway, false) { + Ok(()) => { + debug!("Route to {endpoint_ip} has been added for gateway {gateway}"); } - Ok(None) => { - debug!( - "Default gateway for IPv6 has not been found, routing the \ - traffic destined to {host} through localhost as a blackhole \ - route..." + Err(err) => { + error!( + "Failed to add route to {endpoint_ip} for gateway {gateway}: {err}" ); - match add_gateway(&host, localhost, true) { - Ok(()) => debug!("Blackhole route to {host} has been added"), - Err(err) => { - error!("Failed to add blackhole route to {host}: {err}"); - } - } } + } + } + Ok(None) => { + debug!( + "Default gateway for IPv6 has not been found, routing the traffic destined \ + to {endpoint_ip} through localhost as a blackhole route." + ); + match add_gateway(&endpoint_ip, localhost, true) { + Ok(()) => debug!("Blackhole route to {endpoint_ip} has been added"), Err(err) => { - error!("Failed to get gateway for {host}: {err}"); + error!("Failed to add blackhole route to {endpoint_ip}: {err}"); } } - } else if default_route_v4 { + } + Err(ref err) => { + error!("Failed to get gateway for {endpoint_ip}: {err}"); + } + } + } else { + debug!( + "Endpoint is an IPv4 address and a default IPv4 route is present in the allowed \ + IPs; proceeding with further configuration." + ); + match gateway_v4 { + Ok(Some(gateway)) => { debug!( - "Endpoint is an IPv4 address and a default route (IPv4) is present in \ - the alloweds IPs, proceeding with further configuration..." + "Default gateway for IPv4 has been found before: {gateway}, routing the \ + traffic destined to {endpoint_ip} through it." ); - match gateway_v4 { - Ok(Some(gateway)) => { - debug!( - "Default gateway for IPv4 has been found before: {gateway}, \ - routing the traffic destined to {host} through it..." - ); - match add_gateway(&host, gateway, false) { - Ok(()) => { - debug!("Added route to {host} for gateway {gateway}"); - } - Err(err) => { - error!( - "Failed to add route to {host} for gateway {gateway}: \ - {err}" - ); - } - } + match add_gateway(&endpoint_ip, gateway, false) { + Ok(()) => { + debug!("Added route to {endpoint_ip} for gateway {gateway}"); } - Ok(None) => { - debug!( - "Default gateway for IPv4 has not been found, routing the \ - traffic destined to {host} through localhost as a blackhole \ - route..." + Err(err) => { + error!( + "Failed to add route to {endpoint_ip} for gateway {gateway}: {err}" ); - match add_gateway(&host, localhost, true) { - Ok(()) => debug!("Blackhole route to {host} has been added"), - Err(err) => { - error!("Failed to add blackhole route to {host}: {err}"); - } - } } + } + } + Ok(None) => { + debug!( + "Default gateway for IPv4 has not been found, routing the traffic destined \ + to {endpoint_ip} through localhost as a blackhole route." + ); + match add_gateway(&endpoint_ip, localhost, true) { + Ok(()) => debug!("Blackhole route to {endpoint_ip} has been added"), Err(err) => { - error!("Failed to get gateway for {host}: {err}"); + error!("Failed to add blackhole route to {endpoint_ip}: {err}"); } } } + Err(ref err) => { + error!("Failed to get gateway for {endpoint_ip}: {err}"); + } } } }