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:
Generated
+141
-53
@@ -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",
|
||||
]
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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"]}
|
||||
@@ -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} }}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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(())
|
||||
}
|
||||
@@ -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:?}");
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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 = []
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -54,4 +54,4 @@ parking_lot = "0.12"
|
||||
hex = "0.4"
|
||||
|
||||
[features]
|
||||
libp2p-vanilla = []
|
||||
libp2p-vanilla = []
|
||||
|
||||
Reference in New Issue
Block a user