Compare commits

...

9 Commits

Author SHA1 Message Date
Jędrzej Stuczyński 3aaed5aa37 further build/lint fixes 2025-09-01 17:47:27 +01:00
Jędrzej Stuczyński a6570d085c linux fixes 2025-09-01 17:36:59 +01:00
Jędrzej Stuczyński 9b549e838c moved IPR into gateway 2025-09-01 17:31:34 +01:00
Jędrzej Stuczyński f1f302a71c log => tracing 2025-09-01 16:15:35 +01:00
Jędrzej Stuczyński d3ad14e87d removed cli-related files in ipr 2025-09-01 16:10:11 +01:00
Jędrzej Stuczyński d90eda116f moved network requester into gateway 2025-09-01 15:58:35 +01:00
Jędrzej Stuczyński 0c51e6537d log => tracing 2025-09-01 15:14:40 +01:00
Jędrzej Stuczyński c0575a31b5 removed cli-related files in network requester 2025-09-01 14:58:53 +01:00
Jędrzej Stuczyński fa92923ead removed dead dependencies 2025-09-01 13:32:15 +01:00
112 changed files with 529 additions and 3906 deletions
Generated
+13 -137
View File
@@ -14,16 +14,6 @@ dependencies = [
"syn 2.0.104",
]
[[package]]
name = "addr"
version = "0.15.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a93b8a41dbe230ad5087cc721f8d41611de654542180586b315d9f4cf6b72bef"
dependencies = [
"psl",
"psl-types",
]
[[package]]
name = "addr2line"
version = "0.24.2"
@@ -1369,19 +1359,6 @@ dependencies = [
"crossbeam-utils",
]
[[package]]
name = "console"
version = "0.15.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
dependencies = [
"encode_unicode",
"libc",
"once_cell",
"unicode-width 0.2.1",
"windows-sys 0.59.0",
]
[[package]]
name = "console"
version = "0.16.0"
@@ -3895,7 +3872,7 @@ version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70a646d946d06bedbbc4cac4c218acf4bbf2d87757a784857025f4d447e4e1cd"
dependencies = [
"console 0.16.0",
"console",
"portable-atomic",
"unicode-width 0.2.1",
"unit-prefix",
@@ -5751,52 +5728,55 @@ dependencies = [
name = "nym-gateway"
version = "1.1.36"
dependencies = [
"anyhow",
"async-trait",
"bincode",
"bip39",
"bs58",
"bytes",
"dashmap",
"defguard_wireguard_rs",
"etherparse",
"fastrand 2.3.0",
"futures",
"ipnetwork",
"mock_instant",
"nym-api-requests",
"nym-authenticator-requests",
"nym-bin-common",
"nym-client-core",
"nym-credential-verification",
"nym-credentials",
"nym-credentials-interface",
"nym-crypto",
"nym-exit-policy",
"nym-gateway-requests",
"nym-gateway-stats-storage",
"nym-gateway-storage",
"nym-id",
"nym-ip-packet-router",
"nym-ip-packet-requests",
"nym-mixnet-client",
"nym-mixnode-common",
"nym-network-defaults",
"nym-network-requester",
"nym-node-metrics",
"nym-sdk",
"nym-service-provider-requests-common",
"nym-service-providers-common",
"nym-socks5-proxy-helpers",
"nym-socks5-requests",
"nym-sphinx",
"nym-statistics-common",
"nym-task",
"nym-topology",
"nym-types",
"nym-tun",
"nym-validator-client",
"nym-wireguard",
"nym-wireguard-private-metadata-server",
"nym-wireguard-types",
"rand 0.8.5",
"serde",
"sha2 0.10.9",
"thiserror 2.0.12",
"time",
"tokio",
"tokio-stream",
"tokio-tun",
"tokio-tungstenite",
"tokio-util",
"tracing",
@@ -6038,49 +6018,6 @@ dependencies = [
"tokio-util",
]
[[package]]
name = "nym-ip-packet-router"
version = "0.1.0"
dependencies = [
"anyhow",
"async-trait",
"bincode",
"bs58",
"bytes",
"clap",
"etherparse",
"futures",
"log",
"nym-bin-common",
"nym-client-core",
"nym-config",
"nym-crypto",
"nym-exit-policy",
"nym-id",
"nym-ip-packet-requests",
"nym-network-defaults",
"nym-network-requester",
"nym-sdk",
"nym-service-provider-requests-common",
"nym-service-providers-common",
"nym-sphinx",
"nym-task",
"nym-tun",
"nym-types",
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
"reqwest 0.12.22",
"serde",
"serde_json",
"thiserror 2.0.12",
"time",
"tokio",
"tokio-tun",
"tokio-util",
"url",
]
[[package]]
name = "nym-ledger"
version = "0.1.0"
@@ -6231,56 +6168,6 @@ dependencies = [
"utoipa-swagger-ui",
]
[[package]]
name = "nym-network-requester"
version = "1.1.62"
dependencies = [
"addr",
"anyhow",
"async-trait",
"bs58",
"clap",
"dirs",
"futures",
"humantime-serde",
"ipnetwork",
"log",
"nym-async-file-watcher",
"nym-bin-common",
"nym-client-core",
"nym-client-websocket-requests",
"nym-config",
"nym-credential-storage",
"nym-credentials",
"nym-crypto",
"nym-exit-policy",
"nym-id",
"nym-network-defaults",
"nym-ordered-buffer",
"nym-sdk",
"nym-service-providers-common",
"nym-socks5-proxy-helpers",
"nym-socks5-requests",
"nym-sphinx",
"nym-task",
"nym-types",
"publicsuffix",
"rand 0.8.5",
"regex",
"reqwest 0.12.22",
"serde",
"serde_json",
"sqlx",
"tap",
"tempfile",
"thiserror 2.0.12",
"time",
"tokio",
"tokio-tungstenite",
"url",
"zeroize",
]
[[package]]
name = "nym-node"
version = "1.17.0"
@@ -6319,10 +6206,8 @@ dependencies = [
"nym-gateway-stats-storage",
"nym-http-api-client",
"nym-http-api-common",
"nym-ip-packet-router",
"nym-metrics",
"nym-mixnet-client",
"nym-network-requester",
"nym-node-metrics",
"nym-node-requests",
"nym-noise",
@@ -8302,15 +8187,6 @@ dependencies = [
"thiserror 1.0.69",
]
[[package]]
name = "psl"
version = "2.1.126"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45f621acfbd2ca5670eee9a95270747dfa9a29e63e1937d7e6a1ac6994331966"
dependencies = [
"psl-types",
]
[[package]]
name = "psl-types"
version = "2.0.11"
@@ -10317,7 +10193,7 @@ dependencies = [
"bip39",
"bs58",
"clap",
"console 0.16.0",
"console",
"cw-utils",
"dkg-bypass-contract",
"humantime",
@@ -11984,7 +11860,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e"
dependencies = [
"windows-link",
"windows-result 0.3.4",
"windows-result",
"windows-strings",
]
-4
View File
@@ -132,8 +132,6 @@ members = [
"sdk/ffi/shared",
"sdk/rust/nym-sdk",
"service-providers/common",
"service-providers/ip-packet-router",
"service-providers/network-requester",
"sqlx-pool-guard",
"tools/echo-server",
"tools/internal/contract-state-importer/importer-cli",
@@ -168,8 +166,6 @@ default-members = [
"nym-statistics-api",
"nym-validator-rewarder",
"nyx-chain-watcher",
"service-providers/ip-packet-router",
"service-providers/network-requester",
"tools/nymvisor",
]
@@ -7,7 +7,7 @@
use serde::{Deserialize, Serialize};
use std::fmt::{Display, Formatter};
#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
pub struct BinaryBuildInformation {
/// Provides the name of the binary, i.e. the content of `CARGO_PKG_NAME` environmental variable.
pub binary_name: &'static str,
@@ -355,10 +355,9 @@ impl SocksClient {
TransmissionLane::ConnectionId(self.connection_id),
self.packet_type,
);
self.input_sender
.send(input_message)
.await
.expect("InputMessageReceiver has stopped receiving!");
if self.input_sender.send(input_message).await.is_err() {
error!("InputMessageReceiver has stopped receiving!")
}
}
async fn send_connect_to_mixnet_with_return_address(&mut self, remote_address: RemoteAddress) {
@@ -378,10 +377,9 @@ impl SocksClient {
TransmissionLane::ConnectionId(self.connection_id),
self.packet_type,
);
self.input_sender
.send(input_message)
.await
.expect("InputMessageReceiver has stopped receiving!");
if self.input_sender.send(input_message).await.is_err() {
error!("InputMessageReceiver has stopped receiving!")
}
}
async fn send_connect_to_mixnet(&mut self, remote_address: RemoteAddress) {
+21 -10
View File
@@ -19,9 +19,9 @@ rust-version = "1.77"
path = "src/lib.rs"
[dependencies]
anyhow = { workspace = true }
bincode = { workspace = true }
async-trait = { workspace = true }
bincode = { workspace = true }
bytes = { workspace = true }
bip39 = { workspace = true }
bs58 = { workspace = true }
dashmap = { workspace = true }
@@ -30,7 +30,6 @@ futures = { workspace = true }
ipnetwork = { workspace = true }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
sha2 = { workspace = true }
thiserror = { workspace = true }
time = { workspace = true }
tokio = { workspace = true, features = [
@@ -49,7 +48,7 @@ zeroize = { workspace = true }
# internal
nym-api-requests = { path = "../nym-api/nym-api-requests" }
nym-bin-common = { path = "../common/bin-common" }
nym-credentials = { path = "../common/credentials" }
nym-credentials-interface = { path = "../common/credentials-interface" }
nym-credential-verification = { path = "../common/credential-verification" }
@@ -58,31 +57,43 @@ nym-gateway-storage = { path = "../common/gateway-storage" }
nym-gateway-stats-storage = { path = "../common/gateway-stats-storage" }
nym-gateway-requests = { path = "../common/gateway-requests" }
nym-mixnet-client = { path = "../common/client-libs/mixnet-client" }
nym-mixnode-common = { path = "../common/mixnode-common" }
nym-network-defaults = { path = "../common/network-defaults" }
nym-network-requester = { path = "../service-providers/network-requester" }
nym-sdk = { path = "../sdk/rust/nym-sdk" }
nym-sphinx = { path = "../common/nymsphinx" }
nym-statistics-common = { path = "../common/statistics" }
nym-task = { path = "../common/task" }
nym-topology = { path = "../common/topology" }
nym-types = { path = "../common/types" }
nym-validator-client = { path = "../common/client-libs/validator-client" }
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-server = { path = "../common/wireguard-private-metadata/server" }
nym-wireguard-types = { path = "../common/wireguard-types", default-features = false }
nym-authenticator-requests = { path = "../common/authenticator-requests" }
nym-client-core = { path = "../common/client-core", features = ["cli"] }
nym-id = { path = "../common/nym-id" }
nym-service-provider-requests-common = { path = "../common/service-provider-requests-common" }
defguard_wireguard_rs = { workspace = true }
nym-service-providers-common = { path = "../service-providers/common" }
# authenticator specific
nym-authenticator-requests = { path = "../common/authenticator-requests" }
# network-requester specific
nym-socks5-proxy-helpers = { path = "../common/socks5/proxy-helpers" }
nym-socks5-requests = { path = "../common/socks5/requests" }
nym-exit-policy = { path = "../common/exit-policy", features = ["client"] }
# ipr specific
nym-ip-packet-requests = { path = "../common/ip-packet-requests" }
etherparse = { workspace = true }
[target.'cfg(target_os = "linux")'.dependencies]
tokio-tun.workspace = true
nym-tun = { path = "../common/tun" }
[dev-dependencies]
nym-gateway-storage = { path = "../common/gateway-storage", features = ["mock"] }
nym-wireguard = { path = "../common/wireguard", features = ["mock"] }
+6 -6
View File
@@ -5,7 +5,7 @@ use std::net::SocketAddr;
use std::time::Duration;
use url::Url;
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Config {
pub gateway: Gateway,
@@ -40,7 +40,7 @@ impl Config {
}
}
#[derive(Debug, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Gateway {
/// Indicates whether this gateway is accepting only zk-nym credentials for accessing the mixnet
/// or if it also accepts non-paying clients
@@ -57,7 +57,7 @@ pub struct Gateway {
pub nyxd_urls: Vec<Url>,
}
#[derive(Debug, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct NetworkRequester {
/// Specifies whether network requester service is enabled in this process.
pub enabled: bool,
@@ -70,7 +70,7 @@ impl Default for NetworkRequester {
}
}
#[derive(Debug, PartialEq)]
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct IpPacketRouter {
/// Specifies whether ip packet router service is enabled in this process.
pub enabled: bool,
@@ -83,7 +83,7 @@ impl Default for IpPacketRouter {
}
}
#[derive(Debug)]
#[derive(Debug, Clone, Copy)]
pub struct Debug {
/// Defines maximum delay between client bandwidth information being flushed to the persistent storage.
pub client_bandwidth_max_flushing_rate: Duration,
@@ -106,7 +106,7 @@ pub struct Debug {
pub max_request_timestamp_skew: Duration,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Copy)]
pub struct ZkNymTicketHandlerDebug {
/// Specifies the multiplier for revoking a malformed/double-spent ticket
/// (if it has to go all the way to the nym-api for verification)
+4 -4
View File
@@ -1,19 +1,19 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
pub use crate::node::client_handling::websocket::connection_handler::authenticated::RequestHandlingError;
use crate::node::internal_service_providers::authenticator::error::AuthenticatorError;
use crate::node::internal_service_providers::network_requester::error::NetworkRequesterError;
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
use nym_client_core::error::ClientCoreError;
use nym_gateway_stats_storage::error::StatsStorageError;
use nym_gateway_storage::error::GatewayStorageError;
use nym_ip_packet_router::error::IpPacketRouterError;
use nym_network_requester::error::{ClientCoreError, NetworkRequesterError};
use nym_validator_client::nyxd::error::NyxdError;
use nym_validator_client::nyxd::{AccountId, Coin};
use nym_validator_client::ValidatorClientError;
use std::net::IpAddr;
use thiserror::Error;
pub use crate::node::client_handling::websocket::connection_handler::authenticated::RequestHandlingError;
#[derive(Debug, Error)]
pub enum GatewayError {
#[error("the configured version of the gateway ({config_version}) is incompatible with the binary version ({binary_version})")]
+2
View File
@@ -11,4 +11,6 @@ pub mod node;
pub use error::GatewayError;
pub use node::GatewayTasksBuilder;
pub use node::internal_service_providers as service_providers;
pub use node::internal_service_providers::authenticator as nym_authenticator;
pub use node::internal_service_providers::network_requester as nym_network_requester;
@@ -5,7 +5,7 @@ use crate::node::client_handling::websocket::message_receiver::{
MixMessageReceiver, MixMessageSender,
};
use futures::StreamExt;
use nym_network_requester::{GatewayPacketRouter, PacketRouter};
use nym_client_core::client::mix_traffic::transceiver::{GatewayPacketRouter, PacketRouter};
use nym_sphinx::addressing::clients::Recipient;
use nym_sphinx::DestinationAddressBytes;
use nym_task::TaskClient;
@@ -1,11 +1,9 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use std::fmt;
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
use nym_sdk::mixnet::{AnonymousSenderTag, Recipient};
use crate::error::{IpPacketRouterError, Result};
use std::fmt;
#[derive(Clone, Debug, PartialEq, Eq)]
pub(crate) enum ConnectedClientId {
@@ -14,7 +12,7 @@ pub(crate) enum ConnectedClientId {
}
impl ConnectedClientId {
pub(crate) fn into_nym_address(self) -> Result<Recipient> {
pub(crate) fn into_nym_address(self) -> Result<Recipient, IpPacketRouterError> {
match self {
ConnectedClientId::NymAddress(nym_address) => Ok(*nym_address),
ConnectedClientId::AnonymousSenderTag(_) => Err(IpPacketRouterError::InvalidReplyTo),
@@ -1,8 +1,11 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use std::time::Duration;
use crate::service_providers::ip_packet_router::{
clients::ConnectedClientId, constants::CLIENT_HANDLER_ACTIVITY_TIMEOUT,
error::IpPacketRouterError, messages::ClientVersion,
util::create_message::create_input_message,
};
use bytes::{Bytes, BytesMut};
use nym_ip_packet_requests::{
codec::{IprPacket, MultiIpPacketCodec},
@@ -13,19 +16,13 @@ use nym_ip_packet_requests::{
use nym_sdk::mixnet::{
InputMessage, MixnetClientSender, MixnetMessageSender, MixnetMessageSinkTranslator,
};
use std::time::Duration;
use tokio::{
sync::{mpsc, oneshot},
time::{interval, Interval},
};
use tokio_util::codec::Encoder;
use crate::{
clients::ConnectedClientId,
constants::CLIENT_HANDLER_ACTIVITY_TIMEOUT,
error::{IpPacketRouterError, Result},
messages::ClientVersion,
};
// Data flow
// Out: mixnet_listener -> decode -> handle_packet -> write_to_tun
// In: tun_listener -> [connected_client_handler -> encode] -> mixnet_sender
@@ -69,8 +66,8 @@ impl ConnectedClientHandler {
oneshot::Sender<()>,
tokio::task::JoinHandle<()>,
) {
log::debug!("Starting connected client handler for: {client_id}");
log::debug!("client version: {client_version:?}");
tracing::debug!("Starting connected client handler for: {client_id}");
tracing::debug!("client version: {client_version:?}");
let (close_tx, close_rx) = oneshot::channel();
let (forward_from_tun_tx, forward_from_tun_rx) = mpsc::unbounded_channel();
@@ -101,14 +98,14 @@ impl ConnectedClientHandler {
let handle = tokio::spawn(async move {
if let Err(err) = connected_client_handler.run().await {
log::error!("connected client handler has failed: {err}")
tracing::error!("connected client handler has failed: {err}")
}
});
(forward_from_tun_tx, close_tx, handle)
}
fn bundle_packet(&mut self, packet: IprPacket) -> Result<Option<Bytes>> {
fn bundle_packet(&mut self, packet: IprPacket) -> Result<Option<Bytes>, IpPacketRouterError> {
let mut bundled_packets = BytesMut::new();
self.packet_bundler
.encode(packet, &mut bundled_packets)
@@ -120,7 +117,7 @@ impl ConnectedClientHandler {
}
}
async fn handle_packet(&mut self, packet: IprPacket) -> Result<()> {
async fn handle_packet(&mut self, packet: IprPacket) -> Result<(), IpPacketRouterError> {
self.activity_timeout.reset();
let bundled_packets = match self.bundle_packet(packet)? {
@@ -145,37 +142,37 @@ impl ConnectedClientHandler {
})
}
async fn run(mut self) -> Result<()> {
async fn run(mut self) -> Result<(), IpPacketRouterError> {
loop {
tokio::select! {
_ = &mut self.close_rx => {
log::info!("client handler stopping: received close: {}", self.sent_by);
tracing::info!("client handler stopping: received close: {}", self.sent_by);
break;
},
_ = self.activity_timeout.tick() => {
log::info!("client handler stopping: activity timeout: {}", self.sent_by);
tracing::info!("client handler stopping: activity timeout: {}", self.sent_by);
break;
},
_ = self.payload_topup_interval.tick() => {
if let Err(err) = self.handle_packet(IprPacket::Flush).await {
log::error!("client handler: failed to handle packet: {err}");
tracing::error!("client handler: failed to handle packet: {err}");
}
},
packet = self.forward_from_tun_rx.recv() => match packet {
Some(packet) => {
if let Err(err) = self.handle_packet(IprPacket::from(packet)).await {
log::error!("client handler: failed to handle packet: {err}");
tracing::error!("client handler: failed to handle packet: {err}");
}
},
None => {
log::info!("client handler stopping: tun channel closed");
tracing::info!("client handler stopping: tun channel closed");
break;
}
},
}
}
log::debug!("ConnectedClientHandler: exiting");
tracing::debug!("ConnectedClientHandler: exiting");
Ok(())
}
}
@@ -210,8 +207,7 @@ impl MixnetMessageSinkTranslator for ToIprDataResponse {
// Wrap the response packet in a mixnet input message
let input_message =
crate::util::create_message::create_input_message(&self.send_to, response_packet)
.with_max_retransmissions(0);
create_input_message(&self.send_to, response_packet).with_max_retransmissions(0);
Ok(input_message)
}
@@ -1,24 +1,20 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use super::ConnectedClientId;
use crate::service_providers::ip_packet_router::{
constants::CLIENT_MIXNET_INACTIVITY_TIMEOUT, error::IpPacketRouterError, tun_listener,
util::generate_new_ip,
};
use nym_ip_packet_requests::IpPair;
use std::{
collections::HashMap,
net::{IpAddr, Ipv4Addr, Ipv6Addr},
sync::Arc,
time::Instant,
};
use nym_ip_packet_requests::IpPair;
use tokio::sync::{mpsc, oneshot, RwLock};
use crate::{
constants::CLIENT_MIXNET_INACTIVITY_TIMEOUT,
error::{IpPacketRouterError, Result},
tun_listener,
};
use super::ConnectedClientId;
pub(crate) struct ConnectedClients {
// The set of connected clients
clients_ipv4_mapping: HashMap<Ipv4Addr, ConnectedClient>,
@@ -61,7 +57,7 @@ impl ConnectedClients {
pub(crate) fn disconnect_client(&mut self, client_id: &ConnectedClientId) {
if let Some(ips) = self.lookup_ip_from_client_id(client_id) {
log::debug!("Disconnect client that requested to do so: {ips}");
tracing::debug!("Disconnect client that requested to do so: {ips}");
self.disconnect_client_handle(ips);
}
}
@@ -72,7 +68,7 @@ impl ConnectedClients {
self.tun_listener_connected_client_tx
.send(ConnectedClientEvent::Disconnect(DisconnectEvent(ips)))
.inspect_err(|err| {
log::error!("Failed to send disconnect event: {err}");
tracing::error!("Failed to send disconnect event: {err}");
})
.ok();
}
@@ -117,7 +113,7 @@ impl ConnectedClients {
handle: Arc::new(handle),
};
log::info!("Inserting {} and {}", ips.ipv4, ips.ipv6);
tracing::info!("Inserting {} and {}", ips.ipv4, ips.ipv6);
self.clients_ipv4_mapping.insert(ips.ipv4, client.clone());
self.clients_ipv6_mapping.insert(ips.ipv6, client);
@@ -129,12 +125,15 @@ impl ConnectedClients {
forward_from_tun_tx,
})))
.inspect_err(|err| {
log::error!("Failed to send connected client event: {err}");
tracing::error!("Failed to send connected client event: {err}");
})
.ok();
}
pub(crate) async fn update_activity(&mut self, ips: &IpPair) -> Result<()> {
pub(crate) async fn update_activity(
&mut self,
ips: &IpPair,
) -> Result<(), IpPacketRouterError> {
if let Some(client) = self.clients_ipv4_mapping.get(&ips.ipv4) {
*client.last_activity.write().await = Instant::now();
Ok(())
@@ -181,7 +180,7 @@ impl ConnectedClients {
stopped_clients: Vec<(IpPair, ConnectedClientId)>,
) {
for (ips, _) in &stopped_clients {
log::info!("Disconnect stopped client: {ips}");
tracing::info!("Disconnect stopped client: {ips}");
self.disconnect_client_handle(*ips);
}
}
@@ -191,16 +190,13 @@ impl ConnectedClients {
inactive_clients: Vec<(IpPair, ConnectedClientId)>,
) {
for (ips, _) in &inactive_clients {
log::info!("Disconnect inactive client: {ips}");
tracing::info!("Disconnect inactive client: {ips}");
self.disconnect_client_handle(*ips);
}
}
pub(crate) fn find_new_ip(&self) -> Option<IpPair> {
crate::util::generate_new_ip::find_new_ips(
&self.clients_ipv4_mapping,
&self.clients_ipv6_mapping,
)
generate_new_ip::find_new_ips(&self.clients_ipv4_mapping, &self.clients_ipv6_mapping)
}
}
@@ -242,7 +238,7 @@ impl ConnectedClient {
impl Drop for CloseTx {
fn drop(&mut self) {
log::debug!("signal to close client: {}", self.client_id);
tracing::debug!("signal to close client: {}", self.client_id);
if let Some(close_tx) = self.inner.take() {
close_tx.send(()).ok();
}
@@ -0,0 +1,54 @@
use nym_bin_common::logging::LoggingSettings;
use nym_network_defaults::mainnet;
use url::Url;
mod persistence;
pub use crate::service_providers::ip_packet_router::config::persistence::IpPacketRouterPaths;
pub use nym_client_core::config::Config as BaseClientConfig;
#[derive(Debug, Clone, PartialEq)]
pub struct Config {
pub base: BaseClientConfig,
pub ip_packet_router: IpPacketRouter,
pub storage_paths: IpPacketRouterPaths,
pub logging: LoggingSettings,
}
impl Config {
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()
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct IpPacketRouter {
/// Disable Poisson sending rate.
pub disable_poisson_rate: bool,
/// Specifies the url for an upstream source of the exit policy used by this node.
pub upstream_exit_policy_url: Option<Url>,
}
impl Default for IpPacketRouter {
fn default() -> Self {
IpPacketRouter {
disable_poisson_rate: true,
#[allow(clippy::expect_used)]
upstream_exit_policy_url: Some(
mainnet::EXIT_POLICY_URL
.parse()
.expect("invalid default exit policy URL"),
),
}
}
}
@@ -1,5 +1,5 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
// SPDX-License-Identifier: Apache-2.0
use std::net::SocketAddr;
@@ -75,12 +75,6 @@ pub enum IpPacketRouterError {
source: PolicyError,
},
#[error("the url provided for the upstream exit policy source is malformed: {source}")]
MalformedExitPolicyUpstreamUrl {
#[source]
source: reqwest::Error,
},
#[error("can't setup an exit policy without any upstream urls")]
NoUpstreamExitPolicy,
@@ -117,5 +111,3 @@ pub enum IpPacketRouterError {
#[error("failed to deserialize protocol: {source}")]
FailedToDeserializeProtocol { source: ProtocolError },
}
pub type Result<T> = std::result::Result<T, IpPacketRouterError>;
@@ -5,6 +5,9 @@ mod v6;
mod v7;
mod v8;
use super::ClientVersion;
use crate::service_providers::ip_packet_router::clients::ConnectedClientId;
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
use nym_ip_packet_requests::{
v6::request::IpPacketRequest as IpPacketRequestV6,
v7::request::IpPacketRequest as IpPacketRequestV7,
@@ -14,10 +17,6 @@ use nym_sdk::mixnet::ReconstructedMessage;
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use std::fmt;
use crate::{clients::ConnectedClientId, error::IpPacketRouterError};
use super::ClientVersion;
// The internal representation of the request after deserialization, valid for all versions
#[derive(Clone, Debug, PartialEq)]
pub(crate) enum IpPacketRequest {
@@ -130,7 +129,7 @@ impl TryFrom<&ReconstructedMessage> for IpPacketRequest {
Ok(IpPacketRequest::from((request_v8, sender_tag)))
}
_ => {
log::info!("Received packet with invalid version: v{request_version}");
tracing::info!("Received packet with invalid version: v{request_version}");
Err(IpPacketRouterError::InvalidPacketVersion(request_version))
}
}
@@ -12,12 +12,9 @@ use nym_ip_packet_requests::{
v8::response::IpPacketResponse as IpPacketResponseV8, IpPair,
};
use crate::{
clients::ConnectedClientId,
error::{IpPacketRouterError, Result},
};
use super::ClientVersion;
use crate::service_providers::ip_packet_router::clients::ConnectedClientId;
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
pub(crate) struct VersionedResponse {
pub(crate) version: ClientVersion,
@@ -124,7 +121,7 @@ pub(crate) struct HealthResponse {
}
impl VersionedResponse {
pub(crate) fn try_into_bytes(self) -> Result<Vec<u8>> {
pub(crate) fn try_into_bytes(self) -> Result<Vec<u8>, IpPacketRouterError> {
match self.version {
ClientVersion::V6 => IpPacketResponseV6::try_from(self)?.to_bytes(),
ClientVersion::V7 => IpPacketResponseV7::try_from(self)?.to_bytes(),
@@ -1,6 +1,12 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use super::{
DisconnectFailureReason, DisconnectResponse, DynamicConnectFailureReason,
DynamicConnectResponse, DynamicConnectSuccess, HealthResponse, InfoLevel, InfoResponseReply,
Response, StaticConnectFailureReason, StaticConnectResponse, VersionedResponse,
};
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
use nym_ip_packet_requests::v6::response::{
DisconnectFailureReason as DisconnectFailureReasonV6,
DisconnectResponse as DisconnectResponseV6,
@@ -17,14 +23,6 @@ use nym_ip_packet_requests::v6::response::{
StaticConnectResponseReply as StaticConnectResponseReplyV6,
};
use crate::error::IpPacketRouterError;
use super::{
DisconnectFailureReason, DisconnectResponse, DynamicConnectFailureReason,
DynamicConnectResponse, DynamicConnectSuccess, HealthResponse, InfoLevel, InfoResponseReply,
Response, StaticConnectFailureReason, StaticConnectResponse, VersionedResponse,
};
impl TryFrom<VersionedResponse> for IpPacketResponseV6 {
type Error = IpPacketRouterError;
@@ -1,6 +1,12 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use super::{
DisconnectFailureReason, DisconnectResponse, DynamicConnectFailureReason,
DynamicConnectResponse, DynamicConnectSuccess, HealthResponse, InfoLevel, InfoResponseReply,
Response, StaticConnectFailureReason, StaticConnectResponse, VersionedResponse,
};
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
use nym_ip_packet_requests::v7::response::{
DisconnectFailureReason as DisconnectFailureReasonV7,
DisconnectResponse as DisconnectResponseV7,
@@ -17,14 +23,6 @@ use nym_ip_packet_requests::v7::response::{
StaticConnectResponseReply as StaticConnectResponseReplyV7,
};
use crate::error::IpPacketRouterError;
use super::{
DisconnectFailureReason, DisconnectResponse, DynamicConnectFailureReason,
DynamicConnectResponse, DynamicConnectSuccess, HealthResponse, InfoLevel, InfoResponseReply,
Response, StaticConnectFailureReason, StaticConnectResponse, VersionedResponse,
};
impl TryFrom<VersionedResponse> for IpPacketResponseV7 {
type Error = IpPacketRouterError;
@@ -1,6 +1,12 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use super::{
DisconnectFailureReason, DisconnectResponse, DynamicConnectFailureReason,
DynamicConnectResponse, DynamicConnectSuccess, HealthResponse, InfoLevel, InfoResponseReply,
Response, VersionedResponse,
};
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
use nym_ip_packet_requests::v8::response::{
ConnectFailureReason as ConnectFailureReasonV8, ConnectResponse as ConnectResponseV8,
ConnectResponseReply as ConnectResponseReplyV8, ConnectSuccess as ConnectSuccessV8,
@@ -13,14 +19,6 @@ use nym_ip_packet_requests::v8::response::{
PongResponse as PongResponseV8,
};
use crate::error::IpPacketRouterError;
use super::{
DisconnectFailureReason, DisconnectResponse, DynamicConnectFailureReason,
DynamicConnectResponse, DynamicConnectSuccess, HealthResponse, InfoLevel, InfoResponseReply,
Response, VersionedResponse,
};
impl TryFrom<VersionedResponse> for IpPacketResponseV8 {
type Error = IpPacketRouterError;
@@ -5,7 +5,9 @@ use nym_client_core::{config::disk_persistence::CommonClientPaths, TopologyProvi
use nym_sdk::{GatewayTransceiver, NymNetworkDetails};
use nym_task::TaskClient;
use crate::{config::BaseClientConfig, error::IpPacketRouterError};
use crate::service_providers::ip_packet_router::{
config::BaseClientConfig, error::IpPacketRouterError,
};
// Helper function to create the mixnet client.
// This is NOT in the SDK since we don't want to expose any of the client-core config types.
@@ -1,5 +1,5 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
// SPDX-License-Identifier: Apache-2.0
use futures::StreamExt;
use nym_ip_packet_requests::codec::MultiIpPacketCodec;
@@ -10,11 +10,11 @@ use std::{net::SocketAddr, time::Duration};
use tokio::io::AsyncWriteExt;
use tokio_util::codec::FramedRead;
use crate::{
use crate::service_providers::ip_packet_router::{
clients::{ConnectedClientHandler, ConnectedClients},
config::Config,
constants::DISCONNECT_TIMER_INTERVAL,
error::{IpPacketRouterError, Result},
error::IpPacketRouterError,
messages::{
request::{
ControlRequest, DataRequest, DisconnectRequest, DynamicConnectRequest, HealthRequest,
@@ -28,11 +28,14 @@ use crate::{
ClientVersion,
},
request_filter::RequestFilter,
util::parse_ip::ParsedPacket,
util::{
create_message::create_input_message,
parse_ip::{parse_packet, ParsedPacket},
},
};
#[cfg(not(target_os = "linux"))]
type TunDevice = crate::non_linux_dummy::DummyDevice;
type TunDevice = crate::service_providers::ip_packet_router::non_linux_dummy::DummyDevice;
#[cfg(target_os = "linux")]
type TunDevice = tokio_tun::Tun;
@@ -66,7 +69,7 @@ impl MixnetListener {
ip_packet: &[u8],
version: ClientVersion,
) -> PacketHandleResult {
log::trace!("Received data request");
tracing::trace!("Received data request");
// We don't forward packets that we are not able to parse. BUT, there might be a good
// reason to still forward them.
@@ -77,10 +80,10 @@ impl MixnetListener {
src_addr,
dst_addr,
dst,
} = crate::util::parse_ip::parse_packet(ip_packet)?;
} = parse_packet(ip_packet)?;
let dst_str = dst.map_or(dst_addr.to_string(), |dst| dst.to_string());
log::debug!("Received packet: {packet_type}: {src_addr} -> {dst_str}");
tracing::debug!("Received packet: {packet_type}: {src_addr} -> {dst_str}");
if let Some(connected_client) = self.connected_clients.get_client_from_ip_mut(&src_addr) {
// Keep track of activity so we can disconnect inactive clients
@@ -98,7 +101,7 @@ impl MixnetListener {
.map_err(|_| IpPacketRouterError::FailedToWritePacketToTun)?;
Ok(None)
} else {
log::debug!("Denied filter check: {dst}");
tracing::debug!("Denied filter check: {dst}");
Ok(Some(VersionedResponse {
version,
reply_to: connected_client.client_id.clone(),
@@ -115,7 +118,7 @@ impl MixnetListener {
}
} else {
// If the client is not connected, just drop the packet silently
log::debug!("dropping packet from mixnet: no registered client for packet with source: {src_addr}");
tracing::debug!("dropping packet from mixnet: no registered client for packet with source: {src_addr}");
Ok(None)
}
}
@@ -123,7 +126,7 @@ impl MixnetListener {
async fn on_data_request(
&mut self,
data_request: DataRequest,
) -> Result<Vec<PacketHandleResult>> {
) -> Result<Vec<PacketHandleResult>, IpPacketRouterError> {
let mut responses = Vec::new();
let decoder = MultiIpPacketCodec::new();
let mut framed_reader = FramedRead::new(data_request.ip_packets.as_ref(), decoder);
@@ -144,7 +147,7 @@ impl MixnetListener {
&mut self,
connect_request: StaticConnectRequest,
) -> PacketHandleResult {
log::info!(
tracing::info!(
"Received static connect request from {}",
connect_request.sent_by
);
@@ -166,14 +169,14 @@ impl MixnetListener {
let response = match (is_ip_taken, is_client_id_taken) {
(true, true) => {
log::info!("Connecting an already connected client");
tracing::info!("Connecting an already connected client");
if self
.connected_clients
.update_activity(&requested_ips)
.await
.is_err()
{
log::error!("Failed to update activity for client");
tracing::error!("Failed to update activity for client");
};
Response::StaticConnect {
request_id,
@@ -181,7 +184,7 @@ impl MixnetListener {
}
}
(false, false) => {
log::info!("Connecting a new client");
tracing::info!("Connecting a new client");
// Spawn the ConnectedClientHandler for the new client
let (forward_from_tun_tx, close_tx, handle) = ConnectedClientHandler::start(
@@ -205,14 +208,14 @@ impl MixnetListener {
}
}
(true, false) => {
log::info!("Requested IP is not available");
tracing::info!("Requested IP is not available");
Response::StaticConnect {
request_id,
reply: StaticConnectFailureReason::RequestedIpAlreadyInUse.into(),
}
}
(false, true) => {
log::info!("Nym address is already registered");
tracing::info!("Nym address is already registered");
Response::StaticConnect {
request_id,
reply: StaticConnectFailureReason::ClientAlreadyConnected.into(),
@@ -231,7 +234,7 @@ impl MixnetListener {
&mut self,
connect_request: DynamicConnectRequest,
) -> PacketHandleResult {
log::info!(
tracing::info!(
"Received dynamic connect request from {}",
connect_request.sent_by
);
@@ -245,7 +248,7 @@ impl MixnetListener {
.unwrap_or(nym_ip_packet_requests::codec::BUFFER_TIMEOUT);
if let Some(ips) = self.connected_clients.lookup_ip_from_client_id(&reply_to) {
log::debug!("Reconnecting to the previous session");
tracing::debug!("Reconnecting to the previous session");
return Ok(Some(VersionedResponse {
version,
reply_to,
@@ -257,7 +260,7 @@ impl MixnetListener {
}
let Some(new_ips) = self.connected_clients.find_new_ip() else {
log::info!("No available IP address");
tracing::info!("No available IP address");
return Ok(Some(VersionedResponse {
version,
reply_to,
@@ -299,7 +302,7 @@ impl MixnetListener {
&mut self,
disconnect_request: DisconnectRequest,
) -> PacketHandleResult {
log::info!(
tracing::info!(
"Received disconnect request from {}",
disconnect_request.sent_by
);
@@ -310,7 +313,7 @@ impl MixnetListener {
// Check if the client is connected
if !self.connected_clients.is_client_connected(&client_id) {
log::info!("Client {client_id} is not connected, cannot disconnect");
tracing::info!("Client {client_id} is not connected, cannot disconnect");
return Ok(Some(VersionedResponse {
version,
reply_to: client_id,
@@ -322,7 +325,7 @@ impl MixnetListener {
}
// Disconnect the client
log::info!("Disconnecting client {client_id}");
tracing::info!("Disconnecting client {client_id}");
self.connected_clients.disconnect_client(&client_id);
Ok(Some(VersionedResponse {
@@ -383,8 +386,8 @@ impl MixnetListener {
async fn on_reconstructed_message(
&mut self,
reconstructed: ReconstructedMessage,
) -> Result<Vec<PacketHandleResult>> {
log::debug!(
) -> Result<Vec<PacketHandleResult>, IpPacketRouterError> {
tracing::debug!(
"Received message with sender_tag: {}",
reconstructed
.sender_tag
@@ -395,13 +398,13 @@ impl MixnetListener {
// First deserialize the request
let request = match IpPacketRequest::try_from(&reconstructed) {
Err(IpPacketRouterError::InvalidPacketVersion(version)) => {
log::debug!("Received packet with invalid version: v{version}");
tracing::debug!("Received packet with invalid version: v{version}");
return Ok(vec![self.on_version_mismatch(version, &reconstructed)]);
}
req => req,
}?;
log::debug!("Received request: {request}");
tracing::debug!("Received request: {request}");
match request {
IpPacketRequest::Data(request) => self.on_data_request(request).await,
@@ -417,7 +420,7 @@ impl MixnetListener {
//for (ip, nym_address) in stopped_clients.iter().chain(disconnected_clients.iter()) {
// let response = IpPacketResponse::new_unrequested_disconnect(...)
// if let Err(err) = self.handle_response(response).await {
// log::error!("Failed to send disconnect response: {err}");
// tracing::error!("Failed to send disconnect response: {err}");
// }
//}
@@ -429,11 +432,13 @@ impl MixnetListener {
// When an incoming mixnet message triggers a response that we send back, such as during
// connect handshake.
async fn handle_response(&self, response: VersionedResponse) -> Result<()> {
async fn handle_response(
&self,
response: VersionedResponse,
) -> Result<(), IpPacketRouterError> {
let send_to = response.reply_to.clone();
let response_bytes = response.try_into_bytes()?;
let input_message =
crate::util::create_message::create_input_message(&send_to, response_bytes);
let input_message = create_input_message(&send_to, response_bytes);
self.mixnet_client.send(input_message).await.map_err(|err| {
IpPacketRouterError::FailedToSendPacketToMixnet {
@@ -449,27 +454,27 @@ impl MixnetListener {
match response {
Ok(Some(response)) => {
if let Err(err) = self.handle_response(response).await {
log::error!("Mixnet listener failed to handle response: {err}");
tracing::error!("Mixnet listener failed to handle response: {err}");
}
}
Ok(None) => {
continue;
}
Err(err) => {
log::error!("Error handling mixnet message: {err}");
tracing::error!("Error handling mixnet message: {err}");
}
}
}
}
pub(crate) async fn run(mut self) -> Result<()> {
pub(crate) async fn run(mut self) -> Result<(), IpPacketRouterError> {
let mut task_client = self.task_handle.fork("main_loop");
let mut disconnect_timer = tokio::time::interval(DISCONNECT_TIMER_INTERVAL);
while !task_client.is_shutdown() {
tokio::select! {
_ = task_client.recv() => {
log::debug!("IpPacketRouter [main loop]: received shutdown");
tracing::debug!("IpPacketRouter [main loop]: received shutdown");
},
_ = disconnect_timer.tick() => {
self.handle_disconnect_timer().await;
@@ -479,21 +484,21 @@ impl MixnetListener {
match self.on_reconstructed_message(msg).await {
Ok(responses) => self.handle_responses(responses).await,
Err(err) => {
log::error!("Error handling reconstructed mixnet message: {err}");
tracing::error!("Error handling reconstructed mixnet message: {err}");
}
};
} else {
log::trace!("IpPacketRouter [main loop]: stopping since channel closed");
tracing::trace!("IpPacketRouter [main loop]: stopping since channel closed");
break;
};
},
}
}
log::debug!("IpPacketRouter: stopping");
tracing::debug!("IpPacketRouter: stopping");
Ok(())
}
}
pub(crate) type PacketHandleResult = Result<Option<VersionedResponse>>;
pub(crate) type PacketHandleResult = Result<Option<VersionedResponse>, IpPacketRouterError>;
@@ -4,8 +4,9 @@
#![cfg_attr(not(target_os = "linux"), allow(dead_code))]
#![cfg_attr(not(target_os = "linux"), allow(unused_imports))]
use std::path::Path;
use crate::node::internal_service_providers::ip_packet_router::{
error::IpPacketRouterError, request_filter::RequestFilter,
};
use futures::channel::oneshot;
use nym_client_core::{
client::mix_traffic::transceiver::GatewayTransceiver, HardcodedTopologyProvider,
@@ -13,8 +14,23 @@ use nym_client_core::{
};
use nym_sdk::mixnet::Recipient;
use nym_task::{TaskClient, TaskHandle};
use std::path::Path;
use crate::{config::Config, error::IpPacketRouterError, request_filter::RequestFilter};
pub mod config;
pub mod error;
pub mod request_filter;
pub(crate) mod messages;
pub(crate) mod non_linux_dummy;
mod clients;
mod constants;
mod mixnet_client;
mod mixnet_listener;
mod tun_listener;
mod util;
pub use config::Config;
pub struct OnStartData {
// to add more fields as required
@@ -115,7 +131,9 @@ impl IpPacketRouter {
pub async fn run_service_provider(self) -> Result<(), IpPacketRouterError> {
// for debugging purposes, don't crash in debug builds on non-linux platforms
if cfg!(debug_assertions) {
log::error!("ip packet router service provider is not yet supported on this platform");
tracing::error!(
"ip packet router service provider is not yet supported on this platform"
);
Ok(())
} else {
todo!("service provider is not yet supported on this platform")
@@ -126,14 +144,14 @@ impl IpPacketRouter {
pub async fn run_service_provider(self) -> Result<(), IpPacketRouterError> {
// Used to notify tasks to shutdown. Not all tasks fully supports this (yet).
use crate::{
use crate::service_providers::ip_packet_router::{
clients::ConnectedClients, mixnet_listener::MixnetListener,
request_filter::RequestFilter, tun_listener::TunListener,
};
let task_handle: TaskHandle = self.shutdown.map(Into::into).unwrap_or_default();
// Connect to the mixnet
let mixnet_client = crate::mixnet_client::create_mixnet_client(
let mixnet_client = mixnet_client::create_mixnet_client(
&self.config.base,
task_handle.get_handle().named("nym_sdk::MixnetClient[IPR]"),
self.custom_gateway_transceiver,
@@ -180,8 +198,8 @@ impl IpPacketRouter {
connected_clients,
};
log::info!("The address of this client is: {self_address}");
log::info!("All systems go. Press CTRL-C to stop the server.");
tracing::info!("The address of this client is: {self_address}");
tracing::info!("All systems go. Press CTRL-C to stop the server.");
if let Some(on_start) = self.on_start {
if on_start
@@ -1,12 +1,10 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use std::net::SocketAddr;
use crate::error::IpPacketRouterError;
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
use nym_exit_policy::client::get_exit_policy;
use nym_exit_policy::ExitPolicy;
use reqwest::IntoUrl;
use std::net::SocketAddr;
use url::Url;
pub struct ExitPolicyRequestFilter {
@@ -16,11 +14,7 @@ pub struct ExitPolicyRequestFilter {
}
impl ExitPolicyRequestFilter {
pub(crate) async fn new_upstream(url: impl IntoUrl) -> Result<Self, IpPacketRouterError> {
let url = url
.into_url()
.map_err(|source| IpPacketRouterError::MalformedExitPolicyUpstreamUrl { source })?;
pub(crate) async fn new_upstream(url: Url) -> Result<Self, IpPacketRouterError> {
Ok(ExitPolicyRequestFilter {
upstream: Some(url.clone()),
policy: get_exit_policy(url).await?,
@@ -1,11 +1,11 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::config::Config;
use crate::error::IpPacketRouterError;
use crate::request_filter::exit_policy::ExitPolicyRequestFilter;
use log::{info, warn};
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
use crate::service_providers::ip_packet_router::request_filter::exit_policy::ExitPolicyRequestFilter;
use crate::service_providers::ip_packet_router::Config;
use std::{net::SocketAddr, sync::Arc};
use tracing::{info, warn};
pub mod exit_policy;
@@ -1,17 +1,17 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
// SPDX-License-Identifier: Apache-2.0
use nym_ip_packet_requests::IpPair;
use nym_task::TaskClient;
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
#[cfg(target_os = "linux")]
use tokio::io::AsyncReadExt;
use tokio::sync::mpsc;
use crate::clients::{ConnectEvent, ConnectedClientEvent, DisconnectEvent};
use crate::{error::Result, util::parse_ip::parse_dst_addr};
use crate::node::internal_service_providers::ip_packet_router::clients::{
ConnectEvent, ConnectedClientEvent, DisconnectEvent,
};
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
// The TUN listener keeps a local map of the connected clients that has its state updated by the
// mixnet listener. Basically it's just so that we don't have to have mutexes around shared state.
@@ -50,7 +50,7 @@ impl ConnectedClientsListener {
ips,
forward_from_tun_tx,
} = *connected_event;
log::trace!("Connect client: {ips}");
tracing::trace!("Connect client: {ips}");
self.clients_ipv4.insert(
ips.ipv4,
ConnectedClientMirror {
@@ -67,7 +67,7 @@ impl ConnectedClientsListener {
);
}
ConnectedClientEvent::Disconnect(DisconnectEvent(ips)) => {
log::trace!("Disconnect client: {ips}");
tracing::trace!("Disconnect client: {ips}");
self.clients_ipv4.remove(&ips.ipv4);
self.clients_ipv6.remove(&ips.ipv6);
}
@@ -79,15 +79,17 @@ impl ConnectedClientsListener {
#[cfg(target_os = "linux")]
pub(crate) struct TunListener {
pub(crate) tun_reader: tokio::io::ReadHalf<tokio_tun::Tun>,
pub(crate) task_client: TaskClient,
pub(crate) task_client: nym_task::TaskClient,
pub(crate) connected_clients: ConnectedClientsListener,
}
#[cfg(target_os = "linux")]
impl TunListener {
async fn handle_packet(&mut self, buf: &[u8], len: usize) -> Result<()> {
let Some(dst_addr) = parse_dst_addr(&buf[..len]) else {
log::warn!("Failed to parse packet");
async fn handle_packet(&mut self, buf: &[u8], len: usize) -> Result<(), IpPacketRouterError> {
let Some(dst_addr) =
crate::service_providers::ip_packet_router::util::parse_ip::parse_dst_addr(&buf[..len])
else {
tracing::warn!("Failed to parse packet");
return Ok(());
};
@@ -98,12 +100,12 @@ impl TunListener {
{
let packet = buf[..len].to_vec();
if forward_from_tun_tx.send(packet).is_err() {
log::warn!("Failed to forward packet to connected client {dst_addr}: disconnecting it from tun listener");
tracing::warn!("Failed to forward packet to connected client {dst_addr}: disconnecting it from tun listener");
self.connected_clients
.update(ConnectedClientEvent::Disconnect(DisconnectEvent(*ips)));
}
} else {
log::debug!(
tracing::debug!(
"dropping packet from network: no registered client for destination: {dst_addr}"
);
}
@@ -111,42 +113,42 @@ impl TunListener {
Ok(())
}
async fn run(mut self) -> Result<()> {
async fn run(mut self) -> Result<(), IpPacketRouterError> {
let mut buf = [0u8; 65535];
while !self.task_client.is_shutdown() {
tokio::select! {
_ = self.task_client.recv() => {
log::trace!("TunListener: received shutdown");
tracing::trace!("TunListener: received shutdown");
},
// TODO: ConnectedClientsListener::update should poll the channel instead
event = self.connected_clients.connected_client_rx.recv() => match event {
Some(event) => self.connected_clients.update(event),
None => {
log::error!("TunListener: connected client channel closed");
tracing::error!("TunListener: connected client channel closed");
break;
},
},
len = self.tun_reader.read(&mut buf) => match len {
Ok(len) => {
if let Err(err) = self.handle_packet(&buf, len).await {
log::error!("tun: failed to handle packet: {err}");
tracing::error!("tun: failed to handle packet: {err}");
}
},
Err(err) => {
log::warn!("iface: read error: {err}");
tracing::warn!("iface: read error: {err}");
// break;
}
}
}
}
log::debug!("TunListener: stopping");
tracing::debug!("TunListener: stopping");
Ok(())
}
pub(crate) fn start(self) {
tokio::spawn(async move {
if let Err(err) = self.run().await {
log::error!("tun listener router has failed: {err}")
tracing::error!("tun listener router has failed: {err}")
}
});
}
@@ -1,8 +1,7 @@
use crate::service_providers::ip_packet_router::clients::ConnectedClientId;
use nym_sdk::mixnet::InputMessage;
use nym_task::connections::TransmissionLane;
use crate::clients::ConnectedClientId;
pub(crate) fn create_input_message(
recipient: &ConnectedClientId,
response_packet: Vec<u8>,
@@ -1,7 +1,6 @@
use crate::service_providers::ip_packet_router::error::IpPacketRouterError;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use crate::error::IpPacketRouterError;
pub(crate) struct ParsedPacket<'a> {
pub(crate) packet_type: &'a str,
pub(crate) src_addr: IpAddr,
@@ -11,7 +10,7 @@ pub(crate) struct ParsedPacket<'a> {
pub(crate) fn parse_packet(packet: &[u8]) -> Result<ParsedPacket<'_>, IpPacketRouterError> {
let headers = etherparse::SlicedPacket::from_ip(packet).map_err(|err| {
log::warn!("Unable to parse incoming data as IP packet: {err}");
tracing::warn!("Unable to parse incoming data as IP packet: {err}");
IpPacketRouterError::PacketParseFailed { source: err }
})?;
@@ -22,7 +21,7 @@ pub(crate) fn parse_packet(packet: &[u8]) -> Result<ParsedPacket<'_>, IpPacketRo
Some(etherparse::TransportSlice::Icmpv6(_)) => ("icmpv6", None),
Some(etherparse::TransportSlice::Unknown(_)) => ("unknown", None),
None => {
log::warn!("Received packet missing transport header");
tracing::warn!("Received packet missing transport header");
return Err(IpPacketRouterError::PacketMissingTransportHeader);
}
};
@@ -41,7 +40,7 @@ pub(crate) fn parse_packet(packet: &[u8]) -> Result<ParsedPacket<'_>, IpPacketRo
(src_addr, dst_addr, dst)
}
None => {
log::warn!("Received packet missing IP header");
tracing::warn!("Received packet missing IP header");
return Err(IpPacketRouterError::PacketMissingIpHeader);
}
};
@@ -6,35 +6,54 @@ use crate::node::client_handling::websocket::message_receiver::{
MixMessageReceiver, MixMessageSender,
};
use crate::node::internal_service_providers::authenticator::Authenticator;
use crate::node::internal_service_providers::network_requester::{
error::NetworkRequesterError, NRServiceProviderBuilder,
};
use crate::service_providers::ip_packet_router::{error::IpPacketRouterError, IpPacketRouter};
use crate::GatewayError;
use async_trait::async_trait;
use futures::channel::{mpsc, oneshot};
use nym_crypto::asymmetric::ed25519;
use nym_ip_packet_router::error::IpPacketRouterError;
use nym_ip_packet_router::IpPacketRouter;
use nym_mixnet_client::forwarder::MixForwardingSender;
use nym_network_requester::error::NetworkRequesterError;
use nym_network_requester::NRServiceProviderBuilder;
use nym_sdk::mixnet::Recipient;
use nym_sdk::{GatewayTransceiver, LocalGateway, PacketRouter};
use nym_task::TaskClient;
use std::fmt::Display;
use tokio::task::JoinHandle;
use tracing::error;
pub use nym_client_core::{
client::{
base_client::{
non_wasm_helpers::{setup_fs_gateways_storage, setup_fs_reply_surb_backend},
storage::{
gateways_storage::{
CustomGatewayDetails, GatewayDetails, GatewayRegistration, RemoteGatewayDetails,
},
helpers::{set_active_gateway, store_gateway_details},
GatewaysDetailsStore, OnDiskGatewaysDetails, OnDiskPersistent,
},
},
key_manager::persistence::OnDiskKeys,
mix_traffic::transceiver::*,
},
error::ClientCoreError,
};
pub mod authenticator;
pub mod ip_packet_router;
pub mod network_requester;
pub trait LocalRecipient {
fn address(&self) -> Recipient;
}
impl LocalRecipient for nym_network_requester::core::OnStartData {
impl LocalRecipient for network_requester::OnStartData {
fn address(&self) -> Recipient {
self.address
}
}
impl LocalRecipient for nym_ip_packet_router::OnStartData {
impl LocalRecipient for ip_packet_router::OnStartData {
fn address(&self) -> Recipient {
self.address
}
@@ -58,7 +77,7 @@ pub trait RunnableServiceProvider {
#[async_trait]
impl RunnableServiceProvider for NRServiceProviderBuilder {
const NAME: &'static str = "network requester";
type OnStartData = nym_network_requester::core::OnStartData;
type OnStartData = network_requester::OnStartData;
type Error = NetworkRequesterError;
async fn run_service_provider(self) -> Result<(), Self::Error> {
@@ -69,7 +88,7 @@ impl RunnableServiceProvider for NRServiceProviderBuilder {
#[async_trait]
impl RunnableServiceProvider for IpPacketRouter {
const NAME: &'static str = "ip router";
type OnStartData = nym_ip_packet_router::OnStartData;
type OnStartData = ip_packet_router::OnStartData;
type Error = IpPacketRouterError;
async fn run_service_provider(self) -> Result<(), Self::Error> {
@@ -0,0 +1,90 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use nym_network_defaults::mainnet;
use std::path::Path;
use std::time::Duration;
use url::Url;
pub use nym_client_core::config::Config as BaseClientConfig;
pub use persistence::NetworkRequesterPaths;
mod persistence;
pub const DEFAULT_STANDARD_LIST_UPDATE_INTERVAL: Duration = Duration::from_secs(30 * 60);
#[derive(Debug, Clone, PartialEq)]
pub struct Config {
pub base: BaseClientConfig,
pub network_requester: NetworkRequester,
pub storage_paths: NetworkRequesterPaths,
pub network_requester_debug: Debug,
}
impl Config {
// this is a false positive, this method is actually called when used as a library
// but clippy complains about it when building the binary
#[must_use]
pub fn with_data_directory<P: AsRef<Path>>(mut self, data_directory: P) -> Self {
self.storage_paths = NetworkRequesterPaths::new_base(data_directory);
self
}
pub fn validate(&self) -> bool {
// no other sections have explicit requirements (yet)
self.base.validate()
}
#[must_use]
pub fn with_open_proxy(mut self, open_proxy: bool) -> Self {
self.network_requester.open_proxy = open_proxy;
self
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct NetworkRequester {
/// specifies whether this network requester should run in 'open-proxy' mode
/// and thus would attempt to resolve **ANY** request it receives.
pub open_proxy: bool,
/// Disable Poisson sending rate.
/// This is equivalent to setting debug.traffic.disable_main_poisson_packet_distribution = true,
pub disable_poisson_rate: bool,
/// Specifies the url for an upstream source of the exit policy used by this node.
pub upstream_exit_policy_url: Option<Url>,
}
#[allow(clippy::expect_used)]
impl Default for NetworkRequester {
fn default() -> Self {
NetworkRequester {
open_proxy: false,
disable_poisson_rate: true,
upstream_exit_policy_url: Some(
mainnet::EXIT_POLICY_URL
.parse()
.expect("invalid default exit policy URL"),
),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Debug {
/// Defines how often the standard allow list should get updated
/// Deprecated
pub standard_list_update_interval: Duration,
}
impl Default for Debug {
fn default() -> Self {
Debug {
standard_list_update_interval: DEFAULT_STANDARD_LIST_UPDATE_INTERVAL,
}
}
}
@@ -1,12 +1,10 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_client_core::config::disk_persistence::CommonClientPaths;
use serde::{Deserialize, Serialize};
use std::path::Path;
pub mod old;
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
pub struct NetworkRequesterPaths {
#[serde(flatten)]
@@ -1,16 +1,17 @@
// Copyright 2020-2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::{BaseClientConfig, Config};
use crate::error::NetworkRequesterError;
use crate::reply::MixnetMessage;
use crate::request_filter::RequestFilter;
use crate::{reply, socks5};
use crate::node::internal_service_providers::network_requester::config::{
BaseClientConfig, Config,
};
use crate::node::internal_service_providers::network_requester::error::NetworkRequesterError;
use crate::node::internal_service_providers::network_requester::reply::MixnetMessage;
use crate::node::internal_service_providers::network_requester::request_filter::RequestFilter;
use crate::node::internal_service_providers::network_requester::{reply, socks5};
use async_trait::async_trait;
use futures::channel::{mpsc, oneshot};
use futures::stream::StreamExt;
use log::{debug, warn};
use nym_bin_common::bin_info_owned;
use nym_bin_common::build_information::BinaryBuildInformation;
use nym_client_core::client::mix_traffic::transceiver::GatewayTransceiver;
use nym_client_core::config::disk_persistence::CommonClientPaths;
use nym_client_core::HardcodedTopologyProvider;
@@ -38,6 +39,7 @@ use nym_task::manager::TaskHandle;
use nym_task::TaskClient;
use std::path::Path;
use std::sync::atomic::{AtomicUsize, Ordering};
use tracing::{debug, error, warn};
// Since it's an atomic, it's safe to be kept static and shared across threads
static ACTIVE_PROXIES: AtomicUsize = AtomicUsize::new(0);
@@ -69,6 +71,7 @@ pub struct NRServiceProviderBuilder {
custom_gateway_transceiver: Option<Box<dyn GatewayTransceiver + Send + Sync>>,
shutdown: Option<TaskClient>,
on_start: Option<oneshot::Sender<OnStartData>>,
binary_build_information: BinaryBuildInformation,
}
pub struct NRServiceProvider {
@@ -77,6 +80,7 @@ pub struct NRServiceProvider {
mixnet_client: nym_sdk::mixnet::MixnetClient,
controller_sender: ControllerSender,
binary_build_information: BinaryBuildInformation,
mix_input_sender: MixProxySender<MixnetMessage>,
shutdown: TaskHandle,
@@ -92,15 +96,14 @@ impl ServiceProvider<Socks5Request> for NRServiceProvider {
request: Request<Socks5Request>,
) -> Result<(), Self::ServiceProviderError> {
// TODO: this should perhaps be parallelised
log::debug!("on_request {:?}", request);
tracing::debug!("on_request {:?}", request);
if let Some(response) = self.handle_request(sender, request).await? {
// TODO: this (i.e. `reply::MixnetAddress`) should be incorporated into the actual interface
if let Some(return_address) = reply::MixnetAddress::new(None, sender) {
let msg = MixnetMessage::new_provider_response(return_address, 0, response);
self.mix_input_sender
.send(msg)
.await
.expect("InputMessageReceiver has stopped receiving!");
if self.mix_input_sender.send(msg).await.is_err() {
error!("InputMessageReceiver has stopped receiving!");
}
} else {
warn!("currently we can only send generic replies via reply surbs and we haven't got any : (")
}
@@ -113,7 +116,7 @@ impl ServiceProvider<Socks5Request> for NRServiceProvider {
) -> Result<BinaryInformation, Self::ServiceProviderError> {
Ok(BinaryInformation {
binary_name: env!("CARGO_PKG_NAME").to_string(),
build_information: bin_info_owned!(),
build_information: self.binary_build_information.to_owned(),
})
}
@@ -123,12 +126,12 @@ impl ServiceProvider<Socks5Request> for NRServiceProvider {
request: Socks5Request,
interface_version: ProviderInterfaceVersion,
) -> Result<Option<Socks5Response>, Self::ServiceProviderError> {
log::debug!("handle_provider_data_request {:?}", request);
tracing::debug!("handle_provider_data_request {:?}", request);
// TODO: streamline this a bit more
let request_version = RequestVersion::new(interface_version, request.protocol_version);
log::debug!(
tracing::debug!(
"received request of version {:?} (interface) / {:?} (socks5)",
interface_version,
request.protocol_version
@@ -148,7 +151,10 @@ impl ServiceProvider<Socks5Request> for NRServiceProvider {
}
impl NRServiceProviderBuilder {
pub fn new(config: Config) -> NRServiceProviderBuilder {
pub fn new(
config: Config,
binary_build_information: BinaryBuildInformation,
) -> NRServiceProviderBuilder {
NRServiceProviderBuilder {
config,
wait_for_gateway: false,
@@ -156,6 +162,7 @@ impl NRServiceProviderBuilder {
custom_gateway_transceiver: None,
shutdown: None,
on_start: None,
binary_build_information,
}
}
@@ -284,12 +291,13 @@ impl NRServiceProviderBuilder {
request_filter: request_filter.clone(),
mixnet_client,
controller_sender,
binary_build_information: self.binary_build_information,
mix_input_sender,
shutdown,
};
log::info!("The address of this client is: {self_address}");
log::info!("All systems go. Press CTRL-C to stop the server.");
tracing::info!("The address of this client is: {self_address}");
tracing::info!("All systems go. Press CTRL-C to stop the server.");
if let Some(on_start) = self.on_start {
if on_start
@@ -317,7 +325,7 @@ impl NRServiceProvider {
msg = self.mixnet_client.next() => match msg {
Some(msg) => self.on_message(msg).await,
None => {
log::trace!("NRServiceProvider::run: Stopping since channel closed");
tracing::trace!("NRServiceProvider::run: Stopping since channel closed");
break;
}
},
@@ -333,7 +341,7 @@ impl NRServiceProvider {
Ok(req) => req,
Err(err) => {
// TODO: or should it even be further lowered to debug/trace?
log::warn!("Failed to deserialize received message: {err}");
tracing::warn!("Failed to deserialize received message: {err}");
return;
}
};
@@ -342,7 +350,7 @@ impl NRServiceProvider {
// TODO: again, should it be a warning?
// we should also probably log some information regarding the origin of the request
// so that it would be easier to debug it
log::warn!("failed to resolve the received request: {err}");
tracing::warn!("failed to resolve the received request: {err}");
}
}
@@ -358,9 +366,12 @@ impl NRServiceProvider {
socks5_msg = mix_input_reader.recv() => {
if let Some(msg) = socks5_msg {
let response_message = msg.into_input_message(packet_type);
mixnet_client_sender.send(response_message).await.unwrap();
if mixnet_client_sender.send(response_message).await.is_err() {
error!("failed to send response - channel is closed");
break;
}
} else {
log::error!("Exiting: channel closed!");
tracing::error!("Exiting: channel closed!");
break;
}
},
@@ -389,7 +400,7 @@ impl NRServiceProvider {
{
Ok(conn) => conn,
Err(err) => {
log::error!("error while connecting to {remote_addr}: {err}",);
tracing::error!("error while connecting to {remote_addr}: {err}",);
shutdown.disarm();
// inform the remote that the connection is closed before it even was established
@@ -400,10 +411,9 @@ impl NRServiceProvider {
SocketData::new(0, connection_id, true, Vec::new()),
);
mix_input_sender
.send(mixnet_message)
.await
.expect("InputMessageReceiver has stopped receiving!");
if mix_input_sender.send(mixnet_message).await.is_err() {
error!("InputMessageReceiver has stopped receiving!")
}
return;
}
@@ -411,15 +421,19 @@ impl NRServiceProvider {
// Connect implies it's a fresh connection - register it with our controller
let (mix_sender, mix_receiver) = mpsc::unbounded();
controller_sender
if controller_sender
.unbounded_send(ControllerCommand::Insert {
connection_id,
connection_sender: mix_sender,
})
.unwrap();
.is_err()
{
error!("failed to insert new proxy info - the channel is closed!");
return;
}
let old_count = ACTIVE_PROXIES.fetch_add(1, Ordering::SeqCst);
log::info!(
tracing::info!(
"Starting proxy for {remote_addr} (currently there are {} proxies being handled)",
old_count + 1
);
@@ -436,12 +450,15 @@ impl NRServiceProvider {
.await;
// proxy is done - remove the access channel from the controller
controller_sender
if controller_sender
.unbounded_send(ControllerCommand::Remove { connection_id })
.unwrap();
.is_err()
{
error!("failed to send controller remove request - the channel is closed")
}
let old_count = ACTIVE_PROXIES.fetch_sub(1, Ordering::SeqCst);
log::info!(
tracing::info!(
"Proxy for {remote_addr} is finished (currently there are {} proxies being handled)",
old_count - 1
);
@@ -456,7 +473,7 @@ impl NRServiceProvider {
let Some(return_address) =
reply::MixnetAddress::new(connect_req.return_address, sender_tag)
else {
log::warn!(
tracing::warn!(
"attempted to start connection with no way of returning data back to the sender"
);
return;
@@ -483,7 +500,7 @@ impl NRServiceProvider {
tokio::spawn(async move {
if !request_filter.check_address(&remote_addr).await {
let log_msg = format!("Domain {remote_addr:?} failed filter check");
log::info!("{log_msg}");
tracing::info!("{log_msg}");
let error_msg = MixnetMessage::new_connection_error(
return_address,
remote_version,
@@ -491,11 +508,12 @@ impl NRServiceProvider {
log_msg,
);
mix_input_sender_clone
.send(error_msg)
.await
.expect("InputMessageReceiver has stopped receiving!");
shutdown.disarm();
if mix_input_sender_clone.send(error_msg).await.is_err() {
// don't disarm the shutdown, do cause global shutdown here!
error!("InputMessageReceiver has stopped receiving!");
} else {
shutdown.disarm();
}
return;
}
@@ -516,9 +534,13 @@ impl NRServiceProvider {
}
fn handle_proxy_send(&mut self, req: SendRequest) {
self.controller_sender
if self
.controller_sender
.unbounded_send(ControllerCommand::new_send(req.data))
.unwrap()
.is_err()
{
error!("failed to handle proxy send request - the channel is closed")
}
}
fn handle_query(
@@ -58,12 +58,6 @@ pub enum NetworkRequesterError {
source: PolicyError,
},
#[error("the url provided for the upstream exit policy source is malformed: {source}")]
MalformedExitPolicyUpstreamUrl {
#[source]
source: reqwest::Error,
},
#[error("can't setup an exit policy without any upstream urls")]
NoUpstreamExitPolicy,
@@ -0,0 +1,13 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
pub mod config;
pub mod core;
pub mod error;
mod reply;
pub mod request_filter;
mod socks5;
pub use config::Config;
pub use core::{NRServiceProvider, NRServiceProviderBuilder, OnStartData};
pub use request_filter::RequestFilter;
@@ -1,14 +1,13 @@
// Copyright 2023-2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::config::Config;
use crate::error::NetworkRequesterError;
use log::trace;
use crate::node::internal_service_providers::network_requester::config::Config;
use crate::node::internal_service_providers::network_requester::error::NetworkRequesterError;
use nym_exit_policy::client::get_exit_policy;
use nym_exit_policy::ExitPolicy;
use nym_socks5_requests::RemoteAddress;
use reqwest::IntoUrl;
use tokio::net::lookup_host;
use tracing::trace;
use url::Url;
pub struct ExitPolicyRequestFilter {
@@ -23,11 +22,7 @@ impl From<ExitPolicy> for ExitPolicyRequestFilter {
}
impl ExitPolicyRequestFilter {
pub(crate) async fn new_upstream(url: impl IntoUrl) -> Result<Self, NetworkRequesterError> {
let url = url
.into_url()
.map_err(|source| NetworkRequesterError::MalformedExitPolicyUpstreamUrl { source })?;
pub(crate) async fn new_upstream(url: Url) -> Result<Self, NetworkRequesterError> {
Ok(ExitPolicyRequestFilter {
upstream: Some(url.clone()),
policy: get_exit_policy(url).await?,
@@ -1,11 +1,11 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::config::Config;
use crate::error::NetworkRequesterError;
use log::warn;
use crate::node::internal_service_providers::network_requester::config::Config;
use crate::node::internal_service_providers::network_requester::error::NetworkRequesterError;
use nym_socks5_requests::RemoteAddress;
use std::sync::Arc;
use tracing::warn;
pub mod exit_policy;
@@ -1,8 +1,8 @@
// Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::reply;
use crate::reply::MixnetMessage;
use crate::node::internal_service_providers::network_requester::reply;
use crate::node::internal_service_providers::network_requester::reply::MixnetMessage;
use nym_service_providers_common::interface::RequestVersion;
use nym_socks5_proxy_helpers::connection_controller::ConnectionReceiver;
use nym_socks5_proxy_helpers::proxy_runner::{MixProxySender, ProxyRunner};
@@ -12,6 +12,7 @@ use nym_task::connections::LaneQueueLengths;
use nym_task::TaskClient;
use std::io;
use tokio::net::TcpStream;
use tracing::error;
/// An outbound TCP connection between the Socks5 service provider, which makes
/// requests on behalf of users and returns the responses through
@@ -49,7 +50,10 @@ impl Connection {
lane_queue_lengths: LaneQueueLengths,
shutdown: TaskClient,
) {
let stream = self.conn.take().unwrap();
let Some(stream) = self.conn.take() else {
error!("the proxy is being run for the second time");
return;
};
let remote_source_address = "???".to_string(); // we don't know ip address of requester
let connection_id = self.id;
let return_address = self.return_address.clone();
+20 -14
View File
@@ -4,19 +4,21 @@
use crate::config::Config;
use crate::error::GatewayError;
use crate::node::client_handling::websocket;
use crate::node::internal_service_providers::authenticator::{self, Authenticator};
use crate::node::internal_service_providers::ip_packet_router::{self, IpPacketRouter};
use crate::node::internal_service_providers::network_requester::{self, NRServiceProviderBuilder};
use crate::node::internal_service_providers::{
authenticator, ExitServiceProviders, ServiceProviderBeingBuilt, SpMessageRouterBuilder,
ExitServiceProviders, ServiceProviderBeingBuilt, SpMessageRouterBuilder,
};
use crate::node::stale_data_cleaner::StaleMessagesCleaner;
use futures::channel::oneshot;
use nym_bin_common::build_information::BinaryBuildInformation;
use nym_credential_verification::ecash::{
credential_sender::CredentialHandlerConfig, EcashManager,
};
use nym_crypto::asymmetric::ed25519;
use nym_ip_packet_router::IpPacketRouter;
use nym_mixnet_client::forwarder::MixForwardingSender;
use nym_network_defaults::NymNetworkDetails;
use nym_network_requester::NRServiceProviderBuilder;
use nym_node_metrics::events::MetricEventsSender;
use nym_node_metrics::NymNodeMetrics;
use nym_task::{ShutdownToken, TaskClient};
@@ -32,10 +34,9 @@ use tracing::*;
use zeroize::Zeroizing;
pub(crate) mod client_handling;
pub(crate) mod internal_service_providers;
pub mod internal_service_providers;
mod stale_data_cleaner;
use crate::node::internal_service_providers::authenticator::Authenticator;
pub use client_handling::active_clients::ActiveClientsStore;
pub use nym_gateway_stats_storage::PersistentStatsStorage;
pub use nym_gateway_storage::{
@@ -47,14 +48,14 @@ pub use nym_sdk::{NymApiTopologyProvider, NymApiTopologyProviderConfig, UserAgen
#[derive(Debug, Clone)]
pub struct LocalNetworkRequesterOpts {
pub config: nym_network_requester::Config,
pub config: network_requester::Config,
pub custom_mixnet_path: Option<PathBuf>,
}
#[derive(Debug, Clone)]
pub struct LocalIpPacketRouterOpts {
pub config: nym_ip_packet_router::Config,
pub config: ip_packet_router::Config,
pub custom_mixnet_path: Option<PathBuf>,
}
@@ -69,6 +70,8 @@ pub struct LocalAuthenticatorOpts {
pub struct GatewayTasksBuilder {
config: Config,
binary_build_information: BinaryBuildInformation,
network_requester_opts: Option<LocalNetworkRequesterOpts>,
ip_packet_router_opts: Option<LocalIpPacketRouterOpts>,
@@ -121,11 +124,13 @@ impl GatewayTasksBuilder {
metrics_sender: MetricEventsSender,
metrics: NymNodeMetrics,
mnemonic: Arc<Zeroizing<bip39::Mnemonic>>,
binary_build_information: BinaryBuildInformation,
legacy_task_client: TaskClient,
shutdown_token: ShutdownToken,
) -> GatewayTasksBuilder {
GatewayTasksBuilder {
config,
binary_build_information,
network_requester_opts: None,
ip_packet_router_opts: None,
authenticator_opts: None,
@@ -296,13 +301,14 @@ impl GatewayTasksBuilder {
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.legacy_task_client.fork("network_requester_sp"))
.with_custom_gateway_transceiver(transceiver)
.with_wait_for_gateway(true)
.with_minimum_gateway_performance(0)
.with_custom_topology_provider(topology_provider)
.with_on_start(on_start_tx);
let mut nr_builder =
NRServiceProviderBuilder::new(nr_opts.config.clone(), self.binary_build_information)
.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)
.with_custom_topology_provider(topology_provider)
.with_on_start(on_start_tx);
if let Some(custom_mixnet) = &nr_opts.custom_mixnet_path {
nr_builder = nr_builder.with_stored_topology(custom_mixnet)?
-3
View File
@@ -100,10 +100,7 @@ nym-node-requests = { path = "nym-node-requests", default-features = false, feat
] }
nym-node-metrics = { path = "nym-node-metrics" }
# nodes:
nym-gateway = { path = "../gateway" }
nym-network-requester = { path = "../service-providers/network-requester" }
nym-ip-packet-router = { path = "../service-providers/ip-packet-router" }
# throughput tester to recreate lioness
@@ -5,7 +5,7 @@ use crate::cli::helpers::ConfigArgs;
use crate::config::upgrade_helpers::try_load_current_config;
use crate::node::helpers::load_ed25519_identity_public_key;
use crate::node::ServiceProvidersData;
use nym_network_requester::{CustomGatewayDetails, GatewayDetails, GatewayRegistration};
use nym_gateway::service_providers::{CustomGatewayDetails, GatewayDetails, GatewayRegistration};
use std::fs;
#[derive(Debug, clap::Args)]
+5 -4
View File
@@ -8,6 +8,8 @@ use nym_gateway::node::{
LocalAuthenticatorOpts, LocalIpPacketRouterOpts, LocalNetworkRequesterOpts,
};
use nym_gateway::nym_authenticator;
use nym_gateway::nym_network_requester;
use nym_gateway::service_providers::ip_packet_router;
// a temporary solution until further refactoring is made
fn ephemeral_gateway_config(config: &Config) -> nym_gateway::config::Config {
@@ -117,7 +119,6 @@ pub fn gateway_tasks_config(config: &Config) -> GatewayTasksConfig {
.to_common_client_paths(),
},
network_requester_debug: Default::default(),
logging: config.logging,
},
custom_mixnet_path: None,
};
@@ -136,12 +137,12 @@ pub fn gateway_tasks_config(config: &Config) -> GatewayTasksConfig {
.unwrap();
let mut ipr_opts = LocalIpPacketRouterOpts {
config: nym_ip_packet_router::Config {
config: ip_packet_router::Config {
base: nym_client_core_config_types::Config {
client: base_client_config(config),
debug: config.service_providers.ip_packet_router.debug.client_debug,
},
ip_packet_router: nym_ip_packet_router::config::IpPacketRouter {
ip_packet_router: ip_packet_router::config::IpPacketRouter {
disable_poisson_rate: config
.service_providers
.ip_packet_router
@@ -151,7 +152,7 @@ pub fn gateway_tasks_config(config: &Config) -> GatewayTasksConfig {
config.service_providers.upstream_exit_policy_url.clone(),
),
},
storage_paths: nym_ip_packet_router::config::IpPacketRouterPaths {
storage_paths: ip_packet_router::config::IpPacketRouterPaths {
common_paths: config
.service_providers
.storage_paths
@@ -7,7 +7,7 @@ use crate::{config::*, error::KeyIOFailure};
use nym_client_core_config_types::DebugConfig as ClientDebugConfig;
use nym_config::serde_helpers::de_maybe_port;
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_network_requester::{
use nym_gateway::service_providers::{
set_active_gateway, setup_fs_gateways_storage, store_gateway_details, CustomGatewayDetails,
GatewayDetails,
};
+1 -1
View File
@@ -3,8 +3,8 @@
use crate::node::http::error::NymNodeHttpError;
use crate::wireguard::error::WireguardError;
use nym_gateway::service_providers::ClientCoreError;
use nym_http_api_client::HttpClientError;
use nym_ip_packet_router::error::ClientCoreError;
use nym_validator_client::nyxd::error::NyxdError;
use nym_validator_client::ValidatorClientError;
use std::io;
+4 -3
View File
@@ -41,12 +41,12 @@ use crate::node::shared_network::{
use nym_bin_common::bin_info;
use nym_crypto::asymmetric::{ed25519, x25519};
use nym_gateway::node::{ActiveClientsStore, GatewayTasksBuilder};
use nym_mixnet_client::client::ActiveConnections;
use nym_mixnet_client::forwarder::MixForwardingSender;
use nym_network_requester::{
use nym_gateway::service_providers::{
set_active_gateway, setup_fs_gateways_storage, store_gateway_details, CustomGatewayDetails,
GatewayDetails, GatewayRegistration,
};
use nym_mixnet_client::client::ActiveConnections;
use nym_mixnet_client::forwarder::MixForwardingSender;
use nym_node_metrics::events::MetricEventsSender;
use nym_node_metrics::NymNodeMetrics;
use nym_node_requests::api::v1::node::models::{AnnouncePorts, NodeDescription};
@@ -624,6 +624,7 @@ impl NymNode {
metrics_sender,
self.metrics.clone(),
self.entry_gateway.mnemonic.clone(),
bin_info!(),
legacy_task_client,
shutdown_token,
);
@@ -1,52 +0,0 @@
[package]
name = "nym-ip-packet-router"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license = "GPL-3.0"
[dependencies]
anyhow.workspace = true
bincode = { workspace = true }
bs58 = { workspace = true }
bytes = { workspace = true }
clap.workspace = true
etherparse = { workspace = true }
futures = { workspace = true }
log = { workspace = true }
nym-bin-common = { path = "../../common/bin-common", features = ["clap", "basic_tracing"] }
nym-client-core = { path = "../../common/client-core" }
nym-config = { path = "../../common/config" }
nym-crypto = { path = "../../common/crypto" }
nym-exit-policy = { path = "../../common/exit-policy" }
nym-id = { path = "../../common/nym-id" }
nym-ip-packet-requests = { path = "../../common/ip-packet-requests" }
nym-network-defaults = { path = "../../common/network-defaults" }
nym-network-requester = { path = "../network-requester" }
nym-sdk = { path = "../../sdk/rust/nym-sdk" }
nym-service-provider-requests-common = { path = "../../common/service-provider-requests-common" }
nym-service-providers-common = { path = "../common" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-task = { path = "../../common/task" }
nym-tun = { path = "../../common/tun" }
nym-types = { path = "../../common/types" }
nym-wireguard = { path = "../../common/wireguard" }
nym-wireguard-types = { path = "../../common/wireguard-types" }
rand = { workspace = true }
reqwest.workspace = true
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
time = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util", "macros"] }
tokio-util = { workspace = true, features = ["codec"] }
url.workspace = true
[target.'cfg(target_os = "linux")'.dependencies]
tokio-tun.workspace = true
[dev-dependencies]
async-trait.workspace = true
@@ -1,30 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::CliIpPacketRouterClient;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_add_gateway::{add_gateway, CommonClientAddGatewayArgs};
use nym_ip_packet_router::error::IpPacketRouterError;
#[derive(clap::Args)]
pub(crate) struct Args {
#[command(flatten)]
common_args: CommonClientAddGatewayArgs,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl AsRef<CommonClientAddGatewayArgs> for Args {
fn as_ref(&self) -> &CommonClientAddGatewayArgs {
&self.common_args
}
}
pub(crate) async fn execute(args: Args) -> Result<(), IpPacketRouterError> {
let output = args.output;
let res = add_gateway::<CliIpPacketRouterClient, _>(args, None).await?;
println!("{}", output.format(&res));
Ok(())
}
@@ -1,13 +0,0 @@
use clap::Args;
use nym_bin_common::bin_info_owned;
use nym_bin_common::output_format::OutputFormat;
#[derive(Args)]
pub(crate) struct BuildInfo {
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
pub(crate) fn execute(args: BuildInfo) {
println!("{}", args.output.format(&bin_info_owned!()))
}
@@ -1,16 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::CliIpPacketRouterClient;
use nym_client_core::cli_helpers::client_import_coin_index_signatures::{
import_coin_index_signatures, CommonClientImportCoinIndexSignaturesArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
pub(crate) async fn execute(
args: CommonClientImportCoinIndexSignaturesArgs,
) -> Result<(), IpPacketRouterError> {
import_coin_index_signatures::<CliIpPacketRouterClient, _>(args).await?;
println!("successfully imported coin index signatures!");
Ok(())
}
@@ -1,14 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::CliIpPacketRouterClient;
use nym_client_core::cli_helpers::client_import_credential::{
import_credential, CommonClientImportTicketBookArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
pub async fn execute(args: CommonClientImportTicketBookArgs) -> Result<(), IpPacketRouterError> {
import_credential::<CliIpPacketRouterClient, _>(args).await?;
println!("successfully imported credential!");
Ok(())
}
@@ -1,16 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::CliIpPacketRouterClient;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::{
import_expiration_date_signatures, CommonClientImportExpirationDateSignaturesArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
pub(crate) async fn execute(
args: CommonClientImportExpirationDateSignaturesArgs,
) -> Result<(), IpPacketRouterError> {
import_expiration_date_signatures::<CliIpPacketRouterClient, _>(args).await?;
println!("successfully imported expiration date signatures!");
Ok(())
}
@@ -1,16 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::CliIpPacketRouterClient;
use nym_client_core::cli_helpers::client_import_master_verification_key::{
import_master_verification_key, CommonClientImportMasterVerificationKeyArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
pub(crate) async fn execute(
args: CommonClientImportMasterVerificationKeyArgs,
) -> Result<(), IpPacketRouterError> {
import_master_verification_key::<CliIpPacketRouterClient, _>(args).await?;
println!("successfully imported master verification key!");
Ok(())
}
@@ -1,59 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use clap::{Args, Subcommand};
use nym_client_core::cli_helpers::client_import_coin_index_signatures::CommonClientImportCoinIndexSignaturesArgs;
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportTicketBookArgs;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::CommonClientImportExpirationDateSignaturesArgs;
use nym_client_core::cli_helpers::client_import_master_verification_key::CommonClientImportMasterVerificationKeyArgs;
use nym_ip_packet_router::error::IpPacketRouterError;
pub(crate) mod import_coin_index_signatures;
pub(crate) mod import_credential;
pub(crate) mod import_expiration_date_signatures;
pub(crate) mod import_master_verification_key;
pub(crate) mod show_ticketbooks;
#[derive(Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Ecash {
#[clap(subcommand)]
pub command: EcashCommands,
}
impl Ecash {
pub async fn execute(self) -> Result<(), IpPacketRouterError> {
match self.command {
EcashCommands::ShowTicketBooks(args) => show_ticketbooks::execute(args).await?,
EcashCommands::ImportTicketBook(args) => import_credential::execute(args).await?,
EcashCommands::ImportCoinIndexSignatures(args) => {
import_coin_index_signatures::execute(args).await?
}
EcashCommands::ImportExpirationDateSignatures(args) => {
import_expiration_date_signatures::execute(args).await?
}
EcashCommands::ImportMasterVerificationKey(args) => {
import_master_verification_key::execute(args).await?
}
}
Ok(())
}
}
#[derive(Subcommand)]
pub enum EcashCommands {
/// Display information associated with the imported ticketbooks,
ShowTicketBooks(show_ticketbooks::Args),
/// Import a pre-generated ticketbook
ImportTicketBook(CommonClientImportTicketBookArgs),
/// Import coin index signatures needed for ticketbooks
ImportCoinIndexSignatures(CommonClientImportCoinIndexSignaturesArgs),
/// Import expiration date signatures needed for ticketbooks
ImportExpirationDateSignatures(CommonClientImportExpirationDateSignaturesArgs),
/// Import master verification key needed for ticketbooks
ImportMasterVerificationKey(CommonClientImportMasterVerificationKeyArgs),
}
@@ -1,32 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::CliIpPacketRouterClient;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_show_ticketbooks::{
show_ticketbooks, CommonShowTicketbooksArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
#[derive(clap::Args)]
pub struct Args {
#[command(flatten)]
common_args: CommonShowTicketbooksArgs,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl AsRef<CommonShowTicketbooksArgs> for Args {
fn as_ref(&self) -> &CommonShowTicketbooksArgs {
&self.common_args
}
}
pub async fn execute(args: Args) -> Result<(), IpPacketRouterError> {
let output = args.output;
let res = show_ticketbooks::<CliIpPacketRouterClient, _>(args).await?;
println!("{}", output.format(&res));
Ok(())
}
@@ -1,97 +0,0 @@
use crate::cli::{override_config, CliIpPacketRouterClient, OverrideConfig};
use clap::Args;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_init::{
initialise_client, CommonClientInitArgs, InitResultsWithConfig, InitialisableClient,
};
use nym_ip_packet_router::{
config::{default_config_directory, default_config_filepath, default_data_directory, Config},
error::IpPacketRouterError,
};
use serde::Serialize;
use std::{fmt::Display, fs, path::PathBuf};
impl InitialisableClient for CliIpPacketRouterClient {
type InitArgs = Init;
fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> {
fs::create_dir_all(default_data_directory(id))?;
fs::create_dir_all(default_config_directory(id))?;
Ok(())
}
fn default_config_path(id: &str) -> PathBuf {
default_config_filepath(id)
}
fn construct_config(init_args: &Self::InitArgs) -> Self::Config {
override_config(
Config::new(&init_args.common_args.id),
OverrideConfig::from(init_args.clone()),
)
}
}
#[derive(Args, Clone, Debug)]
pub(crate) struct Init {
#[command(flatten)]
common_args: CommonClientInitArgs,
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl From<Init> for OverrideConfig {
fn from(init_config: Init) -> Self {
OverrideConfig {
nym_apis: init_config.common_args.nym_apis,
nyxd_urls: init_config.common_args.nyxd_urls,
enabled_credentials_mode: init_config.common_args.enabled_credentials_mode,
}
}
}
impl AsRef<CommonClientInitArgs> for Init {
fn as_ref(&self) -> &CommonClientInitArgs {
&self.common_args
}
}
#[derive(Debug, Serialize)]
pub struct InitResults {
#[serde(flatten)]
client_core: nym_client_core::init::types::InitResults,
client_address: String,
}
impl InitResults {
fn new(res: InitResultsWithConfig<Config>) -> Self {
Self {
client_address: res.init_results.address.to_string(),
client_core: res.init_results,
}
}
}
impl Display for InitResults {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", self.client_core)?;
write!(
f,
"Address of this ip-packet-router: {}",
self.client_address
)
}
}
pub(crate) async fn execute(args: Init) -> Result<(), IpPacketRouterError> {
eprintln!("Initialising client...");
let output = args.output;
let res = initialise_client::<CliIpPacketRouterClient>(args, None).await?;
let init_results = InitResults::new(res);
println!("{}", output.format(&init_results));
Ok(())
}
@@ -1,32 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::CliIpPacketRouterClient;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_list_gateways::{
list_gateways, CommonClientListGatewaysArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
#[derive(clap::Args)]
pub(crate) struct Args {
#[command(flatten)]
common_args: CommonClientListGatewaysArgs,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl AsRef<CommonClientListGatewaysArgs> for Args {
fn as_ref(&self) -> &CommonClientListGatewaysArgs {
&self.common_args
}
}
pub(crate) async fn execute(args: Args) -> Result<(), IpPacketRouterError> {
let output = args.output;
let res = list_gateways::<CliIpPacketRouterClient, _>(args).await?;
println!("{}", output.format(&res));
Ok(())
}
@@ -1,169 +0,0 @@
use crate::cli::ecash::Ecash;
use clap::{CommandFactory, Parser, Subcommand};
use log::error;
use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client_core::cli_helpers::CliClient;
use nym_ip_packet_router::config::helpers::{try_upgrade_config, try_upgrade_config_by_id};
use nym_ip_packet_router::config::{BaseClientConfig, Config};
use nym_ip_packet_router::error::IpPacketRouterError;
use std::sync::OnceLock;
mod add_gateway;
mod build_info;
pub mod ecash;
mod init;
mod list_gateways;
mod run;
mod sign;
mod switch_gateway;
pub(crate) struct CliIpPacketRouterClient;
impl CliClient for CliIpPacketRouterClient {
const NAME: &'static str = "ip packet router";
type Error = IpPacketRouterError;
type Config = Config;
async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> {
try_upgrade_config(id).await
}
async fn try_load_current_config(id: &str) -> Result<Self::Config, Self::Error> {
try_load_current_config(id).await
}
}
fn pretty_build_info_static() -> &'static str {
static PRETTY_BUILD_INFORMATION: OnceLock<String> = OnceLock::new();
PRETTY_BUILD_INFORMATION.get_or_init(|| bin_info!().pretty_print())
}
#[derive(Parser)]
#[command(author = "Nymtech", version, about, long_version = pretty_build_info_static())]
pub(crate) struct Cli {
/// Path pointing to an env file that configures the client.
#[arg(short, long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
/// Flag used for disabling the printed banner in tty.
#[arg(long)]
pub(crate) no_banner: bool,
#[command(subcommand)]
command: Commands,
}
#[allow(clippy::large_enum_variant)]
#[derive(Subcommand)]
pub(crate) enum Commands {
/// Initialize a network-requester. Do this first!
Init(init::Init),
/// Run the network requester with the provided configuration and optionally override
/// parameters.
Run(run::Run),
/// Ecash-related functionalities
Ecash(Ecash),
/// List all registered with gateways
ListGateways(list_gateways::Args),
/// Add new gateway to this client
AddGateway(add_gateway::Args),
/// Change the currently active gateway. Note that you must have already registered with the new gateway!
SwitchGateway(switch_gateway::Args),
/// Sign to prove ownership of this network requester
Sign(sign::Sign),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
/// Generate shell completions
Completions(ArgShell),
/// Generate Fig specification
GenerateFigSpec,
}
// Configuration that can be overridden.
pub(crate) struct OverrideConfig {
nym_apis: Option<Vec<url::Url>>,
nyxd_urls: Option<Vec<url::Url>>,
enabled_credentials_mode: Option<bool>,
}
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
// disable poisson rate in the BASE client if the IPR option is enabled
if config.ip_packet_router.disable_poisson_rate {
log::info!("Disabling poisson rate for ip packet router");
config.set_no_poisson_process();
}
config
.with_optional_base_custom_env(
BaseClientConfig::with_custom_nym_apis,
args.nym_apis,
nym_network_defaults::var_names::NYM_API,
nym_config::parse_urls,
)
.with_optional_base_custom_env(
BaseClientConfig::with_custom_nyxd,
args.nyxd_urls,
nym_network_defaults::var_names::NYXD,
nym_config::parse_urls,
)
.with_optional_base(
BaseClientConfig::with_disabled_credentials,
args.enabled_credentials_mode.map(|b| !b),
)
}
pub(crate) async fn execute(args: Cli) -> Result<(), IpPacketRouterError> {
let bin_name = "nym-ip-packet-router";
match args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(&m).await?,
Commands::Ecash(ecash) => ecash.execute().await?,
Commands::ListGateways(args) => list_gateways::execute(args).await?,
Commands::AddGateway(args) => add_gateway::execute(args).await?,
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
Commands::Sign(m) => sign::execute(&m).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
}
Ok(())
}
async fn try_load_current_config(id: &str) -> Result<Config, IpPacketRouterError> {
// try to load the config as is
if let Ok(cfg) = Config::read_from_default_path(id) {
return if !cfg.validate() {
Err(IpPacketRouterError::ConfigValidationFailure)
} else {
Ok(cfg)
};
}
// we couldn't load it - try upgrading it from older revisions
try_upgrade_config_by_id(id).await?;
let config = match Config::read_from_default_path(id) {
Ok(cfg) => cfg,
Err(err) => {
error!("Failed to load config for {id}. Are you sure you have run `init` before? (Error was: {err})");
return Err(IpPacketRouterError::FailedToLoadConfig(id.to_string()));
}
};
if !config.validate() {
return Err(IpPacketRouterError::ConfigValidationFailure);
}
Ok(config)
}
@@ -1,36 +0,0 @@
use crate::cli::try_load_current_config;
use crate::cli::{override_config, OverrideConfig};
use clap::Args;
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs;
use nym_ip_packet_router::error::IpPacketRouterError;
#[allow(clippy::struct_excessive_bools)]
#[derive(Args, Clone)]
pub(crate) struct Run {
#[command(flatten)]
common_args: CommonClientRunArgs,
}
impl From<Run> for OverrideConfig {
fn from(run_config: Run) -> Self {
OverrideConfig {
nym_apis: None,
nyxd_urls: run_config.common_args.nyxd_urls,
enabled_credentials_mode: run_config.common_args.enabled_credentials_mode,
}
}
}
pub(crate) async fn execute(args: &Run) -> Result<(), IpPacketRouterError> {
let mut config = try_load_current_config(&args.common_args.id).await?;
config = override_config(config, OverrideConfig::from(args.clone()));
log::debug!("Using config: {config:#?}");
log::info!("Starting ip packet router service provider");
let mut server = nym_ip_packet_router::IpPacketRouter::new(config);
if let Some(custom_mixnet) = &args.common_args.custom_mixnet {
server = server.with_stored_topology(custom_mixnet)?
}
server.run_service_provider().await
}
@@ -1,71 +0,0 @@
use crate::cli::try_load_current_config;
use clap::Args;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::error::ClientCoreError;
use nym_crypto::asymmetric::ed25519;
use nym_ip_packet_router::error::IpPacketRouterError;
use nym_types::helpers::ConsoleSigningOutput;
#[derive(Args, Clone)]
pub(crate) struct Sign {
/// The id of the mixnode you want to sign with
#[arg(long)]
id: String,
/// Signs a transaction-specific payload, that is going to be sent to the smart contract, with your identity key
#[arg(long)]
contract_msg: String,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
fn print_signed_contract_msg(
private_key: &ed25519::PrivateKey,
raw_msg: &str,
output: OutputFormat,
) {
let trimmed = raw_msg.trim();
eprintln!(">>> attempting to sign {trimmed}");
let Ok(decoded) = bs58::decode(trimmed).into_vec() else {
println!("it seems you have incorrectly copied the message to sign. Make sure you didn't accidentally skip any characters");
return;
};
eprintln!(">>> decoding the message...");
// we don't really care about what particular information is embedded inside of it,
// we just want to know if user correctly copied the string, i.e. whether it's a valid bs58 encoded json
if serde_json::from_slice::<serde_json::Value>(&decoded).is_err() {
println!("it seems you have incorrectly copied the message to sign. Make sure you didn't accidentally skip any characters");
return;
};
// if this is a valid json, it MUST be a valid string
let decoded_string = String::from_utf8(decoded.clone()).unwrap();
let signature = private_key.sign(&decoded).to_base58_string();
let sign_output = ConsoleSigningOutput::new(decoded_string, signature);
println!("{}", output.format(&sign_output));
}
pub(crate) async fn execute(args: &Sign) -> Result<(), IpPacketRouterError> {
let config = try_load_current_config(&args.id).await?;
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys);
let identity_keypair = key_store.load_identity_keypair().map_err(|source| {
IpPacketRouterError::ClientCoreError(ClientCoreError::KeyStoreError {
source: Box::new(source),
})
})?;
print_signed_contract_msg(
identity_keypair.private_key(),
&args.contract_msg,
args.output,
);
Ok(())
}
@@ -1,24 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::CliIpPacketRouterClient;
use nym_client_core::cli_helpers::client_switch_gateway::{
switch_gateway, CommonClientSwitchGatewaysArgs,
};
use nym_ip_packet_router::error::IpPacketRouterError;
#[derive(clap::Args, Clone, Debug)]
pub struct Args {
#[command(flatten)]
common_args: CommonClientSwitchGatewaysArgs,
}
impl AsRef<CommonClientSwitchGatewaysArgs> for Args {
fn as_ref(&self) -> &CommonClientSwitchGatewaysArgs {
&self.common_args
}
}
pub(crate) async fn execute(args: Args) -> Result<(), IpPacketRouterError> {
switch_gateway::<CliIpPacketRouterClient, _>(args).await
}
@@ -1,73 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::config::default_config_filepath;
use crate::config::old_config_v1::ConfigV1;
use crate::config::old_config_v2::ConfigV2;
use crate::error::IpPacketRouterError;
use log::{info, trace};
use nym_client_core::cli_helpers::CliClientConfig;
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
use std::path::Path;
async fn try_upgrade_v1_config<P: AsRef<Path>>(
config_path: P,
) -> Result<bool, IpPacketRouterError> {
// explicitly load it as v1 (which is incompatible with the current one)
let Ok(old_config) = ConfigV1::read_from_toml_file(config_path.as_ref()) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using v1 config template.");
info!("It is going to get updated to the current specification.");
let old_paths = old_config.storage_paths.clone();
let updated_step1: ConfigV2 = old_config.try_into()?;
v1_1_33::migrate_gateway_details(
&old_paths.common_paths,
&updated_step1.storage_paths.common_paths,
None,
)
.await?;
let updated = updated_step1.try_upgrade()?;
updated.save_to(config_path)?;
Ok(true)
}
async fn try_upgrade_v2_config<P: AsRef<Path>>(
config_path: P,
) -> Result<bool, IpPacketRouterError> {
// explicitly load it as v2 (which is incompatible with the current one)
let Ok(old_config) = ConfigV2::read_from_toml_file(config_path.as_ref()) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using v2 config template.");
info!("It is going to get updated to the current specification.");
let updated = old_config.try_upgrade()?;
updated.save_to(config_path)?;
Ok(true)
}
pub async fn try_upgrade_config<P: AsRef<Path>>(config_path: P) -> Result<(), IpPacketRouterError> {
trace!("Attempting to upgrade config");
if try_upgrade_v1_config(config_path.as_ref()).await? {
return Ok(());
}
if try_upgrade_v2_config(config_path).await? {
return Ok(());
}
Ok(())
}
pub async fn try_upgrade_config_by_id(id: &str) -> Result<(), IpPacketRouterError> {
try_upgrade_config(default_config_filepath(id)).await
}
@@ -1,211 +0,0 @@
pub use nym_client_core::config::Config as BaseClientConfig;
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::{cli_helpers::CliClientConfig, config::disk_persistence::CommonClientPaths};
use nym_config::{
defaults::mainnet, must_get_home, save_formatted_config_to_file,
serde_helpers::de_maybe_stringified, NymConfigTemplate, OptionalSet, DEFAULT_CONFIG_DIR,
DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
};
use nym_service_providers_common::DEFAULT_SERVICE_PROVIDERS_DIR;
use serde::{Deserialize, Serialize};
use std::{
io,
path::{Path, PathBuf},
str::FromStr,
};
use url::Url;
pub use crate::config::persistence::IpPacketRouterPaths;
use self::template::CONFIG_TEMPLATE;
pub mod helpers;
pub mod old_config_v1;
pub mod old_config_v2;
mod persistence;
mod template;
const DEFAULT_IP_PACKET_ROUTER_DIR: &str = "ip-packet-router";
/// Derive default path to ip packet routers' config directory.
/// It should get resolved to `$HOME/.nym/service-providers/ip-packet-router/<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_IP_PACKET_ROUTER_DIR)
.join(id)
.join(DEFAULT_CONFIG_DIR)
}
/// Derive default path to ip packet routers' config file.
/// It should get resolved to `$HOME/.nym/service-providers/ip-packet-router/<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 network requester's data directory where files, such as keys, are stored.
/// It should get resolved to `$HOME/.nym/service-providers/network-requester/<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_IP_PACKET_ROUTER_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 ip_packet_router: IpPacketRouter,
pub storage_paths: IpPacketRouterPaths,
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")),
ip_packet_router: Default::default(),
storage_paths: IpPacketRouterPaths::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 = IpPacketRouterPaths::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 IpPacketRouter {
/// Disable Poisson sending rate.
pub disable_poisson_rate: bool,
/// Specifies the url for an upstream source of the exit policy used by this node.
#[serde(deserialize_with = "de_maybe_stringified")]
pub upstream_exit_policy_url: Option<Url>,
}
impl Default for IpPacketRouter {
fn default() -> Self {
IpPacketRouter {
disable_poisson_rate: true,
#[allow(clippy::expect_used)]
upstream_exit_policy_url: Some(
mainnet::EXIT_POLICY_URL
.parse()
.expect("invalid default exit policy URL"),
),
}
}
}
@@ -1,101 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::config::persistence::IpPacketRouterPaths;
use crate::config::{default_config_filepath, IpPacketRouter};
use crate::error::IpPacketRouterError;
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::disk_persistence::old_v1_1_33::CommonClientPathsV1_1_33;
use nym_client_core::config::old_config_v1_1_33::ConfigV1_1_33 as BaseConfigV1_1_33;
use nym_config::read_config_from_toml_file;
use nym_config::serde_helpers::de_maybe_stringified;
use nym_network_defaults::mainnet;
use serde::{Deserialize, Serialize};
use std::io;
use std::path::{Path, PathBuf};
use url::Url;
use super::old_config_v2::ConfigV2;
#[derive(Debug, Deserialize, PartialEq, Eq, Serialize, Clone)]
pub struct IpPacketRouterPathsV1 {
#[serde(flatten)]
pub common_paths: CommonClientPathsV1_1_33,
/// Location of the file containing our description
pub ip_packet_router_description: PathBuf,
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV1 {
#[serde(flatten)]
pub base: BaseConfigV1_1_33,
#[serde(default)]
pub ip_packet_router: IpPacketRouterV1,
pub storage_paths: IpPacketRouterPathsV1,
pub logging: LoggingSettings,
}
impl TryFrom<ConfigV1> for ConfigV2 {
type Error = IpPacketRouterError;
fn try_from(value: ConfigV1) -> Result<Self, Self::Error> {
Ok(ConfigV2 {
base: value.base.into(),
ip_packet_router: value.ip_packet_router.into(),
storage_paths: IpPacketRouterPaths {
common_paths: value.storage_paths.common_paths.upgrade_default()?,
ip_packet_router_description: value.storage_paths.ip_packet_router_description,
},
logging: value.logging,
})
}
}
impl ConfigV1 {
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
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))
}
}
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct IpPacketRouterV1 {
/// Disable Poisson sending rate.
pub disable_poisson_rate: bool,
/// Specifies the url for an upstream source of the exit policy used by this node.
#[serde(deserialize_with = "de_maybe_stringified")]
pub upstream_exit_policy_url: Option<Url>,
}
impl Default for IpPacketRouterV1 {
fn default() -> Self {
IpPacketRouterV1 {
disable_poisson_rate: true,
#[allow(clippy::expect_used)]
upstream_exit_policy_url: Some(
mainnet::EXIT_POLICY_URL
.parse()
.expect("invalid default exit policy URL"),
),
}
}
}
impl From<IpPacketRouterV1> for IpPacketRouter {
fn from(value: IpPacketRouterV1) -> Self {
IpPacketRouter {
disable_poisson_rate: value.disable_poisson_rate,
upstream_exit_policy_url: value.upstream_exit_policy_url,
}
}
}
@@ -1,42 +0,0 @@
use std::{io, path::Path};
use crate::{config::Config, error::IpPacketRouterError};
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::config::old_config_v1_1_54::ConfigV1_1_54 as BaseConfigV1_1_54;
use nym_config::read_config_from_toml_file;
use serde::{Deserialize, Serialize};
use super::{default_config_filepath, IpPacketRouter, IpPacketRouterPaths};
#[derive(Debug, Clone, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct ConfigV2 {
#[serde(flatten)]
pub base: BaseConfigV1_1_54,
#[serde(default)]
pub ip_packet_router: IpPacketRouter,
pub storage_paths: IpPacketRouterPaths,
pub logging: LoggingSettings,
}
impl ConfigV2 {
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
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 try_upgrade(self) -> Result<Config, IpPacketRouterError> {
Ok(Config {
base: self.base.into(),
ip_packet_router: self.ip_packet_router,
storage_paths: self.storage_paths,
logging: self.logging,
})
}
}
@@ -1,97 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
pub(crate) const CONFIG_TEMPLATE: &str =
// While using normal toml marshalling would have been way simpler with less overhead,
// I think it's useful to have comments attached to the saved config file to explain behaviour of
// particular fields.
// Note: any changes to the template must be reflected in the appropriate structs.
r#"
# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
##### main base client config options #####
[client]
# Version of the client for which this configuration was created.
version = '{{ client.version }}'
# Human readable ID of this particular client.
id = '{{ client.id }}'
# Indicates whether this client is running in a disabled credentials mode, thus attempting
# to claim bandwidth without presenting bandwidth credentials.
disabled_credentials_mode = {{ client.disabled_credentials_mode }}
# Addresses to nyxd validators via which the client can communicate with the chain.
nyxd_urls = [
{{#each client.nyxd_urls }}
'{{this}}',
{{/each}}
]
# Addresses to APIs running on validator from which the client gets the view of the network.
nym_api_urls = [
{{#each client.nym_api_urls }}
'{{this}}',
{{/each}}
]
[storage_paths]
# Path to file containing private identity key.
keys.private_identity_key_file = '{{ storage_paths.keys.private_identity_key_file }}'
# Path to file containing public identity key.
keys.public_identity_key_file = '{{ storage_paths.keys.public_identity_key_file }}'
# Path to file containing private encryption key.
keys.private_encryption_key_file = '{{ storage_paths.keys.private_encryption_key_file }}'
# Path to file containing public encryption key.
keys.public_encryption_key_file = '{{ storage_paths.keys.public_encryption_key_file }}'
# Path to file containing key used for encrypting and decrypting the content of an
# acknowledgement so that nobody besides the client knows which packet it refers to.
keys.ack_key_file = '{{ storage_paths.keys.ack_key_file }}'
# Path to the database containing bandwidth credentials
credentials_database = '{{ storage_paths.credentials_database }}'
# Path to the persistent store for received reply surbs, unused encryption keys and used sender tags.
reply_surb_database = '{{ storage_paths.reply_surb_database }}'
# Path to the file containing information about gateways used by this client,
# i.e. details such as their public keys, owner addresses or the network information.
gateway_registrations = '{{ storage_paths.gateway_registrations }}'
# Location of the file containing our allow.list
allowed_list_location = '{{ storage_paths.allowed_list_location }}'
# Location of the file containing our unknown.list
unknown_list_location = '{{ storage_paths.unknown_list_location }}'
# Path to file containing description of this network-requester.
ip_packet_router_description = '{{ storage_paths.ip_packet_router_description }}'
##### logging configuration options #####
[logging]
# TODO
##### debug configuration options #####
# The following options should not be modified unless you know EXACTLY what you are doing
# as if set incorrectly, they may impact your anonymity.
[debug]
[debug.acknowledgements]
average_ack_delay = '{{ debug.acknowledgements.average_ack_delay }}'
[debug.cover_traffic]
loop_cover_traffic_average_delay = '{{ debug.cover_traffic.loop_cover_traffic_average_delay }}'
"#;
@@ -1,26 +0,0 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
#![warn(clippy::expect_used)]
#![warn(clippy::unwrap_used)]
#![warn(clippy::panic)]
#![cfg_attr(not(target_os = "linux"), allow(dead_code))]
#![cfg_attr(not(target_os = "linux"), allow(unused_imports))]
pub mod config;
pub mod error;
pub mod request_filter;
pub(crate) mod messages;
pub(crate) mod non_linux_dummy;
mod clients;
mod constants;
mod ip_packet_router;
mod mixnet_client;
mod mixnet_listener;
mod tun_listener;
mod util;
pub use crate::config::Config;
pub use ip_packet_router::{IpPacketRouter, OnStartData};
@@ -1,27 +0,0 @@
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
#[cfg(target_os = "linux")]
mod cli;
#[cfg(target_os = "linux")]
#[tokio::main]
async fn main() -> anyhow::Result<()> {
use clap::Parser;
let args = cli::Cli::parse();
nym_bin_common::logging::setup_tracing_logger();
nym_network_defaults::setup_env(args.config_env_file.as_ref());
if !args.no_banner {
nym_bin_common::logging::maybe_print_banner(clap::crate_name!(), clap::crate_version!());
}
cli::execute(args).await?;
Ok(())
}
#[cfg(not(target_os = "linux"))]
fn main() {
println!("This binary is currently only supported on linux");
}
@@ -1,66 +0,0 @@
# Copyright 2020 - Nym Technologies SA <contact@nymtech.net>
# SPDX-License-Identifier: GPL-3.0-only
[package]
name = "nym-network-requester"
license = "GPL-3.0"
version = "1.1.62"
authors.workspace = true
edition.workspace = true
rust-version = "1.70"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "nym_network_requester"
path = "src/lib.rs"
[dependencies]
anyhow = { workspace = true }
addr = { workspace = true }
async-trait = { workspace = true }
bs58 = { workspace = true }
clap = { workspace = true, features = ["cargo", "derive"]}
dirs = { workspace = true }
futures = { workspace = true }
humantime-serde = { workspace = true }
ipnetwork = { workspace = true }
log = { workspace = true }
publicsuffix = { workspace = true }
rand = { workspace = true }
regex = { workspace = true }
reqwest = { workspace = true, features = ["json"] }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
sqlx = { workspace = true, features = ["runtime-tokio-rustls", "chrono"]}
tap = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true, features = [ "net", "rt-multi-thread", "macros" ] }
tokio-tungstenite = { workspace = true }
url = { workspace = true }
time = { workspace = true }
zeroize = { workspace = true }
# internal
nym-async-file-watcher = { path = "../../common/async-file-watcher" }
nym-bin-common = { path = "../../common/bin-common", features = ["output_format", "clap", "basic_tracing"] }
nym-client-core = { path = "../../common/client-core", features = ["cli", "fs-gateways-storage", "fs-surb-storage"] }
nym-client-websocket-requests = { path = "../../clients/native/websocket-requests" }
nym-config = { path = "../../common/config" }
nym-credentials = { path = "../../common/credentials" }
nym-credential-storage = { path = "../../common/credential-storage" }
nym-crypto = { path = "../../common/crypto" }
nym-network-defaults = { path = "../../common/network-defaults" }
nym-ordered-buffer = { path = "../../common/socks5/ordered-buffer" }
nym-sdk = { path = "../../sdk/rust/nym-sdk" }
nym-service-providers-common = { path = "../common" }
nym-socks5-proxy-helpers = { path = "../../common/socks5/proxy-helpers" }
nym-socks5-requests = { path = "../../common/socks5/requests" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-task = { path = "../../common/task" }
nym-types = { path = "../../common/types" }
nym-exit-policy = { path = "../../common/exit-policy", features = ["client"] }
nym-id = { path = "../../common/nym-id" }
[dev-dependencies]
tempfile = { workspace = true }
@@ -1,42 +0,0 @@
Copyright 2022 - Nym Technologies SA <contact@nymtech.net>
SPDX-License-Identifier: GPL-3.0-only
-->
## License
Copyright (C) 2022 Nym Technologies SA <contact@nymtech.net>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
## Network requester
The network requester is used to interpret socks5 client messages that need to
be proxied to a running service i.e. a host and a port.
If you have a service that you want to expose to the mixnet, you'd need to
first run the native client and provide the client address to your users that
will use it in their socks5 configuration.
After starting the native client, start the network requester and configure it,
setting your service's endpoint in
`${HOME}/.nym/service-providers/network-requester/allowed.list`
Running in `open-proxy` mode allows any traffic to be proxied by the network
requester.
### Statistics service
The network requester can be ran as a gatherer of statistics for all
the services it proxies. For that, run the binary with the
`enable-statistics` flag enabled. Anonymized statistics are then sent to
a central server, through the mixnet.
@@ -1,2 +0,0 @@
[release]
address = "0.0.0.0"
@@ -1,74 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_sdk::mixnet::{
IncludedSurbs, MixnetClient, MixnetMessageSender, Recipient, ReconstructedMessage,
};
use nym_service_providers_common::interface::{
ProviderInterfaceVersion, Request, Response, ResponseContent,
};
use nym_socks5_requests::{QueryRequest, Socks5ProtocolVersion, Socks5Request, Socks5Response};
fn parse_response(received: Vec<ReconstructedMessage>) -> Socks5Response {
assert_eq!(received.len(), 1);
let response: Response<Socks5Request> = Response::try_from_bytes(&received[0].message).unwrap();
match response.content {
ResponseContent::Control(control) => panic!("unexpected control response: {control:?}"),
ResponseContent::ProviderData(data) => data,
}
}
async fn wait_for_response(client: &mut MixnetClient) -> Socks5Response {
loop {
let next = client.wait_for_messages().await.unwrap();
if !next.is_empty() {
return parse_response(next);
}
}
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
//nym_bin_common::logging::setup_logging();
let mut client = MixnetClient::connect_new().await.unwrap();
let provider: Recipient = "AN8eLxYWFitCkMn92zim3PrPszxJZDYyFFKP7qnnAAew.8UAxL3LwQBis6WpM3GGXaqKGaVdnLCpGJWumHT6KNdTH@77TSuVU8d1oXKbPzjec2xh4i3Wj5WwUyy9Lr36sm8gZm".parse().unwrap();
let open_proxy_request = Request::new_provider_data(
ProviderInterfaceVersion::new_current(),
Socks5Request::new_query(
Socks5ProtocolVersion::new_current(),
QueryRequest::OpenProxy,
),
);
let description_request = Request::new_provider_data(
ProviderInterfaceVersion::new_current(),
Socks5Request::new_query(
Socks5ProtocolVersion::new_current(),
QueryRequest::Description,
),
);
println!("Sending 'OpenProxy' query...");
client
.send_message(
provider,
open_proxy_request.into_bytes(),
IncludedSurbs::new(10),
)
.await?;
let response = wait_for_response(&mut client).await;
println!("response to 'OpenProxy' query: {response:#?}");
println!("Sending 'Description' query...");
client
.send_message(
provider,
description_request.into_bytes(),
IncludedSurbs::none(),
)
.await?;
let response = wait_for_response(&mut client).await;
println!("response to 'Description' query: {response:#?}");
client.disconnect().await;
Ok(())
}
@@ -1,30 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_add_gateway::{add_gateway, CommonClientAddGatewayArgs};
#[derive(clap::Args)]
pub(crate) struct Args {
#[command(flatten)]
common_args: CommonClientAddGatewayArgs,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl AsRef<CommonClientAddGatewayArgs> for Args {
fn as_ref(&self) -> &CommonClientAddGatewayArgs {
&self.common_args
}
}
pub(crate) async fn execute(args: Args) -> Result<(), NetworkRequesterError> {
let output = args.output;
let res = add_gateway::<CliNetworkRequesterClient, _>(args, None).await?;
println!("{}", output.format(&res));
Ok(())
}
@@ -1,16 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use clap::Args;
use nym_bin_common::bin_info_owned;
use nym_bin_common::output_format::OutputFormat;
#[derive(Args)]
pub(crate) struct BuildInfo {
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
pub(crate) fn execute(args: BuildInfo) {
println!("{}", args.output.format(&bin_info_owned!()))
}
@@ -1,16 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_client_core::cli_helpers::client_import_coin_index_signatures::{
import_coin_index_signatures, CommonClientImportCoinIndexSignaturesArgs,
};
pub(crate) async fn execute(
args: CommonClientImportCoinIndexSignaturesArgs,
) -> Result<(), NetworkRequesterError> {
import_coin_index_signatures::<CliNetworkRequesterClient, _>(args).await?;
println!("successfully imported coin index signatures!");
Ok(())
}
@@ -1,14 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_client_core::cli_helpers::client_import_credential::{
import_credential, CommonClientImportTicketBookArgs,
};
pub async fn execute(args: CommonClientImportTicketBookArgs) -> Result<(), NetworkRequesterError> {
import_credential::<CliNetworkRequesterClient, _>(args).await?;
println!("successfully imported credential!");
Ok(())
}
@@ -1,16 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::{
import_expiration_date_signatures, CommonClientImportExpirationDateSignaturesArgs,
};
pub(crate) async fn execute(
args: CommonClientImportExpirationDateSignaturesArgs,
) -> Result<(), NetworkRequesterError> {
import_expiration_date_signatures::<CliNetworkRequesterClient, _>(args).await?;
println!("successfully imported expiration date signatures!");
Ok(())
}
@@ -1,16 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_client_core::cli_helpers::client_import_master_verification_key::{
import_master_verification_key, CommonClientImportMasterVerificationKeyArgs,
};
pub(crate) async fn execute(
args: CommonClientImportMasterVerificationKeyArgs,
) -> Result<(), NetworkRequesterError> {
import_master_verification_key::<CliNetworkRequesterClient, _>(args).await?;
println!("successfully imported master verification key!");
Ok(())
}
@@ -1,59 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::NetworkRequesterError;
use clap::{Args, Subcommand};
use nym_client_core::cli_helpers::client_import_coin_index_signatures::CommonClientImportCoinIndexSignaturesArgs;
use nym_client_core::cli_helpers::client_import_credential::CommonClientImportTicketBookArgs;
use nym_client_core::cli_helpers::client_import_expiration_date_signatures::CommonClientImportExpirationDateSignaturesArgs;
use nym_client_core::cli_helpers::client_import_master_verification_key::CommonClientImportMasterVerificationKeyArgs;
pub(crate) mod import_coin_index_signatures;
pub(crate) mod import_credential;
pub(crate) mod import_expiration_date_signatures;
pub(crate) mod import_master_verification_key;
pub(crate) mod show_ticketbooks;
#[derive(Args)]
#[clap(args_conflicts_with_subcommands = true, subcommand_required = true)]
pub struct Ecash {
#[clap(subcommand)]
pub command: EcashCommands,
}
impl Ecash {
pub async fn execute(self) -> Result<(), NetworkRequesterError> {
match self.command {
EcashCommands::ShowTicketBooks(args) => show_ticketbooks::execute(args).await?,
EcashCommands::ImportTicketBook(args) => import_credential::execute(args).await?,
EcashCommands::ImportCoinIndexSignatures(args) => {
import_coin_index_signatures::execute(args).await?
}
EcashCommands::ImportExpirationDateSignatures(args) => {
import_expiration_date_signatures::execute(args).await?
}
EcashCommands::ImportMasterVerificationKey(args) => {
import_master_verification_key::execute(args).await?
}
}
Ok(())
}
}
#[derive(Subcommand)]
pub enum EcashCommands {
/// Display information associated with the imported ticketbooks,
ShowTicketBooks(show_ticketbooks::Args),
/// Import a pre-generated ticketbook
ImportTicketBook(CommonClientImportTicketBookArgs),
/// Import coin index signatures needed for ticketbooks
ImportCoinIndexSignatures(CommonClientImportCoinIndexSignaturesArgs),
/// Import expiration date signatures needed for ticketbooks
ImportExpirationDateSignatures(CommonClientImportExpirationDateSignaturesArgs),
/// Import master verification key needed for ticketbooks
ImportMasterVerificationKey(CommonClientImportMasterVerificationKeyArgs),
}
@@ -1,32 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_show_ticketbooks::{
show_ticketbooks, CommonShowTicketbooksArgs,
};
#[derive(clap::Args)]
pub(crate) struct Args {
#[command(flatten)]
common_args: CommonShowTicketbooksArgs,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl AsRef<CommonShowTicketbooksArgs> for Args {
fn as_ref(&self) -> &CommonShowTicketbooksArgs {
&self.common_args
}
}
pub(crate) async fn execute(args: Args) -> Result<(), NetworkRequesterError> {
let output = args.output;
let res = show_ticketbooks::<CliNetworkRequesterClient, _>(args).await?;
println!("{}", output.format(&res));
Ok(())
}
@@ -1,112 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::CliNetworkRequesterClient;
use crate::config::{default_config_directory, default_config_filepath, default_data_directory};
use crate::{
cli::{override_config, OverrideConfig},
config::Config,
error::NetworkRequesterError,
};
use clap::Args;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_init::{
initialise_client, CommonClientInitArgs, InitResultsWithConfig, InitialisableClient,
};
use serde::Serialize;
use std::fmt::Display;
use std::fs;
use std::path::PathBuf;
impl InitialisableClient for CliNetworkRequesterClient {
type InitArgs = Init;
fn initialise_storage_paths(id: &str) -> Result<(), Self::Error> {
fs::create_dir_all(default_data_directory(id))?;
fs::create_dir_all(default_config_directory(id))?;
Ok(())
}
fn default_config_path(id: &str) -> PathBuf {
default_config_filepath(id)
}
fn construct_config(init_args: &Self::InitArgs) -> Self::Config {
override_config(
Config::new(&init_args.common_args.id),
OverrideConfig::from(init_args.clone()),
)
}
}
#[derive(Args, Clone, Debug)]
pub(crate) struct Init {
#[command(flatten)]
common_args: CommonClientInitArgs,
/// Specifies whether this network requester should run in 'open-proxy' mode
#[clap(long)]
open_proxy: Option<bool>,
#[clap(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl From<Init> for OverrideConfig {
fn from(init_config: Init) -> Self {
OverrideConfig {
nym_apis: init_config.common_args.nym_apis,
fastmode: init_config.common_args.fastmode,
no_cover: init_config.common_args.no_cover,
medium_toggle: false,
nyxd_urls: init_config.common_args.nyxd_urls,
enabled_credentials_mode: init_config.common_args.enabled_credentials_mode,
open_proxy: init_config.open_proxy,
}
}
}
impl AsRef<CommonClientInitArgs> for Init {
fn as_ref(&self) -> &CommonClientInitArgs {
&self.common_args
}
}
#[derive(Debug, Serialize)]
pub struct InitResults {
#[serde(flatten)]
client_core: nym_client_core::init::types::InitResults,
client_address: String,
}
impl InitResults {
fn new(res: InitResultsWithConfig<Config>) -> Self {
Self {
client_address: res.init_results.address.to_string(),
client_core: res.init_results,
}
}
}
impl Display for InitResults {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", self.client_core)?;
write!(
f,
"Address of this network-requester: {}",
self.client_address
)
}
}
pub(crate) async fn execute(args: Init) -> Result<(), NetworkRequesterError> {
eprintln!("Initialising client...");
let output = args.output;
let res = initialise_client::<CliNetworkRequesterClient>(args, None).await?;
let init_results = InitResults::new(res);
println!("{}", output.format(&init_results));
Ok(())
}
@@ -1,32 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::cli_helpers::client_list_gateways::{
list_gateways, CommonClientListGatewaysArgs,
};
#[derive(clap::Args)]
pub(crate) struct Args {
#[command(flatten)]
common_args: CommonClientListGatewaysArgs,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
impl AsRef<CommonClientListGatewaysArgs> for Args {
fn as_ref(&self) -> &CommonClientListGatewaysArgs {
&self.common_args
}
}
pub(crate) async fn execute(args: Args) -> Result<(), NetworkRequesterError> {
let output = args.output;
let res = list_gateways::<CliNetworkRequesterClient, _>(args).await?;
println!("{}", output.format(&res));
Ok(())
}
@@ -1,197 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::ecash::Ecash;
use crate::config::helpers::try_upgrade_config_by_id;
use crate::{
config::{BaseClientConfig, Config},
error::NetworkRequesterError,
};
use clap::{CommandFactory, Parser, Subcommand};
use log::error;
use nym_bin_common::bin_info;
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_client_core::cli_helpers::CliClient;
use nym_config::OptionalSet;
use std::sync::OnceLock;
mod add_gateway;
mod build_info;
pub mod ecash;
mod init;
mod list_gateways;
mod run;
mod sign;
mod switch_gateway;
pub(crate) struct CliNetworkRequesterClient;
impl CliClient for CliNetworkRequesterClient {
const NAME: &'static str = "network requester";
type Error = NetworkRequesterError;
type Config = Config;
async fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> {
try_upgrade_config_by_id(id).await
}
async fn try_load_current_config(id: &str) -> Result<Self::Config, Self::Error> {
try_load_current_config(id).await
}
}
fn pretty_build_info_static() -> &'static str {
static PRETTY_BUILD_INFORMATION: OnceLock<String> = OnceLock::new();
PRETTY_BUILD_INFORMATION.get_or_init(|| bin_info!().pretty_print())
}
#[derive(Parser)]
#[command(author = "Nymtech", version, about, long_version = pretty_build_info_static())]
pub(crate) struct Cli {
/// Path pointing to an env file that configures the client.
#[arg(short, long)]
pub(crate) config_env_file: Option<std::path::PathBuf>,
/// Flag used for disabling the printed banner in tty.
#[arg(long)]
pub(crate) no_banner: bool,
#[command(subcommand)]
command: Commands,
}
#[allow(clippy::large_enum_variant)]
#[derive(Subcommand)]
pub(crate) enum Commands {
/// Initialize a network-requester. Do this first!
Init(init::Init),
/// Run the network requester with the provided configuration and optionally override
/// parameters.
Run(run::Run),
/// Ecash-related functionalities
Ecash(Ecash),
/// Sign to prove ownership of this network requester
Sign(sign::Sign),
/// List all registered with gateways
ListGateways(list_gateways::Args),
/// Add new gateway to this client
AddGateway(add_gateway::Args),
/// Change the currently active gateway. Note that you must have already registered with the new gateway!
SwitchGateway(switch_gateway::Args),
/// Show build information of this binary
BuildInfo(build_info::BuildInfo),
/// Generate shell completions
Completions(ArgShell),
/// Generate Fig specification
GenerateFigSpec,
}
// Configuration that can be overridden.
pub(crate) struct OverrideConfig {
nym_apis: Option<Vec<url::Url>>,
fastmode: bool,
no_cover: bool,
medium_toggle: bool,
nyxd_urls: Option<Vec<url::Url>>,
enabled_credentials_mode: Option<bool>,
open_proxy: Option<bool>,
}
// NOTE: make sure this is in sync with `gateway/src/helpers.rs::override_network_requester_config`
pub(crate) fn override_config(mut config: Config, args: OverrideConfig) -> Config {
// in the old code we had calls to `assert` thus panicking
config
.base
.try_apply_traffic_modes(
config.network_requester.disable_poisson_rate,
args.medium_toggle,
args.fastmode,
args.no_cover,
)
.expect("failed to apply traffic modes");
config
.with_optional_base_custom_env(
BaseClientConfig::with_custom_nym_apis,
args.nym_apis,
nym_network_defaults::var_names::NYM_API,
nym_config::parse_urls,
)
.with_optional_base_custom_env(
BaseClientConfig::with_custom_nyxd,
args.nyxd_urls,
nym_network_defaults::var_names::NYXD,
nym_config::parse_urls,
)
.with_optional_base(
BaseClientConfig::with_disabled_credentials,
args.enabled_credentials_mode.map(|b| !b),
)
.with_optional(Config::with_open_proxy, args.open_proxy)
}
pub(crate) async fn execute(args: Cli) -> Result<(), NetworkRequesterError> {
let bin_name = "nym-network-requester";
match args.command {
Commands::Init(m) => init::execute(m).await?,
Commands::Run(m) => run::execute(&m).await?,
Commands::Ecash(ecash) => ecash.execute().await?,
Commands::Sign(m) => sign::execute(&m).await?,
Commands::ListGateways(args) => list_gateways::execute(args).await?,
Commands::AddGateway(args) => add_gateway::execute(args).await?,
Commands::SwitchGateway(args) => switch_gateway::execute(args).await?,
Commands::BuildInfo(m) => build_info::execute(m),
Commands::Completions(s) => s.generate(&mut Cli::command(), bin_name),
Commands::GenerateFigSpec => fig_generate(&mut Cli::command(), bin_name),
}
Ok(())
}
async fn try_load_current_config(id: &str) -> Result<Config, NetworkRequesterError> {
// try to load the config as is
if let Ok(cfg) = Config::read_from_default_path(id) {
return if !cfg.validate() {
Err(NetworkRequesterError::ConfigValidationFailure)
} else {
Ok(cfg)
};
}
// we couldn't load it - try upgrading it from older revisions
try_upgrade_config_by_id(id).await?;
let config = match Config::read_from_default_path(id) {
Ok(cfg) => cfg,
Err(err) => {
error!("Failed to load config for {id}. Are you sure you have run `init` before? (Error was: {err})");
return Err(NetworkRequesterError::FailedToLoadConfig(id.to_string()));
}
};
if !config.validate() {
return Err(NetworkRequesterError::ConfigValidationFailure);
}
Ok(config)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn verify_cli() {
Cli::command().debug_assert();
}
}
@@ -1,67 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::try_load_current_config;
use crate::{
cli::{override_config, OverrideConfig},
error::NetworkRequesterError,
};
use clap::Args;
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs;
#[allow(clippy::struct_excessive_bools)]
#[derive(Args, Clone)]
pub(crate) struct Run {
#[command(flatten)]
common_args: CommonClientRunArgs,
/// Specifies whether this network requester should run in 'open-proxy' mode
#[arg(long)]
open_proxy: Option<bool>,
/// Enable medium mixnet traffic, for experiments only.
/// This includes things like disabling cover traffic, no per hop delays, etc.
#[arg(
long,
hide = true,
conflicts_with = "no_cover",
conflicts_with = "fastmode"
)]
medium_toggle: bool,
}
impl From<Run> for OverrideConfig {
fn from(run_config: Run) -> Self {
OverrideConfig {
nym_apis: None,
fastmode: run_config.common_args.fastmode,
no_cover: run_config.common_args.no_cover,
medium_toggle: run_config.medium_toggle,
nyxd_urls: run_config.common_args.nyxd_urls,
enabled_credentials_mode: run_config.common_args.enabled_credentials_mode,
open_proxy: run_config.open_proxy,
}
}
}
pub(crate) async fn execute(args: &Run) -> Result<(), NetworkRequesterError> {
let mut config = try_load_current_config(&args.common_args.id).await?;
config = override_config(config, OverrideConfig::from(args.clone()));
log::debug!("Using config: {config:#?}");
if config.network_requester.open_proxy {
println!(
"\n\nYOU HAVE STARTED IN 'OPEN PROXY' MODE. ANYONE WITH YOUR CLIENT ADDRESS \
CAN MAKE REQUESTS FROM YOUR MACHINE. PLEASE QUIT IF YOU DON'T UNDERSTAND WHAT \
YOU'RE DOING.\n\n"
);
}
log::info!("Starting socks5 service provider");
let mut server = crate::core::NRServiceProviderBuilder::new(config);
if let Some(custom_mixnet) = &args.common_args.custom_mixnet {
server = server.with_stored_topology(custom_mixnet)?
}
server.run_service_provider().await
}
@@ -1,74 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::cli::try_load_current_config;
use crate::error::NetworkRequesterError;
use clap::Args;
use nym_bin_common::output_format::OutputFormat;
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::error::ClientCoreError;
use nym_crypto::asymmetric::ed25519;
use nym_types::helpers::ConsoleSigningOutput;
#[derive(Args, Clone)]
pub(crate) struct Sign {
/// The id of the mixnode you want to sign with
#[arg(long)]
id: String,
/// Signs a transaction-specific payload, that is going to be sent to the smart contract, with your identity key
#[arg(long)]
contract_msg: String,
#[arg(short, long, default_value_t = OutputFormat::default())]
output: OutputFormat,
}
fn print_signed_contract_msg(
private_key: &ed25519::PrivateKey,
raw_msg: &str,
output: OutputFormat,
) {
let trimmed = raw_msg.trim();
eprintln!(">>> attempting to sign {trimmed}");
let Ok(decoded) = bs58::decode(trimmed).into_vec() else {
println!("it seems you have incorrectly copied the message to sign. Make sure you didn't accidentally skip any characters");
return;
};
eprintln!(">>> decoding the message...");
// we don't really care about what particular information is embedded inside of it,
// we just want to know if user correctly copied the string, i.e. whether it's a valid bs58 encoded json
if serde_json::from_slice::<serde_json::Value>(&decoded).is_err() {
println!("it seems you have incorrectly copied the message to sign. Make sure you didn't accidentally skip any characters");
return;
};
// if this is a valid json, it MUST be a valid string
let decoded_string = String::from_utf8(decoded.clone()).unwrap();
let signature = private_key.sign(&decoded).to_base58_string();
let sign_output = ConsoleSigningOutput::new(decoded_string, signature);
println!("{}", output.format(&sign_output));
}
pub(crate) async fn execute(args: &Sign) -> Result<(), NetworkRequesterError> {
let config = try_load_current_config(&args.id).await?;
let key_store = OnDiskKeys::new(config.storage_paths.common_paths.keys);
let identity_keypair = key_store.load_identity_keypair().map_err(|source| {
NetworkRequesterError::ClientCoreError(ClientCoreError::KeyStoreError {
source: Box::new(source),
})
})?;
print_signed_contract_msg(
identity_keypair.private_key(),
&args.contract_msg,
args.output,
);
Ok(())
}
@@ -1,24 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::cli::CliNetworkRequesterClient;
use crate::error::NetworkRequesterError;
use nym_client_core::cli_helpers::client_switch_gateway::{
switch_gateway, CommonClientSwitchGatewaysArgs,
};
#[derive(clap::Args, Clone, Debug)]
pub struct Args {
#[command(flatten)]
common_args: CommonClientSwitchGatewaysArgs,
}
impl AsRef<CommonClientSwitchGatewaysArgs> for Args {
fn as_ref(&self) -> &CommonClientSwitchGatewaysArgs {
&self.common_args
}
}
pub(crate) async fn execute(args: Args) -> Result<(), NetworkRequesterError> {
switch_gateway::<CliNetworkRequesterClient, _>(args).await
}
@@ -1,216 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::default_config_filepath;
use crate::config::old::v6::ConfigV6;
use crate::config::old_config_v1_1_13::OldConfigV1;
use crate::config::old_config_v1_1_20::ConfigV2;
use crate::config::old_config_v1_1_20_2::ConfigV3;
use crate::config::old_config_v1_1_33::ConfigV4;
use crate::config::old_config_v1_1_54::ConfigV5;
use crate::config::Config;
use crate::error::NetworkRequesterError;
use log::{info, trace};
use nym_client_core::cli_helpers::CliClientConfig;
use nym_client_core::client::base_client::storage::migration_helpers::v1_1_33;
use std::path::Path;
async fn try_upgrade_v1_config<P: AsRef<Path>>(
config_path: P,
) -> Result<bool, NetworkRequesterError> {
trace!("Trying to load as v1.1.13 config");
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
// explicitly load it as v1.1.13 (which is incompatible with the next step, i.e. 1.1.19)
let Ok(old_config) = OldConfigV1::load_from_filepath(config_path.as_ref()) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v1.1.13 config template.");
info!("It is going to get updated to the current specification.");
let updated_step1: ConfigV2 = old_config.into();
let updated_step2: ConfigV3 = updated_step1.into();
let (updated_step3, gateway_config) = updated_step2.upgrade()?;
let old_paths = updated_step3.storage_paths.clone();
let updated_step4 = updated_step3.try_upgrade()?;
v1_1_33::migrate_gateway_details(
&old_paths.common_paths,
&updated_step4.storage_paths.common_paths,
Some(gateway_config),
)
.await?;
let updated_step5: ConfigV6 = updated_step4.into();
let updated: Config = updated_step5.into();
updated.save_to(config_path)?;
Ok(true)
}
async fn try_upgrade_v2_config<P: AsRef<Path>>(
config_path: P,
) -> Result<bool, NetworkRequesterError> {
trace!("Trying to load as v1.1.20 config");
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
// explicitly load it as v1.1.20 (which is incompatible with the current one, i.e. +1.1.21)
let Ok(old_config) = ConfigV2::load_from_filepath(config_path.as_ref()) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v1.1.20 config template.");
info!("It is going to get updated to the current specification.");
let updated_step1: ConfigV3 = old_config.into();
let (updated_step2, gateway_config) = updated_step1.upgrade()?;
let old_paths = updated_step2.storage_paths.clone();
let updated_step3 = updated_step2.try_upgrade()?;
v1_1_33::migrate_gateway_details(
&old_paths.common_paths,
&updated_step3.storage_paths.common_paths,
Some(gateway_config),
)
.await?;
let updated_step4: ConfigV6 = updated_step3.into();
let updated: Config = updated_step4.into();
updated.save_to(config_path)?;
Ok(true)
}
async fn try_upgrade_v3_config<P: AsRef<Path>>(
config_path: P,
) -> Result<bool, NetworkRequesterError> {
trace!("Trying to load as v1.1.20_2 config");
// explicitly load it as v1.1.20_2 (which is incompatible with the current one, i.e. +1.1.21)
let Ok(old_config) = ConfigV3::read_from_toml_file(config_path.as_ref()) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v1.1.20_2 config template.");
info!("It is going to get updated to the current specification.");
let (updated_step1, gateway_config) = old_config.upgrade()?;
let old_paths = updated_step1.storage_paths.clone();
let updated_step2 = updated_step1.try_upgrade()?;
v1_1_33::migrate_gateway_details(
&old_paths.common_paths,
&updated_step2.storage_paths.common_paths,
Some(gateway_config),
)
.await?;
let updated_step3: ConfigV6 = updated_step2.into();
let updated: Config = updated_step3.into();
updated.save_to(config_path)?;
Ok(true)
}
async fn try_upgrade_v4_config<P: AsRef<Path>>(
config_path: P,
) -> Result<bool, NetworkRequesterError> {
trace!("Trying to load as v1.1.33 config");
// explicitly load it as v1.1.33 (which is incompatible with the current one, i.e. +1.1.34)
let Ok(old_config) = ConfigV4::read_from_toml_file(config_path.as_ref()) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v1.1.33 config template.");
info!("It is going to get updated to the current specification.");
let old_paths = old_config.storage_paths.clone();
let updated_step1 = old_config.try_upgrade()?;
v1_1_33::migrate_gateway_details(
&old_paths.common_paths,
&updated_step1.storage_paths.common_paths,
None,
)
.await?;
let updated_step2: ConfigV6 = updated_step1.into();
let updated: Config = updated_step2.into();
updated.save_to(config_path)?;
Ok(true)
}
async fn try_upgrade_v5_config<P: AsRef<Path>>(
config_path: P,
) -> Result<bool, NetworkRequesterError> {
// explicitly load it as v5 (which is incompatible with the current one)
let Ok(old_config) = ConfigV5::read_from_toml_file(config_path.as_ref()) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v5 config template.");
info!("It is going to get updated to the current specification.");
let updated_step1: ConfigV6 = old_config.into();
let updated: Config = updated_step1.into();
updated.save_to(config_path)?;
Ok(true)
}
async fn try_upgrade_v6_config<P: AsRef<Path>>(
config_path: P,
) -> Result<bool, NetworkRequesterError> {
// explicitly load it as v6 (which is incompatible with the current one)
let Ok(old_config) = ConfigV6::read_from_toml_file(config_path.as_ref()) else {
// if we failed to load it, there might have been nothing to upgrade
// or maybe it was an even older file. in either way. just ignore it and carry on with our day
return Ok(false);
};
info!("It seems the client is using <= v6 config template.");
info!("It is going to get updated to the current specification.");
let updated: Config = old_config.into();
updated.save_to(config_path)?;
Ok(true)
}
pub async fn try_upgrade_config<P: AsRef<Path>>(
config_path: P,
) -> Result<(), NetworkRequesterError> {
trace!("Attempting to upgrade config");
if try_upgrade_v1_config(config_path.as_ref()).await? {
return Ok(());
}
if try_upgrade_v2_config(config_path.as_ref()).await? {
return Ok(());
}
if try_upgrade_v3_config(config_path.as_ref()).await? {
return Ok(());
}
if try_upgrade_v4_config(config_path.as_ref()).await? {
return Ok(());
}
if try_upgrade_v5_config(config_path.as_ref()).await? {
return Ok(());
}
if try_upgrade_v6_config(config_path).await? {
return Ok(());
}
Ok(())
}
pub async fn try_upgrade_config_by_id(id: &str) -> Result<(), NetworkRequesterError> {
try_upgrade_config(default_config_filepath(id)).await
}
@@ -1,251 +0,0 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: GPL-3.0-only
use crate::config::template::CONFIG_TEMPLATE;
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::cli_helpers::CliClientConfig;
use nym_client_core::config::disk_persistence::CommonClientPaths;
use nym_config::{
must_get_home, read_config_from_toml_file, save_formatted_config_to_file,
serde_helpers::de_maybe_stringified, NymConfigTemplate, OptionalSet, DEFAULT_CONFIG_DIR,
DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
};
use nym_network_defaults::mainnet;
use nym_service_providers_common::DEFAULT_SERVICE_PROVIDERS_DIR;
use serde::{Deserialize, Serialize};
use std::io;
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::time::Duration;
use url::Url;
pub use crate::config::persistence::NetworkRequesterPaths;
pub use nym_client_core::config::Config as BaseClientConfig;
pub mod helpers;
pub mod old;
mod persistence;
mod template;
// aliases for backwards compatibility
pub use old::v1 as old_config_v1_1_13;
pub use old::v2 as old_config_v1_1_20;
pub use old::v3 as old_config_v1_1_20_2;
pub use old::v4 as old_config_v1_1_33;
pub use old::v5 as old_config_v1_1_54;
const DEFAULT_NETWORK_REQUESTERS_DIR: &str = "network-requester";
pub const DEFAULT_STANDARD_LIST_UPDATE_INTERVAL: Duration = Duration::from_secs(30 * 60);
/// Derive default path to network requester's config directory.
/// It should get resolved to `$HOME/.nym/service-providers/network-requester/<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_NETWORK_REQUESTERS_DIR)
.join(id)
.join(DEFAULT_CONFIG_DIR)
}
/// Derive default path to network requester's config file.
/// It should get resolved to `$HOME/.nym/service-providers/network-requester/<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 network requester's data directory where files, such as keys, are stored.
/// It should get resolved to `$HOME/.nym/service-providers/network-requester/<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_NETWORK_REQUESTERS_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 network_requester: NetworkRequester,
pub storage_paths: NetworkRequesterPaths,
#[serde(default)]
pub network_requester_debug: Debug,
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")),
network_requester: Default::default(),
storage_paths: NetworkRequesterPaths::new_base(default_data_directory(id.as_ref())),
network_requester_debug: Default::default(),
logging: Default::default(),
}
}
// this is a false positive, this method is actually called when used as a library
// but clippy complains about it when building the binary
#[allow(unused)]
pub fn with_data_directory<P: AsRef<Path>>(mut self, data_directory: P) -> Self {
self.storage_paths = NetworkRequesterPaths::new_base(data_directory);
self
}
pub fn read_from_toml_file<P: AsRef<Path>>(path: P) -> io::Result<Self> {
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(dead_code)]
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()
}
#[must_use]
pub fn with_open_proxy(mut self, open_proxy: bool) -> Self {
self.network_requester.open_proxy = open_proxy;
self
}
// 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
}
#[allow(unused)]
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)]
pub struct NetworkRequester {
/// specifies whether this network requester should run in 'open-proxy' mode
/// and thus would attempt to resolve **ANY** request it receives.
pub open_proxy: bool,
/// Disable Poisson sending rate.
/// This is equivalent to setting debug.traffic.disable_main_poisson_packet_distribution = true,
pub disable_poisson_rate: bool,
/// Specifies the url for an upstream source of the exit policy used by this node.
#[serde(deserialize_with = "de_maybe_stringified")]
pub upstream_exit_policy_url: Option<Url>,
}
impl Default for NetworkRequester {
fn default() -> Self {
NetworkRequester {
open_proxy: false,
disable_poisson_rate: true,
upstream_exit_policy_url: Some(
mainnet::EXIT_POLICY_URL
.parse()
.expect("invalid default exit policy URL"),
),
}
}
}
#[derive(Debug, Clone, Copy, Deserialize, PartialEq, Serialize)]
#[serde(default, deny_unknown_fields)]
pub struct Debug {
/// Defines how often the standard allow list should get updated
/// Deprecated
#[serde(with = "humantime_serde")]
pub standard_list_update_interval: Duration,
}
impl Default for Debug {
fn default() -> Self {
Debug {
standard_list_update_interval: DEFAULT_STANDARD_LIST_UPDATE_INTERVAL,
}
}
}
@@ -1,9 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod v1;
pub mod v2;
pub mod v3;
pub mod v4;
pub mod v5;
pub mod v6;
@@ -1,35 +0,0 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::config::old_config_v1_1_20::ConfigV2;
use nym_client_core::config::old_config_v1_1_13::OldConfigV1_1_13 as OldBaseConfigV1_1_13;
use nym_config::legacy_helpers::nym_config::MigrationNymConfig;
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct OldConfigV1 {
#[serde(flatten)]
pub base: OldBaseConfigV1_1_13<OldConfigV1>,
}
impl MigrationNymConfig for OldConfigV1 {
fn default_root_directory() -> PathBuf {
dirs::home_dir()
.expect("Failed to evaluate $HOME value")
.join(".nym")
.join("../../../..")
.join("network-requester")
}
}
impl From<OldConfigV1> for ConfigV2 {
fn from(value: OldConfigV1) -> Self {
ConfigV2 {
base: value.base.into(),
network_requester: Default::default(),
network_requester_debug: Default::default(),
}
}
}

Some files were not shown because too many files have changed in this diff Show More