increased configurability

This commit is contained in:
Jędrzej Stuczyński
2023-10-12 11:00:04 +01:00
parent 07e6d7750a
commit a6f0fbff3d
11 changed files with 205 additions and 31 deletions
-9
View File
@@ -189,15 +189,6 @@ impl<'a> TryFrom<&'a DescribedGateway> for Node {
});
}
let ips = ips
.iter()
.map(|ip| ip.parse())
.collect::<Result<Vec<_>, _>>()
.map_err(|err| GatewayConversionError::MalformedIpAddress {
gateway: value.bond.gateway.identity_key.clone(),
err,
})?;
let host = match &self_described.host_information.hostname {
None => NetworkAddress::IpAddr(ips[0]),
Some(hostname) => NetworkAddress::Hostname(hostname.clone()),
+1 -1
View File
@@ -41,7 +41,7 @@ pub(crate) struct OverrideConfig {
impl OverrideConfig {
pub(crate) fn do_override(self, mut config: Config) -> Result<Config, GatewayError> {
config = config
.with_optional(Config::with_listening_address, self.host)
.with_optional(Config::with_host, self.host)
.with_optional(Config::with_mix_port, self.mix_port)
.with_optional(Config::with_clients_port, self.clients_port)
.with_optional_custom_env(
+42 -4
View File
@@ -13,9 +13,9 @@ use nym_config::{
};
use nym_network_defaults::mainnet;
use nym_node::config;
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize};
use std::io;
use std::net::IpAddr;
use std::net::{IpAddr, SocketAddr};
use std::path::{Path, PathBuf};
use std::time::Duration;
use url::Url;
@@ -40,6 +40,18 @@ const DEFAULT_MAXIMUM_CONNECTION_BUFFER_SIZE: usize = 2000;
const DEFAULT_STORED_MESSAGE_FILENAME_LENGTH: u16 = 16;
const DEFAULT_MESSAGE_RETRIEVAL_LIMIT: i64 = 100;
fn de_maybe_port<'de, D>(deserializer: D) -> Result<Option<u16>, D::Error>
where
D: Deserializer<'de>,
{
let port = u16::deserialize(deserializer)?;
if port == 0 {
Ok(None)
} else {
Ok(Some(port))
}
}
/// Derive default path to gateway's config directory.
/// It should get resolved to `$HOME/.nym/gateways/<id>/config`
pub fn default_config_directory<P: AsRef<Path>>(id: P) -> PathBuf {
@@ -73,11 +85,17 @@ pub struct Config {
#[serde(skip)]
pub(crate) save_path: Option<PathBuf>,
pub host: config::Host,
#[serde(default)]
pub http: config::Http,
pub gateway: Gateway,
#[serde(default)]
// currently not really used for anything useful
pub wireguard: config::Wireguard,
pub storage_paths: GatewayPaths,
pub network_requester: NetworkRequester,
@@ -97,10 +115,16 @@ impl NymConfigTemplate for Config {
impl Config {
pub fn new<S: AsRef<str>>(id: S) -> Self {
let default_gateway = Gateway::new_default(id.as_ref());
Config {
save_path: None,
host: config::Host {
public_ips: vec![default_gateway.listening_address],
..Default::default()
},
http: Default::default(),
gateway: Gateway::new_default(id.as_ref()),
gateway: default_gateway,
wireguard: Default::default(),
storage_paths: GatewayPaths::new_default(id.as_ref()),
network_requester: Default::default(),
logging: Default::default(),
@@ -188,8 +212,16 @@ impl Config {
self
}
pub fn with_listening_address(mut self, listening_address: IpAddr) -> Self {
pub fn with_host(mut self, listening_address: IpAddr) -> Self {
self.gateway.listening_address = listening_address;
// temporary workaround
self.host.public_ips = vec![listening_address];
let http_port = self.http.bind_address.port();
self.http.bind_address = SocketAddr::new(listening_address, http_port);
let wg_port = self.wireguard.bind_address.port();
self.wireguard.bind_address = SocketAddr::new(listening_address, wg_port);
self
}
@@ -251,6 +283,11 @@ pub struct Gateway {
/// (default: 9000)
pub clients_port: u16,
/// If applicable, announced port for listening for secure websocket client traffic.
/// (default: None)
#[serde(deserialize_with = "de_maybe_port")]
pub clients_wss_port: Option<u16>,
/// Whether gateway collects and sends anonymized statistics
pub enabled_statistics: bool,
@@ -285,6 +322,7 @@ impl Gateway {
listening_address: inaddr_any(),
mix_port: DEFAULT_MIX_LISTENING_PORT,
clients_port: DEFAULT_CLIENT_LISTENING_PORT,
clients_wss_port: None,
enabled_statistics: false,
statistics_service_url: mainnet::STATISTICS_SERVICE_DOMAIN_ADDRESS
.parse()
+14
View File
@@ -110,6 +110,13 @@ impl From<ConfigV1_1_29> for Config {
Config {
save_path: value.save_path,
// \/ ADDED
host: nym_node::config::Host {
public_ips: vec![value.gateway.listening_address],
..Default::default()
},
// /\ ADDED
// \/ ADDED
http: Default::default(),
// /\ ADDED
@@ -120,12 +127,19 @@ impl From<ConfigV1_1_29> for Config {
listening_address: value.gateway.listening_address,
mix_port: value.gateway.mix_port,
clients_port: value.gateway.clients_port,
// \/ ADDED
clients_wss_port: None,
// /\ ADDED
enabled_statistics: value.gateway.enabled_statistics,
nym_api_urls: value.gateway.nym_api_urls,
nyxd_urls: value.gateway.nyxd_urls,
statistics_service_url: value.gateway.statistics_service_url,
cosmos_mnemonic: value.gateway.cosmos_mnemonic,
},
// \/ ADDED
wireguard: Default::default(),
// /\ ADDED
storage_paths: GatewayPaths {
keys: KeysPaths {
private_identity_key_file: value.storage_paths.keys.private_identity_key_file,
+16 -1
View File
@@ -9,7 +9,18 @@ pub(crate) const CONFIG_TEMPLATE: &str = r#"
# This is a TOML config file.
# For more information, see https://github.com/toml-lang/toml
##### main base mixnode config options #####
##### main base gateway config options #####
[host]
# Ip address(es) of this host, such as 1.1.1.1 that external clients will use for connections.
public_ips = [
{{#each host.public_ips }}
'{{this}}',
{{/each}}
]
# (temporary) Optional hostname of this node, for example nymtech.net.
hostname = '{{ host.hostname }}'
[gateway]
# Version of the gateway for which this configuration was created.
@@ -33,6 +44,10 @@ mix_port = {{ gateway.mix_port }}
# (default: 9000)
clients_port = {{ gateway.clients_port }}
# If applicable, announced port for listening for secure websocket client traffic.
# (default: 0 - disabled)
clients_wss_port ={{#if gateway.clients_wss_port }} {{ gateway.clients_wss_port }} {{else}} 0 {{/if}}
# Wheather gateway collects and sends anonymized statistics
enabled_statistics = {{ gateway.enabled_statistics }}
+13 -4
View File
@@ -19,12 +19,21 @@ use tokio::sync::RwLock;
fn load_gateway_details(
config: &Config,
) -> Result<api_requests::v1::gateway::models::Gateway, GatewayError> {
let wireguard = if config.wireguard.enabled {
Some(api_requests::v1::gateway::models::Wireguard {
port: config.wireguard.announced_port,
public_key: "placeholder key value".to_string(),
})
} else {
None
};
Ok(api_requests::v1::gateway::models::Gateway {
client_interfaces: api_requests::v1::gateway::models::ClientInterfaces {
wireguard: None,
wireguard,
mixnet_websockets: Some(api_requests::v1::gateway::models::WebSockets {
ws_port: config.gateway.clients_port,
wss_port: None,
wss_port: config.gateway.clients_wss_port,
}),
},
})
@@ -37,8 +46,8 @@ fn load_host_details(
) -> Result<api_requests::v1::node::models::SignedHostInformation, GatewayError> {
let host_info = api_requests::v1::node::models::HostInformation {
// TODO: this should be extracted differently, i.e. it's the issue of the public/private address
ip_address: vec![config.gateway.listening_address.to_string()],
hostname: None,
ip_address: config.host.public_ips.clone(),
hostname: config.host.hostname.clone(),
keys: api_requests::v1::node::models::HostKeys {
ed25519: identity_keypair.public_key().to_base58_string(),
x25519: sphinx_key.to_base58_string(),
@@ -3,6 +3,7 @@
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::net::IpAddr;
pub use crate::api::SignedHostInformation;
pub use nym_bin_common::build_information::BinaryBuildInformationOwned;
@@ -19,9 +20,11 @@ pub struct NodeRoles {
#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
pub struct HostInformation {
/// Ip address(es) of this host, such as `1.1.1.1`.
pub ip_address: Vec<String>,
#[cfg_attr(feature = "openapi", schema(value_type = Vec<String>, format = Byte, example = json!(["1.1.1.1"])))]
pub ip_address: Vec<IpAddr>,
/// Optional hostname of this node, for example `nymtech.net`.
#[cfg_attr(feature = "openapi", schema(example = "nymtech.net"))]
pub hostname: Option<String>,
/// Public keys associated with this node.
+62 -10
View File
@@ -1,24 +1,43 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Deserializer, Serialize};
use serde::{Deserialize, Serialize};
use serde_helpers::*;
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::path::PathBuf;
fn de_maybe_path<'de, D>(deserializer: D) -> Result<Option<PathBuf>, D::Error>
where
D: Deserializer<'de>,
{
let path = PathBuf::deserialize(deserializer)?;
if path.as_os_str().is_empty() {
Ok(None)
} else {
Ok(Some(path))
pub mod persistence;
mod serde_helpers;
pub const DEFAULT_WIREGUARD_PORT: u16 = 51820;
// TODO: this is very much a WIP. we need proper ssl certificate support here
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct Host {
/// Ip address(es) of this host, such as 1.1.1.1 that external clients will use for connections.
pub public_ips: Vec<IpAddr>,
/// Optional hostname of this node, for example nymtech.net.
// TODO: this is temporary. to be replaced by pulling the data directly from the certs.
#[serde(deserialize_with = "de_maybe_string")]
pub hostname: Option<String>,
}
#[allow(clippy::derivable_impls)]
impl Default for Host {
fn default() -> Self {
Host {
public_ips: vec![],
hostname: None,
}
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct Http {
/// Socket address this node will use for binding its http API.
/// default: `0.0.0.0:80`
@@ -37,3 +56,36 @@ impl Default for Http {
}
}
}
#[derive(Debug, Deserialize, PartialEq, Serialize)]
#[serde(default)]
#[serde(deny_unknown_fields)]
pub struct Wireguard {
/// Specifies whether the wireguard service is enabled on this node.
pub enabled: bool,
/// Socket address this node will use for binding its wireguard interface.
/// default: `0.0.0.0:51820`
pub bind_address: SocketAddr,
/// Port announced to external clients wishing to connect to the wireguard interface.
/// Useful in the instances where the node is behind a proxy.
pub announced_port: u16,
/// Paths for wireguard keys, client registries, etc.
pub storage_paths: persistence::WireguardPaths,
}
impl Default for Wireguard {
fn default() -> Self {
Wireguard {
enabled: false,
bind_address: SocketAddr::new(
IpAddr::V4(Ipv4Addr::UNSPECIFIED),
DEFAULT_WIREGUARD_PORT,
),
announced_port: DEFAULT_WIREGUARD_PORT,
storage_paths: persistence::WireguardPaths {},
}
}
}
+10
View File
@@ -0,0 +1,10 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
#[serde(deny_unknown_fields)]
pub struct WireguardPaths {
// pub keys:
}
+29
View File
@@ -0,0 +1,29 @@
// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use serde::{Deserialize, Deserializer};
use std::path::PathBuf;
pub(super) fn de_maybe_path<'de, D>(deserializer: D) -> Result<Option<PathBuf>, D::Error>
where
D: Deserializer<'de>,
{
let path = PathBuf::deserialize(deserializer)?;
if path.as_os_str().is_empty() {
Ok(None)
} else {
Ok(Some(path))
}
}
pub(super) fn de_maybe_string<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
let path = String::deserialize(deserializer)?;
if path.is_empty() {
Ok(None)
} else {
Ok(Some(path))
}
}
+14 -1
View File
@@ -7,7 +7,7 @@ use crate::http::middleware::logging;
use crate::http::state::AppState;
use crate::http::NymNodeHTTPServer;
use axum::Router;
use nym_node_requests::api::v1::gateway::models::Gateway;
use nym_node_requests::api::v1::gateway::models::{Gateway, Wireguard};
use nym_node_requests::api::v1::mixnode::models::Mixnode;
use nym_node_requests::api::v1::network_requester::models::NetworkRequester;
use nym_node_requests::api::v1::node::models;
@@ -15,6 +15,7 @@ use nym_node_requests::api::SignedHostInformation;
use nym_node_requests::routes;
use std::net::SocketAddr;
use std::path::Path;
use tracing::warn;
pub mod api;
pub mod landing_page;
@@ -48,6 +49,18 @@ impl Config {
}
}
pub fn with_wireguard_interface(mut self, wireguard: Wireguard) -> Self {
match &mut self.api.v1_config.gateway.details {
Some(gw) => gw.client_interfaces.wireguard = Some(wireguard),
None => {
warn!(
"can't add wireguard interface information as the gateway role is not enabled."
);
}
}
self
}
#[must_use]
pub fn with_landing_page_assets<P: AsRef<Path>>(mut self, assets_path: Option<P>) -> Self {
self.landing.assets_path = assets_path.map(|p| p.as_ref().to_path_buf());