Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 10270a0f6a | |||
| 406a384393 | |||
| 4508c1db68 | |||
| 2d3c36f851 | |||
| 2b998c1363 | |||
| 13308cf80b |
@@ -43,7 +43,7 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
args: --workspace --release
|
args: --workspace --release --features wireguard
|
||||||
|
|
||||||
- name: Upload Artifact
|
- name: Upload Artifact
|
||||||
uses: actions/upload-artifact@v3
|
uses: actions/upload-artifact@v3
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ jobs:
|
|||||||
uses: actions-rs/cargo@v1
|
uses: actions-rs/cargo@v1
|
||||||
with:
|
with:
|
||||||
command: build
|
command: build
|
||||||
args: --workspace --release
|
args: --workspace --release --features wireguard
|
||||||
|
|
||||||
- name: Prepare build output
|
- name: Prepare build output
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
Generated
+1
@@ -7572,6 +7572,7 @@ dependencies = [
|
|||||||
"nym-network-defaults",
|
"nym-network-defaults",
|
||||||
"nym-task",
|
"nym-task",
|
||||||
"nym-wireguard-types",
|
"nym-wireguard-types",
|
||||||
|
"serde",
|
||||||
"tokio",
|
"tokio",
|
||||||
"x25519-dalek 2.0.0",
|
"x25519-dalek 2.0.0",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -275,6 +275,10 @@ impl NymApiClient {
|
|||||||
Ok(self.nym_api.get_gateways().await?)
|
Ok(self.nym_api.get_gateways().await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_all_gateways(&self) -> Result<Vec<GatewayBond>, ValidatorClientError> {
|
||||||
|
Ok(self.nym_api.get_all_gateways().await?)
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_cached_described_gateways(
|
pub async fn get_cached_described_gateways(
|
||||||
&self,
|
&self,
|
||||||
) -> Result<Vec<DescribedGateway>, ValidatorClientError> {
|
) -> Result<Vec<DescribedGateway>, ValidatorClientError> {
|
||||||
|
|||||||
@@ -79,6 +79,11 @@ pub trait NymApiClientExt: ApiClient {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_all_gateways(&self) -> Result<Vec<GatewayBond>, NymAPIError> {
|
||||||
|
self.get_json(&[routes::API_VERSION, routes::GATEWAYS_ALL], NO_PARAMS)
|
||||||
|
.await
|
||||||
|
}
|
||||||
|
|
||||||
async fn get_gateways_described(&self) -> Result<Vec<DescribedGateway>, NymAPIError> {
|
async fn get_gateways_described(&self) -> Result<Vec<DescribedGateway>, NymAPIError> {
|
||||||
self.get_json(
|
self.get_json(
|
||||||
&[routes::API_VERSION, routes::GATEWAYS, routes::DESCRIBED],
|
&[routes::API_VERSION, routes::GATEWAYS, routes::DESCRIBED],
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use nym_network_defaults::NYM_API_VERSION;
|
|||||||
pub const API_VERSION: &str = NYM_API_VERSION;
|
pub const API_VERSION: &str = NYM_API_VERSION;
|
||||||
pub const MIXNODES: &str = "mixnodes";
|
pub const MIXNODES: &str = "mixnodes";
|
||||||
pub const GATEWAYS: &str = "gateways";
|
pub const GATEWAYS: &str = "gateways";
|
||||||
|
pub const GATEWAYS_ALL: &str = "gateways/all";
|
||||||
pub const DESCRIBED: &str = "described";
|
pub const DESCRIBED: &str = "described";
|
||||||
|
|
||||||
pub const DETAILED: &str = "detailed";
|
pub const DETAILED: &str = "detailed";
|
||||||
|
|||||||
@@ -81,6 +81,15 @@ ExitPolicy accept6 *6:119
|
|||||||
ExitPolicy accept *4:120
|
ExitPolicy accept *4:120
|
||||||
ExitPolicy reject6 [FC00::]/7:*
|
ExitPolicy reject6 [FC00::]/7:*
|
||||||
|
|
||||||
|
# Portless
|
||||||
|
ExitPolicy accept *:0
|
||||||
|
ExitPolicy accept *4:0
|
||||||
|
ExitPolicy accept *6:0
|
||||||
|
|
||||||
|
ExitPolicy reject *:0
|
||||||
|
ExitPolicy reject *4:0
|
||||||
|
ExitPolicy reject *6:0
|
||||||
|
|
||||||
#ExitPolicy accept *:8080 #and another comment here
|
#ExitPolicy accept *:8080 #and another comment here
|
||||||
|
|
||||||
ExitPolicy reject FE80:0000:0000:0000:0202:B3FF:FE1E:8329:*
|
ExitPolicy reject FE80:0000:0000:0000:0202:B3FF:FE1E:8329:*
|
||||||
@@ -184,6 +193,60 @@ ExitPolicy reject *:*
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// ExitPolicy accept *:0
|
||||||
|
expected.push(
|
||||||
|
Accept,
|
||||||
|
AddressPortPattern {
|
||||||
|
ip_pattern: IpPattern::Star,
|
||||||
|
ports: PortRange::new_zero(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// ExitPolicy accept *4:0
|
||||||
|
expected.push(
|
||||||
|
Accept,
|
||||||
|
AddressPortPattern {
|
||||||
|
ip_pattern: IpPattern::V4Star,
|
||||||
|
ports: PortRange::new_zero(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// ExitPolicy accept *6:0
|
||||||
|
expected.push(
|
||||||
|
Accept,
|
||||||
|
AddressPortPattern {
|
||||||
|
ip_pattern: IpPattern::V6Star,
|
||||||
|
ports: PortRange::new_zero(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// ExitPolicy reject *:0
|
||||||
|
expected.push(
|
||||||
|
Reject,
|
||||||
|
AddressPortPattern {
|
||||||
|
ip_pattern: IpPattern::Star,
|
||||||
|
ports: PortRange::new_zero(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// ExitPolicy reject *4:0
|
||||||
|
expected.push(
|
||||||
|
Reject,
|
||||||
|
AddressPortPattern {
|
||||||
|
ip_pattern: IpPattern::V4Star,
|
||||||
|
ports: PortRange::new_zero(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
// ExitPolicy reject *6:0
|
||||||
|
expected.push(
|
||||||
|
Reject,
|
||||||
|
AddressPortPattern {
|
||||||
|
ip_pattern: IpPattern::V6Star,
|
||||||
|
ports: PortRange::new_zero(),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// ExitPolicy FE80:0000:0000:0000:0202:B3FF:FE1E:8329:*
|
// ExitPolicy FE80:0000:0000:0000:0202:B3FF:FE1E:8329:*
|
||||||
expected.push(
|
expected.push(
|
||||||
Reject,
|
Reject,
|
||||||
|
|||||||
@@ -264,7 +264,13 @@ mod stringified_ip_pattern {
|
|||||||
impl AddressPortPattern {
|
impl AddressPortPattern {
|
||||||
/// Return true iff this pattern matches a given address and port.
|
/// Return true iff this pattern matches a given address and port.
|
||||||
pub fn matches(&self, addr: &IpAddr, port: u16) -> bool {
|
pub fn matches(&self, addr: &IpAddr, port: u16) -> bool {
|
||||||
self.ip_pattern.matches(addr) && self.ports.contains(port)
|
// For backward compatibility, we treat port 0 as a wildcard until all gateways have
|
||||||
|
// upgraded, at which point we can add *:0 to the policy list.
|
||||||
|
if port == 0 {
|
||||||
|
self.ip_pattern.matches(addr)
|
||||||
|
} else {
|
||||||
|
self.ip_pattern.matches(addr) && self.ports.contains(port)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// As matches, but accept a SocketAddr.
|
/// As matches, but accept a SocketAddr.
|
||||||
@@ -395,19 +401,9 @@ fn parse_addr(s: &str) -> Result<IpAddr, PolicyError> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper: try to parse a port making sure it's non-zero
|
|
||||||
fn parse_port(s: &str) -> Result<u16, PolicyError> {
|
fn parse_port(s: &str) -> Result<u16, PolicyError> {
|
||||||
let port = s
|
s.parse::<u16>()
|
||||||
.parse::<u16>()
|
.map_err(|_| PolicyError::InvalidPort { raw: s.to_string() })
|
||||||
.map_err(|_| PolicyError::InvalidPort { raw: s.to_string() })?;
|
|
||||||
|
|
||||||
if port == 0 {
|
|
||||||
Err(PolicyError::InvalidPort {
|
|
||||||
raw: port.to_string(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(port)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromStr for IpPattern {
|
impl FromStr for IpPattern {
|
||||||
@@ -494,6 +490,10 @@ impl PortRange {
|
|||||||
PortRange::new_unchecked(1, 65535)
|
PortRange::new_unchecked(1, 65535)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_zero() -> Self {
|
||||||
|
PortRange { start: 0, end: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
/// Create a new PortRange.
|
/// Create a new PortRange.
|
||||||
///
|
///
|
||||||
/// The Portrange contains all ports between `start` and `end` inclusive.
|
/// The Portrange contains all ports between `start` and `end` inclusive.
|
||||||
@@ -574,6 +574,7 @@ mod test {
|
|||||||
|
|
||||||
check("marzipan:80");
|
check("marzipan:80");
|
||||||
check("1.2.3.4:90-80");
|
check("1.2.3.4:90-80");
|
||||||
|
check("1.2.3.4:0-80");
|
||||||
check("1.2.3.4/100:8888");
|
check("1.2.3.4/100:8888");
|
||||||
check("[1.2.3.4]/16:80");
|
check("[1.2.3.4]/16:80");
|
||||||
check("[::1]/130:8888");
|
check("[::1]/130:8888");
|
||||||
@@ -612,6 +613,22 @@ mod test {
|
|||||||
|
|
||||||
check("0.0.0.0/0:*", &["127.0.0.1:80"], &["[f00b::]:80"]);
|
check("0.0.0.0/0:*", &["127.0.0.1:80"], &["[f00b::]:80"]);
|
||||||
check("[::]/0:*", &["[f00b::]:80"], &["127.0.0.1:80"]);
|
check("[::]/0:*", &["[f00b::]:80"], &["127.0.0.1:80"]);
|
||||||
|
|
||||||
|
check(
|
||||||
|
"*:0",
|
||||||
|
&["1.2.3.4:0", "[::1]:0", "9.0.0.0:0"],
|
||||||
|
&["1.2.3.4:443", "[::1]:500", "9.0.0.0:80", "[::1]:80"],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
"*4:0",
|
||||||
|
&["1.2.3.4:0", "9.0.0.0:0"],
|
||||||
|
&["1.2.3.4:443", "9.0.0.0:80", "[::1]:0", "[::1]:80"],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
"*6:0",
|
||||||
|
&["[::1]:0"],
|
||||||
|
&["[::1]:80", "1.2.3.4:0", "1.2.3.4:443"],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -620,6 +637,7 @@ mod test {
|
|||||||
policy.push(AddressPolicyAction::Accept, "*:443".parse()?);
|
policy.push(AddressPolicyAction::Accept, "*:443".parse()?);
|
||||||
policy.push(AddressPolicyAction::Accept, "[::1]:80".parse()?);
|
policy.push(AddressPolicyAction::Accept, "[::1]:80".parse()?);
|
||||||
policy.push(AddressPolicyAction::Reject, "*:80".parse()?);
|
policy.push(AddressPolicyAction::Reject, "*:80".parse()?);
|
||||||
|
policy.push(AddressPolicyAction::Accept, "*:0".parse()?);
|
||||||
|
|
||||||
let policy = policy; // drop mut
|
let policy = policy; // drop mut
|
||||||
assert!(policy
|
assert!(policy
|
||||||
@@ -640,6 +658,9 @@ mod test {
|
|||||||
assert!(policy
|
assert!(policy
|
||||||
.allows_sockaddr(&"127.0.0.1:66".parse().unwrap())
|
.allows_sockaddr(&"127.0.0.1:66".parse().unwrap())
|
||||||
.is_none());
|
.is_none());
|
||||||
|
assert!(policy
|
||||||
|
.allows_sockaddr(&"127.0.0.1:0".parse().unwrap())
|
||||||
|
.unwrap());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -672,7 +693,6 @@ mod test {
|
|||||||
assert_eq!("*".parse::<PortRange>().unwrap(), PortRange::new_all());
|
assert_eq!("*".parse::<PortRange>().unwrap(), PortRange::new_all());
|
||||||
|
|
||||||
assert!("hello".parse::<PortRange>().is_err());
|
assert!("hello".parse::<PortRange>().is_err());
|
||||||
assert!("0".parse::<PortRange>().is_err());
|
|
||||||
assert!("65536".parse::<PortRange>().is_err());
|
assert!("65536".parse::<PortRange>().is_err());
|
||||||
assert!("65537".parse::<PortRange>().is_err());
|
assert!("65537".parse::<PortRange>().is_err());
|
||||||
assert!("1-2-3".parse::<PortRange>().is_err());
|
assert!("1-2-3".parse::<PortRange>().is_err());
|
||||||
@@ -680,6 +700,9 @@ mod test {
|
|||||||
assert!("1-".parse::<PortRange>().is_err());
|
assert!("1-".parse::<PortRange>().is_err());
|
||||||
assert!("-2".parse::<PortRange>().is_err());
|
assert!("-2".parse::<PortRange>().is_err());
|
||||||
assert!("-".parse::<PortRange>().is_err());
|
assert!("-".parse::<PortRange>().is_err());
|
||||||
|
|
||||||
|
assert_eq!("0".parse::<PortRange>().unwrap(), PortRange::new_zero(),);
|
||||||
|
assert!("0-1".parse::<PortRange>().is_err());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -22,4 +22,5 @@ log.workspace = true
|
|||||||
nym-network-defaults = { path = "../network-defaults" }
|
nym-network-defaults = { path = "../network-defaults" }
|
||||||
nym-task = { path = "../task" }
|
nym-task = { path = "../task" }
|
||||||
nym-wireguard-types = { path = "../wireguard-types" }
|
nym-wireguard-types = { path = "../wireguard-types" }
|
||||||
|
serde = { workspace = true, features = ["derive"] }
|
||||||
tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util"] }
|
tokio = { workspace = true, features = ["rt-multi-thread", "net", "io-util"] }
|
||||||
|
|||||||
+10
-11
@@ -9,13 +9,12 @@ use nym_wireguard_types::registration::GatewayClientRegistry;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
// Currently the module related to setting up the virtual network device is platform specific.
|
// Currently the module related to setting up the virtual network device is platform specific.
|
||||||
|
use crate::setup::PeerPair;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use crate::setup::{peer_allowed_ips, peer_static_public_key, PRIVATE_KEY};
|
use crate::setup::{peer_static_pairs, PRIVATE_KEY};
|
||||||
use defguard_wireguard_rs::WGApi;
|
use defguard_wireguard_rs::WGApi;
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use defguard_wireguard_rs::{
|
use defguard_wireguard_rs::{InterfaceConfiguration, WireguardInterfaceApi};
|
||||||
host::Peer, key::Key, net::IpAddrMask, InterfaceConfiguration, WireguardInterfaceApi,
|
|
||||||
};
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
use nym_network_defaults::{WG_PORT, WG_TUN_DEVICE_ADDRESS};
|
use nym_network_defaults::{WG_PORT, WG_TUN_DEVICE_ADDRESS};
|
||||||
|
|
||||||
@@ -24,6 +23,7 @@ use nym_network_defaults::{WG_PORT, WG_TUN_DEVICE_ADDRESS};
|
|||||||
pub async fn start_wireguard(
|
pub async fn start_wireguard(
|
||||||
mut task_client: nym_task::TaskClient,
|
mut task_client: nym_task::TaskClient,
|
||||||
_gateway_client_registry: Arc<GatewayClientRegistry>,
|
_gateway_client_registry: Arc<GatewayClientRegistry>,
|
||||||
|
peer_pairs: Vec<PeerPair>,
|
||||||
) -> Result<WGApi, Box<dyn std::error::Error + Send + Sync + 'static>> {
|
) -> Result<WGApi, Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||||
let ifname = String::from("wg0");
|
let ifname = String::from("wg0");
|
||||||
let wgapi = WGApi::new(ifname.clone(), false)?;
|
let wgapi = WGApi::new(ifname.clone(), false)?;
|
||||||
@@ -36,13 +36,11 @@ pub async fn start_wireguard(
|
|||||||
peers: vec![],
|
peers: vec![],
|
||||||
};
|
};
|
||||||
wgapi.configure_interface(&interface_config)?;
|
wgapi.configure_interface(&interface_config)?;
|
||||||
let peer = peer_static_public_key();
|
let peers = peer_static_pairs(peer_pairs);
|
||||||
let mut peer = Peer::new(Key::new(peer.to_bytes()));
|
for peer in peers.iter() {
|
||||||
let peer_ip = peer_allowed_ips();
|
wgapi.configure_peer(peer)?;
|
||||||
let peer_ip_mask = IpAddrMask::new(peer_ip.network_address(), peer_ip.netmask());
|
}
|
||||||
peer.set_allowed_ips(vec![peer_ip_mask]);
|
wgapi.configure_peer_routing(&peers)?;
|
||||||
wgapi.configure_peer(&peer)?;
|
|
||||||
wgapi.configure_peer_routing(&[peer.clone()])?;
|
|
||||||
|
|
||||||
tokio::spawn(async move { task_client.recv().await });
|
tokio::spawn(async move { task_client.recv().await });
|
||||||
|
|
||||||
@@ -52,6 +50,7 @@ pub async fn start_wireguard(
|
|||||||
pub async fn start_wireguard(
|
pub async fn start_wireguard(
|
||||||
_task_client: nym_task::TaskClient,
|
_task_client: nym_task::TaskClient,
|
||||||
_gateway_client_registry: Arc<GatewayClientRegistry>,
|
_gateway_client_registry: Arc<GatewayClientRegistry>,
|
||||||
|
_peer_pairs: Vec<PeerPair>,
|
||||||
) -> Result<WGApi, Box<dyn std::error::Error + Send + Sync + 'static>> {
|
) -> Result<WGApi, Box<dyn std::error::Error + Send + Sync + 'static>> {
|
||||||
todo!("WireGuard is currently only supported on Linux")
|
todo!("WireGuard is currently only supported on Linux")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
use std::net::IpAddr;
|
use std::net::IpAddr;
|
||||||
|
|
||||||
use base64::{engine::general_purpose, Engine as _};
|
use base64::{engine::general_purpose, Engine as _};
|
||||||
use log::info;
|
use defguard_wireguard_rs::host::Peer;
|
||||||
|
use defguard_wireguard_rs::key::Key;
|
||||||
|
use defguard_wireguard_rs::net::IpAddrMask;
|
||||||
|
use log::{info, warn};
|
||||||
|
use serde::Deserialize;
|
||||||
|
|
||||||
// The wireguard UDP listener
|
// The wireguard UDP listener
|
||||||
pub const WG_ADDRESS: &str = "0.0.0.0";
|
pub const WG_ADDRESS: &str = "0.0.0.0";
|
||||||
@@ -10,21 +14,23 @@ pub const WG_ADDRESS: &str = "0.0.0.0";
|
|||||||
// Corresponding public key: "WM8s8bYegwMa0TJ+xIwhk+dImk2IpDUKslDBCZPizlE="
|
// Corresponding public key: "WM8s8bYegwMa0TJ+xIwhk+dImk2IpDUKslDBCZPizlE="
|
||||||
pub(crate) const PRIVATE_KEY: &str = "AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=";
|
pub(crate) const PRIVATE_KEY: &str = "AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=";
|
||||||
|
|
||||||
// The AllowedIPs for the connected peer, which is one a single IP and the same as the IP that the
|
#[derive(Deserialize, Debug)]
|
||||||
// peer has configured on their side.
|
pub struct PeerPair {
|
||||||
const ALLOWED_IPS: &str = "10.1.0.2";
|
pub addr: String,
|
||||||
|
pub public_key: String,
|
||||||
|
}
|
||||||
|
|
||||||
fn decode_base64_key(base64_key: &str) -> [u8; 32] {
|
fn decode_base64_key(base64_key: &str) -> Result<[u8; 32], String> {
|
||||||
general_purpose::STANDARD
|
general_purpose::STANDARD
|
||||||
.decode(base64_key)
|
.decode(base64_key)
|
||||||
.unwrap()
|
.map_err(|_| String::from("Could not decode"))?
|
||||||
.try_into()
|
.try_into()
|
||||||
.unwrap()
|
.map_err(|_| String::from("Not enough bytes"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn server_static_private_key() -> x25519_dalek::StaticSecret {
|
pub fn server_static_private_key() -> x25519_dalek::StaticSecret {
|
||||||
// TODO: this is a temporary solution for development
|
// TODO: this is a temporary solution for development
|
||||||
let static_private_bytes: [u8; 32] = decode_base64_key(PRIVATE_KEY);
|
let static_private_bytes: [u8; 32] = decode_base64_key(PRIVATE_KEY).unwrap();
|
||||||
let static_private = x25519_dalek::StaticSecret::from(static_private_bytes);
|
let static_private = x25519_dalek::StaticSecret::from(static_private_bytes);
|
||||||
let static_public = x25519_dalek::PublicKey::from(&static_private);
|
let static_public = x25519_dalek::PublicKey::from(&static_private);
|
||||||
info!(
|
info!(
|
||||||
@@ -34,23 +40,29 @@ pub fn server_static_private_key() -> x25519_dalek::StaticSecret {
|
|||||||
static_private
|
static_private
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn peer_static_public_key() -> x25519_dalek::PublicKey {
|
pub fn peer_static_pairs(raw_pairs: Vec<PeerPair>) -> Vec<Peer> {
|
||||||
// A single static public key is used during development
|
raw_pairs
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|pair| {
|
||||||
|
if let Ok(peer_static_public_bytes) = decode_base64_key(&pair.public_key) {
|
||||||
|
let peer_static_public = x25519_dalek::PublicKey::from(peer_static_public_bytes);
|
||||||
|
let mut peer = Peer::new(Key::new(peer_static_public.to_bytes()));
|
||||||
|
|
||||||
// Read from NYM_PEER_PUBLIC_KEY env variable
|
if let Ok(key) = pair.addr.parse::<IpAddr>() {
|
||||||
let peer = std::env::var("NYM_PEER_PUBLIC_KEY").expect("NYM_PEER_PUBLIC_KEY must be set");
|
let peer_ip = ip_network::IpNetwork::new_truncate(key, 32u8)
|
||||||
|
.expect("Netmask should be correct");
|
||||||
let peer_static_public_bytes: [u8; 32] = decode_base64_key(&peer);
|
let peer_ip_mask =
|
||||||
let peer_static_public = x25519_dalek::PublicKey::from(peer_static_public_bytes);
|
IpAddrMask::new(peer_ip.network_address(), peer_ip.netmask());
|
||||||
info!(
|
peer.set_allowed_ips(vec![peer_ip_mask]);
|
||||||
"Adding wg peer public key: {}",
|
Some(peer)
|
||||||
general_purpose::STANDARD.encode(peer_static_public)
|
} else {
|
||||||
);
|
warn!("Not adding {:?} as IP doesn't parse", pair);
|
||||||
peer_static_public
|
None
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
pub fn peer_allowed_ips() -> ip_network::IpNetwork {
|
warn!("Not adding {:?} as public key doesn't decode", pair);
|
||||||
let key: IpAddr = ALLOWED_IPS.parse().unwrap();
|
None
|
||||||
let cidr = 32u8;
|
}
|
||||||
ip_network::IpNetwork::new_truncate(key, cidr).unwrap()
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,6 +242,11 @@ impl Config {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_client_keys_path(mut self, client_keys: PathBuf) -> Self {
|
||||||
|
self.wireguard.storage_paths.client_keys = client_keys;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_listening_address(mut self, listening_address: IpAddr) -> Self {
|
pub fn with_listening_address(mut self, listening_address: IpAddr) -> Self {
|
||||||
self.gateway.listening_address = listening_address;
|
self.gateway.listening_address = listening_address;
|
||||||
|
|
||||||
|
|||||||
@@ -130,7 +130,7 @@ impl From<ConfigV1_1_31> for Config {
|
|||||||
announced_port: value.wireguard.announced_port,
|
announced_port: value.wireguard.announced_port,
|
||||||
private_network_prefix: Default::default(),
|
private_network_prefix: Default::default(),
|
||||||
storage_paths: nym_node::config::persistence::WireguardPaths {
|
storage_paths: nym_node::config::persistence::WireguardPaths {
|
||||||
// no fields (yet)
|
client_keys: Default::default(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
storage_paths: GatewayPaths {
|
storage_paths: GatewayPaths {
|
||||||
|
|||||||
@@ -207,7 +207,10 @@ impl<St> Gateway<St> {
|
|||||||
&self,
|
&self,
|
||||||
shutdown: TaskClient,
|
shutdown: TaskClient,
|
||||||
) -> Result<WGApi, Box<dyn Error + Send + Sync>> {
|
) -> Result<WGApi, Box<dyn Error + Send + Sync>> {
|
||||||
nym_wireguard::start_wireguard(shutdown, Arc::clone(&self.client_registry)).await
|
let file = std::fs::File::open(&self.config.wireguard.storage_paths.client_keys)?;
|
||||||
|
let reader = std::io::BufReader::new(file);
|
||||||
|
let peers = serde_json::from_reader(reader)?;
|
||||||
|
nym_wireguard::start_wireguard(shutdown, Arc::clone(&self.client_registry), peers).await
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_client_websocket_listener(
|
fn start_client_websocket_listener(
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ impl PacketPreparer {
|
|||||||
let initialisation_backoff = Duration::from_secs(30);
|
let initialisation_backoff = Duration::from_secs(30);
|
||||||
loop {
|
loop {
|
||||||
let gateways = self.validator_cache.gateways_all().await;
|
let gateways = self.validator_cache.gateways_all().await;
|
||||||
let mixnodes = self.validator_cache.mixnodes_basic().await;
|
let mixnodes = self.validator_cache.mixnodes_all_basic().await;
|
||||||
|
|
||||||
if gateways.len() < minimum_full_routes {
|
if gateways.len() < minimum_full_routes {
|
||||||
self.topology_wait_backoff(initialisation_backoff).await;
|
self.topology_wait_backoff(initialisation_backoff).await;
|
||||||
@@ -179,12 +179,21 @@ impl PacketPreparer {
|
|||||||
async fn all_mixnodes_and_gateways(&self) -> (Vec<MixNodeBond>, Vec<GatewayBond>) {
|
async fn all_mixnodes_and_gateways(&self) -> (Vec<MixNodeBond>, Vec<GatewayBond>) {
|
||||||
info!("Obtaining network topology...");
|
info!("Obtaining network topology...");
|
||||||
|
|
||||||
let mixnodes = self.validator_cache.mixnodes_basic().await;
|
let mixnodes = self.validator_cache.mixnodes_all_basic().await;
|
||||||
let gateways = self.validator_cache.gateways_all().await;
|
let gateways = self.validator_cache.gateways_all().await;
|
||||||
|
|
||||||
(mixnodes, gateways)
|
(mixnodes, gateways)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn filtered_mixnodes_and_gateways(&self) -> (Vec<MixNodeBond>, Vec<GatewayBond>) {
|
||||||
|
info!("Obtaining network topology...");
|
||||||
|
|
||||||
|
let mixnodes = self.validator_cache.mixnodes_filtered_basic().await;
|
||||||
|
let gateways = self.validator_cache.gateways_filtered().await;
|
||||||
|
|
||||||
|
(mixnodes, gateways)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn try_parse_mix_bond(&self, mix: &MixNodeBond) -> Result<mix::Node, String> {
|
pub(crate) fn try_parse_mix_bond(&self, mix: &MixNodeBond) -> Result<mix::Node, String> {
|
||||||
let identity = mix.mix_node.identity_key.clone();
|
let identity = mix.mix_node.identity_key.clone();
|
||||||
mix.try_into().map_err(|_| identity)
|
mix.try_into().map_err(|_| identity)
|
||||||
@@ -208,7 +217,7 @@ impl PacketPreparer {
|
|||||||
n: usize,
|
n: usize,
|
||||||
blacklist: &mut HashSet<String>,
|
blacklist: &mut HashSet<String>,
|
||||||
) -> Option<Vec<TestRoute>> {
|
) -> Option<Vec<TestRoute>> {
|
||||||
let (mixnodes, gateways) = self.all_mixnodes_and_gateways().await;
|
let (mixnodes, gateways) = self.filtered_mixnodes_and_gateways().await;
|
||||||
// separate mixes into layers for easier selection
|
// separate mixes into layers for easier selection
|
||||||
let mut layered_mixes = HashMap::new();
|
let mut layered_mixes = HashMap::new();
|
||||||
for mix in mixnodes {
|
for mix in mixnodes {
|
||||||
|
|||||||
+14
-13
@@ -182,19 +182,20 @@ impl NymContractCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn mixnodes_basic(&self) -> Vec<MixNodeBond> {
|
pub async fn mixnodes_filtered_basic(&self) -> Vec<MixNodeBond> {
|
||||||
match time::timeout(Duration::from_millis(100), self.inner.read()).await {
|
self.mixnodes_filtered()
|
||||||
Ok(cache) => cache
|
.await
|
||||||
.mixnodes
|
.into_iter()
|
||||||
.clone()
|
.map(|bond| bond.bond_information)
|
||||||
.into_iter()
|
.collect()
|
||||||
.map(|bond| bond.bond_information)
|
}
|
||||||
.collect(),
|
|
||||||
Err(err) => {
|
pub async fn mixnodes_all_basic(&self) -> Vec<MixNodeBond> {
|
||||||
error!("{err}");
|
self.mixnodes_all()
|
||||||
Vec::new()
|
.await
|
||||||
}
|
.into_iter()
|
||||||
}
|
.map(|bond| bond.bond_information)
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn gateways_filtered(&self) -> Vec<GatewayBond> {
|
pub async fn gateways_filtered(&self) -> Vec<GatewayBond> {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ pub(crate) fn nym_contract_cache_routes(settings: &OpenApiSettings) -> (Vec<Rout
|
|||||||
settings: routes::get_mixnodes,
|
settings: routes::get_mixnodes,
|
||||||
routes::get_mixnodes_detailed,
|
routes::get_mixnodes_detailed,
|
||||||
routes::get_gateways,
|
routes::get_gateways,
|
||||||
|
routes::get_all_gateways,
|
||||||
routes::get_active_set,
|
routes::get_active_set,
|
||||||
routes::get_active_set_detailed,
|
routes::get_active_set_detailed,
|
||||||
routes::get_rewarded_set,
|
routes::get_rewarded_set,
|
||||||
|
|||||||
@@ -114,6 +114,12 @@ pub async fn get_blacklisted_gateways(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[openapi(tag = "contract-cache")]
|
||||||
|
#[get("/gateways/all")]
|
||||||
|
pub async fn get_all_gateways(cache: &State<NymContractCache>) -> Json<Vec<GatewayBond>> {
|
||||||
|
Json(cache.gateways_all().await.clone())
|
||||||
|
}
|
||||||
|
|
||||||
#[openapi(tag = "contract-cache")]
|
#[openapi(tag = "contract-cache")]
|
||||||
#[get("/epoch/reward_params")]
|
#[get("/epoch/reward_params")]
|
||||||
pub async fn get_interval_reward_params(
|
pub async fn get_interval_reward_params(
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ impl StorageManager {
|
|||||||
r#"
|
r#"
|
||||||
SELECT
|
SELECT
|
||||||
d.identity as "identity: String",
|
d.identity as "identity: String",
|
||||||
AVG(reliability) as "value: f32"
|
CASE WHEN count(*) > 3 THEN AVG(reliability) ELSE 100 END as "value: f32"
|
||||||
FROM
|
FROM
|
||||||
gateway_details d
|
gateway_details d
|
||||||
JOIN
|
JOIN
|
||||||
|
|||||||
@@ -93,7 +93,9 @@ impl Default for Wireguard {
|
|||||||
),
|
),
|
||||||
announced_port: DEFAULT_WIREGUARD_PORT,
|
announced_port: DEFAULT_WIREGUARD_PORT,
|
||||||
private_network_prefix: DEFAULT_WIREGUARD_PREFIX,
|
private_network_prefix: DEFAULT_WIREGUARD_PREFIX,
|
||||||
storage_paths: persistence::WireguardPaths {},
|
storage_paths: persistence::WireguardPaths {
|
||||||
|
client_keys: PathBuf::from("/root/keys_pub.json"),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
#[derive(Debug, Clone, Deserialize, PartialEq, Eq, Serialize)]
|
||||||
#[serde(deny_unknown_fields)]
|
#[serde(deny_unknown_fields)]
|
||||||
pub struct WireguardPaths {
|
pub struct WireguardPaths {
|
||||||
// pub keys:
|
pub client_keys: PathBuf,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ impl MyTopologyProvider {
|
|||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let gateways = self.validator_client.get_cached_gateways().await.unwrap();
|
let gateways = self.validator_client.get_all_gateways().await.unwrap();
|
||||||
|
|
||||||
nym_topology_from_detailed(filtered_mixnodes, gateways)
|
nym_topology_from_detailed(filtered_mixnodes, gateways)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use std::net::SocketAddr;
|
use std::net::{IpAddr, SocketAddr};
|
||||||
|
|
||||||
pub use nym_client_core::error::ClientCoreError;
|
pub use nym_client_core::error::ClientCoreError;
|
||||||
use nym_exit_policy::PolicyError;
|
use nym_exit_policy::PolicyError;
|
||||||
@@ -57,9 +57,15 @@ 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}'")]
|
#[error("failed filter check: '{addr}'")]
|
||||||
AddressFailedFilterCheck { addr: SocketAddr },
|
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]
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use std::{collections::HashMap, net::IpAddr};
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
net::{IpAddr, SocketAddr},
|
||||||
|
};
|
||||||
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use nym_ip_packet_requests::{
|
use nym_ip_packet_requests::{
|
||||||
@@ -320,15 +323,11 @@ impl MixnetListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Filter check
|
// Filter check
|
||||||
if let Some(dst) = dst {
|
let dst = dst.unwrap_or_else(|| SocketAddr::new(dst_addr, 0));
|
||||||
if !self.request_filter.check_address(&dst).await {
|
if !self.request_filter.check_address(&dst).await {
|
||||||
log::warn!("Failed filter check: {dst}");
|
log::info!("Denied filter check: {dst}");
|
||||||
// TODO: we could consider sending back a response here
|
// TODO: we could consider sending back a response here
|
||||||
return Err(IpPacketRouterError::AddressFailedFilterCheck { addr: dst });
|
return Err(IpPacketRouterError::AddressFailedFilterCheck { addr: dst });
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: we should also filter packets without port number
|
|
||||||
log::warn!("Ignoring filter check for packet without port number! TODO!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider changing from Vec<u8> to bytes::Bytes?
|
// TODO: consider changing from Vec<u8> to bytes::Bytes?
|
||||||
|
|||||||
Reference in New Issue
Block a user