From 7866cb0ae89d1212c841cb51f97dfab3cea27086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Thu, 7 Dec 2023 23:38:31 +0100 Subject: [PATCH 1/6] Add IPR to nym-node http endpoint --- gateway/src/http/mod.rs | 59 +++++++++++++++++++ gateway/src/node/mod.rs | 1 + nym-node/nym-node-requests/src/api/client.rs | 6 ++ .../src/api/v1/ip_packet_router/mod.rs | 4 ++ .../src/api/v1/ip_packet_router/models.rs | 19 ++++++ nym-node/nym-node-requests/src/api/v1/mod.rs | 1 + .../src/api/v1/node/models.rs | 1 + nym-node/nym-node-requests/src/lib.rs | 10 ++++ .../router/api/v1/ip_packet_router/mod.rs | 25 ++++++++ .../router/api/v1/ip_packet_router/root.rs | 33 +++++++++++ nym-node/src/http/router/api/v1/mod.rs | 6 ++ nym-node/src/http/router/mod.rs | 9 +++ 12 files changed, 174 insertions(+) create mode 100644 nym-node/nym-node-requests/src/api/v1/ip_packet_router/mod.rs create mode 100644 nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs create mode 100644 nym-node/src/http/router/api/v1/ip_packet_router/mod.rs create mode 100644 nym-node/src/http/router/api/v1/ip_packet_router/root.rs diff --git a/gateway/src/http/mod.rs b/gateway/src/http/mod.rs index 8a8457f1c6..43ebaa7746 100644 --- a/gateway/src/http/mod.rs +++ b/gateway/src/http/mod.rs @@ -103,10 +103,52 @@ fn load_network_requester_details( ) } +fn load_ip_packet_router_details( + config: &Config, + ip_packet_router_config: &nym_ip_packet_router::Config, +) -> Result { + let identity_public_key: identity::PublicKey = load_public_key( + &ip_packet_router_config + .storage_paths + .common_paths + .keys + .public_identity_key_file, + "ip packet router identity", + )?; + + let dh_public_key: encryption::PublicKey = load_public_key( + &ip_packet_router_config + .storage_paths + .common_paths + .keys + .public_encryption_key_file, + "ip packet router diffie hellman", + )?; + + let gateway_identity_public_key: identity::PublicKey = load_public_key( + &config.storage_paths.keys.public_identity_key_file, + "gateway identity", + )?; + + Ok( + api_requests::v1::ip_packet_router::models::IpPacketRouter { + encoded_identity_key: identity_public_key.to_base58_string(), + encoded_x25519_key: dh_public_key.to_base58_string(), + address: Recipient::new( + identity_public_key, + dh_public_key, + gateway_identity_public_key, + ) + .to_string(), + }, + ) +} + pub(crate) struct HttpApiBuilder<'a> { gateway_config: &'a Config, network_requester_config: Option<&'a nym_network_requester::Config>, exit_policy: Option, + ip_packet_router_config: Option<&'a nym_ip_packet_router::Config>, identity_keypair: &'a identity::KeyPair, // TODO: this should be a wg specific key and not re-used sphinx @@ -124,6 +166,7 @@ impl<'a> HttpApiBuilder<'a> { HttpApiBuilder { gateway_config, network_requester_config: None, + ip_packet_router_config: None, exit_policy: None, identity_keypair, sphinx_keypair, @@ -187,6 +230,15 @@ impl<'a> HttpApiBuilder<'a> { self } + #[must_use] + pub(crate) fn with_maybe_ip_packet_router( + mut self, + ip_packet_router_config: Option<&'a nym_ip_packet_router::Config>, + ) -> Self { + self.ip_packet_router_config = ip_packet_router_config; + self + } + #[must_use] pub(crate) fn with_wireguard_client_registry( mut self, @@ -225,6 +277,13 @@ impl<'a> HttpApiBuilder<'a> { } } + if let Some(ipr_config) = self.ip_packet_router_config { + config = config.with_ip_packet_router(load_ip_packet_router_details( + self.gateway_config, + ipr_config, + )?); + } + let wireguard_private_network = IpNetwork::new( IpAddr::from(Ipv4Addr::new(10, 1, 0, 0)), self.gateway_config.wireguard.private_network_prefix, diff --git a/gateway/src/node/mod.rs b/gateway/src/node/mod.rs index fa0f8b35b0..dc35050785 100644 --- a/gateway/src/node/mod.rs +++ b/gateway/src/node/mod.rs @@ -519,6 +519,7 @@ impl Gateway { .with_wireguard_client_registry(self.client_registry.clone()) .with_maybe_network_requester(self.network_requester_opts.as_ref().map(|o| &o.config)) .with_maybe_network_request_filter(nr_request_filter) + .with_maybe_ip_packet_router(self.ip_packet_router_opts.as_ref().map(|o| &o.config)) .start(shutdown.subscribe().named("http-api"))?; // Once this is a bit more mature, make this a commandline flag instead of a compile time diff --git a/nym-node/nym-node-requests/src/api/client.rs b/nym-node/nym-node-requests/src/api/client.rs index c4e6dde33a..c4c89e2514 100644 --- a/nym-node/nym-node-requests/src/api/client.rs +++ b/nym-node/nym-node-requests/src/api/client.rs @@ -11,6 +11,7 @@ use nym_bin_common::build_information::BinaryBuildInformationOwned; use nym_wireguard_types::{ClientMessage, ClientRegistrationResponse}; use crate::api::v1::health::models::NodeHealth; +use crate::api::v1::ip_packet_router::models::IpPacketRouter; use crate::api::v1::network_requester::exit_policy::models::UsedExitPolicy; use crate::api::v1::network_requester::models::NetworkRequester; pub use http_api_client::Client; @@ -54,6 +55,11 @@ pub trait NymNodeApiClientExt: ApiClient { .await } + async fn get_ip_packet_router(&self) -> Result { + self.get_json_from(routes::api::v1::ip_packet_router_absolute()) + .await + } + async fn post_gateway_register_client( &self, client_message: &ClientMessage, diff --git a/nym-node/nym-node-requests/src/api/v1/ip_packet_router/mod.rs b/nym-node/nym-node-requests/src/api/v1/ip_packet_router/mod.rs new file mode 100644 index 0000000000..c57081432b --- /dev/null +++ b/nym-node/nym-node-requests/src/api/v1/ip_packet_router/mod.rs @@ -0,0 +1,4 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +pub mod models; diff --git a/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs b/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs new file mode 100644 index 0000000000..2e7f4807d9 --- /dev/null +++ b/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs @@ -0,0 +1,19 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: Apache-2.0 + +use schemars::JsonSchema; +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Debug, Clone, JsonSchema)] +#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))] +pub struct IpPacketRouter { + /// Base58 encoded ed25519 EdDSA public key of the ip-packet-router. + pub encoded_identity_key: String, + + /// Base58-encoded x25519 public key used for performing key exchange with remote clients. + pub encoded_x25519_key: String, + + /// Nym address of this network requester. + pub address: String, +} + diff --git a/nym-node/nym-node-requests/src/api/v1/mod.rs b/nym-node/nym-node-requests/src/api/v1/mod.rs index b07fdbb7aa..33d67d598e 100644 --- a/nym-node/nym-node-requests/src/api/v1/mod.rs +++ b/nym-node/nym-node-requests/src/api/v1/mod.rs @@ -3,6 +3,7 @@ pub mod gateway; pub mod health; +pub mod ip_packet_router; pub mod mixnode; pub mod network_requester; pub mod node; diff --git a/nym-node/nym-node-requests/src/api/v1/node/models.rs b/nym-node/nym-node-requests/src/api/v1/node/models.rs index 260752436b..3b79601a00 100644 --- a/nym-node/nym-node-requests/src/api/v1/node/models.rs +++ b/nym-node/nym-node-requests/src/api/v1/node/models.rs @@ -14,6 +14,7 @@ pub struct NodeRoles { pub mixnode_enabled: bool, pub gateway_enabled: bool, pub network_requester_enabled: bool, + pub ip_packet_router_enabled: bool, } #[derive(Clone, Default, Debug, Serialize, Deserialize, JsonSchema)] diff --git a/nym-node/nym-node-requests/src/lib.rs b/nym-node/nym-node-requests/src/lib.rs index cb7942f861..9bb345eca9 100644 --- a/nym-node/nym-node-requests/src/lib.rs +++ b/nym-node/nym-node-requests/src/lib.rs @@ -33,6 +33,7 @@ pub mod routes { pub const GATEWAY: &str = "/gateway"; pub const MIXNODE: &str = "/mixnode"; pub const NETWORK_REQUESTER: &str = "/network-requester"; + pub const IP_PACKET_ROUTER: &str = "/ip-packet-router"; pub const SWAGGER: &str = "/swagger"; // define helper functions to get absolute routes @@ -43,6 +44,7 @@ pub mod routes { absolute_route!(gateway_absolute, v1_absolute(), GATEWAY); absolute_route!(mixnode_absolute, v1_absolute(), MIXNODE); absolute_route!(network_requester_absolute, v1_absolute(), NETWORK_REQUESTER); + absolute_route!(ip_packet_router_absolute, v1_absolute(), IP_PACKET_ROUTER); absolute_route!(swagger_absolute, v1_absolute(), SWAGGER); pub mod gateway { @@ -96,6 +98,10 @@ pub mod routes { EXIT_POLICY ); } + + pub mod ip_packet_router { + // use super::*; + } } } } @@ -146,5 +152,9 @@ mod tests { "/api/v1/network-requester", routes::api::v1::network_requester_absolute() ); + assert_eq!( + "/api/v1/ip-packet-router", + routes::api::v1::ip_packet_router_absolute() + ); } } diff --git a/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs b/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs new file mode 100644 index 0000000000..b7eedde9dc --- /dev/null +++ b/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs @@ -0,0 +1,25 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use axum::routing::get; +use axum::Router; +use nym_node_requests::api::v1::ip_packet_router::models; +use nym_node_requests::routes::api::v1::ip_packet_router; + +pub mod root; + +#[derive(Debug, Clone, Default)] +pub struct Config { + pub details: Option, +} + +pub(crate) fn routes(config: Config) -> Router { + Router::new() + .route( + "/", + get({ + let ip_packet_router_details = config.details; + move |query| root::root_ip_packet_router(ip_packet_router_details, query) + }), + ) +} diff --git a/nym-node/src/http/router/api/v1/ip_packet_router/root.rs b/nym-node/src/http/router/api/v1/ip_packet_router/root.rs new file mode 100644 index 0000000000..498bf7c084 --- /dev/null +++ b/nym-node/src/http/router/api/v1/ip_packet_router/root.rs @@ -0,0 +1,33 @@ +// Copyright 2023 - Nym Technologies SA +// SPDX-License-Identifier: GPL-3.0-only + +use crate::http::router::api::{FormattedResponse, OutputParams}; +use axum::extract::Query; +use axum::http::StatusCode; +use nym_node_requests::api::v1::ip_packet_router::models::IpPacketRouter; + +/// Returns root network requester information +#[utoipa::path( + get, + path = "", + context_path = "/api/v1/ip-packet-router", + tag = "IP Packet Router", + responses( + (status = 501, description = "the endpoint hasn't been implemented yet"), + (status = 200, content( + ("application/json" = IpPacketRouter), + ("application/yaml" = IpPacketRouter) + )) + ), + params(OutputParams) +)] +pub(crate) async fn root_ip_packet_router( + details: Option, + Query(output): Query, +) -> Result { + let details = details.ok_or(StatusCode::NOT_IMPLEMENTED)?; + let output = output.output.unwrap_or_default(); + Ok(output.to_response(details)) +} + +pub type IpPacketRouterResponse = FormattedResponse; diff --git a/nym-node/src/http/router/api/v1/mod.rs b/nym-node/src/http/router/api/v1/mod.rs index f9415d5309..97d7aff172 100644 --- a/nym-node/src/http/router/api/v1/mod.rs +++ b/nym-node/src/http/router/api/v1/mod.rs @@ -9,6 +9,7 @@ use nym_node_requests::routes::api::v1; pub mod gateway; pub mod health; +pub mod ip_packet_router; pub mod mixnode; pub mod network_requester; pub mod node; @@ -20,6 +21,7 @@ pub struct Config { pub gateway: gateway::Config, pub mixnode: mixnode::Config, pub network_requester: network_requester::Config, + pub ip_packet_router: ip_packet_router::Config, } pub(super) fn routes(config: Config, initial_wg_state: WireguardAppState) -> Router { @@ -34,6 +36,10 @@ pub(super) fn routes(config: Config, initial_wg_state: WireguardAppState) -> Rou v1::NETWORK_REQUESTER, network_requester::routes(config.network_requester), ) + .nest( + v1::IP_PACKET_ROUTER, + ip_packet_router::routes(config.ip_packet_router), + ) .merge(node::routes(config.node)) .merge(openapi::route()) } diff --git a/nym-node/src/http/router/mod.rs b/nym-node/src/http/router/mod.rs index e1d9e03b35..71de3c3c8d 100644 --- a/nym-node/src/http/router/mod.rs +++ b/nym-node/src/http/router/mod.rs @@ -8,6 +8,7 @@ use crate::http::state::AppState; use crate::http::NymNodeHTTPServer; use axum::Router; use nym_node_requests::api::v1::gateway::models::{Gateway, Wireguard}; +use nym_node_requests::api::v1::ip_packet_router::models::IpPacketRouter; use nym_node_requests::api::v1::mixnode::models::Mixnode; use nym_node_requests::api::v1::network_requester::exit_policy::models::UsedExitPolicy; use nym_node_requests::api::v1::network_requester::models::NetworkRequester; @@ -45,6 +46,7 @@ impl Config { gateway: Default::default(), mixnode: Default::default(), network_requester: Default::default(), + ip_packet_router: Default::default(), }, }, } @@ -94,6 +96,13 @@ impl Config { self.api.v1_config.network_requester.exit_policy = Some(exit_policy); self } + + #[must_use] + pub fn with_ip_packet_router(mut self, ip_packet_router: IpPacketRouter) -> Self { + self.api.v1_config.node.roles.ip_packet_router_enabled = true; + self.api.v1_config.ip_packet_router.details = Some(ip_packet_router); + self + } } pub struct NymNodeRouter { From af3a216f7186c048a051a4763d5e673480f5b6c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Thu, 7 Dec 2023 23:40:06 +0100 Subject: [PATCH 2/6] formatting --- gateway/src/http/mod.rs | 22 +++++++++---------- .../src/api/v1/ip_packet_router/models.rs | 1 - .../router/api/v1/ip_packet_router/mod.rs | 15 ++++++------- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/gateway/src/http/mod.rs b/gateway/src/http/mod.rs index 43ebaa7746..7b63a522fb 100644 --- a/gateway/src/http/mod.rs +++ b/gateway/src/http/mod.rs @@ -130,18 +130,16 @@ fn load_ip_packet_router_details( "gateway identity", )?; - Ok( - api_requests::v1::ip_packet_router::models::IpPacketRouter { - encoded_identity_key: identity_public_key.to_base58_string(), - encoded_x25519_key: dh_public_key.to_base58_string(), - address: Recipient::new( - identity_public_key, - dh_public_key, - gateway_identity_public_key, - ) - .to_string(), - }, - ) + Ok(api_requests::v1::ip_packet_router::models::IpPacketRouter { + encoded_identity_key: identity_public_key.to_base58_string(), + encoded_x25519_key: dh_public_key.to_base58_string(), + address: Recipient::new( + identity_public_key, + dh_public_key, + gateway_identity_public_key, + ) + .to_string(), + }) } pub(crate) struct HttpApiBuilder<'a> { diff --git a/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs b/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs index 2e7f4807d9..c1932a7bc6 100644 --- a/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs +++ b/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs @@ -16,4 +16,3 @@ pub struct IpPacketRouter { /// Nym address of this network requester. pub address: String, } - diff --git a/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs b/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs index b7eedde9dc..531e32896b 100644 --- a/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs +++ b/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs @@ -14,12 +14,11 @@ pub struct Config { } pub(crate) fn routes(config: Config) -> Router { - Router::new() - .route( - "/", - get({ - let ip_packet_router_details = config.details; - move |query| root::root_ip_packet_router(ip_packet_router_details, query) - }), - ) + Router::new().route( + "/", + get({ + let ip_packet_router_details = config.details; + move |query| root::root_ip_packet_router(ip_packet_router_details, query) + }), + ) } From b898ad3e9756058e740c43c0e7517fd8cbb11b49 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Thu, 7 Dec 2023 23:44:00 +0100 Subject: [PATCH 3/6] Remove unused --- nym-node/src/http/router/api/v1/ip_packet_router/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs b/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs index 531e32896b..ab6b2ed72e 100644 --- a/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs +++ b/nym-node/src/http/router/api/v1/ip_packet_router/mod.rs @@ -4,7 +4,6 @@ use axum::routing::get; use axum::Router; use nym_node_requests::api::v1::ip_packet_router::models; -use nym_node_requests::routes::api::v1::ip_packet_router; pub mod root; From 24a859d03c527c4565a911823de58ebeda6cfe12 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Thu, 7 Dec 2023 23:57:17 +0100 Subject: [PATCH 4/6] Add to nym-api node-describe-cache --- nym-api/nym-api-requests/src/models.rs | 9 +++++++++ nym-api/src/node_describe_cache/mod.rs | 13 ++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/nym-api/nym-api-requests/src/models.rs b/nym-api/nym-api-requests/src/models.rs index 35fad2b7c4..142a607e5a 100644 --- a/nym-api/nym-api-requests/src/models.rs +++ b/nym-api/nym-api-requests/src/models.rs @@ -366,6 +366,9 @@ pub struct NymNodeDescription { #[serde(default)] pub network_requester: Option, + #[serde(default)] + pub ip_packet_router: Option, + // for now we only care about their ws/wss situation, nothing more pub mixnet_websockets: WebSockets, } @@ -393,3 +396,9 @@ pub struct NetworkRequesterDetails { /// flag indicating whether this network requester uses the exit policy rather than the deprecated allow list pub uses_exit_policy: bool, } + +#[derive(Clone, Debug, Serialize, Deserialize, schemars::JsonSchema)] +pub struct IpPacketRouterDetails { + /// address of the embedded ip packet router + pub address: String, +} diff --git a/nym-api/src/node_describe_cache/mod.rs b/nym-api/src/node_describe_cache/mod.rs index 0a11a5224a..21b621f428 100644 --- a/nym-api/src/node_describe_cache/mod.rs +++ b/nym-api/src/node_describe_cache/mod.rs @@ -7,7 +7,9 @@ use crate::support::caching::refresher::{CacheItemProvider, CacheRefresher}; use crate::support::config; use crate::support::config::DEFAULT_NODE_DESCRIBE_BATCH_SIZE; use futures_util::{stream, StreamExt}; -use nym_api_requests::models::{NetworkRequesterDetails, NymNodeDescription}; +use nym_api_requests::models::{ + IpPacketRouterDetails, NetworkRequesterDetails, NymNodeDescription, +}; use nym_config::defaults::{mainnet, DEFAULT_NYM_NODE_HTTP_PORT}; use nym_contracts_common::IdentityKey; use nym_mixnet_contract_common::Gateway; @@ -170,10 +172,19 @@ async fn get_gateway_description( None }; + let ip_packet_router = if let Ok(ipr) = client.get_ip_packet_router().await { + Some(IpPacketRouterDetails { + address: ipr.address, + }) + } else { + None + }; + let description = NymNodeDescription { host_information: host_info.data, build_information: build_info, network_requester, + ip_packet_router, mixnet_websockets: websockets, }; From 08613043683172083ce954f77a4746ee9d1686de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Fri, 8 Dec 2023 09:23:42 +0100 Subject: [PATCH 5/6] Add routes to openapi --- nym-node/src/http/router/api/v1/openapi.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/nym-node/src/http/router/api/v1/openapi.rs b/nym-node/src/http/router/api/v1/openapi.rs index d016de72fb..e23eca84f3 100644 --- a/nym-node/src/http/router/api/v1/openapi.rs +++ b/nym-node/src/http/router/api/v1/openapi.rs @@ -27,6 +27,7 @@ use utoipa_swagger_ui::SwaggerUi; api::v1::mixnode::root::root_mixnode, api::v1::network_requester::root::root_network_requester, api::v1::network_requester::exit_policy::node_exit_policy, + api::v1::ip_packet_router::root::root_ip_packet_router, ), components( schemas( @@ -56,6 +57,7 @@ use utoipa_swagger_ui::SwaggerUi; api_requests::v1::network_requester::exit_policy::models::AddressPortPattern, api_requests::v1::network_requester::exit_policy::models::PortRange, api_requests::v1::network_requester::exit_policy::models::UsedExitPolicy, + api_requests::v1::ip_packet_router::models::IpPacketRouter, ), responses(RequestError) ) From a08cc64fc72fb1e7fb854656292cea525abb4f11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Fri, 8 Dec 2023 12:28:03 +0100 Subject: [PATCH 6/6] typo --- .../nym-node-requests/src/api/v1/ip_packet_router/models.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs b/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs index c1932a7bc6..eea0783b67 100644 --- a/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs +++ b/nym-node/nym-node-requests/src/api/v1/ip_packet_router/models.rs @@ -13,6 +13,6 @@ pub struct IpPacketRouter { /// Base58-encoded x25519 public key used for performing key exchange with remote clients. pub encoded_x25519_key: String, - /// Nym address of this network requester. + /// Nym address of this ip packet router. pub address: String, }