Upgrade to def_guard_wireguard v0.8.0 (#6315)
* Upgrade to def_guard_wireguard v0.8.0 * Update nix, netlink-packet-wireguard * Adapt linux code for defguard_wireguard * rustfmt * Revert nix to 0.27.1 * clippy: fix * fix from rebase * Restore userspace imp on condition * Add send+sync on boxed wgapi * Use error to indicate when userspace/kernel imps are unavailable; userspace is not available on all platforms * Remove duplicate import --------- Co-authored-by: mfahampshire <maxhampshire@pm.me>
This commit is contained in:
Generated
+745
-430
File diff suppressed because it is too large
Load Diff
+1
-2
@@ -256,8 +256,7 @@ ctr = "0.9.1"
|
||||
cupid = "0.6.1"
|
||||
curve25519-dalek = "4.1.3"
|
||||
dashmap = "5.5.3"
|
||||
# We want https://github.com/DefGuard/wireguard-rs/pull/64 , but there's no crates.io release being pushed out anymore
|
||||
defguard_wireguard_rs = { git = "https://github.com/DefGuard/wireguard-rs.git", rev = "v0.4.7" }
|
||||
defguard_wireguard_rs = "0.8.0"
|
||||
digest = "0.10.7"
|
||||
dirs = "6.0"
|
||||
dotenvy = "0.15.6"
|
||||
|
||||
+127
-42
@@ -6,16 +6,18 @@
|
||||
// #![warn(clippy::expect_used)]
|
||||
// #![warn(clippy::unwrap_used)]
|
||||
|
||||
use defguard_wireguard_rs::{WGApi, WireguardInterfaceApi, host::Peer, key::Key, net::IpAddrMask};
|
||||
use defguard_wireguard_rs::{
|
||||
WGApi, WireguardInterfaceApi, error::WireguardInterfaceError, host::Peer, key::Key,
|
||||
net::IpAddrMask,
|
||||
};
|
||||
use nym_crypto::asymmetric::x25519::KeyPair;
|
||||
use std::net::IpAddr;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::mpsc::{self, Receiver, Sender};
|
||||
use tracing::error;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use nym_ip_packet_requests::IpPair;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::net::IpAddr;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
use nym_network_defaults::constants::WG_TUN_BASE_NAME;
|
||||
@@ -33,13 +35,104 @@ pub use peer_controller::{PeerControlRequest, PeerRegistrationData};
|
||||
|
||||
pub const CONTROL_CHANNEL_SIZE: usize = 256;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum WgApiWrapperError {
|
||||
#[error("WireGuard kernel implementation is not available on this platform")]
|
||||
KernelUnavailable,
|
||||
|
||||
#[error("WireGuard userspace implementation is not available on this platform")]
|
||||
UserspaceUnavailable,
|
||||
|
||||
#[error("WireGuard interface error: {0}")]
|
||||
Interface(#[from] WireguardInterfaceError),
|
||||
}
|
||||
|
||||
pub struct WgApiWrapper {
|
||||
inner: WGApi,
|
||||
inner: Box<dyn WireguardInterfaceApi + Sync + Send>,
|
||||
}
|
||||
|
||||
impl WgApiWrapper {
|
||||
/// Create new instance of `WgApiWrapper` choosing internal implementation based on `use_userspace` flag and platform availability.
|
||||
///
|
||||
/// Falls back to userspace implementation when kernel implementation is requested but not available.
|
||||
pub fn new(ifname: &str, use_userspace: bool) -> Result<Self, WgApiWrapperError> {
|
||||
if use_userspace {
|
||||
Self::userspace(ifname)
|
||||
} else {
|
||||
Self::kernel(ifname).or_else(|err| {
|
||||
if matches!(err, WgApiWrapperError::KernelUnavailable) {
|
||||
Self::userspace(ifname)
|
||||
} else {
|
||||
Err(err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Create userspace implementation
|
||||
fn userspace(_ifname: &str) -> Result<Self, WgApiWrapperError> {
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
{
|
||||
let api = WGApi::<defguard_wireguard_rs::Userspace>::new(_ifname)?;
|
||||
Ok(Self {
|
||||
inner: Box::new(api),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "linux",
|
||||
target_os = "macos",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"
|
||||
)))]
|
||||
{
|
||||
Err(WgApiWrapperError::UserspaceUnavailable)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create kernel implementation if available.
|
||||
fn kernel(_ifname: &str) -> Result<Self, WgApiWrapperError> {
|
||||
#[cfg(any(
|
||||
target_os = "linux",
|
||||
target_os = "windows",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"
|
||||
))]
|
||||
{
|
||||
let api = WGApi::<defguard_wireguard_rs::Kernel>::new(_ifname)?;
|
||||
Ok(Self {
|
||||
inner: Box::new(api),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "linux",
|
||||
target_os = "windows",
|
||||
target_os = "freebsd",
|
||||
target_os = "netbsd"
|
||||
)))]
|
||||
{
|
||||
Err(WgApiWrapperError::KernelUnavailable)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WgApiWrapper {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = self.inner.remove_interface() {
|
||||
error!("Could not remove the wireguard interface: {e:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl WireguardInterfaceApi for WgApiWrapper {
|
||||
fn create_interface(
|
||||
&self,
|
||||
&mut self,
|
||||
) -> Result<(), defguard_wireguard_rs::error::WireguardInterfaceError> {
|
||||
self.inner.create_interface()
|
||||
}
|
||||
@@ -58,7 +151,6 @@ impl WireguardInterfaceApi for WgApiWrapper {
|
||||
self.inner.configure_peer_routing(peers)
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn configure_interface(
|
||||
&self,
|
||||
config: &defguard_wireguard_rs::InterfaceConfiguration,
|
||||
@@ -66,21 +158,20 @@ impl WireguardInterfaceApi for WgApiWrapper {
|
||||
self.inner.configure_interface(config)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn configure_interface(
|
||||
&self,
|
||||
config: &defguard_wireguard_rs::InterfaceConfiguration,
|
||||
dns: &[std::net::IpAddr],
|
||||
) -> Result<(), defguard_wireguard_rs::error::WireguardInterfaceError> {
|
||||
self.inner.configure_interface(config, dns)
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn remove_interface(
|
||||
&self,
|
||||
) -> Result<(), defguard_wireguard_rs::error::WireguardInterfaceError> {
|
||||
self.inner.remove_interface()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn remove_interface(
|
||||
&mut self,
|
||||
) -> Result<(), defguard_wireguard_rs::error::WireguardInterfaceError> {
|
||||
self.inner.remove_interface()
|
||||
}
|
||||
|
||||
fn configure_peer(
|
||||
&self,
|
||||
peer: &Peer,
|
||||
@@ -106,24 +197,10 @@ impl WireguardInterfaceApi for WgApiWrapper {
|
||||
|
||||
fn configure_dns(
|
||||
&self,
|
||||
dns: &[std::net::IpAddr],
|
||||
dns: &[IpAddr],
|
||||
search_domains: &[&str],
|
||||
) -> Result<(), defguard_wireguard_rs::error::WireguardInterfaceError> {
|
||||
self.inner.configure_dns(dns)
|
||||
}
|
||||
}
|
||||
|
||||
impl WgApiWrapper {
|
||||
pub fn new(wg_api: WGApi) -> Self {
|
||||
WgApiWrapper { inner: wg_api }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for WgApiWrapper {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = defguard_wireguard_rs::WireguardInterfaceApi::remove_interface(&self.inner)
|
||||
{
|
||||
error!("Could not remove the wireguard interface: {e:?}");
|
||||
}
|
||||
self.inner.configure_dns(dns, search_domains)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +258,7 @@ pub async fn start_wireguard(
|
||||
use_userspace: bool,
|
||||
) -> Result<std::sync::Arc<WgApiWrapper>, Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||
use base64::{Engine, prelude::BASE64_STANDARD};
|
||||
use defguard_wireguard_rs::{InterfaceConfiguration, WireguardInterfaceApi};
|
||||
use defguard_wireguard_rs::InterfaceConfiguration;
|
||||
use ip_network::IpNetwork;
|
||||
use peer_controller::PeerController;
|
||||
use std::collections::HashMap;
|
||||
@@ -193,7 +270,7 @@ pub async fn start_wireguard(
|
||||
"Initializing WireGuard interface '{}' with use_userspace={}",
|
||||
ifname, use_userspace
|
||||
);
|
||||
let wg_api = defguard_wireguard_rs::WGApi::new(ifname.clone(), use_userspace)?;
|
||||
let mut wg_api = WgApiWrapper::new(&ifname, use_userspace)?;
|
||||
let mut peer_bandwidth_managers = HashMap::with_capacity(peers.len());
|
||||
|
||||
for peer in peers.iter() {
|
||||
@@ -214,14 +291,22 @@ pub async fn start_wireguard(
|
||||
let interface_config = InterfaceConfiguration {
|
||||
name: ifname.clone(),
|
||||
prvkey: BASE64_STANDARD.encode(wireguard_data.inner.keypair().private_key().to_bytes()),
|
||||
address: wireguard_data.inner.config().private_ipv4.to_string(),
|
||||
port: wireguard_data.inner.config().announced_tunnel_port as u32,
|
||||
addresses: vec![IpAddrMask::host(IpAddr::from(
|
||||
wireguard_data.inner.config().private_ipv4,
|
||||
))],
|
||||
port: wireguard_data.inner.config().announced_tunnel_port,
|
||||
peers: peers.clone(), // Clone since we need to use peers later to mark IPs as used
|
||||
mtu: None,
|
||||
};
|
||||
info!(
|
||||
"attempting to configure wireguard interface '{ifname}': address={}, port={}",
|
||||
interface_config.address, interface_config.port
|
||||
"attempting to configure wireguard interface '{ifname}': addresses=[{}], port={}",
|
||||
interface_config
|
||||
.addresses
|
||||
.iter()
|
||||
.map(|s| s.to_string())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", "),
|
||||
interface_config.port
|
||||
);
|
||||
|
||||
info!("Configuring WireGuard interface...");
|
||||
@@ -263,7 +348,6 @@ pub async fn start_wireguard(
|
||||
wg_api.configure_peer_routing(&[catch_all_peer])?;
|
||||
|
||||
let host = wg_api.read_interface_data()?;
|
||||
let wg_api = std::sync::Arc::new(WgApiWrapper::new(wg_api));
|
||||
|
||||
// Initialize IP pool from configuration
|
||||
info!("Initializing IP pool for WireGuard peer allocation");
|
||||
@@ -278,13 +362,13 @@ pub async fn start_wireguard(
|
||||
for peer in &peers {
|
||||
for allowed_ip in &peer.allowed_ips {
|
||||
// Extract IPv4 and IPv6 from peer's allowed_ips
|
||||
if let IpAddr::V4(ipv4) = allowed_ip.ip {
|
||||
if let IpAddr::V4(ipv4) = allowed_ip.address {
|
||||
// Find corresponding IPv6
|
||||
if let Some(ipv6_mask) = peer
|
||||
.allowed_ips
|
||||
.iter()
|
||||
.find(|ip| matches!(ip.ip, IpAddr::V6(_)))
|
||||
&& let IpAddr::V6(ipv6) = ipv6_mask.ip
|
||||
.find(|ip| matches!(ip.address, IpAddr::V6(_)))
|
||||
&& let IpAddr::V6(ipv6) = ipv6_mask.address
|
||||
{
|
||||
ip_pool.mark_used(IpPair::new(ipv4, ipv6)).await;
|
||||
}
|
||||
@@ -292,6 +376,7 @@ pub async fn start_wireguard(
|
||||
}
|
||||
}
|
||||
|
||||
let wg_api = std::sync::Arc::new(wg_api);
|
||||
let mut controller = PeerController::new(
|
||||
ecash_manager,
|
||||
metrics,
|
||||
|
||||
@@ -321,7 +321,7 @@ impl PeerController {
|
||||
bw_manager
|
||||
.allowed_ips()
|
||||
.iter()
|
||||
.find(|ip_mask| ip_mask.ip == ip)
|
||||
.find(|ip_mask| ip_mask.address == ip)
|
||||
.and(Some(key.clone()))
|
||||
}))
|
||||
}
|
||||
@@ -551,7 +551,7 @@ struct MockWgApi {
|
||||
#[allow(clippy::todo)]
|
||||
impl WireguardInterfaceApi for MockWgApi {
|
||||
fn create_interface(
|
||||
&self,
|
||||
&mut self,
|
||||
) -> std::result::Result<(), defguard_wireguard_rs::error::WireguardInterfaceError> {
|
||||
todo!()
|
||||
}
|
||||
@@ -570,7 +570,6 @@ impl WireguardInterfaceApi for MockWgApi {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
fn configure_interface(
|
||||
&self,
|
||||
_config: &defguard_wireguard_rs::InterfaceConfiguration,
|
||||
@@ -578,21 +577,20 @@ impl WireguardInterfaceApi for MockWgApi {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn configure_interface(
|
||||
&self,
|
||||
_config: &defguard_wireguard_rs::InterfaceConfiguration,
|
||||
_dns: &[std::net::IpAddr],
|
||||
) -> std::result::Result<(), defguard_wireguard_rs::error::WireguardInterfaceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn remove_interface(
|
||||
&self,
|
||||
) -> std::result::Result<(), defguard_wireguard_rs::error::WireguardInterfaceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn remove_interface(
|
||||
&mut self,
|
||||
) -> std::result::Result<(), defguard_wireguard_rs::error::WireguardInterfaceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn configure_peer(
|
||||
&self,
|
||||
peer: &Peer,
|
||||
@@ -623,6 +621,7 @@ impl WireguardInterfaceApi for MockWgApi {
|
||||
fn configure_dns(
|
||||
&self,
|
||||
_dns: &[std::net::IpAddr],
|
||||
_search_domains: &[&str],
|
||||
) -> std::result::Result<(), defguard_wireguard_rs::error::WireguardInterfaceError> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ impl MixnetListener {
|
||||
let allowed_ipv4 = peer
|
||||
.allowed_ips
|
||||
.iter()
|
||||
.find_map(|ip_mask| match ip_mask.ip {
|
||||
.find_map(|ip_mask| match ip_mask.address {
|
||||
IpAddr::V4(ipv4_addr) => Some(ipv4_addr),
|
||||
_ => None,
|
||||
})
|
||||
@@ -307,7 +307,7 @@ impl MixnetListener {
|
||||
let allowed_ipv6 = peer
|
||||
.allowed_ips
|
||||
.iter()
|
||||
.find_map(|ip_mask| match ip_mask.ip {
|
||||
.find_map(|ip_mask| match ip_mask.address {
|
||||
IpAddr::V6(ipv6_addr) => Some(ipv6_addr),
|
||||
_ => None,
|
||||
})
|
||||
|
||||
@@ -155,7 +155,7 @@ async fn check_existing_registration(
|
||||
let mut ipv4 = None;
|
||||
let mut ipv6 = None;
|
||||
for ip_mask in &defguard_peer.allowed_ips {
|
||||
match ip_mask.ip {
|
||||
match ip_mask.address {
|
||||
std::net::IpAddr::V4(v4) => ipv4 = Some(v4),
|
||||
std::net::IpAddr::V6(v6) => ipv6 = Some(v6),
|
||||
}
|
||||
|
||||
@@ -447,7 +447,7 @@ impl GatewayTasksBuilder {
|
||||
.await?;
|
||||
continue;
|
||||
};
|
||||
used_private_network_ips.push(allowed_ip.ip);
|
||||
used_private_network_ips.push(allowed_ip.address);
|
||||
all_peers.push(peer);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user