c07ef0253d
* Replace MixnetStream with LP framing
- Replace custom header with LpFrameHeader
- Added sequence number for message ordering
* IPR: support LP Stream-framed client connections
- Detect and route LP Stream frames in mixnet_listener
- Wrap inline responses in LP Stream frames
- Thread stream_id to ConnectedClientHandler for TUN responses
* sdk: add ipr_wrapper module with IpMixStream
- IpMixStream wraps MixnetStream for IPR tunnel over mixnet
- LP Stream framing handled automatically by MixnetStream
- Gateway discovery, connect handshake, IP packet send/receive
* sdk: remove superseded stream_wrapper module
* Trim obvious comments, add architecture.md stub
* sdk: add missing deps and fix warnings
* Cut down architecture diagram until finished with rest of the code, leaving stubs
* sdk: refactor IpMixStream, extract shared helpers
- Extract gateway discovery and connect response parsing
- Add recv() to MixnetStream, remove 64KB read buffer
- Simplify IpMixStream constructor
* Fix SphinxStream renames missed during rebase
* Add IpPacketResponse::from_bytes() for stream-based deserialization
* Clean up ip_packet_client: delete stale connect.rs, take raw bytes not ReconstructedMessage
* Clippy
* Delete unused ip_packet_client modules
- Remove helpers.rs (ICMP utilities moved to example)
- Remove error.rs (errors consolidated into sdk/error.rs)
- Remove README.md
- Update module root to only export discovery + listener
* Simplify listener, IpMixStream, and network_env
- Collapse IprListener struct into standalone handle_ipr_response()
- Move check_ipr_message_version() into listener.rs
- Remove IpMixStream test module (moved to example)
- Remove parse_network() and commented-out Sandbox arms
- Return Result from find_workspace_root() instead of panicking
- Add IprTunnelDisconnected and WorkspaceRootNotFound error variants
* Refactor IPR stream handling and document seq conventions
- Inline stream_id tracking (remove current_stream_id field)
- Re-export encode_stream_frame from clients module
- Document seq=0 reservation for inline control responses
- Document data-path counter starting at 1 with skip-on-wrap
* Add ipr_tunnel example for integration testing
- ICMP ping through IPR with --gateway flag for targeting specific exits
- Move pnet_packet from dependencies to dev-dependencies
* Add message reordering to stream router
- Buffer out-of-order messages per-stream using BTreeMap
- Drain contiguous sequences individually to preserve message boundaries
- Drop duplicate/old sequence numbers with a warning
- Remove dead_code allow on StreamFrame::sequence_num
* Clean up comments and fill architecture.md
- Remove separator line comments
- Update stale comments about ordering not being implemented
- Remove collapsible_if allows, use let-else instead
- Fill in architecture.md data flow and connection lifecycle
* Simplify ipr_tunnel example to minimal smoke test
- Single ping instead of multi-ping loop
- Remove identifier and PING_COUNT
- Collapse ICMP helpers into single build_icmp_ping function
* Add dual-stack IPv6 ping and rename gateway → ipr
- Rename --gateway flag to --ipr and new_with_gateway() to new_with_ipr()
- Add ICMPv6 ping to ipr_tunnel example for dual-stack smoke test
- Tighten echo reply validation (protocol field check, diagnostic output)
- Document IP allocation (subnets, static vs dynamic, client keying) in architecture.md
- Promote LP Stream Open handshake log to INFO
* Tweak subnet comment in docs
* Don't stop IPR listener on decode failure
- Change break to continue so garbage packets can't kill the listener
- Remaining valid packets in the bundle are still processed
* Fix license headers and use workspace dep for pnet_packet
- Switch GPL-3.0 to Apache-2.0 on all SDK library files
- Add missing license headers to 7 files
- Use workspace version for pnet_packet dependency
* Document IP pool isolation from WG/LP dVPN pool
- IPR uses 10.0.0.0/16 on nymtun, WG uses 10.1.0.0/16 on nymwg
- Reference constants.rs as source of truth
* Remove network_env.rs and simplify IpMixStream API
- Default to mainnet via setup_env(None) instead of requiring env param
- Remove NetworkEnvironment enum and workspace root detection
- Remove WorkspaceRootNotFound error variant
- Update ipr_tunnel example to match new signatures
* Use weighted random selection for IPR gateway discovery
- Replace max_by_key with choose_weighted biased by performance score
- Prevents all clients converging on a single highest-performing IPR
* Cap stream reorder buffer to prevent unbounded memory growth
- Add MAX_REORDER_BUFFER (256) to limit per-stream pending messages:
- buffer overflows = skip ahead to lowest buffered seq and drain
- protects against malicious senders that deliberately skip sequence numbers
* Extract shared IPR response helpers into nym-ip-packet-requests
- Add response_helpers module with version check, connect response
parsing, and control response dispatch
- SDK ip_packet_client now delegates to shared module
- Monorepo nym-ip-packet-client uses shared version check and
connect response parsing
- Fix doc comment attributing fork to nym-vpn-client
* Extract ICMP test helpers into nym-ip-packet-requests
- Add icmp_utils module behind test-utils feature flag
- Move build_icmp_ping, build_icmpv6_ping, is_echo_reply_v4/v6 from
example
- Update ipr_tunnel example to use shared helpers
* Add protocol v9 LP-framed transport marker
- Add v9 module (re-exports v8, VERSION=9)
- Accept v9 requests and responses in IPR
- Switch SDK IpMixStream to send v9
* Log protocol version in dynamic connect requests
* Remove KCP from IPR and fix unwrap_or_default in SDK
- Remove all KCP session management from ip-packet-router (replaced by
LP Stream framing)
- Drop nym-kcp dependency and KcpError variant from IPR
- Replace unwrap_or_default with ok_or(Error::NoNymAPIUrl) in
IpMixStream::new()
* Add v9 protocol wrapper constructors and enforce version/transport
consistency
- Add v9::new_connect_request(), new_data_request(),
new_ip_packet_response() to centralise version stamping
- Replace manual protocol.version overrides in SDK and IPR with v9
wrapper calls
- Bump nym-ip-packet-client current re-export from v8 to v9
- Enforce LP Stream frames must carry v9+ payloads, non-stream must be
v8 or lower
* Filter IPR exit nodes by minimum v9-compatible release version
- Define MIN_RELEASE_VERSION (1.30.0) in ip-packet-requests/v9 alongside protocol constants
- Add semver-based filtering in SDK gateway discovery to skip nodes below v9 threshold
- Add semver dependency to ip-packet-requests and nym-sdk
* Use numeric version comparison for transport/version enforcement
- Compare version as u8 instead of enum equality so future v10+ is handled correctly
- Remove unused `use super::*` import left over from KCP test removal
158 lines
4.8 KiB
Rust
158 lines
4.8 KiB
Rust
// Copyright 2025 - Nym Technologies SA <contact@nymtech.net>
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
use nym_ip_packet_requests::v8::response::{ConnectFailureReason, IpPacketResponseData};
|
|
use nym_validator_client::nym_api::error::NymAPIError;
|
|
use nym_validator_client::nyxd::error::NyxdError;
|
|
use std::path::PathBuf;
|
|
|
|
/// Top-level Error enum for the mixnet client and its relevant types.
|
|
#[derive(Debug, thiserror::Error)]
|
|
pub enum Error {
|
|
#[error("i/o error: {0}")]
|
|
IoError(#[from] std::io::Error),
|
|
|
|
#[error("toml serialization error: {0}")]
|
|
TomlSerializationError(#[from] toml::ser::Error),
|
|
|
|
#[error("toml deserialization error: {0}")]
|
|
TomlDeserializationError(#[from] toml::de::Error),
|
|
|
|
#[error("Ed25519 error: {0}")]
|
|
Ed25519RecoveryError(#[from] nym_crypto::asymmetric::ed25519::Ed25519RecoveryError),
|
|
|
|
#[error(transparent)]
|
|
ClientCoreError(#[from] nym_client_core::error::ClientCoreError),
|
|
|
|
#[error("key file encountered that we don't want to overwrite: {0}")]
|
|
DontOverwrite(PathBuf),
|
|
|
|
#[error("shared gateway key file encountered that we don't want to overwrite: {0}")]
|
|
DontOverwriteGatewayKey(PathBuf),
|
|
|
|
#[error("no gateway config available for writing")]
|
|
GatewayNotAvailableForWriting,
|
|
|
|
#[error("expected to received a directory, received: {0}")]
|
|
ExpectedDirectory(PathBuf),
|
|
|
|
#[error("failed to transition to registered state before connection to mixnet")]
|
|
FailedToTransitionToRegisteredState,
|
|
|
|
#[error(
|
|
"registering with gateway when the client is already in a registered state is not \
|
|
supported, and likely and user mistake"
|
|
)]
|
|
ReregisteringGatewayNotSupported,
|
|
|
|
#[error("no gateway key set")]
|
|
NoGatewayKeySet,
|
|
|
|
#[error("credentials mode not enabled")]
|
|
DisabledCredentialsMode,
|
|
|
|
#[error("bad validator details: {0}")]
|
|
BadValidatorDetails(#[from] NyxdError),
|
|
|
|
#[error("socks5 configuration set: {}, but expected to be {}", set, !set)]
|
|
Socks5Config { set: bool },
|
|
|
|
#[error("socks5 channel could not be started")]
|
|
Socks5NotStarted,
|
|
|
|
#[error("bandwidth controller error: {0}")]
|
|
BandwidthControllerError(#[from] nym_bandwidth_controller::error::BandwidthControllerError),
|
|
|
|
#[error("invalid voucher blob")]
|
|
InvalidVoucherBlob,
|
|
|
|
#[error("invalid mnemonic: {0}")]
|
|
InvalidMnemonic(#[from] bip39::Error),
|
|
|
|
#[error("failed to use reply storage backend: {source}")]
|
|
ReplyStorageError {
|
|
source: Box<dyn std::error::Error + Send + Sync>,
|
|
},
|
|
|
|
#[error("failed to use key storage backend: {source}")]
|
|
KeyStorageError {
|
|
source: Box<dyn std::error::Error + Send + Sync>,
|
|
},
|
|
|
|
#[error("failed to use credential storage backend: {source}")]
|
|
CredentialStorageError {
|
|
source: Box<dyn std::error::Error + Send + Sync>,
|
|
},
|
|
|
|
#[error(transparent)]
|
|
CredentialIssuanceError {
|
|
#[from]
|
|
source: nym_credential_utils::Error,
|
|
},
|
|
|
|
#[error("loaded shared gateway key without providing information about what gateway it corresponds to")]
|
|
GatewayWithUnknownEndpoint,
|
|
|
|
#[error("failed to send the provided message")]
|
|
MessageSendingFailure,
|
|
|
|
#[error("this operation is currently unsupported: {details}")]
|
|
Unsupported { details: String },
|
|
|
|
#[error(transparent)]
|
|
Bincode(#[from] bincode::Error),
|
|
|
|
#[error("Failed to get shutdown tracker from the task runtime registry: {0}")]
|
|
RegistryAccess(#[from] nym_task::RegistryAccessError),
|
|
|
|
#[error("Cannot use message-based functions after stream mode is activated")]
|
|
StreamModeActive,
|
|
|
|
#[error("Stream listener has already been taken — listener() can only be called once")]
|
|
ListenerAlreadyTaken,
|
|
|
|
#[error("Stream subsystem failed to initialise: reconstructed_receiver unavailable")]
|
|
StreamInitFailure,
|
|
|
|
#[error("client not connected")]
|
|
IprStreamClientNotConnected,
|
|
|
|
#[error("listening for connection response timed out")]
|
|
IPRConnectResponseTimeout,
|
|
|
|
#[error("stream closed")]
|
|
IPRClientStreamClosed,
|
|
|
|
#[error("expected control response, got {0:?}")]
|
|
UnexpectedResponseType(IpPacketResponseData),
|
|
|
|
#[error("connect denied: {0:?}")]
|
|
ConnectDenied(ConnectFailureReason),
|
|
|
|
#[allow(clippy::result_large_err)]
|
|
#[error("api directory error: {0}")]
|
|
GatewayDirectoryError(#[from] NymAPIError),
|
|
|
|
#[error("did not receive Nym API URL")]
|
|
NoNymAPIUrl,
|
|
|
|
#[error("no available gateway")]
|
|
NoGatewayAvailable,
|
|
|
|
#[error("tunnel disconnected by IPR")]
|
|
IprTunnelDisconnected,
|
|
|
|
#[error("message version check failed: {0}")]
|
|
IPRMessageVersionCheckFailed(String),
|
|
}
|
|
|
|
impl Error {
|
|
pub fn new_unsupported<S: Into<String>>(details: S) -> Self {
|
|
Error::Unsupported {
|
|
details: details.into(),
|
|
}
|
|
}
|
|
}
|
|
|
|
pub type Result<T, E = Error> = std::result::Result<T, E>;
|