Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 6e215646c3 |
@@ -1,7 +1,319 @@
|
|||||||
pub mod request;
|
use std::net::IpAddr;
|
||||||
pub mod response;
|
|
||||||
|
|
||||||
pub const CURRENT_VERSION: u8 = 2;
|
use nym_sphinx::addressing::clients::Recipient;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
pub const CURRENT_VERSION: u8 = 1;
|
||||||
|
|
||||||
|
fn generate_random() -> u64 {
|
||||||
|
use rand::RngCore;
|
||||||
|
let mut rng = rand::rngs::OsRng;
|
||||||
|
rng.next_u64()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct IpPacketRequest {
|
||||||
|
pub version: u8,
|
||||||
|
pub data: IpPacketRequestData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpPacketRequest {
|
||||||
|
pub fn new_static_connect_request(
|
||||||
|
ip: IpAddr,
|
||||||
|
reply_to: Recipient,
|
||||||
|
reply_to_hops: Option<u8>,
|
||||||
|
reply_to_avg_mix_delays: Option<f64>,
|
||||||
|
) -> (Self, u64) {
|
||||||
|
let request_id = generate_random();
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
version: CURRENT_VERSION,
|
||||||
|
data: IpPacketRequestData::StaticConnect(StaticConnectRequest {
|
||||||
|
request_id,
|
||||||
|
ip,
|
||||||
|
reply_to,
|
||||||
|
reply_to_hops,
|
||||||
|
reply_to_avg_mix_delays,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_dynamic_connect_request(
|
||||||
|
reply_to: Recipient,
|
||||||
|
reply_to_hops: Option<u8>,
|
||||||
|
reply_to_avg_mix_delays: Option<f64>,
|
||||||
|
) -> (Self, u64) {
|
||||||
|
let request_id = generate_random();
|
||||||
|
(
|
||||||
|
Self {
|
||||||
|
version: CURRENT_VERSION,
|
||||||
|
data: IpPacketRequestData::DynamicConnect(DynamicConnectRequest {
|
||||||
|
request_id,
|
||||||
|
reply_to,
|
||||||
|
reply_to_hops,
|
||||||
|
reply_to_avg_mix_delays,
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
request_id,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_ip_packet(ip_packet: bytes::Bytes) -> Self {
|
||||||
|
Self {
|
||||||
|
version: CURRENT_VERSION,
|
||||||
|
data: IpPacketRequestData::Data(DataRequest { ip_packet }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> Option<u64> {
|
||||||
|
match &self.data {
|
||||||
|
IpPacketRequestData::StaticConnect(request) => Some(request.request_id),
|
||||||
|
IpPacketRequestData::DynamicConnect(request) => Some(request.request_id),
|
||||||
|
IpPacketRequestData::Data(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recipient(&self) -> Option<&Recipient> {
|
||||||
|
match &self.data {
|
||||||
|
IpPacketRequestData::StaticConnect(request) => Some(&request.reply_to),
|
||||||
|
IpPacketRequestData::DynamicConnect(request) => Some(&request.reply_to),
|
||||||
|
IpPacketRequestData::Data(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
|
||||||
|
use bincode::Options;
|
||||||
|
make_bincode_serializer().serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_reconstructed_message(
|
||||||
|
message: &nym_sphinx::receiver::ReconstructedMessage,
|
||||||
|
) -> Result<Self, bincode::Error> {
|
||||||
|
use bincode::Options;
|
||||||
|
make_bincode_serializer().deserialize(&message.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub enum IpPacketRequestData {
|
||||||
|
StaticConnect(StaticConnectRequest),
|
||||||
|
DynamicConnect(DynamicConnectRequest),
|
||||||
|
Data(DataRequest),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct StaticConnectRequest {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub ip: IpAddr,
|
||||||
|
// The nym-address the response should be sent back to
|
||||||
|
pub reply_to: Recipient,
|
||||||
|
// The number of mix node hops that responses should take, in addition to the entry and exit
|
||||||
|
// node. Zero means only client -> entry -> exit -> client.
|
||||||
|
pub reply_to_hops: Option<u8>,
|
||||||
|
// The average delay at each mix node, in milliseconds. Currently this is not supported by the
|
||||||
|
// ip packet router.
|
||||||
|
pub reply_to_avg_mix_delays: Option<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct DynamicConnectRequest {
|
||||||
|
pub request_id: u64,
|
||||||
|
// The nym-address the response should be sent back to
|
||||||
|
pub reply_to: Recipient,
|
||||||
|
// The number of mix node hops that responses should take, in addition to the entry and exit
|
||||||
|
// node. Zero means only client -> entry -> exit -> client.
|
||||||
|
pub reply_to_hops: Option<u8>,
|
||||||
|
// The average delay at each mix node, in milliseconds. Currently this is not supported by the
|
||||||
|
// ip packet router.
|
||||||
|
pub reply_to_avg_mix_delays: Option<f64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||||
|
pub struct DataRequest {
|
||||||
|
pub ip_packet: bytes::Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct IpPacketResponse {
|
||||||
|
pub version: u8,
|
||||||
|
pub data: IpPacketResponseData,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl IpPacketResponse {
|
||||||
|
pub fn new_static_connect_success(request_id: u64, reply_to: Recipient) -> Self {
|
||||||
|
Self {
|
||||||
|
version: CURRENT_VERSION,
|
||||||
|
data: IpPacketResponseData::StaticConnect(StaticConnectResponse {
|
||||||
|
request_id,
|
||||||
|
reply_to,
|
||||||
|
reply: StaticConnectResponseReply::Success,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_static_connect_failure(
|
||||||
|
request_id: u64,
|
||||||
|
reply_to: Recipient,
|
||||||
|
reason: StaticConnectFailureReason,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
version: CURRENT_VERSION,
|
||||||
|
data: IpPacketResponseData::StaticConnect(StaticConnectResponse {
|
||||||
|
request_id,
|
||||||
|
reply_to,
|
||||||
|
reply: StaticConnectResponseReply::Failure(reason),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_dynamic_connect_success(request_id: u64, reply_to: Recipient, ip: IpAddr) -> Self {
|
||||||
|
Self {
|
||||||
|
version: CURRENT_VERSION,
|
||||||
|
data: IpPacketResponseData::DynamicConnect(DynamicConnectResponse {
|
||||||
|
request_id,
|
||||||
|
reply_to,
|
||||||
|
reply: DynamicConnectResponseReply::Success(DynamicConnectSuccess { ip }),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_dynamic_connect_failure(
|
||||||
|
request_id: u64,
|
||||||
|
reply_to: Recipient,
|
||||||
|
reason: DynamicConnectFailureReason,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
version: CURRENT_VERSION,
|
||||||
|
data: IpPacketResponseData::DynamicConnect(DynamicConnectResponse {
|
||||||
|
request_id,
|
||||||
|
reply_to,
|
||||||
|
reply: DynamicConnectResponseReply::Failure(reason),
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_ip_packet(ip_packet: bytes::Bytes) -> Self {
|
||||||
|
Self {
|
||||||
|
version: CURRENT_VERSION,
|
||||||
|
data: IpPacketResponseData::Data(DataResponse { ip_packet }),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> Option<u64> {
|
||||||
|
match &self.data {
|
||||||
|
IpPacketResponseData::StaticConnect(response) => Some(response.request_id),
|
||||||
|
IpPacketResponseData::DynamicConnect(response) => Some(response.request_id),
|
||||||
|
IpPacketResponseData::Data(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recipient(&self) -> Option<&Recipient> {
|
||||||
|
match &self.data {
|
||||||
|
IpPacketResponseData::StaticConnect(response) => Some(&response.reply_to),
|
||||||
|
IpPacketResponseData::DynamicConnect(response) => Some(&response.reply_to),
|
||||||
|
IpPacketResponseData::Data(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
|
||||||
|
use bincode::Options;
|
||||||
|
make_bincode_serializer().serialize(self)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_reconstructed_message(
|
||||||
|
message: &nym_sphinx::receiver::ReconstructedMessage,
|
||||||
|
) -> Result<Self, bincode::Error> {
|
||||||
|
use bincode::Options;
|
||||||
|
make_bincode_serializer().deserialize(&message.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::large_enum_variant)]
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum IpPacketResponseData {
|
||||||
|
StaticConnect(StaticConnectResponse),
|
||||||
|
DynamicConnect(DynamicConnectResponse),
|
||||||
|
Data(DataResponse),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct StaticConnectResponse {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub reply_to: Recipient,
|
||||||
|
pub reply: StaticConnectResponseReply,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum StaticConnectResponseReply {
|
||||||
|
Success,
|
||||||
|
Failure(StaticConnectFailureReason),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl StaticConnectResponseReply {
|
||||||
|
pub fn is_success(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
StaticConnectResponseReply::Success => true,
|
||||||
|
StaticConnectResponseReply::Failure(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
|
||||||
|
pub enum StaticConnectFailureReason {
|
||||||
|
#[error("requested ip address is already in use")]
|
||||||
|
RequestedIpAlreadyInUse,
|
||||||
|
#[error("requested nym-address is already in use")]
|
||||||
|
RequestedNymAddressAlreadyInUse,
|
||||||
|
#[error("{0}")]
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct DynamicConnectResponse {
|
||||||
|
pub request_id: u64,
|
||||||
|
pub reply_to: Recipient,
|
||||||
|
pub reply: DynamicConnectResponseReply,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub enum DynamicConnectResponseReply {
|
||||||
|
Success(DynamicConnectSuccess),
|
||||||
|
Failure(DynamicConnectFailureReason),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DynamicConnectResponseReply {
|
||||||
|
pub fn is_success(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
DynamicConnectResponseReply::Success(_) => true,
|
||||||
|
DynamicConnectResponseReply::Failure(_) => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct DynamicConnectSuccess {
|
||||||
|
pub ip: IpAddr,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
|
||||||
|
pub enum DynamicConnectFailureReason {
|
||||||
|
#[error("requested nym-address is already in use")]
|
||||||
|
RequestedNymAddressAlreadyInUse,
|
||||||
|
#[error("no available ip address")]
|
||||||
|
NoAvailableIp,
|
||||||
|
#[error("{0}")]
|
||||||
|
Other(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
|
pub struct DataResponse {
|
||||||
|
pub ip_packet: bytes::Bytes,
|
||||||
|
}
|
||||||
|
|
||||||
fn make_bincode_serializer() -> impl bincode::Options {
|
fn make_bincode_serializer() -> impl bincode::Options {
|
||||||
use bincode::Options;
|
use bincode::Options;
|
||||||
@@ -9,3 +321,63 @@ fn make_bincode_serializer() -> impl bincode::Options {
|
|||||||
.with_big_endian()
|
.with_big_endian()
|
||||||
.with_varint_encoding()
|
.with_varint_encoding()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_size_of_request() {
|
||||||
|
let connect = IpPacketRequest {
|
||||||
|
version: 4,
|
||||||
|
data: IpPacketRequestData::StaticConnect(
|
||||||
|
StaticConnectRequest {
|
||||||
|
request_id: 123,
|
||||||
|
ip: IpAddr::from([10, 0, 0, 1]),
|
||||||
|
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(),
|
||||||
|
reply_to_hops: None,
|
||||||
|
reply_to_avg_mix_delays: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
};
|
||||||
|
assert_eq!(connect.to_bytes().unwrap().len(), 107);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn check_size_of_data() {
|
||||||
|
let data = IpPacketRequest {
|
||||||
|
version: 4,
|
||||||
|
data: IpPacketRequestData::Data(DataRequest {
|
||||||
|
ip_packet: bytes::Bytes::from(vec![1u8; 32]),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
assert_eq!(data.to_bytes().unwrap().len(), 35);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn serialize_and_deserialize_data_request() {
|
||||||
|
let data = IpPacketRequest {
|
||||||
|
version: 4,
|
||||||
|
data: IpPacketRequestData::Data(DataRequest {
|
||||||
|
ip_packet: bytes::Bytes::from(vec![1, 2, 4, 2, 5]),
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
let serialized = data.to_bytes().unwrap();
|
||||||
|
let deserialized = IpPacketRequest::from_reconstructed_message(
|
||||||
|
&nym_sphinx::receiver::ReconstructedMessage {
|
||||||
|
message: serialized,
|
||||||
|
sender_tag: None,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(deserialized.version, 4);
|
||||||
|
assert_eq!(
|
||||||
|
deserialized.data,
|
||||||
|
IpPacketRequestData::Data(DataRequest {
|
||||||
|
ip_packet: bytes::Bytes::from(vec![1, 2, 4, 2, 5]),
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,221 +0,0 @@
|
|||||||
use std::net::IpAddr;
|
|
||||||
|
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{make_bincode_serializer, CURRENT_VERSION};
|
|
||||||
|
|
||||||
fn generate_random() -> u64 {
|
|
||||||
use rand::RngCore;
|
|
||||||
let mut rng = rand::rngs::OsRng;
|
|
||||||
rng.next_u64()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct IpPacketRequest {
|
|
||||||
pub version: u8,
|
|
||||||
pub data: IpPacketRequestData,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IpPacketRequest {
|
|
||||||
pub fn new_static_connect_request(
|
|
||||||
ip: IpAddr,
|
|
||||||
reply_to: Recipient,
|
|
||||||
reply_to_hops: Option<u8>,
|
|
||||||
reply_to_avg_mix_delays: Option<f64>,
|
|
||||||
) -> (Self, u64) {
|
|
||||||
let request_id = generate_random();
|
|
||||||
(
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketRequestData::StaticConnect(StaticConnectRequest {
|
|
||||||
request_id,
|
|
||||||
ip,
|
|
||||||
reply_to,
|
|
||||||
reply_to_hops,
|
|
||||||
reply_to_avg_mix_delays,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
request_id,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_dynamic_connect_request(
|
|
||||||
reply_to: Recipient,
|
|
||||||
reply_to_hops: Option<u8>,
|
|
||||||
reply_to_avg_mix_delays: Option<f64>,
|
|
||||||
) -> (Self, u64) {
|
|
||||||
let request_id = generate_random();
|
|
||||||
(
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketRequestData::DynamicConnect(DynamicConnectRequest {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply_to_hops,
|
|
||||||
reply_to_avg_mix_delays,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
request_id,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_disconnect_request(reply_to: Recipient) -> (Self, u64) {
|
|
||||||
let request_id = generate_random();
|
|
||||||
(
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketRequestData::Disconnect(DisconnectRequest {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
request_id,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_ip_packet(ip_packet: bytes::Bytes) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketRequestData::Data(DataRequest { ip_packet }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn id(&self) -> Option<u64> {
|
|
||||||
match &self.data {
|
|
||||||
IpPacketRequestData::StaticConnect(request) => Some(request.request_id),
|
|
||||||
IpPacketRequestData::DynamicConnect(request) => Some(request.request_id),
|
|
||||||
IpPacketRequestData::Disconnect(request) => Some(request.request_id),
|
|
||||||
IpPacketRequestData::Data(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recipient(&self) -> Option<&Recipient> {
|
|
||||||
match &self.data {
|
|
||||||
IpPacketRequestData::StaticConnect(request) => Some(&request.reply_to),
|
|
||||||
IpPacketRequestData::DynamicConnect(request) => Some(&request.reply_to),
|
|
||||||
IpPacketRequestData::Disconnect(request) => Some(&request.reply_to),
|
|
||||||
IpPacketRequestData::Data(_) => None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
|
|
||||||
use bincode::Options;
|
|
||||||
make_bincode_serializer().serialize(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_reconstructed_message(
|
|
||||||
message: &nym_sphinx::receiver::ReconstructedMessage,
|
|
||||||
) -> Result<Self, bincode::Error> {
|
|
||||||
use bincode::Options;
|
|
||||||
make_bincode_serializer().deserialize(&message.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub enum IpPacketRequestData {
|
|
||||||
StaticConnect(StaticConnectRequest),
|
|
||||||
DynamicConnect(DynamicConnectRequest),
|
|
||||||
Disconnect(DisconnectRequest),
|
|
||||||
Data(DataRequest),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub struct StaticConnectRequest {
|
|
||||||
pub request_id: u64,
|
|
||||||
pub ip: IpAddr,
|
|
||||||
// The nym-address the response should be sent back to
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
// The number of mix node hops that responses should take, in addition to the entry and exit
|
|
||||||
// node. Zero means only client -> entry -> exit -> client.
|
|
||||||
pub reply_to_hops: Option<u8>,
|
|
||||||
// The average delay at each mix node, in milliseconds. Currently this is not supported by the
|
|
||||||
// ip packet router.
|
|
||||||
pub reply_to_avg_mix_delays: Option<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub struct DynamicConnectRequest {
|
|
||||||
pub request_id: u64,
|
|
||||||
// The nym-address the response should be sent back to
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
// The number of mix node hops that responses should take, in addition to the entry and exit
|
|
||||||
// node. Zero means only client -> entry -> exit -> client.
|
|
||||||
pub reply_to_hops: Option<u8>,
|
|
||||||
// The average delay at each mix node, in milliseconds. Currently this is not supported by the
|
|
||||||
// ip packet router.
|
|
||||||
pub reply_to_avg_mix_delays: Option<f64>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub struct DisconnectRequest {
|
|
||||||
pub request_id: u64,
|
|
||||||
// The nym-address the response should be sent back to
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
|
||||||
pub struct DataRequest {
|
|
||||||
pub ip_packet: bytes::Bytes,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn check_size_of_request() {
|
|
||||||
let connect = IpPacketRequest {
|
|
||||||
version: 4,
|
|
||||||
data: IpPacketRequestData::StaticConnect(
|
|
||||||
StaticConnectRequest {
|
|
||||||
request_id: 123,
|
|
||||||
ip: IpAddr::from([10, 0, 0, 1]),
|
|
||||||
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(),
|
|
||||||
reply_to_hops: None,
|
|
||||||
reply_to_avg_mix_delays: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
};
|
|
||||||
assert_eq!(connect.to_bytes().unwrap().len(), 107);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn check_size_of_data() {
|
|
||||||
let data = IpPacketRequest {
|
|
||||||
version: 4,
|
|
||||||
data: IpPacketRequestData::Data(DataRequest {
|
|
||||||
ip_packet: bytes::Bytes::from(vec![1u8; 32]),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
assert_eq!(data.to_bytes().unwrap().len(), 35);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn serialize_and_deserialize_data_request() {
|
|
||||||
let data = IpPacketRequest {
|
|
||||||
version: 4,
|
|
||||||
data: IpPacketRequestData::Data(DataRequest {
|
|
||||||
ip_packet: bytes::Bytes::from(vec![1, 2, 4, 2, 5]),
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
||||||
let serialized = data.to_bytes().unwrap();
|
|
||||||
let deserialized = IpPacketRequest::from_reconstructed_message(
|
|
||||||
&nym_sphinx::receiver::ReconstructedMessage {
|
|
||||||
message: serialized,
|
|
||||||
sender_tag: None,
|
|
||||||
},
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
assert_eq!(deserialized.version, 4);
|
|
||||||
assert_eq!(
|
|
||||||
deserialized.data,
|
|
||||||
IpPacketRequestData::Data(DataRequest {
|
|
||||||
ip_packet: bytes::Bytes::from(vec![1, 2, 4, 2, 5]),
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,262 +0,0 @@
|
|||||||
use std::net::IpAddr;
|
|
||||||
|
|
||||||
use nym_sphinx::addressing::clients::Recipient;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{make_bincode_serializer, CURRENT_VERSION};
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct IpPacketResponse {
|
|
||||||
pub version: u8,
|
|
||||||
pub data: IpPacketResponseData,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IpPacketResponse {
|
|
||||||
pub fn new_static_connect_success(request_id: u64, reply_to: Recipient) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::StaticConnect(StaticConnectResponse {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply: StaticConnectResponseReply::Success,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_static_connect_failure(
|
|
||||||
request_id: u64,
|
|
||||||
reply_to: Recipient,
|
|
||||||
reason: StaticConnectFailureReason,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::StaticConnect(StaticConnectResponse {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply: StaticConnectResponseReply::Failure(reason),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_dynamic_connect_success(request_id: u64, reply_to: Recipient, ip: IpAddr) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::DynamicConnect(DynamicConnectResponse {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply: DynamicConnectResponseReply::Success(DynamicConnectSuccess { ip }),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_dynamic_connect_failure(
|
|
||||||
request_id: u64,
|
|
||||||
reply_to: Recipient,
|
|
||||||
reason: DynamicConnectFailureReason,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::DynamicConnect(DynamicConnectResponse {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply: DynamicConnectResponseReply::Failure(reason),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_ip_packet(ip_packet: bytes::Bytes) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::Data(DataResponse { ip_packet }),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_version_mismatch(
|
|
||||||
request_id: u64,
|
|
||||||
reply_to: Recipient,
|
|
||||||
request_version: u8,
|
|
||||||
our_version: u8,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::Error(ErrorResponse {
|
|
||||||
request_id,
|
|
||||||
reply_to,
|
|
||||||
reply: ErrorResponseReply::VersionMismatch {
|
|
||||||
request_version,
|
|
||||||
response_version: our_version,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_data_error_response(reply_to: Recipient, reply: ErrorResponseReply) -> Self {
|
|
||||||
Self {
|
|
||||||
version: CURRENT_VERSION,
|
|
||||||
data: IpPacketResponseData::Error(ErrorResponse {
|
|
||||||
request_id: 0,
|
|
||||||
reply_to,
|
|
||||||
reply,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn id(&self) -> Option<u64> {
|
|
||||||
match &self.data {
|
|
||||||
IpPacketResponseData::StaticConnect(response) => Some(response.request_id),
|
|
||||||
IpPacketResponseData::DynamicConnect(response) => Some(response.request_id),
|
|
||||||
IpPacketResponseData::Disconnect(response) => Some(response.request_id),
|
|
||||||
IpPacketResponseData::Data(_) => None,
|
|
||||||
IpPacketResponseData::Error(response) => Some(response.request_id),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn recipient(&self) -> Option<&Recipient> {
|
|
||||||
match &self.data {
|
|
||||||
IpPacketResponseData::StaticConnect(response) => Some(&response.reply_to),
|
|
||||||
IpPacketResponseData::DynamicConnect(response) => Some(&response.reply_to),
|
|
||||||
IpPacketResponseData::Disconnect(response) => Some(&response.reply_to),
|
|
||||||
IpPacketResponseData::Data(_) => None,
|
|
||||||
IpPacketResponseData::Error(response) => Some(&response.reply_to),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
|
|
||||||
use bincode::Options;
|
|
||||||
make_bincode_serializer().serialize(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn from_reconstructed_message(
|
|
||||||
message: &nym_sphinx::receiver::ReconstructedMessage,
|
|
||||||
) -> Result<Self, bincode::Error> {
|
|
||||||
use bincode::Options;
|
|
||||||
make_bincode_serializer().deserialize(&message.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(clippy::large_enum_variant)]
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum IpPacketResponseData {
|
|
||||||
StaticConnect(StaticConnectResponse),
|
|
||||||
DynamicConnect(DynamicConnectResponse),
|
|
||||||
Disconnect(DisconnectResponse),
|
|
||||||
Data(DataResponse),
|
|
||||||
Error(ErrorResponse),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct StaticConnectResponse {
|
|
||||||
pub request_id: u64,
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
pub reply: StaticConnectResponseReply,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum StaticConnectResponseReply {
|
|
||||||
Success,
|
|
||||||
Failure(StaticConnectFailureReason),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl StaticConnectResponseReply {
|
|
||||||
pub fn is_success(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
StaticConnectResponseReply::Success => true,
|
|
||||||
StaticConnectResponseReply::Failure(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
|
|
||||||
pub enum StaticConnectFailureReason {
|
|
||||||
#[error("requested ip address is already in use")]
|
|
||||||
RequestedIpAlreadyInUse,
|
|
||||||
#[error("requested nym-address is already in use")]
|
|
||||||
RequestedNymAddressAlreadyInUse,
|
|
||||||
#[error("{0}")]
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct DynamicConnectResponse {
|
|
||||||
pub request_id: u64,
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
pub reply: DynamicConnectResponseReply,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum DynamicConnectResponseReply {
|
|
||||||
Success(DynamicConnectSuccess),
|
|
||||||
Failure(DynamicConnectFailureReason),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DynamicConnectResponseReply {
|
|
||||||
pub fn is_success(&self) -> bool {
|
|
||||||
match self {
|
|
||||||
DynamicConnectResponseReply::Success(_) => true,
|
|
||||||
DynamicConnectResponseReply::Failure(_) => false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct DynamicConnectSuccess {
|
|
||||||
pub ip: IpAddr,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
|
|
||||||
pub enum DynamicConnectFailureReason {
|
|
||||||
#[error("requested nym-address is already in use")]
|
|
||||||
RequestedNymAddressAlreadyInUse,
|
|
||||||
#[error("no available ip address")]
|
|
||||||
NoAvailableIp,
|
|
||||||
#[error("{0}")]
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct DisconnectResponse {
|
|
||||||
pub request_id: u64,
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
pub reply: DisconnectResponseReply,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub enum DisconnectResponseReply {
|
|
||||||
Success,
|
|
||||||
Failure(DisconnectFailureReason),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
|
|
||||||
pub enum DisconnectFailureReason {
|
|
||||||
#[error("requested nym-address is not currently connected")]
|
|
||||||
RequestedNymAddressNotConnected,
|
|
||||||
#[error("{0}")]
|
|
||||||
Other(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct DataResponse {
|
|
||||||
pub ip_packet: bytes::Bytes,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
|
||||||
pub struct ErrorResponse {
|
|
||||||
pub request_id: u64,
|
|
||||||
pub reply_to: Recipient,
|
|
||||||
pub reply: ErrorResponseReply,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize, thiserror::Error)]
|
|
||||||
pub enum ErrorResponseReply {
|
|
||||||
#[error("{msg}")]
|
|
||||||
Generic { msg: String },
|
|
||||||
#[error(
|
|
||||||
"version mismatch: response is v{request_version} and response is v{response_version}"
|
|
||||||
)]
|
|
||||||
VersionMismatch {
|
|
||||||
request_version: u8,
|
|
||||||
response_version: u8,
|
|
||||||
},
|
|
||||||
#[error("destination failed exit policy filter check: {dst}")]
|
|
||||||
ExitPolicyFilterCheckFailed { dst: String },
|
|
||||||
}
|
|
||||||
@@ -57,6 +57,13 @@ pub enum IpPacketRouterError {
|
|||||||
#[error("the provided socket address, '{addr}' is not covered by the exit policy!")]
|
#[error("the provided socket address, '{addr}' is not covered by the exit policy!")]
|
||||||
AddressNotCoveredByExitPolicy { addr: SocketAddr },
|
AddressNotCoveredByExitPolicy { addr: SocketAddr },
|
||||||
|
|
||||||
|
// #[error("the provided ip address, '{ip}' is not covered by the exit policy!")]
|
||||||
|
// IpNotCoveredByExitPolicy { ip: IpAddr },
|
||||||
|
#[error("failed filter check: '{addr}'")]
|
||||||
|
AddressFailedFilterCheck { addr: SocketAddr },
|
||||||
|
|
||||||
|
// #[error("failed filter check: '{ip}'")]
|
||||||
|
// IpFailedFilterCheck { ip: IpAddr },
|
||||||
#[error("failed to apply the exit policy: {source}")]
|
#[error("failed to apply the exit policy: {source}")]
|
||||||
ExitPolicyFailure {
|
ExitPolicyFailure {
|
||||||
#[from]
|
#[from]
|
||||||
|
|||||||
@@ -5,11 +5,8 @@ use std::{
|
|||||||
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use nym_ip_packet_requests::{
|
use nym_ip_packet_requests::{
|
||||||
request::{IpPacketRequest, IpPacketRequestData},
|
DynamicConnectFailureReason, IpPacketRequest, IpPacketRequestData, IpPacketResponse,
|
||||||
response::{
|
StaticConnectFailureReason,
|
||||||
DynamicConnectFailureReason, ErrorResponseReply, IpPacketResponse,
|
|
||||||
StaticConnectFailureReason,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
use nym_sdk::mixnet::{MixnetMessageSender, Recipient};
|
use nym_sdk::mixnet::{MixnetMessageSender, Recipient};
|
||||||
use nym_sphinx::receiver::ReconstructedMessage;
|
use nym_sphinx::receiver::ReconstructedMessage;
|
||||||
@@ -99,17 +96,13 @@ impl ConnectedClients {
|
|||||||
self.clients.contains_key(ip)
|
self.clients.contains_key(ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_client_from_ip_mut(&mut self, ip: &IpAddr) -> Option<&mut ConnectedClient> {
|
|
||||||
self.clients.get_mut(ip)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_nym_address_connected(&self, nym_address: &Recipient) -> bool {
|
fn is_nym_address_connected(&self, nym_address: &Recipient) -> bool {
|
||||||
self.clients
|
self.clients
|
||||||
.values()
|
.values()
|
||||||
.any(|client| client.nym_address == *nym_address)
|
.any(|client| client.nym_address == *nym_address)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_ip_from_nym_address(&self, nym_address: &Recipient) -> Option<IpAddr> {
|
fn get_ip(&self, nym_address: &Recipient) -> Option<IpAddr> {
|
||||||
self.clients.iter().find_map(|(ip, client)| {
|
self.clients.iter().find_map(|(ip, client)| {
|
||||||
if client.nym_address == *nym_address {
|
if client.nym_address == *nym_address {
|
||||||
Some(*ip)
|
Some(*ip)
|
||||||
@@ -119,7 +112,7 @@ impl ConnectedClients {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lookup_client_from_nym_address(&self, nym_address: &Recipient) -> Option<&ConnectedClient> {
|
fn get_client_by_nym_address(&self, nym_address: &Recipient) -> Option<&ConnectedClient> {
|
||||||
self.clients
|
self.clients
|
||||||
.values()
|
.values()
|
||||||
.find(|client| client.nym_address == *nym_address)
|
.find(|client| client.nym_address == *nym_address)
|
||||||
@@ -185,17 +178,11 @@ pub(crate) struct ConnectedClient {
|
|||||||
pub(crate) last_activity: std::time::Instant,
|
pub(crate) last_activity: std::time::Instant,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConnectedClient {
|
|
||||||
fn update_activity(&mut self) {
|
|
||||||
self.last_activity = std::time::Instant::now();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
impl MixnetListener {
|
impl MixnetListener {
|
||||||
async fn on_static_connect_request(
|
async fn on_static_connect_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
connect_request: nym_ip_packet_requests::request::StaticConnectRequest,
|
connect_request: nym_ip_packet_requests::StaticConnectRequest,
|
||||||
) -> Result<Option<IpPacketResponse>> {
|
) -> Result<Option<IpPacketResponse>> {
|
||||||
log::info!(
|
log::info!(
|
||||||
"Received static connect request from {sender_address}",
|
"Received static connect request from {sender_address}",
|
||||||
@@ -257,7 +244,7 @@ impl MixnetListener {
|
|||||||
|
|
||||||
async fn on_dynamic_connect_request(
|
async fn on_dynamic_connect_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
connect_request: nym_ip_packet_requests::request::DynamicConnectRequest,
|
connect_request: nym_ip_packet_requests::DynamicConnectRequest,
|
||||||
) -> Result<Option<IpPacketResponse>> {
|
) -> Result<Option<IpPacketResponse>> {
|
||||||
log::info!(
|
log::info!(
|
||||||
"Received dynamic connect request from {sender_address}",
|
"Received dynamic connect request from {sender_address}",
|
||||||
@@ -273,7 +260,7 @@ impl MixnetListener {
|
|||||||
// TODO: this is problematic. Until we sign connect requests this means you can spam people
|
// TODO: this is problematic. Until we sign connect requests this means you can spam people
|
||||||
// with return traffic
|
// with return traffic
|
||||||
|
|
||||||
if let Some(existing_ip) = self.connected_clients.lookup_ip_from_nym_address(&reply_to) {
|
if let Some(existing_ip) = self.connected_clients.get_ip(&reply_to) {
|
||||||
log::info!("Found existing client for nym address");
|
log::info!("Found existing client for nym address");
|
||||||
if self
|
if self
|
||||||
.connected_clients
|
.connected_clients
|
||||||
@@ -305,17 +292,9 @@ impl MixnetListener {
|
|||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_disconnect_request(
|
|
||||||
&self,
|
|
||||||
_disconnect_request: nym_ip_packet_requests::request::DisconnectRequest,
|
|
||||||
) -> Result<Option<IpPacketResponse>> {
|
|
||||||
log::info!("Received disconnect request: not implemented, dropping");
|
|
||||||
Ok(None)
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn on_data_request(
|
async fn on_data_request(
|
||||||
&mut self,
|
&mut self,
|
||||||
data_request: nym_ip_packet_requests::request::DataRequest,
|
data_request: nym_ip_packet_requests::DataRequest,
|
||||||
) -> Result<Option<IpPacketResponse>> {
|
) -> Result<Option<IpPacketResponse>> {
|
||||||
log::trace!("Received data request");
|
log::trace!("Received data request");
|
||||||
|
|
||||||
@@ -336,60 +315,30 @@ impl MixnetListener {
|
|||||||
let dst_str = dst.map_or(dst_addr.to_string(), |dst| dst.to_string());
|
let dst_str = dst.map_or(dst_addr.to_string(), |dst| dst.to_string());
|
||||||
log::info!("Received packet: {packet_type}: {src_addr} -> {dst_str}");
|
log::info!("Received packet: {packet_type}: {src_addr} -> {dst_str}");
|
||||||
|
|
||||||
if let Some(connected_client) = self.connected_clients.get_client_from_ip_mut(&src_addr) {
|
// Check if there is a connected client for this src_addr. If there is, update the last activity time
|
||||||
// Keep track of activity so we can disconnect inactive clients
|
// for the client. If there isn't, drop the packet.
|
||||||
connected_client.update_activity();
|
if self.connected_clients.update_activity(&src_addr).is_err() {
|
||||||
|
|
||||||
// For packets without a port, use 0.
|
|
||||||
let dst = dst.unwrap_or_else(|| SocketAddr::new(dst_addr, 0));
|
|
||||||
|
|
||||||
// Filter check
|
|
||||||
if self.request_filter.check_address(&dst).await {
|
|
||||||
// Forward the packet to the TUN device where it will be routed out to the internet
|
|
||||||
self.tun_writer
|
|
||||||
.write_all(&data_request.ip_packet)
|
|
||||||
.await
|
|
||||||
.map_err(|_| IpPacketRouterError::FailedToWritePacketToTun)?;
|
|
||||||
Ok(None)
|
|
||||||
} else {
|
|
||||||
log::info!("Denied filter check: {dst}");
|
|
||||||
Ok(Some(IpPacketResponse::new_data_error_response(
|
|
||||||
connected_client.nym_address,
|
|
||||||
ErrorResponseReply::ExitPolicyFilterCheckFailed {
|
|
||||||
dst: dst.to_string(),
|
|
||||||
},
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// If the client is not connected, just drop the packet silently
|
|
||||||
log::info!("Dropping packet: no connected client for {src_addr}");
|
log::info!("Dropping packet: no connected client for {src_addr}");
|
||||||
Ok(None)
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filter check
|
||||||
|
let dst = dst.unwrap_or_else(|| SocketAddr::new(dst_addr, 0));
|
||||||
|
if !self.request_filter.check_address(&dst).await {
|
||||||
|
log::info!("Denied filter check: {dst}");
|
||||||
|
// TODO: we could consider sending back a response here
|
||||||
|
return Err(IpPacketRouterError::AddressFailedFilterCheck { addr: dst });
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: consider changing from Vec<u8> to bytes::Bytes?
|
||||||
|
let packet = data_request.ip_packet;
|
||||||
|
self.tun_writer
|
||||||
|
.write_all(&packet)
|
||||||
|
.await
|
||||||
|
.map_err(|_| IpPacketRouterError::FailedToWritePacketToTun)?;
|
||||||
|
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn on_version_mismatch(
|
|
||||||
&self,
|
|
||||||
version: u8,
|
|
||||||
reconstructed: &ReconstructedMessage,
|
|
||||||
) -> Result<Option<IpPacketResponse>> {
|
|
||||||
// If it's possible to parse, do so and return back a response, otherwise just drop
|
|
||||||
let (id, recipient) = IpPacketRequest::from_reconstructed_message(reconstructed)
|
|
||||||
.ok()
|
|
||||||
.and_then(|request| {
|
|
||||||
request
|
|
||||||
.recipient()
|
|
||||||
.map(|recipient| (request.id().unwrap_or(0), *recipient))
|
|
||||||
})
|
|
||||||
.ok_or(IpPacketRouterError::InvalidPacketVersion(version))?;
|
|
||||||
|
|
||||||
Ok(Some(IpPacketResponse::new_version_mismatch(
|
|
||||||
id,
|
|
||||||
recipient,
|
|
||||||
version,
|
|
||||||
nym_ip_packet_requests::CURRENT_VERSION,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn on_reconstructed_message(
|
async fn on_reconstructed_message(
|
||||||
&mut self,
|
&mut self,
|
||||||
reconstructed: ReconstructedMessage,
|
reconstructed: ReconstructedMessage,
|
||||||
@@ -404,8 +353,8 @@ impl MixnetListener {
|
|||||||
// The idea is that in the future we can add logic here to parse older versions to stay
|
// The idea is that in the future we can add logic here to parse older versions to stay
|
||||||
// backwards compatible.
|
// backwards compatible.
|
||||||
if *version != nym_ip_packet_requests::CURRENT_VERSION {
|
if *version != nym_ip_packet_requests::CURRENT_VERSION {
|
||||||
log::info!("Received packet with invalid version: v{version}");
|
log::warn!("Received packet with invalid version");
|
||||||
return self.on_version_mismatch(*version, &reconstructed);
|
return Err(IpPacketRouterError::InvalidPacketVersion(*version));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,9 +368,6 @@ impl MixnetListener {
|
|||||||
IpPacketRequestData::DynamicConnect(connect_request) => {
|
IpPacketRequestData::DynamicConnect(connect_request) => {
|
||||||
self.on_dynamic_connect_request(connect_request).await
|
self.on_dynamic_connect_request(connect_request).await
|
||||||
}
|
}
|
||||||
IpPacketRequestData::Disconnect(disconnect_request) => {
|
|
||||||
self.on_disconnect_request(disconnect_request)
|
|
||||||
}
|
|
||||||
IpPacketRequestData::Data(data_request) => self.on_data_request(data_request).await,
|
IpPacketRequestData::Data(data_request) => self.on_data_request(data_request).await,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,7 +388,7 @@ impl MixnetListener {
|
|||||||
// We could avoid this lookup if we check this when we create the response.
|
// We could avoid this lookup if we check this when we create the response.
|
||||||
let mix_hops = self
|
let mix_hops = self
|
||||||
.connected_clients
|
.connected_clients
|
||||||
.lookup_client_from_nym_address(recipient)
|
.get_client_by_nym_address(recipient)
|
||||||
.and_then(|c| c.mix_hops);
|
.and_then(|c| c.mix_hops);
|
||||||
|
|
||||||
let input_message = create_input_message(*recipient, response_packet, mix_hops);
|
let input_message = create_input_message(*recipient, response_packet, mix_hops);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use nym_ip_packet_requests::response::IpPacketResponse;
|
use nym_ip_packet_requests::IpPacketResponse;
|
||||||
use nym_sdk::mixnet::MixnetMessageSender;
|
use nym_sdk::mixnet::MixnetMessageSender;
|
||||||
use nym_task::TaskClient;
|
use nym_task::TaskClient;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
|||||||
Reference in New Issue
Block a user