Wireguard private metadata
This commit is contained in:
Generated
+25
@@ -5723,6 +5723,7 @@ dependencies = [
|
||||
"nym-types",
|
||||
"nym-validator-client",
|
||||
"nym-wireguard",
|
||||
"nym-wireguard-private-metadata",
|
||||
"nym-wireguard-types",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
@@ -7322,6 +7323,30 @@ dependencies = [
|
||||
"x25519-dalek",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-wireguard-private-metadata"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-trait",
|
||||
"axum 0.7.9",
|
||||
"bincode",
|
||||
"futures",
|
||||
"nym-credential-verification",
|
||||
"nym-credentials-interface",
|
||||
"nym-http-api-common",
|
||||
"nym-wireguard",
|
||||
"schemars 0.8.22",
|
||||
"serde",
|
||||
"thiserror 2.0.12",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tower-http 0.5.2",
|
||||
"utoipa",
|
||||
"utoipa-swagger-ui",
|
||||
"utoipauto",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nym-wireguard-types"
|
||||
version = "0.1.0"
|
||||
|
||||
@@ -102,6 +102,7 @@ members = [
|
||||
"common/wasm/storage",
|
||||
"common/wasm/utils",
|
||||
"common/wireguard",
|
||||
"common/wireguard-private-metadata",
|
||||
"common/wireguard-types",
|
||||
"common/zulip-client",
|
||||
"documentation/autodoc",
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::ecash::traits::EcashManager;
|
||||
use async_trait::async_trait;
|
||||
use bandwidth_storage_manager::BandwidthStorageManager;
|
||||
use nym_credentials::ecash::utils::{cred_exp_date, ecash_today, EcashTime};
|
||||
use nym_credentials_interface::{Bandwidth, ClientTicket, TicketType};
|
||||
@@ -139,3 +140,18 @@ impl CredentialVerifier {
|
||||
.await)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait TicketVerifier {
|
||||
/// Verify that the ticket is valid and cryptographically correct.
|
||||
/// If the verification succeeds, also increase the bandwidth with the ticket's
|
||||
/// amount and return the latest available bandwidth
|
||||
async fn verify(&mut self) -> Result<i64>;
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl TicketVerifier for CredentialVerifier {
|
||||
async fn verify(&mut self) -> Result<i64> {
|
||||
self.verify().await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,7 +47,8 @@ pub mod nyx {
|
||||
pub mod wireguard {
|
||||
use std::net::{Ipv4Addr, Ipv6Addr};
|
||||
|
||||
pub const WG_PORT: u16 = 51822;
|
||||
pub const WG_TUNNEL_PORT: u16 = 51822;
|
||||
pub const WG_METADATA_PORT: u16 = 51830;
|
||||
|
||||
// The interface used to route traffic
|
||||
pub const WG_TUN_BASE_NAME: &str = "nymwg";
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
[package]
|
||||
name = "nym-wireguard-private-metadata"
|
||||
version = "0.1.0"
|
||||
authors.workspace = true
|
||||
repository.workspace = true
|
||||
homepage.workspace = true
|
||||
documentation.workspace = true
|
||||
edition.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
anyhow = { workspace = true }
|
||||
axum = { workspace = true, features = ["tokio", "macros"] }
|
||||
bincode = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
schemars = { workspace = true, features = ["preserve_order"] }
|
||||
serde = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util"] }
|
||||
tokio-util = { workspace = true }
|
||||
tower-http = { workspace = true, features = [
|
||||
"cors",
|
||||
"trace",
|
||||
"compression-br",
|
||||
"compression-deflate",
|
||||
"compression-gzip",
|
||||
"compression-zstd",
|
||||
] }
|
||||
utoipa = { workspace = true, features = ["axum_extras", "time"] }
|
||||
utoipauto = { workspace = true }
|
||||
utoipa-swagger-ui = { workspace = true, features = ["axum"] }
|
||||
|
||||
nym-credentials-interface = { path = "../credentials-interface" }
|
||||
nym-credential-verification = { path = "../credential-verification" }
|
||||
nym-http-api-common = { path = "../http-api-common", features = [
|
||||
"middleware",
|
||||
"utoipa",
|
||||
"output",
|
||||
] }
|
||||
nym-wireguard = { path = "../wireguard" }
|
||||
|
||||
[dev-dependencies]
|
||||
async-trait = { workspace = true }
|
||||
@@ -0,0 +1,36 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, thiserror::Error)]
|
||||
pub enum MetadataError {
|
||||
#[error("peers can't be interacted with anymore")]
|
||||
PeerInteractionStopped,
|
||||
|
||||
#[error("no response received")]
|
||||
NoResponse,
|
||||
|
||||
#[error("query was not successful: {reason}")]
|
||||
Unsuccessful { reason: String },
|
||||
|
||||
#[error("Models error: {message}")]
|
||||
Models { message: String },
|
||||
|
||||
#[error("Credential verification error: {message}")]
|
||||
CredentialVerification { message: String },
|
||||
}
|
||||
|
||||
impl From<crate::models::error::Error> for MetadataError {
|
||||
fn from(value: crate::models::error::Error) -> Self {
|
||||
Self::Models {
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<nym_credential_verification::Error> for MetadataError {
|
||||
fn from(value: nym_credential_verification::Error) -> Self {
|
||||
Self::CredentialVerification {
|
||||
message: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use tokio::task::JoinHandle;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
|
||||
use nym_wireguard::WgApiWrapper;
|
||||
|
||||
pub(crate) mod openapi;
|
||||
pub(crate) mod router;
|
||||
pub(crate) mod state;
|
||||
|
||||
/// Shutdown goes 2 directions:
|
||||
/// 1. signal background tasks to gracefully finish
|
||||
/// 2. signal server itself
|
||||
///
|
||||
/// These are done through separate shutdown handles. Of course, shut down server
|
||||
/// AFTER you have shut down BG tasks (or past their grace period).
|
||||
#[allow(unused)]
|
||||
pub struct ShutdownHandles {
|
||||
axum_shutdown_button: CancellationToken,
|
||||
/// Tokio JoinHandle for axum server's task
|
||||
axum_join_handle: AxumJoinHandle,
|
||||
/// Wireguard API for kernel interactions
|
||||
wg_api: Arc<WgApiWrapper>,
|
||||
}
|
||||
|
||||
impl ShutdownHandles {
|
||||
/// Cancellation token is given to Axum server constructor. When the token
|
||||
/// receives a shutdown signal, Axum server will shut down gracefully.
|
||||
pub fn new(
|
||||
axum_join_handle: AxumJoinHandle,
|
||||
wg_api: Arc<WgApiWrapper>,
|
||||
axum_shutdown_button: CancellationToken,
|
||||
) -> Self {
|
||||
Self {
|
||||
axum_shutdown_button,
|
||||
axum_join_handle,
|
||||
wg_api,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type AxumJoinHandle = JoinHandle<std::io::Result<()>>;
|
||||
@@ -0,0 +1,14 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use utoipa::OpenApi;
|
||||
|
||||
use crate::models::{AvailableBandwidthResponse, TopUpRequest};
|
||||
|
||||
#[derive(OpenApi)]
|
||||
#[openapi(
|
||||
info(title = "Nym Wireguard Private Metadata"),
|
||||
tags(),
|
||||
components(schemas(AvailableBandwidthResponse, TopUpRequest))
|
||||
)]
|
||||
pub(crate) struct ApiDoc;
|
||||
@@ -0,0 +1,101 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use anyhow::anyhow;
|
||||
use axum::response::Redirect;
|
||||
use axum::routing::get;
|
||||
use axum::Router;
|
||||
use core::net::SocketAddr;
|
||||
use nym_http_api_common::middleware::logging::log_request_info;
|
||||
use tokio::net::TcpListener;
|
||||
use tokio_util::sync::WaitForCancellationFutureOwned;
|
||||
use tower_http::cors::CorsLayer;
|
||||
use utoipa::OpenApi;
|
||||
use utoipa_swagger_ui::SwaggerUi;
|
||||
|
||||
use crate::http::openapi::ApiDoc;
|
||||
use crate::http::state::AppState;
|
||||
use crate::network::bandwidth_routes;
|
||||
|
||||
/// Wrapper around `axum::Router` which ensures correct [order of layers][order].
|
||||
/// Add new routes as if you were working directly with `axum`.
|
||||
///
|
||||
/// Why? Middleware like logger, CORS, TLS which need to handle request before other
|
||||
/// layers should be added last. Using this builder pattern ensures that.
|
||||
///
|
||||
/// [order]: https://docs.rs/axum/latest/axum/middleware/index.html#ordering
|
||||
pub struct RouterBuilder {
|
||||
unfinished_router: Router<AppState>,
|
||||
}
|
||||
|
||||
impl RouterBuilder {
|
||||
/// All routes should be, if possible, added here. Exceptions are e.g.
|
||||
/// routes which are added conditionally in other places based on some `if`.
|
||||
pub fn with_default_routes() -> Self {
|
||||
let default_routes = Router::new()
|
||||
.merge(SwaggerUi::new("/swagger").url("/api-docs/openapi.json", ApiDoc::openapi()))
|
||||
.route("/", get(|| async { Redirect::to("/swagger") }))
|
||||
.nest("/v1", Router::new().nest("/bandwidth", bandwidth_routes()));
|
||||
Self {
|
||||
unfinished_router: default_routes,
|
||||
}
|
||||
}
|
||||
|
||||
/// Invoke this as late as possible before constructing HTTP server
|
||||
/// (after all routes were added).
|
||||
pub fn with_state(self, state: AppState) -> RouterWithState {
|
||||
RouterWithState {
|
||||
router: self.finalize_routes().with_state(state),
|
||||
}
|
||||
}
|
||||
|
||||
/// Middleware added here intercepts the request before it gets to other routes.
|
||||
fn finalize_routes(self) -> Router<AppState> {
|
||||
self.unfinished_router
|
||||
.layer(setup_cors())
|
||||
.layer(axum::middleware::from_fn(log_request_info))
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_cors() -> CorsLayer {
|
||||
CorsLayer::new()
|
||||
.allow_origin(tower_http::cors::Any)
|
||||
.allow_methods([axum::http::Method::GET, axum::http::Method::POST])
|
||||
.allow_headers(tower_http::cors::Any)
|
||||
.allow_credentials(false)
|
||||
}
|
||||
|
||||
pub struct RouterWithState {
|
||||
router: Router,
|
||||
}
|
||||
|
||||
impl RouterWithState {
|
||||
pub async fn build_server(self, bind_address: &SocketAddr) -> anyhow::Result<ApiHttpServer> {
|
||||
let listener = tokio::net::TcpListener::bind(bind_address)
|
||||
.await
|
||||
.map_err(|err| anyhow!("Couldn't bind to address {} due to {}", bind_address, err))?;
|
||||
|
||||
Ok(ApiHttpServer {
|
||||
router: self.router,
|
||||
listener,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ApiHttpServer {
|
||||
router: Router,
|
||||
listener: TcpListener,
|
||||
}
|
||||
|
||||
impl ApiHttpServer {
|
||||
pub async fn run(self, receiver: WaitForCancellationFutureOwned) -> Result<(), std::io::Error> {
|
||||
// into_make_service_with_connect_info allows us to see client ip address
|
||||
axum::serve(
|
||||
self.listener,
|
||||
self.router
|
||||
.into_make_service_with_connect_info::<SocketAddr>(),
|
||||
)
|
||||
.with_graceful_shutdown(receiver)
|
||||
.await
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::net::IpAddr;
|
||||
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
|
||||
use crate::{
|
||||
error::MetadataError,
|
||||
models::{latest, AvailableBandwidthResponse},
|
||||
transceiver::PeerControllerTransceiver,
|
||||
};
|
||||
|
||||
#[derive(Clone, axum::extract::FromRef)]
|
||||
pub struct AppState {
|
||||
transceiver: PeerControllerTransceiver,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
pub fn new(transceiver: PeerControllerTransceiver) -> Self {
|
||||
Self { transceiver }
|
||||
}
|
||||
|
||||
pub(crate) async fn available_bandwidth(
|
||||
&self,
|
||||
ip: IpAddr,
|
||||
) -> Result<AvailableBandwidthResponse, MetadataError> {
|
||||
let value = self.transceiver.query_bandwidth(ip).await?;
|
||||
let res = latest::InnerAvailableBandwidthResponse::new(value).try_into()?;
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
pub(crate) async fn topup_bandwidth(
|
||||
&self,
|
||||
ip: IpAddr,
|
||||
credential: CredentialSpendingData,
|
||||
) -> Result<(), MetadataError> {
|
||||
self.transceiver
|
||||
.topup_bandwidth(ip, Box::new(credential))
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
mod error;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod http;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod models;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod network;
|
||||
#[cfg(target_os = "linux")]
|
||||
mod transceiver;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use http::{
|
||||
router::{ApiHttpServer, RouterBuilder, RouterWithState},
|
||||
state::AppState,
|
||||
ShutdownHandles,
|
||||
};
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use transceiver::PeerControllerTransceiver;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
fn make_bincode_serializer() -> impl bincode::Options {
|
||||
use bincode::Options;
|
||||
bincode::DefaultOptions::new()
|
||||
.with_big_endian()
|
||||
.with_varint_encoding()
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use crate::models::Version;
|
||||
|
||||
#[derive(Debug, thiserror::Error)]
|
||||
pub enum Error {
|
||||
#[error(transparent)]
|
||||
Bincode(#[from] bincode::Error),
|
||||
|
||||
#[error("trying to deserialize from version {source_version} into {target_version}")]
|
||||
InvalidVersion {
|
||||
source_version: Version,
|
||||
target_version: Version,
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use axum::http::StatusCode;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use utoipa::ToSchema;
|
||||
|
||||
pub(crate) mod error;
|
||||
pub(crate) mod version_1;
|
||||
|
||||
pub(crate) use version_1 as latest;
|
||||
|
||||
pub type Version = usize;
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, ToSchema)]
|
||||
pub struct AvailableBandwidthResponse {
|
||||
pub(crate) version: Version,
|
||||
pub(crate) inner: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, JsonSchema, ToSchema)]
|
||||
pub struct TopUpRequest {
|
||||
pub(crate) version: Version,
|
||||
pub(crate) inner: Vec<u8>,
|
||||
}
|
||||
|
||||
pub(crate) type AxumResult<T> = Result<T, AxumErrorResponse>;
|
||||
|
||||
pub(crate) struct AxumErrorResponse {
|
||||
message: String,
|
||||
status: StatusCode,
|
||||
}
|
||||
|
||||
impl AxumErrorResponse {
|
||||
pub(crate) fn bad_request(msg: impl Display) -> Self {
|
||||
Self {
|
||||
message: msg.to_string(),
|
||||
status: StatusCode::BAD_REQUEST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl axum::response::IntoResponse for AxumErrorResponse {
|
||||
fn into_response(self) -> axum::response::Response {
|
||||
(self.status, self.message).into_response()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use bincode::Options;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::error::Error;
|
||||
use crate::{
|
||||
make_bincode_serializer,
|
||||
models::{AvailableBandwidthResponse, TopUpRequest},
|
||||
};
|
||||
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
|
||||
pub const VERSION: usize = 1;
|
||||
|
||||
#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct InnerAvailableBandwidthResponse {
|
||||
pub(crate) value: i64,
|
||||
}
|
||||
|
||||
impl InnerAvailableBandwidthResponse {
|
||||
pub(crate) fn new(value: i64) -> Self {
|
||||
Self { value }
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<InnerAvailableBandwidthResponse> for AvailableBandwidthResponse {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: InnerAvailableBandwidthResponse) -> Result<Self, Self::Error> {
|
||||
Ok(AvailableBandwidthResponse {
|
||||
version: VERSION,
|
||||
inner: make_bincode_serializer().serialize(&value)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<AvailableBandwidthResponse> for InnerAvailableBandwidthResponse {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: AvailableBandwidthResponse) -> Result<Self, Self::Error> {
|
||||
if value.version != VERSION {
|
||||
return Err(Error::InvalidVersion {
|
||||
source_version: value.version,
|
||||
target_version: VERSION,
|
||||
});
|
||||
}
|
||||
Ok(make_bincode_serializer().deserialize(&value.inner)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||
pub struct InnerTopUpRequest {
|
||||
/// Ecash credential
|
||||
pub credential: CredentialSpendingData,
|
||||
}
|
||||
|
||||
impl TryFrom<InnerTopUpRequest> for TopUpRequest {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: InnerTopUpRequest) -> Result<Self, Self::Error> {
|
||||
Ok(TopUpRequest {
|
||||
version: VERSION,
|
||||
inner: make_bincode_serializer().serialize(&value)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<TopUpRequest> for InnerTopUpRequest {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: TopUpRequest) -> Result<Self, Self::Error> {
|
||||
if value.version != VERSION {
|
||||
return Err(Error::InvalidVersion {
|
||||
source_version: value.version,
|
||||
target_version: VERSION,
|
||||
});
|
||||
}
|
||||
Ok(make_bincode_serializer().deserialize(&value.inner)?)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn serde_available_bandwidth() {
|
||||
let bw = InnerAvailableBandwidthResponse::new(42);
|
||||
let ser = AvailableBandwidthResponse::try_from(bw).unwrap();
|
||||
assert_eq!(VERSION, ser.version);
|
||||
assert_eq!(ser.inner, vec![84]);
|
||||
let de = InnerAvailableBandwidthResponse::try_from(ser).unwrap();
|
||||
assert_eq!(bw, de);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mismatched_version_available_bandwidth() {
|
||||
let version = 4242;
|
||||
let future_bw = AvailableBandwidthResponse {
|
||||
version,
|
||||
inner: vec![],
|
||||
};
|
||||
if let Err(Error::InvalidVersion {
|
||||
source_version,
|
||||
target_version,
|
||||
}) = InnerAvailableBandwidthResponse::try_from(future_bw)
|
||||
{
|
||||
assert_eq!(source_version, version);
|
||||
assert_eq!(target_version, VERSION);
|
||||
} else {
|
||||
panic!("failed");
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_content_available_bandwidth() {
|
||||
let future_bw = AvailableBandwidthResponse {
|
||||
version: VERSION,
|
||||
inner: vec![],
|
||||
};
|
||||
assert!(InnerAvailableBandwidthResponse::try_from(future_bw).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde_topup() {
|
||||
let bw = InnerAvailableBandwidthResponse::new(42);
|
||||
let ser = AvailableBandwidthResponse::try_from(bw).unwrap();
|
||||
assert_eq!(VERSION, ser.version);
|
||||
assert_eq!(ser.inner, vec![84]);
|
||||
let de = InnerAvailableBandwidthResponse::try_from(ser).unwrap();
|
||||
assert_eq!(bw, de);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mismatched_version_topup() {
|
||||
let version = 4242;
|
||||
let future_bw = AvailableBandwidthResponse {
|
||||
version,
|
||||
inner: vec![],
|
||||
};
|
||||
if let Err(Error::InvalidVersion {
|
||||
source_version,
|
||||
target_version,
|
||||
}) = InnerAvailableBandwidthResponse::try_from(future_bw)
|
||||
{
|
||||
assert_eq!(source_version, version);
|
||||
assert_eq!(target_version, VERSION);
|
||||
} else {
|
||||
panic!("failed");
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_content_topup() {
|
||||
let future_bw = AvailableBandwidthResponse {
|
||||
version: VERSION,
|
||||
inner: vec![],
|
||||
};
|
||||
assert!(InnerAvailableBandwidthResponse::try_from(future_bw).is_err());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use axum::{
|
||||
extract::{ConnectInfo, Query, State},
|
||||
Json, Router,
|
||||
};
|
||||
use nym_http_api_common::{FormattedResponse, OutputParams};
|
||||
use tower_http::compression::CompressionLayer;
|
||||
|
||||
use crate::{
|
||||
http::state::AppState,
|
||||
models::{
|
||||
latest::InnerTopUpRequest, AvailableBandwidthResponse, AxumErrorResponse, AxumResult,
|
||||
TopUpRequest,
|
||||
},
|
||||
};
|
||||
|
||||
pub(crate) fn bandwidth_routes() -> Router<AppState> {
|
||||
Router::new()
|
||||
.route("/available", axum::routing::get(available_bandwidth))
|
||||
.route("/topup", axum::routing::post(topup_bandwidth))
|
||||
.layer(CompressionLayer::new())
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
tag = "bandwidth",
|
||||
get,
|
||||
path = "/v1/bandwidth/available",
|
||||
responses(
|
||||
(status = 200, content(
|
||||
(AvailableBandwidthResponse = "application/bincode")
|
||||
))
|
||||
|
||||
),
|
||||
)]
|
||||
async fn available_bandwidth(
|
||||
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||
Query(output): Query<OutputParams>,
|
||||
State(state): State<AppState>,
|
||||
) -> AxumResult<FormattedResponse<AvailableBandwidthResponse>> {
|
||||
let output = output.output.unwrap_or_default();
|
||||
Ok(output.to_response(
|
||||
state
|
||||
.available_bandwidth(addr.ip())
|
||||
.await
|
||||
.map_err(AxumErrorResponse::bad_request)?,
|
||||
))
|
||||
}
|
||||
|
||||
#[utoipa::path(
|
||||
tag = "bandwidth",
|
||||
post,
|
||||
request_body = TopUpRequest,
|
||||
path = "/v1/bandwidth/topup",
|
||||
responses(
|
||||
(status = 200),
|
||||
),
|
||||
)]
|
||||
async fn topup_bandwidth(
|
||||
ConnectInfo(addr): ConnectInfo<SocketAddr>,
|
||||
Query(output): Query<OutputParams>,
|
||||
State(state): State<AppState>,
|
||||
Json(request): Json<TopUpRequest>,
|
||||
) -> AxumResult<FormattedResponse<()>> {
|
||||
let output = output.output.unwrap_or_default();
|
||||
let credential = InnerTopUpRequest::try_from(request)
|
||||
.map_err(AxumErrorResponse::bad_request)?
|
||||
.credential;
|
||||
state
|
||||
.topup_bandwidth(addr.ip(), credential)
|
||||
.await
|
||||
.map_err(AxumErrorResponse::bad_request)?;
|
||||
Ok(output.to_response(()))
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
use futures::channel::oneshot;
|
||||
use nym_credential_verification::ClientBandwidth;
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
use std::net::IpAddr;
|
||||
|
||||
use nym_wireguard::peer_controller::PeerControlRequest;
|
||||
|
||||
use crate::error::MetadataError;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct PeerControllerTransceiver {
|
||||
request_tx: mpsc::Sender<PeerControlRequest>,
|
||||
}
|
||||
|
||||
impl PeerControllerTransceiver {
|
||||
pub fn new(request_tx: mpsc::Sender<PeerControlRequest>) -> Self {
|
||||
Self { request_tx }
|
||||
}
|
||||
|
||||
async fn get_client_bandwidth(&self, ip: IpAddr) -> Result<ClientBandwidth, MetadataError> {
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
let msg = PeerControlRequest::GetClientBandwidthByIp { ip, response_tx };
|
||||
self.request_tx
|
||||
.send(msg)
|
||||
.await
|
||||
.map_err(|_| MetadataError::PeerInteractionStopped)?;
|
||||
|
||||
response_rx
|
||||
.await
|
||||
.map_err(|_| MetadataError::NoResponse)?
|
||||
.map_err(|err| MetadataError::Unsuccessful {
|
||||
reason: err.to_string(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) async fn query_bandwidth(&self, ip: IpAddr) -> Result<i64, MetadataError> {
|
||||
Ok(self.get_client_bandwidth(ip).await?.available().await)
|
||||
}
|
||||
|
||||
pub(crate) async fn topup_bandwidth(
|
||||
&self,
|
||||
ip: IpAddr,
|
||||
credential: Box<CredentialSpendingData>,
|
||||
) -> Result<i64, MetadataError> {
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
let msg = PeerControlRequest::GetVerifierByIp {
|
||||
ip,
|
||||
credential,
|
||||
response_tx,
|
||||
};
|
||||
self.request_tx
|
||||
.send(msg)
|
||||
.await
|
||||
.map_err(|_| MetadataError::PeerInteractionStopped)?;
|
||||
|
||||
let mut verifier = response_rx
|
||||
.await
|
||||
.map_err(|_| MetadataError::NoResponse)?
|
||||
.map_err(|err| MetadataError::Unsuccessful {
|
||||
reason: err.to_string(),
|
||||
})?;
|
||||
let available_bandwidth = verifier.verify().await?;
|
||||
|
||||
Ok(available_bandwidth)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use nym_credential_verification::TicketVerifier;
|
||||
use nym_wireguard::CONTROL_CHANNEL_SIZE;
|
||||
|
||||
use super::*;
|
||||
|
||||
const CREDENTIAL_BYTES: [u8; 1245] = [
|
||||
0, 0, 4, 133, 96, 179, 223, 185, 136, 23, 213, 166, 59, 203, 66, 69, 209, 181, 227, 254,
|
||||
16, 102, 98, 237, 59, 119, 170, 111, 31, 194, 51, 59, 120, 17, 115, 229, 79, 91, 11, 139,
|
||||
154, 2, 212, 23, 68, 70, 167, 3, 240, 54, 224, 171, 221, 1, 69, 48, 60, 118, 119, 249, 123,
|
||||
35, 172, 227, 131, 96, 232, 209, 187, 123, 4, 197, 102, 90, 96, 45, 125, 135, 140, 99, 1,
|
||||
151, 17, 131, 143, 157, 97, 107, 139, 232, 212, 87, 14, 115, 253, 255, 166, 167, 186, 43,
|
||||
90, 96, 173, 105, 120, 40, 10, 163, 250, 224, 214, 200, 178, 4, 160, 16, 130, 59, 76, 193,
|
||||
39, 240, 3, 101, 141, 209, 183, 226, 186, 207, 56, 210, 187, 7, 164, 240, 164, 205, 37, 81,
|
||||
184, 214, 193, 195, 90, 205, 238, 225, 195, 104, 12, 123, 203, 57, 233, 243, 215, 145, 195,
|
||||
196, 57, 38, 125, 172, 18, 47, 63, 165, 110, 219, 180, 40, 58, 116, 92, 254, 160, 98, 48,
|
||||
92, 254, 232, 107, 184, 80, 234, 60, 160, 235, 249, 76, 41, 38, 165, 28, 40, 136, 74, 48,
|
||||
166, 50, 245, 23, 201, 140, 101, 79, 93, 235, 128, 186, 146, 126, 180, 134, 43, 13, 186,
|
||||
19, 195, 48, 168, 201, 29, 216, 95, 176, 198, 132, 188, 64, 39, 212, 150, 32, 52, 53, 38,
|
||||
228, 199, 122, 226, 217, 75, 40, 191, 151, 48, 164, 242, 177, 79, 14, 122, 105, 151, 85,
|
||||
88, 199, 162, 17, 96, 103, 83, 178, 128, 9, 24, 30, 74, 108, 241, 85, 240, 166, 97, 241,
|
||||
85, 199, 11, 198, 226, 234, 70, 107, 145, 28, 208, 114, 51, 12, 234, 108, 101, 202, 112,
|
||||
48, 185, 22, 159, 67, 109, 49, 27, 149, 90, 109, 32, 226, 112, 7, 201, 208, 209, 104, 31,
|
||||
97, 134, 204, 145, 27, 181, 206, 181, 106, 32, 110, 136, 115, 249, 201, 111, 5, 245, 203,
|
||||
71, 121, 169, 126, 151, 178, 236, 59, 221, 195, 48, 135, 115, 6, 50, 227, 74, 97, 107, 107,
|
||||
213, 90, 2, 203, 154, 138, 47, 128, 52, 134, 128, 224, 51, 65, 240, 90, 8, 55, 175, 180,
|
||||
178, 204, 206, 168, 110, 51, 57, 189, 169, 48, 169, 136, 121, 99, 51, 170, 178, 214, 74, 1,
|
||||
96, 151, 167, 25, 173, 180, 171, 155, 10, 55, 142, 234, 190, 113, 90, 79, 80, 244, 71, 166,
|
||||
30, 235, 113, 150, 133, 1, 218, 17, 109, 111, 223, 24, 216, 177, 41, 2, 204, 65, 221, 212,
|
||||
207, 236, 144, 6, 65, 224, 55, 42, 1, 1, 161, 134, 118, 127, 111, 220, 110, 127, 240, 71,
|
||||
223, 129, 12, 93, 20, 220, 60, 56, 71, 146, 184, 95, 132, 69, 28, 56, 53, 192, 213, 22,
|
||||
119, 230, 152, 225, 182, 188, 163, 219, 37, 175, 247, 73, 14, 247, 38, 72, 243, 1, 48, 131,
|
||||
59, 8, 13, 96, 143, 185, 127, 241, 161, 217, 24, 149, 193, 40, 16, 30, 202, 151, 28, 119,
|
||||
240, 153, 101, 156, 61, 193, 72, 245, 199, 181, 12, 231, 65, 166, 67, 142, 121, 207, 202,
|
||||
58, 197, 113, 188, 248, 42, 124, 105, 48, 161, 241, 55, 209, 36, 194, 27, 63, 233, 144,
|
||||
189, 85, 117, 234, 9, 139, 46, 31, 206, 114, 95, 131, 29, 240, 13, 81, 142, 140, 133, 33,
|
||||
30, 41, 141, 37, 80, 217, 95, 221, 76, 115, 86, 201, 165, 51, 252, 9, 28, 209, 1, 48, 150,
|
||||
74, 248, 212, 187, 222, 66, 210, 3, 200, 19, 217, 171, 184, 42, 148, 53, 150, 57, 50, 6,
|
||||
227, 227, 62, 49, 42, 148, 148, 157, 82, 191, 58, 24, 34, 56, 98, 120, 89, 105, 176, 85,
|
||||
15, 253, 241, 41, 153, 195, 136, 1, 48, 142, 126, 213, 101, 223, 79, 133, 230, 105, 38,
|
||||
161, 149, 2, 21, 136, 150, 42, 72, 218, 85, 146, 63, 223, 58, 108, 186, 183, 248, 62, 20,
|
||||
47, 34, 113, 160, 177, 204, 181, 16, 24, 212, 224, 35, 84, 51, 168, 56, 136, 11, 1, 48,
|
||||
135, 242, 62, 149, 230, 178, 32, 224, 119, 26, 234, 163, 237, 224, 114, 95, 112, 140, 170,
|
||||
150, 96, 125, 136, 221, 180, 78, 18, 11, 12, 184, 2, 198, 217, 119, 43, 69, 4, 172, 109,
|
||||
55, 183, 40, 131, 172, 161, 88, 183, 101, 1, 48, 173, 216, 22, 73, 42, 255, 211, 93, 249,
|
||||
87, 159, 115, 61, 91, 55, 130, 17, 216, 60, 34, 122, 55, 8, 244, 244, 153, 151, 57, 5, 144,
|
||||
178, 55, 249, 64, 211, 168, 34, 148, 56, 89, 92, 203, 70, 124, 219, 152, 253, 165, 0, 32,
|
||||
203, 116, 63, 7, 240, 222, 82, 86, 11, 149, 167, 72, 224, 55, 190, 66, 201, 65, 168, 184,
|
||||
96, 47, 194, 241, 168, 124, 7, 74, 214, 250, 37, 76, 32, 218, 69, 122, 103, 215, 145, 169,
|
||||
24, 212, 229, 168, 106, 10, 144, 31, 13, 25, 178, 242, 250, 106, 159, 40, 48, 163, 165, 61,
|
||||
130, 57, 146, 4, 73, 32, 254, 233, 125, 135, 212, 29, 111, 4, 177, 114, 15, 210, 170, 82,
|
||||
108, 110, 62, 166, 81, 209, 106, 176, 156, 14, 133, 242, 60, 127, 120, 242, 28, 97, 0, 1,
|
||||
32, 103, 93, 109, 89, 240, 91, 1, 84, 150, 50, 206, 157, 203, 49, 220, 120, 234, 175, 234,
|
||||
150, 126, 225, 94, 163, 164, 199, 138, 114, 62, 99, 106, 112, 1, 32, 171, 40, 220, 82, 241,
|
||||
203, 76, 146, 111, 139, 182, 179, 237, 182, 115, 75, 128, 201, 107, 43, 214, 0, 135, 217,
|
||||
160, 68, 150, 232, 144, 114, 237, 98, 32, 30, 134, 232, 59, 93, 163, 253, 244, 13, 202, 52,
|
||||
147, 168, 83, 121, 123, 95, 21, 210, 209, 225, 223, 143, 49, 10, 205, 238, 1, 22, 83, 81,
|
||||
70, 1, 32, 26, 76, 6, 234, 160, 50, 139, 102, 161, 232, 155, 106, 130, 171, 226, 210, 233,
|
||||
178, 85, 247, 71, 123, 55, 53, 46, 67, 148, 137, 156, 207, 208, 107, 1, 32, 102, 31, 4, 98,
|
||||
110, 156, 144, 61, 229, 140, 198, 84, 196, 238, 128, 35, 131, 182, 137, 125, 241, 95, 69,
|
||||
131, 170, 27, 2, 144, 75, 72, 242, 102, 3, 32, 121, 80, 45, 173, 56, 65, 218, 27, 40, 251,
|
||||
197, 32, 169, 104, 123, 110, 90, 78, 153, 166, 38, 9, 129, 228, 99, 8, 1, 116, 142, 233,
|
||||
162, 69, 32, 216, 169, 159, 116, 95, 12, 63, 176, 195, 6, 183, 123, 135, 75, 61, 112, 106,
|
||||
83, 235, 176, 41, 27, 248, 48, 71, 165, 170, 12, 92, 103, 103, 81, 32, 58, 74, 75, 145,
|
||||
192, 94, 153, 69, 80, 128, 241, 3, 16, 117, 192, 86, 161, 103, 44, 174, 211, 196, 182, 124,
|
||||
55, 11, 107, 142, 49, 88, 6, 41, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
|
||||
6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 0, 37, 139, 240, 0, 0,
|
||||
0, 0, 0, 0, 0, 1,
|
||||
];
|
||||
|
||||
struct MockVerifier {
|
||||
ret: i64,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl TicketVerifier for MockVerifier {
|
||||
async fn verify(&mut self) -> nym_credential_verification::Result<i64> {
|
||||
Ok(self.ret)
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn get_bandwidth() {
|
||||
let (request_tx, mut request_rx) = mpsc::channel(CONTROL_CHANNEL_SIZE);
|
||||
let transceiver = PeerControllerTransceiver::new(request_tx);
|
||||
|
||||
tokio::spawn(async move {
|
||||
match request_rx.recv().await.unwrap() {
|
||||
PeerControlRequest::GetClientBandwidthByIp { ip: _, response_tx } => {
|
||||
response_tx
|
||||
.send(Ok(ClientBandwidth::new(Default::default())))
|
||||
.ok();
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
});
|
||||
|
||||
let bw = transceiver
|
||||
.query_bandwidth("10.0.0.42".parse().unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(bw, 0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn stop_peer() {
|
||||
let (request_tx, request_rx) = mpsc::channel(CONTROL_CHANNEL_SIZE);
|
||||
let transceiver = PeerControllerTransceiver::new(request_tx);
|
||||
|
||||
drop(request_rx);
|
||||
let err = transceiver
|
||||
.query_bandwidth("10.0.0.42".parse().unwrap())
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert_eq!(err, MetadataError::PeerInteractionStopped);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn unresponsive_peer() {
|
||||
let (request_tx, mut request_rx) = mpsc::channel(CONTROL_CHANNEL_SIZE);
|
||||
let transceiver = PeerControllerTransceiver::new(request_tx);
|
||||
|
||||
tokio::spawn(async move {
|
||||
match request_rx.recv().await.unwrap() {
|
||||
PeerControlRequest::GetClientBandwidthByIp {
|
||||
ip: _,
|
||||
response_tx: _,
|
||||
} => {}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
});
|
||||
|
||||
let err = transceiver
|
||||
.query_bandwidth("10.0.0.42".parse().unwrap())
|
||||
.await
|
||||
.unwrap_err();
|
||||
assert_eq!(err, MetadataError::NoResponse);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn unsuccessful_query_bandwidth() {
|
||||
let (request_tx, mut request_rx) = mpsc::channel(CONTROL_CHANNEL_SIZE);
|
||||
let transceiver = PeerControllerTransceiver::new(request_tx);
|
||||
|
||||
tokio::spawn(async move {
|
||||
match request_rx.recv().await.unwrap() {
|
||||
PeerControlRequest::GetClientBandwidthByIp { ip: _, response_tx } => {
|
||||
response_tx
|
||||
.send(Err(nym_wireguard::error::Error::Internal(
|
||||
"testing".to_owned(),
|
||||
)))
|
||||
.ok();
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
});
|
||||
|
||||
let ret = transceiver
|
||||
.query_bandwidth("10.0.0.42".parse().unwrap())
|
||||
.await;
|
||||
assert!(ret.is_err());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn topup() {
|
||||
let (request_tx, mut request_rx) = mpsc::channel(CONTROL_CHANNEL_SIZE);
|
||||
let transceiver = PeerControllerTransceiver::new(request_tx);
|
||||
let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap();
|
||||
let verifier_bw = 42;
|
||||
|
||||
tokio::spawn(async move {
|
||||
match request_rx.recv().await.unwrap() {
|
||||
PeerControlRequest::GetVerifierByIp {
|
||||
ip: _,
|
||||
credential: _,
|
||||
response_tx,
|
||||
} => {
|
||||
response_tx
|
||||
.send(Ok(Box::new(MockVerifier { ret: verifier_bw })))
|
||||
.ok();
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
});
|
||||
|
||||
let bw = transceiver
|
||||
.topup_bandwidth("10.0.0.42".parse().unwrap(), Box::new(credential))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(bw, verifier_bw);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn unsuccessful_topup() {
|
||||
let (request_tx, mut request_rx) = mpsc::channel(CONTROL_CHANNEL_SIZE);
|
||||
let transceiver = PeerControllerTransceiver::new(request_tx);
|
||||
let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap();
|
||||
|
||||
tokio::spawn(async move {
|
||||
match request_rx.recv().await.unwrap() {
|
||||
PeerControlRequest::GetVerifierByIp {
|
||||
ip: _,
|
||||
credential: _,
|
||||
response_tx,
|
||||
} => {
|
||||
response_tx
|
||||
.send(Err(nym_wireguard::error::Error::Internal(
|
||||
"testing".to_owned(),
|
||||
)))
|
||||
.ok();
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
});
|
||||
|
||||
let ret = transceiver
|
||||
.topup_bandwidth("10.0.0.42".parse().unwrap(), Box::new(credential))
|
||||
.await;
|
||||
assert!(ret.is_err());
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,13 @@ pub struct Config {
|
||||
/// default: `fc01::1`
|
||||
pub private_ipv6: Ipv6Addr,
|
||||
|
||||
/// Port announced to external clients wishing to connect to the wireguard interface.
|
||||
/// Tunnel port announced to external clients wishing to connect to the wireguard interface.
|
||||
/// Useful in the instances where the node is behind a proxy.
|
||||
pub announced_port: u16,
|
||||
pub announced_tunnel_port: u16,
|
||||
|
||||
/// Metadata port announced to external clients wishing to connect to the endpoint.
|
||||
/// Useful in the instances where the node is behind a proxy.
|
||||
pub announced_metadata_port: u16,
|
||||
|
||||
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv4.
|
||||
/// The maximum value for IPv4 is 32
|
||||
|
||||
@@ -18,11 +18,13 @@ use tokio::sync::mpsc::{self, Receiver, Sender};
|
||||
#[cfg(target_os = "linux")]
|
||||
use nym_network_defaults::constants::WG_TUN_BASE_NAME;
|
||||
|
||||
pub(crate) mod error;
|
||||
pub mod error;
|
||||
pub mod peer_controller;
|
||||
pub mod peer_handle;
|
||||
pub mod peer_storage_manager;
|
||||
|
||||
pub const CONTROL_CHANNEL_SIZE: usize = 256;
|
||||
|
||||
pub struct WgApiWrapper {
|
||||
inner: WGApi,
|
||||
}
|
||||
@@ -126,7 +128,7 @@ pub struct WireguardGatewayData {
|
||||
|
||||
impl WireguardGatewayData {
|
||||
pub fn new(config: Config, keypair: Arc<KeyPair>) -> (Self, Receiver<PeerControlRequest>) {
|
||||
let (peer_tx, peer_rx) = mpsc::channel(1);
|
||||
let (peer_tx, peer_rx) = mpsc::channel(CONTROL_CHANNEL_SIZE);
|
||||
(
|
||||
WireguardGatewayData {
|
||||
config,
|
||||
@@ -178,10 +180,16 @@ pub async fn start_wireguard(
|
||||
let mut peer_bandwidth_managers = HashMap::with_capacity(peers.len());
|
||||
|
||||
for peer in peers.iter() {
|
||||
let bandwidth_manager = Arc::new(RwLock::new(
|
||||
PeerController::generate_bandwidth_manager(ecash_manager.storage(), &peer.public_key)
|
||||
let bandwidth_manager = peer_handle::SharedBandwidthStorageManager::new(
|
||||
Arc::new(RwLock::new(
|
||||
PeerController::generate_bandwidth_manager(
|
||||
ecash_manager.storage(),
|
||||
&peer.public_key,
|
||||
)
|
||||
.await?,
|
||||
));
|
||||
)),
|
||||
peer.allowed_ips.clone(),
|
||||
);
|
||||
peer_bandwidth_managers.insert(peer.public_key.clone(), (bandwidth_manager, peer.clone()));
|
||||
}
|
||||
|
||||
@@ -190,7 +198,7 @@ pub async fn start_wireguard(
|
||||
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_port as u32,
|
||||
port: wireguard_data.inner.config().announced_tunnel_port as u32,
|
||||
peers,
|
||||
mtu: None,
|
||||
};
|
||||
@@ -233,6 +241,7 @@ pub async fn start_wireguard(
|
||||
|
||||
let host = wg_api.read_interface_data()?;
|
||||
let wg_api = std::sync::Arc::new(WgApiWrapper::new(wg_api));
|
||||
|
||||
let mut controller = PeerController::new(
|
||||
ecash_manager,
|
||||
metrics,
|
||||
|
||||
@@ -10,15 +10,18 @@ use futures::channel::oneshot;
|
||||
use log::info;
|
||||
use nym_credential_verification::{
|
||||
bandwidth_storage_manager::BandwidthStorageManager, ecash::traits::EcashManager,
|
||||
BandwidthFlushingBehaviourConfig, ClientBandwidth, CredentialVerifier,
|
||||
BandwidthFlushingBehaviourConfig, ClientBandwidth, CredentialVerifier, TicketVerifier,
|
||||
};
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_gateway_requests::models::CredentialSpendingRequest;
|
||||
use nym_gateway_storage::traits::BandwidthGatewayStorage;
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
use nym_wireguard_types::DEFAULT_PEER_TIMEOUT_CHECK;
|
||||
use std::time::{Duration, SystemTime};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use std::{
|
||||
net::IpAddr,
|
||||
time::{Duration, SystemTime},
|
||||
};
|
||||
use tokio::sync::{mpsc, RwLock};
|
||||
use tokio_stream::{wrappers::IntervalStream, StreamExt};
|
||||
|
||||
@@ -41,22 +44,31 @@ pub enum PeerControlRequest {
|
||||
key: Key,
|
||||
response_tx: oneshot::Sender<QueryPeerControlResponse>,
|
||||
},
|
||||
GetClientBandwidth {
|
||||
GetClientBandwidthByKey {
|
||||
key: Key,
|
||||
response_tx: oneshot::Sender<GetClientBandwidthControlResponse>,
|
||||
},
|
||||
GetVerifier {
|
||||
GetClientBandwidthByIp {
|
||||
ip: IpAddr,
|
||||
response_tx: oneshot::Sender<GetClientBandwidthControlResponse>,
|
||||
},
|
||||
GetVerifierByKey {
|
||||
key: Key,
|
||||
credential: Box<CredentialSpendingData>,
|
||||
response_tx: oneshot::Sender<QueryVerifierControlResponse>,
|
||||
},
|
||||
GetVerifierByIp {
|
||||
ip: IpAddr,
|
||||
credential: Box<CredentialSpendingData>,
|
||||
response_tx: oneshot::Sender<QueryVerifierControlResponse>,
|
||||
},
|
||||
}
|
||||
|
||||
pub type AddPeerControlResponse = Result<()>;
|
||||
pub type RemovePeerControlResponse = Result<()>;
|
||||
pub type QueryPeerControlResponse = Result<Option<Peer>>;
|
||||
pub type GetClientBandwidthControlResponse = Result<ClientBandwidth>;
|
||||
pub type QueryVerifierControlResponse = Result<CredentialVerifier>;
|
||||
pub type QueryVerifierControlResponse = Result<Box<dyn TicketVerifier + Send + Sync>>;
|
||||
|
||||
pub struct PeerController {
|
||||
ecash_verifier: Arc<dyn EcashManager + Send + Sync>,
|
||||
@@ -77,7 +89,7 @@ pub struct PeerController {
|
||||
|
||||
impl PeerController {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
pub(crate) fn new(
|
||||
ecash_verifier: Arc<dyn EcashManager + Send + Sync>,
|
||||
metrics: NymNodeMetrics,
|
||||
wg_api: Arc<dyn WireguardInterfaceApi + Send + Sync>,
|
||||
@@ -165,10 +177,13 @@ impl PeerController {
|
||||
|
||||
async fn handle_add_request(&mut self, peer: &Peer) -> Result<()> {
|
||||
self.wg_api.configure_peer(peer)?;
|
||||
let bandwidth_storage_manager = Arc::new(RwLock::new(
|
||||
Self::generate_bandwidth_manager(self.ecash_verifier.storage(), &peer.public_key)
|
||||
.await?,
|
||||
));
|
||||
let bandwidth_storage_manager = SharedBandwidthStorageManager::new(
|
||||
Arc::new(RwLock::new(
|
||||
Self::generate_bandwidth_manager(self.ecash_verifier.storage(), &peer.public_key)
|
||||
.await?,
|
||||
)),
|
||||
peer.allowed_ips.clone(),
|
||||
);
|
||||
let cached_peer_manager = CachedPeerManager::new(peer);
|
||||
let mut handle = PeerHandle::new(
|
||||
peer.public_key.clone(),
|
||||
@@ -192,7 +207,20 @@ impl PeerController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_query_peer(&self, key: &Key) -> Result<Option<Peer>> {
|
||||
async fn ip_to_key(&self, ip: IpAddr) -> Result<Option<Key>> {
|
||||
Ok(self
|
||||
.bw_storage_managers
|
||||
.iter()
|
||||
.find_map(|(key, bw_manager)| {
|
||||
bw_manager
|
||||
.allowed_ips()
|
||||
.iter()
|
||||
.find(|ip_mask| ip_mask.ip == ip)
|
||||
.and(Some(key.clone()))
|
||||
}))
|
||||
}
|
||||
|
||||
async fn handle_query_peer_by_key(&self, key: &Key) -> Result<Option<Peer>> {
|
||||
Ok(self
|
||||
.ecash_verifier
|
||||
.storage()
|
||||
@@ -202,20 +230,32 @@ impl PeerController {
|
||||
.transpose()?)
|
||||
}
|
||||
|
||||
async fn handle_get_client_bandwidth(&self, key: &Key) -> Result<ClientBandwidth> {
|
||||
async fn handle_get_client_bandwidth_by_key(&self, key: &Key) -> Result<ClientBandwidth> {
|
||||
let bandwidth_storage_manager = self
|
||||
.bw_storage_managers
|
||||
.get(key)
|
||||
.ok_or(Error::MissingClientBandwidthEntry)?;
|
||||
|
||||
Ok(bandwidth_storage_manager.read().await.client_bandwidth())
|
||||
Ok(bandwidth_storage_manager
|
||||
.inner()
|
||||
.read()
|
||||
.await
|
||||
.client_bandwidth())
|
||||
}
|
||||
|
||||
async fn handle_query_verifier(
|
||||
async fn handle_get_client_bandwidth_by_ip(&self, ip: IpAddr) -> Result<ClientBandwidth> {
|
||||
let Some(key) = self.ip_to_key(ip).await? else {
|
||||
return Err(Error::MissingClientKernelEntry(ip.to_string()));
|
||||
};
|
||||
|
||||
self.handle_get_client_bandwidth_by_key(&key).await
|
||||
}
|
||||
|
||||
async fn handle_query_verifier_by_key(
|
||||
&self,
|
||||
key: &Key,
|
||||
credential: CredentialSpendingData,
|
||||
) -> Result<CredentialVerifier> {
|
||||
) -> Result<Box<dyn TicketVerifier + Send + Sync>> {
|
||||
let storage = self.ecash_verifier.storage();
|
||||
let client_id = storage
|
||||
.get_wireguard_peer(&key.to_string())
|
||||
@@ -225,7 +265,11 @@ impl PeerController {
|
||||
let Some(bandwidth_storage_manager) = self.bw_storage_managers.get(key) else {
|
||||
return Err(Error::MissingClientBandwidthEntry);
|
||||
};
|
||||
let client_bandwidth = bandwidth_storage_manager.read().await.client_bandwidth();
|
||||
let client_bandwidth = bandwidth_storage_manager
|
||||
.inner()
|
||||
.read()
|
||||
.await
|
||||
.client_bandwidth();
|
||||
let verifier = CredentialVerifier::new(
|
||||
CredentialSpendingRequest::new(credential),
|
||||
self.ecash_verifier.clone(),
|
||||
@@ -237,7 +281,19 @@ impl PeerController {
|
||||
true,
|
||||
),
|
||||
);
|
||||
Ok(verifier)
|
||||
Ok(Box::new(verifier))
|
||||
}
|
||||
|
||||
async fn handle_query_verifier_by_ip(
|
||||
&self,
|
||||
ip: IpAddr,
|
||||
credential: CredentialSpendingData,
|
||||
) -> Result<Box<dyn TicketVerifier + Send + Sync>> {
|
||||
let Some(key) = self.ip_to_key(ip).await? else {
|
||||
return Err(Error::MissingClientKernelEntry(ip.to_string()));
|
||||
};
|
||||
|
||||
self.handle_query_verifier_by_key(&key, credential).await
|
||||
}
|
||||
|
||||
async fn update_metrics(&self, new_host: &Host) {
|
||||
@@ -340,18 +396,23 @@ impl PeerController {
|
||||
response_tx.send(self.remove_peer(&key).await).ok();
|
||||
}
|
||||
Some(PeerControlRequest::QueryPeer { key, response_tx }) => {
|
||||
response_tx.send(self.handle_query_peer(&key).await).ok();
|
||||
response_tx.send(self.handle_query_peer_by_key(&key).await).ok();
|
||||
}
|
||||
Some(PeerControlRequest::GetClientBandwidth { key, response_tx }) => {
|
||||
response_tx.send(self.handle_get_client_bandwidth(&key).await).ok();
|
||||
Some(PeerControlRequest::GetClientBandwidthByKey { key, response_tx }) => {
|
||||
response_tx.send(self.handle_get_client_bandwidth_by_key(&key).await).ok();
|
||||
}
|
||||
Some(PeerControlRequest::GetVerifier { key, credential, response_tx }) => {
|
||||
response_tx.send(self.handle_query_verifier(&key, *credential).await).ok();
|
||||
Some(PeerControlRequest::GetClientBandwidthByIp { ip, response_tx }) => {
|
||||
response_tx.send(self.handle_get_client_bandwidth_by_ip(ip).await).ok();
|
||||
}
|
||||
Some(PeerControlRequest::GetVerifierByKey { key, credential, response_tx }) => {
|
||||
response_tx.send(self.handle_query_verifier_by_key(&key, *credential).await).ok();
|
||||
}
|
||||
Some(PeerControlRequest::GetVerifierByIp { ip, credential, response_tx }) => {
|
||||
response_tx.send(self.handle_query_verifier_by_ip(ip, *credential).await).ok();
|
||||
}
|
||||
None => {
|
||||
log::trace!("PeerController [main loop]: stopping since channel closed");
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use crate::error::Error;
|
||||
use crate::peer_controller::PeerControlRequest;
|
||||
use crate::peer_storage_manager::{CachedPeerManager, PeerInformation};
|
||||
use defguard_wireguard_rs::{host::Host, key::Key};
|
||||
use defguard_wireguard_rs::{host::Host, key::Key, net::IpAddrMask};
|
||||
use futures::channel::oneshot;
|
||||
use nym_credential_verification::bandwidth_storage_manager::BandwidthStorageManager;
|
||||
use nym_task::TaskClient;
|
||||
@@ -13,7 +13,28 @@ use std::sync::Arc;
|
||||
use tokio::sync::{mpsc, RwLock};
|
||||
use tokio_stream::{wrappers::IntervalStream, StreamExt};
|
||||
|
||||
pub(crate) type SharedBandwidthStorageManager = Arc<RwLock<BandwidthStorageManager>>;
|
||||
#[derive(Clone)]
|
||||
pub(crate) struct SharedBandwidthStorageManager {
|
||||
inner: Arc<RwLock<BandwidthStorageManager>>,
|
||||
allowed_ips: Vec<IpAddrMask>,
|
||||
}
|
||||
|
||||
impl SharedBandwidthStorageManager {
|
||||
pub(crate) fn new(
|
||||
inner: Arc<RwLock<BandwidthStorageManager>>,
|
||||
allowed_ips: Vec<IpAddrMask>,
|
||||
) -> Self {
|
||||
Self { inner, allowed_ips }
|
||||
}
|
||||
|
||||
pub(crate) fn inner(&self) -> &RwLock<BandwidthStorageManager> {
|
||||
&self.inner
|
||||
}
|
||||
|
||||
pub(crate) fn allowed_ips(&self) -> &[IpAddrMask] {
|
||||
&self.allowed_ips
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PeerHandle {
|
||||
public_key: Key,
|
||||
@@ -26,7 +47,7 @@ pub struct PeerHandle {
|
||||
}
|
||||
|
||||
impl PeerHandle {
|
||||
pub fn new(
|
||||
pub(crate) fn new(
|
||||
public_key: Key,
|
||||
host_information: Arc<RwLock<Host>>,
|
||||
cached_peer: CachedPeerManager,
|
||||
@@ -120,6 +141,7 @@ impl PeerHandle {
|
||||
if spent_bandwidth > 0
|
||||
&& self
|
||||
.bandwidth_storage_manager
|
||||
.inner()
|
||||
.write()
|
||||
.await
|
||||
.try_use_bandwidth(spent_bandwidth)
|
||||
@@ -182,7 +204,7 @@ impl PeerHandle {
|
||||
|
||||
_ = self.task_client.recv() => {
|
||||
log::trace!("PeerHandle: Received shutdown");
|
||||
if let Err(e) = self.bandwidth_storage_manager.write().await.sync_storage_bandwidth().await {
|
||||
if let Err(e) = self.bandwidth_storage_manager.inner().write().await.sync_storage_bandwidth().await {
|
||||
log::error!("Storage sync failed - {e}, unaccounted bandwidth might have been consumed");
|
||||
}
|
||||
|
||||
|
||||
@@ -58,8 +58,8 @@ Options:
|
||||
Specifies whether the wireguard service is enabled on this node [env: NYMNODE_WG_ENABLED=] [possible values: true, false]
|
||||
--wireguard-bind-address <WIREGUARD_BIND_ADDRESS>
|
||||
Socket address this node will use for binding its wireguard interface. default: `[::]:51822` [env: NYMNODE_WG_BIND_ADDRESS=]
|
||||
--wireguard-announced-port <WIREGUARD_ANNOUNCED_PORT>
|
||||
Port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
|
||||
--wireguard-tunnel-announced-port <WIREGUARD_TUNNEL_ANNOUNCED_PORT>
|
||||
Tunnel port announced to external clients wishing to connect to the wireguard interface. Useful in the instances where the node is behind a proxy [env: NYMNODE_WG_ANNOUNCED_PORT=]
|
||||
--wireguard-private-network-prefix <WIREGUARD_PRIVATE_NETWORK_PREFIX>
|
||||
The prefix denoting the maximum number of the clients that can be connected via Wireguard. The maximum value for IPv4 is 32 and for IPv6 is 128 [env: NYMNODE_WG_PRIVATE_NETWORK_PREFIX=]
|
||||
--verloc-bind-address <VERLOC_BIND_ADDRESS>
|
||||
|
||||
@@ -72,6 +72,7 @@ nym-ip-packet-router = { path = "../service-providers/ip-packet-router" }
|
||||
nym-node-metrics = { path = "../nym-node/nym-node-metrics" }
|
||||
|
||||
nym-wireguard = { path = "../common/wireguard" }
|
||||
nym-wireguard-private-metadata = { path = "../common/wireguard-private-metadata" }
|
||||
nym-wireguard-types = { path = "../common/wireguard-types", default-features = false }
|
||||
|
||||
nym-authenticator-requests = { path = "../common/authenticator-requests" }
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_network_defaults::{
|
||||
WG_PORT, WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6, WG_TUN_DEVICE_NETMASK_V4,
|
||||
WG_TUN_DEVICE_NETMASK_V6,
|
||||
WG_METADATA_PORT, WG_TUNNEL_PORT, WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6,
|
||||
WG_TUN_DEVICE_NETMASK_V4, WG_TUN_DEVICE_NETMASK_V6,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
|
||||
@@ -46,9 +46,9 @@ pub struct Authenticator {
|
||||
/// default: `fc01::1`
|
||||
pub private_ipv6: Ipv6Addr,
|
||||
|
||||
/// Port announced to external clients wishing to connect to the wireguard interface.
|
||||
/// Tunnel port announced to external clients wishing to connect to the wireguard interface.
|
||||
/// Useful in the instances where the node is behind a proxy.
|
||||
pub announced_port: u16,
|
||||
pub tunnel_announced_port: u16,
|
||||
|
||||
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv4.
|
||||
/// The maximum value for IPv4 is 32
|
||||
@@ -62,10 +62,10 @@ pub struct Authenticator {
|
||||
impl Default for Authenticator {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), WG_PORT),
|
||||
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), WG_TUNNEL_PORT),
|
||||
private_ipv4: WG_TUN_DEVICE_IP_ADDRESS_V4,
|
||||
private_ipv6: WG_TUN_DEVICE_IP_ADDRESS_V6,
|
||||
announced_port: WG_PORT,
|
||||
tunnel_announced_port: WG_TUNNEL_PORT,
|
||||
private_network_prefix_v4: WG_TUN_DEVICE_NETMASK_V4,
|
||||
private_network_prefix_v6: WG_TUN_DEVICE_NETMASK_V6,
|
||||
}
|
||||
@@ -78,7 +78,8 @@ impl From<Authenticator> for nym_wireguard_types::Config {
|
||||
bind_address: value.bind_address,
|
||||
private_ipv4: value.private_ipv4,
|
||||
private_ipv6: value.private_ipv6,
|
||||
announced_port: value.announced_port,
|
||||
announced_tunnel_port: value.tunnel_announced_port,
|
||||
announced_metadata_port: WG_METADATA_PORT,
|
||||
private_network_prefix_v4: value.private_network_prefix_v4,
|
||||
private_network_prefix_v6: value.private_network_prefix_v6,
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ impl MixnetListener {
|
||||
v1::registration::RegistredData {
|
||||
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||
private_ip: allowed_ipv4.into(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
wg_port: self.config.authenticator.tunnel_announced_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
@@ -304,7 +304,7 @@ impl MixnetListener {
|
||||
v2::registration::RegistredData {
|
||||
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||
private_ip: allowed_ipv4.into(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
wg_port: self.config.authenticator.tunnel_announced_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
@@ -317,7 +317,7 @@ impl MixnetListener {
|
||||
v3::registration::RegistredData {
|
||||
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||
private_ip: allowed_ipv4.into(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
wg_port: self.config.authenticator.tunnel_announced_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
@@ -330,7 +330,7 @@ impl MixnetListener {
|
||||
v4::registration::RegistredData {
|
||||
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||
private_ips: (allowed_ipv4, allowed_ipv6).into(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
wg_port: self.config.authenticator.tunnel_announced_port,
|
||||
},
|
||||
reply_to.ok_or(AuthenticatorError::MissingReplyToForOldClient)?,
|
||||
request_id,
|
||||
@@ -343,7 +343,7 @@ impl MixnetListener {
|
||||
v5::registration::RegistredData {
|
||||
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
|
||||
private_ips: (allowed_ipv4, allowed_ipv6).into(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
wg_port: self.config.authenticator.tunnel_announced_port,
|
||||
},
|
||||
request_id,
|
||||
)
|
||||
@@ -374,7 +374,7 @@ impl MixnetListener {
|
||||
let registration_data = RegistrationData {
|
||||
nonce,
|
||||
gateway_data: gateway_data.clone(),
|
||||
wg_port: self.config.authenticator.announced_port,
|
||||
wg_port: self.config.authenticator.tunnel_announced_port,
|
||||
};
|
||||
registred_and_free
|
||||
.registration_in_progres
|
||||
@@ -691,7 +691,7 @@ impl MixnetListener {
|
||||
} else {
|
||||
let mut verifier = self
|
||||
.peer_manager
|
||||
.query_verifier(msg.pub_key(), msg.credential())
|
||||
.query_verifier_by_key(msg.pub_key(), msg.credential())
|
||||
.await?;
|
||||
let available_bandwidth = verifier.verify().await?;
|
||||
self.seen_credential_cache
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use crate::node::internal_service_providers::authenticator::error::AuthenticatorError;
|
||||
use defguard_wireguard_rs::{host::Peer, key::Key};
|
||||
use futures::channel::oneshot;
|
||||
use nym_credential_verification::{ClientBandwidth, CredentialVerifier};
|
||||
use nym_credential_verification::{ClientBandwidth, TicketVerifier};
|
||||
use nym_credentials_interface::CredentialSpendingData;
|
||||
use nym_wireguard::{peer_controller::PeerControlRequest, WireguardGatewayData};
|
||||
use nym_wireguard_types::PeerPublicKey;
|
||||
@@ -99,7 +99,7 @@ impl PeerManager {
|
||||
) -> Result<ClientBandwidth, AuthenticatorError> {
|
||||
let key = Key::new(key.to_bytes());
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
let msg = PeerControlRequest::GetClientBandwidth { key, response_tx };
|
||||
let msg = PeerControlRequest::GetClientBandwidthByKey { key, response_tx };
|
||||
self.wireguard_gateway_data
|
||||
.peer_tx()
|
||||
.send(msg)
|
||||
@@ -120,14 +120,14 @@ impl PeerManager {
|
||||
})
|
||||
}
|
||||
|
||||
pub async fn query_verifier(
|
||||
pub async fn query_verifier_by_key(
|
||||
&mut self,
|
||||
key: PeerPublicKey,
|
||||
credential: CredentialSpendingData,
|
||||
) -> Result<CredentialVerifier, AuthenticatorError> {
|
||||
) -> Result<Box<dyn TicketVerifier + Send + Sync>, AuthenticatorError> {
|
||||
let key = Key::new(key.to_bytes());
|
||||
let (response_tx, response_rx) = oneshot::channel();
|
||||
let msg = PeerControlRequest::GetVerifier {
|
||||
let msg = PeerControlRequest::GetVerifierByKey {
|
||||
key,
|
||||
credential: Box::new(credential),
|
||||
response_tx,
|
||||
@@ -398,13 +398,13 @@ mod tests {
|
||||
let credential = CredentialSpendingData::try_from_bytes(&CREDENTIAL_BYTES).unwrap();
|
||||
|
||||
assert!(peer_manager
|
||||
.query_verifier(public_key, credential.clone())
|
||||
.query_verifier_by_key(public_key, credential.clone())
|
||||
.await
|
||||
.is_err());
|
||||
|
||||
helper_add_peer(&storage, &mut peer_manager).await;
|
||||
peer_manager
|
||||
.query_verifier(public_key, credential)
|
||||
.query_verifier_by_key(public_key, credential)
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
+54
-17
@@ -19,7 +19,7 @@ use nym_network_defaults::NymNetworkDetails;
|
||||
use nym_network_requester::NRServiceProviderBuilder;
|
||||
use nym_node_metrics::events::MetricEventsSender;
|
||||
use nym_node_metrics::NymNodeMetrics;
|
||||
use nym_task::TaskClient;
|
||||
use nym_task::{ShutdownToken, TaskClient};
|
||||
use nym_topology::TopologyProvider;
|
||||
use nym_validator_client::nyxd::{Coin, CosmWasmClient};
|
||||
use nym_validator_client::{nyxd, DirectSigningHttpRpcNyxdClient};
|
||||
@@ -91,7 +91,9 @@ pub struct GatewayTasksBuilder {
|
||||
|
||||
mnemonic: Arc<Zeroizing<bip39::Mnemonic>>,
|
||||
|
||||
shutdown: TaskClient,
|
||||
legacy_task_client: TaskClient,
|
||||
|
||||
shutdown_token: ShutdownToken,
|
||||
|
||||
// populated and cached as necessary
|
||||
ecash_manager: Option<Arc<EcashManager>>,
|
||||
@@ -105,7 +107,7 @@ impl Drop for GatewayTasksBuilder {
|
||||
fn drop(&mut self) {
|
||||
// disarm the shutdown as it was already used to construct relevant tasks and we don't want the builder
|
||||
// to cause shutdown
|
||||
self.shutdown.disarm();
|
||||
self.legacy_task_client.disarm();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +121,8 @@ impl GatewayTasksBuilder {
|
||||
metrics_sender: MetricEventsSender,
|
||||
metrics: NymNodeMetrics,
|
||||
mnemonic: Arc<Zeroizing<bip39::Mnemonic>>,
|
||||
shutdown: TaskClient,
|
||||
legacy_task_client: TaskClient,
|
||||
shutdown_token: ShutdownToken,
|
||||
) -> GatewayTasksBuilder {
|
||||
GatewayTasksBuilder {
|
||||
config,
|
||||
@@ -133,7 +136,8 @@ impl GatewayTasksBuilder {
|
||||
metrics_sender,
|
||||
metrics,
|
||||
mnemonic,
|
||||
shutdown,
|
||||
legacy_task_client,
|
||||
shutdown_token,
|
||||
ecash_manager: None,
|
||||
wireguard_peers: None,
|
||||
wireguard_networks: None,
|
||||
@@ -228,7 +232,7 @@ impl GatewayTasksBuilder {
|
||||
handler_config,
|
||||
nyxd_client,
|
||||
self.identity_keypair.public_key().to_bytes(),
|
||||
self.shutdown.fork("ecash_manager"),
|
||||
self.legacy_task_client.fork("ecash_manager"),
|
||||
self.storage.clone(),
|
||||
)
|
||||
.await?,
|
||||
@@ -270,7 +274,7 @@ impl GatewayTasksBuilder {
|
||||
self.config.gateway.websocket_bind_address,
|
||||
self.config.debug.maximum_open_connections,
|
||||
shared_state,
|
||||
self.shutdown.fork("websocket"),
|
||||
self.legacy_task_client.fork("websocket"),
|
||||
))
|
||||
}
|
||||
|
||||
@@ -286,13 +290,14 @@ impl GatewayTasksBuilder {
|
||||
let mut message_router_builder = SpMessageRouterBuilder::new(
|
||||
*self.identity_keypair.public_key(),
|
||||
self.mix_packet_sender.clone(),
|
||||
self.shutdown.fork("network_requester_message_router"),
|
||||
self.legacy_task_client
|
||||
.fork("network_requester_message_router"),
|
||||
);
|
||||
let transceiver = message_router_builder.gateway_transceiver();
|
||||
|
||||
let (on_start_tx, on_start_rx) = oneshot::channel();
|
||||
let mut nr_builder = NRServiceProviderBuilder::new(nr_opts.config.clone())
|
||||
.with_shutdown(self.shutdown.fork("network_requester_sp"))
|
||||
.with_shutdown(self.legacy_task_client.fork("network_requester_sp"))
|
||||
.with_custom_gateway_transceiver(transceiver)
|
||||
.with_wait_for_gateway(true)
|
||||
.with_minimum_gateway_performance(0)
|
||||
@@ -321,13 +326,13 @@ impl GatewayTasksBuilder {
|
||||
let mut message_router_builder = SpMessageRouterBuilder::new(
|
||||
*self.identity_keypair.public_key(),
|
||||
self.mix_packet_sender.clone(),
|
||||
self.shutdown.fork("ipr_message_router"),
|
||||
self.legacy_task_client.fork("ipr_message_router"),
|
||||
);
|
||||
let transceiver = message_router_builder.gateway_transceiver();
|
||||
|
||||
let (on_start_tx, on_start_rx) = oneshot::channel();
|
||||
let mut ip_packet_router = IpPacketRouter::new(ip_opts.config.clone())
|
||||
.with_shutdown(self.shutdown.fork("ipr_sp"))
|
||||
.with_shutdown(self.legacy_task_client.fork("ipr_sp"))
|
||||
.with_custom_gateway_transceiver(Box::new(transceiver))
|
||||
.with_wait_for_gateway(true)
|
||||
.with_minimum_gateway_performance(0)
|
||||
@@ -427,7 +432,7 @@ impl GatewayTasksBuilder {
|
||||
let mut message_router_builder = SpMessageRouterBuilder::new(
|
||||
*self.identity_keypair.public_key(),
|
||||
self.mix_packet_sender.clone(),
|
||||
self.shutdown.fork("authenticator_message_router"),
|
||||
self.legacy_task_client.fork("authenticator_message_router"),
|
||||
);
|
||||
let transceiver = message_router_builder.gateway_transceiver();
|
||||
|
||||
@@ -440,7 +445,7 @@ impl GatewayTasksBuilder {
|
||||
ecash_manager,
|
||||
)
|
||||
.with_custom_gateway_transceiver(transceiver)
|
||||
.with_shutdown(self.shutdown.fork("authenticator_sp"))
|
||||
.with_shutdown(self.legacy_task_client.fork("authenticator_sp"))
|
||||
.with_wait_for_gateway(true)
|
||||
.with_minimum_gateway_performance(0)
|
||||
.with_custom_topology_provider(topology_provider)
|
||||
@@ -460,7 +465,7 @@ impl GatewayTasksBuilder {
|
||||
pub fn build_stale_messages_cleaner(&self) -> StaleMessagesCleaner {
|
||||
StaleMessagesCleaner::new(
|
||||
&self.storage,
|
||||
self.shutdown.fork("stale_messages_cleaner"),
|
||||
self.legacy_task_client.fork("stale_messages_cleaner"),
|
||||
self.config.debug.stale_messages_max_age,
|
||||
self.config.debug.stale_messages_cleaner_run_interval,
|
||||
)
|
||||
@@ -471,13 +476,17 @@ impl GatewayTasksBuilder {
|
||||
&mut self,
|
||||
) -> Result<Arc<nym_wireguard::WgApiWrapper>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
let _ = self.metrics.clone();
|
||||
let _ = self.shutdown_token.clone();
|
||||
unimplemented!("wireguard is not supported on this platform")
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub async fn try_start_wireguard(
|
||||
&mut self,
|
||||
) -> Result<Arc<nym_wireguard::WgApiWrapper>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
) -> Result<
|
||||
nym_wireguard_private_metadata::ShutdownHandles,
|
||||
Box<dyn std::error::Error + Send + Sync>,
|
||||
> {
|
||||
let all_peers = self.get_wireguard_peers().await?;
|
||||
|
||||
let Some(wireguard_data) = self.wireguard_data.take() else {
|
||||
@@ -492,14 +501,42 @@ impl GatewayTasksBuilder {
|
||||
);
|
||||
};
|
||||
|
||||
let router = nym_wireguard_private_metadata::RouterBuilder::with_default_routes();
|
||||
let router = router.with_state(nym_wireguard_private_metadata::AppState::new(
|
||||
nym_wireguard_private_metadata::PeerControllerTransceiver::new(
|
||||
wireguard_data.inner.peer_tx().clone(),
|
||||
),
|
||||
));
|
||||
|
||||
let bind_address = std::net::SocketAddr::new(
|
||||
wireguard_data.inner.config().private_ipv4.into(),
|
||||
wireguard_data.inner.config().announced_metadata_port,
|
||||
);
|
||||
let server = router.build_server(&bind_address).await?;
|
||||
|
||||
let cancel_token: tokio_util::sync::CancellationToken = (*self.shutdown_token).clone();
|
||||
let axum_shutdown_receiver = cancel_token.clone().cancelled_owned();
|
||||
let server_handle = tokio::spawn(async move {
|
||||
{
|
||||
info!("Started Wireguard Axum HTTP V2 server on {bind_address}");
|
||||
server.run(axum_shutdown_receiver).await
|
||||
}
|
||||
});
|
||||
|
||||
let wg_handle = nym_wireguard::start_wireguard(
|
||||
ecash_manager,
|
||||
self.metrics.clone(),
|
||||
all_peers,
|
||||
self.shutdown.fork("wireguard"),
|
||||
self.legacy_task_client.fork("wireguard"),
|
||||
wireguard_data,
|
||||
)
|
||||
.await?;
|
||||
Ok(wg_handle)
|
||||
let shutdown_handles = nym_wireguard_private_metadata::ShutdownHandles::new(
|
||||
server_handle,
|
||||
wg_handle,
|
||||
cancel_token,
|
||||
);
|
||||
|
||||
Ok(shutdown_handles)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -311,7 +311,10 @@ impl From<Authenticator> for AuthenticatorDetails {
|
||||
}
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema, ToSchema)]
|
||||
pub struct WireguardDetails {
|
||||
// NOTE: the port field is deprecated in favour of tunnel_port
|
||||
pub port: u16,
|
||||
pub tunnel_port: u16,
|
||||
pub metadata_port: u16,
|
||||
pub public_key: String,
|
||||
}
|
||||
|
||||
@@ -320,6 +323,8 @@ impl From<Wireguard> for WireguardDetails {
|
||||
fn from(value: Wireguard) -> Self {
|
||||
WireguardDetails {
|
||||
port: value.port,
|
||||
tunnel_port: value.tunnel_port,
|
||||
metadata_port: value.metadata_port,
|
||||
public_key: value.public_key,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,9 +16,16 @@ pub struct Gateway {
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)]
|
||||
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
|
||||
pub struct Wireguard {
|
||||
#[deprecated(note = "use specific port instead (tunnel or metadata service)")]
|
||||
#[cfg_attr(feature = "openapi", schema(example = 51822, default = 51822))]
|
||||
pub port: u16,
|
||||
|
||||
#[cfg_attr(feature = "openapi", schema(example = 51822, default = 51822))]
|
||||
pub tunnel_port: u16,
|
||||
|
||||
#[cfg_attr(feature = "openapi", schema(example = 51830, default = 51830))]
|
||||
pub metadata_port: u16,
|
||||
|
||||
pub public_key: String,
|
||||
}
|
||||
|
||||
|
||||
@@ -276,13 +276,13 @@ pub(crate) struct WireguardArgs {
|
||||
)]
|
||||
pub(crate) wireguard_bind_address: Option<SocketAddr>,
|
||||
|
||||
/// Port announced to external clients wishing to connect to the wireguard interface.
|
||||
/// Tunnel port announced to external clients wishing to connect to the wireguard interface.
|
||||
/// Useful in the instances where the node is behind a proxy.
|
||||
#[clap(
|
||||
long,
|
||||
env = NYMNODE_WG_ANNOUNCED_PORT_ARG
|
||||
)]
|
||||
pub(crate) wireguard_announced_port: Option<u16>,
|
||||
pub(crate) wireguard_tunnel_announced_port: Option<u16>,
|
||||
|
||||
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard.
|
||||
/// The maximum value for IPv4 is 32 and for IPv6 is 128
|
||||
@@ -311,8 +311,8 @@ impl WireguardArgs {
|
||||
section.bind_address = bind_address
|
||||
}
|
||||
|
||||
if let Some(announced_port) = self.wireguard_announced_port {
|
||||
section.announced_port = announced_port
|
||||
if let Some(announced_tunnel_port) = self.wireguard_tunnel_announced_port {
|
||||
section.announced_tunnel_port = announced_tunnel_port
|
||||
}
|
||||
|
||||
if let Some(private_network_prefix) = self.wireguard_private_network_prefix {
|
||||
|
||||
@@ -202,7 +202,8 @@ pub fn gateway_tasks_config(config: &Config) -> GatewayTasksConfig {
|
||||
bind_address: config.wireguard.bind_address,
|
||||
private_ipv4: config.wireguard.private_ipv4,
|
||||
private_ipv6: config.wireguard.private_ipv6,
|
||||
announced_port: config.wireguard.announced_port,
|
||||
announced_tunnel_port: config.wireguard.announced_tunnel_port,
|
||||
announced_metadata_port: config.wireguard.announced_metadata_port,
|
||||
private_network_prefix_v4: config.wireguard.private_network_prefix_v4,
|
||||
private_network_prefix_v6: config.wireguard.private_network_prefix_v6,
|
||||
storage_paths: config.wireguard.storage_paths.clone(),
|
||||
|
||||
@@ -10,7 +10,7 @@ use human_repr::HumanCount;
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_config::defaults::{
|
||||
mainnet, var_names, DEFAULT_MIX_LISTENING_PORT, DEFAULT_NYM_NODE_HTTP_PORT,
|
||||
DEFAULT_VERLOC_LISTENING_PORT, WG_PORT, WG_TUN_DEVICE_IP_ADDRESS_V4,
|
||||
DEFAULT_VERLOC_LISTENING_PORT, WG_METADATA_PORT, WG_TUNNEL_PORT, WG_TUN_DEVICE_IP_ADDRESS_V4,
|
||||
WG_TUN_DEVICE_IP_ADDRESS_V6,
|
||||
};
|
||||
use nym_config::defaults::{WG_TUN_DEVICE_NETMASK_V4, WG_TUN_DEVICE_NETMASK_V6};
|
||||
@@ -931,9 +931,13 @@ pub struct Wireguard {
|
||||
/// default: `fc01::1`
|
||||
pub private_ipv6: Ipv6Addr,
|
||||
|
||||
/// Port announced to external clients wishing to connect to the wireguard interface.
|
||||
/// Tunnel port announced to external clients wishing to connect to the wireguard interface.
|
||||
/// Useful in the instances where the node is behind a proxy.
|
||||
pub announced_port: u16,
|
||||
pub announced_tunnel_port: u16,
|
||||
|
||||
/// Metadata port announced to external clients wishing to connect to the metadata endpoint.
|
||||
/// Useful in the instances where the node is behind a proxy.
|
||||
pub announced_metadata_port: u16,
|
||||
|
||||
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv4.
|
||||
/// The maximum value for IPv4 is 32
|
||||
@@ -951,10 +955,11 @@ impl Wireguard {
|
||||
pub fn new_default<P: AsRef<Path>>(data_dir: P) -> Self {
|
||||
Wireguard {
|
||||
enabled: false,
|
||||
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), WG_PORT),
|
||||
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), WG_TUNNEL_PORT),
|
||||
private_ipv4: WG_TUN_DEVICE_IP_ADDRESS_V4,
|
||||
private_ipv6: WG_TUN_DEVICE_IP_ADDRESS_V6,
|
||||
announced_port: WG_PORT,
|
||||
announced_tunnel_port: WG_TUNNEL_PORT,
|
||||
announced_metadata_port: WG_METADATA_PORT,
|
||||
private_network_prefix_v4: WG_TUN_DEVICE_NETMASK_V4,
|
||||
private_network_prefix_v6: WG_TUN_DEVICE_NETMASK_V6,
|
||||
storage_paths: persistence::WireguardPaths::new(data_dir),
|
||||
@@ -968,7 +973,8 @@ impl From<Wireguard> for nym_wireguard_types::Config {
|
||||
bind_address: value.bind_address,
|
||||
private_ipv4: value.private_ipv4,
|
||||
private_ipv6: value.private_ipv6,
|
||||
announced_port: value.announced_port,
|
||||
announced_tunnel_port: value.announced_tunnel_port,
|
||||
announced_metadata_port: value.announced_metadata_port,
|
||||
private_network_prefix_v4: value.private_network_prefix_v4,
|
||||
private_network_prefix_v6: value.private_network_prefix_v6,
|
||||
}
|
||||
@@ -981,7 +987,7 @@ impl From<Wireguard> for nym_authenticator::config::Authenticator {
|
||||
bind_address: value.bind_address,
|
||||
private_ipv4: value.private_ipv4,
|
||||
private_ipv6: value.private_ipv6,
|
||||
announced_port: value.announced_port,
|
||||
tunnel_announced_port: value.announced_tunnel_port,
|
||||
private_network_prefix_v4: value.private_network_prefix_v4,
|
||||
private_network_prefix_v6: value.private_network_prefix_v6,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
mod old_config_v1;
|
||||
mod old_config_v10;
|
||||
mod old_config_v2;
|
||||
mod old_config_v3;
|
||||
mod old_config_v4;
|
||||
@@ -12,6 +13,7 @@ mod old_config_v8;
|
||||
mod old_config_v9;
|
||||
|
||||
pub use old_config_v1::try_upgrade_config_v1;
|
||||
pub use old_config_v10::try_upgrade_config_v10;
|
||||
pub use old_config_v2::try_upgrade_config_v2;
|
||||
pub use old_config_v3::try_upgrade_config_v3;
|
||||
pub use old_config_v4::try_upgrade_config_v4;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,29 +1,26 @@
|
||||
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
use crate::config::authenticator::{Authenticator, AuthenticatorDebug};
|
||||
use crate::config::gateway_tasks::{
|
||||
ClientBandwidthDebug, StaleMessageDebug, ZkNymTicketHandlerDebug,
|
||||
use crate::config::old_configs::old_config_v10::{
|
||||
AuthenticatorDebugV10, AuthenticatorPathsV10, AuthenticatorV10, ClientBandwidthDebugV10,
|
||||
ConfigV10, GatewayTasksConfigDebugV10, GatewayTasksConfigV10, GatewayTasksPathsV10, HostV10,
|
||||
HttpV10, IpPacketRouterDebugV10, IpPacketRouterPathsV10, IpPacketRouterV10, KeysPathsV10,
|
||||
LoggingSettingsV10, MixnetDebugV10, MixnetV10, NetworkRequesterDebugV10,
|
||||
NetworkRequesterPathsV10, NetworkRequesterV10, NodeModesV10, NymNodePathsV10,
|
||||
ReplayProtectionDebugV10, ReplayProtectionPathsV10, ReplayProtectionV10,
|
||||
ServiceProvidersConfigDebugV10, ServiceProvidersConfigV10, ServiceProvidersPathsV10,
|
||||
StaleMessageDebugV10, VerlocDebugV10, VerlocV10, WireguardPathsV10, WireguardV10,
|
||||
ZkNymTicketHandlerDebugV10,
|
||||
};
|
||||
use crate::config::persistence::{
|
||||
AuthenticatorPaths, GatewayTasksPaths, IpPacketRouterPaths, KeysPaths, NetworkRequesterPaths,
|
||||
NymNodePaths, ReplayProtectionPaths, ServiceProvidersPaths, WireguardPaths,
|
||||
DEFAULT_PRIMARY_X25519_SPHINX_KEY_FILENAME, DEFAULT_SECONDARY_X25519_SPHINX_KEY_FILENAME,
|
||||
};
|
||||
use crate::config::service_providers::{
|
||||
IpPacketRouter, IpPacketRouterDebug, NetworkRequester, NetworkRequesterDebug,
|
||||
};
|
||||
use crate::config::{
|
||||
gateway_tasks, service_providers, Config, GatewayTasksConfig, Host, Http, Mixnet, MixnetDebug,
|
||||
NodeModes, ReplayProtection, ReplayProtectionDebug, ServiceProvidersConfig, Verloc,
|
||||
VerlocDebug, Wireguard, DEFAULT_HTTP_PORT,
|
||||
};
|
||||
use crate::config::{NodeModes, DEFAULT_HTTP_PORT};
|
||||
use crate::error::{KeyIOFailure, NymNodeError};
|
||||
use crate::node::helpers::{get_current_rotation_id, load_key, store_key};
|
||||
use crate::node::key_rotation::key::SphinxPrivateKey;
|
||||
use celes::Country;
|
||||
use clap::ValueEnum;
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
use nym_client_core_config_types::DebugConfig as ClientDebugConfig;
|
||||
use nym_config::defaults::DEFAULT_VERLOC_LISTENING_PORT;
|
||||
use nym_config::helpers::{in6addr_any_init, inaddr_any};
|
||||
@@ -1330,7 +1327,7 @@ async fn upgrade_sphinx_key(old_cfg: &ConfigV9) -> Result<(PathBuf, PathBuf), Ny
|
||||
pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
path: P,
|
||||
prev_config: Option<ConfigV9>,
|
||||
) -> Result<Config, NymNodeError> {
|
||||
) -> Result<ConfigV10, NymNodeError> {
|
||||
debug!("attempting to load v9 config...");
|
||||
|
||||
let old_cfg = if let Some(prev_config) = prev_config {
|
||||
@@ -1342,33 +1339,33 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
let (primary_x25519_sphinx_key_file, secondary_x25519_sphinx_key_file) =
|
||||
upgrade_sphinx_key(&old_cfg).await?;
|
||||
|
||||
let cfg = Config {
|
||||
let cfg = ConfigV10 {
|
||||
save_path: old_cfg.save_path,
|
||||
id: old_cfg.id,
|
||||
modes: NodeModes {
|
||||
modes: NodeModesV10 {
|
||||
mixnode: old_cfg.modes.mixnode,
|
||||
entry: old_cfg.modes.entry,
|
||||
exit: old_cfg.modes.exit,
|
||||
},
|
||||
host: Host {
|
||||
host: HostV10 {
|
||||
public_ips: old_cfg.host.public_ips,
|
||||
hostname: old_cfg.host.hostname,
|
||||
location: old_cfg.host.location,
|
||||
},
|
||||
mixnet: Mixnet {
|
||||
mixnet: MixnetV10 {
|
||||
bind_address: old_cfg.mixnet.bind_address,
|
||||
announce_port: old_cfg.mixnet.announce_port,
|
||||
nym_api_urls: old_cfg.mixnet.nym_api_urls,
|
||||
nyxd_urls: old_cfg.mixnet.nyxd_urls,
|
||||
replay_protection: ReplayProtection {
|
||||
storage_paths: ReplayProtectionPaths {
|
||||
replay_protection: ReplayProtectionV10 {
|
||||
storage_paths: ReplayProtectionPathsV10 {
|
||||
current_bloomfilters_directory: old_cfg
|
||||
.mixnet
|
||||
.replay_protection
|
||||
.storage_paths
|
||||
.current_bloomfilters_directory,
|
||||
},
|
||||
debug: ReplayProtectionDebug {
|
||||
debug: ReplayProtectionDebugV10 {
|
||||
unsafe_disabled: old_cfg.mixnet.replay_protection.debug.unsafe_disabled,
|
||||
maximum_replay_detection_deferral: old_cfg
|
||||
.mixnet
|
||||
@@ -1404,7 +1401,7 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
},
|
||||
},
|
||||
key_rotation: Default::default(),
|
||||
debug: MixnetDebug {
|
||||
debug: MixnetDebugV10 {
|
||||
maximum_forward_packet_delay: old_cfg.mixnet.debug.maximum_forward_packet_delay,
|
||||
packet_forwarding_initial_backoff: old_cfg
|
||||
.mixnet
|
||||
@@ -1420,8 +1417,8 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
storage_paths: NymNodePaths {
|
||||
keys: KeysPaths {
|
||||
storage_paths: NymNodePathsV10 {
|
||||
keys: KeysPathsV10 {
|
||||
private_ed25519_identity_key_file: old_cfg
|
||||
.storage_paths
|
||||
.keys
|
||||
@@ -1443,7 +1440,7 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
},
|
||||
description: old_cfg.storage_paths.description,
|
||||
},
|
||||
http: Http {
|
||||
http: HttpV10 {
|
||||
bind_address: old_cfg.http.bind_address,
|
||||
landing_page_assets_path: old_cfg.http.landing_page_assets_path,
|
||||
access_token: old_cfg.http.access_token,
|
||||
@@ -1452,10 +1449,10 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
expose_crypto_hardware: old_cfg.http.expose_crypto_hardware,
|
||||
node_load_cache_ttl: old_cfg.http.node_load_cache_ttl,
|
||||
},
|
||||
verloc: Verloc {
|
||||
verloc: VerlocV10 {
|
||||
bind_address: old_cfg.verloc.bind_address,
|
||||
announce_port: old_cfg.verloc.announce_port,
|
||||
debug: VerlocDebug {
|
||||
debug: VerlocDebugV10 {
|
||||
packets_per_node: old_cfg.verloc.debug.packets_per_node,
|
||||
connection_timeout: old_cfg.verloc.debug.connection_timeout,
|
||||
packet_timeout: old_cfg.verloc.debug.packet_timeout,
|
||||
@@ -1465,7 +1462,7 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
retry_timeout: old_cfg.verloc.debug.retry_timeout,
|
||||
},
|
||||
},
|
||||
wireguard: Wireguard {
|
||||
wireguard: WireguardV10 {
|
||||
enabled: old_cfg.wireguard.enabled,
|
||||
bind_address: old_cfg.wireguard.bind_address,
|
||||
private_ipv4: old_cfg.wireguard.private_ipv4,
|
||||
@@ -1473,7 +1470,7 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
announced_port: old_cfg.wireguard.announced_port,
|
||||
private_network_prefix_v4: old_cfg.wireguard.private_network_prefix_v4,
|
||||
private_network_prefix_v6: old_cfg.wireguard.private_network_prefix_v6,
|
||||
storage_paths: WireguardPaths {
|
||||
storage_paths: WireguardPathsV10 {
|
||||
private_diffie_hellman_key_file: old_cfg
|
||||
.wireguard
|
||||
.storage_paths
|
||||
@@ -1484,8 +1481,8 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
.public_diffie_hellman_key_file,
|
||||
},
|
||||
},
|
||||
gateway_tasks: GatewayTasksConfig {
|
||||
storage_paths: GatewayTasksPaths {
|
||||
gateway_tasks: GatewayTasksConfigV10 {
|
||||
storage_paths: GatewayTasksPathsV10 {
|
||||
clients_storage: old_cfg.gateway_tasks.storage_paths.clients_storage,
|
||||
stats_storage: old_cfg.gateway_tasks.storage_paths.stats_storage,
|
||||
cosmos_mnemonic: old_cfg.gateway_tasks.storage_paths.cosmos_mnemonic,
|
||||
@@ -1494,12 +1491,12 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
ws_bind_address: old_cfg.gateway_tasks.ws_bind_address,
|
||||
announce_ws_port: old_cfg.gateway_tasks.announce_ws_port,
|
||||
announce_wss_port: old_cfg.gateway_tasks.announce_wss_port,
|
||||
debug: gateway_tasks::Debug {
|
||||
debug: GatewayTasksConfigDebugV10 {
|
||||
message_retrieval_limit: old_cfg.gateway_tasks.debug.message_retrieval_limit,
|
||||
maximum_open_connections: old_cfg.gateway_tasks.debug.maximum_open_connections,
|
||||
minimum_mix_performance: old_cfg.gateway_tasks.debug.minimum_mix_performance,
|
||||
max_request_timestamp_skew: old_cfg.gateway_tasks.debug.max_request_timestamp_skew,
|
||||
stale_messages: StaleMessageDebug {
|
||||
stale_messages: StaleMessageDebugV10 {
|
||||
cleaner_run_interval: old_cfg
|
||||
.gateway_tasks
|
||||
.debug
|
||||
@@ -1507,7 +1504,7 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
.cleaner_run_interval,
|
||||
max_age: old_cfg.gateway_tasks.debug.stale_messages.max_age,
|
||||
},
|
||||
client_bandwidth: ClientBandwidthDebug {
|
||||
client_bandwidth: ClientBandwidthDebugV10 {
|
||||
max_flushing_rate: old_cfg
|
||||
.gateway_tasks
|
||||
.debug
|
||||
@@ -1519,7 +1516,7 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
.client_bandwidth
|
||||
.max_delta_flushing_amount,
|
||||
},
|
||||
zk_nym_tickets: ZkNymTicketHandlerDebug {
|
||||
zk_nym_tickets: ZkNymTicketHandlerDebugV10 {
|
||||
revocation_bandwidth_penalty: old_cfg
|
||||
.gateway_tasks
|
||||
.debug
|
||||
@@ -1544,11 +1541,11 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
},
|
||||
},
|
||||
},
|
||||
service_providers: ServiceProvidersConfig {
|
||||
storage_paths: ServiceProvidersPaths {
|
||||
service_providers: ServiceProvidersConfigV10 {
|
||||
storage_paths: ServiceProvidersPathsV10 {
|
||||
clients_storage: old_cfg.service_providers.storage_paths.clients_storage,
|
||||
stats_storage: old_cfg.service_providers.storage_paths.stats_storage,
|
||||
network_requester: NetworkRequesterPaths {
|
||||
network_requester: NetworkRequesterPathsV10 {
|
||||
private_ed25519_identity_key_file: old_cfg
|
||||
.service_providers
|
||||
.storage_paths
|
||||
@@ -1585,7 +1582,7 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
.network_requester
|
||||
.gateway_registrations,
|
||||
},
|
||||
ip_packet_router: IpPacketRouterPaths {
|
||||
ip_packet_router: IpPacketRouterPathsV10 {
|
||||
private_ed25519_identity_key_file: old_cfg
|
||||
.service_providers
|
||||
.storage_paths
|
||||
@@ -1622,7 +1619,7 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
.ip_packet_router
|
||||
.gateway_registrations,
|
||||
},
|
||||
authenticator: AuthenticatorPaths {
|
||||
authenticator: AuthenticatorPathsV10 {
|
||||
private_ed25519_identity_key_file: old_cfg
|
||||
.service_providers
|
||||
.storage_paths
|
||||
@@ -1662,8 +1659,8 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
},
|
||||
open_proxy: old_cfg.service_providers.open_proxy,
|
||||
upstream_exit_policy_url: old_cfg.service_providers.upstream_exit_policy_url,
|
||||
network_requester: NetworkRequester {
|
||||
debug: NetworkRequesterDebug {
|
||||
network_requester: NetworkRequesterV10 {
|
||||
debug: NetworkRequesterDebugV10 {
|
||||
enabled: old_cfg.service_providers.network_requester.debug.enabled,
|
||||
disable_poisson_rate: old_cfg
|
||||
.service_providers
|
||||
@@ -1677,8 +1674,8 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
.client_debug,
|
||||
},
|
||||
},
|
||||
ip_packet_router: IpPacketRouter {
|
||||
debug: IpPacketRouterDebug {
|
||||
ip_packet_router: IpPacketRouterV10 {
|
||||
debug: IpPacketRouterDebugV10 {
|
||||
enabled: old_cfg.service_providers.ip_packet_router.debug.enabled,
|
||||
disable_poisson_rate: old_cfg
|
||||
.service_providers
|
||||
@@ -1692,8 +1689,8 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
.client_debug,
|
||||
},
|
||||
},
|
||||
authenticator: Authenticator {
|
||||
debug: AuthenticatorDebug {
|
||||
authenticator: AuthenticatorV10 {
|
||||
debug: AuthenticatorDebugV10 {
|
||||
enabled: old_cfg.service_providers.authenticator.debug.enabled,
|
||||
disable_poisson_rate: old_cfg
|
||||
.service_providers
|
||||
@@ -1703,12 +1700,12 @@ pub async fn try_upgrade_config_v9<P: AsRef<Path>>(
|
||||
client_debug: old_cfg.service_providers.authenticator.debug.client_debug,
|
||||
},
|
||||
},
|
||||
debug: service_providers::Debug {
|
||||
debug: ServiceProvidersConfigDebugV10 {
|
||||
message_retrieval_limit: old_cfg.service_providers.debug.message_retrieval_limit,
|
||||
},
|
||||
},
|
||||
metrics: Default::default(),
|
||||
logging: LoggingSettings {},
|
||||
logging: LoggingSettingsV10 {},
|
||||
debug: Default::default(),
|
||||
};
|
||||
Ok(cfg)
|
||||
|
||||
@@ -145,7 +145,11 @@ private_ipv6 = '{{ wireguard.private_ipv6 }}'
|
||||
|
||||
# Port announced to external clients wishing to connect to the wireguard interface.
|
||||
# Useful in the instances where the node is behind a proxy.
|
||||
announced_port = {{ wireguard.announced_port }}
|
||||
announced_tunnel_port = {{ wireguard.announced_tunnel_port }}
|
||||
|
||||
# Port announced to external clients wishing to connect to the metadata service.
|
||||
# Useful in the instances where the node is behind a proxy.
|
||||
announced_metadata_port = {{ wireguard.announced_metadata_port }}
|
||||
|
||||
# The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv4.
|
||||
# The maximum value for IPv4 is 32
|
||||
|
||||
@@ -16,7 +16,8 @@ async fn try_upgrade_config(path: &Path) -> Result<(), NymNodeError> {
|
||||
let cfg = try_upgrade_config_v6(path, cfg).await.ok();
|
||||
let cfg = try_upgrade_config_v7(path, cfg).await.ok();
|
||||
let cfg = try_upgrade_config_v8(path, cfg).await.ok();
|
||||
match try_upgrade_config_v9(path, cfg).await {
|
||||
let cfg = try_upgrade_config_v9(path, cfg).await.ok();
|
||||
match try_upgrade_config_v10(path, cfg).await {
|
||||
Ok(cfg) => cfg.save(),
|
||||
Err(e) => {
|
||||
tracing::error!("Failed to finish upgrade: {e}");
|
||||
|
||||
@@ -605,7 +605,8 @@ impl NymNode {
|
||||
metrics_sender: MetricEventsSender,
|
||||
active_clients_store: ActiveClientsStore,
|
||||
mix_packet_sender: MixForwardingSender,
|
||||
task_client: TaskClient,
|
||||
legacy_task_client: TaskClient,
|
||||
shutdown_token: ShutdownToken,
|
||||
) -> Result<(), NymNodeError> {
|
||||
let config = gateway_tasks_config(&self.config);
|
||||
|
||||
@@ -623,7 +624,8 @@ impl NymNode {
|
||||
metrics_sender,
|
||||
self.metrics.clone(),
|
||||
self.entry_gateway.mnemonic.clone(),
|
||||
task_client,
|
||||
legacy_task_client,
|
||||
shutdown_token,
|
||||
);
|
||||
|
||||
// if we're running in entry mode, start the websocket
|
||||
@@ -716,8 +718,11 @@ impl NymNode {
|
||||
|
||||
// entry gateway info
|
||||
let wireguard = if self.config.wireguard.enabled {
|
||||
#[allow(deprecated)]
|
||||
Some(api_requests::v1::gateway::models::Wireguard {
|
||||
port: self.config.wireguard.announced_port,
|
||||
port: self.config.wireguard.announced_tunnel_port,
|
||||
tunnel_port: self.config.wireguard.announced_tunnel_port,
|
||||
metadata_port: self.config.wireguard.announced_metadata_port,
|
||||
public_key: self.x25519_wireguard_key()?.to_string(),
|
||||
})
|
||||
} else {
|
||||
@@ -1183,6 +1188,7 @@ impl NymNode {
|
||||
active_clients_store,
|
||||
mix_packet_sender,
|
||||
self.shutdown_manager.subscribe_legacy("gateway-tasks"),
|
||||
self.shutdown_manager.child_token("gateway-tasks"),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -0,0 +1,243 @@
|
||||
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use nym_bin_common::logging::LoggingSettings;
|
||||
pub use nym_client_core::config::Config as BaseClientConfig;
|
||||
use nym_client_core::{cli_helpers::CliClientConfig, config::disk_persistence::CommonClientPaths};
|
||||
use nym_config::{
|
||||
must_get_home, save_formatted_config_to_file, NymConfigTemplate, OptionalSet,
|
||||
DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
|
||||
};
|
||||
use nym_network_defaults::{
|
||||
WG_METADATA_PORT, WG_TUNNEL_PORT, WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6,
|
||||
WG_TUN_DEVICE_NETMASK_V4, WG_TUN_DEVICE_NETMASK_V6,
|
||||
};
|
||||
use nym_service_providers_common::DEFAULT_SERVICE_PROVIDERS_DIR;
|
||||
pub use persistence::AuthenticatorPaths;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{
|
||||
io,
|
||||
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
|
||||
path::{Path, PathBuf},
|
||||
str::FromStr,
|
||||
};
|
||||
use template::CONFIG_TEMPLATE;
|
||||
|
||||
pub mod helpers;
|
||||
pub mod old_config_v1_1_54;
|
||||
pub mod persistence;
|
||||
pub mod template;
|
||||
|
||||
const DEFAULT_AUTHENTICATOR_DIR: &str = "authenticator";
|
||||
|
||||
/// Derive default path to authenticator's config directory.
|
||||
/// It should get resolved to `$HOME/.nym/service-providers/authenticator/<id>/config`
|
||||
pub fn default_config_directory<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
must_get_home()
|
||||
.join(NYM_DIR)
|
||||
.join(DEFAULT_SERVICE_PROVIDERS_DIR)
|
||||
.join(DEFAULT_AUTHENTICATOR_DIR)
|
||||
.join(id)
|
||||
.join(DEFAULT_CONFIG_DIR)
|
||||
}
|
||||
|
||||
/// Derive default path to authenticator's config file.
|
||||
/// It should get resolved to `$HOME/.nym/service-providers/authenticator/<id>/config/config.toml`
|
||||
pub fn default_config_filepath<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
default_config_directory(id).join(DEFAULT_CONFIG_FILENAME)
|
||||
}
|
||||
|
||||
/// Derive default path to authenticator's data directory where files, such as keys, are stored.
|
||||
/// It should get resolved to `$HOME/.nym/service-providers/authenticator/<id>/data`
|
||||
pub fn default_data_directory<P: AsRef<Path>>(id: P) -> PathBuf {
|
||||
must_get_home()
|
||||
.join(NYM_DIR)
|
||||
.join(DEFAULT_SERVICE_PROVIDERS_DIR)
|
||||
.join(DEFAULT_AUTHENTICATOR_DIR)
|
||||
.join(id)
|
||||
.join(DEFAULT_DATA_DIR)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
pub struct Config {
|
||||
#[serde(flatten)]
|
||||
pub base: BaseClientConfig,
|
||||
|
||||
#[serde(default)]
|
||||
pub authenticator: Authenticator,
|
||||
|
||||
pub storage_paths: AuthenticatorPaths,
|
||||
|
||||
pub logging: LoggingSettings,
|
||||
}
|
||||
|
||||
impl NymConfigTemplate for Config {
|
||||
fn template(&self) -> &'static str {
|
||||
CONFIG_TEMPLATE
|
||||
}
|
||||
}
|
||||
|
||||
impl CliClientConfig for Config {
|
||||
fn common_paths(&self) -> &CommonClientPaths {
|
||||
&self.storage_paths.common_paths
|
||||
}
|
||||
|
||||
fn core_config(&self) -> &BaseClientConfig {
|
||||
&self.base
|
||||
}
|
||||
|
||||
fn default_store_location(&self) -> PathBuf {
|
||||
self.default_location()
|
||||
}
|
||||
|
||||
fn save_to<P: AsRef<Path>>(&self, path: P) -> io::Result<()> {
|
||||
save_formatted_config_to_file(self, path)
|
||||
}
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new<S: AsRef<str>>(id: S) -> Self {
|
||||
Config {
|
||||
base: BaseClientConfig::new(id.as_ref(), env!("CARGO_PKG_VERSION")),
|
||||
authenticator: Default::default(),
|
||||
storage_paths: AuthenticatorPaths::new_base(default_data_directory(id.as_ref())),
|
||||
logging: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn with_data_directory<P: AsRef<Path>>(mut self, data_directory: P) -> Self {
|
||||
self.storage_paths = AuthenticatorPaths::new_base(data_directory);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
|
||||
nym_config::read_config_from_toml_file(path)
|
||||
}
|
||||
|
||||
pub fn read_from_default_path<P: AsRef<Path>>(id: P) -> io::Result<Self> {
|
||||
Self::read_from_toml_file(default_config_filepath(id))
|
||||
}
|
||||
|
||||
pub fn default_location(&self) -> PathBuf {
|
||||
default_config_filepath(&self.base.client.id)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn save_to_default_location(&self) -> io::Result<()> {
|
||||
let config_save_location: PathBuf = self.default_location();
|
||||
save_formatted_config_to_file(self, config_save_location)
|
||||
}
|
||||
|
||||
pub fn validate(&self) -> bool {
|
||||
// no other sections have explicit requirements (yet)
|
||||
self.base.validate()
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn set_no_poisson_process(&mut self) {
|
||||
self.base.set_no_poisson_process()
|
||||
}
|
||||
|
||||
// poor man's 'builder' method
|
||||
#[allow(unused)]
|
||||
pub fn with_base<F, T>(mut self, f: F, val: T) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
{
|
||||
self.base = f(self.base, val);
|
||||
self
|
||||
}
|
||||
|
||||
// helper methods to use `OptionalSet` trait. Those are defined due to very... ehm. 'specific' structure of this config
|
||||
// (plz, lets refactor it)
|
||||
pub fn with_optional_base<F, T>(mut self, f: F, val: Option<T>) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
{
|
||||
self.base = self.base.with_optional(f, val);
|
||||
self
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn with_optional_base_env<F, T>(mut self, f: F, val: Option<T>, env_var: &str) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
T: FromStr,
|
||||
<T as FromStr>::Err: std::fmt::Debug,
|
||||
{
|
||||
self.base = self.base.with_optional_env(f, val, env_var);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn with_optional_base_custom_env<F, T, G>(
|
||||
mut self,
|
||||
f: F,
|
||||
val: Option<T>,
|
||||
env_var: &str,
|
||||
parser: G,
|
||||
) -> Self
|
||||
where
|
||||
F: Fn(BaseClientConfig, T) -> BaseClientConfig,
|
||||
G: Fn(&str) -> T,
|
||||
{
|
||||
self.base = self.base.with_optional_custom_env(f, val, env_var, parser);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
|
||||
#[serde(default, deny_unknown_fields)]
|
||||
pub struct Authenticator {
|
||||
/// Socket address this node will use for binding its wireguard interface.
|
||||
/// default: `0.0.0.0:51822`
|
||||
pub bind_address: SocketAddr,
|
||||
|
||||
/// Private IP address of the wireguard gateway.
|
||||
/// default: `10.1.0.1`
|
||||
pub private_ipv4: Ipv4Addr,
|
||||
|
||||
/// Private IP address of the wireguard gateway.
|
||||
/// default: `fc01::1`
|
||||
pub private_ipv6: Ipv6Addr,
|
||||
|
||||
/// Tunnel port announced to external clients wishing to connect to the wireguard interface.
|
||||
/// Useful in the instances where the node is behind a proxy.
|
||||
pub tunnel_announced_port: u16,
|
||||
|
||||
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv4.
|
||||
/// The maximum value for IPv4 is 32
|
||||
pub private_network_prefix_v4: u8,
|
||||
|
||||
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv6.
|
||||
/// The maximum value for IPv6 is 128
|
||||
pub private_network_prefix_v6: u8,
|
||||
}
|
||||
|
||||
impl Default for Authenticator {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), WG_TUNNEL_PORT),
|
||||
private_ipv4: WG_TUN_DEVICE_IP_ADDRESS_V4,
|
||||
private_ipv6: WG_TUN_DEVICE_IP_ADDRESS_V6,
|
||||
tunnel_announced_port: WG_TUNNEL_PORT,
|
||||
private_network_prefix_v4: WG_TUN_DEVICE_NETMASK_V4,
|
||||
private_network_prefix_v6: WG_TUN_DEVICE_NETMASK_V6,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Authenticator> for nym_wireguard_types::Config {
|
||||
fn from(value: Authenticator) -> Self {
|
||||
nym_wireguard_types::Config {
|
||||
bind_address: value.bind_address,
|
||||
private_ipv4: value.private_ipv4,
|
||||
private_ipv6: value.private_ipv6,
|
||||
announced_tunnel_port: value.tunnel_announced_port,
|
||||
announced_metadata_port: WG_METADATA_PORT,
|
||||
private_network_prefix_v4: value.private_network_prefix_v4,
|
||||
private_network_prefix_v6: value.private_network_prefix_v6,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user