Update kernel peers on peer modification (#4622)

* Include wireguard in gw config

* Support nym node first

* Create wg keypair

* Activate wg feature in gw dep

* Move key paths to separate structure

* Use client reg

* Generate and use own private key

* Rename network to ip for wg gw

* Propagate wireguard setup error message

* Remove logs

* Bump gateway version number

* Remove upgrade code

* Init wireguard on migration

* Upgrade code for nym-node too

* Wireguard paths upgrade

* Init wg keys on upgrade

* Simplify pub key translatations

* Fix clippy

* Undo comment change

* Fix tests

* Don't bump version just yet

* Remove redundant source attr

* Remove unused wg details

* Rename wg device

* Init for mixnode migration as well

* Add upgrade for gw wireguard deleted field

* Move interface removal to Drop trait impl

* Fix clippy

* Wgapi could be included on other platforms

* Handle peer control msgs

* Send add peer msg

* Handle double registration

* Fix deadlock

* Fix clippy

* More clippy

* Use same defguard

* Fix unit test

* Fix wasm build

* Move implementations from types to wireguard crate

* Fix linux
This commit is contained in:
Bogdan-Ștefan Neacşu
2024-06-07 14:02:47 +03:00
committed by GitHub
parent 102a8a0d8b
commit 70fa41c165
14 changed files with 335 additions and 190 deletions
Generated
+3
View File
@@ -5031,6 +5031,7 @@ dependencies = [
"nym-sphinx-addressing",
"nym-task",
"nym-types",
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"semver 1.0.23",
@@ -5773,9 +5774,11 @@ name = "nym-wireguard"
version = "0.1.0"
dependencies = [
"base64 0.21.7",
"dashmap",
"defguard_wireguard_rs",
"ip_network",
"log",
"nym-crypto",
"nym-network-defaults",
"nym-task",
"nym-wireguard-types",
+3
View File
@@ -32,4 +32,7 @@ pub enum Error {
#[source]
source: hmac::digest::MacError,
},
#[error("peers can't be modified anymore")]
PeerModifyStopped,
}
-33
View File
@@ -1,10 +1,6 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use dashmap::DashMap;
use nym_crypto::asymmetric::encryption::KeyPair;
use std::sync::Arc;
pub mod config;
pub mod error;
pub mod public_key;
@@ -20,32 +16,3 @@ pub use registration::{
#[cfg(feature = "verify")]
pub use registration::HmacSha256;
#[derive(Clone)]
pub struct WireguardGatewayData {
config: Config,
keypair: Arc<KeyPair>,
client_registry: Arc<GatewayClientRegistry>,
}
impl WireguardGatewayData {
pub fn new(config: Config, keypair: Arc<KeyPair>) -> Self {
WireguardGatewayData {
config,
keypair,
client_registry: Arc::new(DashMap::default()),
}
}
pub fn config(&self) -> Config {
self.config
}
pub fn keypair(&self) -> &Arc<KeyPair> {
&self.keypair
}
pub fn client_registry(&self) -> &Arc<GatewayClientRegistry> {
&self.client_registry
}
}
+11 -9
View File
@@ -17,7 +17,7 @@ use nym_crypto::asymmetric::encryption::PrivateKey;
use sha2::Sha256;
pub type GatewayClientRegistry = DashMap<PeerPublicKey, GatewayClient>;
pub type PendingRegistrations = DashMap<PeerPublicKey, Nonce>;
pub type PendingRegistrations = DashMap<PeerPublicKey, RegistrationData>;
pub type PrivateIPs = DashMap<IpAddr, Free>;
#[cfg(feature = "verify")]
@@ -56,14 +56,16 @@ impl InitMessage {
#[serde(tag = "type", rename_all = "camelCase")]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub enum ClientRegistrationResponse {
PendingRegistration {
nonce: u64,
gateway_data: GatewayClient,
wg_port: u16,
},
Registered {
success: bool,
},
PendingRegistration(RegistrationData),
Registered,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct RegistrationData {
pub nonce: u64,
pub gateway_data: GatewayClient,
pub wg_port: u16,
}
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
+2
View File
@@ -12,6 +12,7 @@ license.workspace = true
[dependencies]
base64 = "0.21.3"
dashmap = { workspace = true }
defguard_wireguard_rs = { workspace = true }
# The latest version on crates.io at the time of writing this (6.0.0) has a
# version mismatch with x25519-dalek/curve25519-dalek that is resolved in the
@@ -19,6 +20,7 @@ defguard_wireguard_rs = { workspace = true }
x25519-dalek = "2.0.0"
ip_network = { workspace = true }
log.workspace = true
nym-crypto = { path = "../crypto", features = ["asymmetric"] }
nym-network-defaults = { path = "../network-defaults" }
nym-task = { path = "../task" }
nym-wireguard-types = { path = "../wireguard-types" }
+85 -19
View File
@@ -3,42 +3,106 @@
// #![warn(clippy::expect_used)]
// #![warn(clippy::unwrap_used)]
use defguard_wireguard_rs::WGApi;
use dashmap::DashMap;
use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask, WGApi};
use nym_crypto::asymmetric::encryption::KeyPair;
use nym_wireguard_types::{Config, Error, GatewayClient, GatewayClientRegistry};
use peer_controller::PeerControlMessage;
use std::sync::Arc;
use tokio::sync::mpsc::{self, UnboundedReceiver};
const WG_TUN_NAME: &str = "nymwg";
pub mod peer_controller;
pub struct WgApiWrapper {
wg_api: WGApi,
inner: WGApi,
}
impl WgApiWrapper {
pub fn new(wg_api: WGApi) -> Self {
WgApiWrapper { wg_api }
WgApiWrapper { inner: wg_api }
}
}
impl Drop for WgApiWrapper {
fn drop(&mut self) {
if let Err(e) = defguard_wireguard_rs::WireguardInterfaceApi::remove_interface(&self.wg_api)
if let Err(e) = defguard_wireguard_rs::WireguardInterfaceApi::remove_interface(&self.inner)
{
log::error!("Could not remove the wireguard interface: {:?}", e);
}
}
}
#[derive(Clone)]
pub struct WireguardGatewayData {
config: Config,
keypair: Arc<KeyPair>,
client_registry: Arc<GatewayClientRegistry>,
peer_tx: mpsc::UnboundedSender<PeerControlMessage>,
}
impl WireguardGatewayData {
pub fn new(
config: Config,
keypair: Arc<KeyPair>,
) -> (Self, mpsc::UnboundedReceiver<PeerControlMessage>) {
let (peer_tx, peer_rx) = mpsc::unbounded_channel();
(
WireguardGatewayData {
config,
keypair,
client_registry: Arc::new(DashMap::default()),
peer_tx,
},
peer_rx,
)
}
pub fn config(&self) -> Config {
self.config
}
pub fn keypair(&self) -> &Arc<KeyPair> {
&self.keypair
}
pub fn client_registry(&self) -> &Arc<GatewayClientRegistry> {
&self.client_registry
}
pub fn add_peer(&self, client: &GatewayClient) -> Result<(), Error> {
let mut peer = Peer::new(Key::new(client.pub_key.to_bytes()));
peer.allowed_ips
.push(IpAddrMask::new(client.private_ip, 32));
let msg = PeerControlMessage::AddPeer(peer);
self.peer_tx.send(msg).map_err(|_| Error::PeerModifyStopped)
}
pub fn remove_peer(&self, client: &GatewayClient) -> Result<(), Error> {
let key = Key::new(client.pub_key().to_bytes());
let msg = PeerControlMessage::RemovePeer(key);
self.peer_tx.send(msg).map_err(|_| Error::PeerModifyStopped)
}
}
pub struct WireguardData {
pub inner: WireguardGatewayData,
pub peer_rx: UnboundedReceiver<PeerControlMessage>,
}
/// Start wireguard device
#[cfg(target_os = "linux")]
pub async fn start_wireguard(
mut task_client: nym_task::TaskClient,
wireguard_data: std::sync::Arc<nym_wireguard_types::WireguardGatewayData>,
) -> Result<WgApiWrapper, Box<dyn std::error::Error + Send + Sync + 'static>> {
task_client: nym_task::TaskClient,
wireguard_data: WireguardData,
) -> Result<std::sync::Arc<WgApiWrapper>, Box<dyn std::error::Error + Send + Sync + 'static>> {
use base64::{prelude::BASE64_STANDARD, Engine};
use defguard_wireguard_rs::{
host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WireguardInterfaceApi,
};
use defguard_wireguard_rs::{InterfaceConfiguration, WireguardInterfaceApi};
use peer_controller::PeerController;
let mut peers = vec![];
for peer_client in wireguard_data.client_registry().iter() {
for peer_client in wireguard_data.inner.client_registry().iter() {
let mut peer = Peer::new(Key::new(peer_client.pub_key.to_bytes()));
let peer_ip_mask = IpAddrMask::new(peer_client.private_ip, 32);
peer.set_allowed_ips(vec![peer_ip_mask]);
@@ -46,21 +110,23 @@ pub async fn start_wireguard(
}
let ifname = String::from(WG_TUN_NAME);
let wgapi = WGApi::new(ifname.clone(), false)?;
wgapi.create_interface()?;
let wg_api = defguard_wireguard_rs::WGApi::new(ifname.clone(), false)?;
wg_api.create_interface()?;
let interface_config = InterfaceConfiguration {
name: ifname.clone(),
prvkey: BASE64_STANDARD.encode(wireguard_data.keypair().private_key().to_bytes()),
address: wireguard_data.config().private_ip.to_string(),
port: wireguard_data.config().announced_port as u32,
prvkey: BASE64_STANDARD.encode(wireguard_data.inner.keypair().private_key().to_bytes()),
address: wireguard_data.inner.config().private_ip.to_string(),
port: wireguard_data.inner.config().announced_port as u32,
peers,
};
wgapi.configure_interface(&interface_config)?;
wg_api.configure_interface(&interface_config)?;
// wgapi.configure_peer_routing(&peers)?;
tokio::spawn(async move { task_client.recv().await });
let wg_api = std::sync::Arc::new(WgApiWrapper::new(wg_api));
let mut controller = PeerController::new(wg_api.clone(), wireguard_data.peer_rx);
tokio::spawn(async move { controller.run(task_client).await });
Ok(WgApiWrapper::new(wgapi))
Ok(wg_api)
}
#[cfg(not(target_os = "linux"))]
+58
View File
@@ -0,0 +1,58 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::sync::Arc;
use defguard_wireguard_rs::{host::Peer, key::Key, WireguardInterfaceApi};
use tokio::sync::mpsc;
use crate::WgApiWrapper;
pub enum PeerControlMessage {
AddPeer(Peer),
RemovePeer(Key),
}
pub struct PeerController {
peer_rx: mpsc::UnboundedReceiver<PeerControlMessage>,
wg_api: Arc<WgApiWrapper>,
}
impl PeerController {
pub fn new(
wg_api: Arc<WgApiWrapper>,
peer_rx: mpsc::UnboundedReceiver<PeerControlMessage>,
) -> Self {
PeerController { wg_api, peer_rx }
}
pub async fn run(&mut self, mut task_client: nym_task::TaskClient) {
loop {
tokio::select! {
_ = task_client.recv() => {
log::trace!("PeerController handler: Received shutdown");
break;
}
msg = self.peer_rx.recv() => {
match msg {
Some(PeerControlMessage::AddPeer(peer)) => {
if self.wg_api.inner.configure_peer(&peer).is_err() {
log::error!("Could not configure peer {:?}", peer);
}
}
Some(PeerControlMessage::RemovePeer(peer_pubkey)) => {
if self.wg_api.inner.remove_peer(&peer_pubkey).is_err() {
log::error!("Could not remove peer with key {:?}", peer_pubkey);
}
}
None => {
log::trace!("PeerController [main loop]: stopping since channel closed");
break;
}
}
}
}
}
}
}
-13
View File
@@ -14,7 +14,6 @@ use nym_node_http_api::api::api_requests::SignedHostInformation;
use nym_node_http_api::NymNodeHttpError;
use nym_sphinx::addressing::clients::Recipient;
use nym_task::TaskClient;
use nym_wireguard_types::WireguardGatewayData;
use std::sync::Arc;
fn load_gateway_details(
@@ -141,8 +140,6 @@ pub(crate) struct HttpApiBuilder<'a> {
identity_keypair: &'a identity::KeyPair,
// TODO: this should be a wg specific key and not re-used sphinx
sphinx_keypair: Arc<encryption::KeyPair>,
wireguard_data: Option<Arc<WireguardGatewayData>>,
}
impl<'a> HttpApiBuilder<'a> {
@@ -158,7 +155,6 @@ impl<'a> HttpApiBuilder<'a> {
exit_policy: None,
identity_keypair,
sphinx_keypair,
wireguard_data: None,
}
}
@@ -222,15 +218,6 @@ impl<'a> HttpApiBuilder<'a> {
self
}
#[must_use]
pub(crate) fn with_wireguard_data(
mut self,
wireguard_data: Option<Arc<WireguardGatewayData>>,
) -> Self {
self.wireguard_data = wireguard_data;
self
}
pub(crate) fn start(self, task_client: TaskClient) -> Result<(), GatewayError> {
debug!("starting http API");
+10 -14
View File
@@ -27,7 +27,6 @@ use nym_task::{TaskClient, TaskHandle, TaskManager};
use nym_types::gateway::GatewayNodeDetailsResponse;
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
use nym_validator_client::{nyxd, DirectSigningHttpRpcNyxdClient};
use nym_wireguard_types::WireguardGatewayData;
use rand::seq::SliceRandom;
use rand::thread_rng;
use std::net::SocketAddr;
@@ -128,7 +127,8 @@ pub struct Gateway<St = PersistentStorage> {
storage: St,
wireguard_data: Option<Arc<WireguardGatewayData>>,
#[cfg(all(feature = "wireguard", target_os = "linux"))]
wireguard_data: Option<nym_wireguard::WireguardData>,
run_http_server: bool,
task_client: Option<TaskClient>,
@@ -149,6 +149,7 @@ impl<St> Gateway<St> {
config,
network_requester_opts,
ip_packet_router_opts,
#[cfg(all(feature = "wireguard", target_os = "linux"))]
wireguard_data: None,
run_http_server: true,
task_client: None,
@@ -170,6 +171,7 @@ impl<St> Gateway<St> {
identity_keypair,
sphinx_keypair,
storage,
#[cfg(all(feature = "wireguard", target_os = "linux"))]
wireguard_data: None,
run_http_server: true,
task_client: None,
@@ -184,13 +186,8 @@ impl<St> Gateway<St> {
self.task_client = Some(task_client)
}
pub fn set_wireguard_data(&mut self, wireguard_data: Arc<WireguardGatewayData>) {
// sanity check:
if let Some(wg_data) = self.wireguard_data.as_ref() {
if Arc::strong_count(wg_data) != 1 {
panic!("the client registry is already being used elsewhere")
}
}
#[cfg(all(feature = "wireguard", target_os = "linux"))]
pub fn set_wireguard_data(&mut self, wireguard_data: nym_wireguard::WireguardData) {
self.wireguard_data = Some(wireguard_data)
}
@@ -229,11 +226,11 @@ impl<St> Gateway<St> {
#[cfg(all(feature = "wireguard", target_os = "linux"))]
async fn start_wireguard(
&self,
&mut self,
shutdown: TaskClient,
) -> Result<nym_wireguard::WgApiWrapper, Box<dyn std::error::Error + Send + Sync>> {
if let Some(wireguard_data) = self.wireguard_data.as_ref() {
nym_wireguard::start_wireguard(shutdown, Arc::clone(wireguard_data)).await
) -> Result<Arc<nym_wireguard::WgApiWrapper>, Box<dyn std::error::Error + Send + Sync>> {
if let Some(wireguard_data) = self.wireguard_data.take() {
nym_wireguard::start_wireguard(shutdown, wireguard_data).await
} else {
Err(Box::new(GatewayError::WireguardNotSet))
}
@@ -561,7 +558,6 @@ impl<St> Gateway<St> {
self.identity_keypair.as_ref(),
self.sphinx_keypair.clone(),
)
.with_wireguard_data(self.wireguard_data.clone())
.with_maybe_network_requester(self.network_requester_opts.as_ref().map(|o| &o.config))
.with_maybe_network_request_filter(nr_request_filter)
.with_maybe_ip_packet_router(self.ip_packet_router_opts.as_ref().map(|o| &o.config))
+1
View File
@@ -49,6 +49,7 @@ nym-sphinx-acknowledgements = { path = "../common/nymsphinx/acknowledgements" }
nym-sphinx-addressing = { path = "../common/nymsphinx/addressing" }
nym-task = { path = "../common/task" }
nym-types = { path = "../common/types" }
nym-wireguard = { path = "../common/wireguard" }
nym-wireguard-types = { path = "../common/wireguard-types", default-features = false }
# nodes:
-2
View File
@@ -46,5 +46,3 @@ serde_json.workspace = true
hmac = { workspace = true }
tower = { workspace = true }
x25519-dalek = { version = "2.0.0" }
nym-crypto = { path = "../../common/crypto", features = ["rand"] }
@@ -11,33 +11,59 @@ use axum::extract::{Path, Query, State};
use axum::http::StatusCode;
use axum::Json;
use nym_node_requests::api::v1::gateway::client_interfaces::wireguard::models::{
ClientMessage, ClientRegistrationResponse, GatewayClient, InitMessage, Nonce, PeerPublicKey,
ClientMessage, ClientRegistrationResponse, GatewayClient, InitMessage, PeerPublicKey,
};
use nym_wireguard_types::registration::RegistrationData;
use rand::{prelude::IteratorRandom, thread_rng};
fn remove_from_registry(
state: &WireguardAppStateInner,
remote_public: &PeerPublicKey,
gateway_client: &GatewayClient,
) -> Result<(), RequestError> {
state
.wireguard_gateway_data
.remove_peer(gateway_client)
.map_err(|err| RequestError::from_err(err, StatusCode::INTERNAL_SERVER_ERROR))?;
state
.wireguard_gateway_data
.client_registry()
.remove(remote_public);
Ok(())
}
async fn process_final_message(
client: GatewayClient,
state: &WireguardAppStateInner,
) -> Result<StatusCode, RequestError> {
let preshared_nonce = {
if let Some(nonce) = state.registration_in_progress.get(&client.pub_key()) {
*nonce
} else {
return Err(RequestError::from_err(
WireguardError::RegistrationNotInProgress,
StatusCode::BAD_REQUEST,
));
}
};
) -> Result<ClientRegistrationResponse, RequestError> {
let registration_data = state
.registration_in_progress
.get(&client.pub_key())
.ok_or(RequestError::from_err(
WireguardError::RegistrationNotInProgress,
StatusCode::BAD_REQUEST,
))?
.value()
.clone();
if client
.verify(state.keypair.private_key(), preshared_nonce)
.verify(
state.wireguard_gateway_data.keypair().private_key(),
registration_data.nonce,
)
.is_ok()
{
state
.wireguard_gateway_data
.add_peer(&client)
.map_err(|err| RequestError::from_err(err, StatusCode::INTERNAL_SERVER_ERROR))?;
state.registration_in_progress.remove(&client.pub_key());
state.client_registry.insert(client.pub_key(), client);
state
.wireguard_gateway_data
.client_registry()
.insert(client.pub_key(), client);
Ok(StatusCode::OK)
Ok(ClientRegistrationResponse::Registered)
} else {
Err(RequestError::from_err(
WireguardError::MacVerificationFailure,
@@ -46,12 +72,65 @@ async fn process_final_message(
}
}
async fn process_init_message(init_message: InitMessage, state: &WireguardAppStateInner) -> Nonce {
async fn process_init_message(
init_message: InitMessage,
state: &WireguardAppStateInner,
) -> Result<ClientRegistrationResponse, RequestError> {
let remote_public = init_message.pub_key();
let nonce: u64 = fastrand::u64(..);
if let Some(registration_data) = state.registration_in_progress.get(&remote_public) {
return Ok(ClientRegistrationResponse::PendingRegistration(
registration_data.value().clone(),
));
}
let gateway_client_opt = if let Some(gateway_client) = state
.wireguard_gateway_data
.client_registry()
.get(&remote_public)
{
let mut private_ip_ref = state
.free_private_network_ips
.get_mut(&gateway_client.private_ip)
.ok_or(RequestError::new(
"Internal data corruption",
StatusCode::INTERNAL_SERVER_ERROR,
))?;
*private_ip_ref = true;
Some(gateway_client.clone())
} else {
None
};
if let Some(gateway_client) = gateway_client_opt {
remove_from_registry(state, &remote_public, &gateway_client)?;
}
let mut private_ip_ref = state
.free_private_network_ips
.iter_mut()
.filter(|r| **r)
.choose(&mut thread_rng())
.ok_or(RequestError::new(
"No more space in the network",
StatusCode::SERVICE_UNAVAILABLE,
))?;
// mark it as used, even though it's not final
*private_ip_ref = false;
let gateway_data = GatewayClient::new(
state.wireguard_gateway_data.keypair().private_key(),
remote_public.inner(),
*private_ip_ref.key(),
nonce,
);
let registration_data = RegistrationData {
nonce,
gateway_data,
wg_port: state.binding_port,
};
state
.registration_in_progress
.insert(init_message.pub_key(), nonce);
nonce
.insert(remote_public, registration_data.clone());
Ok(ClientRegistrationResponse::PendingRegistration(
registration_data,
))
}
/// Perform wireguard client registration.
@@ -86,44 +165,11 @@ pub(crate) async fn register_client(
return Err(RequestError::new_status(StatusCode::NOT_IMPLEMENTED));
};
match payload {
ClientMessage::Initial(init) => {
let remote_public = init.pub_key().inner();
let nonce = process_init_message(init, state).await;
let mut private_ip_ref = state
.free_private_network_ips
.iter_mut()
.filter(|r| **r)
.choose(&mut thread_rng())
.ok_or(RequestError::new(
"No more space in the network",
StatusCode::SERVICE_UNAVAILABLE,
))?;
// mark it as used, even though it's not final
*private_ip_ref = false;
let gateway_data = GatewayClient::new(
state.keypair.private_key(),
remote_public,
*private_ip_ref.key(),
nonce,
);
let response = ClientRegistrationResponse::PendingRegistration {
nonce,
gateway_data,
wg_port: state.binding_port,
};
Ok(output.to_response(response))
}
ClientMessage::Final(finalize) => {
let result = process_final_message(finalize, state).await?;
if result.is_success() {
let response = ClientRegistrationResponse::Registered { success: true };
Ok(output.to_response(response))
} else {
Err(RequestError::new_status(result))
}
}
}
let response = match payload {
ClientMessage::Initial(init) => process_init_message(init, state).await?,
ClientMessage::Final(finalize) => process_final_message(finalize, state).await?,
};
Ok(output.to_response(response))
}
pub type RegisterClientResponse = FormattedResponse<ClientRegistrationResponse>;
@@ -154,7 +200,8 @@ pub(crate) async fn get_all_clients(
};
let clients = state
.client_registry
.wireguard_gateway_data
.client_registry()
.iter()
.map(|c| c.pub_key())
.collect::<Vec<PeerPublicKey>>();
@@ -196,7 +243,8 @@ pub(crate) async fn get_client(
};
let clients = state
.client_registry
.wireguard_gateway_data
.client_registry()
.iter()
.filter_map(|c| {
if c.pub_key() == pub_key {
@@ -8,11 +8,10 @@ use crate::error::NymNodeHttpError;
use axum::routing::{get, post};
use axum::Router;
use ipnetwork::IpNetwork;
use nym_crypto::asymmetric::x25519::KeyPair;
use nym_node_requests::routes::api::v1::gateway::client_interfaces::wireguard;
use nym_wireguard::WireguardGatewayData;
use nym_wireguard_types::registration::PendingRegistrations;
use nym_wireguard_types::registration::PrivateIPs;
use nym_wireguard_types::registration::{GatewayClientRegistry, PendingRegistrations};
use nym_wireguard_types::WireguardGatewayData;
use std::sync::Arc;
pub(crate) mod client_registry;
@@ -27,15 +26,14 @@ pub struct WireguardAppState {
impl WireguardAppState {
pub fn new(
wireguard_gateway_data: &WireguardGatewayData,
wireguard_gateway_data: WireguardGatewayData,
registration_in_progress: Arc<PendingRegistrations>,
binding_port: u16,
private_ip_network: IpNetwork,
) -> Result<Self, NymNodeHttpError> {
Ok(WireguardAppState {
inner: Some(WireguardAppStateInner {
keypair: wireguard_gateway_data.keypair().clone(),
client_registry: wireguard_gateway_data.client_registry().clone(),
wireguard_gateway_data,
registration_in_progress,
binding_port,
free_private_network_ips: Arc::new(
@@ -81,8 +79,7 @@ macro_rules! get_state {
#[derive(Clone)]
pub(crate) struct WireguardAppStateInner {
keypair: Arc<KeyPair>,
client_registry: Arc<GatewayClientRegistry>,
wireguard_gateway_data: WireguardGatewayData,
registration_in_progress: Arc<PendingRegistrations>,
binding_port: u16,
free_private_network_ips: Arc<PrivateIPs>,
@@ -116,7 +113,8 @@ mod test {
PeerPublicKey,
};
use nym_node_requests::routes::api::v1::gateway::client_interfaces::wireguard;
use nym_wireguard_types::registration::HmacSha256;
use nym_wireguard::{peer_controller::PeerControlMessage, WireguardGatewayData};
use nym_wireguard_types::registration::{HmacSha256, RegistrationData};
use std::net::IpAddr;
use std::str::FromStr;
use std::sync::Arc;
@@ -169,7 +167,6 @@ mod test {
let client_dh = client_static_private.diffie_hellman(&gateway_static_public);
let registration_in_progress = Arc::new(DashMap::new());
let client_registry = Arc::new(DashMap::new());
let free_private_network_ips = Arc::new(
IpNetwork::from_str("10.1.0.0/24")
.unwrap()
@@ -178,11 +175,19 @@ mod test {
.collect(),
);
let client_private_ip = IpAddr::from_str("10.1.0.42").unwrap();
let (wireguard_gateway_data, mut peer_rx) = WireguardGatewayData::new(
nym_wireguard_types::Config {
bind_address: "0.0.0.0:51822".parse().unwrap(),
private_ip: "10.1.0.1".parse().unwrap(),
announced_port: 51822,
private_network_prefix: 16,
},
Arc::new(gateway_key_pair),
);
let state = WireguardAppState {
inner: Some(WireguardAppStateInner {
client_registry: Arc::clone(&client_registry),
keypair: Arc::new(gateway_key_pair),
wireguard_gateway_data: wireguard_gateway_data.clone(),
registration_in_progress: Arc::clone(&registration_in_progress),
binding_port: 8080,
free_private_network_ips,
@@ -214,11 +219,11 @@ mod test {
assert_eq!(response.status(), StatusCode::OK);
assert!(!registration_in_progress.is_empty());
let ClientRegistrationResponse::PendingRegistration {
let ClientRegistrationResponse::PendingRegistration(RegistrationData {
nonce,
gateway_data,
wg_port: 8080,
} = serde_json::from_slice(&to_bytes(response.into_body(), usize::MAX).await.unwrap())
}) = serde_json::from_slice(&to_bytes(response.into_body(), usize::MAX).await.unwrap())
.unwrap()
else {
panic!("invalid response")
@@ -252,9 +257,11 @@ mod test {
.call(final_request)
.await
.unwrap();
let msg = peer_rx.recv().await.unwrap();
assert!(matches!(msg, PeerControlMessage::AddPeer(_)));
assert_eq!(response.status(), StatusCode::OK);
assert!(!client_registry.is_empty());
assert!(!wireguard_gateway_data.client_registry().is_empty());
let clients_request = Request::builder()
.method("GET")
@@ -278,7 +285,8 @@ mod test {
assert!(!clients.is_empty());
assert_eq!(
client_registry
wireguard_gateway_data
.client_registry()
.iter()
.map(|c| c.value().pub_key())
.collect::<Vec<PeerPublicKey>>(),
+32 -26
View File
@@ -33,11 +33,12 @@ use nym_node_http_api::{NymNodeHTTPServer, NymNodeRouter};
use nym_sphinx_acknowledgements::AckKey;
use nym_sphinx_addressing::Recipient;
use nym_task::{TaskClient, TaskManager};
use nym_wireguard_types::WireguardGatewayData;
use nym_wireguard::{peer_controller::PeerControlMessage, WireguardGatewayData};
use rand::rngs::OsRng;
use rand::{CryptoRng, RngCore};
use std::path::Path;
use std::sync::Arc;
use tokio::sync::mpsc::UnboundedReceiver;
use tracing::{debug, error, info, trace};
use zeroize::Zeroizing;
@@ -252,16 +253,19 @@ impl ExitGatewayData {
}
pub struct WireguardData {
x25519_wireguard_keys: Arc<x25519::KeyPair>,
inner: WireguardGatewayData,
peer_rx: UnboundedReceiver<PeerControlMessage>,
}
impl WireguardData {
pub(crate) fn new(config: &Wireguard) -> Result<Self, NymNodeError> {
Ok(WireguardData {
x25519_wireguard_keys: Arc::new(load_x25519_wireguard_keypair(
let (inner, peer_rx) = WireguardGatewayData::new(
config.clone().into(),
Arc::new(load_x25519_wireguard_keypair(
config.storage_paths.x25519_wireguard_storage_paths(),
)?),
})
);
Ok(WireguardData { inner, peer_rx })
}
pub(crate) fn initialise(config: &Wireguard) -> Result<(), ExitGatewayError> {
@@ -278,6 +282,15 @@ impl WireguardData {
}
}
impl From<WireguardData> for nym_wireguard::WireguardData {
fn from(value: WireguardData) -> Self {
nym_wireguard::WireguardData {
inner: value.inner,
peer_rx: value.peer_rx,
}
}
}
pub(crate) struct NymNode {
config: Config,
description: NodeDescription,
@@ -358,10 +371,6 @@ impl NymNode {
pub(crate) async fn new(config: Config) -> Result<Self, NymNodeError> {
let wireguard_data = WireguardData::new(&config.wireguard)?;
let wireguard_gateway_data = WireguardGatewayData::new(
config.wireguard.clone().into(),
wireguard_data.x25519_wireguard_keys.clone(),
);
Ok(NymNode {
ed25519_identity_keys: Arc::new(load_ed25519_identity_keypair(
config.storage_paths.keys.ed25519_identity_storage_paths(),
@@ -375,8 +384,11 @@ impl NymNode {
description: load_node_description(&config.storage_paths.description)?,
verloc_stats: Default::default(),
mixnode: MixnodeData::new(&config.mixnode)?,
entry_gateway: EntryGatewayData::new(&config.entry_gateway, wireguard_gateway_data)
.await?,
entry_gateway: EntryGatewayData::new(
&config.entry_gateway,
wireguard_data.inner.clone(),
)
.await?,
exit_gateway: ExitGatewayData::new(&config.exit_gateway)?,
wireguard: wireguard_data,
config,
@@ -400,7 +412,7 @@ impl NymNode {
}
fn x25519_wireguard_key(&self) -> &x25519::PublicKey {
self.wireguard.x25519_wireguard_keys.public_key()
self.wireguard.inner.keypair().public_key()
}
pub(crate) fn display_details(&self) -> DisplayDetails {
@@ -432,7 +444,7 @@ impl NymNode {
self.x25519_noise_keys.public_key()
}
fn start_mixnode(&self, task_client: TaskClient) -> Result<(), NymNodeError> {
fn start_mixnode(self, task_client: TaskClient) -> Result<(), NymNodeError> {
info!("going to start the nym-node in MIXNODE mode");
let config = ephemeral_mixnode_config(self.config.clone())?;
@@ -455,15 +467,11 @@ impl NymNode {
Ok(())
}
fn start_entry_gateway(&self, task_client: TaskClient) -> Result<(), NymNodeError> {
fn start_entry_gateway(self, task_client: TaskClient) -> Result<(), NymNodeError> {
info!("going to start the nym-node in ENTRY GATEWAY mode");
let config =
ephemeral_entry_gateway_config(self.config.clone(), &self.entry_gateway.mnemonic)?;
let wireguard_data = Arc::new(WireguardGatewayData::new(
self.config.wireguard.clone().into(),
self.wireguard.x25519_wireguard_keys.clone(),
));
let mut entry_gateway = Gateway::new_loaded(
config,
None,
@@ -474,7 +482,8 @@ impl NymNode {
);
entry_gateway.disable_http_server();
entry_gateway.set_task_client(task_client);
entry_gateway.set_wireguard_data(wireguard_data);
#[cfg(all(feature = "wireguard", target_os = "linux"))]
entry_gateway.set_wireguard_data(self.wireguard.into());
tokio::spawn(async move {
if let Err(err) = entry_gateway.run().await {
@@ -484,15 +493,11 @@ impl NymNode {
Ok(())
}
fn start_exit_gateway(&self, task_client: TaskClient) -> Result<(), NymNodeError> {
fn start_exit_gateway(self, task_client: TaskClient) -> Result<(), NymNodeError> {
info!("going to start the nym-node in EXIT GATEWAY mode");
let config =
ephemeral_exit_gateway_config(self.config.clone(), &self.entry_gateway.mnemonic)?;
let wireguard_data = Arc::new(WireguardGatewayData::new(
self.config.wireguard.clone().into(),
self.wireguard.x25519_wireguard_keys.clone(),
));
let mut exit_gateway = Gateway::new_loaded(
config.gateway,
@@ -504,7 +509,8 @@ impl NymNode {
);
exit_gateway.disable_http_server();
exit_gateway.set_task_client(task_client);
exit_gateway.set_wireguard_data(wireguard_data);
#[cfg(all(feature = "wireguard", target_os = "linux"))]
exit_gateway.set_wireguard_data(self.wireguard.into());
tokio::spawn(async move {
if let Err(err) = exit_gateway.run().await {
@@ -585,7 +591,7 @@ impl NymNode {
)?;
let wg_state = WireguardAppState::new(
&self.entry_gateway.wireguard_data,
self.entry_gateway.wireguard_data.clone(),
Default::default(),
self.config.wireguard.bind_address.port(),
wireguard_private_network,