Skip to content

Commit 460cc02

Browse files
committed
Add LP registration testing to nym-gateway-probe
Implement LP (Lewes Protocol) registration flow testing in nym-gateway-probe to validate gateway LP registration capabilities alongside existing WireGuard and mixnet tests. Changes: - Add LpProbeResults struct to track LP registration test results (can_connect, can_handshake, can_register, error) - Add lp_registration_probe() function that tests full registration flow: * TCP connection to LP listener (port 41264) * Noise protocol handshake with PSK derivation * Registration request with bandwidth credentials * Registration response validation - Integrate LP test into main probe flow - runs automatically if gateway has LP address (derived from gateway IP + port 41264) - Export LpRegistrationClient from nym-registration-client for probe use - Add LP address field to TestedNodeDetails The probe tests only successful registration without additional traffic, keeping the implementation simple and focused.
1 parent 41a3f24 commit 460cc02

File tree

6 files changed

+189
-2
lines changed

6 files changed

+189
-2
lines changed

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

nym-gateway-probe/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ nym-credentials = { path = "../common/credentials" }
5959
nym-http-api-client-macro = { path = "../common/http-api-client-macro", features = ["debug-inventory"] }
6060
nym-http-api-client = { path = "../common/http-api-client" }
6161
nym-node-status-client = { path = "../nym-node-status-api/nym-node-status-client" }
62+
nym-registration-client = { path = "../nym-registration-client" }
63+
nym-lp = { path = "../common/nym-lp" }
64+
nym-registration-common = { path = "../common/registration" }
6265

6366
# TEMP: REMOVE BEFORE PR
6467
nym-topology = { path = "../common/topology" }

nym-gateway-probe/src/lib.rs

Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ pub struct TestedNodeDetails {
146146
authenticator_address: Option<Recipient>,
147147
authenticator_version: AuthenticatorVersion,
148148
ip_address: Option<IpAddr>,
149+
lp_address: Option<std::net::SocketAddr>,
149150
}
150151

151152
pub struct Probe {
@@ -361,6 +362,7 @@ impl Probe {
361362
},
362363
as_exit: None,
363364
wg: None,
365+
lp: None,
364366
},
365367
});
366368
}
@@ -383,6 +385,7 @@ impl Probe {
383385
},
384386
as_exit: None,
385387
wg: None,
388+
lp: None,
386389
}),
387390
mixnet_client,
388391
)
@@ -449,9 +452,42 @@ impl Probe {
449452
WgProbeResults::default()
450453
};
451454

