IPv6 support for wireguard (#5059)

* Add ipv6 in configs

* Make v4 latest

* Fix linux

* IPv6 prefix in config

* Fix template of private ip

* Fix clippy

* Fix v6 cidr

* Move from 2001:db8::/32 to fc00::/7 addresses

* Fix version number on conversion
This commit is contained in:
Bogdan-Ștefan Neacşu
2024-11-07 12:31:01 +02:00
committed by GitHub
parent bfd7240dcd
commit 44ae29b06d
31 changed files with 2431 additions and 146 deletions
Generated
+1
View File
@@ -4622,6 +4622,7 @@ dependencies = [
"hmac",
"nym-credentials-interface",
"nym-crypto",
"nym-network-defaults",
"nym-service-provider-requests-common",
"nym-sphinx",
"nym-wireguard-types",
+1
View File
@@ -17,6 +17,7 @@ thiserror = { workspace = true }
nym-credentials-interface = { path = "../credentials-interface" }
nym-crypto = { path = "../crypto", features = ["asymmetric"] }
nym-network-defaults = { path = "../network-defaults" }
nym-service-provider-requests-common = { path = "../service-provider-requests-common" }
nym-sphinx = { path = "../nymsphinx" }
nym-wireguard-types = { path = "../wireguard-types" }
+3 -2
View File
@@ -4,13 +4,14 @@
pub mod v1;
pub mod v2;
pub mod v3;
pub mod v4;
mod error;
pub use error::Error;
pub use v3 as latest;
pub use v4 as latest;
pub const CURRENT_VERSION: u8 = 3;
pub const CURRENT_VERSION: u8 = 4;
fn make_bincode_serializer() -> impl bincode::Options {
use bincode::Options;
@@ -9,7 +9,7 @@ impl From<v2::request::AuthenticatorRequest> for v3::request::AuthenticatorReque
fn from(authenticator_request: v2::request::AuthenticatorRequest) -> Self {
Self {
protocol: Protocol {
version: 2,
version: 3,
service_provider_type: ServiceProviderType::Authenticator,
},
data: authenticator_request.data.into(),
@@ -0,0 +1,200 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use crate::{v3, v4};
impl From<v3::request::AuthenticatorRequest> for v4::request::AuthenticatorRequest {
fn from(authenticator_request: v3::request::AuthenticatorRequest) -> Self {
Self {
protocol: Protocol {
version: 4,
service_provider_type: ServiceProviderType::Authenticator,
},
data: authenticator_request.data.into(),
reply_to: authenticator_request.reply_to,
request_id: authenticator_request.request_id,
}
}
}
impl From<v3::request::AuthenticatorRequestData> for v4::request::AuthenticatorRequestData {
fn from(authenticator_request_data: v3::request::AuthenticatorRequestData) -> Self {
match authenticator_request_data {
v3::request::AuthenticatorRequestData::Initial(init_msg) => {
v4::request::AuthenticatorRequestData::Initial(init_msg.into())
}
v3::request::AuthenticatorRequestData::Final(gw_client) => {
v4::request::AuthenticatorRequestData::Final(gw_client.into())
}
v3::request::AuthenticatorRequestData::QueryBandwidth(pub_key) => {
v4::request::AuthenticatorRequestData::QueryBandwidth(pub_key)
}
v3::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message) => {
v4::request::AuthenticatorRequestData::TopUpBandwidth(top_up_message.into())
}
}
}
}
impl From<v3::registration::InitMessage> for v4::registration::InitMessage {
fn from(init_msg: v3::registration::InitMessage) -> Self {
Self {
pub_key: init_msg.pub_key,
}
}
}
impl From<Box<v3::registration::FinalMessage>> for Box<v4::registration::FinalMessage> {
fn from(gw_client: Box<v3::registration::FinalMessage>) -> Self {
Box::new(v4::registration::FinalMessage {
gateway_client: gw_client.gateway_client.into(),
credential: gw_client.credential,
})
}
}
impl From<Box<v3::topup::TopUpMessage>> for Box<v4::topup::TopUpMessage> {
fn from(top_up_message: Box<v3::topup::TopUpMessage>) -> Self {
Box::new(v4::topup::TopUpMessage {
pub_key: top_up_message.pub_key,
credential: top_up_message.credential,
})
}
}
impl From<v3::registration::GatewayClient> for v4::registration::GatewayClient {
fn from(gw_client: v3::registration::GatewayClient) -> Self {
Self {
pub_key: gw_client.pub_key,
private_ips: gw_client.private_ip.into(),
mac: gw_client.mac.into(),
}
}
}
impl From<v4::registration::GatewayClient> for v3::registration::GatewayClient {
fn from(gw_client: v4::registration::GatewayClient) -> Self {
Self {
pub_key: gw_client.pub_key,
private_ip: gw_client.private_ips.ipv4.into(),
mac: gw_client.mac.into(),
}
}
}
impl From<v3::registration::ClientMac> for v4::registration::ClientMac {
fn from(mac: v3::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl From<v4::registration::ClientMac> for v3::registration::ClientMac {
fn from(mac: v4::registration::ClientMac) -> Self {
Self::new(mac.to_vec())
}
}
impl TryFrom<v4::response::AuthenticatorResponse> for v3::response::AuthenticatorResponse {
type Error = crate::Error;
fn try_from(
authenticator_response: v4::response::AuthenticatorResponse,
) -> Result<Self, Self::Error> {
Ok(Self {
data: authenticator_response.data.try_into()?,
reply_to: authenticator_response.reply_to,
protocol: authenticator_response.protocol,
})
}
}
impl TryFrom<v4::response::AuthenticatorResponseData> for v3::response::AuthenticatorResponseData {
type Error = crate::Error;
fn try_from(
authenticator_response_data: v4::response::AuthenticatorResponseData,
) -> Result<Self, Self::Error> {
match authenticator_response_data {
v4::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response,
) => Ok(
v3::response::AuthenticatorResponseData::PendingRegistration(
pending_registration_response.into(),
),
),
v4::response::AuthenticatorResponseData::Registered(registered_response) => Ok(
v3::response::AuthenticatorResponseData::Registered(registered_response.into()),
),
v4::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response,
) => Ok(v3::response::AuthenticatorResponseData::RemainingBandwidth(
remaining_bandwidth_response.into(),
)),
v4::response::AuthenticatorResponseData::TopUpBandwidth(_) => {
Err(Self::Error::Conversion(
"a v3 request couldn't produce a v4 only type of response".to_string(),
))
}
}
}
}
impl From<v4::response::PendingRegistrationResponse> for v3::response::PendingRegistrationResponse {
fn from(value: v4::response::PendingRegistrationResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v4::response::RegisteredResponse> for v3::response::RegisteredResponse {
fn from(value: v4::response::RegisteredResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.into(),
}
}
}
impl From<v4::response::RemainingBandwidthResponse> for v3::response::RemainingBandwidthResponse {
fn from(value: v4::response::RemainingBandwidthResponse) -> Self {
Self {
request_id: value.request_id,
reply_to: value.reply_to,
reply: value.reply.map(Into::into),
}
}
}
impl From<v4::registration::RegistrationData> for v3::registration::RegistrationData {
fn from(value: v4::registration::RegistrationData) -> Self {
Self {
nonce: value.nonce,
gateway_data: value.gateway_data.into(),
wg_port: value.wg_port,
}
}
}
impl From<v4::registration::RegistredData> for v3::registration::RegistredData {
fn from(value: v4::registration::RegistredData) -> Self {
Self {
pub_key: value.pub_key,
private_ip: value.private_ips.ipv4.into(),
wg_port: value.wg_port,
}
}
}
impl From<v4::registration::RemainingBandwidthData> for v3::registration::RemainingBandwidthData {
fn from(value: v4::registration::RemainingBandwidthData) -> Self {
Self {
available_bandwidth: value.available_bandwidth,
}
}
}
@@ -0,0 +1,10 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
pub mod conversion;
pub mod registration;
pub mod request;
pub mod response;
pub mod topup;
pub const VERSION: u8 = 4;
@@ -0,0 +1,258 @@
// -2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use crate::error::Error;
use base64::{engine::general_purpose, Engine};
use nym_credentials_interface::CredentialSpendingData;
use nym_network_defaults::constants::{WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6};
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::time::SystemTime;
use std::{fmt, ops::Deref, str::FromStr};
#[cfg(feature = "verify")]
use hmac::{Hmac, Mac};
#[cfg(feature = "verify")]
use nym_crypto::asymmetric::encryption::PrivateKey;
#[cfg(feature = "verify")]
use sha2::Sha256;
pub type PendingRegistrations = HashMap<PeerPublicKey, RegistrationData>;
pub type PrivateIPs = HashMap<IpPair, Taken>;
#[cfg(feature = "verify")]
pub type HmacSha256 = Hmac<Sha256>;
pub type Nonce = u64;
pub type Taken = Option<SystemTime>;
pub const BANDWIDTH_CAP_PER_DAY: u64 = 1024 * 1024 * 1024; // 1 GB
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct IpPair {
pub ipv4: Ipv4Addr,
pub ipv6: Ipv6Addr,
}
impl IpPair {
pub fn new(ipv4: Ipv4Addr, ipv6: Ipv6Addr) -> Self {
IpPair { ipv4, ipv6 }
}
}
impl fmt::Display for IpPair {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "({}, {})", self.ipv4, self.ipv6)
}
}
impl From<IpAddr> for IpPair {
fn from(value: IpAddr) -> Self {
let transformed_ipv4 = WG_TUN_DEVICE_IP_ADDRESS_V4;
let transformed_ipv6 = WG_TUN_DEVICE_IP_ADDRESS_V6;
let (ipv4, ipv6) = match value {
std::net::IpAddr::V4(ipv4_addr) => (ipv4_addr, transformed_ipv6),
std::net::IpAddr::V6(ipv6_addr) => (transformed_ipv4, ipv6_addr),
};
IpPair::new(ipv4, ipv6)
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct InitMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
}
impl InitMessage {
pub fn new(pub_key: PeerPublicKey) -> Self {
InitMessage { pub_key }
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FinalMessage {
/// Gateway client data
pub gateway_client: GatewayClient,
/// Ecash credential
pub credential: Option<CredentialSpendingData>,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistrationData {
pub nonce: u64,
pub gateway_data: GatewayClient,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RegistredData {
pub pub_key: PeerPublicKey,
pub private_ips: IpPair,
pub wg_port: u16,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct RemainingBandwidthData {
pub available_bandwidth: i64,
}
/// Client that wants to register sends its PublicKey bytes mac digest encrypted with a DH shared secret.
/// Gateway/Nym node can then verify pub_key payload using the same process
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct GatewayClient {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
/// Assigned private IPs (v4 and v6)
pub private_ips: IpPair,
/// Sha256 hmac on the data (alongside the prior nonce)
pub mac: ClientMac,
}
impl GatewayClient {
#[cfg(feature = "verify")]
pub fn new(
local_secret: &PrivateKey,
remote_public: x25519_dalek::PublicKey,
private_ips: IpPair,
nonce: u64,
) -> Self {
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
#[allow(clippy::expect_used)]
let static_secret = x25519_dalek::StaticSecret::from(local_secret.to_bytes());
let local_public: x25519_dalek::PublicKey = (&static_secret).into();
let dh = static_secret.diffie_hellman(&remote_public);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
.expect("x25519 shared secret is always 32 bytes long");
mac.update(local_public.as_bytes());
mac.update(private_ips.to_string().as_bytes());
mac.update(&nonce.to_le_bytes());
GatewayClient {
pub_key: PeerPublicKey::new(local_public),
private_ips,
mac: ClientMac(mac.finalize().into_bytes().to_vec()),
}
}
// Reusable secret should be gateways Wireguard PK
// Client should perform this step when generating its payload, using its own WG PK
#[cfg(feature = "verify")]
pub fn verify(&self, gateway_key: &PrivateKey, nonce: u64) -> Result<(), Error> {
// convert from 1.0 x25519-dalek private key into 2.0 x25519-dalek
#[allow(clippy::expect_used)]
let static_secret = x25519_dalek::StaticSecret::from(gateway_key.to_bytes());
let dh = static_secret.diffie_hellman(&self.pub_key);
// TODO: change that to use our nym_crypto::hmac module instead
#[allow(clippy::expect_used)]
let mut mac = HmacSha256::new_from_slice(dh.as_bytes())
.expect("x25519 shared secret is always 32 bytes long");
mac.update(self.pub_key.as_bytes());
mac.update(self.private_ips.to_string().as_bytes());
mac.update(&nonce.to_le_bytes());
mac.verify_slice(&self.mac)
.map_err(|source| Error::FailedClientMacVerification {
client: self.pub_key.to_string(),
source,
})
}
pub fn pub_key(&self) -> PeerPublicKey {
self.pub_key
}
}
// TODO: change the inner type into generic array of size HmacSha256::OutputSize
// TODO2: rely on our internal crypto/hmac
#[derive(Debug, Clone)]
pub struct ClientMac(Vec<u8>);
impl fmt::Display for ClientMac {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", general_purpose::STANDARD.encode(&self.0))
}
}
impl ClientMac {
#[allow(dead_code)]
pub fn new(mac: Vec<u8>) -> Self {
ClientMac(mac)
}
}
impl Deref for ClientMac {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl FromStr for ClientMac {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mac_bytes: Vec<u8> =
general_purpose::STANDARD
.decode(s)
.map_err(|source| Error::MalformedClientMac {
mac: s.to_string(),
source,
})?;
Ok(ClientMac(mac_bytes))
}
}
impl Serialize for ClientMac {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let encoded_key = general_purpose::STANDARD.encode(self.0.clone());
serializer.serialize_str(&encoded_key)
}
}
impl<'de> Deserialize<'de> for ClientMac {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let encoded_key = String::deserialize(deserializer)?;
ClientMac::from_str(&encoded_key).map_err(serde::de::Error::custom)
}
}
#[cfg(test)]
mod tests {
use super::*;
use nym_crypto::asymmetric::encryption;
#[test]
#[cfg(feature = "verify")]
fn client_request_roundtrip() {
let mut rng = rand::thread_rng();
let gateway_key_pair = encryption::KeyPair::new(&mut rng);
let client_key_pair = encryption::KeyPair::new(&mut rng);
let nonce = 1234567890;
let client = GatewayClient::new(
client_key_pair.private_key(),
x25519_dalek::PublicKey::from(gateway_key_pair.public_key().to_bytes()),
IpPair::new("10.0.0.42".parse().unwrap(), "fc00::42".parse().unwrap()),
nonce,
);
assert!(client.verify(gateway_key_pair.private_key(), nonce).is_ok())
}
}
@@ -0,0 +1,136 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::{
registration::{FinalMessage, InitMessage},
topup::TopUpMessage,
};
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use nym_sphinx::addressing::Recipient;
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
fn generate_random() -> u64 {
use rand::RngCore;
let mut rng = rand::rngs::OsRng;
rng.next_u64()
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorRequest {
pub protocol: Protocol,
pub data: AuthenticatorRequestData,
pub reply_to: Recipient,
pub request_id: u64,
}
impl AuthenticatorRequest {
pub fn from_reconstructed_message(
message: &nym_sphinx::receiver::ReconstructedMessage,
) -> Result<Self, bincode::Error> {
use bincode::Options;
make_bincode_serializer().deserialize(&message.message)
}
pub fn new_initial_request(init_message: InitMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::Initial(init_message),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_final_request(final_message: FinalMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::Final(Box::new(final_message)),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_query_request(peer_public_key: PeerPublicKey, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::QueryBandwidth(peer_public_key),
reply_to,
request_id,
},
request_id,
)
}
pub fn new_topup_request(top_up_message: TopUpMessage, reply_to: Recipient) -> (Self, u64) {
let request_id = generate_random();
(
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorRequestData::TopUpBandwidth(Box::new(top_up_message)),
reply_to,
request_id,
},
request_id,
)
}
pub fn to_bytes(&self) -> Result<Vec<u8>, bincode::Error> {
use bincode::Options;
make_bincode_serializer().serialize(self)
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorRequestData {
Initial(InitMessage),
Final(Box<FinalMessage>),
QueryBandwidth(PeerPublicKey),
TopUpBandwidth(Box<TopUpMessage>),
}
#[cfg(test)]
mod tests {
use super::*;
use std::str::FromStr;
#[test]
fn check_first_bytes_protocol() {
let version = 4;
let data = AuthenticatorRequest {
protocol: Protocol { version, service_provider_type: ServiceProviderType::Authenticator },
data: AuthenticatorRequestData::Initial(InitMessage::new(
PeerPublicKey::from_str("yvNUDpT5l7W/xDhiu6HkqTHDQwbs/B3J5UrLmORl1EQ=").unwrap(),
)),
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(),
request_id: 1,
};
let bytes = *data.to_bytes().unwrap().first_chunk::<2>().unwrap();
assert_eq!(bytes, [version, ServiceProviderType::Authenticator as u8]);
}
}
@@ -0,0 +1,157 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use super::registration::{RegistrationData, RegistredData, RemainingBandwidthData};
use nym_service_provider_requests_common::{Protocol, ServiceProviderType};
use nym_sphinx::addressing::Recipient;
use serde::{Deserialize, Serialize};
use crate::make_bincode_serializer;
use super::VERSION;
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct AuthenticatorResponse {
pub protocol: Protocol,
pub data: AuthenticatorResponseData,
pub reply_to: Recipient,
}
impl AuthenticatorResponse {
pub fn new_pending_registration_success(
registration_data: RegistrationData,
request_id: u64,
reply_to: Recipient,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::PendingRegistration(PendingRegistrationResponse {
reply: registration_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_registered(
registred_data: RegistredData,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::Registered(RegisteredResponse {
reply: registred_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_remaining_bandwidth(
remaining_bandwidth_data: Option<RemainingBandwidthData>,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::RemainingBandwidth(RemainingBandwidthResponse {
reply: remaining_bandwidth_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn new_topup_bandwidth(
remaining_bandwidth_data: RemainingBandwidthData,
reply_to: Recipient,
request_id: u64,
) -> Self {
Self {
protocol: Protocol {
service_provider_type: ServiceProviderType::Authenticator,
version: VERSION,
},
data: AuthenticatorResponseData::TopUpBandwidth(TopUpBandwidthResponse {
reply: remaining_bandwidth_data,
reply_to,
request_id,
}),
reply_to,
}
}
pub fn recipient(&self) -> Recipient {
self.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)
}
pub fn id(&self) -> Option<u64> {
match &self.data {
AuthenticatorResponseData::PendingRegistration(response) => Some(response.request_id),
AuthenticatorResponseData::Registered(response) => Some(response.request_id),
AuthenticatorResponseData::RemainingBandwidth(response) => Some(response.request_id),
AuthenticatorResponseData::TopUpBandwidth(response) => Some(response.request_id),
}
}
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum AuthenticatorResponseData {
PendingRegistration(PendingRegistrationResponse),
Registered(RegisteredResponse),
RemainingBandwidth(RemainingBandwidthResponse),
TopUpBandwidth(TopUpBandwidthResponse),
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PendingRegistrationResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistrationData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RegisteredResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RegistredData,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct RemainingBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: Option<RemainingBandwidthData>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TopUpBandwidthResponse {
pub request_id: u64,
pub reply_to: Recipient,
pub reply: RemainingBandwidthData,
}
@@ -0,0 +1,15 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use nym_credentials_interface::CredentialSpendingData;
use nym_wireguard_types::PeerPublicKey;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct TopUpMessage {
/// Base64 encoded x25519 public key
pub pub_key: PeerPublicKey,
/// Ecash credential
pub credential: CredentialSpendingData,
}
+1 -1
View File
@@ -248,7 +248,7 @@ mod tests {
data: IpPacketRequestData::StaticConnect(
StaticConnectRequest {
request_id: 123,
ips: IpPair::new(Ipv4Addr::from_str("10.0.0.1").unwrap(), Ipv6Addr::from_str("2001:db8:a160::1").unwrap()),
ips: IpPair::new(Ipv4Addr::from_str("10.0.0.1").unwrap(), Ipv6Addr::from_str("fc00::1").unwrap()),
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(),
reply_to_hops: None,
reply_to_avg_mix_delays: None,
+1 -1
View File
@@ -429,7 +429,7 @@ mod tests {
SignedStaticConnectRequest {
request: StaticConnectRequest {
request_id: 123,
ips: IpPair::new(Ipv4Addr::from_str("10.0.0.1").unwrap(), Ipv6Addr::from_str("2001:db8:a160::1").unwrap()),
ips: IpPair::new(Ipv4Addr::from_str("10.0.0.1").unwrap(), Ipv6Addr::from_str("fc00::1").unwrap()),
reply_to: Recipient::try_from_base58_string("D1rrpsysCGCYXy9saP8y3kmNpGtJZUXN9SvFoUcqAsM9.9Ssso1ea5NfkbMASdiseDSjTN1fSWda5SgEVjdSN4CvV@GJqd3ZxpXWSNxTfx7B1pPtswpetH4LnJdFeLeuY5KUuN").unwrap(),
reply_to_hops: None,
reply_to_avg_mix_delays: None,
+5 -3
View File
@@ -45,13 +45,15 @@ pub mod nyx {
}
pub mod wireguard {
use std::net::{IpAddr, Ipv4Addr};
use std::net::{Ipv4Addr, Ipv6Addr};
pub const WG_PORT: u16 = 51822;
// The interface used to route traffic
pub const WG_TUN_BASE_NAME: &str = "nymwg";
pub const WG_TUN_DEVICE_ADDRESS: &str = "10.1.0.1";
pub const WG_TUN_DEVICE_IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::new(10, 1, 0, 1));
pub const WG_TUN_DEVICE_NETMASK: &str = "255.255.255.0";
pub const WG_TUN_DEVICE_IP_ADDRESS_V4: Ipv4Addr = Ipv4Addr::new(10, 1, 0, 1);
pub const WG_TUN_DEVICE_NETMASK_V4: u8 = 16;
pub const WG_TUN_DEVICE_IP_ADDRESS_V6: Ipv6Addr = Ipv6Addr::new(0xfc01, 0, 0, 0, 0, 0, 0, 0x1); // fc01::1
pub const WG_TUN_DEVICE_NETMASK_V6: u8 = 112;
}
+14 -6
View File
@@ -1,7 +1,7 @@
// Copyright 2024 - Nym Technologies SA <contact@nymtech.net>
// SPDX-License-Identifier: Apache-2.0
use std::net::{IpAddr, SocketAddr};
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)]
pub struct Config {
@@ -9,15 +9,23 @@ pub struct Config {
/// default: `0.0.0.0:51822`
pub bind_address: SocketAddr,
/// Private IP address of the wireguard gateway.
/// Private IPv4 address of the wireguard gateway.
/// default: `10.1.0.1`
pub private_ip: IpAddr,
pub private_ipv4: Ipv4Addr,
/// Private IPv6 address of the wireguard gateway.
/// default: `fc01::1`
pub private_ipv6: Ipv6Addr,
/// Port announced to external clients wishing to connect to the wireguard interface.
/// Useful in the instances where the node is behind a proxy.
pub announced_port: u16,
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard.
/// The maximum value for IPv4 is 32 and for IPv6 is 128
pub private_network_prefix: u8,
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv4.
/// The maximum value for IPv4 is 32
pub private_network_prefix_v4: u8,
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv6.
/// The maximum value for IPv6 is 128
pub private_network_prefix_v6: u8,
}
+29 -11
View File
@@ -10,13 +10,13 @@ use defguard_wireguard_rs::WGApi;
#[cfg(target_os = "linux")]
use defguard_wireguard_rs::{host::Peer, key::Key, net::IpAddrMask};
use nym_crypto::asymmetric::encryption::KeyPair;
#[cfg(target_os = "linux")]
use nym_network_defaults::constants::WG_TUN_BASE_NAME;
use nym_wireguard_types::Config;
use peer_controller::PeerControlRequest;
use std::sync::Arc;
use tokio::sync::mpsc::{self, Receiver, Sender};
const WG_TUN_NAME: &str = "nymwg";
pub(crate) mod error;
pub mod peer_controller;
pub mod peer_handle;
@@ -93,7 +93,7 @@ pub async fn start_wireguard<St: nym_gateway_storage::Storage + Clone + 'static>
use std::collections::HashMap;
use tokio::sync::RwLock;
let ifname = String::from(WG_TUN_NAME);
let ifname = String::from(WG_TUN_BASE_NAME);
let wg_api = defguard_wireguard_rs::WGApi::new(ifname.clone(), false)?;
let mut peer_bandwidth_managers = HashMap::with_capacity(all_peers.len());
let peers = all_peers
@@ -124,23 +124,41 @@ pub async fn start_wireguard<St: nym_gateway_storage::Storage + Clone + 'static>
let interface_config = InterfaceConfiguration {
name: ifname.clone(),
prvkey: BASE64_STANDARD.encode(wireguard_data.inner.keypair().private_key().to_bytes()),
address: wireguard_data.inner.config().private_ip.to_string(),
address: wireguard_data.inner.config().private_ipv4.to_string(),
port: wireguard_data.inner.config().announced_port as u32,
peers,
mtu: None,
};
wg_api.configure_interface(&interface_config)?;
std::process::Command::new("ip")
.args([
"-6",
"addr",
"add",
&format!(
"{}/{}",
wireguard_data.inner.config().private_ipv6,
wireguard_data.inner.config().private_network_prefix_v6
),
"dev",
(&ifname),
])
.output()?;
// Use a dummy peer to create routing rule for the entire network space
let mut catch_all_peer = Peer::new(Key::new([0; 32]));
let network = IpNetwork::new_truncate(
wireguard_data.inner.config().private_ip,
wireguard_data.inner.config().private_network_prefix,
let network_v4 = IpNetwork::new_truncate(
wireguard_data.inner.config().private_ipv4,
wireguard_data.inner.config().private_network_prefix_v4,
)?;
catch_all_peer.set_allowed_ips(vec![IpAddrMask::new(
network.network_address(),
network.netmask(),
)]);
let network_v6 = IpNetwork::new_truncate(
wireguard_data.inner.config().private_ipv6,
wireguard_data.inner.config().private_network_prefix_v6,
)?;
catch_all_peer.set_allowed_ips(vec![
IpAddrMask::new(network_v4.network_address(), network_v4.netmask()),
IpAddrMask::new(network_v6.network_address(), network_v6.netmask()),
]);
wg_api.configure_peer_routing(&[catch_all_peer])?;
let host = wg_api.read_interface_data()?;
@@ -389,7 +389,7 @@ ip addr show nymtun0
link/none
inet 10.0.0.1/16 scope global nymtun0
valid_lft forever preferred_lft forever
inet6 2001:db8:a160::1/112 scope global
inet6 fc00::1/112 scope global
valid_lft forever preferred_lft forever
inet6 fe80::ad08:d167:5700:8c7c/64 scope link stable-privacy
valid_lft forever preferred_lft forever`
+1 -13
View File
@@ -265,14 +265,6 @@ pub(crate) struct WireguardArgs {
)]
pub(crate) wireguard_bind_address: Option<SocketAddr>,
/// Private IP address of the wireguard gateway.
/// default: `10.1.0.1`
#[clap(
long,
env = NYMNODE_WG_IP_ARG,
)]
pub(crate) wireguard_private_ip: Option<IpAddr>,
/// Port announced to external clients wishing to connect to the wireguard interface.
/// Useful in the instances where the node is behind a proxy.
#[clap(
@@ -312,12 +304,8 @@ impl WireguardArgs {
section.announced_port = announced_port
}
if let Some(private_ip) = self.wireguard_private_ip {
section.private_ip = private_ip
}
if let Some(private_network_prefix) = self.wireguard_private_network_prefix {
section.private_network_prefix = private_network_prefix
section.private_network_prefix_v4 = private_network_prefix
}
section
+4 -2
View File
@@ -181,9 +181,11 @@ pub fn ephemeral_entry_gateway_config(
config: super::Wireguard {
enabled: config.wireguard.enabled,
bind_address: config.wireguard.bind_address,
private_ip: config.wireguard.private_ip,
private_ipv4: config.wireguard.private_ipv4,
private_ipv6: config.wireguard.private_ipv6,
announced_port: config.wireguard.announced_port,
private_network_prefix: config.wireguard.private_network_prefix,
private_network_prefix_v4: config.wireguard.private_network_prefix_v4,
private_network_prefix_v6: config.wireguard.private_network_prefix_v6,
storage_paths: config.wireguard.storage_paths.clone(),
},
custom_mixnet_path: None,
+4 -2
View File
@@ -278,9 +278,11 @@ pub fn ephemeral_exit_gateway_config(
config: super::Wireguard {
enabled: config.wireguard.enabled,
bind_address: config.wireguard.bind_address,
private_ip: config.wireguard.private_ip,
private_ipv4: config.wireguard.private_ipv4,
private_ipv6: config.wireguard.private_ipv6,
announced_port: config.wireguard.announced_port,
private_network_prefix: config.wireguard.private_network_prefix,
private_network_prefix_v4: config.wireguard.private_network_prefix_v4,
private_network_prefix_v6: config.wireguard.private_network_prefix_v6,
storage_paths: config.wireguard.storage_paths.clone(),
},
custom_mixnet_path: None,
+30 -20
View File
@@ -10,7 +10,9 @@ use clap::ValueEnum;
use nym_bin_common::logging::LoggingSettings;
use nym_config::defaults::{
mainnet, var_names, DEFAULT_MIX_LISTENING_PORT, DEFAULT_NYM_NODE_HTTP_PORT, WG_PORT,
WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6,
};
use nym_config::defaults::{WG_TUN_DEVICE_NETMASK_V4, WG_TUN_DEVICE_NETMASK_V6};
use nym_config::helpers::inaddr_any;
use nym_config::serde_helpers::de_maybe_port;
use nym_config::serde_helpers::de_maybe_stringified;
@@ -21,7 +23,7 @@ use nym_config::{
use serde::{Deserialize, Serialize};
use std::env;
use std::fmt::{Display, Formatter};
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use std::path::{Path, PathBuf};
use std::time::Duration;
use tracing::{debug, error};
@@ -43,9 +45,6 @@ pub use crate::config::mixnode::MixnodeConfig;
const DEFAULT_NYMNODES_DIR: &str = "nym-nodes";
pub const DEFAULT_WIREGUARD_PORT: u16 = WG_PORT;
pub const DEFAULT_WIREGUARD_IP: IpAddr = IpAddr::V4(Ipv4Addr::new(10, 1, 0, 1));
pub const DEFAULT_WIREGUARD_PREFIX: u8 = 16;
pub const DEFAULT_HTTP_PORT: u16 = DEFAULT_NYM_NODE_HTTP_PORT;
pub const DEFAULT_MIXNET_PORT: u16 = DEFAULT_MIX_LISTENING_PORT;
@@ -518,17 +517,25 @@ pub struct Wireguard {
/// default: `0.0.0.0:51822`
pub bind_address: SocketAddr,
/// Private IP address of the wireguard gateway.
/// Private IPv4 address of the wireguard gateway.
/// default: `10.1.0.1`
pub private_ip: IpAddr,
pub private_ipv4: Ipv4Addr,
/// Private IPv6 address of the wireguard gateway.
/// default: `fc01::1`
pub private_ipv6: Ipv6Addr,
/// Port announced to external clients wishing to connect to the wireguard interface.
/// Useful in the instances where the node is behind a proxy.
pub announced_port: u16,
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard.
/// The maximum value for IPv4 is 32 and for IPv6 is 128
pub private_network_prefix: u8,
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv4.
/// The maximum value for IPv4 is 32
pub private_network_prefix_v4: u8,
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv6.
/// The maximum value for IPv6 is 128
pub private_network_prefix_v6: u8,
/// Paths for wireguard keys, client registries, etc.
pub storage_paths: persistence::WireguardPaths,
@@ -538,13 +545,12 @@ impl Wireguard {
pub fn new_default<P: AsRef<Path>>(data_dir: P) -> Self {
Wireguard {
enabled: false,
bind_address: SocketAddr::new(
IpAddr::V4(Ipv4Addr::UNSPECIFIED),
DEFAULT_WIREGUARD_PORT,
),
private_ip: DEFAULT_WIREGUARD_IP,
announced_port: DEFAULT_WIREGUARD_PORT,
private_network_prefix: DEFAULT_WIREGUARD_PREFIX,
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), WG_PORT),
private_ipv4: WG_TUN_DEVICE_IP_ADDRESS_V4,
private_ipv6: WG_TUN_DEVICE_IP_ADDRESS_V6,
announced_port: WG_PORT,
private_network_prefix_v4: WG_TUN_DEVICE_NETMASK_V4,
private_network_prefix_v6: WG_TUN_DEVICE_NETMASK_V6,
storage_paths: persistence::WireguardPaths::new(data_dir),
}
}
@@ -554,9 +560,11 @@ impl From<Wireguard> for nym_wireguard_types::Config {
fn from(value: Wireguard) -> Self {
nym_wireguard_types::Config {
bind_address: value.bind_address,
private_ip: value.private_ip,
private_ipv4: value.private_ipv4,
private_ipv6: value.private_ipv6,
announced_port: value.announced_port,
private_network_prefix: value.private_network_prefix,
private_network_prefix_v4: value.private_network_prefix_v4,
private_network_prefix_v6: value.private_network_prefix_v6,
}
}
}
@@ -565,9 +573,11 @@ impl From<Wireguard> for nym_authenticator::config::Authenticator {
fn from(value: Wireguard) -> Self {
nym_authenticator::config::Authenticator {
bind_address: value.bind_address,
private_ip: value.private_ip,
private_ipv4: value.private_ipv4,
private_ipv6: value.private_ipv6,
announced_port: value.announced_port,
private_network_prefix: value.private_network_prefix,
private_network_prefix_v4: value.private_network_prefix_v4,
private_network_prefix_v6: value.private_network_prefix_v6,
}
}
}
+2
View File
@@ -5,8 +5,10 @@ mod old_config_v1;
mod old_config_v2;
mod old_config_v3;
mod old_config_v4;
mod old_config_v5;
pub use old_config_v1::try_upgrade_config_v1;
pub use old_config_v2::try_upgrade_config_v2;
pub use old_config_v3::try_upgrade_config_v3;
pub use old_config_v4::try_upgrade_config_v4;
pub use old_config_v5::try_upgrade_config_v5;
@@ -4,12 +4,6 @@
#![allow(dead_code)]
use crate::{config::*, error::KeyIOFailure};
use entry_gateway::{Debug as EntryGatewayConfigDebug, ZkNymTicketHandlerDebug};
use exit_gateway::{
Debug as ExitGatewayConfigDebug, IpPacketRouter, IpPacketRouterDebug, NetworkRequester,
NetworkRequesterDebug,
};
use mixnode::{Verloc, VerlocDebug};
use nym_client_core_config_types::{
disk_persistence::{ClientKeysPaths, CommonClientPaths},
DebugConfig as ClientDebugConfig,
@@ -22,6 +16,7 @@ use nym_network_requester::{
};
use nym_pemstore::{store_key, store_keypair};
use nym_sphinx_acknowledgements::AckKey;
use old_configs::old_config_v5::*;
use persistence::*;
use rand::rngs::OsRng;
use serde::{Deserialize, Serialize};
@@ -93,12 +88,12 @@ pub enum NodeModeV4 {
ExitGateway,
}
impl From<NodeModeV4> for NodeMode {
impl From<NodeModeV4> for NodeModeV5 {
fn from(config: NodeModeV4) -> Self {
match config {
NodeModeV4::Mixnode => NodeMode::Mixnode,
NodeModeV4::EntryGateway => NodeMode::EntryGateway,
NodeModeV4::ExitGateway => NodeMode::ExitGateway,
NodeModeV4::Mixnode => NodeModeV5::Mixnode,
NodeModeV4::EntryGateway => NodeModeV5::EntryGateway,
NodeModeV4::ExitGateway => NodeModeV5::ExitGateway,
}
}
}
@@ -1068,7 +1063,7 @@ pub async fn initialise(
pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
path: P,
prev_config: Option<ConfigV4>,
) -> Result<Config, NymNodeError> {
) -> Result<ConfigV5, NymNodeError> {
tracing::debug!("Updating from 1.1.5");
let old_cfg = if let Some(prev_config) = prev_config {
prev_config
@@ -1094,21 +1089,21 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
.ok_or(NymNodeError::DataDirDerivationFailure)?,
);
let cfg = Config {
let cfg = ConfigV5 {
save_path: old_cfg.save_path,
id: old_cfg.id,
mode: old_cfg.mode.into(),
host: Host {
host: HostV5 {
public_ips: old_cfg.host.public_ips,
hostname: old_cfg.host.hostname,
location: old_cfg.host.location,
},
mixnet: Mixnet {
mixnet: MixnetV5 {
bind_address: old_cfg.mixnet.bind_address,
announce_port: old_cfg.mixnet.announce_port,
nym_api_urls: old_cfg.mixnet.nym_api_urls,
nyxd_urls: old_cfg.mixnet.nyxd_urls,
debug: MixnetDebug {
debug: MixnetDebugV5 {
packet_forwarding_initial_backoff: old_cfg
.mixnet
.debug
@@ -1122,8 +1117,8 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
unsafe_disable_noise: old_cfg.mixnet.debug.unsafe_disable_noise,
},
},
storage_paths: NymNodePaths {
keys: KeysPaths {
storage_paths: NymNodePathsV5 {
keys: KeysPathsV5 {
private_ed25519_identity_key_file: old_cfg
.storage_paths
.keys
@@ -1151,7 +1146,7 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
},
description: old_cfg.storage_paths.description,
},
http: Http {
http: HttpV5 {
bind_address: old_cfg.http.bind_address,
landing_page_assets_path: old_cfg.http.landing_page_assets_path,
access_token: old_cfg.http.access_token,
@@ -1159,13 +1154,13 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
expose_system_hardware: old_cfg.http.expose_system_hardware,
expose_crypto_hardware: old_cfg.http.expose_crypto_hardware,
},
wireguard: Wireguard {
wireguard: WireguardV5 {
enabled: old_cfg.wireguard.enabled,
bind_address: old_cfg.wireguard.bind_address,
private_ip: old_cfg.wireguard.private_ip,
announced_port: old_cfg.wireguard.announced_port,
private_network_prefix: old_cfg.wireguard.private_network_prefix,
storage_paths: WireguardPaths {
storage_paths: WireguardPathsV5 {
private_diffie_hellman_key_file: old_cfg
.wireguard
.storage_paths
@@ -1176,12 +1171,12 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
.public_diffie_hellman_key_file,
},
},
mixnode: MixnodeConfig {
storage_paths: MixnodePaths {},
verloc: Verloc {
mixnode: MixnodeConfigV5 {
storage_paths: MixnodePathsV5 {},
verloc: VerlocV5 {
bind_address: old_cfg.mixnode.verloc.bind_address,
announce_port: old_cfg.mixnode.verloc.announce_port,
debug: VerlocDebug {
debug: VerlocDebugV5 {
packets_per_node: old_cfg.mixnode.verloc.debug.packets_per_node,
connection_timeout: old_cfg.mixnode.verloc.debug.connection_timeout,
packet_timeout: old_cfg.mixnode.verloc.debug.packet_timeout,
@@ -1191,17 +1186,17 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
retry_timeout: old_cfg.mixnode.verloc.debug.retry_timeout,
},
},
debug: mixnode::Debug {
debug: DebugV5 {
node_stats_logging_delay: old_cfg.mixnode.debug.node_stats_logging_delay,
node_stats_updating_delay: old_cfg.mixnode.debug.node_stats_updating_delay,
},
},
entry_gateway: EntryGatewayConfig {
storage_paths: EntryGatewayPaths {
entry_gateway: EntryGatewayConfigV5 {
storage_paths: EntryGatewayPathsV5 {
clients_storage: old_cfg.entry_gateway.storage_paths.clients_storage,
stats_storage: entry_gateway_paths.stats_storage,
cosmos_mnemonic: old_cfg.entry_gateway.storage_paths.cosmos_mnemonic,
authenticator: AuthenticatorPaths {
authenticator: AuthenticatorPathsV5 {
private_ed25519_identity_key_file: old_cfg
.entry_gateway
.storage_paths
@@ -1243,9 +1238,9 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
bind_address: old_cfg.entry_gateway.bind_address,
announce_ws_port: old_cfg.entry_gateway.announce_ws_port,
announce_wss_port: old_cfg.entry_gateway.announce_wss_port,
debug: EntryGatewayConfigDebug {
debug: EntryGatewayConfigDebugV5 {
message_retrieval_limit: old_cfg.entry_gateway.debug.message_retrieval_limit,
zk_nym_tickets: ZkNymTicketHandlerDebug {
zk_nym_tickets: ZkNymTicketHandlerDebugV5 {
revocation_bandwidth_penalty: old_cfg
.entry_gateway
.debug
@@ -1270,11 +1265,11 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
},
},
},
exit_gateway: ExitGatewayConfig {
storage_paths: ExitGatewayPaths {
exit_gateway: ExitGatewayConfigV5 {
storage_paths: ExitGatewayPathsV5 {
clients_storage: old_cfg.exit_gateway.storage_paths.clients_storage,
stats_storage: exit_gateway_paths.stats_storage,
network_requester: NetworkRequesterPaths {
network_requester: NetworkRequesterPathsV5 {
private_ed25519_identity_key_file: old_cfg
.exit_gateway
.storage_paths
@@ -1311,7 +1306,7 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
.network_requester
.gateway_registrations,
},
ip_packet_router: IpPacketRouterPaths {
ip_packet_router: IpPacketRouterPathsV5 {
private_ed25519_identity_key_file: old_cfg
.exit_gateway
.storage_paths
@@ -1348,7 +1343,7 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
.ip_packet_router
.gateway_registrations,
},
authenticator: AuthenticatorPaths {
authenticator: AuthenticatorPathsV5 {
private_ed25519_identity_key_file: old_cfg
.exit_gateway
.storage_paths
@@ -1388,8 +1383,8 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
},
open_proxy: old_cfg.exit_gateway.open_proxy,
upstream_exit_policy_url: old_cfg.exit_gateway.upstream_exit_policy_url,
network_requester: NetworkRequester {
debug: NetworkRequesterDebug {
network_requester: NetworkRequesterV5 {
debug: NetworkRequesterDebugV5 {
enabled: old_cfg.exit_gateway.network_requester.debug.enabled,
disable_poisson_rate: old_cfg
.exit_gateway
@@ -1399,8 +1394,8 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
client_debug: old_cfg.exit_gateway.network_requester.debug.client_debug,
},
},
ip_packet_router: IpPacketRouter {
debug: IpPacketRouterDebug {
ip_packet_router: IpPacketRouterV5 {
debug: IpPacketRouterDebugV5 {
enabled: old_cfg.exit_gateway.ip_packet_router.debug.enabled,
disable_poisson_rate: old_cfg
.exit_gateway
@@ -1410,12 +1405,18 @@ pub async fn try_upgrade_config_v4<P: AsRef<Path>>(
client_debug: old_cfg.exit_gateway.ip_packet_router.debug.client_debug,
},
},
debug: ExitGatewayConfigDebug {
debug: ExitGatewayDebugV5 {
message_retrieval_limit: old_cfg.exit_gateway.debug.message_retrieval_limit,
},
},
authenticator: Default::default(),
logging: LoggingSettings {},
authenticator: AuthenticatorV5 {
debug: AuthenticatorDebugV5 {
enabled: old_cfg.authenticator.debug.enabled,
disable_poisson_rate: old_cfg.authenticator.debug.disable_poisson_rate,
client_debug: old_cfg.authenticator.debug.client_debug,
},
},
logging: LoggingSettingsV5 {},
};
Ok(cfg)
File diff suppressed because it is too large Load Diff
+12 -4
View File
@@ -123,15 +123,23 @@ bind_address = '{{ wireguard.bind_address }}'
# Private IP address of the wireguard gateway.
# default: `10.1.0.1`
private_ip = '{{ wireguard.private_ip }}'
private_ipv4 = '{{ wireguard.private_ipv4 }}'
# Private IP address of the wireguard gateway.
# default: `fc01::1`
private_ipv6 = '{{ wireguard.private_ipv6 }}'
# Port announced to external clients wishing to connect to the wireguard interface.
# Useful in the instances where the node is behind a proxy.
announced_port = {{ wireguard.announced_port }}
# The prefix denoting the maximum number of the clients that can be connected via Wireguard.
# The maximum value for IPv4 is 32 and for IPv6 is 128
private_network_prefix = {{ wireguard.private_network_prefix }}
# The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv4.
# The maximum value for IPv4 is 32
private_network_prefix_v4 = {{ wireguard.private_network_prefix_v4 }}
# The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv6.
# The maximum value for IPv6 is 128
private_network_prefix_v6 = {{ wireguard.private_network_prefix_v6 }}
[wireguard.storage_paths]
# Path to file containing wireguard x25519 diffie hellman private key.
+2 -1
View File
@@ -11,7 +11,8 @@ async fn try_upgrade_config(path: &Path) -> Result<(), NymNodeError> {
let cfg = try_upgrade_config_v1(path, None).await.ok();
let cfg = try_upgrade_config_v2(path, cfg).await.ok();
let cfg = try_upgrade_config_v3(path, cfg).await.ok();
match try_upgrade_config_v4(path, cfg).await {
let cfg = try_upgrade_config_v4(path, cfg).await.ok();
match try_upgrade_config_v5(path, cfg).await {
Ok(cfg) => cfg.save(),
Err(e) => {
tracing::error!("Failed to finish upgrade - {e}");
-1
View File
@@ -43,7 +43,6 @@ pub mod vars {
// wireguard:
pub const NYMNODE_WG_ENABLED_ARG: &str = "NYMNODE_WG_ENABLED";
pub const NYMNODE_WG_BIND_ADDRESS_ARG: &str = "NYMNODE_WG_BIND_ADDRESS";
pub const NYMNODE_WG_IP_ARG: &str = "NYMNODE_WG_IP";
pub const NYMNODE_WG_ANNOUNCED_PORT_ARG: &str = "NYMNODE_WG_ANNOUNCED_PORT";
pub const NYMNODE_WG_PRIVATE_NETWORK_PREFIX_ARG: &str = "NYMNODE_WG_PRIVATE_NETWORK_PREFIX";
@@ -143,17 +143,17 @@ impl<S: Storage + Clone + 'static> Authenticator<S> {
let used_private_network_ips =
std::collections::BTreeSet::from_iter(self.used_private_network_ips.iter());
let private_ip_network = IpNetwork::new(
self.config.authenticator.private_ip,
self.config.authenticator.private_network_prefix,
self.config.authenticator.private_ipv4.into(),
self.config.authenticator.private_network_prefix_v4,
)?;
let now = SystemTime::now();
let free_private_network_ips = private_ip_network
.iter()
.map(|ip| {
.map(|ip: IpAddr| {
if used_private_network_ips.contains(&ip) {
(ip, Some(now))
(ip.into(), Some(now))
} else {
(ip, None)
(ip.into(), None)
}
})
.collect();
@@ -6,14 +6,14 @@ use crate::cli::{override_config, OverrideConfig};
use crate::cli::{try_load_current_config, version_check};
use clap::{Args, Subcommand};
use nym_authenticator_requests::latest::{
registration::{ClientMac, FinalMessage, GatewayClient, InitMessage},
registration::{ClientMac, FinalMessage, GatewayClient, InitMessage, IpPair},
request::{AuthenticatorRequest, AuthenticatorRequestData},
};
use nym_client_core::cli_helpers::client_run::CommonClientRunArgs;
use nym_sdk::mixnet::{MixnetMessageSender, Recipient, TransmissionLane};
use nym_task::TaskHandle;
use nym_wireguard_types::PeerPublicKey;
use std::net::IpAddr;
use std::net::{Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
use std::time::Duration;
use tokio::time::sleep;
@@ -55,7 +55,8 @@ pub(crate) struct Initial {
#[derive(Args, Clone, Debug)]
pub(crate) struct Final {
pub_key: String,
private_ip: String,
private_ipv4: String,
private_ipv6: String,
mac: String,
}
@@ -75,7 +76,10 @@ impl TryFrom<RequestType> for AuthenticatorRequestData {
RequestType::Final(req) => AuthenticatorRequestData::Final(Box::new(FinalMessage {
gateway_client: GatewayClient {
pub_key: PeerPublicKey::from_str(&req.pub_key)?,
private_ip: IpAddr::from_str(&req.private_ip)?,
private_ips: IpPair::new(
Ipv4Addr::from_str(&req.private_ipv4)?,
Ipv6Addr::from_str(&req.private_ipv6)?,
),
mac: ClientMac::from_str(&req.mac)?,
},
credential: None,
@@ -8,13 +8,16 @@ use nym_config::{
must_get_home, save_formatted_config_to_file, NymConfigTemplate, OptionalSet,
DEFAULT_CONFIG_DIR, DEFAULT_CONFIG_FILENAME, DEFAULT_DATA_DIR, NYM_DIR,
};
use nym_network_defaults::WG_PORT;
use nym_network_defaults::{
WG_PORT, WG_TUN_DEVICE_IP_ADDRESS_V4, WG_TUN_DEVICE_IP_ADDRESS_V6, WG_TUN_DEVICE_NETMASK_V4,
WG_TUN_DEVICE_NETMASK_V6,
};
use nym_service_providers_common::DEFAULT_SERVICE_PROVIDERS_DIR;
pub use persistence::AuthenticatorPaths;
use serde::{Deserialize, Serialize};
use std::{
io,
net::{IpAddr, Ipv4Addr, SocketAddr},
net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr},
path::{Path, PathBuf},
str::FromStr,
};
@@ -192,24 +195,34 @@ pub struct Authenticator {
/// Private IP address of the wireguard gateway.
/// default: `10.1.0.1`
pub private_ip: IpAddr,
pub private_ipv4: Ipv4Addr,
/// Private IP address of the wireguard gateway.
/// default: `fc01::1`
pub private_ipv6: Ipv6Addr,
/// Port announced to external clients wishing to connect to the wireguard interface.
/// Useful in the instances where the node is behind a proxy.
pub announced_port: u16,
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard.
/// The maximum value for IPv4 is 32 and for IPv6 is 128
pub private_network_prefix: u8,
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv4.
/// The maximum value for IPv4 is 32
pub private_network_prefix_v4: u8,
/// The prefix denoting the maximum number of the clients that can be connected via Wireguard using IPv6.
/// The maximum value for IPv6 is 128
pub private_network_prefix_v6: u8,
}
impl Default for Authenticator {
fn default() -> Self {
Self {
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 51822),
private_ip: IpAddr::V4(Ipv4Addr::new(10, 1, 0, 1)),
bind_address: SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), WG_PORT),
private_ipv4: WG_TUN_DEVICE_IP_ADDRESS_V4,
private_ipv6: WG_TUN_DEVICE_IP_ADDRESS_V6,
announced_port: WG_PORT,
private_network_prefix: 16,
private_network_prefix_v4: WG_TUN_DEVICE_NETMASK_V4,
private_network_prefix_v6: WG_TUN_DEVICE_NETMASK_V6,
}
}
}
@@ -218,9 +231,11 @@ impl From<Authenticator> for nym_wireguard_types::Config {
fn from(value: Authenticator) -> Self {
nym_wireguard_types::Config {
bind_address: value.bind_address,
private_ip: value.private_ip,
private_ipv4: value.private_ipv4,
private_ipv6: value.private_ipv6,
announced_port: value.announced_port,
private_network_prefix: value.private_network_prefix,
private_network_prefix_v4: value.private_network_prefix_v4,
private_network_prefix_v6: value.private_network_prefix_v6,
}
}
}
@@ -11,17 +11,15 @@ use defguard_wireguard_rs::net::IpAddrMask;
use defguard_wireguard_rs::{host::Peer, key::Key};
use futures::StreamExt;
use nym_authenticator_requests::{
v1, v2,
v3::{
self,
latest::{
registration::{
FinalMessage, GatewayClient, InitMessage, PendingRegistrations, PrivateIPs,
FinalMessage, GatewayClient, InitMessage, IpPair, PendingRegistrations, PrivateIPs,
RegistrationData, RegistredData, RemainingBandwidthData,
},
request::{AuthenticatorRequest, AuthenticatorRequestData},
response::AuthenticatorResponse,
},
CURRENT_VERSION,
v1, v2, v3, v4, CURRENT_VERSION,
};
use nym_credential_verification::{
bandwidth_storage_manager::BandwidthStorageManager, ecash::EcashManager,
@@ -116,10 +114,10 @@ impl<S: Storage + Clone + 'static> MixnetListener<S> {
for reg in registred_values {
let ip = registred_and_free
.free_private_network_ips
.get_mut(&reg.gateway_data.private_ip)
.get_mut(&reg.gateway_data.private_ips)
.ok_or(AuthenticatorError::InternalDataCorruption(format!(
"IP {} should be present",
reg.gateway_data.private_ip
"IPs {} should be present",
reg.gateway_data.private_ips
)))?;
let Some(timestamp) = ip else {
@@ -173,15 +171,29 @@ impl<S: Storage + Clone + 'static> MixnetListener<S> {
let peer = self.peer_manager.query_peer(remote_public).await?;
if let Some(peer) = peer {
let Some(allowed_ip) = peer.allowed_ips.first() else {
let private_ipv4 = peer
.allowed_ips
.iter()
.find_map(|ip_mask| match ip_mask.ip {
std::net::IpAddr::V4(ipv4_addr) => Some(ipv4_addr),
_ => None,
});
let private_ipv6 = peer
.allowed_ips
.iter()
.find_map(|ip_mask| match ip_mask.ip {
std::net::IpAddr::V6(ipv6_addr) => Some(ipv6_addr),
_ => None,
});
let (Some(allowed_ipv4), Some(allowed_ipv6)) = (private_ipv4, private_ipv6) else {
return Err(AuthenticatorError::InternalError(
"private ip list should not be empty".to_string(),
"there should be one private IP pair in the list".to_string(),
));
};
return Ok(AuthenticatorResponse::new_registered(
RegistredData {
pub_key: PeerPublicKey::new(self.keypair().public_key().to_bytes().into()),
private_ip: allowed_ip.ip,
private_ips: IpPair::new(allowed_ipv4, allowed_ipv6),
wg_port: self.config.authenticator.announced_port,
},
reply_to,
@@ -241,8 +253,14 @@ impl<S: Storage + Clone + 'static> MixnetListener<S> {
}
let mut peer = Peer::new(Key::new(final_message.gateway_client.pub_key.to_bytes()));
peer.allowed_ips
.push(IpAddrMask::new(final_message.gateway_client.private_ip, 32));
peer.allowed_ips.push(IpAddrMask::new(
final_message.gateway_client.private_ips.ipv4.into(),
32,
));
peer.allowed_ips.push(IpAddrMask::new(
final_message.gateway_client.private_ips.ipv6.into(),
128,
));
// If gateway does ecash verification and client sends a credential, we do the additional
// credential verification. Later this will become mandatory.
@@ -284,7 +302,7 @@ impl<S: Storage + Clone + 'static> MixnetListener<S> {
Ok(AuthenticatorResponse::new_registered(
RegistredData {
pub_key: registration_data.gateway_data.pub_key,
private_ip: registration_data.gateway_data.private_ip,
private_ips: registration_data.gateway_data.private_ips,
wg_port: registration_data.wg_port,
},
reply_to,
@@ -507,6 +525,7 @@ fn deserialize_request(reconstructed: &ReconstructedMessage) -> Result<Authentic
[1, _] => v1::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket { source: err })
.map(Into::<v2::request::AuthenticatorRequest>::into)
.map(Into::<v3::request::AuthenticatorRequest>::into)
.map(Into::into),
[2, request_type] => {
if request_type == ServiceProviderType::Authenticator as u8 {
@@ -514,6 +533,7 @@ fn deserialize_request(reconstructed: &ReconstructedMessage) -> Result<Authentic
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket {
source: err,
})
.map(Into::<v3::request::AuthenticatorRequest>::into)
.map(Into::into)
} else {
Err(AuthenticatorError::InvalidPacketType(request_type))
@@ -525,6 +545,17 @@ fn deserialize_request(reconstructed: &ReconstructedMessage) -> Result<Authentic
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket {
source: err,
})
.map(Into::into)
} else {
Err(AuthenticatorError::InvalidPacketType(request_type))
}
}
[4, request_type] => {
if request_type == ServiceProviderType::Authenticator as u8 {
v4::request::AuthenticatorRequest::from_reconstructed_message(reconstructed)
.map_err(|err| AuthenticatorError::FailedToDeserializeTaggedPacket {
source: err,
})
} else {
Err(AuthenticatorError::InvalidPacketType(request_type))
}
@@ -5,7 +5,7 @@ use std::time::Duration;
pub const TUN_BASE_NAME: &str = "nymtun";
pub const TUN_DEVICE_ADDRESS_V4: Ipv4Addr = Ipv4Addr::new(10, 0, 0, 1);
pub const TUN_DEVICE_NETMASK_V4: Ipv4Addr = Ipv4Addr::new(255, 255, 0, 0);
pub const TUN_DEVICE_ADDRESS_V6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0xa160, 0, 0, 0, 0, 0x1); // 2001:db8:a160::1
pub const TUN_DEVICE_ADDRESS_V6: Ipv6Addr = Ipv6Addr::new(0xfc00, 0, 0, 0, 0, 0, 0, 0x1); // fc00::1
pub const TUN_DEVICE_NETMASK_V6: &str = "112";