Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f4bd48263d | |||
| 5c40052d39 |
@@ -97,6 +97,8 @@ impl BuilderConfig {
|
||||
exit: self.exit_node.clone(),
|
||||
mode: self.mode,
|
||||
lp_registration_config: self.lp_registration_config,
|
||||
#[cfg(unix)]
|
||||
connection_fd_callback: self.connection_fd_callback.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,32 @@ impl LpBasedRegistrationClient {
|
||||
self.config.lp_registration_config,
|
||||
);
|
||||
|
||||
// Open the entry connection through a socket that has the connection
|
||||
// fd callback applied before connecting (sets SO_MARK on Linux), so
|
||||
// the connection is allowed through the VPN firewall during the
|
||||
// connecting state.
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let fd_callback = self.config.connection_fd_callback.clone();
|
||||
entry_client.set_dialer(Arc::new(move |addr| {
|
||||
let fd_callback = fd_callback.clone();
|
||||
Box::pin(async move {
|
||||
let socket = if addr.is_ipv4() {
|
||||
tokio::net::TcpSocket::new_v4()
|
||||
} else {
|
||||
tokio::net::TcpSocket::new_v6()
|
||||
}
|
||||
.map_err(|err| {
|
||||
nym_lp::transport::LpTransportError::connection_failure(err.to_string())
|
||||
})?;
|
||||
fd_callback(std::os::fd::AsRawFd::as_raw_fd(&socket));
|
||||
socket.connect(addr).await.map_err(|err| {
|
||||
nym_lp::transport::LpTransportError::connection_failure(err.to_string())
|
||||
})
|
||||
})
|
||||
}));
|
||||
}
|
||||
|
||||
// Perform handshake with entry gateway (outer session now established)
|
||||
entry_client.perform_handshake().await.map_err(|source| {
|
||||
RegistrationClientError::EntryGatewayRegisterLp {
|
||||
|
||||
@@ -19,4 +19,9 @@ pub struct RegistrationClientConfig {
|
||||
pub(crate) exit: NymNodeWithKeys,
|
||||
pub(crate) mode: RegistrationMode,
|
||||
pub(crate) lp_registration_config: LpRegistrationConfig,
|
||||
/// Callback invoked with the raw fd of sockets opened for registration,
|
||||
/// before connecting. Used to set `SO_MARK` on Linux so the connection is
|
||||
/// allowed through the VPN firewall during the connecting state.
|
||||
#[cfg(unix)]
|
||||
pub(crate) connection_fd_callback: std::sync::Arc<dyn Fn(std::os::fd::RawFd) + Send + Sync>,
|
||||
}
|
||||
|
||||
@@ -33,6 +33,19 @@ use std::time::Duration;
|
||||
use tokio::net::TcpStream;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
/// Custom dialer used to open the connection to the gateway.
|
||||
///
|
||||
/// Allows the caller to configure the socket before the connection is
|
||||
/// initiated, e.g. set `SO_MARK` on Linux so the connection is allowed
|
||||
/// through the VPN firewall during the connecting state.
|
||||
pub type LpDialer<S> = Arc<
|
||||
dyn Fn(
|
||||
SocketAddr,
|
||||
) -> futures::future::BoxFuture<'static, std::result::Result<S, LpTransportError>>
|
||||
+ Send
|
||||
+ Sync,
|
||||
>;
|
||||
|
||||
/// LP (Lewes Protocol) registration client for direct gateway connections.
|
||||
///
|
||||
/// This client uses a persistent TCP connection model where a single TCP
|
||||
@@ -70,6 +83,11 @@ pub struct LpRegistrationClient<S = TcpStream> {
|
||||
/// Persistent TCP stream for the connection.
|
||||
/// Opened on first use, closed after registration.
|
||||
stream: Option<S>,
|
||||
|
||||
/// Optional custom dialer used to open the connection, allowing socket
|
||||
/// configuration (e.g. `SO_MARK`) before the connection is initiated.
|
||||
/// Falls back to `S::connect` when unset.
|
||||
dialer: Option<LpDialer<S>>,
|
||||
}
|
||||
|
||||
impl<S> LpRegistrationClient<S>
|
||||
@@ -115,9 +133,18 @@ where
|
||||
transport_session: None,
|
||||
config,
|
||||
stream: None,
|
||||
dialer: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets a custom dialer used to open the connection to the gateway.
|
||||
///
|
||||
/// Allows socket configuration (e.g. setting `SO_MARK` on Linux so the
|
||||
/// connection is allowed through the VPN firewall) before connecting.
|
||||
pub fn set_dialer(&mut self, dialer: LpDialer<S>) {
|
||||
self.dialer = Some(dialer);
|
||||
}
|
||||
|
||||
/// Attempt to use this `LpRegistrationClient` as transport for `NestedSession`
|
||||
pub fn as_nested_connection(&mut self, exit_address: SocketAddr) -> NestedConnection<'_, S> {
|
||||
NestedConnection {
|
||||
@@ -209,22 +236,32 @@ where
|
||||
self.gateway_lp_address
|
||||
);
|
||||
|
||||
let mut stream = tokio::time::timeout(
|
||||
self.config.connect_timeout,
|
||||
S::connect(self.gateway_lp_address),
|
||||
)
|
||||
.await
|
||||
.map_err(|_| LpClientError::TcpConnection {
|
||||
address: self.gateway_lp_address.to_string(),
|
||||
source: LpTransportError::ConnectionFailure(format!(
|
||||
"Connection timeout after {:?}",
|
||||
self.config.connect_timeout
|
||||
)),
|
||||
})?
|
||||
.map_err(|source| LpClientError::TcpConnection {
|
||||
address: self.gateway_lp_address.to_string(),
|
||||
source,
|
||||
})?;
|
||||
let connect_result = match &self.dialer {
|
||||
Some(dialer) => {
|
||||
tokio::time::timeout(self.config.connect_timeout, dialer(self.gateway_lp_address))
|
||||
.await
|
||||
}
|
||||
None => {
|
||||
tokio::time::timeout(
|
||||
self.config.connect_timeout,
|
||||
S::connect(self.gateway_lp_address),
|
||||
)
|
||||
.await
|
||||
}
|
||||
};
|
||||
|
||||
let mut stream = connect_result
|
||||
.map_err(|_| LpClientError::TcpConnection {
|
||||
address: self.gateway_lp_address.to_string(),
|
||||
source: LpTransportError::ConnectionFailure(format!(
|
||||
"Connection timeout after {:?}",
|
||||
self.config.connect_timeout
|
||||
)),
|
||||
})?
|
||||
.map_err(|source| LpClientError::TcpConnection {
|
||||
address: self.gateway_lp_address.to_string(),
|
||||
source,
|
||||
})?;
|
||||
|
||||
// Set TCP_NODELAY for low latency
|
||||
stream
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "@nymproject/nym-client-wasm",
|
||||
"version": "1.0.0",
|
||||
"sideEffects": false
|
||||
}
|
||||
Reference in New Issue
Block a user