Wireguard listener (#3868)

* wip

* wip

* Most channels are in place

* tidy

* Send data to tunnel

* wip: adding in boringtun

* Handle timers

* Add consume_wg

* Split into mod

* Reorder

* Comments

* Refine channel handling

* Sort out dependency conflict

* Move wireguard listener in gateway beind a feature flag
This commit is contained in:
Jon Häggblad
2023-09-12 14:14:46 +02:00
committed by GitHub
parent b07627d57e
commit 96b54db060
9 changed files with 558 additions and 54 deletions
Generated
+141 -53
View File
@@ -36,7 +36,7 @@ dependencies = [
"actix-service",
"actix-utils",
"ahash 0.8.3",
"base64 0.21.2",
"base64 0.21.4",
"bitflags 1.3.2",
"brotli",
"bytes",
@@ -631,6 +631,17 @@ dependencies = [
"event-listener",
]
[[package]]
name = "async-recursion"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.28",
]
[[package]]
name = "async-stream"
version = "0.3.5"
@@ -819,9 +830,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]]
name = "base64"
version = "0.21.2"
version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2"
[[package]]
name = "base64ct"
@@ -1030,6 +1041,29 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "845141a4fade3f790628b7daaaa298a25b204fb28907eb54febe5142db6ce653"
[[package]]
name = "boringtun"
version = "0.6.0"
source = "git+https://github.com/cloudflare/boringtun?rev=e1d6360d6ab4529fc942a078e4c54df107abe2ba#e1d6360d6ab4529fc942a078e4c54df107abe2ba"
dependencies = [
"aead 0.5.2",
"base64 0.13.1",
"blake2 0.10.6",
"chacha20poly1305 0.10.1",
"hex",
"hmac 0.12.1",
"ip_network",
"ip_network_table",
"libc",
"nix 0.25.1",
"parking_lot 0.12.1",
"rand_core 0.6.4",
"ring",
"tracing",
"untrusted 0.9.0",
"x25519-dalek 2.0.0",
]
[[package]]
name = "brotli"
version = "3.3.4"
@@ -1096,9 +1130,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.4.0"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
dependencies = [
"serde",
]
@@ -2107,18 +2141,31 @@ dependencies = [
[[package]]
name = "curve25519-dalek"
version = "4.0.0-rc.1"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8d4ba9852b42210c7538b75484f9daa0655e9a3ac04f693747bb0f02cf3cfe16"
checksum = "622178105f911d937a42cdb140730ba4a3ed2becd8ae6ce39c7d28b5d75d4588"
dependencies = [
"cfg-if",
"cpufeatures",
"curve25519-dalek-derive",
"fiat-crypto",
"packed_simd_2",
"platforms",
"rustc_version 0.4.0",
"subtle 2.4.1",
"zeroize",
]
[[package]]
name = "curve25519-dalek-derive"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fdaf97f4804dcebfa5862639bc9ce4121e82140bec2a987ac5140294865b5b"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.28",
]
[[package]]
name = "curve25519-dalek-ng"
version = "4.1.1"
@@ -3085,9 +3132,9 @@ dependencies = [
[[package]]
name = "fiat-crypto"
version = "0.1.20"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77"
checksum = "d0870c84016d4b481be5c9f323c24f65e31e901ae618f0e80f4308fb00de1d2d"
[[package]]
name = "figment"
@@ -4214,6 +4261,28 @@ dependencies = [
"windows-sys 0.48.0",
]
[[package]]
name = "ip_network"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa2f047c0a98b2f299aa5d6d7088443570faae494e9ae1305e48be000c9e0eb1"
[[package]]
name = "ip_network_table"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4099b7cfc5c5e2fe8c5edf3f6f7adf7a714c9cc697534f63a5a5da30397cb2c0"
dependencies = [
"ip_network",
"ip_network_table-deps-treebitmap",
]
[[package]]
name = "ip_network_table-deps-treebitmap"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e537132deb99c0eb4b752f0346b6a836200eaaa3516dd7e5514b63930a09e5d"
[[package]]
name = "ipconfig"
version = "0.3.1"
@@ -4508,12 +4577,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "libm"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
[[package]]
name = "libm"
version = "0.2.7"
@@ -4699,7 +4762,7 @@ version = "0.44.0"
source = "git+https://github.com/ChainSafe/rust-libp2p.git?rev=e3440d25681df380c9f0f8cfdcfd5ecc0a4f2fb6#e3440d25681df380c9f0f8cfdcfd5ecc0a4f2fb6"
dependencies = [
"asynchronous-codec",
"base64 0.21.2",
"base64 0.21.4",
"byteorder",
"bytes",
"fnv",
@@ -4729,7 +4792,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70b34b6da8165c0bde35c82db8efda39b824776537e73973549e76cadb3a77c5"
dependencies = [
"asynchronous-codec",
"base64 0.21.2",
"base64 0.21.4",
"byteorder",
"bytes",
"either",
@@ -5806,6 +5869,18 @@ dependencies = [
"memoffset 0.6.5",
]
[[package]]
name = "nix"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
dependencies = [
"autocfg 1.1.0",
"bitflags 1.3.2",
"cfg-if",
"libc",
]
[[package]]
name = "no-std-compat"
version = "0.4.1"
@@ -5913,7 +5988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
dependencies = [
"autocfg 1.1.0",
"libm 0.2.7",
"libm",
]
[[package]]
@@ -6187,7 +6262,7 @@ name = "nym-client-core"
version = "1.1.15"
dependencies = [
"async-trait",
"base64 0.21.2",
"base64 0.21.4",
"cfg-if",
"dashmap 5.5.0",
"dirs 4.0.0",
@@ -6510,6 +6585,7 @@ dependencies = [
"nym-task",
"nym-types",
"nym-validator-client",
"nym-wireguard",
"once_cell",
"pretty_env_logger",
"rand 0.7.3",
@@ -7442,6 +7518,21 @@ dependencies = [
"nym-node-tester-wasm",
]
[[package]]
name = "nym-wireguard"
version = "0.1.0"
dependencies = [
"async-recursion",
"base64 0.21.4",
"boringtun",
"bytes",
"futures",
"log",
"nym-task",
"tap",
"tokio",
]
[[package]]
name = "object"
version = "0.31.1"
@@ -7698,16 +7789,6 @@ dependencies = [
"sha2 0.10.7",
]
[[package]]
name = "packed_simd_2"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1914cd452d8fccd6f9db48147b29fd4ae05bea9dc5d9ad578509f72415de282"
dependencies = [
"cfg-if",
"libm 0.1.4",
]
[[package]]
name = "pairing"
version = "0.20.0"
@@ -8224,13 +8305,13 @@ dependencies = [
[[package]]
name = "prometheus-client-derive-encode"
version = "0.4.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b6a5217beb0ad503ee7fa752d451c905113d70721b937126158f3106a48cc1"
checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8"
dependencies = [
"proc-macro2",
"quote",
"syn 1.0.109",
"syn 2.0.28",
]
[[package]]
@@ -8792,7 +8873,7 @@ version = "0.11.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
dependencies = [
"base64 0.21.2",
"base64 0.21.4",
"bytes",
"encoding_rs",
"futures-core",
@@ -8865,7 +8946,7 @@ dependencies = [
"libc",
"once_cell",
"spin 0.5.2",
"untrusted",
"untrusted 0.7.1",
"web-sys",
"winapi",
]
@@ -9036,7 +9117,7 @@ dependencies = [
"log",
"netlink-packet-route",
"netlink-proto",
"nix",
"nix 0.24.3",
"thiserror",
"tokio",
]
@@ -9226,7 +9307,7 @@ version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
dependencies = [
"base64 0.21.2",
"base64 0.21.4",
]
[[package]]
@@ -9236,7 +9317,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e98ff011474fa39949b7e5c0428f9b4937eda7da7848bbb947786b7be0b27dab"
dependencies = [
"ring",
"untrusted",
"untrusted 0.7.1",
]
[[package]]
@@ -9246,7 +9327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7d93931baf2d282fff8d3a532bbfd7653f734643161b87e3e01e59a04439bf0d"
dependencies = [
"ring",
"untrusted",
"untrusted 0.7.1",
]
[[package]]
@@ -9374,7 +9455,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce"
dependencies = [
"ring",
"untrusted",
"untrusted 0.7.1",
]
[[package]]
@@ -9384,7 +9465,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
dependencies = [
"ring",
"untrusted",
"untrusted 0.7.1",
]
[[package]]
@@ -9828,14 +9909,14 @@ dependencies = [
[[package]]
name = "snow"
version = "0.9.2"
version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ccba027ba85743e09d15c03296797cad56395089b832b48b5a5217880f57733"
checksum = "0c9d1425eb528a21de2755c75af4c9b5d57f50a0d4c3b7f1828a4cd03f8ba155"
dependencies = [
"aes-gcm 0.9.4",
"blake2 0.10.6",
"chacha20poly1305 0.9.1",
"curve25519-dalek 4.0.0-rc.1",
"curve25519-dalek 4.1.0",
"rand_core 0.6.4",
"ring",
"rustc_version 0.4.0",
@@ -10874,7 +10955,7 @@ checksum = "3082666a3a6433f7f511c7192923fa1fe07c69332d3c6a2e6bb040b569199d5a"
dependencies = [
"async-trait",
"axum",
"base64 0.21.2",
"base64 0.21.4",
"bytes",
"futures-core",
"futures-util",
@@ -11400,6 +11481,12 @@ version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
[[package]]
name = "untrusted"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
[[package]]
name = "unwind_safe"
version = "0.1.0"
@@ -11412,7 +11499,7 @@ version = "2.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b11c96ac7ee530603dcdf68ed1557050f374ce55a5a07193ebf8cbc9f8927e9"
dependencies = [
"base64 0.21.2",
"base64 0.21.4",
"log",
"native-tls",
"once_cell",
@@ -11805,7 +11892,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
dependencies = [
"ring",
"untrusted",
"untrusted 0.7.1",
]
[[package]]
@@ -11815,7 +11902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
dependencies = [
"ring",
"untrusted",
"untrusted 0.7.1",
]
[[package]]
@@ -11938,7 +12025,7 @@ dependencies = [
"tokio",
"webpki 0.21.4",
"webrtc-util",
"x25519-dalek 2.0.0-pre.1",
"x25519-dalek 2.0.0",
"x509-parser 0.13.2",
]
@@ -12047,7 +12134,7 @@ dependencies = [
"lazy_static",
"libc",
"log",
"nix",
"nix 0.24.3",
"rand 0.8.5",
"thiserror",
"tokio",
@@ -12347,12 +12434,13 @@ dependencies = [
[[package]]
name = "x25519-dalek"
version = "2.0.0-pre.1"
version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5da623d8af10a62342bcbbb230e33e58a63255a58012f8653c578e54bab48df"
checksum = "fb66477291e7e8d2b0ff1bcb900bf29489a9692816d79874bea351e7a8b6de96"
dependencies = [
"curve25519-dalek 3.2.0",
"curve25519-dalek 4.1.0",
"rand_core 0.6.4",
"serde",
"zeroize",
]
+1
View File
@@ -77,6 +77,7 @@ members = [
"common/wasm/client-core",
"common/wasm/storage",
"common/wasm/utils",
"common/wireguard",
"explorer-api",
"explorer-api/explorer-api-requests",
"explorer-api/explorer-client",
+26
View File
@@ -0,0 +1,26 @@
[package]
name = "nym-wireguard"
version = "0.1.0"
authors.workspace = true
repository.workspace = true
homepage.workspace = true
documentation.workspace = true
edition.workspace = true
license.workspace = true
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
async-recursion = "1.0.4"
base64 = "0.21.3"
# The latest version on crates.io at the time of writing this (6.0.0) has a
# version mismatch with x25519-dalek/curve25519-dalek that is resolved in the
# latest commit. So pick that for now.
#boringtun = "0.6.0"
boringtun = { git = "https://github.com/cloudflare/boringtun", rev = "e1d6360d6ab4529fc942a078e4c54df107abe2ba" }
bytes = "1.5.0"
futures = "0.3.28"
log.workspace = true
nym-task = { path = "../task" }
tap.workspace = true
tokio = { workspace = true, features = ["rt-multi-thread", "net"]}
+33
View File
@@ -0,0 +1,33 @@
use std::fmt::{Display, Formatter};
use bytes::Bytes;
#[allow(unused)]
#[derive(Debug, Clone)]
pub enum Event {
/// Dumb event with no data.
Dumb,
/// IP packet received from the WireGuard tunnel that should be passed through to the corresponding virtual device/internet.
/// Original implementation also has protocol here since it understands it, but we'll have to infer it downstream
WgPacket(Bytes),
/// IP packet to be sent through the WireGuard tunnel as crafted by the virtual device.
IpPacket(Bytes),
}
impl Display for Event {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Event::Dumb => {
write!(f, "Dumb{{}}")
}
Event::WgPacket(data) => {
let size = data.len();
write!(f, "WgPacket{{ size={size} }}")
}
Event::IpPacket(data) => {
let size = data.len();
write!(f, "IpPacket{{ size={size} }}")
}
}
}
}
+137
View File
@@ -0,0 +1,137 @@
use std::{collections::HashMap, net::SocketAddr, sync::Arc};
use base64::{engine::general_purpose, Engine as _};
use boringtun::x25519;
use futures::StreamExt;
use log::{error, info};
use nym_task::TaskClient;
use tap::TapFallible;
use tokio::{net::UdpSocket, sync::mpsc, task::JoinHandle};
use tun::WireGuardTunnel;
use crate::event::Event;
mod event;
mod tun;
//const WG_ADDRESS = "0.0.0.0:51820";
const WG_ADDRESS: &str = "0.0.0.0:51822";
// The private key of the listener
// Corresponding public key: "WM8s8bYegwMa0TJ+xIwhk+dImk2IpDUKslDBCZPizlE="
const PRIVATE_KEY: &str = "AEqXrLFT4qjYq3wmX0456iv94uM6nDj5ugp6Jedcflg=";
// The public keys of the registered peers (clients)
const PEERS: &[&str; 1] = &[
// Corresponding private key: "ILeN6gEh6vJ3Ju8RJ3HVswz+sPgkcKtAYTqzQRhTtlo="
"NCIhkgiqxFx1ckKl3Zuh595DzIFl8mxju1Vg995EZhI=", // "mxV/mw7WZTe+0Msa0kvJHMHERDA/cSskiZWQce+TdEs=",
];
const MAX_PACKET: usize = 65535;
fn init_static_dev_keys() -> (x25519::StaticSecret, x25519::PublicKey) {
// TODO: this is a temporary solution for development
let static_private_bytes: [u8; 32] = general_purpose::STANDARD
.decode(PRIVATE_KEY)
.unwrap()
.try_into()
.unwrap();
let static_private = x25519::StaticSecret::try_from(static_private_bytes).unwrap();
let static_public = x25519::PublicKey::from(&static_private);
info!(
"wg public key: {}",
general_purpose::STANDARD.encode(static_public)
);
// TODO: A single static public key is used for all peers during development
let peer_static_public_bytes: [u8; 32] = general_purpose::STANDARD
.decode(PEERS[0])
.unwrap()
.try_into()
.unwrap();
let peer_static_public = x25519::PublicKey::try_from(peer_static_public_bytes).unwrap();
(static_private, peer_static_public)
}
fn start_wg_tunnel(
addr: SocketAddr,
udp: Arc<UdpSocket>,
static_private: x25519::StaticSecret,
peer_static_public: x25519::PublicKey,
) -> (JoinHandle<SocketAddr>, mpsc::UnboundedSender<Event>) {
let (mut tunnel, peer_tx) = WireGuardTunnel::new(udp, addr, static_private, peer_static_public);
let join_handle = tokio::spawn(async move {
tunnel.spin_off().await;
addr
});
(join_handle, peer_tx)
}
pub async fn start_wg_listener(
mut task_client: TaskClient,
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
log::info!("Starting wireguard listener on {}", WG_ADDRESS);
let udp_socket = Arc::new(UdpSocket::bind(WG_ADDRESS).await?);
// Setup some static keys for development
let (static_private, peer_static_public) = init_static_dev_keys();
tokio::spawn(async move {
// The set of active tunnels indexed by the peer's address
let mut active_peers: HashMap<SocketAddr, mpsc::UnboundedSender<Event>> = HashMap::new();
// Each tunnel is run in its own task, and the task handle is stored here so we can remove
// it from `active_peers` when the tunnel is closed
let mut active_peers_task_handles = futures::stream::FuturesUnordered::new();
let mut buf = [0u8; MAX_PACKET];
while !task_client.is_shutdown() {
tokio::select! {
_ = task_client.recv() => {
log::trace!("WireGuard listener: received shutdown");
break;
}
// Handle tunnel closing
Some(addr) = active_peers_task_handles.next() => {
match addr {
Ok(addr) => {
info!("WireGuard listener: closed {addr:?}");
active_peers.remove(&addr);
}
Err(err) => {
error!("WireGuard listener: error receiving shutdown from peer: {err}");
}
}
}
// Handle incoming packets
Ok((len, addr)) = udp_socket.recv_from(&mut buf) => {
log::info!("Received {} bytes from {}", len, addr);
if let Some(peer_tx) = active_peers.get_mut(&addr) {
log::info!("WireGuard listener: received packet from known peer");
peer_tx.send(Event::WgPacket(buf[..len].to_vec().into()))
.tap_err(|err| log::error!("{err}"))
.unwrap();
} else {
log::info!("WireGuard listener: received packet from unknown peer, starting tunnel");
let (join_handle, peer_tx) = start_wg_tunnel(
addr,
udp_socket.clone(),
static_private.clone(),
peer_static_public
);
peer_tx.send(Event::WgPacket(buf[..len].to_vec().into()))
.tap_err(|err| log::error!("{err}"))
.unwrap();
active_peers.insert(addr, peer_tx);
active_peers_task_handles.push(join_handle);
}
}
}
}
log::info!("WireGuard listener: shutting down");
});
Ok(())
}
+210
View File
@@ -0,0 +1,210 @@
use std::{net::SocketAddr, sync::Arc, time::Duration};
use async_recursion::async_recursion;
use boringtun::{
noise::{errors::WireGuardError, Tunn, TunnResult},
x25519,
};
use bytes::Bytes;
use log::{debug, error, info, warn};
use tokio::{
net::UdpSocket,
sync::{broadcast, mpsc},
time::timeout,
};
use crate::event::Event;
const MAX_PACKET: usize = 65535;
pub struct WireGuardTunnel {
// Incoming data from the UDP socket received in the main event loop
udp_rx: mpsc::UnboundedReceiver<Event>,
// UDP socket used for sending data
udp: Arc<UdpSocket>,
// Peer endpoint
addr: SocketAddr,
// `boringtun` tunnel, used for crypto & WG protocol
wg_tunnel: Arc<tokio::sync::Mutex<Tunn>>,
// Signal close
close_tx: broadcast::Sender<()>,
close_rx: broadcast::Receiver<()>,
}
impl Drop for WireGuardTunnel {
fn drop(&mut self) {
info!("WireGuard tunnel: dropping");
self.close();
}
}
impl WireGuardTunnel {
fn close(&self) {
let _ = self.close_tx.send(());
}
pub fn new(
udp: Arc<UdpSocket>,
addr: SocketAddr,
static_private: x25519::StaticSecret,
peer_static_public: x25519::PublicKey,
) -> (Self, mpsc::UnboundedSender<Event>) {
let preshared_key = None;
let persistent_keepalive = None;
let index = 0;
let rate_limiter = None;
let wg_tunnel = Arc::new(tokio::sync::Mutex::new(
Tunn::new(
static_private,
peer_static_public,
preshared_key,
persistent_keepalive,
index,
rate_limiter,
)
.unwrap(),
));
// Channels with incoming data that is received by the main event loop
let (udp_tx, udp_rx) = mpsc::unbounded_channel();
// Signal close tunnel
let (close_tx, close_rx) = broadcast::channel(1);
let tunnel = WireGuardTunnel {
udp_rx,
udp,
addr,
wg_tunnel,
close_tx,
close_rx,
};
(tunnel, udp_tx)
}
pub async fn spin_off(&mut self) {
loop {
tokio::select! {
_ = self.close_rx.recv() => {
info!("WireGuard tunnel: received msg to close");
break;
},
packet = self.udp_rx.recv() => match packet {
Some(packet) => {
info!("WireGuard tunnel received: {packet}");
match packet {
Event::WgPacket(data) => self.consume_wg(&data).await,
Event::IpPacket(data) => self.consume_eth(&data).await,
_ => {},
}
},
None => {
info!("WireGuard tunnel: incoming UDP stream closed, closing tunnel");
break;
},
},
_ = tokio::time::sleep(Duration::from_millis(250)) => {
self.update_wg_timers().await;
},
}
}
info!("WireGuard tunnel ({}): closed", self.addr);
}
async fn wg_tunnel_lock(&self) -> tokio::sync::MutexGuard<'_, Tunn> {
timeout(Duration::from_millis(100), self.wg_tunnel.lock())
.await
.unwrap()
}
async fn consume_wg(&self, data: &[u8]) {
let mut send_buf = [0u8; MAX_PACKET];
let mut peer = self.wg_tunnel_lock().await;
match peer.decapsulate(None, data, &mut send_buf) {
TunnResult::WriteToNetwork(packet) => {
debug!("WireGuard: writing to network");
if let Err(err) = self.udp.send_to(packet, self.addr).await {
error!("Failed to send decapsulation-instructed packet to WireGuard endpoint: {err:?}");
};
// Flush pending queue
loop {
let mut send_buf = [0u8; MAX_PACKET];
match peer.decapsulate(None, &[], &mut send_buf) {
TunnResult::WriteToNetwork(packet) => {
if let Err(err) = self.udp.send_to(packet, self.addr).await {
error!("Failed to send decapsulation-instructed packet to WireGuard endpoint: {err:?}");
break;
};
}
_ => {
break;
}
}
}
}
TunnResult::WriteToTunnelV4(packet, _) | TunnResult::WriteToTunnelV6(packet, _) => {
debug!("WireGuard: writing to tunnel");
info!(
"WireGuard endpoint sent IP packet of {} bytes (not yet implemented)",
packet.len()
);
// TODO
}
TunnResult::Done => {
debug!("WireGuard: decapsulate done");
}
TunnResult::Err(err) => {
error!("WireGuard: decapsulate error: {err:?}");
}
}
}
async fn consume_eth(&self, _data: &Bytes) {
info!("WireGuard tunnel: consume_eth");
todo!();
}
async fn update_wg_timers(&mut self) {
let mut send_buf = [0u8; MAX_PACKET];
let mut tun = self.wg_tunnel_lock().await;
let tun_result = tun.update_timers(&mut send_buf);
self.handle_routine_tun_result(tun_result).await;
}
#[async_recursion]
async fn handle_routine_tun_result<'a: 'async_recursion>(&self, result: TunnResult<'a>) {
match result {
TunnResult::WriteToNetwork(packet) => {
info!(
"Sending routine packet of {} bytes to WireGuard endpoint",
packet.len()
);
if let Err(err) = self.udp.send_to(packet, self.addr).await {
error!("Failed to send routine packet to WireGuard endpoint: {err:?}",);
};
}
TunnResult::Err(WireGuardError::ConnectionExpired) => {
warn!("Wireguard handshake has expired!");
let mut buf = vec![0u8; MAX_PACKET];
let result = self
.wg_tunnel_lock()
.await
.format_handshake_initiation(&mut buf[..], false);
self.handle_routine_tun_result(result).await
}
TunnResult::Err(err) => {
error!("Failed to prepare routine packet for WireGuard endpoint: {err:?}");
}
TunnResult::Done => {}
other => {
warn!("Unexpected WireGuard routine task state: {other:?}");
}
};
}
}
+4
View File
@@ -61,6 +61,7 @@ nym-statistics-common = { path = "../common/statistics" }
nym-task = { path = "../common/task" }
nym-types = { path = "../common/types" }
nym-validator-client = { path = "../common/client-libs/validator-client" }
nym-wireguard = { path = "../common/wireguard" }
[build-dependencies]
tokio = { version = "1.24.1", features = ["rt-multi-thread", "macros"] }
@@ -70,3 +71,6 @@ sqlx = { version = "0.5", features = [
"macros",
"migrate",
] }
[features]
wireguard = []
+5
View File
@@ -293,6 +293,11 @@ impl<St> Gateway<St> {
Arc::new(coconut_verifier),
);
// Once this is a bit more mature, make this a commandline flag instead of a compile time
// flag
#[cfg(feature = "wireguard")]
nym_wireguard::start_wg_listener(shutdown.subscribe()).await?;
info!("Finished nym gateway startup procedure - it should now be able to receive mix and client traffic!");
self.wait_for_interrupt(shutdown).await
+1 -1
View File
@@ -54,4 +54,4 @@ parking_lot = "0.12"
hex = "0.4"
[features]
libp2p-vanilla = []
libp2p-vanilla = []