455+
// Test LP registration if node has LP address
456+
let lp_outcome = if let (Some(lp_address), Some(ip_address)) =
457+
(node_info.lp_address, node_info.ip_address)
458+
{
459+
info!("Node has LP address, testing LP registration...");
460+
461+
// Prepare bandwidth credential for LP registration
462+
let config = nym_validator_client::nyxd::Config::try_from_nym_network_details(
463+
&NymNetworkDetails::new_from_env(),
464+
)?;
465+
let client =
466+
nym_validator_client::nyxd::NyxdClient::connect(config, nyxd_url.as_str())?;
467+
let bw_controller = nym_bandwidth_controller::BandwidthController::new(
468+
storage.credential_store().clone(),
469+
client,
470+
);
471+
472+
let outcome = lp_registration_probe(
473+
node_info.identity,
474+
lp_address,
475+
ip_address,
476+
&bw_controller,
477+
)
478+
.await
479+
.unwrap_or_default();
480+
481+
Some(outcome)
482+
} else {
483+
info!("Node does not have LP address, skipping LP registration test");
484+
None
485+
};
486+
452487
// Disconnect the mixnet client gracefully
453488
outcome.map(|mut outcome| {
454489
outcome.wg = Some(wg_outcome);
490+
outcome.lp = lp_outcome;
455491
ProbeResult {
456492
node: node_info.identity.to_string(),
457493
used_entry: mixnet_entry_gateway_id.to_string(),
@@ -676,6 +712,135 @@ async fn wg_probe(
676712
Ok(wg_outcome)
677713
}
678714

715+
async fn lp_registration_probe<St>(
716+
gateway_identity: NodeIdentity,
717+
gateway_lp_address: std::net::SocketAddr,
718+
gateway_ip: IpAddr,
719+
bandwidth_controller: &nym_bandwidth_controller::BandwidthController<
720+
nym_validator_client::nyxd::NyxdClient<nym_validator_client::HttpRpcClient>,
721+
St,
722+
>,
723+
) -> anyhow::Result<types::LpProbeResults>
724+
where
725+
St: nym_sdk::mixnet::CredentialStorage + Clone + Send + Sync + 'static,
726+
<St as nym_sdk::mixnet::CredentialStorage>::StorageError: Send + Sync,
727+
{
728+
use nym_lp::keypair::{Keypair as LpKeypair, PublicKey as LpPublicKey};
729+
use nym_registration_client::LpRegistrationClient;
730+
731+
info!("Starting LP registration probe for gateway at {}", gateway_lp_address);
732+
733+
let mut lp_outcome = types::LpProbeResults::default();
734+
735+
// Generate LP keypair for this connection
736+
let client_lp_keypair = std::sync::Arc::new(LpKeypair::default());
737+
738+
// Derive gateway LP public key from gateway identity (as done in registration-client)
739+
let gateway_lp_key = match LpPublicKey::from_bytes(&gateway_identity.to_bytes()) {
740+
Ok(key) => key,
741+
Err(e) => {
742+
let error_msg = format!("Failed to derive gateway LP key: {}", e);
743+
error!("{}", error_msg);
744+
lp_outcome.error = Some(error_msg);
745+
return Ok(lp_outcome);
746+
}
747+
};
748+
749+
// Create LP registration client
750+
let mut client = LpRegistrationClient::new_with_default_psk(
751+
client_lp_keypair,
752+
gateway_lp_key,
753+
gateway_lp_address,
754+
gateway_ip,
755+
);
756+
757+
// Step 1: Connect to gateway
758+
info!("Connecting to LP listener at {}...", gateway_lp_address);
759+
match client.connect().await {
760+
Ok(_) => {
761+
info!("Successfully connected to LP listener");
762+
lp_outcome.can_connect = true;
763+
}
764+
Err(e) => {
765+
let error_msg = format!("Failed to connect to LP listener: {}", e);
766+
error!("{}", error_msg);
767+
lp_outcome.error = Some(error_msg);
768+
return Ok(lp_outcome);
769+
}
770+
}
771+
772+
// Step 2: Perform handshake
773+
info!("Performing LP handshake...");
774+
match client.perform_handshake().await {
775+
Ok(_) => {
776+
info!("LP handshake completed successfully");
777+
lp_outcome.can_handshake = true;
778+
}
779+
Err(e) => {
780+
let error_msg = format!("LP handshake failed: {}", e);
781+
error!("{}", error_msg);
782+
lp_outcome.error = Some(error_msg);
783+
return Ok(lp_outcome);
784+
}
785+
}
786+
787+
// Step 3: Send registration request
788+
info!("Sending LP registration request...");
789+
790+
// Generate WireGuard keypair for dVPN registration
791+
let mut rng = rand::thread_rng();
792+
let wg_keypair = nym_crypto::asymmetric::x25519::KeyPair::new(&mut rng);
793+
794+
// Convert gateway identity to ed25519 public key
795+
let gateway_ed25519_pubkey = match nym_crypto::asymmetric::ed25519::PublicKey::from_bytes(&gateway_identity.to_bytes()) {
796+
Ok(key) => key,
797+
Err(e) => {
798+
let error_msg = format!("Failed to convert gateway identity: {}", e);
799+
error!("{}", error_msg);
800+
lp_outcome.error = Some(error_msg);
801+
return Ok(lp_outcome);
802+
}
803+
};
804+
805+
match client.send_registration_request(
806+
&wg_keypair,
807+
&gateway_ed25519_pubkey,
808+
bandwidth_controller,
809+
TicketType::V1WireguardEntry,
810+
).await {
811+
Ok(_) => {
812+
info!("LP registration request sent successfully");
813+
}
814+
Err(e) => {
815+
let error_msg = format!("Failed to send LP registration request: {}", e);
816+
error!("{}", error_msg);
817+
lp_outcome.error = Some(error_msg);
818+
return Ok(lp_outcome);
819+
}
820+
}
821+
822+
// Step 4: Receive registration response
823+
info!("Waiting for LP registration response...");
824+
match client.receive_registration_response().await {
825+
Ok(gateway_data) => {
826+
info!("LP registration successful! Received gateway data:");
827+
info!(" - Gateway public key: {:?}", gateway_data.public_key);
828+
info!(" - Private IPv4: {}", gateway_data.private_ipv4);
829+
info!(" - Private IPv6: {}", gateway_data.private_ipv6);
830+
info!(" - Endpoint: {}", gateway_data.endpoint);
831+
lp_outcome.can_register = true;
832+
}
833+
Err(e) => {
834+
let error_msg = format!("Failed to receive LP registration response: {}", e);
835+
error!("{}", error_msg);
836+
lp_outcome.error = Some(error_msg);
837+
return Ok(lp_outcome);
838+
}
839+
}
840+
841+
Ok(lp_outcome)
842+
}
843+
679844
fn mixnet_debug_config(
680845
min_gateway_performance: Option<u8>,
681846
ignore_egress_epoch_role: bool,
@@ -722,6 +887,7 @@ async fn do_ping(
722887
as_entry: entry,
723888
as_exit: exit,
724889
wg: None,
890+
lp: None,
725891
}),
726892
mixnet_client,
727893
)

nym-gateway-probe/src/nodes.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,17 @@ impl DirectoryNode {
118118
.first()
119119
.copied();
120120

121+
// Derive LP address from gateway IP + default LP control port (41264)
122+
// TODO: Update this when LP address is exposed in node description API
123+
let lp_address = ip_address.map(|ip| std::net::SocketAddr::new(ip, 41264));
124+
121125
Ok(TestedNodeDetails {
122126
identity: self.identity(),
123127
exit_router_address,
124128
authenticator_address,
125129
authenticator_version,
126130
ip_address,
131+
lp_address,
127132
})
128133
}
129134
}

nym-gateway-probe/src/types.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub struct ProbeOutcome {
1313
pub as_entry: Entry,
1414
pub as_exit: Option<Exit>,
1515
pub wg: Option<WgProbeResults>,
16+
pub lp: Option<LpProbeResults>,
1617
}
1718

1819
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
@@ -44,6 +45,15 @@ pub struct WgProbeResults {
4445
pub download_error_v6: String,
4546
}
4647

48+
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
49+
#[serde(rename = "lp")]
50+
pub struct LpProbeResults {
51+
pub can_connect: bool,
52+
pub can_handshake: bool,
53+
pub can_register: bool,
54+
pub error: Option<String>,
55+
}
56+
4757
#[derive(Debug, Clone, Serialize, Deserialize)]
4858
#[serde(untagged)]
4959
#[allow(clippy::enum_variant_names)]

nym-registration-client/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ use nym_sdk::mixnet::{EventReceiver, MixnetClient, Recipient};
1313
use std::sync::Arc;
1414

1515
use crate::config::RegistrationClientConfig;
16-
use crate::lp_client::{LpClientError, LpRegistrationClient, LpTransport};
16+
use crate::lp_client::{LpClientError, LpTransport};
1717

1818
mod builder;
1919
mod config;
@@ -28,7 +28,7 @@ pub use builder::config::{
2828
};
2929
pub use config::RegistrationMode;
3030
pub use error::RegistrationClientError;
31-
pub use lp_client::LpConfig;
31+
pub use lp_client::{LpConfig, LpRegistrationClient};
3232
pub use types::{
3333
LpRegistrationResult, MixnetRegistrationResult, RegistrationResult, WireguardRegistrationResult,
3434
};

0 commit comments

Comments
 (0)