diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-11-24 18:51:45 +0100 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-11-24 18:51:45 +0100 |
| commit | 71e469bdd21cfbf9dcec1bbd0e195c43303a722b (patch) | |
| tree | 31fa0d43eb7bb97bf7d895fa81ded864800620db | |
| parent | 299c6e6a6013f866a9f618e060edf0bfbb2fd7fc (diff) | |
| parent | 6fb00c9c0890e661bef225c7d40bde8c0ea858ff (diff) | |
| download | mullvadvpn-71e469bdd21cfbf9dcec1bbd0e195c43303a722b.tar.xz mullvadvpn-71e469bdd21cfbf9dcec1bbd0e195c43303a722b.zip | |
Merge branch 'openvpn-2.5'
26 files changed, 577 insertions, 493 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index af0fb1d27c..acef112297 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,7 @@ Line wrap the file at 100 chars. Th - Randomly select addresses to use for communicating with the API. - Bundle a list of API addresses to use instead of assuming that the primary address can be reached. - Rename CLI subcommand `mullvad relay set relay` to `mullvad relay set hostname`. +- Upgrade OpenVPN from 2.4.9 to 2.5.0. #### Android - Remove the Quit button. @@ -63,6 +64,9 @@ Line wrap the file at 100 chars. Th - Set up routes for OpenVPN using the route manager instead of relying on OpenVPN. - Use rule-based routing and static routes. +#### Windows +- Use Wintun instead of the OpenVPN TAP driver for OpenVPN. + ### Fixed - Fix missing map animation after selecting a new location in the desktop app. - Fix crash on older kernels which report a default route through the loopback interface. @@ -104,6 +108,7 @@ Line wrap the file at 100 chars. Th even if the tunnel was up when the crash occurred. - Add firewall rules for `mullvad-exclude`, i.e. split tunneling, that disallow all traffic in the tunnel other than non-custom DNS traffic. This prevents leaks into the tunnel. +- Force OpenVPN to use TLS 1.3 or newer. #### Windows - Block all traffic received or sent before the BFE service and daemon service have started during diff --git a/Cargo.lock b/Cargo.lock index ae329be543..33f33fdc61 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,8 +98,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25f9db3b38af870bf7e5cc649167533b493928e50744e2c30ae350230b414670" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -109,8 +109,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "687c230d85c0a52504709705fc8a53e4a692b83a2184f03dae73e38e1e93a783" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -368,9 +368,9 @@ dependencies = [ "fnv", "ident_case", "proc-macro2", - "quote 1.0.7", + "quote", "strsim 0.9.3", - "syn 1.0.41", + "syn", ] [[package]] @@ -380,8 +380,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b5a2f4ac4969822c62224815d069952656cadc7084fdca9751e6d959189b72" dependencies = [ "darling_core", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -396,12 +396,13 @@ dependencies = [ [[package]] name = "derive-try-from-primitive" -version = "0.1.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dbd65eb15734b6d50dc6ac86f14f928462be0a5df6bda17761e909071ede5d" +checksum = "302ccf094df1151173bb6f5a2282fcd2f45accd5eae1bdf82dcbfefbc501ad5c" dependencies = [ - "quote 0.3.15", - "syn 0.11.11", + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -413,8 +414,8 @@ dependencies = [ "darling", "derive_builder_core", "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -425,8 +426,8 @@ checksum = "2791ea3e372c8495c0bc2033991d76b512cd799d07491fbd6890124db9458bef" dependencies = [ "darling", "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -497,9 +498,9 @@ checksum = "22deed3a8124cff5fa835713fa105621e43bbdc46690c3a6b68328a012d350d4" dependencies = [ "proc-macro-error", "proc-macro2", - "quote 1.0.7", + "quote", "rustversion", - "syn 1.0.41", + "syn", "synstructure", ] @@ -551,8 +552,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", "synstructure", ] @@ -681,8 +682,8 @@ checksum = "d0b5a30a4328ab5473878237c447333c093297bded83a4983d10f4deea240d39" dependencies = [ "proc-macro-hack", "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -1016,8 +1017,8 @@ checksum = "c78132fe420156f13b30518fcda9449b0ab8ae3b5584e8a1c53ce390fe770b44" dependencies = [ "heck", "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -1638,8 +1639,9 @@ checksum = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de" [[package]] name = "openvpn-plugin" -version = "0.3.0" -source = "git+https://github.com/mullvad/openvpn-plugin-rs?branch=auth-failed-event#c989d7a43de59e4207c31355be7952251273236b" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f433e2b9c41d166526a6737b96ebf015f27f5c94b95bad06295943c241601e40" dependencies = [ "derive-try-from-primitive", "log 0.4.11", @@ -1789,8 +1791,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c0e815c3ee9a031fdf5af21c10aa17c573c9c6a566328d99e3936c34e36461f" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -1864,8 +1866,8 @@ checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", "version_check", ] @@ -1876,7 +1878,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ "proc-macro2", - "quote 1.0.7", + "quote", "version_check", ] @@ -1938,8 +1940,8 @@ dependencies = [ "anyhow", "itertools", "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -1977,18 +1979,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "608c156fd8e97febc07dc9c2e2c80bf74cfc6ef26893eae3daf8bc2bc94a4b7f" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] name = "quote" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" - -[[package]] -name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" @@ -2199,8 +2195,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9bdc5e856e51e685846fb6c13a1f5e5432946c2c90501bdc76a1319f19e29da" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -2310,8 +2306,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -2420,44 +2416,24 @@ checksum = "343f3f510c2915908f155e94f17220b19ccfacf2a64a2a5d8004f2c3e311e7fd" [[package]] name = "syn" -version = "0.11.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" -dependencies = [ - "quote 0.3.15", - "synom", - "unicode-xid 0.0.4", -] - -[[package]] -name = "syn" version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" dependencies = [ "proc-macro2", - "quote 1.0.7", + "quote", "unicode-xid 0.2.1", ] [[package]] -name = "synom" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" -dependencies = [ - "unicode-xid 0.0.4", -] - -[[package]] name = "synstructure" version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b834f2d66f734cb897113e34aaff2f1ab4719ca946f9a7358dba8f8064148701" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", "unicode-xid 0.2.1", ] @@ -2680,8 +2656,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd80fc12f73063ac132ac92aceea36734f04a1d93c1240c6944e23a3b8841793" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -2735,8 +2711,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0c3acc6aa564495a0f2e1d59fab677cd7f81a19994cfc7f3ad0e64301560389" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -2826,8 +2802,8 @@ checksum = "19970cf58f3acc820962be74c4021b8bbc8e8a1c4e3a02095d0aa60cde5f3633" dependencies = [ "proc-macro2", "prost-build", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -3027,8 +3003,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", ] [[package]] @@ -3109,12 +3085,6 @@ checksum = "36dff09cafb4ec7c8cf0023eb0b686cb6ce65499116a12201c9e11840ca01beb" [[package]] name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" - -[[package]] -name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" @@ -3220,8 +3190,8 @@ dependencies = [ "lazy_static", "log 0.4.11", "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", "wasm-bindgen-shared", ] @@ -3231,7 +3201,7 @@ version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6b13312a745c08c469f0b292dd2fcd6411dba5f7160f593da6ef69b64e407038" dependencies = [ - "quote 1.0.7", + "quote", "wasm-bindgen-macro-support", ] @@ -3242,8 +3212,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f249f06ef7ee334cc3b8ff031bfc11ec99d00f34d86da7498396dc1e3b1498fe" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3415,7 +3385,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f369ddb18862aba61aa49bf31e74d29f0f162dec753063200e1dc084345d16" dependencies = [ "proc-macro2", - "quote 1.0.7", - "syn 1.0.41", + "quote", + "syn", "synstructure", ] diff --git a/dist-assets/binaries b/dist-assets/binaries -Subproject b82a3e9a7717b8b15c339bc78d4a2f3c6d90ea5 +Subproject 793ca61d9335f9a4342fe8624c9987bf21899ca diff --git a/dist-assets/windows/installer.nsh b/dist-assets/windows/installer.nsh index 80c4ba998b..47b3536244 100644 --- a/dist-assets/windows/installer.nsh +++ b/dist-assets/windows/installer.nsh @@ -12,8 +12,8 @@ # Do not compare variables using the <> operator - broken # -# TAP device hardware ID -!define TAP_HARDWARE_ID "tapmullvad0901" +!define WINTUN_POOL "Mullvad" +!define WINTUN_ADAPTER "Mullvad" # "sc" exit code !define SERVICE_STARTED 0 @@ -24,6 +24,7 @@ !define MULLVAD_SUCCESS 1 # Return codes from driverlogic +!define DL_ADAPTER_NOT_FOUND -2 !define DL_GENERAL_ERROR -1 !define DL_GENERAL_SUCCESS 0 @@ -48,31 +49,6 @@ !define PERSISTENT_BLOCK_OUTBOUND_IPV4_FILTER_GUID "{79860c64-9a5e-48a3-b5f3-d64b41659aa5}" # -# ExtractTapDriver -# -# Extract the correct driver for the current platform -# placing it into $TEMP\tap-driver -# -!macro ExtractTapDriver - - SetOutPath "$TEMP\tap-driver" - - File "${BUILD_RESOURCES_DIR}\..\windows\driverlogic\bin\x64-Release\driverlogic.exe" - File "${BUILD_RESOURCES_DIR}\binaries\x86_64-pc-windows-msvc\tap-driver\*" - - ${If} ${AtLeastWin10} - File "${BUILD_RESOURCES_DIR}\binaries\x86_64-pc-windows-msvc\tap-driver\win10\*" - ${ElseIf} ${AtLeastWin8} - File "${BUILD_RESOURCES_DIR}\binaries\x86_64-pc-windows-msvc\tap-driver\win8\*" - ${Else} - File "${BUILD_RESOURCES_DIR}\binaries\x86_64-pc-windows-msvc\tap-driver\win7\*" - ${EndIf} - -!macroend - -!define ExtractTapDriver '!insertmacro "ExtractTapDriver"' - -# # ExtractWintun # # Extract Wintun installer into $TEMP @@ -80,7 +56,8 @@ !macro ExtractWintun SetOutPath "$TEMP" - File "${BUILD_RESOURCES_DIR}\binaries\x86_64-pc-windows-msvc\mullvad-wintun-amd64.msi" + File "${BUILD_RESOURCES_DIR}\binaries\x86_64-pc-windows-msvc\wintun.dll" + File "${BUILD_RESOURCES_DIR}\..\windows\driverlogic\bin\x64-Release\driverlogic.exe" !macroend @@ -102,185 +79,87 @@ !define ExtractMullvadSetup '!insertmacro "ExtractMullvadSetup"' # -# RemoveBrandedTap -# -# Try to remove the Mullvad TAP adapter driver -# -!macro RemoveBrandedTap - Push $0 - Push $1 - - nsExec::ExecToStack '"$TEMP\tap-driver\driverlogic.exe" remove ${TAP_HARDWARE_ID}' - Pop $0 - Pop $1 - - Pop $1 - Pop $0 - -!macroend - -!define RemoveBrandedTap '!insertmacro "RemoveBrandedTap"' - -# -# RemoveVanillaTap +# RemoveWintun # -# Try to remove the old Mullvad TAP adapter (with a non-unique hardware ID), -# and uninstall the driver if it's not in use. +# Try to remove Wintun # -!macro RemoveVanillaTap +!macro RemoveWintun Push $0 Push $1 - log::Log "RemoveVanillaTap()" - - nsExec::ExecToStack '"$TEMP\tap-driver\driverlogic.exe" remove-vanilla-tap' + log::Log "RemoveWintun()" + nsExec::ExecToStack '"$TEMP\driverlogic.exe" wintun delete-pool-driver ${WINTUN_POOL}' Pop $0 Pop $1 ${If} $0 != ${DL_GENERAL_SUCCESS} IntFmt $0 "0x%X" $0 - StrCpy $R0 "Failed to remove vanilla TAP adapter: error $0" + StrCpy $R0 "Failed to remove Wintun pool: error $0" log::LogWithDetails $R0 $1 - - Goto RemoveVanillaTap_return + Goto RemoveWintun_return_only ${EndIf} - log::Log "RemoveVanillaTap() completed successfully" - - RemoveVanillaTap_return: + log::Log "RemoveWintun() completed successfully" Push 0 Pop $R0 + RemoveWintun_return_only: + Pop $1 Pop $0 !macroend -!define RemoveVanillaTap '!insertmacro "RemoveVanillaTap"' +!define RemoveWintun '!insertmacro "RemoveWintun"' # -# InstallTapDriver +# InstallWintun # -# Install OpenVPN TAP adapter driver +# Create Wintun Mullvad adapter # # Returns: 0 in $R0 on success, otherwise an error message in $R0 # -!macro InstallTapDriver +!macro InstallWintun - log::Log "InstallTapDriver()" + log::Log "InstallWintun()" Push $0 Push $1 - # - # Remove the old-ID Mullvad TAP, if it exists - # - ${RemoveVanillaTap} - - # - # Silently approve the certificate before installing the driver - # - ${IfNot} ${AtLeastWin10} - log::Log "Adding OpenVPN certificate to the certificate store" - - nsExec::ExecToStack '"$SYSDIR\certutil.exe" -f -addstore TrustedPublisher "$TEMP\tap-driver\driver.cer"' - Pop $0 - Pop $1 - - ${If} $0 != 0 - StrCpy $R0 "Failed to add trusted publisher certificate: error $0" - log::LogWithDetails $R0 $1 - ${EndIf} - ${EndIf} - - log::Log "Creating new virtual adapter" - nsExec::ExecToStack '"$TEMP\tap-driver\driverlogic.exe" install "$TEMP\tap-driver\OemVista.inf"' + nsExec::ExecToStack '"$TEMP\driverlogic.exe" wintun adapter-exists ${WINTUN_POOL} ${WINTUN_ADAPTER}' Pop $0 Pop $1 - ${If} $0 != ${DL_GENERAL_SUCCESS} + ${If} $0 == ${DL_GENERAL_ERROR} IntFmt $0 "0x%X" $0 - StrCpy $R0 "Failed to create virtual adapter: error $0" + StrCpy $R0 "Failed to identify virtual adapter: error $0" log::LogWithDetails $R0 $1 - Goto InstallTapDriver_return + Goto InstallWintun_return ${EndIf} - log::Log "InstallTapDriver() completed successfully" - - Push 0 - Pop $R0 - - InstallTapDriver_return: - - Pop $1 - Pop $0 - -!macroend - -!define InstallTapDriver '!insertmacro "InstallTapDriver"' - -# -# RemoveWintun -# -# Try to remove Wintun -# -!macro RemoveWintun - Push $0 - Push $1 - - log::Log "RemoveWintun()" - - msiutil::SilentUninstall "$TEMP\mullvad-wintun-amd64.msi" - Pop $0 - Pop $1 - - ${If} $0 != ${MULLVAD_SUCCESS} - StrCpy $R0 "Failed to remove Wintun: $1" - log::Log $R0 - Goto RemoveWintun_return_only + ${If} $0 != ${DL_ADAPTER_NOT_FOUND} + log::Log "Found existing virtual adapter" + Goto InstallWintun_return_success ${EndIf} - log::Log "RemoveWintun() completed successfully" - - Push 0 - Pop $R0 - - RemoveWintun_return_only: - - Pop $1 - Pop $0 - -!macroend - -!define RemoveWintun '!insertmacro "RemoveWintun"' - -# -# InstallWintun -# -# Install Wintun driver -# -# Returns: 0 in $R0 on success, otherwise an error message in $R0 -# -!macro InstallWintun - - log::Log "InstallWintun()" - - Push $0 - Push $1 + log::Log "Creating new virtual adapter" + nsExec::ExecToStack '"$TEMP\driverlogic.exe" wintun create-adapter ${WINTUN_POOL} ${WINTUN_ADAPTER}' - msiutil::SilentInstall "$TEMP\mullvad-wintun-amd64.msi" Pop $0 Pop $1 - ${If} $0 != ${MULLVAD_SUCCESS} - StrCpy $R0 "Failed to install Wintun: $1" - log::Log $R0 + ${If} $0 != ${DL_GENERAL_SUCCESS} + IntFmt $0 "0x%X" $0 + StrCpy $R0 "Failed to create virtual adapter: error $0" + log::LogWithDetails $R0 $1 Goto InstallWintun_return ${EndIf} + InstallWintun_return_success: + log::Log "InstallWintun() completed successfully" Push 0 @@ -746,14 +625,6 @@ ${RemoveRelayCache} ${RemoveApiAddressCache} - ${ExtractTapDriver} - ${InstallTapDriver} - - ${If} $R0 != 0 - MessageBox MB_OK "Fatal error during driver installation: $R0" - Goto customInstall_abort_installation - ${EndIf} - ${ExtractWintun} ${InstallWintun} @@ -890,10 +761,6 @@ ${RemoveCLIFromEnvironPath} - # Remove the TAP adapter - ${ExtractTapDriver} - ${RemoveBrandedTap} - ${If} $FullUninstall == 1 ${ClearFirewallRules} ${ClearAccountHistory} diff --git a/gui/src/main/daemon-rpc.ts b/gui/src/main/daemon-rpc.ts index c7f4ce8608..ffb455365c 100644 --- a/gui/src/main/daemon-rpc.ts +++ b/gui/src/main/daemon-rpc.ts @@ -776,8 +776,8 @@ function convertFromTunnelStateErrorCause( return { reason: 'ipv6_unavailable' }; case grpcTypes.ErrorState.Cause.START_TUNNEL_ERROR: return { reason: 'start_tunnel_error' }; - case grpcTypes.ErrorState.Cause.TAP_ADAPTER_PROBLEM: - return { reason: 'tap_adapter_problem' }; + case grpcTypes.ErrorState.Cause.VIRTUAL_ADAPTER_PROBLEM: + return { reason: 'virtual_adapter_problem' }; case grpcTypes.ErrorState.Cause.SET_FIREWALL_POLICY_ERROR: return { reason: 'set_firewall_policy_error', diff --git a/gui/src/shared/daemon-rpc-types.ts b/gui/src/shared/daemon-rpc-types.ts index bac978f7d6..95d8758088 100644 --- a/gui/src/shared/daemon-rpc-types.ts +++ b/gui/src/shared/daemon-rpc-types.ts @@ -38,7 +38,7 @@ export type ErrorStateCause = | 'set_dns_error' | 'start_tunnel_error' | 'is_offline' - | 'tap_adapter_problem'; + | 'virtual_adapter_problem'; } | { reason: 'set_firewall_policy_error'; details: FirewallPolicyError } | { reason: 'tunnel_parameter_error'; details: TunnelParameterError } diff --git a/gui/src/shared/notifications/error.ts b/gui/src/shared/notifications/error.ts index d9fd12de1a..672dc27b94 100644 --- a/gui/src/shared/notifications/error.ts +++ b/gui/src/shared/notifications/error.ts @@ -117,10 +117,10 @@ function getMessage(errorDetails: IErrorState, accountExpiry?: string): string { 'notifications', "Your device is offline. Try connecting when it's back online.", ); - case 'tap_adapter_problem': + case 'virtual_adapter_problem': return messages.pgettext( 'notifications', - 'Unable to detect a working TAP adapter on this device. Try enabling it. Otherwise, please reinstall the app.', + 'Unable to detect a working virtual adapter on this device. Try enabling it. Otherwise, please reinstall the app.', ); } } diff --git a/mullvad-cli/src/format.rs b/mullvad-cli/src/format.rs index 92f6076e66..7070e322ac 100644 --- a/mullvad-cli/src/format.rs +++ b/mullvad-cli/src/format.rs @@ -138,7 +138,6 @@ fn error_state_to_string(error_state: &ErrorState) -> String { ); } IsOffline => "This device is offline, no tunnels can be established", - TapAdapterProblem => "A problem with the TAP adapter has been detected", #[cfg(target_os = "android")] VpnPermissionDenied => "The Android VPN permission was denied when creating the tunnel", #[cfg(not(target_os = "android"))] diff --git a/mullvad-daemon/src/management_interface.rs b/mullvad-daemon/src/management_interface.rs index a19179a502..57d063c6a9 100644 --- a/mullvad-daemon/src/management_interface.rs +++ b/mullvad-daemon/src/management_interface.rs @@ -1370,8 +1370,8 @@ fn convert_state(state: TunnelState) -> types::TunnelState { i32::from(ProtoErrorCause::TunnelParameterError) } ErrorStateCause::IsOffline => i32::from(ProtoErrorCause::IsOffline), - ErrorStateCause::TapAdapterProblem => { - i32::from(ProtoErrorCause::TapAdapterProblem) + ErrorStateCause::VirtualAdapterProblem => { + i32::from(ProtoErrorCause::VirtualAdapterProblem) } #[cfg(target_os = "android")] ErrorStateCause::VpnPermissionDenied => { diff --git a/mullvad-management-interface/proto/management_interface.proto b/mullvad-management-interface/proto/management_interface.proto index 6d40e50d78..817d97cd95 100644 --- a/mullvad-management-interface/proto/management_interface.proto +++ b/mullvad-management-interface/proto/management_interface.proto @@ -96,7 +96,7 @@ message ErrorState { START_TUNNEL_ERROR = 4; TUNNEL_PARAMETER_ERROR = 5; IS_OFFLINE = 6; - TAP_ADAPTER_PROBLEM = 7; + VIRTUAL_ADAPTER_PROBLEM = 7; VPN_PERMISSION_DENIED = 8; } diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml index 5ea9a2fea7..d9e9b544a9 100644 --- a/talpid-core/Cargo.toml +++ b/talpid-core/Cargo.toml @@ -31,7 +31,7 @@ rand = "0.7" [target.'cfg(not(target_os="android"))'.dependencies] -openvpn-plugin = { git = "https://github.com/mullvad/openvpn-plugin-rs", branch = "auth-failed-event", features = ["serde"] } +openvpn-plugin = { version = "0.4", features = ["serde", "auth-failed-event"] } parity-tokio-ipc = "0.7" triggered = "0.1.1" tonic = "0.3.1" diff --git a/talpid-core/src/firewall/windows.rs b/talpid-core/src/firewall/windows.rs index 90f1d73c78..ac1b0b41d9 100644 --- a/talpid-core/src/firewall/windows.rs +++ b/talpid-core/src/firewall/windows.rs @@ -39,9 +39,9 @@ pub enum Error { #[error(display = "Failed to reset firewall policies")] ResettingPolicy(#[error(source)] FirewallPolicyError), - /// Failure to set TAP adapter metric - #[error(display = "Unable to set TAP adapter metric")] - SetTapMetric(#[error(source)] crate::winnet::Error), + /// Failure to set virtual adapter metric + #[error(display = "Unable to set virtual adapter metric")] + SetTunMetric(#[error(source)] crate::winnet::Error), } const WINFW_TIMEOUT_SECONDS: u32 = 2; @@ -214,7 +214,7 @@ impl Firewall { }; let metrics_set = winnet::ensure_best_metric_for_interface(&tunnel_metadata.interface) - .map_err(Error::SetTapMetric)?; + .map_err(Error::SetTunMetric)?; if metrics_set { debug!("Network interface metrics were changed"); diff --git a/talpid-core/src/process/openvpn.rs b/talpid-core/src/process/openvpn.rs index e4172ff4ec..de5206a56b 100644 --- a/talpid-core/src/process/openvpn.rs +++ b/talpid-core/src/process/openvpn.rs @@ -30,7 +30,7 @@ static BASE_ARGUMENTS: &[&[&str]] = &[ &["--sndbuf", "1048576"], &["--fast-io"], &["--cipher", "AES-256-CBC"], - &["--tls-version-min", "1.2"], + &["--tls-version-min", "1.3"], &["--verb", "3"], #[cfg(windows)] &[ @@ -45,15 +45,32 @@ static BASE_ARGUMENTS: &[&[&str]] = &[ // The route manager is used to add the routes. #[cfg(target_os = "linux")] &["--route-noexec"], + #[cfg(windows)] + &["--ip-win32", "ipapi"], ]; -static ALLOWED_TLS1_2_CIPHERS: &[&str] = &[ - "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384", - "TLS-DHE-RSA-WITH-AES-256-CBC-SHA", -]; static ALLOWED_TLS1_3_CIPHERS: &[&str] = &["TLS_AES_256_GCM_SHA384", "TLS_CHACHA20_POLY1305_SHA256"]; +/// Tun driver to use, specified using `--windows-driver`. +#[derive(Clone)] +pub enum WindowsDriver { + /// TAP adapter driver + TapWindows6, + /// Wintun driver + Wintun, +} + +impl WindowsDriver { + /// Return string to use with the `--windows-driver` option. + pub fn as_str(&self) -> &'static str { + match self { + WindowsDriver::TapWindows6 => "tap-windows6", + WindowsDriver::Wintun => "wintun", + } + } +} + /// An OpenVPN process builder, providing control over the different arguments that the OpenVPN /// binary accepts. #[derive(Clone)] @@ -70,6 +87,8 @@ pub struct OpenVpnCommand { log: Option<PathBuf>, tunnel_options: net::openvpn::TunnelOptions, proxy_settings: Option<net::openvpn::ProxySettings>, + #[cfg(windows)] + windows_driver: Option<WindowsDriver>, tunnel_alias: Option<OsString>, enable_ipv6: bool, proxy_port: Option<u16>, @@ -92,6 +111,8 @@ impl OpenVpnCommand { log: None, tunnel_options: net::openvpn::TunnelOptions::default(), proxy_settings: None, + #[cfg(windows)] + windows_driver: None, tunnel_alias: None, enable_ipv6: true, proxy_port: None, @@ -160,6 +181,13 @@ impl OpenVpnCommand { self } + /// Sets the driver to use for tunneling + #[cfg(windows)] + pub fn windows_driver(&mut self, driver: Option<WindowsDriver>) -> &mut Self { + self.windows_driver = driver; + self + } + /// Sets the tunnel alias which will be used to identify a tunnel device that will be used by /// OpenVPN. pub fn tunnel_alias(&mut self, tunnel_alias: Option<OsString>) -> &mut Self { @@ -249,6 +277,12 @@ impl OpenVpnCommand { args.push(tunnel_device.clone()); } + #[cfg(windows)] + if let Some(ref windows_driver) = self.windows_driver { + args.push(OsString::from("--windows-driver")); + args.push(OsString::from(windows_driver.as_str())); + } + args.extend(Self::tls_cipher_arguments().iter().map(OsString::from)); args.extend(self.proxy_arguments().iter().map(OsString::from)); @@ -274,8 +308,6 @@ impl OpenVpnCommand { fn tls_cipher_arguments() -> Vec<String> { let mut args = vec![]; - args.push("--tls-cipher".to_owned()); - args.push(ALLOWED_TLS1_2_CIPHERS.join(":")); args.push("--tls-ciphersuites".to_owned()); args.push(ALLOWED_TLS1_3_CIPHERS.join(":")); args diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index 81ca04519a..3e27b792c8 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -387,7 +387,7 @@ fn try_enabling_ipv6(tunnel_parameters: &TunnelParameters) -> Result<()> { let guid = match tunnel_parameters { TunnelParameters::OpenVpn(..) => { - let alias = crate::winnet::get_tap_interface_alias().map_err(Error::WinnetError)?; + let alias = crate::winnet::get_interface_alias().map_err(Error::WinnetError)?; guid_string = crate::winnet::interface_alias_to_guid(&alias).map_err(Error::WinnetError)?; &guid_string diff --git a/talpid-core/src/tunnel/openvpn.rs b/talpid-core/src/tunnel/openvpn.rs index 54591565fb..dcd2268772 100644 --- a/talpid-core/src/tunnel/openvpn.rs +++ b/talpid-core/src/tunnel/openvpn.rs @@ -70,15 +70,15 @@ pub enum Error { #[error(display = "The OpenVPN event dispatcher exited unexpectedly")] EventDispatcherExited, - /// No TAP adapter was detected + /// No virtual adapter was detected #[cfg(windows)] - #[error(display = "No TAP adapter was detected")] - MissingTapAdapter, + #[error(display = "No virtual adapter was detected")] + MissingVirtualAdapter, - /// TAP adapter seems to be disabled + /// virtual adapter seems to be disabled #[cfg(windows)] - #[error(display = "The TAP adapter appears to be disabled")] - DisabledTapAdapter, + #[error(display = "The virtual adapter appears to be disabled")] + DisabledVirtualAdapter, /// OpenVPN process died unexpectedly #[error(display = "OpenVPN process died unexpectedly")] @@ -510,10 +510,10 @@ impl<C: OpenVpnBuilder + 'static> OpenVpnMonitor<C> { if let Some(log_path) = self.log_path.take() { if let Ok(log) = fs::read_to_string(log_path) { if log.contains("There are no TAP-Windows adapters on this system") { - return Error::MissingTapAdapter; + return Error::MissingVirtualAdapter; } if log.contains("CreateFile failed on TAP device") { - return Error::DisabledTapAdapter; + return Error::DisabledVirtualAdapter; } } } @@ -600,9 +600,12 @@ impl<C: OpenVpnBuilder + 'static> OpenVpnMonitor<C> { .enable_ipv6(params.generic_options.enable_ipv6) .ca(resource_dir.join("ca.crt")); #[cfg(windows)] - cmd.tunnel_alias(Some( - crate::winnet::get_tap_interface_alias().map_err(Error::WinnetError)?, - )); + { + cmd.tunnel_alias(Some( + crate::winnet::get_interface_alias().map_err(Error::WinnetError)?, + )); + cmd.windows_driver(Some(crate::process::openvpn::WindowsDriver::Wintun)); + } if let Some(proxy_settings) = params.proxy.clone().take() { cmd.proxy_settings(proxy_settings); } @@ -721,6 +724,7 @@ mod event_server { use parity_tokio_ipc::{Endpoint as IpcEndpoint, SecurityAttributes}; use std::{ collections::HashMap, + convert::TryFrom, pin::Pin, task::{Context, Poll}, }; @@ -769,8 +773,10 @@ mod event_server { let request = request.into_inner(); - let event_type = openvpn_plugin::EventType::try_from(request.event) - .ok_or(tonic::Status::invalid_argument("Unknown event type"))?; + let event_type = + openvpn_plugin::EventType::try_from(request.event).map_err(|event: i32| { + tonic::Status::invalid_argument(format!("Unknown event type: {}", event)) + })?; (self.on_event)(event_type, request.env); diff --git a/talpid-core/src/tunnel_state_machine/connecting_state.rs b/talpid-core/src/tunnel_state_machine/connecting_state.rs index 60f87787a2..bc59a1d812 100644 --- a/talpid-core/src/tunnel_state_machine/connecting_state.rs +++ b/talpid-core/src/tunnel_state_machine/connecting_state.rs @@ -154,18 +154,18 @@ impl ConnectingState { error @ tunnel::Error::OpenVpnTunnelMonitoringError( - tunnel::openvpn::Error::DisabledTapAdapter, + tunnel::openvpn::Error::DisabledVirtualAdapter, ) | error @ tunnel::Error::OpenVpnTunnelMonitoringError( - tunnel::openvpn::Error::MissingTapAdapter, + tunnel::openvpn::Error::MissingVirtualAdapter, ) => { warn!( "{}", - error.display_chain_with_msg("TAP adapter problem detected") + error.display_chain_with_msg("Virtual adapter problem detected") ); - Some(ErrorStateCause::TapAdapterProblem) + Some(ErrorStateCause::VirtualAdapterProblem) } error => { warn!( @@ -416,12 +416,12 @@ impl TunnelState for ConnectingState { #[cfg(windows)] tunnel::Error::OpenVpnTunnelMonitoringError( tunnel::openvpn::Error::WinnetError( - crate::winnet::Error::GetTapAlias, + crate::winnet::Error::GetVirtualAdapterAlias, ), ) | tunnel::Error::WinnetError( - crate::winnet::Error::GetTapAlias, - ) => ErrorStateCause::TapAdapterProblem, + crate::winnet::Error::GetVirtualAdapterAlias, + ) => ErrorStateCause::VirtualAdapterProblem, #[cfg(target_os = "android")] tunnel::Error::WireguardTunnelMonitoringError( tunnel::wireguard::Error::TunnelError( diff --git a/talpid-core/src/winnet.rs b/talpid-core/src/winnet.rs index 9fed90ac21..e78fd5f03b 100644 --- a/talpid-core/src/winnet.rs +++ b/talpid-core/src/winnet.rs @@ -41,9 +41,9 @@ pub enum Error { #[error(display = "Failed to read IPv6 status on the TAP network interface")] GetIpv6Status, - /// Failed to determine alias of TAP adapter. - #[error(display = "Failed to determine alias of TAP adapter")] - GetTapAlias, + /// Failed to determine alias of virtual adapter. + #[error(display = "Failed to determine alias of virtual adapter")] + GetVirtualAdapterAlias, /// Can't establish whether host is connected to a non-virtual network #[error(display = "Network connectivity undecideable")] @@ -102,15 +102,15 @@ pub fn enable_ipv6_for_adapter(interface_guid: &str) -> Result<(), Error> { } } -/// Dynamically determines the alias of the TAP adapter. -pub fn get_tap_interface_alias() -> Result<OsString, Error> { +/// Dynamically determines the alias of the virtual adapter. +pub fn get_interface_alias() -> Result<OsString, Error> { let mut alias_ptr: *mut wchar_t = ptr::null_mut(); let status = unsafe { - WinNet_GetTapInterfaceAlias(&mut alias_ptr as *mut _, Some(log_sink), logging_context()) + WinNet_GetInterfaceAlias(&mut alias_ptr as *mut _, Some(log_sink), logging_context()) }; if !status { - return Err(Error::GetTapAlias); + return Err(Error::GetVirtualAdapterAlias); } let alias = unsafe { WideCString::from_ptr_str(alias_ptr) }; @@ -521,8 +521,8 @@ mod api { sink_context: *const u8, ) -> WinNetStatus; - #[link_name = "WinNet_GetTapInterfaceAlias"] - pub fn WinNet_GetTapInterfaceAlias( + #[link_name = "WinNet_GetInterfaceAlias"] + pub fn WinNet_GetInterfaceAlias( tunnel_interface_alias: *mut *mut wchar_t, sink: Option<LogSink>, sink_context: *const u8, diff --git a/talpid-openvpn-plugin/Cargo.toml b/talpid-openvpn-plugin/Cargo.toml index 2a10e462e2..29799c3322 100644 --- a/talpid-openvpn-plugin/Cargo.toml +++ b/talpid-openvpn-plugin/Cargo.toml @@ -17,7 +17,7 @@ env_logger = "0.7" parity-tokio-ipc = "0.7" tokio = { version = "0.2", features = [ "rt-core" ] } -openvpn-plugin = { git = "https://github.com/mullvad/openvpn-plugin-rs", branch = "auth-failed-event", features = ["serde", "log"] } +openvpn-plugin = { version = "0.4", features = ["serde", "log", "auth-failed-event"] } talpid-types = { path = "../talpid-types" } tonic = "0.3.1" diff --git a/talpid-types/src/tunnel.rs b/talpid-types/src/tunnel.rs index c803a489a7..fd476e14c6 100644 --- a/talpid-types/src/tunnel.rs +++ b/talpid-types/src/tunnel.rs @@ -96,8 +96,8 @@ pub enum ErrorStateCause { TunnelParameterError(ParameterGenerationError), /// This device is offline, no tunnels can be established. IsOffline, - /// A problem with the TAP adapter has been detected. - TapAdapterProblem, + /// A problem with the virtual adapter has been detected. + VirtualAdapterProblem, /// The Android VPN permission was denied. #[cfg(target_os = "android")] VpnPermissionDenied, @@ -177,7 +177,7 @@ impl fmt::Display for ErrorStateCause { return write!(f, "Failure to generate tunnel parameters: {}", err); } IsOffline => "This device is offline, no tunnels can be established", - TapAdapterProblem => "A problem with the TAP adapter has been detected", + VirtualAdapterProblem => "A problem with the virtual adapter has been detected", #[cfg(target_os = "android")] VpnPermissionDenied => "The Android VPN permission was denied when creating the tunnel", }; diff --git a/windows/driverlogic/driverlogic.vcxproj b/windows/driverlogic/driverlogic.vcxproj index fd9ba06616..5d78c90479 100644 --- a/windows/driverlogic/driverlogic.vcxproj +++ b/windows/driverlogic/driverlogic.vcxproj @@ -61,7 +61,7 @@ <SDLCheck>true</SDLCheck> <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ConformanceMode>true</ConformanceMode> - <AdditionalIncludeDirectories>$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/;$(ProjectDir)../windows-libraries/src/;$(ProjectDir)../</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>$(ProjectDir)../../dist-assets/binaries/x86_64-pc-windows-msvc/;$(ProjectDir)../windows-libraries/src/;$(ProjectDir)../</AdditionalIncludeDirectories> <LanguageStandard>stdcpplatest</LanguageStandard> <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> </ClCompile> @@ -83,7 +83,7 @@ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> <ConformanceMode>true</ConformanceMode> <LanguageStandard>stdcpplatest</LanguageStandard> - <AdditionalIncludeDirectories>$(ProjectDir)../../../../dist-assets/binaries/x86_64-pc-windows-msvc/;$(ProjectDir)../windows-libraries/src/;$(ProjectDir)../</AdditionalIncludeDirectories> + <AdditionalIncludeDirectories>$(ProjectDir)../../dist-assets/binaries/x86_64-pc-windows-msvc/;$(ProjectDir)../windows-libraries/src/;$(ProjectDir)../</AdditionalIncludeDirectories> <RuntimeLibrary>MultiThreaded</RuntimeLibrary> </ClCompile> <Link> diff --git a/windows/driverlogic/src/driverlogic.cpp b/windows/driverlogic/src/driverlogic.cpp index 989ee70cf5..acc601811b 100644 --- a/windows/driverlogic/src/driverlogic.cpp +++ b/windows/driverlogic/src/driverlogic.cpp @@ -6,6 +6,7 @@ #include <string> #include <optional> #include <set> +#include <filesystem> #include <libcommon/error.h> #include <libcommon/guid.h> #include <libcommon/memory.h> @@ -20,21 +21,19 @@ #include <cfgmgr32.h> #include <io.h> #include <fcntl.h> +#include <wintun.h> namespace { -constexpr wchar_t DEPRECATED_TAP_HARDWARE_ID[] = L"tap0901"; -constexpr wchar_t TAP_HARDWARE_ID[] = L"tapmullvad0901"; -constexpr wchar_t TAP_BASE_ALIAS[] = L"Mullvad"; - constexpr std::chrono::milliseconds REGISTRY_GET_TIMEOUT_MS{ 10000 }; enum ReturnCodes { GENERAL_SUCCESS = 0, - GENERAL_ERROR = -1 + GENERAL_ERROR = -1, + ADAPTER_NOT_FOUND = -2 }; struct NetworkAdapter @@ -451,7 +450,7 @@ void ForEachNetworkDevice(const std::optional<std::wstring> hwId, std::function< // std::wstringstream ss; - ss << L"Skipping TAP adapter due to exception caught while iterating: " + ss << L"Skipping virtual adapter due to exception caught while iterating: " << common::string::ToWide(e.what()); LogError(ss.str()); continue; @@ -504,7 +503,76 @@ std::set<NetworkAdapter> GetNetworkAdapters(const std::optional<std::wstring> ha return adapters; } -void CreateTapDevice() +void throwUpdateException(DWORD lastError, const char *operation) +{ + if (ERROR_DEVICE_INSTALLER_NOT_READY == lastError) + { + bool deviceInstallDisabled = false; + + try + { + const auto key = common::registry::Registry::OpenKey( + HKEY_LOCAL_MACHINE, + L"SYSTEM\\CurrentControlSet\\Services\\DeviceInstall\\Parameters" + ); + deviceInstallDisabled = (0 != key->readUint32(L"DeviceInstallDisabled")); + } + catch (...) + { + } + + if (deviceInstallDisabled) + { + throw common::error::WindowsException( + "Device installs must be enabled to continue. " + "Enable them in the Local Group Policy editor, or " + "update the registry value DeviceInstallDisabled in " + "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DeviceInstall\\Parameters]", + lastError + ); + } + } + + THROW_SETUPAPI_ERROR(lastError, operation); +} + +// +// Broken adapters may use our "Mullvad" name, so find one that is not in use. +// NOTE: Enumerating adapters first and picking the next free name is not sufficient, +// because the broken adapter may not be included. +// +void RenameAdapter(const std::wstring &guid, const std::wstring &baseName) +{ + common::network::Nci nci; + + try + { + nci.setConnectionName(common::Guid::FromString(guid), baseName.c_str()); + return; + } + catch (...) + { + } + + for (int i = 1; i < 10; i++) + { + std::wstringstream ss; + ss << baseName << L"-" << i; + + try + { + nci.setConnectionName(common::Guid::FromString(guid), ss.str().c_str()); + return; + } + catch (...) + { + } + } + + THROW_ERROR("Unable to rename network adapter"); +} + +void CreateNetDevice(const std::wstring &hardwareId, const std::optional<std::wstring> alias, bool installDeviceDriver) { GUID classGuid = GUID_DEVCLASS_NET; @@ -542,8 +610,8 @@ void CreateTapDevice() deviceInfoSet, &devInfoData, SPDRP_HARDWAREID, - reinterpret_cast<const BYTE *>(TAP_HARDWARE_ID), - sizeof(TAP_HARDWARE_ID) - sizeof(L'\0') + reinterpret_cast<const BYTE *>(hardwareId.c_str()), + static_cast<DWORD>(sizeof(wchar_t) * hardwareId.size()) ); if (FALSE == status) @@ -565,117 +633,82 @@ void CreateTapDevice() THROW_SETUPAPI_ERROR(GetLastError(), "SetupDiCallClassInstaller"); } - Log(L"Created new TAP adapter successfully"); -} - -void UpdateTapDriver(const std::wstring &infPath) -{ - Log(L"Attempting to install new driver"); - - DWORD installFlags = 0; - BOOL rebootRequired = FALSE; + Log(L"Created new network adapter successfully"); -ATTEMPT_UPDATE: - - auto result = UpdateDriverForPlugAndPlayDevicesW( - nullptr, - TAP_HARDWARE_ID, - infPath.c_str(), - installFlags, - &rebootRequired - ); - - if (FALSE == result) + if (installDeviceDriver) { - const auto lastError = GetLastError(); - - if (ERROR_NO_MORE_ITEMS == lastError - && (installFlags ^ INSTALLFLAG_FORCE)) - { - Log(L"Driver update failed. Attempting forced install."); - installFlags |= INSTALLFLAG_FORCE; + BOOL rebootRequired = FALSE; - goto ATTEMPT_UPDATE; - } - - if (ERROR_DEVICE_INSTALLER_NOT_READY == lastError) + if (FALSE == DiInstallDevice( + nullptr, + deviceInfoSet, + &devInfoData, + nullptr, + 0, + &rebootRequired + )) { - bool deviceInstallDisabled = false; - - try - { - const auto key = common::registry::Registry::OpenKey( - HKEY_LOCAL_MACHINE, - L"SYSTEM\\CurrentControlSet\\Services\\DeviceInstall\\Parameters" - ); - deviceInstallDisabled = (0 != key->readUint32(L"DeviceInstallDisabled")); - } - catch (...) - { - } - - if (deviceInstallDisabled) - { - throw common::error::WindowsException( - "Device installs must be enabled to continue. " - "Enable them in the Local Group Policy editor, or " - "update the registry value DeviceInstallDisabled in " - "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Services\\DeviceInstall\\Parameters]", - lastError - ); - } + throwUpdateException(GetLastError(), "DiInstallDevice"); } - THROW_SETUPAPI_ERROR(lastError, "UpdateDriverForPlugAndPlayDevicesW"); + std::wstringstream ss; + ss << L"Installed driver on device. Reboot required: " + << rebootRequired; + Log(ss.str()); } - // - // Driver successfully installed or updated - // - - std::wstringstream ss; - ss << L"TAP driver update complete. Reboot required: " - << rebootRequired; - Log(ss.str()); + if (alias.has_value()) + { + RenameAdapter( + GetNetCfgInstanceId(deviceInfoSet, devInfoData), + alias.value() + ); + } } -// -// Broken adapters may use our "Mullvad" name, so find one that is not in use. -// NOTE: Enumerating adapters first and picking the next free name is not sufficient, -// because the broken TAP may not be included. -// -void RenameAdapterToMullvad(const NetworkAdapter &adapter) +std::wstring FindFreeAdapterAlias(const std::set<NetworkAdapter> &adapters, const std::wstring &baseName) { - common::network::Nci nci; - - try + if (adapters.empty()) { - nci.setConnectionName(common::Guid::FromString(adapter.guid), TAP_BASE_ALIAS); - return; + return baseName; } - catch (...) + + auto findByAlias = [](const std::set<NetworkAdapter> &adapters, const std::wstring &alias) { + const auto it = std::find_if(adapters.begin(), adapters.end(), [&alias](const NetworkAdapter &candidate) + { + return 0 == _wcsicmp(candidate.alias.c_str(), alias.c_str()); + }); + + return it; + }; + + const auto foundAdapter = findByAlias(adapters, baseName); + + if (adapters.end() == foundAdapter) + { + return baseName; } - for (int i = 1; i < 10; i++) + for (auto i = 1; i < 100; ++i) { std::wstringstream ss; - ss << TAP_BASE_ALIAS << L"-" << i; - try - { - nci.setConnectionName(common::Guid::FromString(adapter.guid), ss.str().c_str()); - return; - } - catch (...) + ss << baseName << L"-" << i; + + const auto alias = ss.str(); + const auto nextAdapter = findByAlias(adapters, alias); + + if (adapters.end() == nextAdapter) { + return alias; } } - THROW_ERROR("Exhausted TAP adapter namespace"); + THROW_ERROR("Cannot find an unused adapter alias") } -std::optional<NetworkAdapter> FindMullvadAdapter(const std::set<NetworkAdapter> &tapAdapters) +std::optional<NetworkAdapter> FindAdapterByAlias(const std::set<NetworkAdapter> &tapAdapters, const std::wstring &baseName) { if (tapAdapters.empty()) { @@ -683,7 +716,7 @@ std::optional<NetworkAdapter> FindMullvadAdapter(const std::set<NetworkAdapter> } // - // Look for TAP adapter with alias "Mullvad". + // Look for TAP adapter with aliases starting with baseName. // auto findByAlias = [](const std::set<NetworkAdapter> &adapters, const std::wstring &alias) @@ -696,7 +729,7 @@ std::optional<NetworkAdapter> FindMullvadAdapter(const std::set<NetworkAdapter> return it; }; - const auto firstMullvadAdapter = findByAlias(tapAdapters, TAP_BASE_ALIAS); + const auto firstMullvadAdapter = findByAlias(tapAdapters, baseName); if (tapAdapters.end() != firstMullvadAdapter) { @@ -711,7 +744,7 @@ std::optional<NetworkAdapter> FindMullvadAdapter(const std::set<NetworkAdapter> { std::wstringstream ss; - ss << TAP_BASE_ALIAS << L"-" << i; + ss << baseName << L"-" << i; const auto alias = ss.str(); @@ -726,30 +759,18 @@ std::optional<NetworkAdapter> FindMullvadAdapter(const std::set<NetworkAdapter> return std::nullopt; } -NetworkAdapter FindBrandedTap() +bool RemoveNetDevice(const std::wstring &tapHardwareId, const std::wstring &guid) { - std::set<NetworkAdapter> added = GetNetworkAdapters(TAP_HARDWARE_ID); - - if (added.empty()) - { - THROW_ERROR("Could not identify TAP"); - } - else if (added.size() > 1) - { - LogAdapters(L"Enumerable network TAP adapters", added); - - THROW_ERROR("Identified more TAP adapters than expected"); - } - - return *added.begin(); -} + bool deletedAdapter = false; -void RemoveTapDriver(const std::wstring &tapHardwareId) -{ - ForEachNetworkDevice(tapHardwareId, [](HDEVINFO devInfo, const SP_DEVINFO_DATA &devInfoData) { + ForEachNetworkDevice(tapHardwareId, [&](HDEVINFO devInfo, const SP_DEVINFO_DATA &devInfoData) { try { - DeleteDevice(devInfo, devInfoData); + if (0 == GetNetCfgInstanceId(devInfo, devInfoData).compare(guid)) + { + deletedAdapter = DeleteDevice(devInfo, devInfoData); + return false; + } } catch (const std::exception & e) { @@ -758,59 +779,222 @@ void RemoveTapDriver(const std::wstring &tapHardwareId) // std::wstringstream ss; - ss << L"Skipping TAP adapter due to exception caught while iterating: " + ss << L"Skipping virtual adapter due to exception caught while iterating: " << common::string::ToWide(e.what()); LogError(ss.str()); } return true; }); + + return deletedAdapter; } -void DeleteVanillaMullvadAdapter() +void RemoveNetAdapterByAlias(const std::wstring &hardwareId, const std::wstring &baseName) { - auto tapAdapters = GetNetworkAdapters(DEPRECATED_TAP_HARDWARE_ID); - std::optional<NetworkAdapter> mullvadAdapter = FindMullvadAdapter(tapAdapters); + auto tapAdapters = GetNetworkAdapters(hardwareId); + std::optional<NetworkAdapter> adapter = FindAdapterByAlias(tapAdapters, baseName); - if (!mullvadAdapter.has_value()) + if (!adapter.has_value()) { return; } - const auto mullvadGuid = mullvadAdapter.value().guid; - bool deletedAdapter = false; + const auto guid = adapter.value().guid; // - // Enumerate over all network devices with the hardware ID DEPRECATED_TAP_HARDWARE_ID, + // Enumerate over all network devices with the hardware ID, // and delete any adapter whose GUID matches that of the "Mullvad" adapter. // - ForEachNetworkDevice(DEPRECATED_TAP_HARDWARE_ID, [&](HDEVINFO devInfo, const SP_DEVINFO_DATA &devInfoData) { + if (!RemoveNetDevice(hardwareId, guid)) + { + THROW_ERROR("The virtual adapter could not be removed"); + } +} + +std::filesystem::path GetCurrentModulePath() +{ + std::vector<wchar_t> pathBuffer; + + SetLastError(ERROR_SUCCESS); + + size_t nextCapacity = 256; + + do + { + pathBuffer.reserve(nextCapacity); + + const auto writtenChars = GetModuleFileNameW(nullptr, &pathBuffer[0], static_cast<DWORD>(pathBuffer.capacity())); + + if (0 == writtenChars) + { + THROW_WINDOWS_ERROR(GetLastError(), "GetModuleFileNameW"); + } + + pathBuffer.resize(writtenChars); + + nextCapacity = 2 * pathBuffer.capacity(); + } while (ERROR_INSUFFICIENT_BUFFER == GetLastError()); + + return std::filesystem::path(pathBuffer.begin(), pathBuffer.end()); +} + +class WintunDll +{ +public: + + WintunDll() : dllHandle(nullptr) + { + auto wintunPath = GetCurrentModulePath().replace_filename(L"wintun.dll"); + dllHandle = LoadLibraryExW(wintunPath.c_str(), nullptr, LOAD_WITH_ALTERED_SEARCH_PATH); + + if (nullptr == dllHandle) + { + THROW_WINDOWS_ERROR(GetLastError(), "LoadLibraryExW"); + } + try { - if (0 == GetNetCfgInstanceId(devInfo, devInfoData).compare(mullvadGuid)) + createAdapter = getProcAddressOrThrow<WINTUN_CREATE_ADAPTER_FUNC>("WintunCreateAdapter"); + openAdapter = getProcAddressOrThrow<WINTUN_OPEN_ADAPTER_FUNC>("WintunOpenAdapter"); + freeAdapter = getProcAddressOrThrow<WINTUN_FREE_ADAPTER_FUNC>("WintunFreeAdapter"); + deletePoolDriver = getProcAddressOrThrow<WINTUN_DELETE_POOL_DRIVER_FUNC>("WintunDeletePoolDriver"); + } + catch (...) + { + FreeLibrary(dllHandle); + throw; + } + } + + ~WintunDll() + { + if (nullptr != dllHandle) + { + FreeLibrary(dllHandle); + } + } + + WINTUN_CREATE_ADAPTER_FUNC createAdapter; + WINTUN_OPEN_ADAPTER_FUNC openAdapter; + WINTUN_FREE_ADAPTER_FUNC freeAdapter; + WINTUN_DELETE_POOL_DRIVER_FUNC deletePoolDriver; + +private: + + template<typename T> + T getProcAddressOrThrow(const char *procName) + { + const T result = reinterpret_cast<T>(GetProcAddress(dllHandle, procName)); + if (nullptr == result) + { + THROW_WINDOWS_ERROR(GetLastError(), "GetProcAddress"); + } + return result; + } + + HMODULE dllHandle; +}; + +int HandleWintunCommands(int argc, const wchar_t *argv[]) +{ + WintunDll wintun; + + if (argc < 3) + { + goto INVALID_ARGUMENTS; + } + + if (0 == _wcsicmp(argv[2], L"create-adapter")) + { + if (argc < 5) + { + goto INVALID_ARGUMENTS; + } + + const wchar_t *pool = argv[3]; + const wchar_t *adapter = argv[4]; + + GUID guidObject; + const GUID *requestGuid = nullptr; + if (argc >= 6) + { + guidObject = common::Guid::FromString(argv[5]); + requestGuid = &guidObject; + } + + const auto adapters = GetNetworkAdapters(std::nullopt); + const auto freeAdapterName = FindFreeAdapterAlias(adapters, adapter); + + const auto handle = wintun.createAdapter( + pool, + freeAdapterName.c_str(), + requestGuid, + nullptr + ); + + if (nullptr == handle) + { + const auto status = GetLastError(); + if (ERROR_FILE_NOT_FOUND == status) { - deletedAdapter = DeleteDevice(devInfo, devInfoData); - return false; + return ADAPTER_NOT_FOUND; + } + else + { + THROW_WINDOWS_ERROR(status, "wintun.createAdapter"); } } - catch (const std::exception & e) + wintun.freeAdapter(handle); + } + else if (0 == _wcsicmp(argv[2], L"delete-pool-driver")) + { + if (4 != argc) { - // - // Skip this adapter - // + goto INVALID_ARGUMENTS; + } - std::wstringstream ss; - ss << L"Skipping TAP adapter due to exception caught while iterating: " - << common::string::ToWide(e.what()); - LogError(ss.str()); + const wchar_t *pool = argv[3]; + + wintun.deletePoolDriver(pool, nullptr); + } + else if (0 == _wcsicmp(argv[2], L"adapter-exists")) + { + if (5 != argc) + { + goto INVALID_ARGUMENTS; } - return true; - }); - if (!deletedAdapter) + const wchar_t *pool = argv[3]; + const wchar_t *adapter = argv[4]; + + const auto handle = wintun.openAdapter(pool, adapter); + + if (nullptr == handle) + { + const auto status = GetLastError(); + if (ERROR_FILE_NOT_FOUND == status) + { + return ADAPTER_NOT_FOUND; + } + else + { + THROW_WINDOWS_ERROR(status, "wintun.openAdapter"); + } + } + wintun.freeAdapter(handle); + } + else { - THROW_ERROR("The TAP adapter could not be removed"); + goto INVALID_ARGUMENTS; } + + return GENERAL_SUCCESS; + +INVALID_ARGUMENTS: + + LogError(L"Invalid arguments."); + return GENERAL_ERROR; } } // anonymous namespace @@ -830,38 +1014,51 @@ int wmain(int argc, const wchar_t * argv[], const wchar_t * []) try { - if (0 == _wcsicmp(argv[1], L"install")) + if (0 == _wcsicmp(argv[1], L"new-device")) { - if (3 != argc) + if (4 != argc) { goto INVALID_ARGUMENTS; } - CreateTapDevice(); - UpdateTapDriver(argv[2]); - RenameAdapterToMullvad(FindBrandedTap()); + const wchar_t *hardwareId = argv[2]; + const wchar_t *baseName = argv[3]; + + CreateNetDevice(hardwareId, baseName, true); } - else if (0 == _wcsicmp(argv[1], L"update")) + else if (0 == _wcsicmp(argv[1], L"remove-device")) { - if (3 != argc) + if (4 != argc) { goto INVALID_ARGUMENTS; } - UpdateTapDriver(argv[2]); + const wchar_t *hardwareId = argv[2]; + const wchar_t *baseName = argv[3]; + + RemoveNetAdapterByAlias(hardwareId, baseName); } - else if (0 == _wcsicmp(argv[1], L"remove")) + else if (0 == _wcsicmp(argv[1], L"device-exists")) { - if (3 != argc) + if (4 != argc) { goto INVALID_ARGUMENTS; } - RemoveTapDriver(argv[2]); + const wchar_t *hardwareId = argv[2]; + const wchar_t *baseName = argv[3]; + + const auto virtualAdapters = GetNetworkAdapters(hardwareId); + const auto adapter = FindAdapterByAlias(virtualAdapters, baseName); + + if (!adapter.has_value()) + { + return ADAPTER_NOT_FOUND; + } } - else if (0 == _wcsicmp(argv[1], L"remove-vanilla-tap")) + else if (0 == _wcsicmp(argv[1], L"wintun")) { - DeleteVanillaMullvadAdapter(); + return HandleWintunCommands(argc, argv); } else { diff --git a/windows/libshared/src/libshared/network/interfaceutils.cpp b/windows/libshared/src/libshared/network/interfaceutils.cpp index 042753aed6..26588206b3 100644 --- a/windows/libshared/src/libshared/network/interfaceutils.cpp +++ b/windows/libshared/src/libshared/network/interfaceutils.cpp @@ -5,6 +5,18 @@ #include <libcommon/error.h> #include <libcommon/string.h> +namespace +{ + +// Interface description substrings found for virtual adapters. +const wchar_t *TUNNEL_INTERFACE_DESCS[] = { + L"WireGuard", + L"Wintun", + L"Mullvad" +}; + +} // anonymous namespace + namespace shared::network { @@ -111,38 +123,34 @@ void InterfaceUtils::AddDeviceIpAddresses(NET_LUID device, const std::vector<SOC //static std::set<InterfaceUtils::NetworkAdapter> -InterfaceUtils::GetTapAdapters(const std::set<NetworkAdapter>& adapters) +InterfaceUtils::GetVirtualAdapters(const std::set<NetworkAdapter>& adapters) { - std::set<NetworkAdapter> tapAdapters; + std::set<NetworkAdapter> virtualAdapters; for (const auto& adapter : adapters) { - static constexpr wchar_t name[] = L"Mullvad VPN TAP Adapter"; - - // - // Compare partial name, because once you start having more TAP adapters - // they're named "Mullvad VPN TAP Adapter #2" and so on. - // - - if (0 == adapter.name().compare(0, _countof(name) - 1, name)) + for (size_t i = 0; i < ARRAYSIZE(TUNNEL_INTERFACE_DESCS); i++) { - tapAdapters.insert(adapter); + if (nullptr != wcsstr(adapter.raw().Description, TUNNEL_INTERFACE_DESCS[i])) + { + virtualAdapters.insert(adapter); + } } } - return tapAdapters; + return virtualAdapters; } //static -std::wstring InterfaceUtils::GetTapInterfaceAlias() +std::wstring InterfaceUtils::GetInterfaceAlias() { // - // Look for TAP adapter with alias "Mullvad". + // Look for virtual adapter with alias "Mullvad". // using shared::network::InterfaceUtils; - auto adapters = InterfaceUtils::GetTapAdapters(InterfaceUtils::GetAllAdapters( + auto adapters = InterfaceUtils::GetVirtualAdapters(InterfaceUtils::GetAllAdapters( AF_INET, GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST )); @@ -165,7 +173,7 @@ std::wstring InterfaceUtils::GetTapInterfaceAlias() } // - // Look for TAP adapter with alias "Mullvad-1", "Mullvad-2", etc. + // Look for virtual adapter with alias "Mullvad-1", "Mullvad-2", etc. // for (auto i = 0; i < 10; ++i) @@ -182,7 +190,7 @@ std::wstring InterfaceUtils::GetTapInterfaceAlias() } } - THROW_ERROR("Unable to find TAP adapter"); + THROW_ERROR("Unable to find virtual adapter"); } } diff --git a/windows/libshared/src/libshared/network/interfaceutils.h b/windows/libshared/src/libshared/network/interfaceutils.h index 85a243d591..e29b2fbcb2 100644 --- a/windows/libshared/src/libshared/network/interfaceutils.h +++ b/windows/libshared/src/libshared/network/interfaceutils.h @@ -68,12 +68,12 @@ public: static void AddDeviceIpAddresses(NET_LUID device, const std::vector<SOCKADDR_INET> &addresses); - static std::set<NetworkAdapter> GetTapAdapters(const std::set<NetworkAdapter> &adapters); + static std::set<NetworkAdapter> GetVirtualAdapters(const std::set<NetworkAdapter> &adapters); // - // Determines alias of primary TAP adapter. + // Determines alias of primary virtual adapter. // - static std::wstring GetTapInterfaceAlias(); + static std::wstring GetInterfaceAlias(); }; } diff --git a/windows/winnet/src/winnet/winnet.cpp b/windows/winnet/src/winnet/winnet.cpp index 50332a85e6..bccf5561d8 100644 --- a/windows/winnet/src/winnet/winnet.cpp +++ b/windows/winnet/src/winnet/winnet.cpp @@ -215,7 +215,7 @@ extern "C" WINNET_LINKAGE
bool
WINNET_API
-WinNet_GetTapInterfaceAlias(
+WinNet_GetInterfaceAlias(
wchar_t **alias,
MullvadLogSink logSink,
void *logSinkContext
@@ -228,7 +228,7 @@ WinNet_GetTapInterfaceAlias( THROW_ERROR("Invalid argument: alias");
}
- const auto currentAlias = InterfaceUtils::GetTapInterfaceAlias();
+ const auto currentAlias = InterfaceUtils::GetInterfaceAlias();
auto stringBuffer = new wchar_t[currentAlias.size() + 1];
wcscpy(stringBuffer, currentAlias.c_str());
diff --git a/windows/winnet/src/winnet/winnet.def b/windows/winnet/src/winnet/winnet.def index 21bb2725c7..34d3c4e59d 100644 --- a/windows/winnet/src/winnet/winnet.def +++ b/windows/winnet/src/winnet/winnet.def @@ -3,7 +3,7 @@ EXPORTS WinNet_EnsureBestMetric WinNet_InterfaceAliasToGuid WinNet_EnableIpv6ForAdapter - WinNet_GetTapInterfaceAlias + WinNet_GetInterfaceAlias WinNet_ReleaseString WinNet_ActivateConnectivityMonitor WinNet_DeactivateConnectivityMonitor diff --git a/windows/winnet/src/winnet/winnet.h b/windows/winnet/src/winnet/winnet.h index 0da271274e..5634298a93 100644 --- a/windows/winnet/src/winnet/winnet.h +++ b/windows/winnet/src/winnet/winnet.h @@ -47,7 +47,7 @@ extern "C" WINNET_LINKAGE bool WINNET_API -WinNet_GetTapInterfaceAlias( +WinNet_GetInterfaceAlias( wchar_t **alias, MullvadLogSink logSink, void *logSinkContext |
