Standalone ip-packet-router (#4342)

* Initial copy of code from network-requester

* Fix unused

* Fix reading nym-api

* Log env setup steps

* rustfmt

* fix

* Fix unused

* Log number of retransmissions instead of rate
This commit is contained in:
Jon Häggblad
2024-01-30 13:15:34 +01:00
committed by GitHub
parent 914c586e68
commit b874fc9314
25 changed files with 642 additions and 23 deletions
Generated
+7
View File
@@ -6673,21 +6673,27 @@ name = "nym-ip-packet-router"
version = "0.1.0"
dependencies = [
"bincode",
"bs58 0.4.0",
"bytes",
"clap 4.4.7",
"etherparse",
"futures",
"lazy_static",
"log",
"nym-bin-common",
"nym-client-core",
"nym-config",
"nym-crypto",
"nym-exit-policy",
"nym-ip-packet-requests",
"nym-network-defaults",
"nym-network-requester",
"nym-sdk",
"nym-service-providers-common",
"nym-sphinx",
"nym-task",
"nym-tun",
"nym-types",
"nym-wireguard",
"nym-wireguard-types",
"rand 0.8.5",
@@ -6846,6 +6852,7 @@ dependencies = [
"cfg-if",
"dotenvy",
"hex-literal",
"log",
"once_cell",
"schemars",
"serde",
+1 -1
View File
@@ -51,7 +51,7 @@ impl InitialisableClient for NativeClientInit {
}
}
#[derive(Args, Clone)]
#[derive(Args, Clone, Debug)]
pub(crate) struct Init {
#[command(flatten)]
common_args: CommonClientInitArgs,
+1 -1
View File
@@ -51,7 +51,7 @@ impl InitialisableClient for Socks5ClientInit {
}
}
#[derive(Args, Clone)]
#[derive(Args, Clone, Debug)]
pub(crate) struct Init {
#[command(flatten)]
common_args: CommonClientInitArgs,
@@ -109,6 +109,8 @@ pub async fn initialise_client<C>(
) -> Result<InitResultsWithConfig<C::Config>, C::Error>
where
C: InitialisableClient,
<C as InitialisableClient>::Config: std::fmt::Debug,
<C as InitialisableClient>::InitArgs: std::fmt::Debug,
{
info!("initialising {} client", C::NAME);
@@ -140,17 +142,32 @@ where
// Attempt to use a user-provided gateway, if possible
let user_chosen_gateway_id = common_args.gateway;
log::debug!("User chosen gateway id: {user_chosen_gateway_id:?}");
let selection_spec = GatewaySelectionSpecification::new(
user_chosen_gateway_id.map(|id| id.to_base58_string()),
Some(common_args.latency_based_selection),
false,
);
log::debug!("Gateway selection specification: {selection_spec:?}");
// Load and potentially override config
log::debug!("Init arguments: {init_args:#?}");
let config = C::construct_config(&init_args);
log::debug!("Constructed config: {config:#?}");
let paths = config.common_paths();
let core = config.core_config();
log::info!(
"Using nym-api: {}",
core.client
.nym_api_urls
.iter()
.map(|url| url.as_str())
.collect::<Vec<&str>>()
.join(",")
);
// Setup gateway by either registering a new one, or creating a new config from the selected
// one but with keys kept, or reusing the gateway configuration.
let key_store = OnDiskKeys::new(paths.keys.clone());
@@ -13,8 +13,9 @@ const PACKET_REPORT_INTERVAL_SECS: u64 = 2;
const SNAPSHOT_INTERVAL_MS: u64 = 500;
// When computing rates, we include snapshots that are up to this old. We set it to some odd number
// a tad larger than an integer number of snapshot intervals, so that we don't have to worry about
// threshold effects
const RECORDING_WINDOW_MS: u64 = 1700;
// threshold effects.
// Also, set it larger than the packet report interval so that we don't miss notable singular events
const RECORDING_WINDOW_MS: u64 = 2300;
#[derive(Default, Debug, Clone)]
struct PacketStatistics {
@@ -434,10 +435,18 @@ impl PacketStatisticsControl {
// If we get a burst of retransmissions
// TODO: consider making this the number of retransmissions since last report instead.
if latest_rates.retransmissions_queued > 0.0 {
log::info!(
"retransmissions: {} pkt/s",
log::debug!(
"retransmissions: {:.2} pkt/s",
latest_rates.retransmissions_queued
);
// Check what the number of retransmissions was during the recording window
if let Some((_, start_stats)) = self.history.front() {
let delta = self.stats.clone() - start_stats.clone();
log::info!("retransmissions: {}", delta.retransmissions_queued,);
} else {
log::warn!("Unable to check retransmissions during recording window");
}
}
// IDEA: if there is a burst of acks, that could indicate tokio task starvation.
+1 -1
View File
@@ -65,7 +65,7 @@ pub async fn current_gateways<R: Rng>(
.ok_or(ClientCoreError::ListOfNymApisIsEmpty)?;
let client = nym_validator_client::client::NymApiClient::new(nym_api.clone());
log::trace!("Fetching list of gateways from: {nym_api}");
log::debug!("Fetching list of gateways from: {nym_api}");
let gateways = client.get_cached_described_gateways().await?;
log::debug!("Found {} gateways", gateways.len());
+1 -1
View File
@@ -178,7 +178,7 @@ impl<T> From<PersistedGatewayDetails<T>> for GatewayDetails<T> {
}
}
#[derive(Clone)]
#[derive(Clone, Debug)]
pub enum GatewaySelectionSpecification<T = EmptyCustomDetails> {
/// Uniformly choose a random remote gateway.
UniformRemote { must_use_tls: bool },
+1
View File
@@ -11,6 +11,7 @@ repository.workspace = true
cfg-if = { workspace = true }
dotenvy = { workspace = true }
hex-literal = "0.3.3"
log = { workspace = true }
once_cell = { workspace = true }
schemars = { workspace = true, features = ["preserve_order"] }
serde = { workspace = true, features = ["derive"]}
+25 -3
View File
@@ -400,11 +400,25 @@ fn fix_deprecated_environmental_variables() {
}
}
// Read the variables from the file and log what the corresponding values in the environment are.
fn print_env_vars_with_keys_in_file<P: AsRef<Path> + Copy>(config_env_file: P) {
let items = dotenvy::from_path_iter(config_env_file)
.expect("Invalid path to environment configuration file");
for item in items {
let (key, val) = item.expect("Invalid item in environment configuration file");
log::debug!("{}: {}", key, val);
}
}
pub fn setup_env<P: AsRef<Path>>(config_env_file: Option<P>) {
match std::env::var(var_names::CONFIGURED) {
// if the configuration is not already set in the env vars
Err(std::env::VarError::NotPresent) => {
if let Some(config_env_file) = config_env_file {
if let Some(config_env_file) = &config_env_file {
log::debug!(
"Loading environment variables from {:?}",
config_env_file.as_ref()
);
dotenvy::from_path(config_env_file)
.expect("Invalid path to environment configuration file");
fix_deprecated_environmental_variables();
@@ -412,17 +426,25 @@ pub fn setup_env<P: AsRef<Path>>(config_env_file: Option<P>) {
// if nothing is set, the use mainnet defaults
// if the user has not set `CONFIGURED`, then even if they set any of the env variables,
// overwrite them
log::debug!("Loading mainnet defaults");
crate::mainnet::export_to_env();
}
}
Err(_) => crate::mainnet::export_to_env(),
Err(_) => {
log::debug!("Environment variables already set. Using them");
crate::mainnet::export_to_env()
}
_ => {
fix_deprecated_environmental_variables();
}
}
// if we haven't explicitly defined any of the constants, fallback to defaults
crate::mainnet::export_to_env_if_not_set()
crate::mainnet::export_to_env_if_not_set();
if let Some(config_env_file) = &config_env_file {
print_env_vars_with_keys_in_file(config_env_file);
}
}
// Name of the event triggered by the eth contract. If the event name is changed,
+1
View File
@@ -240,6 +240,7 @@ pub(crate) fn override_network_requester_config(
)
}
// NOTE: make sure this is in sync with service-providers/ip-packet-router/src/cli/mod.rs::override_config
pub(crate) fn override_ip_packet_router_config(
mut cfg: nym_ip_packet_router::Config,
opts: Option<OverrideIpPacketRouterConfig>,
@@ -10,21 +10,27 @@ license.workspace = true
[dependencies]
bincode = "1.3.3"
bs58 = "0.4.0"
bytes = "1.5.0"
clap.workspace = true
etherparse = "0.13.0"
futures = { workspace = true }
lazy_static.workspace = true
log = { workspace = true }
nym-bin-common = { path = "../../common/bin-common" }
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-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-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 = "0.8.5"
@@ -0,0 +1,13 @@
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!()))
}
@@ -0,0 +1,108 @@
use std::{fmt::Display, fs, path::PathBuf};
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 crate::{
cli::{override_config, try_upgrade_config, OverrideConfig},
config::{default_config_directory, default_config_filepath, default_data_directory, Config},
error::IpPacketRouterError,
};
struct IpPacketRouterInit;
impl InitialisableClient for IpPacketRouterInit {
const NAME: &'static str = "ip packet router";
type Error = IpPacketRouterError;
type InitArgs = Init;
type Config = Config;
fn try_upgrade_outdated_config(id: &str) -> Result<(), Self::Error> {
try_upgrade_config(id)
}
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::<IpPacketRouterInit>(args).await?;
let init_results = InitResults::new(res);
println!("{}", output.format(&init_results));
Ok(())
}
@@ -0,0 +1,197 @@
use clap::{CommandFactory, Parser, Subcommand};
use log::{error, trace};
use nym_bin_common::completions::{fig_generate, ArgShell};
use nym_bin_common::{bin_info, version_checker};
use nym_client_core::client::base_client::storage::gateway_details::{
OnDiskGatewayDetails, PersistedGatewayDetails,
};
use nym_client_core::client::key_manager::persistence::OnDiskKeys;
use nym_client_core::config::GatewayEndpointConfig;
use nym_client_core::error::ClientCoreError;
use crate::config::{BaseClientConfig, Config};
use crate::error::IpPacketRouterError;
mod build_info;
mod init;
mod run;
mod sign;
lazy_static::lazy_static! {
pub static ref PRETTY_BUILD_INFORMATION: String = bin_info!().pretty_print();
}
// Helper for passing LONG_VERSION to clap
fn pretty_build_info_static() -> &'static str {
&PRETTY_BUILD_INFORMATION
}
#[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),
/// 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::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(())
}
// Unused until we need to start implementing config upgrades
#[allow(unused)]
fn persist_gateway_details(
config: &Config,
details: GatewayEndpointConfig,
) -> Result<(), IpPacketRouterError> {
let details_store =
OnDiskGatewayDetails::new(&config.storage_paths.common_paths.gateway_details);
let keys_store = OnDiskKeys::new(config.storage_paths.common_paths.keys.clone());
let shared_keys = keys_store.ephemeral_load_gateway_keys().map_err(|source| {
IpPacketRouterError::ClientCoreError(ClientCoreError::KeyStoreError {
source: Box::new(source),
})
})?;
let persisted_details = PersistedGatewayDetails::new(details.into(), Some(&shared_keys))?;
details_store
.store_to_disk(&persisted_details)
.map_err(|source| {
IpPacketRouterError::ClientCoreError(ClientCoreError::GatewayDetailsStoreError {
source: Box::new(source),
})
})
}
fn try_upgrade_config(_id: &str) -> Result<(), IpPacketRouterError> {
trace!("Attempting to upgrade config");
Ok(())
}
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(id)?;
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)
}
// this only checks compatibility between config the binary. It does not take into consideration
// network version. It might do so in the future.
fn version_check(cfg: &Config) -> bool {
let binary_version = env!("CARGO_PKG_VERSION");
let config_version = &cfg.base.client.version;
if binary_version == config_version {
true
} else {
log::warn!(
"The native-client binary has different version than what is specified \
in config file! {binary_version} and {config_version}",
);
if version_checker::is_minor_version_compatible(binary_version, config_version) {
log::info!(
"but they are still semver compatible. \
However, consider running the `upgrade` command"
);
true
} else {
log::error!(
"and they are semver incompatible! - \
please run the `upgrade` command before attempting `run` again"
);
false
}
}
}
@@ -0,0 +1,44 @@
use crate::cli::{try_load_current_config, version_check};
use crate::{
cli::{override_config, OverrideConfig},
error::IpPacketRouterError,
};
use clap::Args;
use log::error;
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,
}
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)?;
config = override_config(config, OverrideConfig::from(args.clone()));
log::debug!("Using config: {:#?}", config);
if !version_check(&config) {
error!("failed the local version check");
return Err(IpPacketRouterError::FailedLocalVersionCheck);
}
log::info!("Starting ip packet router service provider");
let mut server = crate::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
}
@@ -0,0 +1,76 @@
use crate::cli::{try_load_current_config, version_check};
use crate::error::IpPacketRouterError;
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::identity;
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: &identity::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)?;
if !version_check(&config) {
log::error!("Failed the local version check");
return Err(IpPacketRouterError::FailedLocalVersionCheck);
}
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,9 +1,12 @@
pub use nym_client_core::config::Config as BaseClientConfig;
use nym_bin_common::logging::LoggingSettings;
use nym_client_core::{
cli_helpers::client_init::ClientConfig, config::disk_persistence::CommonClientPaths,
};
use nym_config::{
defaults::mainnet, must_get_home, save_formatted_config_to_file,
serde_helpers::de_maybe_stringified, NymConfigTemplate, DEFAULT_CONFIG_DIR,
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;
@@ -11,6 +14,7 @@ use serde::{Deserialize, Serialize};
use std::{
io,
path::{Path, PathBuf},
str::FromStr,
};
use url::Url;
@@ -71,6 +75,24 @@ impl NymConfigTemplate for Config {
}
}
impl ClientConfig 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 {
@@ -81,6 +103,7 @@ impl Config {
}
}
#[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
@@ -98,6 +121,7 @@ impl Config {
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)
@@ -112,6 +136,52 @@ impl Config {
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)]
@@ -1,4 +1,4 @@
use std::net::{IpAddr, SocketAddr};
use std::net::SocketAddr;
pub use nym_client_core::error::ClientCoreError;
use nym_exit_policy::PolicyError;
@@ -57,15 +57,13 @@ pub enum IpPacketRouterError {
#[error("the provided socket address, '{addr}' is not covered by the exit policy!")]
AddressNotCoveredByExitPolicy { addr: SocketAddr },
#[error("the provided ip address, '{ip}' is not covered by the exit policy!")]
IpNotCoveredByExitPolicy { ip: IpAddr },
// #[error("the provided ip address, '{ip}' is not covered by the exit policy!")]
// IpNotCoveredByExitPolicy { ip: IpAddr },
#[error("failed filter check: '{addr}'")]
AddressFailedFilterCheck { addr: SocketAddr },
#[error("failed filter check: '{ip}'")]
IpFailedFilterCheck { ip: IpAddr },
// #[error("failed filter check: '{ip}'")]
// IpFailedFilterCheck { ip: IpAddr },
#[error("failed to apply the exit policy: {source}")]
ExitPolicyFailure {
#[from]
@@ -12,9 +12,9 @@ use nym_sdk::mixnet::Recipient;
use nym_task::{TaskClient, TaskHandle};
use crate::{
config::Config,
error::IpPacketRouterError,
request_filter::{self, RequestFilter},
Config,
};
pub struct OnStartData {
@@ -56,12 +56,14 @@ impl IpPacketRouter {
}
#[must_use]
#[allow(unused)]
pub fn with_shutdown(mut self, shutdown: TaskClient) -> Self {
self.shutdown = Some(shutdown);
self
}
#[must_use]
#[allow(unused)]
pub fn with_custom_gateway_transceiver(
mut self,
gateway_transceiver: Box<dyn GatewayTransceiver + Send + Sync>,
@@ -71,18 +73,21 @@ impl IpPacketRouter {
}
#[must_use]
#[allow(unused)]
pub fn with_wait_for_gateway(mut self, wait_for_gateway: bool) -> Self {
self.wait_for_gateway = wait_for_gateway;
self
}
#[must_use]
#[allow(unused)]
pub fn with_on_start(mut self, on_start: oneshot::Sender<OnStartData>) -> Self {
self.on_start = Some(on_start);
self
}
#[must_use]
#[allow(unused)]
pub fn with_custom_topology_provider(
mut self,
topology_provider: Box<dyn TopologyProvider + Send + Sync>,
@@ -10,6 +10,6 @@ pub mod error;
mod ip_packet_router;
mod mixnet_client;
mod mixnet_listener;
mod request_filter;
pub mod request_filter;
mod tun_listener;
mod util;
@@ -0,0 +1,41 @@
#[cfg(target_os = "linux")]
mod cli;
#[cfg(target_os = "linux")]
mod config;
#[cfg(target_os = "linux")]
mod constants;
#[cfg(target_os = "linux")]
mod error;
#[cfg(target_os = "linux")]
mod ip_packet_router;
#[cfg(target_os = "linux")]
mod mixnet_client;
#[cfg(target_os = "linux")]
mod mixnet_listener;
#[cfg(target_os = "linux")]
mod request_filter;
#[cfg(target_os = "linux")]
mod tun_listener;
#[cfg(target_os = "linux")]
mod util;
#[cfg(target_os = "linux")]
#[tokio::main]
async fn main() -> Result<(), error::IpPacketRouterError> {
use clap::Parser;
let args = cli::Cli::parse();
nym_bin_common::logging::setup_logging();
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
}
#[cfg(not(target_os = "linux"))]
fn main() {
println!("This binary is currently only supported on linux");
}
@@ -15,6 +15,7 @@ use nym_task::TaskHandle;
use tokio::io::AsyncWriteExt;
use crate::{
config::Config,
constants::{CLIENT_INACTIVITY_TIMEOUT, DISCONNECT_TIMER_INTERVAL},
error::{IpPacketRouterError, Result},
request_filter::{self},
@@ -23,7 +24,6 @@ use crate::{
create_message::create_input_message,
parse_ip::{parse_packet, ParsedPacket},
},
Config,
};
#[cfg(target_os = "linux")]
@@ -10,6 +10,7 @@ use reqwest::IntoUrl;
use url::Url;
pub struct ExitPolicyRequestFilter {
#[allow(unused)]
upstream: Option<Url>,
policy: ExitPolicy,
}
@@ -34,10 +35,12 @@ impl ExitPolicyRequestFilter {
}
}
#[allow(unused)]
pub fn policy(&self) -> &ExitPolicy {
&self.policy
}
#[allow(unused)]
pub fn upstream(&self) -> Option<&Url> {
self.upstream.as_ref()
}
@@ -26,6 +26,7 @@ impl RequestFilter {
Self::new_exit_policy_filter(config).await
}
#[allow(unused)]
pub fn current_exit_policy_filter(&self) -> Option<&ExitPolicyRequestFilter> {
match &*self.inner {
RequestFilterInner::ExitPolicy { policy_filter } => Some(policy_filter),
@@ -48,7 +48,7 @@ impl InitialisableClient for NetworkRequesterInit {
}
}
#[derive(Args, Clone)]
#[derive(Args, Clone, Debug)]
pub(crate) struct Init {
#[command(flatten)]
common_args: CommonClientInitArgs,