Simplify IPR v8 (#5532)

* Purge stuff from v8

* Adapt to v8 changes

* Use protocol in ipr header

* Remove commented out code

* Remove unused error
This commit is contained in:
Jon Häggblad
2025-02-28 13:04:53 +01:00
committed by GitHub
parent f13ce6bf2d
commit 128f69a5d6
13 changed files with 311 additions and 567 deletions
Generated
+4
View File
@@ -5913,6 +5913,7 @@ dependencies = [
"bytes",
"nym-bin-common",
"nym-crypto",
"nym-service-provider-requests-common",
"nym-sphinx",
"rand 0.8.5",
"serde",
@@ -5944,6 +5945,7 @@ dependencies = [
"nym-network-defaults",
"nym-network-requester",
"nym-sdk",
"nym-service-provider-requests-common",
"nym-service-providers-common",
"nym-sphinx",
"nym-task",
@@ -6517,7 +6519,9 @@ dependencies = [
name = "nym-service-provider-requests-common"
version = "0.1.0"
dependencies = [
"bincode",
"serde",
"thiserror 2.0.11",
]
[[package]]
+1
View File
@@ -13,6 +13,7 @@ bincode = { workspace = true }
bytes = { workspace = true }
nym-bin-common = { path = "../bin-common" }
nym-crypto = { path = "../crypto" }
nym-service-provider-requests-common = { path = "../service-provider-requests-common" }
nym-sphinx = { path = "../nymsphinx" }
rand = { workspace = true }
serde = { workspace = true, features = ["derive"] }
+76 -308
View File
@@ -1,20 +1,14 @@
use std::{fmt, sync::Arc};
use std::fmt;
use nym_crypto::asymmetric::ed25519;
use nym_sphinx::addressing::Recipient;
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use serde::{Deserialize, Serialize};
use time::OffsetDateTime;
use crate::{
sign::{SignatureError, SignedRequest},
IpPair,
};
use super::VERSION;
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct IpPacketRequest {
pub version: u8,
pub protocol: Protocol,
pub data: IpPacketRequestData,
}
@@ -26,9 +20,8 @@ pub enum IpPacketRequestData {
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum ControlRequest {
StaticConnect(SignedStaticConnectRequest),
DynamicConnect(SignedDynamicConnectRequest),
Disconnect(SignedDisconnectRequest),
Connect(ConnectRequest),
Disconnect(DisconnectRequest),
Ping(PingRequest),
Health(HealthRequest),
}
@@ -39,35 +32,10 @@ pub struct DataRequest {
pub ip_packets: bytes::Bytes,
}
// A static connect request is when the client provides the internal IP address it will use on the
// ip packet router.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct StaticConnectRequest {
pub request_id: u64,
// The requested internal IP addresses.
pub ips: IpPair,
// The maximum time in milliseconds the IPR should wait when filling up a mix packet
// with ip packets.
pub buffer_timeout: Option<u64>,
// Timestamp of when the request was sent by the client.
pub timestamp: OffsetDateTime,
pub sender: SentBy,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct SignedStaticConnectRequest {
pub request: StaticConnectRequest,
pub signature: Option<ed25519::Signature>,
}
// A dynamic connect request is when the client does not provide the internal IP address it will use
// on the ip packet router, and instead requests one to be assigned to it.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct DynamicConnectRequest {
pub struct ConnectRequest {
pub request_id: u64,
// The maximum time in milliseconds the IPR should wait when filling up a mix packet
@@ -76,14 +44,6 @@ pub struct DynamicConnectRequest {
// Timestamp of when the request was sent by the client.
pub timestamp: OffsetDateTime,
pub sender: SentBy,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct SignedDynamicConnectRequest {
pub request: DynamicConnectRequest,
pub signature: Option<ed25519::Signature>,
}
// A disconnect request is when the client wants to disconnect from the ip packet router and free
@@ -94,14 +54,6 @@ pub struct DisconnectRequest {
// Timestamp of when the request was sent by the client.
pub timestamp: OffsetDateTime,
pub sender: SentBy,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct SignedDisconnectRequest {
pub request: DisconnectRequest,
pub signature: Option<ed25519::Signature>,
}
// A ping request is when the client wants to check if the ip packet router is still alive.
@@ -109,8 +61,6 @@ pub struct SignedDisconnectRequest {
pub struct PingRequest {
pub request_id: u64,
pub sender: SentBy,
// Timestamp of when the request was sent by the client.
pub timestamp: OffsetDateTime,
}
@@ -119,142 +69,89 @@ pub struct PingRequest {
pub struct HealthRequest {
pub request_id: u64,
pub sender: SentBy,
// Timestamp of when the request was sent by the client.
pub timestamp: OffsetDateTime,
}
// When constructing the request, use this return address. It has the keypair to be able to sign
// the request if we reveal the sender.
#[derive(Clone, Debug)]
pub enum ReturnAddress {
AnonymousSenderTag,
NymAddress {
reply_to: Box<Recipient>,
signing_keypair: Arc<ed25519::KeyPair>,
},
}
// The serialized sender field in the request, that does not contain the keypair.
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub enum SentBy {
AnonymousSenderTag,
NymAddress(Box<Recipient>),
}
impl IpPacketRequest {
pub fn new_connect_request(
ips: Option<IpPair>,
buffer_timeout: Option<u64>,
return_address: ReturnAddress,
) -> Result<(Self, u64), SignatureError> {
pub fn new_connect_request(buffer_timeout: Option<u64>) -> (Self, u64) {
let protocol = Protocol {
version: VERSION,
service_provider_type: ServiceProviderType::IpPacketRouter,
};
let request_id = rand::random();
let timestamp = OffsetDateTime::now_utc();
let sender = return_address.clone().into();
let request = if let Some(ips) = ips {
let request = StaticConnectRequest {
request_id,
ips,
buffer_timeout,
timestamp,
sender,
};
let signature = return_address
.signing_key()
.map(|keypair| {
request
.to_bytes()
.map(|bytes| keypair.private_key().sign(bytes))
})
.transpose()?;
ControlRequest::StaticConnect(SignedStaticConnectRequest { request, signature })
} else {
let request = DynamicConnectRequest {
request_id,
buffer_timeout,
timestamp,
sender,
};
let signature = return_address
.signing_key()
.map(|keypair| {
request
.to_bytes()
.map(|bytes| keypair.private_key().sign(bytes))
})
.transpose()?;
ControlRequest::DynamicConnect(SignedDynamicConnectRequest { request, signature })
let connect = ConnectRequest {
request_id,
buffer_timeout,
timestamp,
};
let request = Self {
version: VERSION,
data: IpPacketRequestData::Control(Box::new(request)),
protocol,
data: IpPacketRequestData::Control(Box::new(ControlRequest::Connect(connect))),
};
Ok((request, request_id))
(request, request_id)
}
pub fn new_disconnect_request(
return_address: ReturnAddress,
) -> Result<(Self, u64), SignatureError> {
pub fn new_disconnect_request() -> (Self, u64) {
let protocol = Protocol {
version: VERSION,
service_provider_type: ServiceProviderType::IpPacketRouter,
};
let request_id = rand::random();
let timestamp = OffsetDateTime::now_utc();
let sender = return_address.clone().into();
let request = DisconnectRequest {
let disconnect = DisconnectRequest {
request_id,
timestamp,
sender,
};
let signature = return_address
.signing_key()
.map(|keypair| {
request
.to_bytes()
.map(|bytes| keypair.private_key().sign(bytes))
})
.transpose()?;
let request = Self {
version: VERSION,
data: IpPacketRequestData::Control(Box::new(ControlRequest::Disconnect(
SignedDisconnectRequest { request, signature },
))),
protocol,
data: IpPacketRequestData::Control(Box::new(ControlRequest::Disconnect(disconnect))),
};
Ok((request, request_id))
(request, request_id)
}
pub fn new_data_request(ip_packets: bytes::Bytes) -> Self {
Self {
version: VERSION,
protocol: Protocol {
version: VERSION,
service_provider_type: ServiceProviderType::IpPacketRouter,
},
data: IpPacketRequestData::Data(DataRequest { ip_packets }),
}
}
pub fn new_ping(return_address: ReturnAddress) -> (Self, u64) {
pub fn new_ping() -> (Self, u64) {
let protocol = Protocol {
version: VERSION,
service_provider_type: ServiceProviderType::IpPacketRouter,
};
let request_id = rand::random();
let timestamp = OffsetDateTime::now_utc();
let sender = return_address.into();
let ping_request = PingRequest {
request_id,
sender,
timestamp,
};
let request = Self {
version: VERSION,
protocol,
data: IpPacketRequestData::Control(Box::new(ControlRequest::Ping(ping_request))),
};
(request, request_id)
}
pub fn new_health_request(return_address: ReturnAddress) -> (Self, u64) {
pub fn new_health_request() -> (Self, u64) {
let protocol = Protocol {
version: VERSION,
service_provider_type: ServiceProviderType::IpPacketRouter,
};
let request_id = rand::random();
let timestamp = OffsetDateTime::now_utc();
let sender = return_address.into();
let health_request = HealthRequest {
request_id,
sender,
timestamp,
};
let request = Self {
version: VERSION,
protocol,
data: IpPacketRequestData::Control(Box::new(ControlRequest::Health(health_request))),
};
(request, request_id)
@@ -267,13 +164,6 @@ impl IpPacketRequest {
}
}
pub fn verify(&self) -> Result<(), SignatureError> {
match &self.data {
IpPacketRequestData::Control(c) => c.verify(),
IpPacketRequestData::Data(_) => Ok(()),
}
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
crate::make_bincode_serializer().serialize(self)
@@ -292,7 +182,7 @@ impl fmt::Display for IpPacketRequest {
write!(
f,
"IpPacketRequest {{ version: {}, data: {} }}",
self.version, self.data
self.protocol.version, self.data
)
}
}
@@ -309,30 +199,18 @@ impl fmt::Display for IpPacketRequestData {
impl ControlRequest {
fn id(&self) -> u64 {
match self {
ControlRequest::StaticConnect(request) => request.request.request_id,
ControlRequest::DynamicConnect(request) => request.request.request_id,
ControlRequest::Disconnect(request) => request.request.request_id,
ControlRequest::Connect(request) => request.request_id,
ControlRequest::Disconnect(request) => request.request_id,
ControlRequest::Ping(request) => request.request_id,
ControlRequest::Health(request) => request.request_id,
}
}
fn verify(&self) -> Result<(), SignatureError> {
match self {
ControlRequest::StaticConnect(request) => request.verify(),
ControlRequest::DynamicConnect(request) => request.verify(),
ControlRequest::Disconnect(request) => request.verify(),
ControlRequest::Ping(_) => Ok(()),
ControlRequest::Health(_) => Ok(()),
}
}
}
impl fmt::Display for ControlRequest {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
ControlRequest::StaticConnect(_) => write!(f, "StaticConnect"),
ControlRequest::DynamicConnect(_) => write!(f, "DynamicConnect"),
ControlRequest::Connect(_) => write!(f, "Connect"),
ControlRequest::Disconnect(_) => write!(f, "Disconnect"),
ControlRequest::Ping(_) => write!(f, "Ping"),
ControlRequest::Health(_) => write!(f, "Health"),
@@ -340,128 +218,17 @@ impl fmt::Display for ControlRequest {
}
}
impl StaticConnectRequest {
pub fn to_bytes(&self) -> Result<Vec<u8>, SignatureError> {
impl ConnectRequest {
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
crate::make_bincode_serializer()
.serialize(self)
.map_err(|error| SignatureError::RequestSerializationError {
message: "failed to serialize request to binary".to_string(),
error,
})
}
}
impl SignedRequest for SignedStaticConnectRequest {
fn request_as_bytes(&self) -> Result<Vec<u8>, SignatureError> {
self.request.to_bytes()
}
fn timestamp(&self) -> OffsetDateTime {
self.request.timestamp
}
fn identity(&self) -> Option<&ed25519::PublicKey> {
self.request.sender.identity()
}
fn signature(&self) -> Option<&ed25519::Signature> {
self.signature.as_ref()
}
}
impl DynamicConnectRequest {
pub fn to_bytes(&self) -> Result<Vec<u8>, SignatureError> {
use bincode::Options;
crate::make_bincode_serializer()
.serialize(self)
.map_err(|error| SignatureError::RequestSerializationError {
message: "failed to serialize request to binary".to_string(),
error,
})
}
}
impl SignedRequest for SignedDynamicConnectRequest {
fn request_as_bytes(&self) -> Result<Vec<u8>, SignatureError> {
self.request.to_bytes()
}
fn timestamp(&self) -> OffsetDateTime {
self.request.timestamp
}
fn identity(&self) -> Option<&ed25519::PublicKey> {
self.request.sender.identity()
}
fn signature(&self) -> Option<&ed25519::Signature> {
self.signature.as_ref()
crate::make_bincode_serializer().serialize(self)
}
}
impl DisconnectRequest {
pub fn to_bytes(&self) -> Result<Vec<u8>, SignatureError> {
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
crate::make_bincode_serializer()
.serialize(self)
.map_err(|error| SignatureError::RequestSerializationError {
message: "failed to serialize request to binary".to_string(),
error,
})
}
}
impl SignedRequest for SignedDisconnectRequest {
fn request_as_bytes(&self) -> Result<Vec<u8>, SignatureError> {
self.request.to_bytes()
}
fn timestamp(&self) -> OffsetDateTime {
self.request.timestamp
}
fn identity(&self) -> Option<&ed25519::PublicKey> {
self.request.sender.identity()
}
fn signature(&self) -> Option<&ed25519::Signature> {
self.signature.as_ref()
}
}
impl SentBy {
fn identity(&self) -> Option<&ed25519::PublicKey> {
match self {
SentBy::AnonymousSenderTag => None,
SentBy::NymAddress(recipient) => Some(recipient.identity()),
}
}
}
impl From<Recipient> for SentBy {
fn from(recipient: Recipient) -> Self {
SentBy::NymAddress(Box::new(recipient))
}
}
impl ReturnAddress {
fn signing_key(&self) -> Option<&ed25519::KeyPair> {
match self {
ReturnAddress::AnonymousSenderTag => None,
ReturnAddress::NymAddress {
signing_keypair, ..
} => Some(signing_keypair.as_ref()),
}
}
}
impl From<ReturnAddress> for SentBy {
fn from(return_address: ReturnAddress) -> Self {
match return_address {
ReturnAddress::AnonymousSenderTag => SentBy::AnonymousSenderTag,
ReturnAddress::NymAddress { reply_to, .. } => SentBy::NymAddress(reply_to),
}
crate::make_bincode_serializer().serialize(self)
}
}
@@ -470,47 +237,44 @@ mod tests {
use time::macros::datetime;
use super::*;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
#[test]
fn check_size_of_request() {
let connect = IpPacketRequest {
version: 4,
data: IpPacketRequestData::Control(Box::new(ControlRequest::StaticConnect(
SignedStaticConnectRequest {
request: StaticConnectRequest {
request_id: 123,
ips: IpPair::new(
Ipv4Addr::from_str("10.0.0.1").unwrap(),
Ipv6Addr::from_str("fc00::1").unwrap(),
),
buffer_timeout: None,
timestamp: datetime!(2024-01-01 12:59:59.5 UTC),
sender: SentBy::AnonymousSenderTag,
},
signature: None,
},
))),
protocol: Protocol {
version: 4,
service_provider_type: ServiceProviderType::IpPacketRouter,
},
data: IpPacketRequestData::Control(Box::new(ControlRequest::Connect(ConnectRequest {
request_id: 123,
buffer_timeout: None,
timestamp: datetime!(2024-01-01 12:59:59.5 UTC),
}))),
};
assert_eq!(connect.to_bytes().unwrap().len(), 42);
assert_eq!(connect.to_bytes().unwrap().len(), 21);
}
#[test]
fn check_size_of_data() {
let data = IpPacketRequest {
version: 4,
protocol: Protocol {
version: 4,
service_provider_type: ServiceProviderType::IpPacketRouter,
},
data: IpPacketRequestData::Data(DataRequest {
ip_packets: bytes::Bytes::from(vec![1u8; 32]),
}),
};
assert_eq!(data.to_bytes().unwrap().len(), 35);
assert_eq!(data.to_bytes().unwrap().len(), 36);
}
#[test]
fn serialize_and_deserialize_data_request() {
let data = IpPacketRequest {
version: 4,
protocol: Protocol {
version: 4,
service_provider_type: ServiceProviderType::IpPacketRouter,
},
data: IpPacketRequestData::Data(DataRequest {
ip_packets: bytes::Bytes::from(vec![1, 2, 4, 2, 5]),
}),
@@ -525,7 +289,11 @@ mod tests {
)
.unwrap();
assert_eq!(deserialized.version, 4);
assert_eq!(deserialized.protocol.version, 4);
assert_eq!(
deserialized.protocol.service_provider_type,
ServiceProviderType::IpPacketRouter
);
assert_eq!(
deserialized.data,
IpPacketRequestData::Data(DataRequest {
+13 -53
View File
@@ -24,11 +24,8 @@ pub struct DataResponse {
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum ControlResponse {
// Response for a static connect request
StaticConnect(StaticConnectResponse),
// Response for a dynamic connect request
DynamicConnect(DynamicConnectResponse),
// Response for a connect request
Connect(ConnectResponse),
// Response for a disconnect initiqated by the client
Disconnect(DisconnectResponse),
@@ -47,51 +44,24 @@ pub enum ControlResponse {
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct StaticConnectResponse {
pub struct ConnectResponse {
pub request_id: u64,
pub reply: StaticConnectResponseReply,
pub reply: ConnectResponseReply,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum StaticConnectResponseReply {
Success,
Failure(StaticConnectFailureReason),
}
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
pub enum StaticConnectFailureReason {
#[error("requested ip address is already in use")]
RequestedIpAlreadyInUse,
#[error("client is already connected")]
ClientAlreadyConnected,
#[error("request timestamp is out of date")]
OutOfDateTimestamp,
#[error("{0}")]
Other(String),
pub enum ConnectResponseReply {
Success(ConnectSuccess),
Failure(ConnectFailureReason),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DynamicConnectResponse {
pub request_id: u64,
pub reply: DynamicConnectResponseReply,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum DynamicConnectResponseReply {
Success(DynamicConnectSuccess),
Failure(DynamicConnectFailureReason),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct DynamicConnectSuccess {
pub struct ConnectSuccess {
pub ips: IpPair,
}
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
pub enum DynamicConnectFailureReason {
pub enum ConnectFailureReason {
#[error("client is already connected")]
ClientAlreadyConnected,
@@ -229,8 +199,7 @@ impl IpPacketResponseData {
impl ControlResponse {
fn id(&self) -> Option<u64> {
match self {
ControlResponse::StaticConnect(response) => Some(response.request_id),
ControlResponse::DynamicConnect(response) => Some(response.request_id),
ControlResponse::Connect(response) => Some(response.request_id),
ControlResponse::Disconnect(response) => Some(response.request_id),
ControlResponse::UnrequestedDisconnect(_) => None,
ControlResponse::Pong(response) => Some(response.request_id),
@@ -240,20 +209,11 @@ impl ControlResponse {
}
}
impl StaticConnectResponseReply {
impl ConnectResponseReply {
pub fn is_success(&self) -> bool {
match self {
StaticConnectResponseReply::Success => true,
StaticConnectResponseReply::Failure(_) => false,
}
}
}
impl DynamicConnectResponseReply {
pub fn is_success(&self) -> bool {
match self {
DynamicConnectResponseReply::Success(_) => true,
DynamicConnectResponseReply::Failure(_) => false,
ConnectResponseReply::Success(_) => true,
ConnectResponseReply::Failure(_) => false,
}
}
}
@@ -12,3 +12,7 @@ readme.workspace = true
[dependencies]
serde = { workspace = true, features = ["derive"] }
thiserror.workspace = true
[dev-dependencies]
bincode.workspace = true
@@ -1,8 +1,16 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::fmt;
use serde::{Deserialize, Serialize};
#[derive(thiserror::Error, Debug)]
pub enum ProtocolError {
#[error("invalid service provider type: {0}")]
InvalidServiceProviderType(u8),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
#[repr(u8)]
pub enum ServiceProviderType {
@@ -11,8 +19,103 @@ pub enum ServiceProviderType {
Authenticator = 2,
}
impl fmt::Display for ServiceProviderType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::NetworkRequester => write!(f, "NetworkRequester"),
Self::IpPacketRouter => write!(f, "IpPacketRouter"),
Self::Authenticator => write!(f, "Authenticator"),
}
}
}
impl TryFrom<u8> for ServiceProviderType {
type Error = ProtocolError;
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(Self::NetworkRequester),
1 => Ok(Self::IpPacketRouter),
2 => Ok(Self::Authenticator),
_ => Err(ProtocolError::InvalidServiceProviderType(value)),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Protocol {
pub version: u8,
pub service_provider_type: ServiceProviderType,
}
impl TryFrom<&[u8; 2]> for Protocol {
type Error = ProtocolError;
fn try_from(bytes: &[u8; 2]) -> Result<Self, Self::Error> {
let version = bytes[0];
let service_provider_type = ServiceProviderType::try_from(bytes[1])
.map_err(|_| ProtocolError::InvalidServiceProviderType(bytes[1]))?;
Ok(Self {
version,
service_provider_type,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use bincode::Options;
fn make_bincode_serializer() -> impl bincode::Options {
bincode::DefaultOptions::new()
.with_big_endian()
.with_varint_encoding()
}
#[test]
fn protocol_serialization() {
let protocol = Protocol {
version: 4,
service_provider_type: ServiceProviderType::NetworkRequester,
};
let serialized = make_bincode_serializer().serialize(&protocol).unwrap();
let deserialized: Protocol = make_bincode_serializer().deserialize(&serialized).unwrap();
assert_eq!(protocol, deserialized);
}
#[test]
fn compact_serialization() {
let protocol = Protocol {
version: 4,
service_provider_type: ServiceProviderType::NetworkRequester,
};
let serialized = make_bincode_serializer().serialize(&protocol).unwrap();
assert_eq!(serialized.len(), 2);
}
#[test]
fn protocol_deserialization() {
let bytes = [4, ServiceProviderType::NetworkRequester as u8];
let deserialized = Protocol::try_from(&bytes).unwrap();
let expected = Protocol {
version: 4,
service_provider_type: ServiceProviderType::NetworkRequester,
};
assert_eq!(expected, deserialized);
}
#[test]
fn invalid_protocol_deserialization() {
let bytes = [4, 3];
let deserialized = Protocol::try_from(&bytes);
assert!(deserialized.is_err());
}
}
@@ -27,6 +27,7 @@ nym-ip-packet-requests = { path = "../../common/ip-packet-requests" }
nym-network-defaults = { path = "../../common/network-defaults" }
nym-network-requester = { path = "../network-requester" }
nym-sdk = { path = "../../sdk/rust/nym-sdk" }
nym-service-provider-requests-common = { path = "../../common/service-provider-requests-common" }
nym-service-providers-common = { path = "../common" }
nym-sphinx = { path = "../../common/nymsphinx" }
nym-task = { path = "../../common/task" }
@@ -3,7 +3,6 @@
use std::fmt;
use nym_ip_packet_requests::v8::request::SentBy;
use nym_sdk::mixnet::{AnonymousSenderTag, Recipient};
use crate::error::{IpPacketRouterError, Result};
@@ -43,16 +42,3 @@ impl From<AnonymousSenderTag> for ConnectedClientId {
ConnectedClientId::AnonymousSenderTag(tag)
}
}
impl TryFrom<(SentBy, Option<AnonymousSenderTag>)> for ConnectedClientId {
type Error = IpPacketRouterError;
fn try_from((sent_by, sender_tag): (SentBy, Option<AnonymousSenderTag>)) -> Result<Self> {
match sent_by {
SentBy::NymAddress(nym_address) => Ok(ConnectedClientId::NymAddress(nym_address)),
SentBy::AnonymousSenderTag => sender_tag
.map(ConnectedClientId::AnonymousSenderTag)
.ok_or(IpPacketRouterError::InvalidReplyTo),
}
}
}
@@ -7,6 +7,7 @@ pub use nym_client_core::error::ClientCoreError;
use nym_exit_policy::PolicyError;
use nym_id::NymIdError;
use nym_ip_packet_requests::sign::SignatureError;
use nym_service_provider_requests_common::{ProtocolError, ServiceProviderType};
#[derive(thiserror::Error, Debug)]
pub enum IpPacketRouterError {
@@ -96,11 +97,20 @@ pub enum IpPacketRouterError {
#[error("failed to verify request: {source}")]
FailedToVerifyRequest { source: SignatureError },
#[error("client is connected with an invalid version: {version}")]
InvalidConnectedClientVersion { version: u8 },
#[error("invalid reply-to address in the response")]
InvalidReplyTo,
#[error("missing sender tag in the request")]
MissingSenderTag,
#[error("unsupported response: {0}")]
UnsupportedResponse(String),
#[error("invalid service provider type: {0}")]
InvalidServiceProviderType(ServiceProviderType),
#[error("failed to deserialize protocol: {source}")]
FailedToDeserializeProtocol { source: ProtocolError },
}
pub type Result<T> = std::result::Result<T, IpPacketRouterError>;
@@ -11,6 +11,7 @@ use nym_ip_packet_requests::{
v8::request::IpPacketRequest as IpPacketRequestV8, IpPair,
};
use nym_sdk::mixnet::ReconstructedMessage;
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use std::fmt;
use crate::{clients::ConnectedClientId, error::IpPacketRouterError};
@@ -83,9 +84,23 @@ impl TryFrom<&ReconstructedMessage> for IpPacketRequest {
fn try_from(reconstructed: &ReconstructedMessage) -> Result<Self, Self::Error> {
let request_version = *reconstructed
.message
.first()
.first_chunk::<2>()
.ok_or(IpPacketRouterError::EmptyPacket)?;
// With version v8 and onwards, the type of the service provider is included in the
// header.
if request_version[0] >= 8 {
let protocol = Protocol::try_from(&request_version)
.map_err(|source| IpPacketRouterError::FailedToDeserializeProtocol { source })?;
if protocol.service_provider_type != ServiceProviderType::IpPacketRouter {
return Err(IpPacketRouterError::InvalidServiceProviderType(
protocol.service_provider_type,
));
}
}
let request_version = request_version[0];
match request_version {
6 => {
let request_v6 = IpPacketRequestV6::from_reconstructed_message(reconstructed)
@@ -109,10 +124,10 @@ impl TryFrom<&ReconstructedMessage> for IpPacketRequest {
.map_err(
|source| IpPacketRouterError::FailedToDeserializeTaggedPacket { source },
)?;
request_v8
.verify()
.map_err(|source| IpPacketRouterError::FailedToVerifyRequest { source })?;
IpPacketRequest::try_from((request_v8, reconstructed.sender_tag))
let sender_tag = reconstructed
.sender_tag
.ok_or(IpPacketRouterError::MissingSenderTag)?;
Ok(IpPacketRequest::from((request_v8, sender_tag)))
}
_ => {
log::info!("Received packet with invalid version: v{request_version}");
@@ -2,34 +2,27 @@
// SPDX-License-Identifier: GPL-3.0-only
use nym_ip_packet_requests::v8::request::{
ControlRequest as ControlRequestV8, DataRequest as DataRequestV8,
DisconnectRequest as DisconnectRequestV8, DynamicConnectRequest as DynamicConnectRequestV8,
ConnectRequest as ConnectRequestV8, ControlRequest as ControlRequestV8,
DataRequest as DataRequestV8, DisconnectRequest as DisconnectRequestV8,
HealthRequest as HealthRequestV8, IpPacketRequest as IpPacketRequestV8,
IpPacketRequestData as IpPacketRequestDataV8, PingRequest as PingRequestV8,
StaticConnectRequest as StaticConnectRequestV8,
};
use nym_sdk::mixnet::AnonymousSenderTag;
use crate::error::IpPacketRouterError;
use super::{
ClientVersion, ConnectedClientId, ControlRequest, DataRequest, DisconnectRequest,
DynamicConnectRequest, HealthRequest, IpPacketRequest, PingRequest, StaticConnectRequest,
ClientVersion, ControlRequest, DataRequest, DisconnectRequest, DynamicConnectRequest,
HealthRequest, IpPacketRequest, PingRequest,
};
impl TryFrom<(IpPacketRequestV8, Option<AnonymousSenderTag>)> for IpPacketRequest {
type Error = IpPacketRouterError;
fn try_from(
(request, sender_tag): (IpPacketRequestV8, Option<AnonymousSenderTag>),
) -> Result<Self, Self::Error> {
impl From<(IpPacketRequestV8, AnonymousSenderTag)> for IpPacketRequest {
fn from((request, sender_tag): (IpPacketRequestV8, AnonymousSenderTag)) -> Self {
let version = ClientVersion::V8;
Ok(match request.data {
match request.data {
IpPacketRequestDataV8::Data(inner) => Self::Data((inner, version).into()),
IpPacketRequestDataV8::Control(inner) => {
Self::Control((*inner, sender_tag, version).try_into()?)
Self::Control((*inner, sender_tag, version).into())
}
})
}
}
}
@@ -42,139 +35,72 @@ impl From<(DataRequestV8, ClientVersion)> for DataRequest {
}
}
impl TryFrom<(ControlRequestV8, Option<AnonymousSenderTag>, ClientVersion)> for ControlRequest {
type Error = IpPacketRouterError;
fn try_from(
(request, sender_tag, version): (
ControlRequestV8,
Option<AnonymousSenderTag>,
ClientVersion,
),
) -> Result<Self, Self::Error> {
Ok(match request {
ControlRequestV8::StaticConnect(inner) => {
ControlRequest::StaticConnect((inner.request, sender_tag, version).try_into()?)
}
ControlRequestV8::DynamicConnect(inner) => {
ControlRequest::DynamicConnect((inner.request, sender_tag, version).try_into()?)
impl From<(ControlRequestV8, AnonymousSenderTag, ClientVersion)> for ControlRequest {
fn from(
(request, sender_tag, version): (ControlRequestV8, AnonymousSenderTag, ClientVersion),
) -> Self {
match request {
ControlRequestV8::Connect(inner) => {
ControlRequest::DynamicConnect((inner, sender_tag, version).into())
}
ControlRequestV8::Disconnect(inner) => {
ControlRequest::Disconnect((inner.request, sender_tag, version).try_into()?)
ControlRequest::Disconnect((inner, sender_tag, version).into())
}
ControlRequestV8::Ping(inner) => {
ControlRequest::Ping((inner, sender_tag, version).try_into()?)
ControlRequest::Ping((inner, sender_tag, version).into())
}
ControlRequestV8::Health(inner) => {
ControlRequest::Health((inner, sender_tag, version).try_into()?)
ControlRequest::Health((inner, sender_tag, version).into())
}
})
}
}
}
impl
TryFrom<(
StaticConnectRequestV8,
Option<AnonymousSenderTag>,
ClientVersion,
)> for StaticConnectRequest
{
type Error = IpPacketRouterError;
fn try_from(
(request, sender_tag, version): (
StaticConnectRequestV8,
Option<AnonymousSenderTag>,
ClientVersion,
),
) -> Result<Self, Self::Error> {
Ok(Self {
impl From<(ConnectRequestV8, AnonymousSenderTag, ClientVersion)> for DynamicConnectRequest {
fn from(
(request, sender_tag, version): (ConnectRequestV8, AnonymousSenderTag, ClientVersion),
) -> Self {
Self {
version,
request_id: request.request_id,
sent_by: ConnectedClientId::try_from((request.sender, sender_tag))?,
ips: request.ips,
sent_by: sender_tag.into(),
buffer_timeout: request.buffer_timeout,
})
}
}
}
impl
TryFrom<(
DynamicConnectRequestV8,
Option<AnonymousSenderTag>,
ClientVersion,
)> for DynamicConnectRequest
{
type Error = IpPacketRouterError;
fn try_from(
(request, sender_tag, version): (
DynamicConnectRequestV8,
Option<AnonymousSenderTag>,
ClientVersion,
),
) -> Result<Self, Self::Error> {
Ok(Self {
impl From<(DisconnectRequestV8, AnonymousSenderTag, ClientVersion)> for DisconnectRequest {
fn from(
(request, sender_tag, version): (DisconnectRequestV8, AnonymousSenderTag, ClientVersion),
) -> Self {
Self {
version,
request_id: request.request_id,
sent_by: ConnectedClientId::try_from((request.sender, sender_tag))?,
buffer_timeout: request.buffer_timeout,
})
sent_by: sender_tag.into(),
}
}
}
impl
TryFrom<(
DisconnectRequestV8,
Option<AnonymousSenderTag>,
ClientVersion,
)> for DisconnectRequest
{
type Error = IpPacketRouterError;
fn try_from(
(request, sender_tag, version): (
DisconnectRequestV8,
Option<AnonymousSenderTag>,
ClientVersion,
),
) -> Result<Self, Self::Error> {
Ok(Self {
impl From<(PingRequestV8, AnonymousSenderTag, ClientVersion)> for PingRequest {
fn from(
(request, sender_tag, version): (PingRequestV8, AnonymousSenderTag, ClientVersion),
) -> Self {
Self {
version,
request_id: request.request_id,
sent_by: ConnectedClientId::try_from((request.sender, sender_tag))?,
})
sent_by: sender_tag.into(),
}
}
}
impl TryFrom<(PingRequestV8, Option<AnonymousSenderTag>, ClientVersion)> for PingRequest {
type Error = IpPacketRouterError;
fn try_from(
(request, sender_tag, version): (PingRequestV8, Option<AnonymousSenderTag>, ClientVersion),
) -> Result<Self, Self::Error> {
Ok(Self {
impl From<(HealthRequestV8, AnonymousSenderTag, ClientVersion)> for HealthRequest {
fn from(
(request, sender_tag, version): (HealthRequestV8, AnonymousSenderTag, ClientVersion),
) -> Self {
Self {
version,
request_id: request.request_id,
sent_by: ConnectedClientId::try_from((request.sender, sender_tag))?,
})
}
}
impl TryFrom<(HealthRequestV8, Option<AnonymousSenderTag>, ClientVersion)> for HealthRequest {
type Error = IpPacketRouterError;
fn try_from(
(request, sender_tag, version): (
HealthRequestV8,
Option<AnonymousSenderTag>,
ClientVersion,
),
) -> Result<Self, Self::Error> {
Ok(Self {
version,
request_id: request.request_id,
sent_by: ConnectedClientId::try_from((request.sender, sender_tag))?,
})
sent_by: sender_tag.into(),
}
}
}
@@ -131,7 +131,7 @@ impl VersionedResponse {
match self.version {
ClientVersion::V6 => IpPacketResponseV6::try_from(self)?.to_bytes(),
ClientVersion::V7 => IpPacketResponseV7::try_from(self)?.to_bytes(),
ClientVersion::V8 => IpPacketResponseV8::from(self).to_bytes(),
ClientVersion::V8 => IpPacketResponseV8::try_from(self)?.to_bytes(),
}
.map_err(|err| IpPacketRouterError::FailedToSerializeResponsePacket { source: err })
}
@@ -2,46 +2,44 @@
// SPDX-License-Identifier: GPL-3.0-only
use nym_ip_packet_requests::v8::response::{
ConnectFailureReason as ConnectFailureReasonV8, ConnectResponse as ConnectResponseV8,
ConnectResponseReply as ConnectResponseReplyV8, ConnectSuccess as ConnectSuccessV8,
ControlResponse as ControlResponseV8, DisconnectFailureReason as DisconnectFailureReasonV8,
DisconnectResponse as DisconnectResponseV8,
DisconnectResponseReply as DisconnectResponseReplyV8,
DynamicConnectFailureReason as DynamicConnectFailureReasonV8,
DynamicConnectResponse as DynamicConnectResponseV8,
DynamicConnectResponseReply as DynamicConnectResponseReplyV8,
DynamicConnectSuccess as DynamicConnectSuccessV8, HealthResponse as HealthResponseV8,
DisconnectResponseReply as DisconnectResponseReplyV8, HealthResponse as HealthResponseV8,
HealthResponseReply as HealthResponseReplyV8, InfoLevel as InfoLevelV8,
InfoResponse as InfoResponseV8, InfoResponseReply as InfoResponseReplyV8,
IpPacketResponse as IpPacketResponseV8, IpPacketResponseData as IpPacketResponseDataV8,
PongResponse as PongResponseV8, StaticConnectFailureReason as StaticConnectFailureReasonV8,
StaticConnectResponse as StaticConnectResponseV8,
StaticConnectResponseReply as StaticConnectResponseReplyV8,
PongResponse as PongResponseV8,
};
use crate::error::IpPacketRouterError;
use super::{
DisconnectFailureReason, DisconnectResponse, DynamicConnectFailureReason,
DynamicConnectResponse, DynamicConnectSuccess, HealthResponse, InfoLevel, InfoResponseReply,
Response, StaticConnectFailureReason, StaticConnectResponse, VersionedResponse,
Response, VersionedResponse,
};
impl From<VersionedResponse> for IpPacketResponseV8 {
fn from(response: VersionedResponse) -> Self {
impl TryFrom<VersionedResponse> for IpPacketResponseV8 {
type Error = IpPacketRouterError;
fn try_from(response: VersionedResponse) -> Result<Self, Self::Error> {
let version = response.version.into_u8();
let data =
match response.response {
Response::StaticConnect { request_id, reply } => IpPacketResponseDataV8::Control(
Box::new(ControlResponseV8::StaticConnect(StaticConnectResponseV8 {
Response::StaticConnect { .. } => {
return Err(IpPacketRouterError::UnsupportedResponse(format!(
"Static connect response is not supported in version {}",
version
)))
}
Response::DynamicConnect { request_id, reply } => IpPacketResponseDataV8::Control(
Box::new(ControlResponseV8::Connect(ConnectResponseV8 {
request_id,
reply: reply.into(),
})),
),
Response::DynamicConnect { request_id, reply } => {
IpPacketResponseDataV8::Control(Box::new(ControlResponseV8::DynamicConnect(
DynamicConnectResponseV8 {
request_id,
reply: reply.into(),
},
)))
}
Response::Disconnect { request_id, reply } => IpPacketResponseDataV8::Control(
Box::new(ControlResponseV8::Disconnect(DisconnectResponseV8 {
request_id,
@@ -66,61 +64,29 @@ impl From<VersionedResponse> for IpPacketResponseV8 {
)),
};
IpPacketResponseV8 { version, data }
Ok(IpPacketResponseV8 { version, data })
}
}
impl From<StaticConnectResponse> for StaticConnectResponseReplyV8 {
fn from(reply: StaticConnectResponse) -> Self {
match reply {
StaticConnectResponse::Success => StaticConnectResponseReplyV8::Success,
StaticConnectResponse::Failure(err) => {
StaticConnectResponseReplyV8::Failure(err.into())
}
}
}
}
impl From<StaticConnectFailureReason> for StaticConnectFailureReasonV8 {
fn from(reason: StaticConnectFailureReason) -> Self {
match reason {
StaticConnectFailureReason::RequestedIpAlreadyInUse => {
StaticConnectFailureReasonV8::RequestedIpAlreadyInUse
}
StaticConnectFailureReason::ClientAlreadyConnected => {
StaticConnectFailureReasonV8::ClientAlreadyConnected
}
StaticConnectFailureReason::OutOfDateTimestamp => {
StaticConnectFailureReasonV8::OutOfDateTimestamp
}
StaticConnectFailureReason::Other(err) => StaticConnectFailureReasonV8::Other(err),
}
}
}
impl From<DynamicConnectResponse> for DynamicConnectResponseReplyV8 {
impl From<DynamicConnectResponse> for ConnectResponseReplyV8 {
fn from(reply: DynamicConnectResponse) -> Self {
match reply {
DynamicConnectResponse::Success(DynamicConnectSuccess { ips }) => {
DynamicConnectResponseReplyV8::Success(DynamicConnectSuccessV8 { ips })
}
DynamicConnectResponse::Failure(err) => {
DynamicConnectResponseReplyV8::Failure(err.into())
ConnectResponseReplyV8::Success(ConnectSuccessV8 { ips })
}
DynamicConnectResponse::Failure(err) => ConnectResponseReplyV8::Failure(err.into()),
}
}
}
impl From<DynamicConnectFailureReason> for DynamicConnectFailureReasonV8 {
impl From<DynamicConnectFailureReason> for ConnectFailureReasonV8 {
fn from(reason: DynamicConnectFailureReason) -> Self {
match reason {
DynamicConnectFailureReason::ClientAlreadyConnected => {
DynamicConnectFailureReasonV8::ClientAlreadyConnected
ConnectFailureReasonV8::ClientAlreadyConnected
}
DynamicConnectFailureReason::NoAvailableIp => {
DynamicConnectFailureReasonV8::NoAvailableIp
}
DynamicConnectFailureReason::Other(err) => DynamicConnectFailureReasonV8::Other(err),
DynamicConnectFailureReason::NoAvailableIp => ConnectFailureReasonV8::NoAvailableIp,
DynamicConnectFailureReason::Other(err) => ConnectFailureReasonV8::Other(err),
}
}
}