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.
This commit is contained in:
Generated
+3
@@ -5935,7 +5935,10 @@ dependencies = [
|
||||
"nym-http-api-client-macro",
|
||||
"nym-ip-packet-client",
|
||||
"nym-ip-packet-requests",
|
||||
"nym-lp",
|
||||
"nym-node-status-client",
|
||||
"nym-registration-client",
|
||||
"nym-registration-common",
|
||||
"nym-sdk",
|
||||
"nym-topology",
|
||||
"nym-validator-client",
|
||||
|
||||
@@ -59,6 +59,9 @@ nym-credentials = { path = "../common/credentials" }
|
||||
nym-http-api-client-macro = { path = "../common/http-api-client-macro" }
|
||||
nym-http-api-client = { path = "../common/http-api-client" }
|
||||
nym-node-status-client = { path = "../nym-node-status-api/nym-node-status-client" }
|
||||
nym-registration-client = { path = "../nym-registration-client" }
|
||||
nym-lp = { path = "../common/nym-lp" }
|
||||
nym-registration-common = { path = "../common/registration" }
|
||||
|
||||
# TEMP: REMOVE BEFORE PR
|
||||
nym-topology = { path = "../common/topology" }
|
||||
|
||||
@@ -146,6 +146,7 @@ pub struct TestedNodeDetails {
|
||||
authenticator_address: Option<Recipient>,
|
||||
authenticator_version: AuthenticatorVersion,
|
||||
ip_address: Option<IpAddr>,
|
||||
lp_address: Option<std::net::SocketAddr>,
|
||||
}
|
||||
|
||||
pub struct Probe {
|
||||
@@ -361,6 +362,7 @@ impl Probe {
|
||||
},
|
||||
as_exit: None,
|
||||
wg: None,
|
||||
lp: None,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -383,6 +385,7 @@ impl Probe {
|
||||
},
|
||||
as_exit: None,
|
||||
wg: None,
|
||||
lp: None,
|
||||
}),
|
||||
mixnet_client,
|
||||
)
|
||||
@@ -449,9 +452,42 @@ impl Probe {
|
||||
WgProbeResults::default()
|
||||
};
|
||||
|
||||
// Test LP registration if node has LP address
|
||||
let lp_outcome = if let (Some(lp_address), Some(ip_address)) =
|
||||
(node_info.lp_address, node_info.ip_address)
|
||||
{
|
||||
info!("Node has LP address, testing LP registration...");
|
||||
|
||||
// Prepare bandwidth credential for LP registration
|
||||
let config = nym_validator_client::nyxd::Config::try_from_nym_network_details(
|
||||
&NymNetworkDetails::new_from_env(),
|
||||
)?;
|
||||
let client =
|
||||
nym_validator_client::nyxd::NyxdClient::connect(config, nyxd_url.as_str())?;
|
||||
let bw_controller = nym_bandwidth_controller::BandwidthController::new(
|
||||
storage.credential_store().clone(),
|
||||
client,
|
||||
);
|
||||
|
||||
let outcome = lp_registration_probe(
|
||||
node_info.identity,
|
||||
lp_address,
|
||||
ip_address,
|
||||
&bw_controller,
|
||||
)
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
|
||||
Some(outcome)
|
||||
} else {
|
||||
info!("Node does not have LP address, skipping LP registration test");
|
||||
None
|
||||
};
|
||||
|
||||
// Disconnect the mixnet client gracefully
|
||||
outcome.map(|mut outcome| {
|
||||
outcome.wg = Some(wg_outcome);
|
||||
outcome.lp = lp_outcome;
|
||||
ProbeResult {
|
||||
node: node_info.identity.to_string(),
|
||||
used_entry: mixnet_entry_gateway_id.to_string(),
|
||||
@@ -640,6 +676,135 @@ async fn wg_probe(
|
||||
Ok(wg_outcome)
|
||||
}
|
||||
|
||||
async fn lp_registration_probe<St>(
|
||||
gateway_identity: NodeIdentity,
|
||||
gateway_lp_address: std::net::SocketAddr,
|
||||
gateway_ip: IpAddr,
|
||||
bandwidth_controller: &nym_bandwidth_controller::BandwidthController<
|
||||
nym_validator_client::nyxd::NyxdClient<nym_validator_client::HttpRpcClient>,
|
||||
St,
|
||||
>,
|
||||
) -> anyhow::Result<types::LpProbeResults>
|
||||
where
|
||||
St: nym_sdk::mixnet::CredentialStorage + Clone + Send + Sync + 'static,
|
||||
<St as nym_sdk::mixnet::CredentialStorage>::StorageError: Send + Sync,
|
||||
{
|
||||
use nym_lp::keypair::{Keypair as LpKeypair, PublicKey as LpPublicKey};
|
||||
use nym_registration_client::LpRegistrationClient;
|
||||
|
||||
info!("Starting LP registration probe for gateway at {}", gateway_lp_address);
|
||||
|
||||
let mut lp_outcome = types::LpProbeResults::default();
|
||||
|
||||
// Generate LP keypair for this connection
|
||||
let client_lp_keypair = std::sync::Arc::new(LpKeypair::default());
|
||||
|
||||
// Derive gateway LP public key from gateway identity (as done in registration-client)
|
||||
let gateway_lp_key = match LpPublicKey::from_bytes(&gateway_identity.to_bytes()) {
|
||||
Ok(key) => key,
|
||||
Err(e) => {
|
||||
let error_msg = format!("Failed to derive gateway LP key: {}", e);
|
||||
error!("{}", error_msg);
|
||||
lp_outcome.error = Some(error_msg);
|
||||
return Ok(lp_outcome);
|
||||
}
|
||||
};
|
||||
|
||||
// Create LP registration client
|
||||
let mut client = LpRegistrationClient::new_with_default_psk(
|
||||
client_lp_keypair,
|
||||
gateway_lp_key,
|
||||
gateway_lp_address,
|
||||
gateway_ip,
|
||||
);
|
||||
|
||||
// Step 1: Connect to gateway
|
||||
info!("Connecting to LP listener at {}...", gateway_lp_address);
|
||||
match client.connect().await {
|
||||
Ok(_) => {
|
||||
info!("Successfully connected to LP listener");
|
||||
lp_outcome.can_connect = true;
|
||||
}
|
||||
Err(e) => {
|
||||
let error_msg = format!("Failed to connect to LP listener: {}", e);
|
||||
error!("{}", error_msg);
|
||||
lp_outcome.error = Some(error_msg);
|
||||
return Ok(lp_outcome);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 2: Perform handshake
|
||||
info!("Performing LP handshake...");
|
||||
match client.perform_handshake().await {
|
||||
Ok(_) => {
|
||||
info!("LP handshake completed successfully");
|
||||
lp_outcome.can_handshake = true;
|
||||
}
|
||||
Err(e) => {
|
||||
let error_msg = format!("LP handshake failed: {}", e);
|
||||
error!("{}", error_msg);
|
||||
lp_outcome.error = Some(error_msg);
|
||||
return Ok(lp_outcome);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 3: Send registration request
|
||||
info!("Sending LP registration request...");
|
||||
|
||||
// Generate WireGuard keypair for dVPN registration
|
||||
let mut rng = rand::thread_rng();
|
||||
let wg_keypair = nym_crypto::asymmetric::x25519::KeyPair::new(&mut rng);
|
||||
|
||||
// Convert gateway identity to ed25519 public key
|
||||
let gateway_ed25519_pubkey = match nym_crypto::asymmetric::ed25519::PublicKey::from_bytes(&gateway_identity.to_bytes()) {
|
||||
Ok(key) => key,
|
||||
Err(e) => {
|
||||
let error_msg = format!("Failed to convert gateway identity: {}", e);
|
||||
error!("{}", error_msg);
|
||||
lp_outcome.error = Some(error_msg);
|
||||
return Ok(lp_outcome);
|
||||
}
|
||||
};
|
||||
|
||||
match client.send_registration_request(
|
||||
&wg_keypair,
|
||||
&gateway_ed25519_pubkey,
|
||||
bandwidth_controller,
|
||||
TicketType::V1WireguardEntry,
|
||||
).await {
|
||||
Ok(_) => {
|
||||
info!("LP registration request sent successfully");
|
||||
}
|
||||
Err(e) => {
|
||||
let error_msg = format!("Failed to send LP registration request: {}", e);
|
||||
error!("{}", error_msg);
|
||||
lp_outcome.error = Some(error_msg);
|
||||
return Ok(lp_outcome);
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: Receive registration response
|
||||
info!("Waiting for LP registration response...");
|
||||
match client.receive_registration_response().await {
|
||||
Ok(gateway_data) => {
|
||||
info!("LP registration successful! Received gateway data:");
|
||||
info!(" - Gateway public key: {:?}", gateway_data.public_key);
|
||||
info!(" - Private IPv4: {}", gateway_data.private_ipv4);
|
||||
info!(" - Private IPv6: {}", gateway_data.private_ipv6);
|
||||
info!(" - Endpoint: {}", gateway_data.endpoint);
|
||||
lp_outcome.can_register = true;
|
||||
}
|
||||
Err(e) => {
|
||||
let error_msg = format!("Failed to receive LP registration response: {}", e);
|
||||
error!("{}", error_msg);
|
||||
lp_outcome.error = Some(error_msg);
|
||||
return Ok(lp_outcome);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(lp_outcome)
|
||||
}
|
||||
|
||||
fn mixnet_debug_config(
|
||||
min_gateway_performance: Option<u8>,
|
||||
ignore_egress_epoch_role: bool,
|
||||
@@ -686,6 +851,7 @@ async fn do_ping(
|
||||
as_entry: entry,
|
||||
as_exit: exit,
|
||||
wg: None,
|
||||
lp: None,
|
||||
}),
|
||||
mixnet_client,
|
||||
)
|
||||
|
||||
@@ -118,12 +118,17 @@ impl DirectoryNode {
|
||||
.first()
|
||||
.copied();
|
||||
|
||||
// Derive LP address from gateway IP + default LP control port (41264)
|
||||
// TODO: Update this when LP address is exposed in node description API
|
||||
let lp_address = ip_address.map(|ip| std::net::SocketAddr::new(ip, 41264));
|
||||
|
||||
Ok(TestedNodeDetails {
|
||||
identity: self.identity(),
|
||||
exit_router_address,
|
||||
authenticator_address,
|
||||
authenticator_version,
|
||||
ip_address,
|
||||
lp_address,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ pub struct ProbeOutcome {
|
||||
pub as_entry: Entry,
|
||||
pub as_exit: Option<Exit>,
|
||||
pub wg: Option<WgProbeResults>,
|
||||
pub lp: Option<LpProbeResults>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
@@ -44,6 +45,15 @@ pub struct WgProbeResults {
|
||||
pub download_error_v6: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
#[serde(rename = "lp")]
|
||||
pub struct LpProbeResults {
|
||||
pub can_connect: bool,
|
||||
pub can_handshake: bool,
|
||||
pub can_register: bool,
|
||||
pub error: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
#[allow(clippy::enum_variant_names)]
|
||||
|
||||
@@ -13,7 +13,7 @@ use nym_sdk::mixnet::{EventReceiver, MixnetClient, Recipient};
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::config::RegistrationClientConfig;
|
||||
use crate::lp_client::{LpClientError, LpRegistrationClient, LpTransport};
|
||||
use crate::lp_client::{LpClientError, LpTransport};
|
||||
|
||||
mod builder;
|
||||
mod config;
|
||||
@@ -28,7 +28,7 @@ pub use builder::config::{
|
||||
};
|
||||
pub use config::RegistrationMode;
|
||||
pub use error::RegistrationClientError;
|
||||
pub use lp_client::LpConfig;
|
||||
pub use lp_client::{LpConfig, LpRegistrationClient};
|
||||
pub use types::{
|
||||
LpRegistrationResult, MixnetRegistrationResult, RegistrationResult, WireguardRegistrationResult,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user