diff --git a/Cargo.lock b/Cargo.lock index 153ba1b793..7f0738d92e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7530,6 +7530,7 @@ dependencies = [ "nym-network-defaults", "nym-task", "nym-wireguard-types", + "serde", "tokio", "x25519-dalek 2.0.0", ] diff --git a/common/wireguard/Cargo.toml b/common/wireguard/Cargo.toml index d1744d975b..fe64c81677 100644 --- a/common/wireguard/Cargo.toml +++ b/common/wireguard/Cargo.toml @@ -22,4 +22,5 @@ log.workspace = true nym-network-defaults = { path = "../network-defaults" } nym-task = { path = "../task" } nym-wireguard-types = { path = "../wireguard-types" } +serde = { workspace = true, features = ["derive"] } tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util"] } diff --git a/common/wireguard/src/lib.rs b/common/wireguard/src/lib.rs index d9e72f382b..84ba863f80 100644 --- a/common/wireguard/src/lib.rs +++ b/common/wireguard/src/lib.rs @@ -9,13 +9,12 @@ use nym_wireguard_types::registration::GatewayClientRegistry; use std::sync::Arc; // Currently the module related to setting up the virtual network device is platform specific. +use crate::setup::PeerPair; #[cfg(target_os = "linux")] -use crate::setup::{peer_allowed_ips, peer_static_public_key, PRIVATE_KEY}; +use crate::setup::{peer_static_pairs, PRIVATE_KEY}; use defguard_wireguard_rs::WGApi; #[cfg(target_os = "linux")] -use defguard_wireguard_rs::{ - host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WireguardInterfaceApi, -}; +use defguard_wireguard_rs::{InterfaceConfiguration, WireguardInterfaceApi}; #[cfg(target_os = "linux")] use nym_network_defaults::{WG_PORT, WG_TUN_DEVICE_ADDRESS}; @@ -24,6 +23,7 @@ use nym_network_defaults::{WG_PORT, WG_TUN_DEVICE_ADDRESS}; pub async fn start_wireguard( mut task_client: nym_task::TaskClient, _gateway_client_registry: Arc, + peer_pairs: Vec, ) -> Result> { let ifname = String::from("wg0"); let wgapi = WGApi::new(ifname.clone(), false)?; @@ -36,13 +36,11 @@ pub async fn start_wireguard( peers: vec![], }; wgapi.configure_interface(&interface_config)?; - let peer = peer_static_public_key(); - let mut peer = Peer::new(Key::new(peer.to_bytes())); - let peer_ip = peer_allowed_ips(); - let peer_ip_mask = IpAddrMask::new(peer_ip.network_address(), peer_ip.netmask()); - peer.set_allowed_ips(vec![peer_ip_mask]); - wgapi.configure_peer(&peer)?; - wgapi.configure_peer_routing(&[peer.clone()])?; + let peers = peer_static_pairs(peer_pairs); + for peer in peers.iter() { + wgapi.configure_peer(peer)?; + } + wgapi.configure_peer_routing(&peers)?; tokio::spawn(async move { task_client.recv().await }); @@ -52,6 +50,7 @@ pub async fn start_wireguard( pub async fn start_wireguard( _task_client: nym_task::TaskClient, _gateway_client_registry: Arc, + _peer_pairs: Vec, ) -> Result> { todo!("WireGuard is currently only supported on Linux") } diff --git a/common/wireguard/src/setup.rs b/common/wireguard/src/setup.rs index 5cda585a52..0e3eec7d53 100644 --- a/common/wireguard/src/setup.rs +++ b/common/wireguard/src/setup.rs @@ -1,7 +1,11 @@ use std::net::IpAddr; use base64::{engine::general_purpose, Engine as _}; -use log::info; +use defguard_wireguard_rs::host::Peer; +use defguard_wireguard_rs::key::Key; +use defguard_wireguard_rs::net::IpAddrMask; +use log::{info, warn}; +use serde::Deserialize; // The wireguard UDP listener pub const WG_ADDRESS: &str = "0.0.0.0"; @@ -10,21 +14,23 @@ pub const WG_ADDRESS: &str = "0.0.0.0"; // Corresponding public key: "WM8s8bYegwMa0TJ+xIwhk+dImk2IpDUKslDBCZPizlE=" pub(crate) const PRIVATE_KEY: &str = "AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg="; -// The AllowedIPs for the connected peer, which is one a single IP and the same as the IP that the -// peer has configured on their side. -const ALLOWED_IPS: &str = "10.1.0.2"; +#[derive(Deserialize, Debug)] +pub struct PeerPair { + pub addr: String, + pub public_key: String, +} -fn decode_base64_key(base64_key: &str) -> [u8; 32] { +fn decode_base64_key(base64_key: &str) -> Result<[u8; 32], String> { general_purpose::STANDARD .decode(base64_key) - .unwrap() + .map_err(|_| String::from("Could not decode"))? .try_into() - .unwrap() + .map_err(|_| String::from("Not enough bytes")) } pub fn server_static_private_key() -> x25519_dalek::StaticSecret { // TODO: this is a temporary solution for development - let static_private_bytes: [u8; 32] = decode_base64_key(PRIVATE_KEY); + let static_private_bytes: [u8; 32] = decode_base64_key(PRIVATE_KEY).unwrap(); let static_private = x25519_dalek::StaticSecret::from(static_private_bytes); let static_public = x25519_dalek::PublicKey::from(&static_private); info!( @@ -34,23 +40,29 @@ pub fn server_static_private_key() -> x25519_dalek::StaticSecret { static_private } -pub fn peer_static_public_key() -> x25519_dalek::PublicKey { - // A single static public key is used during development +pub fn peer_static_pairs(raw_pairs: Vec) -> Vec { + raw_pairs + .into_iter() + .filter_map(|pair| { + if let Ok(peer_static_public_bytes) = decode_base64_key(&pair.public_key) { + let peer_static_public = x25519_dalek::PublicKey::from(peer_static_public_bytes); + let mut peer = Peer::new(Key::new(peer_static_public.to_bytes())); - // Read from NYM_PEER_PUBLIC_KEY env variable - let peer = std::env::var("NYM_PEER_PUBLIC_KEY").expect("NYM_PEER_PUBLIC_KEY must be set"); - - let peer_static_public_bytes: [u8; 32] = decode_base64_key(&peer); - let peer_static_public = x25519_dalek::PublicKey::from(peer_static_public_bytes); - info!( - "Adding wg peer public key: {}", - general_purpose::STANDARD.encode(peer_static_public) - ); - peer_static_public -} - -pub fn peer_allowed_ips() -> ip_network::IpNetwork { - let key: IpAddr = ALLOWED_IPS.parse().unwrap(); - let cidr = 32u8; - ip_network::IpNetwork::new_truncate(key, cidr).unwrap() + if let Ok(key) = pair.addr.parse::() { + let peer_ip = ip_network::IpNetwork::new_truncate(key, 32u8) + .expect("Netmask should be correct"); + let peer_ip_mask = + IpAddrMask::new(peer_ip.network_address(), peer_ip.netmask()); + peer.set_allowed_ips(vec![peer_ip_mask]); + Some(peer) + } else { + warn!("Not adding {:?} as IP doesn't parse", pair); + None + } + } else { + warn!("Not adding {:?} as public key doesn't decode", pair); + None + } + }) + .collect() } diff --git a/gateway/src/config/mod.rs b/gateway/src/config/mod.rs index b872a1dffd..8489fd6528 100644 --- a/gateway/src/config/mod.rs +++ b/gateway/src/config/mod.rs @@ -242,6 +242,11 @@ impl Config { self } + pub fn with_client_keys_path(mut self, client_keys: PathBuf) -> Self { + self.wireguard.storage_paths.client_keys = client_keys; + self + } + pub fn with_listening_address(mut self, listening_address: IpAddr) -> Self { self.gateway.listening_address = listening_address; diff --git a/gateway/src/config/old_config_v1_1_31.rs b/gateway/src/config/old_config_v1_1_31.rs index 18841a4993..4fbcea6840 100644 --- a/gateway/src/config/old_config_v1_1_31.rs +++ b/gateway/src/config/old_config_v1_1_31.rs @@ -130,7 +130,7 @@ impl From for Config { announced_port: value.wireguard.announced_port, private_network_prefix: Default::default(), storage_paths: nym_node::config::persistence::WireguardPaths { - // no fields (yet) + client_keys: Default::default(), }, }, storage_paths: GatewayPaths { diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index dc35050785..eeb1643857 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -207,7 +207,10 @@ impl Gateway { &self, shutdown: TaskClient, ) -> Result> { - nym_wireguard::start_wireguard(shutdown, Arc::clone(&self.client_registry)).await + let file = std::fs::File::open(&self.config.wireguard.storage_paths.client_keys)?; + let reader = std::io::BufReader::new(file); + let peers = serde_json::from_reader(reader)?; + nym_wireguard::start_wireguard(shutdown, Arc::clone(&self.client_registry), peers).await } fn start_client_websocket_listener( diff --git a/nym-node/src/config/mod.rs b/nym-node/src/config/mod.rs index 3b712f2e63..dd892da235 100644 --- a/nym-node/src/config/mod.rs +++ b/nym-node/src/config/mod.rs @@ -93,7 +93,9 @@ impl Default for Wireguard { ), announced_port: DEFAULT_WIREGUARD_PORT, private_network_prefix: DEFAULT_WIREGUARD_PREFIX, - storage_paths: persistence::WireguardPaths {}, + storage_paths: persistence::WireguardPaths { + client_keys: PathBuf::from("/root/keys_pub.json"), + }, } } } diff --git a/nym-node/src/config/persistence.rs b/nym-node/src/config/persistence.rs index c1cf1824ab..078ace3aa5 100644 --- a/nym-node/src/config/persistence.rs +++ b/nym-node/src/config/persistence.rs @@ -2,9 +2,10 @@ // SPDX-License-Identifier: GPL-3.0-only use serde::{Deserialize, Serialize}; +use std::path::PathBuf; #[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)] #[serde(deny_unknown_fields)] pub struct WireguardPaths { - // pub keys: + pub client_keys: PathBuf, }