Add Boringtun
Co-authored-by: Joakim Hulthe <joakim.hulthe@mullvad.net> Co-authored-by: Sebastian Holmin <sebastian.holmin@mullvad.net> Co-authored-by: David Göransson <david.goransson@mullvad.net> Co-authored-by: Markus Pettersson <markus.pettersson@mullvad.net> Co-authored-by: David Lönnhager <david.l@mullvad.net>
This commit is contained in:
parent
9dfafb3e50
commit
8f3900bb99
336
Cargo.lock
generated
336
Cargo.lock
generated
@ -182,6 +182,18 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-channel"
|
||||||
|
version = "2.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a"
|
||||||
|
dependencies = [
|
||||||
|
"concurrent-queue",
|
||||||
|
"event-listener-strategy",
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-stream"
|
name = "async-stream"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
@ -204,6 +216,12 @@ dependencies = [
|
|||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "async-task"
|
||||||
|
version = "4.7.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "async-tempfile"
|
name = "async-tempfile"
|
||||||
version = "0.6.0"
|
version = "0.6.0"
|
||||||
@ -224,6 +242,12 @@ dependencies = [
|
|||||||
"syn 2.0.100",
|
"syn 2.0.100",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "atomic-waker"
|
||||||
|
version = "1.1.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
@ -298,6 +322,12 @@ version = "0.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "base64"
|
||||||
|
version = "0.13.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "base64"
|
name = "base64"
|
||||||
version = "0.21.7"
|
version = "0.21.7"
|
||||||
@ -352,6 +382,15 @@ version = "2.9.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blake2"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "blake3"
|
name = "blake3"
|
||||||
version = "1.5.1"
|
version = "1.5.1"
|
||||||
@ -389,6 +428,49 @@ dependencies = [
|
|||||||
"objc2",
|
"objc2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "blocking"
|
||||||
|
version = "1.6.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea"
|
||||||
|
dependencies = [
|
||||||
|
"async-channel",
|
||||||
|
"async-task",
|
||||||
|
"futures-io",
|
||||||
|
"futures-lite",
|
||||||
|
"piper",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "boringtun"
|
||||||
|
version = "0.6.0"
|
||||||
|
source = "git+https://github.com/mullvad/boringtun?rev=a7e11fb46d4a#a7e11fb46d4ae65d4c7bf4efb9617548c072afa0"
|
||||||
|
dependencies = [
|
||||||
|
"aead",
|
||||||
|
"base64 0.13.1",
|
||||||
|
"blake2",
|
||||||
|
"chacha20poly1305",
|
||||||
|
"eyre",
|
||||||
|
"hex",
|
||||||
|
"hmac",
|
||||||
|
"ip_network",
|
||||||
|
"ip_network_table",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"nix 0.25.1",
|
||||||
|
"parking_lot",
|
||||||
|
"rand_core 0.6.4",
|
||||||
|
"ring",
|
||||||
|
"socket2 0.4.10",
|
||||||
|
"thiserror 1.0.59",
|
||||||
|
"tokio",
|
||||||
|
"tracing",
|
||||||
|
"tun 0.7.13",
|
||||||
|
"typed-builder 0.20.1",
|
||||||
|
"untrusted",
|
||||||
|
"x25519-dalek",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bumpalo"
|
name = "bumpalo"
|
||||||
version = "3.16.0"
|
version = "3.16.0"
|
||||||
@ -413,6 +495,26 @@ version = "1.10.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
|
checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "c2rust-bitfields"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "367e5d1b30f28be590b6b3868da1578361d29d9bfac516d22f497d28ed7c9055"
|
||||||
|
dependencies = [
|
||||||
|
"c2rust-bitfields-derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "c2rust-bitfields-derive"
|
||||||
|
version = "0.19.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "a279db9c50c4024eeca1a763b6e0f033848ce74e83e47454bcf8a8a98f7b0b56"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 1.0.109",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cacao"
|
name = "cacao"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
@ -647,10 +749,19 @@ dependencies = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "console"
|
name = "concurrent-queue"
|
||||||
version = "0.15.10"
|
version = "2.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b"
|
checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"
|
||||||
|
dependencies = [
|
||||||
|
"crossbeam-utils",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "console"
|
||||||
|
version = "0.15.11"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"encode_unicode",
|
"encode_unicode",
|
||||||
"libc",
|
"libc",
|
||||||
@ -1179,6 +1290,37 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "event-listener"
|
||||||
|
version = "5.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae"
|
||||||
|
dependencies = [
|
||||||
|
"concurrent-queue",
|
||||||
|
"parking",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "event-listener-strategy"
|
||||||
|
version = "0.5.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c3e4e0dd3673c1139bf041f3008816d9cf2946bbfac2945c09e523b8d7b05b2"
|
||||||
|
dependencies = [
|
||||||
|
"event-listener",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "eyre"
|
||||||
|
version = "0.6.12"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec"
|
||||||
|
dependencies = [
|
||||||
|
"indenter",
|
||||||
|
"once_cell",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fastrand"
|
name = "fastrand"
|
||||||
version = "2.0.2"
|
version = "2.0.2"
|
||||||
@ -1326,6 +1468,16 @@ version = "0.3.31"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "futures-lite"
|
||||||
|
version = "2.6.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f5edaec856126859abb19ed65f39e90fea3a9574b9707f13539acf4abf7eb532"
|
||||||
|
dependencies = [
|
||||||
|
"futures-core",
|
||||||
|
"pin-project-lite",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "futures-macro"
|
name = "futures-macro"
|
||||||
version = "0.3.31"
|
version = "0.3.31"
|
||||||
@ -1821,7 +1973,7 @@ dependencies = [
|
|||||||
"http-body",
|
"http-body",
|
||||||
"hyper",
|
"hyper",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tower-service",
|
"tower-service",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -1995,6 +2147,12 @@ dependencies = [
|
|||||||
"icu_properties",
|
"icu_properties",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "indenter"
|
||||||
|
version = "0.3.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "1.9.3"
|
version = "1.9.3"
|
||||||
@ -2134,13 +2292,35 @@ version = "0.8.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c"
|
checksum = "8bd11f3a29434026f5ff98c730b668ba74b1033637b8817940b54d040696133c"
|
||||||
|
|
||||||
|
[[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]]
|
[[package]]
|
||||||
name = "ipconfig"
|
name = "ipconfig"
|
||||||
version = "0.3.2"
|
version = "0.3.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
|
checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"widestring",
|
"widestring",
|
||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
"winreg 0.50.0",
|
"winreg 0.50.0",
|
||||||
@ -2765,7 +2945,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"serde_json",
|
"serde_json",
|
||||||
"simple-signal",
|
"simple-signal",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"talpid-core",
|
"talpid-core",
|
||||||
"talpid-dbus",
|
"talpid-dbus",
|
||||||
"talpid-future",
|
"talpid-future",
|
||||||
@ -2878,7 +3058,7 @@ dependencies = [
|
|||||||
"pnet_packet 0.35.0",
|
"pnet_packet 0.35.0",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"talpid-windows",
|
"talpid-windows",
|
||||||
"tokio",
|
"tokio",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
@ -2923,10 +3103,10 @@ dependencies = [
|
|||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rustls 0.23.18",
|
"rustls 0.23.18",
|
||||||
"rustls-pemfile 2.1.3",
|
"rustls-pemfile 2.1.3",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.9",
|
||||||
"tokio",
|
"tokio",
|
||||||
"typed-builder",
|
"typed-builder 0.21.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -3238,6 +3418,19 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nix"
|
||||||
|
version = "0.25.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
|
||||||
|
dependencies = [
|
||||||
|
"autocfg",
|
||||||
|
"bitflags 1.3.2",
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"memoffset 0.6.5",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nix"
|
name = "nix"
|
||||||
version = "0.28.0"
|
version = "0.28.0"
|
||||||
@ -3580,6 +3773,12 @@ dependencies = [
|
|||||||
"winapi",
|
"winapi",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "parking"
|
||||||
|
version = "2.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
@ -3769,6 +3968,17 @@ version = "0.1.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "piper"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066"
|
||||||
|
dependencies = [
|
||||||
|
"atomic-waker",
|
||||||
|
"fastrand",
|
||||||
|
"futures-io",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pkcs8"
|
name = "pkcs8"
|
||||||
version = "0.10.2"
|
version = "0.10.2"
|
||||||
@ -4113,7 +4323,7 @@ dependencies = [
|
|||||||
"quinn-udp",
|
"quinn-udp",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"rustls 0.23.18",
|
"rustls 0.23.18",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.9",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -4150,7 +4360,7 @@ dependencies = [
|
|||||||
"cfg_aliases 0.2.1",
|
"cfg_aliases 0.2.1",
|
||||||
"libc",
|
"libc",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"tracing",
|
"tracing",
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
@ -4789,7 +4999,7 @@ dependencies = [
|
|||||||
"serde_json",
|
"serde_json",
|
||||||
"serde_urlencoded",
|
"serde_urlencoded",
|
||||||
"shadowsocks-crypto",
|
"shadowsocks-crypto",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"spin",
|
"spin",
|
||||||
"thiserror 1.0.59",
|
"thiserror 1.0.59",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -4848,7 +5058,7 @@ dependencies = [
|
|||||||
"regex",
|
"regex",
|
||||||
"serde",
|
"serde",
|
||||||
"shadowsocks",
|
"shadowsocks",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"spin",
|
"spin",
|
||||||
"thiserror 1.0.59",
|
"thiserror 1.0.59",
|
||||||
"tokio",
|
"tokio",
|
||||||
@ -4941,6 +5151,16 @@ version = "1.13.2"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "socket2"
|
||||||
|
version = "0.4.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"winapi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "socket2"
|
name = "socket2"
|
||||||
version = "0.5.8"
|
version = "0.5.8"
|
||||||
@ -4998,7 +5218,7 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pnet_packet 0.34.0",
|
"pnet_packet 0.34.0",
|
||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"thiserror 1.0.59",
|
"thiserror 1.0.59",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tracing",
|
"tracing",
|
||||||
@ -5131,7 +5351,7 @@ dependencies = [
|
|||||||
"tokio",
|
"tokio",
|
||||||
"tonic-build",
|
"tonic-build",
|
||||||
"triggered",
|
"triggered",
|
||||||
"tun",
|
"tun 0.5.5",
|
||||||
"which",
|
"which",
|
||||||
"widestring",
|
"widestring",
|
||||||
"windows 0.58.0",
|
"windows 0.58.0",
|
||||||
@ -5178,7 +5398,7 @@ dependencies = [
|
|||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
"nix 0.29.0",
|
"nix 0.29.0",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"talpid-types",
|
"talpid-types",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.9",
|
||||||
]
|
]
|
||||||
@ -5287,7 +5507,8 @@ dependencies = [
|
|||||||
"talpid-windows",
|
"talpid-windows",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.9",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tun",
|
"tun 0.5.5",
|
||||||
|
"tun 0.7.13",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -5333,7 +5554,7 @@ name = "talpid-windows"
|
|||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"futures",
|
"futures",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"talpid-types",
|
"talpid-types",
|
||||||
"thiserror 2.0.9",
|
"thiserror 2.0.9",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
@ -5345,6 +5566,7 @@ version = "0.0.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"async-trait",
|
"async-trait",
|
||||||
"bitflags 1.3.2",
|
"bitflags 1.3.2",
|
||||||
|
"boringtun",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"chrono",
|
"chrono",
|
||||||
"futures",
|
"futures",
|
||||||
@ -5365,7 +5587,7 @@ dependencies = [
|
|||||||
"rand 0.8.5",
|
"rand 0.8.5",
|
||||||
"rand_chacha 0.3.1",
|
"rand_chacha 0.3.1",
|
||||||
"rtnetlink",
|
"rtnetlink",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"surge-ping",
|
"surge-ping",
|
||||||
"talpid-dbus",
|
"talpid-dbus",
|
||||||
"talpid-net",
|
"talpid-net",
|
||||||
@ -5377,6 +5599,7 @@ dependencies = [
|
|||||||
"thiserror 2.0.9",
|
"thiserror 2.0.9",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
|
"tun 0.7.13",
|
||||||
"tunnel-obfuscation",
|
"tunnel-obfuscation",
|
||||||
"widestring",
|
"widestring",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
@ -5525,7 +5748,7 @@ dependencies = [
|
|||||||
"parking_lot",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"tokio-macros",
|
"tokio-macros",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
@ -5597,7 +5820,7 @@ dependencies = [
|
|||||||
"log",
|
"log",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"tokio",
|
"tokio",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
@ -5694,7 +5917,7 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"prost 0.13.3",
|
"prost 0.13.3",
|
||||||
"socket2",
|
"socket2 0.5.8",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tower 0.4.13",
|
"tower 0.4.13",
|
||||||
@ -5863,6 +6086,27 @@ dependencies = [
|
|||||||
"tokio-util 0.6.10",
|
"tokio-util 0.6.10",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tun"
|
||||||
|
version = "0.7.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9298ac5c7f0076908d7a168c634bf4867b4a7d5725eb6356863f8640c6c35ef1"
|
||||||
|
dependencies = [
|
||||||
|
"bytes",
|
||||||
|
"cfg-if",
|
||||||
|
"futures",
|
||||||
|
"futures-core",
|
||||||
|
"ipnet",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"nix 0.29.0",
|
||||||
|
"thiserror 2.0.9",
|
||||||
|
"tokio",
|
||||||
|
"tokio-util 0.7.10",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
"wintun-bindings",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tunnel-obfuscation"
|
name = "tunnel-obfuscation"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
@ -5877,13 +6121,33 @@ dependencies = [
|
|||||||
"udp-over-tcp",
|
"udp-over-tcp",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typed-builder"
|
||||||
|
version = "0.20.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cd9d30e3a08026c78f246b173243cf07b3696d274debd26680773b6773c2afc7"
|
||||||
|
dependencies = [
|
||||||
|
"typed-builder-macro 0.20.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "typed-builder"
|
name = "typed-builder"
|
||||||
version = "0.21.0"
|
version = "0.21.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ce63bcaf7e9806c206f7d7b9c1f38e0dce8bb165a80af0898161058b19248534"
|
checksum = "ce63bcaf7e9806c206f7d7b9c1f38e0dce8bb165a80af0898161058b19248534"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"typed-builder-macro",
|
"typed-builder-macro 0.21.0",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "typed-builder-macro"
|
||||||
|
version = "0.20.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "3c36781cc0e46a83726d9879608e4cf6c2505237e263a8eb8c24502989cfdb28"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn 2.0.100",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -6748,6 +7012,16 @@ dependencies = [
|
|||||||
"windows-sys 0.48.0",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "winreg"
|
||||||
|
version = "0.55.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "cb5a765337c50e9ec252c2069be9bf91c7df47afb103b642ba3a53bf8101be97"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winres"
|
name = "winres"
|
||||||
version = "0.1.12"
|
version = "0.1.12"
|
||||||
@ -6757,6 +7031,22 @@ dependencies = [
|
|||||||
"toml 0.5.11",
|
"toml 0.5.11",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wintun-bindings"
|
||||||
|
version = "0.7.30"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67a02981bed4592bcd271f9bfe154228ddbd2fd69e37a7d358da5d3a1251d696"
|
||||||
|
dependencies = [
|
||||||
|
"blocking",
|
||||||
|
"c2rust-bitfields",
|
||||||
|
"futures",
|
||||||
|
"libloading",
|
||||||
|
"log",
|
||||||
|
"thiserror 2.0.9",
|
||||||
|
"windows-sys 0.59.0",
|
||||||
|
"winreg 0.55.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wireguard-go-rs"
|
name = "wireguard-go-rs"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
|
@ -140,10 +140,10 @@ strip = true
|
|||||||
|
|
||||||
# Selectively optimize packages where we know it makes a difference
|
# Selectively optimize packages where we know it makes a difference
|
||||||
[profile.release.package]
|
[profile.release.package]
|
||||||
|
boringtun.opt-level = 3
|
||||||
pqcrypto-hqc.opt-level = 3
|
pqcrypto-hqc.opt-level = 3
|
||||||
quinn-proto.opt-level = 3
|
quinn-proto.opt-level = 3
|
||||||
quinn-udp.opt-level = 3
|
quinn-udp.opt-level = 3
|
||||||
quinn.opt-level = 3
|
quinn.opt-level = 3
|
||||||
mullvad-masque-proxy.opt-level = 3
|
mullvad-masque-proxy.opt-level = 3
|
||||||
ring.opt-level = 3
|
ring.opt-level = 3
|
||||||
|
|
||||||
|
@ -247,6 +247,7 @@ junitPlatform {
|
|||||||
|
|
||||||
cargo {
|
cargo {
|
||||||
val isReleaseBuild = isReleaseBuild()
|
val isReleaseBuild = isReleaseBuild()
|
||||||
|
val enableBoringTun = getBooleanProperty("mullvad.app.build.boringtun.enable")
|
||||||
val enableApiOverride = !isReleaseBuild || isDevBuild() || isAlphaBuild()
|
val enableApiOverride = !isReleaseBuild || isDevBuild() || isAlphaBuild()
|
||||||
module = repoRootPath
|
module = repoRootPath
|
||||||
libname = "mullvad-jni"
|
libname = "mullvad-jni"
|
||||||
@ -262,9 +263,15 @@ cargo {
|
|||||||
prebuiltToolchains = true
|
prebuiltToolchains = true
|
||||||
targetDirectory = "$repoRootPath/target"
|
targetDirectory = "$repoRootPath/target"
|
||||||
features {
|
features {
|
||||||
if (enableApiOverride) {
|
val enabledFeatures = buildList {
|
||||||
defaultAnd(arrayOf("api-override"))
|
if (enableApiOverride) {
|
||||||
|
add("api-override")
|
||||||
|
}
|
||||||
|
if (enableBoringTun) {
|
||||||
|
add("boringtun")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
defaultAnd(enabledFeatures.toTypedArray())
|
||||||
}
|
}
|
||||||
targetIncludes = arrayOf("libmullvad_jni.so")
|
targetIncludes = arrayOf("libmullvad_jni.so")
|
||||||
extraCargoBuildArguments = buildList {
|
extraCargoBuildArguments = buildList {
|
||||||
|
@ -33,6 +33,9 @@ mullvad.app.build.cargo.cleanBuild=true
|
|||||||
# to be substantially larger.
|
# to be substantially larger.
|
||||||
mullvad.app.build.keepDebugSymbols=false
|
mullvad.app.build.keepDebugSymbols=false
|
||||||
|
|
||||||
|
# Enable/Disable boringtun
|
||||||
|
mullvad.app.build.boringtun.enable=false
|
||||||
|
|
||||||
## E2E tests ##
|
## E2E tests ##
|
||||||
|
|
||||||
# To run e2e tests you need to provide credentails for the enviroment you
|
# To run e2e tests you need to provide credentails for the enviroment you
|
||||||
|
@ -54,7 +54,7 @@ fi
|
|||||||
|
|
||||||
set -x
|
set -x
|
||||||
exec "$CONTAINER_RUNNER" run --rm -it \
|
exec "$CONTAINER_RUNNER" run --rm -it \
|
||||||
-v "$REPO_DIR:$REPO_MOUNT_TARGET:Z" \
|
-v "/$REPO_DIR:$REPO_MOUNT_TARGET:Z" \
|
||||||
-v "$CARGO_TARGET_VOLUME_NAME:/cargo-target:Z" \
|
-v "$CARGO_TARGET_VOLUME_NAME:/cargo-target:Z" \
|
||||||
-v "$CARGO_REGISTRY_VOLUME_NAME:/root/.cargo/registry:Z" \
|
-v "$CARGO_REGISTRY_VOLUME_NAME:/root/.cargo/registry:Z" \
|
||||||
"${optional_gradle_cache_volume[@]}" \
|
"${optional_gradle_cache_volume[@]}" \
|
||||||
|
@ -13,6 +13,8 @@ workspace = true
|
|||||||
[features]
|
[features]
|
||||||
# Allow the API server to use to be configured
|
# Allow the API server to use to be configured
|
||||||
api-override = ["mullvad-api/api-override"]
|
api-override = ["mullvad-api/api-override"]
|
||||||
|
boringtun = ["talpid-core/boringtun"]
|
||||||
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true }
|
||||||
|
@ -13,6 +13,7 @@ workspace = true
|
|||||||
[features]
|
[features]
|
||||||
# Allow the API server to use to be configured
|
# Allow the API server to use to be configured
|
||||||
api-override = ["mullvad-api/api-override", "mullvad-daemon/api-override"]
|
api-override = ["mullvad-api/api-override", "mullvad-daemon/api-override"]
|
||||||
|
boringtun = ["mullvad-daemon/boringtun"]
|
||||||
|
|
||||||
[lib]
|
[lib]
|
||||||
crate-type = ["cdylib"]
|
crate-type = ["cdylib"]
|
||||||
|
@ -10,6 +10,9 @@ rust-version.workspace = true
|
|||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
boringtun = ["talpid-wireguard/boringtun"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
chrono = { workspace = true, features = ["clock"] }
|
chrono = { workspace = true, features = ["clock"] }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
|
@ -175,14 +175,11 @@ impl TunnelMonitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn start_wireguard_tunnel(
|
fn start_wireguard_tunnel(
|
||||||
#[cfg(not(any(target_os = "linux", target_os = "windows")))]
|
|
||||||
params: &wireguard_types::TunnelParameters,
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
|
||||||
params: &wireguard_types::TunnelParameters,
|
params: &wireguard_types::TunnelParameters,
|
||||||
log: Option<path::PathBuf>,
|
log: Option<path::PathBuf>,
|
||||||
args: TunnelArgs<'_>,
|
args: TunnelArgs<'_>,
|
||||||
) -> Result<Self> {
|
) -> Result<Self> {
|
||||||
let monitor = talpid_wireguard::WireguardMonitor::start(params, log.as_deref(), args)?;
|
let monitor = talpid_wireguard::WireguardMonitor::start(params, args, log.as_deref())?;
|
||||||
Ok(TunnelMonitor {
|
Ok(TunnelMonitor {
|
||||||
monitor: InternalTunnelMonitor::Wireguard(monitor),
|
monitor: InternalTunnelMonitor::Wireguard(monitor),
|
||||||
})
|
})
|
||||||
|
@ -10,6 +10,9 @@ rust-version.workspace = true
|
|||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
boringtun = ["dep:tun07"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
cfg-if = "1.0"
|
cfg-if = "1.0"
|
||||||
@ -19,12 +22,17 @@ talpid-types = { path = "../talpid-types" }
|
|||||||
futures = { workspace = true }
|
futures = { workspace = true }
|
||||||
tokio = { workspace = true, features = ["process", "rt-multi-thread", "fs"] }
|
tokio = { workspace = true, features = ["process", "rt-multi-thread", "fs"] }
|
||||||
|
|
||||||
|
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
||||||
|
tun = { workspace = true } # use tun 0.5.5 for wireguard-go
|
||||||
|
|
||||||
[target.'cfg(target_os = "android")'.dependencies]
|
[target.'cfg(target_os = "android")'.dependencies]
|
||||||
jnix = { version = "0.5.1", features = ["derive"] }
|
jnix = { version = "0.5.1", features = ["derive"] }
|
||||||
log = { workspace = true }
|
log = { workspace = true }
|
||||||
|
|
||||||
[target.'cfg(any(target_os = "linux", target_os = "macos"))'.dependencies]
|
[target.'cfg(not(target_os = "android"))'.dependencies]
|
||||||
tun = { workspace = true }
|
tun07 = { package = "tun", version = "0.7.11", optional = true, features = [
|
||||||
|
"async",
|
||||||
|
] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
talpid-windows = { path = "../talpid-windows" }
|
talpid-windows = { path = "../talpid-windows" }
|
||||||
@ -32,7 +40,7 @@ talpid-windows = { path = "../talpid-windows" }
|
|||||||
[target.'cfg(windows)'.dependencies.windows-sys]
|
[target.'cfg(windows)'.dependencies.windows-sys]
|
||||||
workspace = true
|
workspace = true
|
||||||
features = [
|
features = [
|
||||||
"Win32_Foundation",
|
"Win32_Foundation",
|
||||||
"Win32_Networking_WinSock",
|
"Win32_Networking_WinSock",
|
||||||
"Win32_NetworkManagement_Ndis",
|
"Win32_NetworkManagement_Ndis",
|
||||||
]
|
]
|
||||||
|
@ -24,6 +24,14 @@ cfg_if! {
|
|||||||
|
|
||||||
pub type Tun = UnixTun;
|
pub type Tun = UnixTun;
|
||||||
pub type TunProvider = UnixTunProvider;
|
pub type TunProvider = UnixTunProvider;
|
||||||
|
} else if #[cfg(all(windows, feature = "boringtun"))] {
|
||||||
|
#[path = "windows.rs"]
|
||||||
|
mod imp;
|
||||||
|
use self::imp::{WindowsTun, WindowsTunProvider};
|
||||||
|
pub use self::imp::Error;
|
||||||
|
|
||||||
|
pub type Tun = WindowsTun;
|
||||||
|
pub type TunProvider = WindowsTunProvider;
|
||||||
} else {
|
} else {
|
||||||
mod stub;
|
mod stub;
|
||||||
use self::stub::StubTunProvider;
|
use self::stub::StubTunProvider;
|
||||||
@ -40,6 +48,10 @@ pub struct TunConfig {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
|
||||||
|
/// Whether to enable the packet_information option on the tun device.
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub packet_information: bool,
|
||||||
|
|
||||||
/// IP addresses for the tunnel interface.
|
/// IP addresses for the tunnel interface.
|
||||||
pub addresses: Vec<IpAddr>,
|
pub addresses: Vec<IpAddr>,
|
||||||
|
|
||||||
@ -95,6 +107,8 @@ pub fn blocking_config() -> TunConfig {
|
|||||||
TunConfig {
|
TunConfig {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
name: None,
|
name: None,
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
packet_information: false,
|
||||||
addresses: vec![IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))],
|
addresses: vec![IpAddr::V4(Ipv4Addr::new(10, 0, 0, 1))],
|
||||||
mtu: 1380,
|
mtu: 1380,
|
||||||
ipv4_gateway: Ipv4Addr::new(10, 64, 0, 1),
|
ipv4_gateway: Ipv4Addr::new(10, 64, 0, 1),
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
use super::TunConfig;
|
use super::TunConfig;
|
||||||
|
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
/// Error stub.
|
/// Error stub.
|
||||||
pub enum Error {}
|
pub enum Error {
|
||||||
|
/// IO error
|
||||||
|
#[error("IO error")]
|
||||||
|
Io(#[from] std::io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
/// Factory stub of tunnel devices.
|
/// Factory stub of tunnel devices.
|
||||||
pub struct StubTunProvider;
|
pub struct StubTunProvider;
|
||||||
|
@ -1,189 +1,393 @@
|
|||||||
use super::TunConfig;
|
#[cfg(not(feature = "boringtun"))]
|
||||||
use std::{
|
pub use tun05_imp::{Error, UnixTun, UnixTunProvider};
|
||||||
net::IpAddr,
|
#[cfg(feature = "boringtun")]
|
||||||
ops::Deref,
|
pub use tun07_imp::{Error, UnixTun, UnixTunProvider};
|
||||||
os::unix::io::{AsRawFd, RawFd},
|
#[cfg(not(feature = "boringtun"))]
|
||||||
process::Command,
|
mod tun05_imp {
|
||||||
};
|
use std::{
|
||||||
use tun::{Configuration, Device};
|
net::IpAddr,
|
||||||
|
ops::Deref,
|
||||||
|
os::unix::io::{AsRawFd, RawFd},
|
||||||
|
process::Command,
|
||||||
|
};
|
||||||
|
use tun::{Configuration, Device};
|
||||||
|
|
||||||
/// Errors that can occur while setting up a tunnel device.
|
use crate::tun_provider::TunConfig;
|
||||||
#[derive(Debug, thiserror::Error)]
|
|
||||||
pub enum Error {
|
|
||||||
/// Failed to set IPv4 address on tunnel device
|
|
||||||
#[error("Failed to set IPv4 address")]
|
|
||||||
SetIpv4(#[source] tun::Error),
|
|
||||||
|
|
||||||
/// Failed to set IPv6 address on tunnel device
|
/// Errors that can occur while setting up a tunnel device.
|
||||||
#[error("Failed to set IPv6 address")]
|
#[derive(Debug, thiserror::Error)]
|
||||||
SetIpv6(#[source] std::io::Error),
|
pub enum Error {
|
||||||
|
/// Failed to set IPv4 address on tunnel device
|
||||||
|
#[error("Failed to set IPv4 address")]
|
||||||
|
SetIpv4(#[source] tun::Error),
|
||||||
|
|
||||||
/// Unable to open a tunnel device
|
/// Failed to set IPv6 address on tunnel device
|
||||||
#[error("Unable to open a tunnel device")]
|
#[error("Failed to set IPv6 address")]
|
||||||
CreateDevice(#[source] tun::Error),
|
SetIpv6(#[source] std::io::Error),
|
||||||
|
|
||||||
/// Failed to enable/disable link device
|
/// Unable to open a tunnel device
|
||||||
#[error("Failed to enable/disable link device")]
|
#[error("Unable to open a tunnel device")]
|
||||||
ToggleDevice(#[source] tun::Error),
|
CreateDevice(#[source] tun::Error),
|
||||||
|
|
||||||
/// Failed to get device name
|
/// Failed to enable/disable link device
|
||||||
#[error("Failed to get tunnel device name")]
|
#[error("Failed to enable/disable link device")]
|
||||||
GetDeviceName(#[source] tun::Error),
|
ToggleDevice(#[source] tun::Error),
|
||||||
}
|
|
||||||
|
|
||||||
/// Factory of tunnel devices on Unix systems.
|
/// Failed to get device name
|
||||||
pub struct UnixTunProvider {
|
#[error("Failed to get tunnel device name")]
|
||||||
config: TunConfig,
|
GetDeviceName(#[source] tun::Error),
|
||||||
}
|
|
||||||
|
|
||||||
impl UnixTunProvider {
|
|
||||||
pub const fn new(config: TunConfig) -> Self {
|
|
||||||
UnixTunProvider { config }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current tunnel config. Note that the tunnel must be recreated for any changes to
|
/// Factory of tunnel devices on Unix systems.
|
||||||
/// take effect.
|
pub struct UnixTunProvider {
|
||||||
pub fn config_mut(&mut self) -> &mut TunConfig {
|
config: TunConfig,
|
||||||
&mut self.config
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open a tunnel using the current tunnel config.
|
impl UnixTunProvider {
|
||||||
pub fn open_tun(&mut self) -> Result<UnixTun, Error> {
|
pub const fn new(config: TunConfig) -> Self {
|
||||||
let mut tunnel_device = {
|
UnixTunProvider { config }
|
||||||
#[allow(unused_mut)]
|
}
|
||||||
let mut builder = TunnelDeviceBuilder::default();
|
|
||||||
#[cfg(target_os = "linux")]
|
/// Get the current tunnel config. Note that the tunnel must be recreated for any changes to
|
||||||
{
|
/// take effect.
|
||||||
builder.enable_packet_information();
|
pub fn config_mut(&mut self) -> &mut TunConfig {
|
||||||
if let Some(ref name) = self.config.name {
|
&mut self.config
|
||||||
builder.name(name);
|
}
|
||||||
|
|
||||||
|
/// Open a tunnel using the current tunnel config.
|
||||||
|
pub fn open_tun(&mut self) -> Result<UnixTun, Error> {
|
||||||
|
let mut tunnel_device = {
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut builder = TunnelDeviceBuilder::default();
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
builder.enable_packet_information();
|
||||||
|
if let Some(ref name) = self.config.name {
|
||||||
|
builder.name(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.create()?
|
||||||
|
};
|
||||||
|
|
||||||
|
for ip in self.config.addresses.iter() {
|
||||||
|
tunnel_device.set_ip(*ip)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
tunnel_device.set_up(true)?;
|
||||||
|
|
||||||
|
Ok(UnixTun(tunnel_device))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic tunnel device.
|
||||||
|
///
|
||||||
|
/// Contains the file descriptor representing the device.
|
||||||
|
pub struct UnixTun(TunnelDevice);
|
||||||
|
|
||||||
|
impl UnixTun {
|
||||||
|
/// Retrieve the tunnel interface name.
|
||||||
|
pub fn interface_name(&self) -> Result<String, Error> {
|
||||||
|
self.get_name()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for UnixTun {
|
||||||
|
type Target = TunnelDevice;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A tunnel device
|
||||||
|
pub struct TunnelDevice {
|
||||||
|
dev: tun::AsyncDevice,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A tunnel device builder.
|
||||||
|
///
|
||||||
|
/// Call [`Self::create`] to create [`TunnelDevice`] from the config.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct TunnelDeviceBuilder {
|
||||||
|
config: Configuration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TunnelDeviceBuilder {
|
||||||
|
/// Create a [`TunnelDevice`] from this builder.
|
||||||
|
pub fn create(self) -> Result<TunnelDevice, Error> {
|
||||||
|
let dev = tun::create_as_async(&self.config).map_err(Error::CreateDevice)?;
|
||||||
|
Ok(TunnelDevice { dev })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a custom name for this tunnel device.
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn name(&mut self, name: &str) -> &mut Self {
|
||||||
|
self.config.name(name);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable packet information.
|
||||||
|
/// When enabled the first 4 bytes of each packet is a header with flags and protocol type.
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn enable_packet_information(&mut self) -> &mut Self {
|
||||||
|
self.config.platform(|config| {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
// NOTE: This function does seemingly have an effect on Linux, despite what the deprecation
|
||||||
|
// warning says.
|
||||||
|
config.packet_information(true);
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for TunnelDevice {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.dev.get_ref().as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TunnelDevice {
|
||||||
|
fn set_ip(&mut self, ip: IpAddr) -> Result<(), Error> {
|
||||||
|
match ip {
|
||||||
|
IpAddr::V4(ipv4) => {
|
||||||
|
self.dev
|
||||||
|
.get_mut()
|
||||||
|
.set_address(ipv4)
|
||||||
|
.map_err(Error::SetIpv4)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: On MacOs, As of `tun 0.7`, `Device::set_address` accepts an `IpAddr` but
|
||||||
|
// only supports the `IpAddr::V4` address kind and panics if you pass it an
|
||||||
|
// `IpAddr::V6` value.
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
IpAddr::V6(ipv6) => {
|
||||||
|
// ifconfig <device> inet6 <ipv6 address> alias
|
||||||
|
let ipv6 = ipv6.to_string();
|
||||||
|
let device = self.dev.get_ref().name();
|
||||||
|
Command::new("ifconfig")
|
||||||
|
.args([device, "inet6", &ipv6, "alias"])
|
||||||
|
.output()
|
||||||
|
.map_err(Error::SetIpv6)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: On Linux, As of `tun 0.7`, `Device::set_address` throws an I/O error if you
|
||||||
|
// pass it an IPv6-address.
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
IpAddr::V6(ipv6) => {
|
||||||
|
// ip -6 addr add <ipv6 address> dev <device>
|
||||||
|
let ipv6 = ipv6.to_string();
|
||||||
|
let device = self.dev.get_ref().name();
|
||||||
|
Command::new("ip")
|
||||||
|
.args(["-6", "addr", "add", &ipv6, "dev", device])
|
||||||
|
.output()
|
||||||
|
.map_err(Error::SetIpv6)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
builder.create()?
|
Ok(())
|
||||||
};
|
|
||||||
|
|
||||||
for ip in self.config.addresses.iter() {
|
|
||||||
tunnel_device.set_ip(*ip)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tunnel_device.set_up(true)?;
|
fn set_up(&mut self, up: bool) -> Result<(), Error> {
|
||||||
|
self.dev.get_mut().enabled(up).map_err(Error::ToggleDevice)
|
||||||
Ok(UnixTun(tunnel_device))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Generic tunnel device.
|
|
||||||
///
|
|
||||||
/// Contains the file descriptor representing the device.
|
|
||||||
pub struct UnixTun(TunnelDevice);
|
|
||||||
|
|
||||||
impl UnixTun {
|
|
||||||
/// Retrieve the tunnel interface name.
|
|
||||||
pub fn interface_name(&self) -> Result<String, Error> {
|
|
||||||
self.get_name()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for UnixTun {
|
|
||||||
type Target = TunnelDevice;
|
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A tunnel device
|
|
||||||
pub struct TunnelDevice {
|
|
||||||
dev: tun::AsyncDevice,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A tunnel device builder.
|
|
||||||
///
|
|
||||||
/// Call [`Self::create`] to create [`TunnelDevice`] from the config.
|
|
||||||
#[derive(Default)]
|
|
||||||
pub struct TunnelDeviceBuilder {
|
|
||||||
config: Configuration,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TunnelDeviceBuilder {
|
|
||||||
/// Create a [`TunnelDevice`] from this builder.
|
|
||||||
pub fn create(self) -> Result<TunnelDevice, Error> {
|
|
||||||
let dev = tun::create_as_async(&self.config).map_err(Error::CreateDevice)?;
|
|
||||||
Ok(TunnelDevice { dev })
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set a custom name for this tunnel device.
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub fn name(&mut self, name: &str) -> &mut Self {
|
|
||||||
self.config.name(name);
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Enable packet information.
|
|
||||||
/// When enabled the first 4 bytes of each packet is a header with flags and protocol type.
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
pub fn enable_packet_information(&mut self) -> &mut Self {
|
|
||||||
self.config.platform(|config| {
|
|
||||||
#[allow(deprecated)]
|
|
||||||
// NOTE: This function does seemingly have an effect on Linux, despite what the deprecation
|
|
||||||
// warning says.
|
|
||||||
config.packet_information(true);
|
|
||||||
});
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsRawFd for TunnelDevice {
|
|
||||||
fn as_raw_fd(&self) -> RawFd {
|
|
||||||
self.dev.get_ref().as_raw_fd()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TunnelDevice {
|
|
||||||
fn set_ip(&mut self, ip: IpAddr) -> Result<(), Error> {
|
|
||||||
match ip {
|
|
||||||
IpAddr::V4(ipv4) => {
|
|
||||||
self.dev
|
|
||||||
.get_mut()
|
|
||||||
.set_address(ipv4)
|
|
||||||
.map_err(Error::SetIpv4)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: On MacOs, As of `tun 0.7`, `Device::set_address` accepts an `IpAddr` but
|
|
||||||
// only supports the `IpAddr::V4` address kind and panics if you pass it an
|
|
||||||
// `IpAddr::V6` value.
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
IpAddr::V6(ipv6) => {
|
|
||||||
// ifconfig <device> inet6 <ipv6 address> alias
|
|
||||||
let ipv6 = ipv6.to_string();
|
|
||||||
let device = self.dev.get_ref().name();
|
|
||||||
Command::new("ifconfig")
|
|
||||||
.args([device, "inet6", &ipv6, "alias"])
|
|
||||||
.output()
|
|
||||||
.map_err(Error::SetIpv6)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE: On Linux, As of `tun 0.7`, `Device::set_address` throws an I/O error if you
|
|
||||||
// pass it an IPv6-address.
|
|
||||||
#[cfg(target_os = "linux")]
|
|
||||||
IpAddr::V6(ipv6) => {
|
|
||||||
// ip -6 addr add <ipv6 address> dev <device>
|
|
||||||
let ipv6 = ipv6.to_string();
|
|
||||||
let device = self.dev.get_ref().name();
|
|
||||||
Command::new("ip")
|
|
||||||
.args(["-6", "addr", "add", &ipv6, "dev", device])
|
|
||||||
.output()
|
|
||||||
.map_err(Error::SetIpv6)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_up(&mut self, up: bool) -> Result<(), Error> {
|
fn get_name(&self) -> Result<String, Error> {
|
||||||
self.dev.get_mut().enabled(up).map_err(Error::ToggleDevice)
|
Ok(self.dev.get_ref().name().to_owned())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
fn get_name(&self) -> Result<String, Error> {
|
}
|
||||||
Ok(self.dev.get_ref().name().to_owned())
|
|
||||||
|
#[cfg(feature = "boringtun")]
|
||||||
|
mod tun07_imp {
|
||||||
|
use std::net::IpAddr;
|
||||||
|
use std::os::fd::{AsRawFd, RawFd};
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
use tun07::{AbstractDevice, AsyncDevice};
|
||||||
|
|
||||||
|
use crate::tun_provider::TunConfig;
|
||||||
|
|
||||||
|
/// Errors that can occur while setting up a tunnel device.
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Failed to set IPv4 address on tunnel device
|
||||||
|
#[error("Failed to set IPv4 address")]
|
||||||
|
SetIpv4(#[source] tun07::Error),
|
||||||
|
|
||||||
|
/// Failed to set IPv6 address on tunnel device
|
||||||
|
#[error("Failed to set IPv6 address")]
|
||||||
|
SetIpv6(#[source] std::io::Error),
|
||||||
|
|
||||||
|
/// Unable to open a tunnel device
|
||||||
|
#[error("Unable to open a tunnel device")]
|
||||||
|
CreateDevice(#[source] tun07::Error),
|
||||||
|
|
||||||
|
/// Failed to enable/disable link device
|
||||||
|
#[error("Failed to enable/disable link device")]
|
||||||
|
ToggleDevice(#[source] tun07::Error),
|
||||||
|
|
||||||
|
/// Failed to get device name
|
||||||
|
#[error("Failed to get tunnel device name")]
|
||||||
|
GetDeviceName(#[source] tun07::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Factory of tunnel devices on Unix systems.
|
||||||
|
pub struct UnixTunProvider {
|
||||||
|
pub(crate) config: TunConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UnixTunProvider {
|
||||||
|
pub const fn new(config: TunConfig) -> Self {
|
||||||
|
UnixTunProvider { config }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current tunnel config. Note that the tunnel must be recreated for any changes to
|
||||||
|
/// take effect.
|
||||||
|
pub fn config_mut(&mut self) -> &mut TunConfig {
|
||||||
|
&mut self.config
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open a tunnel using the current tunnel config.
|
||||||
|
pub fn open_tun(&mut self) -> Result<UnixTun, Error> {
|
||||||
|
let mut tunnel_device = {
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut builder = TunnelDeviceBuilder::default();
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
if self.config.packet_information {
|
||||||
|
builder.enable_packet_information();
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ref name) = self.config.name {
|
||||||
|
builder.name(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
builder.create()?
|
||||||
|
};
|
||||||
|
|
||||||
|
for ip in self.config.addresses.iter() {
|
||||||
|
tunnel_device.set_ip(*ip)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
tunnel_device.set_up(true)?;
|
||||||
|
|
||||||
|
Ok(UnixTun(tunnel_device))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic tunnel device.
|
||||||
|
///
|
||||||
|
/// Contains the file descriptor representing the device.
|
||||||
|
pub struct UnixTun(TunnelDevice);
|
||||||
|
|
||||||
|
impl UnixTun {
|
||||||
|
/// Retrieve the tunnel interface name.
|
||||||
|
pub fn interface_name(&self) -> Result<String, Error> {
|
||||||
|
self.get_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_inner(self) -> TunnelDevice {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for UnixTun {
|
||||||
|
type Target = TunnelDevice;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A tunnel device
|
||||||
|
pub struct TunnelDevice {
|
||||||
|
pub(crate) dev: tun07::AsyncDevice,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A tunnel device builder.
|
||||||
|
///
|
||||||
|
/// Call [`Self::create`] to create [`TunnelDevice`] from the config.
|
||||||
|
#[derive(Default)]
|
||||||
|
pub struct TunnelDeviceBuilder {
|
||||||
|
pub(crate) config: tun07::Configuration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TunnelDeviceBuilder {
|
||||||
|
/// Create a [`TunnelDevice`] from this builder.
|
||||||
|
pub fn create(self) -> Result<TunnelDevice, Error> {
|
||||||
|
let dev = tun07::create_as_async(&self.config).map_err(Error::CreateDevice)?;
|
||||||
|
Ok(TunnelDevice { dev })
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a custom name for this tunnel device.
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn name(&mut self, name: &str) -> &mut Self {
|
||||||
|
self.config.tun_name(name);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Enable packet information.
|
||||||
|
/// When enabled the first 4 bytes of each packet is a header with flags and protocol type.
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
pub fn enable_packet_information(&mut self) -> &mut Self {
|
||||||
|
self.config.platform_config(|config| {
|
||||||
|
#[allow(deprecated)]
|
||||||
|
// NOTE: This function does seemingly have an effect on Linux, despite what the deprecation
|
||||||
|
// warning says.
|
||||||
|
config.packet_information(true);
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRawFd for TunnelDevice {
|
||||||
|
fn as_raw_fd(&self) -> RawFd {
|
||||||
|
self.dev.as_raw_fd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TunnelDevice {
|
||||||
|
pub(crate) fn set_ip(&mut self, ip: IpAddr) -> Result<(), Error> {
|
||||||
|
match ip {
|
||||||
|
IpAddr::V4(ipv4) => {
|
||||||
|
self.dev.set_address(ipv4.into()).map_err(Error::SetIpv4)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: As of `tun 0.7`, `Device::set_address` accepts an `IpAddr` but
|
||||||
|
// only supports the `IpAddr::V4`.
|
||||||
|
// On MacOs, `Device::set_address` panics if you pass it an `IpAddr::V6` value.
|
||||||
|
// On Linux, `Device::set_address` throws an I/O error if you pass it an IPv6-address.
|
||||||
|
IpAddr::V6(ipv6) => {
|
||||||
|
let ipv6 = ipv6.to_string();
|
||||||
|
let device = self.get_name()?;
|
||||||
|
// ifconfig <device> inet6 <ipv6 address> alias
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
Command::new("ifconfig")
|
||||||
|
.args([&device, "inet6", &ipv6, "alias"])
|
||||||
|
.output()
|
||||||
|
.map_err(Error::SetIpv6)?;
|
||||||
|
// ip -6 addr add <ipv6 address> dev <device>
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
Command::new("ip")
|
||||||
|
.args(["-6", "addr", "add", &ipv6, "dev", &device])
|
||||||
|
.output()
|
||||||
|
.map_err(Error::SetIpv6)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn set_up(&mut self, up: bool) -> Result<(), Error> {
|
||||||
|
self.dev.enabled(up).map_err(Error::ToggleDevice)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn get_name(&self) -> Result<String, Error> {
|
||||||
|
self.dev.tun_name().map_err(Error::GetDeviceName)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_inner(self) -> AsyncDevice {
|
||||||
|
self.dev
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
141
talpid-tunnel/src/tun_provider/windows.rs
Normal file
141
talpid-tunnel/src/tun_provider/windows.rs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
use super::TunConfig;
|
||||||
|
use std::{io, net::IpAddr, ops::Deref};
|
||||||
|
use tun07 as tun;
|
||||||
|
use tun07::{AbstractDevice, AsyncDevice, Configuration};
|
||||||
|
|
||||||
|
/// Errors that can occur while setting up a tunnel device.
|
||||||
|
#[derive(Debug, thiserror::Error)]
|
||||||
|
pub enum Error {
|
||||||
|
/// Failed to set IP address
|
||||||
|
#[error("Failed to set IPv4 address")]
|
||||||
|
SetIpv4(#[source] tun::Error),
|
||||||
|
|
||||||
|
/// Failed to set IP address
|
||||||
|
#[error("Failed to set IPv6 address")]
|
||||||
|
SetIpv6(#[source] io::Error),
|
||||||
|
|
||||||
|
/// Unable to open a tunnel device
|
||||||
|
#[error("Unable to open a tunnel device")]
|
||||||
|
CreateDevice(#[source] tun::Error),
|
||||||
|
|
||||||
|
/// Failed to enable/disable link device
|
||||||
|
#[error("Failed to enable/disable link device")]
|
||||||
|
ToggleDevice(#[source] tun::Error),
|
||||||
|
|
||||||
|
/// Failed to get device name
|
||||||
|
#[error("Failed to get tunnel device name")]
|
||||||
|
GetDeviceName(#[source] tun::Error),
|
||||||
|
|
||||||
|
/// IO error
|
||||||
|
#[error("IO error")]
|
||||||
|
Io(#[from] io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Factory of tunnel devices on Unix systems.
|
||||||
|
pub struct WindowsTunProvider {
|
||||||
|
config: TunConfig,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowsTunProvider {
|
||||||
|
pub const fn new(config: TunConfig) -> Self {
|
||||||
|
WindowsTunProvider { config }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the current tunnel config. Note that the tunnel must be recreated for any changes to
|
||||||
|
/// take effect.
|
||||||
|
pub fn config_mut(&mut self) -> &mut TunConfig {
|
||||||
|
&mut self.config
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Open a tunnel using the current tunnel config.
|
||||||
|
pub fn open_tun(&mut self) -> Result<WindowsTun, Error> {
|
||||||
|
let mut tunnel_device = {
|
||||||
|
#[allow(unused_mut)]
|
||||||
|
let mut builder = TunnelDeviceBuilder::default();
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
if let Some(ref name) = self.config.name {
|
||||||
|
builder.name(name);
|
||||||
|
}
|
||||||
|
builder.create()?
|
||||||
|
};
|
||||||
|
|
||||||
|
for ip in self.config.addresses.iter() {
|
||||||
|
tunnel_device.set_ip(*ip)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
tunnel_device.set_up(true)?;
|
||||||
|
|
||||||
|
Ok(WindowsTun(tunnel_device))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generic tunnel device.
|
||||||
|
///
|
||||||
|
/// Contains the file descriptor representing the device.
|
||||||
|
pub struct WindowsTun(TunnelDevice);
|
||||||
|
|
||||||
|
impl WindowsTun {
|
||||||
|
/// Retrieve the tunnel interface name.
|
||||||
|
pub fn interface_name(&self) -> Result<String, Error> {
|
||||||
|
self.get_name()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_inner(self) -> AsyncDevice {
|
||||||
|
AsyncDevice::new(self.0.dev).unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for WindowsTun {
|
||||||
|
type Target = TunnelDevice;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A tunnel device
|
||||||
|
pub struct TunnelDevice {
|
||||||
|
dev: tun::Device,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A tunnel device builder.
|
||||||
|
///
|
||||||
|
/// Call [`Self::create`] to create [`TunnelDevice`] from the config.
|
||||||
|
pub struct TunnelDeviceBuilder {
|
||||||
|
config: Configuration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TunnelDeviceBuilder {
|
||||||
|
/// Create a [`TunnelDevice`] from this builder.
|
||||||
|
pub fn create(self) -> Result<TunnelDevice, Error> {
|
||||||
|
let dev = tun::create(&self.config).map_err(Error::CreateDevice)?;
|
||||||
|
Ok(TunnelDevice { dev })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for TunnelDeviceBuilder {
|
||||||
|
fn default() -> Self {
|
||||||
|
let config = Configuration::default();
|
||||||
|
Self { config }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TunnelDevice {
|
||||||
|
fn set_ip(&mut self, ip: IpAddr) -> Result<(), Error> {
|
||||||
|
match ip {
|
||||||
|
IpAddr::V4(ipv4) => self.dev.set_address(ipv4.into()).map_err(Error::SetIpv4),
|
||||||
|
IpAddr::V6(_ipv6) => {
|
||||||
|
// TODO
|
||||||
|
todo!("ipv6 not implemented");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_up(&mut self, up: bool) -> Result<(), Error> {
|
||||||
|
self.dev.enabled(up).map_err(Error::ToggleDevice)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_name(&self) -> Result<String, Error> {
|
||||||
|
self.dev.tun_name().map_err(Error::GetDeviceName)
|
||||||
|
}
|
||||||
|
}
|
@ -10,6 +10,9 @@ rust-version.workspace = true
|
|||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
|
[features]
|
||||||
|
boringtun = ["dep:boringtun", "dep:tun07", "talpid-tunnel/boringtun"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
async-trait = "0.1"
|
async-trait = "0.1"
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
@ -30,12 +33,21 @@ tunnel-obfuscation = { path = "../tunnel-obfuscation" }
|
|||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
surge-ping = "0.8.0"
|
surge-ping = "0.8.0"
|
||||||
rand_chacha = "0.3.1"
|
rand_chacha = "0.3.1"
|
||||||
wireguard-go-rs = { path = "../wireguard-go-rs"}
|
wireguard-go-rs = { path = "../wireguard-go-rs" }
|
||||||
|
tun07 = { package = "tun", version = "0.7.11", features = [
|
||||||
|
"async",
|
||||||
|
], optional = true }
|
||||||
byteorder = "1"
|
byteorder = "1"
|
||||||
internet-checksum = "0.2"
|
internet-checksum = "0.2"
|
||||||
socket2 = { workspace = true, features = ["all"] }
|
socket2 = { workspace = true, features = ["all"] }
|
||||||
tokio-stream = { version = "0.1", features = ["io-util"] }
|
tokio-stream = { version = "0.1", features = ["io-util"] }
|
||||||
|
|
||||||
|
[dependencies.boringtun]
|
||||||
|
optional = true
|
||||||
|
features = ["device"]
|
||||||
|
git = "https://github.com/mullvad/boringtun"
|
||||||
|
rev = "a7e11fb46d4a"
|
||||||
|
|
||||||
[target.'cfg(unix)'.dependencies]
|
[target.'cfg(unix)'.dependencies]
|
||||||
nix = "0.23"
|
nix = "0.23"
|
||||||
libc = "0.2.150"
|
libc = "0.2.150"
|
||||||
@ -61,27 +73,27 @@ maybenot = "2.0.0"
|
|||||||
[target.'cfg(windows)'.dependencies.windows-sys]
|
[target.'cfg(windows)'.dependencies.windows-sys]
|
||||||
workspace = true
|
workspace = true
|
||||||
features = [
|
features = [
|
||||||
"Win32_Foundation",
|
"Win32_Foundation",
|
||||||
"Win32_Globalization",
|
"Win32_Globalization",
|
||||||
"Win32_Security",
|
"Win32_Security",
|
||||||
"Win32_System_Com",
|
"Win32_System_Com",
|
||||||
"Win32_System_Diagnostics_ToolHelp",
|
"Win32_System_Diagnostics_ToolHelp",
|
||||||
"Win32_System_Ioctl",
|
"Win32_System_Ioctl",
|
||||||
"Win32_System_IO",
|
"Win32_System_IO",
|
||||||
"Win32_System_LibraryLoader",
|
"Win32_System_LibraryLoader",
|
||||||
"Win32_System_ProcessStatus",
|
"Win32_System_ProcessStatus",
|
||||||
"Win32_System_Registry",
|
"Win32_System_Registry",
|
||||||
"Win32_System_Services",
|
"Win32_System_Services",
|
||||||
"Win32_System_SystemServices",
|
"Win32_System_SystemServices",
|
||||||
"Win32_System_Threading",
|
"Win32_System_Threading",
|
||||||
"Win32_System_WindowsProgramming",
|
"Win32_System_WindowsProgramming",
|
||||||
"Win32_Networking_WinSock",
|
"Win32_Networking_WinSock",
|
||||||
"Win32_NetworkManagement_IpHelper",
|
"Win32_NetworkManagement_IpHelper",
|
||||||
"Win32_NetworkManagement_Ndis",
|
"Win32_NetworkManagement_Ndis",
|
||||||
"Win32_UI_Shell",
|
"Win32_UI_Shell",
|
||||||
"Win32_UI_WindowsAndMessaging",
|
"Win32_UI_WindowsAndMessaging",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
proptest = { workspace = true }
|
proptest = { workspace = true }
|
||||||
tokio = { workspace = true, features = [ "test-util" ] }
|
tokio = { workspace = true, features = ["test-util"] }
|
||||||
|
@ -6,9 +6,6 @@ fn main() {
|
|||||||
if target_os == "windows" {
|
if target_os == "windows" {
|
||||||
declare_libs_dir("../dist-assets/binaries");
|
declare_libs_dir("../dist-assets/binaries");
|
||||||
}
|
}
|
||||||
// Wireguard-Go can be used on all platforms
|
|
||||||
println!("cargo::rustc-check-cfg=cfg(wireguard_go)");
|
|
||||||
println!("cargo::rustc-cfg=wireguard_go");
|
|
||||||
|
|
||||||
// Enable DAITA by default on desktop and android
|
// Enable DAITA by default on desktop and android
|
||||||
println!("cargo::rustc-check-cfg=cfg(daita)");
|
println!("cargo::rustc-check-cfg=cfg(daita)");
|
||||||
|
314
talpid-wireguard/src/boringtun/mod.rs
Normal file
314
talpid-wireguard/src/boringtun/mod.rs
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
use crate::{
|
||||||
|
config::Config,
|
||||||
|
stats::{Stats, StatsMap},
|
||||||
|
Tunnel, TunnelError,
|
||||||
|
};
|
||||||
|
use boringtun::device::{
|
||||||
|
api::{command::*, ApiClient, ApiServer},
|
||||||
|
peer::AllowedIP,
|
||||||
|
DeviceConfig, DeviceHandle,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
use ipnetwork::IpNetwork;
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
use std::os::fd::AsRawFd;
|
||||||
|
use std::{
|
||||||
|
future::Future,
|
||||||
|
ops::Deref,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
use talpid_tunnel::tun_provider::{self, Tun, TunProvider};
|
||||||
|
use talpid_tunnel_config_client::DaitaSettings;
|
||||||
|
use tun07::AbstractDevice;
|
||||||
|
|
||||||
|
pub struct BoringTun {
|
||||||
|
device_handle: DeviceHandle,
|
||||||
|
config_tx: ApiClient,
|
||||||
|
config: Config,
|
||||||
|
|
||||||
|
/// Name of the tun interface.
|
||||||
|
interface_name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure and start a boringtun tunnel.
|
||||||
|
pub async fn open_boringtun_tunnel(
|
||||||
|
config: &Config,
|
||||||
|
tun_provider: Arc<Mutex<tun_provider::TunProvider>>,
|
||||||
|
#[cfg(target_os = "android")] route_manager_handle: talpid_routing::RouteManagerHandle,
|
||||||
|
) -> super::Result<BoringTun> {
|
||||||
|
log::info!("BoringTun::start_tunnel");
|
||||||
|
let routes = config.get_tunnel_destinations();
|
||||||
|
|
||||||
|
log::info!("calling get_tunnel_for_userspace");
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
let async_tun = {
|
||||||
|
let tun = get_tunnel_for_userspace(tun_provider, config, routes)?;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
{
|
||||||
|
tun.into_inner().into_inner()
|
||||||
|
}
|
||||||
|
#[cfg(windows)]
|
||||||
|
{
|
||||||
|
tun.into_inner()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let (mut config_tx, config_rx) = ApiServer::new();
|
||||||
|
|
||||||
|
let boringtun_config = DeviceConfig {
|
||||||
|
n_threads: 4,
|
||||||
|
api: Some(config_rx),
|
||||||
|
on_bind: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
let mut boringtun_config = boringtun_config;
|
||||||
|
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
let async_tun = {
|
||||||
|
let _ = routes; // TODO: do we need this?
|
||||||
|
let (mut tun, fd) = get_tunnel_for_userspace(Arc::clone(&tun_provider), config)?;
|
||||||
|
let is_new_tunnel = tun.is_new;
|
||||||
|
|
||||||
|
// TODO We should also wait for routes before sending any ping / connectivity check
|
||||||
|
|
||||||
|
// There is a brief period of time between setting up a Wireguard-go tunnel and the tunnel being ready to serve
|
||||||
|
// traffic. This function blocks until the tunnel starts to serve traffic or until [connectivity::Check] times out.
|
||||||
|
if is_new_tunnel {
|
||||||
|
let expected_routes = tun_provider.lock().unwrap().real_routes();
|
||||||
|
|
||||||
|
route_manager_handle
|
||||||
|
.clone()
|
||||||
|
.wait_for_routes(expected_routes)
|
||||||
|
.await
|
||||||
|
.map_err(crate::Error::SetupRoutingError)
|
||||||
|
.map_err(|e| TunnelError::RecoverableStartWireguardError(Box::new(e)))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut config = tun07::Configuration::default();
|
||||||
|
config.raw_fd(fd);
|
||||||
|
|
||||||
|
boringtun_config.on_bind = Some(Box::new(move |socket| {
|
||||||
|
tun.bypass(socket.as_raw_fd()).unwrap()
|
||||||
|
}));
|
||||||
|
|
||||||
|
let device = tun07::Device::new(&config).unwrap();
|
||||||
|
tun07::AsyncDevice::new(device).unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
let interface_name = async_tun.deref().tun_name().unwrap();
|
||||||
|
|
||||||
|
log::info!("passing tunnel dev to boringtun");
|
||||||
|
let device_handle: DeviceHandle = DeviceHandle::new(async_tun, boringtun_config)
|
||||||
|
.await
|
||||||
|
.map_err(TunnelError::BoringTunDevice)?;
|
||||||
|
|
||||||
|
set_boringtun_config(&mut config_tx, config).await?;
|
||||||
|
|
||||||
|
log::info!(
|
||||||
|
"This tunnel was brought to you by...
|
||||||
|
.........................................................
|
||||||
|
..*...*.. .--. .---. ..*....*.
|
||||||
|
...*..... | ) o | ......*..
|
||||||
|
.*..*..*. |--: .-. .--.. .--. .-..|. . .--. ...*.....
|
||||||
|
...*..... | )( )| | | |( ||| | | | .*.....*.
|
||||||
|
*.....*.. '--' `-' ' -' `-' `-`-`|'`--`-' `- .....*...
|
||||||
|
......... ._.' ..*...*..
|
||||||
|
..*...*.............................................*...."
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(BoringTun {
|
||||||
|
device_handle,
|
||||||
|
config: config.clone(),
|
||||||
|
config_tx,
|
||||||
|
interface_name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl Tunnel for BoringTun {
|
||||||
|
fn get_interface_name(&self) -> String {
|
||||||
|
self.interface_name.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stop(self: Box<Self>) -> Result<(), TunnelError> {
|
||||||
|
log::info!("BoringTun::stop"); // remove me
|
||||||
|
tokio::runtime::Handle::current().block_on(self.device_handle.stop());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_tunnel_stats(&self) -> Result<StatsMap, TunnelError> {
|
||||||
|
let response = self
|
||||||
|
.config_tx
|
||||||
|
.send(Get::default())
|
||||||
|
.await
|
||||||
|
.expect("Failed to get peers");
|
||||||
|
|
||||||
|
let Response::Get(response) = response else {
|
||||||
|
return Err(TunnelError::GetConfigError);
|
||||||
|
};
|
||||||
|
Ok(StatsMap::from_iter(response.peers.into_iter().map(
|
||||||
|
|peer| {
|
||||||
|
(
|
||||||
|
peer.peer.public_key.0,
|
||||||
|
Stats {
|
||||||
|
tx_bytes: peer.tx_bytes.unwrap_or_default(),
|
||||||
|
rx_bytes: peer.rx_bytes.unwrap_or_default(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_config<'a>(
|
||||||
|
&'a mut self,
|
||||||
|
config: Config,
|
||||||
|
) -> std::pin::Pin<Box<dyn Future<Output = Result<(), TunnelError>> + Send + 'a>> {
|
||||||
|
Box::pin(async move {
|
||||||
|
self.config = config;
|
||||||
|
set_boringtun_config(&mut self.config_tx, &self.config).await?;
|
||||||
|
Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start_daita(&mut self, _settings: DaitaSettings) -> Result<(), TunnelError> {
|
||||||
|
log::info!("Haha no");
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn set_boringtun_config(
|
||||||
|
tx: &mut ApiClient,
|
||||||
|
config: &Config,
|
||||||
|
) -> Result<(), crate::TunnelError> {
|
||||||
|
log::info!("configuring boringtun device");
|
||||||
|
let mut set_cmd = Set::builder()
|
||||||
|
.private_key(config.tunnel.private_key.to_bytes())
|
||||||
|
.listen_port(0u16)
|
||||||
|
.replace_peers()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
set_cmd.fwmark = config.fwmark;
|
||||||
|
}
|
||||||
|
|
||||||
|
for peer in config.peers() {
|
||||||
|
let mut boring_peer = Peer::builder()
|
||||||
|
.public_key(*peer.public_key.as_bytes())
|
||||||
|
.endpoint(peer.endpoint)
|
||||||
|
.allowed_ip(
|
||||||
|
peer.allowed_ips
|
||||||
|
.iter()
|
||||||
|
.map(|net| AllowedIP {
|
||||||
|
addr: net.ip(),
|
||||||
|
cidr: net.prefix(),
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
if let Some(psk) = &peer.psk {
|
||||||
|
boring_peer.preshared_key = Some(SetUnset::Set((*psk.as_bytes()).into()));
|
||||||
|
}
|
||||||
|
|
||||||
|
let boring_peer = SetPeer::builder().peer(boring_peer).build();
|
||||||
|
|
||||||
|
set_cmd.peers.push(boring_peer);
|
||||||
|
}
|
||||||
|
|
||||||
|
tx.send(set_cmd).await.map_err(|err| {
|
||||||
|
log::error!("Failed to set boringtun config: {err:#}");
|
||||||
|
TunnelError::SetConfigError
|
||||||
|
})?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
fn get_tunnel_for_userspace(
|
||||||
|
tun_provider: Arc<Mutex<TunProvider>>,
|
||||||
|
config: &Config,
|
||||||
|
routes: impl Iterator<Item = IpNetwork>,
|
||||||
|
) -> Result<Tun, crate::TunnelError> {
|
||||||
|
let mut tun_provider = tun_provider.lock().unwrap();
|
||||||
|
|
||||||
|
let tun_config = tun_provider.config_mut();
|
||||||
|
tun_config.addresses = config.tunnel.addresses.clone();
|
||||||
|
tun_config.ipv4_gateway = config.ipv4_gateway;
|
||||||
|
tun_config.ipv6_gateway = config.ipv6_gateway;
|
||||||
|
tun_config.mtu = config.mtu;
|
||||||
|
|
||||||
|
let _ = routes;
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
tun_provider
|
||||||
|
.open_tun()
|
||||||
|
.map_err(TunnelError::SetupTunnelDevice)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(not(target_os = "android"), unix))]
|
||||||
|
fn get_tunnel_for_userspace(
|
||||||
|
tun_provider: Arc<Mutex<TunProvider>>,
|
||||||
|
config: &Config,
|
||||||
|
routes: impl Iterator<Item = IpNetwork>,
|
||||||
|
) -> Result<Tun, crate::TunnelError> {
|
||||||
|
let mut tun_provider = tun_provider.lock().unwrap();
|
||||||
|
|
||||||
|
let tun_config = tun_provider.config_mut();
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
{
|
||||||
|
tun_config.name = Some(crate::config::MULLVAD_INTERFACE_NAME.to_string());
|
||||||
|
tun_config.packet_information = false;
|
||||||
|
}
|
||||||
|
tun_config.addresses = config.tunnel.addresses.clone();
|
||||||
|
tun_config.ipv4_gateway = config.ipv4_gateway;
|
||||||
|
tun_config.ipv6_gateway = config.ipv6_gateway;
|
||||||
|
tun_config.routes = routes.collect();
|
||||||
|
tun_config.mtu = config.mtu;
|
||||||
|
|
||||||
|
tun_provider
|
||||||
|
.open_tun()
|
||||||
|
.map_err(TunnelError::SetupTunnelDevice)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
pub fn get_tunnel_for_userspace(
|
||||||
|
tun_provider: Arc<Mutex<TunProvider>>,
|
||||||
|
config: &Config,
|
||||||
|
) -> Result<(Tun, std::os::fd::RawFd), TunnelError> {
|
||||||
|
let mut last_error = None;
|
||||||
|
let mut tun_provider = tun_provider.lock().unwrap();
|
||||||
|
|
||||||
|
let tun_config = tun_provider.config_mut();
|
||||||
|
tun_config.addresses = config.tunnel.addresses.clone();
|
||||||
|
tun_config.ipv4_gateway = config.ipv4_gateway;
|
||||||
|
tun_config.ipv6_gateway = config.ipv6_gateway;
|
||||||
|
tun_config.mtu = config.mtu;
|
||||||
|
|
||||||
|
// Route everything into the tunnel and have wireguard-go act as a firewall when
|
||||||
|
// blocking. These will not necessarily be the actual routes used by android. Those will
|
||||||
|
// be generated at a later stage e.g. if Local Network Sharing is enabled.
|
||||||
|
tun_config.routes = vec!["0.0.0.0/0".parse().unwrap(), "::/0".parse().unwrap()];
|
||||||
|
|
||||||
|
const MAX_PREPARE_TUN_ATTEMPTS: usize = 4;
|
||||||
|
|
||||||
|
for _ in 1..=MAX_PREPARE_TUN_ATTEMPTS {
|
||||||
|
let tunnel_device = tun_provider
|
||||||
|
.open_tun()
|
||||||
|
.map_err(TunnelError::SetupTunnelDevice)?;
|
||||||
|
|
||||||
|
match nix::unistd::dup(tunnel_device.as_raw_fd()) {
|
||||||
|
Ok(fd) => return Ok((tunnel_device, fd)),
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
Err(error @ nix::errno::Errno::EBADFD) => last_error = Some(error),
|
||||||
|
Err(error @ nix::errno::Errno::EBADF) => last_error = Some(error),
|
||||||
|
Err(error) => return Err(TunnelError::FdDuplicationError(error)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Err(TunnelError::FdDuplicationError(
|
||||||
|
last_error.expect("Should be collected in loop"),
|
||||||
|
))
|
||||||
|
}
|
@ -1,18 +1,16 @@
|
|||||||
use std::net::Ipv4Addr;
|
use std::{
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
net::Ipv4Addr,
|
||||||
use std::sync::Arc;
|
sync::{
|
||||||
use std::time::Duration;
|
atomic::{AtomicBool, Ordering},
|
||||||
use tokio::sync::broadcast;
|
Arc,
|
||||||
use tokio::time::Instant;
|
},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
use tokio::{sync::broadcast, time::Instant};
|
||||||
|
|
||||||
use super::constants::*;
|
use super::{constants::*, error::Error, pinger};
|
||||||
use super::error::Error;
|
|
||||||
use super::pinger;
|
|
||||||
|
|
||||||
use crate::stats::StatsMap;
|
use crate::{stats::StatsMap, Tunnel, TunnelError};
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
use crate::Tunnel;
|
|
||||||
use crate::{TunnelError, TunnelType};
|
|
||||||
use pinger::Pinger;
|
use pinger::Pinger;
|
||||||
|
|
||||||
/// Verifies if a connection to a tunnel is working.
|
/// Verifies if a connection to a tunnel is working.
|
||||||
@ -132,7 +130,7 @@ impl Check {
|
|||||||
// successful at the start of a connection.
|
// successful at the start of a connection.
|
||||||
pub async fn establish_connectivity(
|
pub async fn establish_connectivity(
|
||||||
&mut self,
|
&mut self,
|
||||||
tunnel_handle: &TunnelType,
|
tunnel_handle: &dyn Tunnel,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
// Send initial ping to prod WireGuard into connecting.
|
// Send initial ping to prod WireGuard into connecting.
|
||||||
self.ping_state
|
self.ping_state
|
||||||
@ -161,7 +159,7 @@ impl Check {
|
|||||||
timeout_initial: Duration,
|
timeout_initial: Duration,
|
||||||
timeout_multiplier: u32,
|
timeout_multiplier: u32,
|
||||||
max_timeout: Duration,
|
max_timeout: Duration,
|
||||||
tunnel_handle: &TunnelType,
|
tunnel_handle: &dyn Tunnel,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
if self.conn_state.connected() {
|
if self.conn_state.connected() {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
@ -226,7 +224,7 @@ impl Check {
|
|||||||
pub(crate) async fn check_connectivity(
|
pub(crate) async fn check_connectivity(
|
||||||
&mut self,
|
&mut self,
|
||||||
now: Instant,
|
now: Instant,
|
||||||
tunnel_handle: &TunnelType,
|
tunnel_handle: &dyn Tunnel,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
Self::check_connectivity_interval(
|
Self::check_connectivity_interval(
|
||||||
&mut self.conn_state,
|
&mut self.conn_state,
|
||||||
@ -244,7 +242,7 @@ impl Check {
|
|||||||
ping_state: &mut PingState,
|
ping_state: &mut PingState,
|
||||||
now: Instant,
|
now: Instant,
|
||||||
timeout: Duration,
|
timeout: Duration,
|
||||||
tunnel_handle: &TunnelType,
|
tunnel_handle: &dyn Tunnel,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
match Self::get_stats(tunnel_handle)
|
match Self::get_stats(tunnel_handle)
|
||||||
.await
|
.await
|
||||||
@ -265,7 +263,7 @@ impl Check {
|
|||||||
|
|
||||||
/// If None is returned, then the underlying tunnel has already been closed and all subsequent
|
/// If None is returned, then the underlying tunnel has already been closed and all subsequent
|
||||||
/// calls will also return None.
|
/// calls will also return None.
|
||||||
async fn get_stats(tunnel_handle: &TunnelType) -> Result<Option<StatsMap>, TunnelError> {
|
async fn get_stats(tunnel_handle: &dyn Tunnel) -> Result<Option<StatsMap>, TunnelError> {
|
||||||
let stats = tunnel_handle.get_tunnel_stats().await?;
|
let stats = tunnel_handle.get_tunnel_stats().await?;
|
||||||
if stats.is_empty() {
|
if stats.is_empty() {
|
||||||
log::error!("Tunnel unexpectedly shut down");
|
log::error!("Tunnel unexpectedly shut down");
|
||||||
@ -604,7 +602,10 @@ mod test {
|
|||||||
Check::maybe_send_ping(&mut checker.conn_state, &mut checker.ping_state, start)
|
Check::maybe_send_ping(&mut checker.conn_state, &mut checker.ping_state, start)
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(!checker.check_connectivity(now, &tunnel).await.unwrap())
|
assert!(!checker
|
||||||
|
.check_connectivity(now, tunnel.as_ref())
|
||||||
|
.await
|
||||||
|
.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@ -617,7 +618,10 @@ mod test {
|
|||||||
let start = now.checked_sub(Duration::from_secs(1)).unwrap();
|
let start = now.checked_sub(Duration::from_secs(1)).unwrap();
|
||||||
let (mut checker, _cancel_token) = mock_checker(start, Box::new(pinger));
|
let (mut checker, _cancel_token) = mock_checker(start, Box::new(pinger));
|
||||||
|
|
||||||
assert!(!checker.check_connectivity(now, &tunnel).await.unwrap())
|
assert!(!checker
|
||||||
|
.check_connectivity(now, tunnel.as_ref())
|
||||||
|
.await
|
||||||
|
.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@ -633,7 +637,10 @@ mod test {
|
|||||||
// Mock the state - connectivity has been established
|
// Mock the state - connectivity has been established
|
||||||
checker.conn_state = connected_state(start);
|
checker.conn_state = connected_state(start);
|
||||||
|
|
||||||
assert!(checker.check_connectivity(now, &tunnel).await.unwrap())
|
assert!(checker
|
||||||
|
.check_connectivity(now, tunnel.as_ref())
|
||||||
|
.await
|
||||||
|
.unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test(start_paused = true)]
|
#[tokio::test(start_paused = true)]
|
||||||
@ -671,7 +678,7 @@ mod test {
|
|||||||
ESTABLISH_TIMEOUT,
|
ESTABLISH_TIMEOUT,
|
||||||
ESTABLISH_TIMEOUT_MULTIPLIER,
|
ESTABLISH_TIMEOUT_MULTIPLIER,
|
||||||
MAX_ESTABLISH_TIMEOUT,
|
MAX_ESTABLISH_TIMEOUT,
|
||||||
&tunnel,
|
tunnel.as_ref(),
|
||||||
)
|
)
|
||||||
.await,
|
.await,
|
||||||
)
|
)
|
||||||
|
@ -6,7 +6,7 @@ mod mock;
|
|||||||
mod monitor;
|
mod monitor;
|
||||||
mod pinger;
|
mod pinger;
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(all(target_os = "android", not(feature = "boringtun")))]
|
||||||
pub use check::CancelReceiver;
|
pub use check::CancelReceiver;
|
||||||
pub use check::{CancelToken, Check};
|
pub use check::{CancelToken, Check};
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
use std::{sync::Weak, time::Duration};
|
use std::{sync::Weak, time::Duration};
|
||||||
|
|
||||||
use tokio::sync::Mutex;
|
use tokio::{
|
||||||
use tokio::time::{Instant, MissedTickBehavior};
|
sync::Mutex,
|
||||||
|
time::{Instant, MissedTickBehavior},
|
||||||
|
};
|
||||||
|
|
||||||
use crate::TunnelType;
|
use crate::TunnelType;
|
||||||
|
|
||||||
use super::check::Check;
|
use super::{check::Check, error::Error};
|
||||||
use super::error::Error;
|
|
||||||
|
|
||||||
/// Sleep time used when checking if an established connection is still working.
|
/// Sleep time used when checking if an established connection is still working.
|
||||||
const REGULAR_LOOP_SLEEP: Duration = Duration::from_secs(1);
|
const REGULAR_LOOP_SLEEP: Duration = Duration::from_secs(1);
|
||||||
@ -66,7 +67,7 @@ impl Monitor {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.connectivity_check
|
self.connectivity_check
|
||||||
.check_connectivity(Instant::now(), tunnel)
|
.check_connectivity(Instant::now(), tunnel.as_ref())
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,15 +76,17 @@ impl Monitor {
|
|||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::sync::atomic::{AtomicBool, Ordering};
|
use std::{
|
||||||
use std::sync::Arc;
|
sync::{
|
||||||
use std::time::Duration;
|
atomic::{AtomicBool, Ordering},
|
||||||
|
Arc,
|
||||||
|
},
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
use tokio::sync::mpsc;
|
use tokio::sync::{mpsc, Mutex};
|
||||||
use tokio::sync::Mutex;
|
|
||||||
|
|
||||||
use crate::connectivity::constants::*;
|
use crate::connectivity::{constants::*, mock::*};
|
||||||
use crate::connectivity::mock::*;
|
|
||||||
|
|
||||||
#[tokio::test(start_paused = true)]
|
#[tokio::test(start_paused = true)]
|
||||||
/// Verify that the connectivity monitor doesn't fail if the tunnel constantly sends traffic,
|
/// Verify that the connectivity monitor doesn't fail if the tunnel constantly sends traffic,
|
||||||
@ -99,7 +102,7 @@ mod test {
|
|||||||
};
|
};
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
let start_result = checker.establish_connectivity(&tunnel).await;
|
let start_result = checker.establish_connectivity(tunnel.as_ref()).await;
|
||||||
result_tx.send(start_result).await.unwrap();
|
result_tx.send(start_result).await.unwrap();
|
||||||
// Pointer dance
|
// Pointer dance
|
||||||
let tunnel = Arc::new(Mutex::new(Some(tunnel)));
|
let tunnel = Arc::new(Mutex::new(Some(tunnel)));
|
||||||
@ -155,7 +158,7 @@ mod test {
|
|||||||
let start = now.checked_sub(Duration::from_secs(1)).unwrap();
|
let start = now.checked_sub(Duration::from_secs(1)).unwrap();
|
||||||
mock_checker(start, Box::new(pinger))
|
mock_checker(start, Box::new(pinger))
|
||||||
};
|
};
|
||||||
let start_result = checker.establish_connectivity(&tunnel).await;
|
let start_result = checker.establish_connectivity(tunnel.as_ref()).await;
|
||||||
result_tx.send(start_result).await.unwrap();
|
result_tx.send(start_result).await.unwrap();
|
||||||
// Pointer dance
|
// Pointer dance
|
||||||
let _tunnel = Arc::new(Mutex::new(Some(tunnel)));
|
let _tunnel = Arc::new(Mutex::new(Some(tunnel)));
|
||||||
|
@ -1,8 +1,6 @@
|
|||||||
//! This module takes care of obtaining ephemeral peers, updating the WireGuard configuration and
|
//! This module takes care of obtaining ephemeral peers, updating the WireGuard configuration and
|
||||||
//! restarting obfuscation and WG tunnels when necessary.
|
//! restarting obfuscation and WG tunnels when necessary.
|
||||||
|
|
||||||
#[cfg(target_os = "android")] // On Android, the Tunnel trait is not imported by default.
|
|
||||||
use super::Tunnel;
|
|
||||||
use super::{config::Config, obfuscation::ObfuscatorHandle, CloseMsg, Error, TunnelType};
|
use super::{config::Config, obfuscation::ObfuscatorHandle, CloseMsg, Error, TunnelType};
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
@ -207,15 +205,15 @@ async fn reconfigure_tunnel(
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
let mut shared_tunnel = tunnel.lock().await;
|
let mut shared_tunnel = tunnel.lock().await;
|
||||||
let tunnel = shared_tunnel.take().expect("tunnel was None");
|
let mut tunnel = shared_tunnel.take().expect("tunnel was None");
|
||||||
|
|
||||||
let updated_tunnel = tunnel
|
tunnel
|
||||||
.set_config(&config)
|
.set_config(config.clone())
|
||||||
.await
|
.await
|
||||||
.map_err(Error::TunnelError)
|
.map_err(Error::TunnelError)
|
||||||
.map_err(CloseMsg::SetupError)?;
|
.map_err(CloseMsg::SetupError)?;
|
||||||
|
|
||||||
*shared_tunnel = Some(updated_tunnel);
|
*shared_tunnel = Some(tunnel);
|
||||||
}
|
}
|
||||||
Ok(config)
|
Ok(config)
|
||||||
}
|
}
|
||||||
|
@ -7,29 +7,20 @@ use self::config::Config;
|
|||||||
use futures::channel::mpsc;
|
use futures::channel::mpsc;
|
||||||
use futures::future::Future;
|
use futures::future::Future;
|
||||||
use obfuscation::ObfuscatorHandle;
|
use obfuscation::ObfuscatorHandle;
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
use std::borrow::Cow;
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::{
|
use std::{
|
||||||
convert::Infallible,
|
convert::Infallible,
|
||||||
net::IpAddr,
|
|
||||||
path::Path,
|
path::Path,
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
sync::{mpsc as sync_mpsc, Arc, Mutex},
|
sync::{mpsc as sync_mpsc, Arc},
|
||||||
};
|
};
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
use std::{env, sync::LazyLock};
|
use std::{env, sync::LazyLock};
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
use talpid_routing::{self, RequiredRoute};
|
use talpid_routing::{self, RequiredRoute};
|
||||||
#[cfg(not(windows))]
|
use talpid_tunnel::{tun_provider, EventHook, TunnelArgs, TunnelEvent, TunnelMetadata};
|
||||||
use talpid_tunnel::tun_provider;
|
|
||||||
use talpid_tunnel::{
|
|
||||||
tun_provider::TunProvider, EventHook, TunnelArgs, TunnelEvent, TunnelMetadata,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
use talpid_routing::RouteManagerHandle;
|
|
||||||
#[cfg(daita)]
|
#[cfg(daita)]
|
||||||
use talpid_tunnel_config_client::DaitaSettings;
|
use talpid_tunnel_config_client::DaitaSettings;
|
||||||
use talpid_types::{
|
use talpid_types::{
|
||||||
@ -38,6 +29,12 @@ use talpid_types::{
|
|||||||
};
|
};
|
||||||
use tokio::sync::Mutex as AsyncMutex;
|
use tokio::sync::Mutex as AsyncMutex;
|
||||||
|
|
||||||
|
#[cfg(feature = "boringtun")]
|
||||||
|
mod boringtun;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "boringtun"))]
|
||||||
|
mod wireguard_go;
|
||||||
|
|
||||||
/// WireGuard config data-types
|
/// WireGuard config data-types
|
||||||
pub mod config;
|
pub mod config;
|
||||||
mod connectivity;
|
mod connectivity;
|
||||||
@ -45,8 +42,6 @@ mod ephemeral;
|
|||||||
mod logging;
|
mod logging;
|
||||||
mod obfuscation;
|
mod obfuscation;
|
||||||
mod stats;
|
mod stats;
|
||||||
#[cfg(wireguard_go)]
|
|
||||||
mod wireguard_go;
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
pub(crate) mod wireguard_kernel;
|
pub(crate) mod wireguard_kernel;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -55,14 +50,7 @@ mod wireguard_nt;
|
|||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
mod mtu_detection;
|
mod mtu_detection;
|
||||||
|
|
||||||
#[cfg(wireguard_go)]
|
|
||||||
use self::wireguard_go::WgGoTunnel;
|
|
||||||
|
|
||||||
// On android we only have Wireguard Go tunnel
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
type TunnelType = Box<dyn Tunnel>;
|
type TunnelType = Box<dyn Tunnel>;
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
type TunnelType = WgGoTunnel;
|
|
||||||
|
|
||||||
type Result<T> = std::result::Result<T, Error>;
|
type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
@ -83,7 +71,7 @@ pub enum Error {
|
|||||||
|
|
||||||
/// An interaction with a tunnel failed
|
/// An interaction with a tunnel failed
|
||||||
#[error("Tunnel failed")]
|
#[error("Tunnel failed")]
|
||||||
TunnelError(#[source] TunnelError),
|
TunnelError(#[from] TunnelError),
|
||||||
|
|
||||||
/// Failed to run tunnel obfuscation
|
/// Failed to run tunnel obfuscation
|
||||||
#[error("Tunnel obfuscation failed")]
|
#[error("Tunnel obfuscation failed")]
|
||||||
@ -122,9 +110,8 @@ impl Error {
|
|||||||
Error::TunnelError(TunnelError::BypassError(_)) => true,
|
Error::TunnelError(TunnelError::BypassError(_)) => true,
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
_ => self.get_tunnel_device_error().is_some(),
|
Error::TunnelError(TunnelError::SetupTunnelDevice(_)) => true,
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -133,7 +120,9 @@ impl Error {
|
|||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
pub fn get_tunnel_device_error(&self) -> Option<&io::Error> {
|
pub fn get_tunnel_device_error(&self) -> Option<&io::Error> {
|
||||||
match self {
|
match self {
|
||||||
Error::TunnelError(TunnelError::SetupTunnelDevice(error)) => Some(error),
|
Error::TunnelError(TunnelError::SetupTunnelDevice(tun_provider::Error::Io(error))) => {
|
||||||
|
Some(error)
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,7 +140,7 @@ pub struct WireguardMonitor {
|
|||||||
obfuscator: Arc<AsyncMutex<Option<ObfuscatorHandle>>>,
|
obfuscator: Arc<AsyncMutex<Option<ObfuscatorHandle>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "windows"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
/// Overrides the preference for the kernel module for WireGuard.
|
/// Overrides the preference for the kernel module for WireGuard.
|
||||||
static FORCE_USERSPACE_WIREGUARD: LazyLock<bool> = LazyLock::new(|| {
|
static FORCE_USERSPACE_WIREGUARD: LazyLock<bool> = LazyLock::new(|| {
|
||||||
env::var("TALPID_FORCE_USERSPACE_WIREGUARD")
|
env::var("TALPID_FORCE_USERSPACE_WIREGUARD")
|
||||||
@ -164,8 +153,8 @@ impl WireguardMonitor {
|
|||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
pub fn start(
|
pub fn start(
|
||||||
params: &TunnelParameters,
|
params: &TunnelParameters,
|
||||||
log_path: Option<&Path>,
|
|
||||||
args: TunnelArgs<'_>,
|
args: TunnelArgs<'_>,
|
||||||
|
_log_path: Option<&Path>,
|
||||||
) -> Result<WireguardMonitor> {
|
) -> Result<WireguardMonitor> {
|
||||||
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
#[cfg(any(target_os = "windows", target_os = "linux"))]
|
||||||
let desired_mtu = args
|
let desired_mtu = args
|
||||||
@ -194,19 +183,27 @@ impl WireguardMonitor {
|
|||||||
config.mtu = clamp_mtu(params, config.mtu);
|
config.mtu = clamp_mtu(params, config.mtu);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NOTE: We force userspace WireGuard while boringtun is enabled to more easily test
|
||||||
|
// the implementation, as DAITA is not currently supported by boringtun.
|
||||||
|
// TODO: Remove `cfg!(feature = "boringtun")`.
|
||||||
|
let userspace_wireguard =
|
||||||
|
*FORCE_USERSPACE_WIREGUARD || config.daita || cfg!(feature = "boringtun");
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
let (setup_done_tx, setup_done_rx) = mpsc::channel(0);
|
let (setup_done_tx, setup_done_rx) = mpsc::channel(0);
|
||||||
let tunnel = Self::open_tunnel(
|
let tunnel = Self::open_tunnel(
|
||||||
args.runtime.clone(),
|
args.runtime.clone(),
|
||||||
&config,
|
&config,
|
||||||
log_path,
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
args.resource_dir,
|
args.resource_dir,
|
||||||
|
#[cfg(not(all(target_os = "windows", not(feature = "boringtun"))))]
|
||||||
args.tun_provider.clone(),
|
args.tun_provider.clone(),
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(all(windows, not(feature = "boringtun")))]
|
||||||
args.route_manager.clone(),
|
args.route_manager.clone(),
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
setup_done_tx,
|
setup_done_tx,
|
||||||
|
userspace_wireguard,
|
||||||
|
_log_path,
|
||||||
)?;
|
)?;
|
||||||
let iface_name = tunnel.get_interface_name();
|
let iface_name = tunnel.get_interface_name();
|
||||||
|
|
||||||
@ -242,8 +239,15 @@ impl WireguardMonitor {
|
|||||||
let close_obfs_sender: sync_mpsc::Sender<CloseMsg> = moved_close_obfs_sender;
|
let close_obfs_sender: sync_mpsc::Sender<CloseMsg> = moved_close_obfs_sender;
|
||||||
let obfuscator = moved_obfuscator;
|
let obfuscator = moved_obfuscator;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
Self::add_device_ip_addresses(&iface_name, &config.tunnel.addresses, setup_done_rx)
|
if cfg!(feature = "boringtun") && userspace_wireguard {
|
||||||
.await?;
|
// NOTE: For boringtun, we use the `tun` crate to create our tunnel interface.
|
||||||
|
// It will automatically configure the IP address and DNS servers using `netsh`.
|
||||||
|
// This is quite slow, so we need to wait for the interface to be created.
|
||||||
|
Self::wait_for_ip_addresses(&config, &iface_name).await?;
|
||||||
|
} else {
|
||||||
|
Self::add_device_ip_addresses(&iface_name, &config.tunnel.addresses, setup_done_rx)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
let metadata = Self::tunnel_metadata(&iface_name, &config);
|
let metadata = Self::tunnel_metadata(&iface_name, &config);
|
||||||
let allowed_traffic = Self::allowed_traffic_during_tunnel_config(&config);
|
let allowed_traffic = Self::allowed_traffic_during_tunnel_config(&config);
|
||||||
@ -330,7 +334,7 @@ impl WireguardMonitor {
|
|||||||
let lock = tunnel.lock().await;
|
let lock = tunnel.lock().await;
|
||||||
let borrowed_tun = lock.as_ref().expect("The tunnel was dropped unexpectedly");
|
let borrowed_tun = lock.as_ref().expect("The tunnel was dropped unexpectedly");
|
||||||
match connectivity_monitor
|
match connectivity_monitor
|
||||||
.establish_connectivity(borrowed_tun)
|
.establish_connectivity(borrowed_tun.as_ref())
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(true) => Ok(()),
|
Ok(true) => Ok(()),
|
||||||
@ -399,8 +403,8 @@ impl WireguardMonitor {
|
|||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
pub fn start(
|
pub fn start(
|
||||||
params: &TunnelParameters,
|
params: &TunnelParameters,
|
||||||
log_path: Option<&Path>,
|
|
||||||
args: TunnelArgs<'_>,
|
args: TunnelArgs<'_>,
|
||||||
|
#[allow(unused_variables)] log_path: Option<&Path>,
|
||||||
) -> Result<WireguardMonitor> {
|
) -> Result<WireguardMonitor> {
|
||||||
let desired_mtu = get_desired_mtu(params);
|
let desired_mtu = get_desired_mtu(params);
|
||||||
let mut config =
|
let mut config =
|
||||||
@ -425,24 +429,39 @@ impl WireguardMonitor {
|
|||||||
let should_negotiate_ephemeral_peer = config.quantum_resistant || config.daita;
|
let should_negotiate_ephemeral_peer = config.quantum_resistant || config.daita;
|
||||||
|
|
||||||
let (cancel_token, cancel_receiver) = connectivity::CancelToken::new();
|
let (cancel_token, cancel_receiver) = connectivity::CancelToken::new();
|
||||||
let connectivity_check = connectivity::Check::new(
|
#[allow(unused_mut)]
|
||||||
|
let mut connectivity_monitor = connectivity::Check::new(
|
||||||
config.ipv4_gateway,
|
config.ipv4_gateway,
|
||||||
args.retry_attempt,
|
args.retry_attempt,
|
||||||
cancel_receiver.clone(),
|
cancel_receiver.clone(),
|
||||||
)
|
)
|
||||||
.map_err(Error::ConnectivityMonitorError)?;
|
.map_err(Error::ConnectivityMonitorError)?;
|
||||||
|
|
||||||
let tunnel = args.runtime.block_on(Self::open_wireguard_go_tunnel(
|
#[cfg(feature = "boringtun")]
|
||||||
&config,
|
let tunnel = args
|
||||||
log_path,
|
.runtime
|
||||||
args.tun_provider.clone(),
|
.block_on(boringtun::open_boringtun_tunnel(
|
||||||
args.route_manager,
|
&config,
|
||||||
// In case we should negotiate an ephemeral peer, we should specify via AllowedIPs
|
args.tun_provider.clone(),
|
||||||
// that we only allows traffic to/from the gateway. This is only needed on Android
|
args.route_manager,
|
||||||
// since we lack a firewall there.
|
))
|
||||||
should_negotiate_ephemeral_peer,
|
.map(Box::new)? as Box<dyn Tunnel>;
|
||||||
cancel_receiver,
|
|
||||||
))?;
|
#[cfg(not(feature = "boringtun"))]
|
||||||
|
let tunnel = args
|
||||||
|
.runtime
|
||||||
|
.block_on(wireguard_go::open_wireguard_go_tunnel(
|
||||||
|
&config,
|
||||||
|
log_path,
|
||||||
|
args.tun_provider.clone(),
|
||||||
|
args.route_manager,
|
||||||
|
// In case we should negotiate an ephemeral peer, we should specify via AllowedIPs
|
||||||
|
// that we only allows traffic to/from the gateway. This is only needed on Android
|
||||||
|
// since we lack a firewall there.
|
||||||
|
should_negotiate_ephemeral_peer,
|
||||||
|
cancel_receiver,
|
||||||
|
))
|
||||||
|
.map(Box::new)? as Box<dyn Tunnel>;
|
||||||
|
|
||||||
let iface_name = tunnel.get_interface_name();
|
let iface_name = tunnel.get_interface_name();
|
||||||
let tunnel = Arc::new(AsyncMutex::new(Some(tunnel)));
|
let tunnel = Arc::new(AsyncMutex::new(Some(tunnel)));
|
||||||
@ -468,6 +487,29 @@ impl WireguardMonitor {
|
|||||||
.on_event(TunnelEvent::InterfaceUp(metadata.clone(), allowed_traffic))
|
.on_event(TunnelEvent::InterfaceUp(metadata.clone(), allowed_traffic))
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
#[cfg(feature = "boringtun")]
|
||||||
|
{
|
||||||
|
let lock = tunnel.lock().await;
|
||||||
|
let borrowed_tun = lock.as_ref().expect("The tunnel was dropped unexpectedly");
|
||||||
|
match connectivity_monitor
|
||||||
|
.establish_connectivity(borrowed_tun.as_ref())
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(true) => Ok(()),
|
||||||
|
Ok(false) => {
|
||||||
|
log::warn!("Timeout while checking tunnel connection");
|
||||||
|
Err(CloseMsg::PingErr)
|
||||||
|
}
|
||||||
|
Err(error) => {
|
||||||
|
log::error!(
|
||||||
|
"{}",
|
||||||
|
error.display_chain_with_msg("Failed to check tunnel connection")
|
||||||
|
);
|
||||||
|
Err(CloseMsg::PingErr)
|
||||||
|
}
|
||||||
|
}?;
|
||||||
|
}
|
||||||
|
|
||||||
if should_negotiate_ephemeral_peer {
|
if should_negotiate_ephemeral_peer {
|
||||||
let ephemeral_obfs_sender = close_obfs_sender.clone();
|
let ephemeral_obfs_sender = close_obfs_sender.clone();
|
||||||
|
|
||||||
@ -501,7 +543,7 @@ impl WireguardMonitor {
|
|||||||
let metadata = Self::tunnel_metadata(&iface_name, &config);
|
let metadata = Self::tunnel_metadata(&iface_name, &config);
|
||||||
event_hook.on_event(TunnelEvent::Up(metadata)).await;
|
event_hook.on_event(TunnelEvent::Up(metadata)).await;
|
||||||
|
|
||||||
if let Err(error) = connectivity::Monitor::init(connectivity_check)
|
if let Err(error) = connectivity::Monitor::init(connectivity_monitor)
|
||||||
.run(Arc::downgrade(&tunnel))
|
.run(Arc::downgrade(&tunnel))
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
@ -561,45 +603,36 @@ impl WireguardMonitor {
|
|||||||
AllowedTunnelTraffic::All
|
AllowedTunnelTraffic::All
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Replace `0.0.0.0/0`/`::/0` with the gateway IPs when `gateway_only` is true.
|
#[cfg(windows)]
|
||||||
/// Used to block traffic to other destinations while connecting on Android.
|
async fn wait_for_ip_addresses(
|
||||||
#[cfg(target_os = "android")]
|
config: &Config,
|
||||||
fn patch_allowed_ips(config: &Config, gateway_only: bool) -> Cow<'_, Config> {
|
iface_name: &String,
|
||||||
if gateway_only {
|
) -> std::result::Result<(), CloseMsg> {
|
||||||
let mut patched_config = config.clone();
|
log::debug!("Waiting for tunnel IP interfaces to arrive");
|
||||||
let gateway_net_v4 = ipnetwork::IpNetwork::from(IpAddr::from(config.ipv4_gateway));
|
let luid = talpid_windows::net::luid_from_alias(iface_name).map_err(|error| {
|
||||||
let gateway_net_v6 = config
|
log::error!("Failed to obtain tunnel interface LUID: {}", error);
|
||||||
.ipv6_gateway
|
CloseMsg::SetupError(Error::IpInterfacesError)
|
||||||
.map(|net| ipnetwork::IpNetwork::from(IpAddr::from(net)));
|
})?;
|
||||||
for peer in patched_config.peers_mut() {
|
talpid_windows::net::wait_for_interfaces(luid, true, config.ipv6_gateway.is_some())
|
||||||
peer.allowed_ips = peer
|
.await
|
||||||
.allowed_ips
|
.map_err(|error| {
|
||||||
.iter()
|
log::error!("Failed to obtain tunnel interface LUID: {}", error);
|
||||||
.cloned()
|
CloseMsg::SetupError(Error::IpInterfacesError)
|
||||||
.filter_map(|mut allowed_ip| {
|
})?;
|
||||||
if allowed_ip.prefix() == 0 {
|
talpid_windows::net::wait_for_addresses(luid)
|
||||||
if allowed_ip.is_ipv4() {
|
.await
|
||||||
allowed_ip = gateway_net_v4;
|
.map_err(|error| {
|
||||||
} else if let Some(net) = gateway_net_v6 {
|
log::error!("Failed to obtain tunnel interface LUID: {}", error);
|
||||||
allowed_ip = net;
|
CloseMsg::SetupError(Error::IpInterfacesError)
|
||||||
} else {
|
})?;
|
||||||
return None;
|
log::debug!("Done waiting for tunnel IP interfaces to arrive");
|
||||||
}
|
Ok(())
|
||||||
}
|
|
||||||
Some(allowed_ip)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
}
|
|
||||||
Cow::Owned(patched_config)
|
|
||||||
} else {
|
|
||||||
Cow::Borrowed(config)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
async fn add_device_ip_addresses(
|
async fn add_device_ip_addresses(
|
||||||
iface_name: &str,
|
iface_name: &str,
|
||||||
addresses: &[IpAddr],
|
addresses: &[std::net::IpAddr],
|
||||||
mut setup_done_rx: mpsc::Receiver<std::result::Result<(), BoxedError>>,
|
mut setup_done_rx: mpsc::Receiver<std::result::Result<(), BoxedError>>,
|
||||||
) -> std::result::Result<(), CloseMsg> {
|
) -> std::result::Result<(), CloseMsg> {
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
@ -631,27 +664,35 @@ impl WireguardMonitor {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn open_tunnel(
|
fn open_tunnel(
|
||||||
runtime: tokio::runtime::Handle,
|
runtime: tokio::runtime::Handle,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
log_path: Option<&Path>,
|
|
||||||
resource_dir: &Path,
|
resource_dir: &Path,
|
||||||
_tun_provider: Arc<Mutex<TunProvider>>,
|
#[cfg(feature = "boringtun")] tun_provider: Arc<
|
||||||
route_manager: talpid_routing::RouteManagerHandle,
|
std::sync::Mutex<tun_provider::TunProvider>,
|
||||||
|
>,
|
||||||
|
#[cfg(not(feature = "boringtun"))] route_manager: talpid_routing::RouteManagerHandle,
|
||||||
setup_done_tx: mpsc::Sender<std::result::Result<(), BoxedError>>,
|
setup_done_tx: mpsc::Sender<std::result::Result<(), BoxedError>>,
|
||||||
|
userspace_wireguard: bool,
|
||||||
|
_log_path: Option<&Path>,
|
||||||
) -> Result<TunnelType> {
|
) -> Result<TunnelType> {
|
||||||
log::debug!("Tunnel MTU: {}", config.mtu);
|
log::debug!("Tunnel MTU: {}", config.mtu);
|
||||||
|
|
||||||
let userspace_wireguard = *FORCE_USERSPACE_WIREGUARD || config.daita;
|
|
||||||
|
|
||||||
if userspace_wireguard {
|
if userspace_wireguard {
|
||||||
log::debug!("Using userspace WireGuard implementation");
|
log::debug!("Using userspace WireGuard implementation");
|
||||||
|
|
||||||
|
#[cfg(feature = "boringtun")]
|
||||||
let tunnel = runtime
|
let tunnel = runtime
|
||||||
.block_on(Self::open_wireguard_go_tunnel(
|
.block_on(boringtun::open_boringtun_tunnel(config, tun_provider))
|
||||||
|
.map(Box::new)?;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "boringtun"))]
|
||||||
|
let tunnel = runtime
|
||||||
|
.block_on(wireguard_go::open_wireguard_go_tunnel(
|
||||||
config,
|
config,
|
||||||
log_path,
|
_log_path,
|
||||||
setup_done_tx,
|
setup_done_tx,
|
||||||
route_manager,
|
route_manager,
|
||||||
))
|
))
|
||||||
@ -660,7 +701,7 @@ impl WireguardMonitor {
|
|||||||
} else {
|
} else {
|
||||||
log::debug!("Using kernel WireGuard implementation");
|
log::debug!("Using kernel WireGuard implementation");
|
||||||
|
|
||||||
wireguard_nt::WgNtTunnel::start_tunnel(config, log_path, resource_dir, setup_done_tx)
|
wireguard_nt::WgNtTunnel::start_tunnel(config, _log_path, resource_dir, setup_done_tx)
|
||||||
.map(|tun| Box::new(tun) as Box<dyn Tunnel + 'static>)
|
.map(|tun| Box::new(tun) as Box<dyn Tunnel + 'static>)
|
||||||
.map_err(Error::TunnelError)
|
.map_err(Error::TunnelError)
|
||||||
}
|
}
|
||||||
@ -670,20 +711,27 @@ impl WireguardMonitor {
|
|||||||
fn open_tunnel(
|
fn open_tunnel(
|
||||||
runtime: tokio::runtime::Handle,
|
runtime: tokio::runtime::Handle,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
log_path: Option<&Path>,
|
tun_provider: Arc<std::sync::Mutex<tun_provider::TunProvider>>,
|
||||||
tun_provider: Arc<Mutex<TunProvider>>,
|
_userspace_wireguard: bool,
|
||||||
|
_log_path: Option<&Path>,
|
||||||
) -> Result<TunnelType> {
|
) -> Result<TunnelType> {
|
||||||
log::debug!("Tunnel MTU: {}", config.mtu);
|
log::debug!("Tunnel MTU: {}", config.mtu);
|
||||||
|
|
||||||
log::debug!("Using userspace WireGuard implementation");
|
log::debug!("Using userspace WireGuard implementation");
|
||||||
|
|
||||||
|
#[cfg(not(feature = "boringtun"))]
|
||||||
let tunnel = runtime
|
let tunnel = runtime
|
||||||
.block_on(Self::open_wireguard_go_tunnel(
|
.block_on(wireguard_go::open_wireguard_go_tunnel(
|
||||||
config,
|
config,
|
||||||
log_path,
|
_log_path,
|
||||||
tun_provider,
|
tun_provider,
|
||||||
))
|
))
|
||||||
.map(Box::new)?;
|
.map(Box::new)?;
|
||||||
|
|
||||||
|
#[cfg(feature = "boringtun")]
|
||||||
|
let tunnel = runtime
|
||||||
|
.block_on(boringtun::open_boringtun_tunnel(config, tun_provider))
|
||||||
|
.map(Box::new)?;
|
||||||
Ok(tunnel)
|
Ok(tunnel)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -691,22 +739,22 @@ impl WireguardMonitor {
|
|||||||
fn open_tunnel(
|
fn open_tunnel(
|
||||||
runtime: tokio::runtime::Handle,
|
runtime: tokio::runtime::Handle,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
log_path: Option<&Path>,
|
tun_provider: Arc<std::sync::Mutex<tun_provider::TunProvider>>,
|
||||||
tun_provider: Arc<Mutex<TunProvider>>,
|
userspace_wireguard: bool,
|
||||||
|
_log_path: Option<&Path>,
|
||||||
) -> Result<TunnelType> {
|
) -> Result<TunnelType> {
|
||||||
log::debug!("Tunnel MTU: {}", config.mtu);
|
log::debug!("Tunnel MTU: {}", config.mtu);
|
||||||
|
|
||||||
let userspace_wireguard = *FORCE_USERSPACE_WIREGUARD || config.daita;
|
|
||||||
if userspace_wireguard {
|
if userspace_wireguard {
|
||||||
log::debug!("Using userspace WireGuard implementation");
|
log::debug!("Using userspace WireGuard implementation");
|
||||||
|
|
||||||
let tunnel = runtime
|
#[cfg(not(feature = "boringtun"))]
|
||||||
.block_on(Self::open_wireguard_go_tunnel(
|
let f = wireguard_go::open_wireguard_go_tunnel(config, _log_path, tun_provider);
|
||||||
config,
|
|
||||||
log_path,
|
#[cfg(feature = "boringtun")]
|
||||||
tun_provider,
|
let f = boringtun::open_boringtun_tunnel(config, tun_provider);
|
||||||
))
|
|
||||||
.map(Box::new)?;
|
let tunnel = runtime.block_on(f).map(Box::new)?;
|
||||||
Ok(tunnel)
|
Ok(tunnel)
|
||||||
} else {
|
} else {
|
||||||
let res = if will_nm_manage_dns() {
|
let res = if will_nm_manage_dns() {
|
||||||
@ -721,81 +769,27 @@ impl WireguardMonitor {
|
|||||||
|
|
||||||
res.or_else(|err| {
|
res.or_else(|err| {
|
||||||
log::warn!("Failed to initialize kernel WireGuard tunnel, falling back to userspace WireGuard implementation:\n{}",err.display_chain() );
|
log::warn!("Failed to initialize kernel WireGuard tunnel, falling back to userspace WireGuard implementation:\n{}",err.display_chain() );
|
||||||
Ok(runtime
|
|
||||||
.block_on(Self::open_wireguard_go_tunnel(
|
#[cfg(not(feature = "boringtun"))]
|
||||||
config,
|
{
|
||||||
log_path,
|
Ok(runtime
|
||||||
tun_provider,
|
.block_on(wireguard_go::open_wireguard_go_tunnel(
|
||||||
))
|
config,
|
||||||
.map(Box::new)?)
|
_log_path,
|
||||||
|
tun_provider,
|
||||||
|
))
|
||||||
|
.map(Box::new)?)
|
||||||
|
}
|
||||||
|
#[cfg(feature = "boringtun")]
|
||||||
|
{
|
||||||
|
Ok(runtime
|
||||||
|
.block_on(boringtun::open_boringtun_tunnel(config, tun_provider))
|
||||||
|
.map(Box::new)?)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Configure and start a Wireguard-go tunnel.
|
|
||||||
#[cfg(wireguard_go)]
|
|
||||||
#[allow(clippy::unused_async)]
|
|
||||||
async fn open_wireguard_go_tunnel(
|
|
||||||
config: &Config,
|
|
||||||
log_path: Option<&Path>,
|
|
||||||
#[cfg(unix)] tun_provider: Arc<Mutex<TunProvider>>,
|
|
||||||
#[cfg(target_os = "android")] route_manager: RouteManagerHandle,
|
|
||||||
#[cfg(windows)] setup_done_tx: mpsc::Sender<std::result::Result<(), BoxedError>>,
|
|
||||||
#[cfg(windows)] route_manager: talpid_routing::RouteManagerHandle,
|
|
||||||
#[cfg(target_os = "android")] gateway_only: bool,
|
|
||||||
#[cfg(target_os = "android")] cancel_receiver: connectivity::CancelReceiver,
|
|
||||||
) -> Result<WgGoTunnel> {
|
|
||||||
#[cfg(all(unix, not(target_os = "android")))]
|
|
||||||
let routes = config.get_tunnel_destinations();
|
|
||||||
|
|
||||||
#[cfg(all(unix, not(target_os = "android")))]
|
|
||||||
let tunnel = WgGoTunnel::start_tunnel(config, log_path, tun_provider, routes)
|
|
||||||
.map_err(Error::TunnelError)?;
|
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
|
||||||
let tunnel = WgGoTunnel::start_tunnel(config, log_path, route_manager, setup_done_tx)
|
|
||||||
.await
|
|
||||||
.map_err(Error::TunnelError)?;
|
|
||||||
|
|
||||||
// Android uses multihop implemented in Mullvad's wireguard-go fork. When negotiating
|
|
||||||
// with an ephemeral peer, this multihop strategy require us to restart the tunnel
|
|
||||||
// every time we want to reconfigure it. As such, we will actually start a multihop
|
|
||||||
// tunnel at a later stage, after we have negotiated with the first ephemeral peer.
|
|
||||||
// At this point, when the tunnel *is first started*, we establish a regular, singlehop
|
|
||||||
// tunnel to where the ephemeral peer resides.
|
|
||||||
//
|
|
||||||
// Refer to `docs/architecture.md` for details on how to use multihop + PQ.
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
let config = Self::patch_allowed_ips(config, gateway_only);
|
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
|
||||||
let tunnel = if let Some(exit_peer) = &config.exit_peer {
|
|
||||||
WgGoTunnel::start_multihop_tunnel(
|
|
||||||
&config,
|
|
||||||
exit_peer,
|
|
||||||
log_path,
|
|
||||||
tun_provider,
|
|
||||||
route_manager,
|
|
||||||
cancel_receiver,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(Error::TunnelError)?
|
|
||||||
} else {
|
|
||||||
WgGoTunnel::start_tunnel(
|
|
||||||
#[allow(clippy::needless_borrow)]
|
|
||||||
&config,
|
|
||||||
log_path,
|
|
||||||
tun_provider,
|
|
||||||
route_manager,
|
|
||||||
cancel_receiver,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(Error::TunnelError)?
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(tunnel)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Blocks the current thread until tunnel disconnects
|
/// Blocks the current thread until tunnel disconnects
|
||||||
pub fn wait(mut self) -> Result<()> {
|
pub fn wait(mut self) -> Result<()> {
|
||||||
let wait_result = match self.close_msg_receiver.recv() {
|
let wait_result = match self.close_msg_receiver.recv() {
|
||||||
@ -837,7 +831,9 @@ impl WireguardMonitor {
|
|||||||
/// Returns routes to the peer endpoints (through the physical interface).
|
/// Returns routes to the peer endpoints (through the physical interface).
|
||||||
#[cfg_attr(target_os = "linux", allow(unused_variables))]
|
#[cfg_attr(target_os = "linux", allow(unused_variables))]
|
||||||
#[cfg(not(target_os = "android"))]
|
#[cfg(not(target_os = "android"))]
|
||||||
fn get_endpoint_routes(endpoints: &[IpAddr]) -> impl Iterator<Item = RequiredRoute> + '_ {
|
fn get_endpoint_routes(
|
||||||
|
endpoints: &[std::net::IpAddr],
|
||||||
|
) -> impl Iterator<Item = RequiredRoute> + '_ {
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
// No need due to policy based routing.
|
// No need due to policy based routing.
|
||||||
@ -1065,15 +1061,9 @@ pub enum TunnelError {
|
|||||||
#[error("Failed to duplicate tunnel file descriptor for wireguard-go")]
|
#[error("Failed to duplicate tunnel file descriptor for wireguard-go")]
|
||||||
FdDuplicationError(#[source] nix::Error),
|
FdDuplicationError(#[source] nix::Error),
|
||||||
|
|
||||||
/// Failed to setup a tunnel device.
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
#[error("Failed to create tunnel device")]
|
|
||||||
SetupTunnelDevice(#[source] tun_provider::Error),
|
|
||||||
|
|
||||||
/// Failed to set up a tunnel device
|
/// Failed to set up a tunnel device
|
||||||
#[cfg(windows)]
|
#[error("Failed to setup a tunnel device")]
|
||||||
#[error("Failed to create tunnel device")]
|
SetupTunnelDevice(#[source] tun_provider::Error),
|
||||||
SetupTunnelDevice(#[source] io::Error),
|
|
||||||
|
|
||||||
/// Failed to setup a tunnel device.
|
/// Failed to setup a tunnel device.
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -1095,6 +1085,7 @@ pub enum TunnelError {
|
|||||||
InvalidAlias,
|
InvalidAlias,
|
||||||
|
|
||||||
/// Failure to set up logging
|
/// Failure to set up logging
|
||||||
|
#[cfg(any(windows, not(feature = "boringtun")))]
|
||||||
#[error("Failed to set up logging")]
|
#[error("Failed to set up logging")]
|
||||||
LoggingError(#[source] logging::Error),
|
LoggingError(#[source] logging::Error),
|
||||||
|
|
||||||
@ -1107,6 +1098,11 @@ pub enum TunnelError {
|
|||||||
#[cfg(daita)]
|
#[cfg(daita)]
|
||||||
#[error("Failed to start DAITA - tunnel implemenation does not support DAITA")]
|
#[error("Failed to start DAITA - tunnel implemenation does not support DAITA")]
|
||||||
DaitaNotSupported,
|
DaitaNotSupported,
|
||||||
|
|
||||||
|
/// BoringTun device error
|
||||||
|
#[cfg(feature = "boringtun")]
|
||||||
|
#[error("Boringtun: {0:?}")]
|
||||||
|
BoringTunDevice(::boringtun::device::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
#![cfg(any(windows, not(feature = "boringtun")))]
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{collections::HashMap, fmt, fs, io::Write, path::Path, sync::LazyLock};
|
use std::{collections::HashMap, fmt, fs, io::Write, path::Path, sync::LazyLock};
|
||||||
|
|
||||||
@ -44,12 +45,12 @@ pub fn clean_up_logging(ordinal: u64) {
|
|||||||
state.map.remove(&ordinal);
|
state.map.remove(&ordinal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub enum LogLevel {
|
pub enum LogLevel {
|
||||||
#[cfg_attr(windows, allow(dead_code))]
|
|
||||||
Verbose,
|
Verbose,
|
||||||
#[cfg_attr(wireguard_go, allow(dead_code))]
|
#[cfg_attr(not(feature = "boringtun"), allow(dead_code))]
|
||||||
Info,
|
Info,
|
||||||
#[cfg_attr(wireguard_go, allow(dead_code))]
|
#[cfg_attr(not(feature = "boringtun"), allow(dead_code))]
|
||||||
Warning,
|
Warning,
|
||||||
Error,
|
Error,
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,8 @@ use crate::connectivity;
|
|||||||
use crate::logging::{clean_up_logging, initialize_logging};
|
use crate::logging::{clean_up_logging, initialize_logging};
|
||||||
#[cfg(all(unix, not(target_os = "android")))]
|
#[cfg(all(unix, not(target_os = "android")))]
|
||||||
use ipnetwork::IpNetwork;
|
use ipnetwork::IpNetwork;
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
use std::borrow::Cow;
|
||||||
#[cfg(daita)]
|
#[cfg(daita)]
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
@ -67,105 +69,191 @@ impl Drop for LoggingContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
pub struct WgGoTunnel {
|
||||||
pub struct WgGoTunnel(WgGoTunnelState);
|
// This should never be [None] _unless_ we have just called [Self::stop] and
|
||||||
|
// we're restarting the tunnel.
|
||||||
#[cfg(target_os = "android")]
|
inner: Option<WgGoTunnelState>,
|
||||||
pub enum WgGoTunnel {
|
#[cfg(target_os = "android")]
|
||||||
Multihop(WgGoTunnelState),
|
r#type: Circuit,
|
||||||
Singlehop(WgGoTunnelState),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(target_os = "android"))]
|
|
||||||
impl WgGoTunnel {
|
|
||||||
fn into_state(self) -> WgGoTunnelState {
|
|
||||||
self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_state(&self) -> &WgGoTunnelState {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_state_mut(&mut self) -> &mut WgGoTunnelState {
|
|
||||||
&mut self.0
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
enum Circuit {
|
||||||
|
Singlehop,
|
||||||
|
Multihop,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configure and start a Wireguard-go tunnel.
|
||||||
|
#[allow(clippy::unused_async)]
|
||||||
|
pub(crate) async fn open_wireguard_go_tunnel(
|
||||||
|
config: &Config,
|
||||||
|
log_path: Option<&Path>,
|
||||||
|
#[cfg(unix)] tun_provider: Arc<std::sync::Mutex<talpid_tunnel::tun_provider::TunProvider>>,
|
||||||
|
#[cfg(target_os = "android")] route_manager: RouteManagerHandle,
|
||||||
|
#[cfg(windows)] setup_done_tx: futures::channel::mpsc::Sender<
|
||||||
|
std::result::Result<(), BoxedError>,
|
||||||
|
>,
|
||||||
|
#[cfg(windows)] route_manager: talpid_routing::RouteManagerHandle,
|
||||||
|
#[cfg(target_os = "android")] gateway_only: bool,
|
||||||
|
#[cfg(target_os = "android")] cancel_receiver: connectivity::CancelReceiver,
|
||||||
|
) -> Result<WgGoTunnel> {
|
||||||
|
#[cfg(all(unix, not(target_os = "android")))]
|
||||||
|
let routes = config.get_tunnel_destinations();
|
||||||
|
|
||||||
|
#[cfg(all(unix, not(target_os = "android")))]
|
||||||
|
let tunnel = WgGoTunnel::start_tunnel(config, log_path, tun_provider, routes)?;
|
||||||
|
|
||||||
|
#[cfg(target_os = "windows")]
|
||||||
|
let tunnel = WgGoTunnel::start_tunnel(config, log_path, route_manager, setup_done_tx).await?;
|
||||||
|
|
||||||
|
// Android uses multihop implemented in Mullvad's wireguard-go fork. When negotiating
|
||||||
|
// with an ephemeral peer, this multihop strategy require us to restart the tunnel
|
||||||
|
// every time we want to reconfigure it. As such, we will actually start a multihop
|
||||||
|
// tunnel at a later stage, after we have negotiated with the first ephemeral peer.
|
||||||
|
// At this point, when the tunnel *is first started*, we establish a regular, singlehop
|
||||||
|
// tunnel to where the ephemeral peer resides.
|
||||||
|
//
|
||||||
|
// Refer to `docs/architecture.md` for details on how to use multihop + PQ.
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
let config = patch_allowed_ips(config, gateway_only);
|
||||||
|
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
let tunnel = if let Some(exit_peer) = &config.exit_peer {
|
||||||
|
WgGoTunnel::start_multihop_tunnel(
|
||||||
|
&config,
|
||||||
|
exit_peer,
|
||||||
|
log_path,
|
||||||
|
tun_provider,
|
||||||
|
route_manager,
|
||||||
|
cancel_receiver,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
} else {
|
||||||
|
WgGoTunnel::start_tunnel(
|
||||||
|
#[allow(clippy::needless_borrow)]
|
||||||
|
&config,
|
||||||
|
log_path,
|
||||||
|
tun_provider,
|
||||||
|
route_manager,
|
||||||
|
cancel_receiver,
|
||||||
|
)
|
||||||
|
.await?
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(tunnel)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace `0.0.0.0/0`/`::/0` with the gateway IPs when `gateway_only` is true.
|
||||||
|
/// Used to block traffic to other destinations while connecting on Android.
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
fn patch_allowed_ips(config: &Config, gateway_only: bool) -> Cow<'_, Config> {
|
||||||
|
use std::net::IpAddr;
|
||||||
|
|
||||||
|
if gateway_only {
|
||||||
|
let mut patched_config = config.clone();
|
||||||
|
let gateway_net_v4 =
|
||||||
|
ipnetwork::IpNetwork::from(std::net::IpAddr::from(config.ipv4_gateway));
|
||||||
|
let gateway_net_v6 = config
|
||||||
|
.ipv6_gateway
|
||||||
|
.map(|net| ipnetwork::IpNetwork::from(IpAddr::from(net)));
|
||||||
|
for peer in patched_config.peers_mut() {
|
||||||
|
peer.allowed_ips = peer
|
||||||
|
.allowed_ips
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.filter_map(|mut allowed_ip| {
|
||||||
|
if allowed_ip.prefix() == 0 {
|
||||||
|
if allowed_ip.is_ipv4() {
|
||||||
|
allowed_ip = gateway_net_v4;
|
||||||
|
} else if let Some(net) = gateway_net_v6 {
|
||||||
|
allowed_ip = net;
|
||||||
|
} else {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Some(allowed_ip)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
Cow::Owned(patched_config)
|
||||||
|
} else {
|
||||||
|
Cow::Borrowed(config)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl WgGoTunnel {
|
impl WgGoTunnel {
|
||||||
fn into_state(self) -> WgGoTunnelState {
|
fn handle(&self) -> &WgGoTunnelState {
|
||||||
match self {
|
debug_assert!(&self.inner.is_some());
|
||||||
WgGoTunnel::Multihop(state) => state,
|
self.inner.as_ref().unwrap()
|
||||||
WgGoTunnel::Singlehop(state) => state,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_state(&self) -> &WgGoTunnelState {
|
fn handle_mut(&mut self) -> &mut WgGoTunnelState {
|
||||||
match self {
|
debug_assert!(&self.inner.is_some());
|
||||||
WgGoTunnel::Multihop(state) => state,
|
self.inner.as_mut().unwrap()
|
||||||
WgGoTunnel::Singlehop(state) => state,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn as_state_mut(&mut self) -> &mut WgGoTunnelState {
|
fn stop(&mut self) -> Result<()> {
|
||||||
match self {
|
if let Some(tunnel) = self.inner.take() {
|
||||||
WgGoTunnel::Multihop(state) => state,
|
tunnel
|
||||||
WgGoTunnel::Singlehop(state) => state,
|
.tunnel_handle
|
||||||
|
.turn_off()
|
||||||
|
.map_err(|e| TunnelError::StopWireguardError(Box::new(e)))?;
|
||||||
}
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn set_config(self, config: &Config) -> Result<Self> {
|
#[cfg(not(target_os = "android"))]
|
||||||
let state = self.as_state();
|
#[allow(clippy::unused_async)]
|
||||||
let log_path = state._logging_context.path.clone();
|
async fn set_config(&mut self, config: Config) -> Result<()> {
|
||||||
let cancel_receiver = state.cancel_receiver.clone();
|
self.handle_mut().set_config(config)
|
||||||
let tun_provider = Arc::clone(&state.tun_provider);
|
}
|
||||||
let route_manager = state.route_manager.clone();
|
|
||||||
|
|
||||||
match self {
|
#[cfg(target_os = "android")]
|
||||||
WgGoTunnel::Multihop(state) if !config.is_multihop() => {
|
pub async fn set_config(&mut self, config: Config) -> Result<()> {
|
||||||
state.stop()?;
|
let log_path = self.handle()._logging_context.path.clone();
|
||||||
Self::start_tunnel(
|
let cancel_receiver = self.handle().cancel_receiver.clone();
|
||||||
config,
|
let tun_provider = Arc::clone(&self.handle().tun_provider);
|
||||||
|
let route_manager = self.handle().route_manager.clone();
|
||||||
|
|
||||||
|
match self.r#type {
|
||||||
|
Circuit::Multihop if !config.is_multihop() => {
|
||||||
|
self.stop()?;
|
||||||
|
*self = Self::start_tunnel(
|
||||||
|
&config,
|
||||||
log_path.as_deref(),
|
log_path.as_deref(),
|
||||||
tun_provider,
|
tun_provider,
|
||||||
route_manager,
|
route_manager,
|
||||||
cancel_receiver,
|
cancel_receiver,
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
}
|
}
|
||||||
WgGoTunnel::Singlehop(state) if config.is_multihop() => {
|
Circuit::Singlehop if config.is_multihop() => {
|
||||||
state.stop()?;
|
self.stop()?;
|
||||||
Self::start_multihop_tunnel(
|
*self = Self::start_multihop_tunnel(
|
||||||
config,
|
&config,
|
||||||
&config.exit_peer.clone().unwrap().clone(),
|
&config.exit_peer.clone().unwrap().clone(),
|
||||||
log_path.as_deref(),
|
log_path.as_deref(),
|
||||||
tun_provider,
|
tun_provider,
|
||||||
route_manager,
|
route_manager,
|
||||||
cancel_receiver,
|
cancel_receiver,
|
||||||
)
|
)
|
||||||
.await
|
.await?;
|
||||||
}
|
}
|
||||||
WgGoTunnel::Singlehop(mut state) => {
|
Circuit::Singlehop => {
|
||||||
state.set_config(config.clone())?;
|
self.handle_mut().set_config(config)?;
|
||||||
let new_state = WgGoTunnel::Singlehop(state);
|
|
||||||
// HACK: Check if the tunnel is working by sending a ping in the tunnel.
|
// HACK: Check if the tunnel is working by sending a ping in the tunnel.
|
||||||
// This check is needed for PQ connections to be established.
|
// This check is needed for PQ connections to be established.
|
||||||
new_state.ensure_tunnel_is_running().await?;
|
self.ensure_tunnel_is_running().await?;
|
||||||
Ok(new_state)
|
|
||||||
}
|
}
|
||||||
WgGoTunnel::Multihop(mut state) => {
|
Circuit::Multihop => {
|
||||||
state.set_config(config.clone())?;
|
self.handle_mut().set_config(config)?;
|
||||||
let new_state = WgGoTunnel::Multihop(state);
|
|
||||||
// HACK: Check if the tunnel is working by sending a ping in the tunnel.
|
// HACK: Check if the tunnel is working by sending a ping in the tunnel.
|
||||||
// This check is needed for PQ connections to be established.
|
// This check is needed for PQ connections to be established.
|
||||||
new_state.ensure_tunnel_is_running().await?;
|
self.ensure_tunnel_is_running().await?;
|
||||||
Ok(new_state)
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
Ok(())
|
||||||
|
|
||||||
pub fn stop(self) -> Result<()> {
|
|
||||||
self.into_state().stop()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,12 +282,6 @@ pub(crate) struct WgGoTunnelState {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl WgGoTunnelState {
|
impl WgGoTunnelState {
|
||||||
fn stop(self) -> Result<()> {
|
|
||||||
self.tunnel_handle
|
|
||||||
.turn_off()
|
|
||||||
.map_err(|e| TunnelError::StopWireguardError(Box::new(e)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_config(&mut self, config: Config) -> Result<()> {
|
fn set_config(&mut self, config: Config) -> Result<()> {
|
||||||
let wg_config_str = config.to_userspace_format();
|
let wg_config_str = config.to_userspace_format();
|
||||||
|
|
||||||
@ -231,7 +313,7 @@ impl WgGoTunnelState {
|
|||||||
|
|
||||||
impl WgGoTunnel {
|
impl WgGoTunnel {
|
||||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
pub fn start_tunnel(
|
fn start_tunnel(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
log_path: Option<&Path>,
|
log_path: Option<&Path>,
|
||||||
tun_provider: Arc<Mutex<TunProvider>>,
|
tun_provider: Arc<Mutex<TunProvider>>,
|
||||||
@ -258,14 +340,18 @@ impl WgGoTunnel {
|
|||||||
)
|
)
|
||||||
.map_err(|e| TunnelError::FatalStartWireguardError(Box::new(e)))?;
|
.map_err(|e| TunnelError::FatalStartWireguardError(Box::new(e)))?;
|
||||||
|
|
||||||
Ok(WgGoTunnel(WgGoTunnelState {
|
let tunnel = WgGoTunnelState {
|
||||||
interface_name,
|
interface_name,
|
||||||
tunnel_handle: handle,
|
tunnel_handle: handle,
|
||||||
_tunnel_device: tunnel_device,
|
_tunnel_device: tunnel_device,
|
||||||
_logging_context: logging_context,
|
_logging_context: logging_context,
|
||||||
#[cfg(daita)]
|
#[cfg(daita)]
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
}))
|
};
|
||||||
|
|
||||||
|
Ok(WgGoTunnel {
|
||||||
|
inner: Some(tunnel),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
@ -329,14 +415,16 @@ impl WgGoTunnel {
|
|||||||
|
|
||||||
let interface_name = handle.name();
|
let interface_name = handle.name();
|
||||||
|
|
||||||
Ok(WgGoTunnel(WgGoTunnelState {
|
Ok(WgGoTunnel {
|
||||||
interface_name: interface_name.to_owned(),
|
inner: Some(WgGoTunnelState {
|
||||||
tunnel_handle: handle,
|
interface_name: interface_name.to_owned(),
|
||||||
_logging_context: logging_context,
|
tunnel_handle: handle,
|
||||||
_socket_update_cb: socket_update_cb,
|
_logging_context: logging_context,
|
||||||
#[cfg(daita)]
|
_socket_update_cb: socket_update_cb,
|
||||||
config: config.clone(),
|
#[cfg(daita)]
|
||||||
}))
|
config: config.clone(),
|
||||||
|
}),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback to be used to rebind the tunnel sockets when the default route changes
|
// Callback to be used to rebind the tunnel sockets when the default route changes
|
||||||
@ -367,6 +455,7 @@ impl WgGoTunnel {
|
|||||||
#[cfg(target_os = "linux")]
|
#[cfg(target_os = "linux")]
|
||||||
{
|
{
|
||||||
tun_config.name = Some(MULLVAD_INTERFACE_NAME.to_string());
|
tun_config.name = Some(MULLVAD_INTERFACE_NAME.to_string());
|
||||||
|
tun_config.packet_information = true;
|
||||||
}
|
}
|
||||||
tun_config.addresses = config.tunnel.addresses.clone();
|
tun_config.addresses = config.tunnel.addresses.clone();
|
||||||
tun_config.ipv4_gateway = config.ipv4_gateway;
|
tun_config.ipv4_gateway = config.ipv4_gateway;
|
||||||
@ -449,7 +538,7 @@ impl WgGoTunnel {
|
|||||||
Self::bypass_tunnel_sockets(&handle, &mut tunnel_device)
|
Self::bypass_tunnel_sockets(&handle, &mut tunnel_device)
|
||||||
.map_err(TunnelError::BypassError)?;
|
.map_err(TunnelError::BypassError)?;
|
||||||
|
|
||||||
let tunnel = WgGoTunnel::Singlehop(WgGoTunnelState {
|
let tunnel = WgGoTunnelState {
|
||||||
interface_name,
|
interface_name,
|
||||||
tunnel_handle: handle,
|
tunnel_handle: handle,
|
||||||
_tunnel_device: tunnel_device,
|
_tunnel_device: tunnel_device,
|
||||||
@ -459,7 +548,11 @@ impl WgGoTunnel {
|
|||||||
#[cfg(daita)]
|
#[cfg(daita)]
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
cancel_receiver,
|
cancel_receiver,
|
||||||
});
|
};
|
||||||
|
let tunnel = Self {
|
||||||
|
inner: Some(tunnel),
|
||||||
|
r#type: Circuit::Singlehop,
|
||||||
|
};
|
||||||
|
|
||||||
if is_new_tunnel {
|
if is_new_tunnel {
|
||||||
tunnel.wait_for_routes().await?;
|
tunnel.wait_for_routes().await?;
|
||||||
@ -527,7 +620,7 @@ impl WgGoTunnel {
|
|||||||
Self::bypass_tunnel_sockets(&handle, &mut tunnel_device)
|
Self::bypass_tunnel_sockets(&handle, &mut tunnel_device)
|
||||||
.map_err(TunnelError::BypassError)?;
|
.map_err(TunnelError::BypassError)?;
|
||||||
|
|
||||||
let tunnel = WgGoTunnel::Multihop(WgGoTunnelState {
|
let tunnel = WgGoTunnelState {
|
||||||
interface_name,
|
interface_name,
|
||||||
tunnel_handle: handle,
|
tunnel_handle: handle,
|
||||||
_tunnel_device: tunnel_device,
|
_tunnel_device: tunnel_device,
|
||||||
@ -537,7 +630,12 @@ impl WgGoTunnel {
|
|||||||
#[cfg(daita)]
|
#[cfg(daita)]
|
||||||
config: config.clone(),
|
config: config.clone(),
|
||||||
cancel_receiver: cancel_receiver.clone(),
|
cancel_receiver: cancel_receiver.clone(),
|
||||||
});
|
};
|
||||||
|
|
||||||
|
let tunnel = Self {
|
||||||
|
inner: Some(tunnel),
|
||||||
|
r#type: Circuit::Multihop,
|
||||||
|
};
|
||||||
|
|
||||||
if is_new_tunnel {
|
if is_new_tunnel {
|
||||||
tunnel.wait_for_routes().await?;
|
tunnel.wait_for_routes().await?;
|
||||||
@ -569,12 +667,10 @@ impl WgGoTunnel {
|
|||||||
/// There is a brief period of time between setting up a Wireguard-go tunnel and the tunnel being ready to serve
|
/// There is a brief period of time between setting up a Wireguard-go tunnel and the tunnel being ready to serve
|
||||||
/// traffic. This function blocks until the tunnel starts to serve traffic or until [connectivity::Check] times out.
|
/// traffic. This function blocks until the tunnel starts to serve traffic or until [connectivity::Check] times out.
|
||||||
async fn wait_for_routes(&self) -> Result<()> {
|
async fn wait_for_routes(&self) -> Result<()> {
|
||||||
let state = self.as_state();
|
let expected_routes = self.handle().tun_provider.lock().unwrap().real_routes();
|
||||||
|
|
||||||
let expected_routes = state.tun_provider.lock().unwrap().real_routes();
|
|
||||||
|
|
||||||
// Wait for routes to come up
|
// Wait for routes to come up
|
||||||
state
|
self.handle()
|
||||||
.route_manager
|
.route_manager
|
||||||
.clone()
|
.clone()
|
||||||
.wait_for_routes(expected_routes)
|
.wait_for_routes(expected_routes)
|
||||||
@ -585,9 +681,8 @@ impl WgGoTunnel {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
async fn ensure_tunnel_is_running(&self) -> Result<()> {
|
async fn ensure_tunnel_is_running(&self) -> Result<()> {
|
||||||
let state = self.as_state();
|
let addr = self.handle().config.ipv4_gateway;
|
||||||
let addr = state.config.ipv4_gateway;
|
let cancel_receiver = self.handle().cancel_receiver.clone();
|
||||||
let cancel_receiver = state.cancel_receiver.clone();
|
|
||||||
let mut check = connectivity::Check::new(addr, 0, cancel_receiver)
|
let mut check = connectivity::Check::new(addr, 0, cancel_receiver)
|
||||||
.map_err(|err| TunnelError::RecoverableStartWireguardError(Box::new(err)))?;
|
.map_err(|err| TunnelError::RecoverableStartWireguardError(Box::new(err)))?;
|
||||||
|
|
||||||
@ -612,16 +707,17 @@ impl WgGoTunnel {
|
|||||||
#[async_trait::async_trait]
|
#[async_trait::async_trait]
|
||||||
impl Tunnel for WgGoTunnel {
|
impl Tunnel for WgGoTunnel {
|
||||||
fn get_interface_name(&self) -> String {
|
fn get_interface_name(&self) -> String {
|
||||||
self.as_state().interface_name.clone()
|
self.handle().interface_name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(self: Box<Self>) -> Result<()> {
|
fn stop(mut self: Box<Self>) -> Result<()> {
|
||||||
self.into_state().stop()
|
WgGoTunnel::stop(&mut self)?;
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_tunnel_stats(&self) -> Result<StatsMap> {
|
async fn get_tunnel_stats(&self) -> Result<StatsMap> {
|
||||||
// NOTE: wireguard-go might perform blocking I/O, but it's most likely not a problem
|
// NOTE: wireguard-go might perform blocking I/O, but it's most likely not a problem
|
||||||
self.as_state()
|
self.handle()
|
||||||
.tunnel_handle
|
.tunnel_handle
|
||||||
.get_config(|cstr| {
|
.get_config(|cstr| {
|
||||||
Stats::parse_config_str(cstr.to_str().expect("Go strings are always UTF-8"))
|
Stats::parse_config_str(cstr.to_str().expect("Go strings are always UTF-8"))
|
||||||
@ -634,20 +730,19 @@ impl Tunnel for WgGoTunnel {
|
|||||||
&mut self,
|
&mut self,
|
||||||
config: Config,
|
config: Config,
|
||||||
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>> {
|
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + '_>> {
|
||||||
Box::pin(async move { self.as_state_mut().set_config(config) })
|
Box::pin(async move { self.set_config(config).await })
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(daita)]
|
#[cfg(daita)]
|
||||||
fn start_daita(&mut self, settings: DaitaSettings) -> Result<()> {
|
fn start_daita(&mut self, settings: DaitaSettings) -> Result<()> {
|
||||||
log::info!("Initializing DAITA for wireguard device");
|
log::info!("Initializing DAITA for wireguard device");
|
||||||
let config = &self.as_state().config;
|
let peer_public_key = self.handle().config.entry_peer.public_key.clone();
|
||||||
let peer_public_key = &config.entry_peer.public_key;
|
|
||||||
|
|
||||||
let machines = settings.client_machines.join("\n");
|
let machines = settings.client_machines.join("\n");
|
||||||
let machines =
|
let machines =
|
||||||
CString::new(machines).map_err(|err| TunnelError::StartDaita(Box::new(err)))?;
|
CString::new(machines).map_err(|err| TunnelError::StartDaita(Box::new(err)))?;
|
||||||
|
|
||||||
self.as_state()
|
self.handle()
|
||||||
.tunnel_handle
|
.tunnel_handle
|
||||||
.activate_daita(
|
.activate_daita(
|
||||||
peer_public_key.as_bytes(),
|
peer_public_key.as_bytes(),
|
||||||
|
@ -440,7 +440,9 @@ impl WgNtTunnel {
|
|||||||
);
|
);
|
||||||
|
|
||||||
match error {
|
match error {
|
||||||
Error::CreateTunnelDevice(error) => super::TunnelError::SetupTunnelDevice(error),
|
Error::CreateTunnelDevice(error) => super::TunnelError::SetupTunnelDevice(
|
||||||
|
talpid_tunnel::tun_provider::Error::Io(error),
|
||||||
|
),
|
||||||
_ => super::TunnelError::FatalStartWireguardError(Box::new(error)),
|
_ => super::TunnelError::FatalStartWireguardError(Box::new(error)),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user