diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-04-23 18:37:06 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-04-24 16:51:47 +0200 |
| commit | 2eaa3845ef8e64208f30784575356f4137412133 (patch) | |
| tree | fa491fe7e5cc57e89694df884a4695f65dc69d8b | |
| parent | 2dfa1d08eb6a3c9d422bfbd84854073fa932182c (diff) | |
| download | mullvadvpn-2eaa3845ef8e64208f30784575356f4137412133.tar.xz mullvadvpn-2eaa3845ef8e64208f30784575356f4137412133.zip | |
Enable IPv6 for WireGuard interface
| -rw-r--r-- | talpid-core/src/tunnel/mod.rs | 22 | ||||
| -rw-r--r-- | talpid-core/src/winnet.rs | 44 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/netconfig.cpp | 25 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/netconfig.h | 2 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/winnet.cpp | 62 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/winnet.def | 1 | ||||
| -rw-r--r-- | windows/winnet/src/winnet/winnet.h | 13 |
7 files changed, 132 insertions, 37 deletions
diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index 0f8a902406..afee640829 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -3,7 +3,6 @@ use crate::logging; #[cfg(not(target_os = "android"))] use std::collections::HashMap; use std::{ - ffi::OsString, io, net::{IpAddr, Ipv4Addr, Ipv6Addr}, path::{Path, PathBuf}, @@ -348,14 +347,27 @@ fn try_enabling_ipv6(tunnel_parameters: &TunnelParameters) -> Result<()> { return Err(Error::EnableIpv6Error); } - let alias = match tunnel_parameters { + let guid_string: String; + + let guid = match tunnel_parameters { TunnelParameters::OpenVpn(..) => { - crate::winnet::get_tap_interface_alias().map_err(Error::WinnetError)? + // TODO: This status check can be removed if it is certain + // that `enable_ipv6_for_adapter` is reliable. + let status = + crate::winnet::get_tap_interface_ipv6_status().map_err(Error::WinnetError)?; + if status { + return Ok(()); + } + + let alias = crate::winnet::get_tap_interface_alias().map_err(Error::WinnetError)?; + guid_string = + crate::winnet::interface_alias_to_guid(&alias).map_err(Error::WinnetError)?; + &guid_string } - TunnelParameters::Wireguard(..) => OsString::from("wg-mullvad"), + TunnelParameters::Wireguard(..) => "{AFE43773-E1F8-4EBB-8536-576AB86AFE9A}", }; - crate::winnet::enable_ipv6_for_adapter(&alias).map_err(Error::WinnetError) + crate::winnet::enable_ipv6_for_adapter(&guid).map_err(Error::WinnetError) } #[cfg(target_os = "windows")] diff --git a/talpid-core/src/winnet.rs b/talpid-core/src/winnet.rs index 3e7a52bf75..534dab5228 100644 --- a/talpid-core/src/winnet.rs +++ b/talpid-core/src/winnet.rs @@ -25,6 +25,10 @@ pub enum Error { #[error(display = "Failed to enable IPv6 on the network interface")] EnableIpv6, + /// Failed to enable IPv6 on the network interface. + #[error(display = "Failed to obtain GUID for the network interface")] + GetInterfaceGuid, + /// Failed to read IPv6 status on the TAP network interface. #[error(display = "Failed to read IPv6 status on the TAP network interface")] GetIpv6Status, @@ -71,13 +75,13 @@ pub fn ensure_best_metric_for_interface(interface_alias: &str) -> Result<bool, E } /// Enables IPv6 for a given interface. -pub fn enable_ipv6_for_adapter(interface_alias: &OsStr) -> Result<(), Error> { - let interface_alias_ws = - WideCString::from_os_str(interface_alias).map_err(Error::InvalidInterfaceAlias)?; +pub fn enable_ipv6_for_adapter(interface_guid: &str) -> Result<(), Error> { + let interface_guid_ws = + WideCString::from_str(interface_guid).map_err(Error::InvalidInterfaceAlias)?; let result = unsafe { WinNet_EnableIpv6ForAdapter( - interface_alias_ws.as_ptr(), + interface_guid_ws.as_ptr(), Some(log_sink), logging_context(), ) @@ -133,6 +137,30 @@ pub fn get_tap_interface_alias() -> Result<OsString, Error> { Ok(alias.to_os_string()) } +/// Determines the interface guid for a given adapter alias. +pub fn interface_alias_to_guid(interface_alias: &OsStr) -> Result<String, Error> { + let interface_alias = + WideCString::from_os_str(interface_alias).map_err(Error::InvalidInterfaceAlias)?; + let mut guid_ptr: *mut wchar_t = ptr::null_mut(); + let status = unsafe { + WinNet_InterfaceAliasToGuid( + interface_alias.as_ptr(), + &mut guid_ptr as *mut _, + Some(log_sink), + logging_context(), + ) + }; + + if !status { + return Err(Error::GetInterfaceGuid); + } + + let guid = unsafe { WideCString::from_ptr_str(guid_ptr) }; + unsafe { WinNet_ReleaseString(guid_ptr) }; + + Ok(guid.to_string_lossy()) +} + #[allow(dead_code)] #[repr(u32)] pub enum WinNetAddrFamily { @@ -428,6 +456,14 @@ mod api { sink_context: *const u8, ) -> bool; + #[link_name = "WinNet_InterfaceAliasToGuid"] + pub fn WinNet_InterfaceAliasToGuid( + interface_alias: *const wchar_t, + interface_guid: *mut *mut wchar_t, + sink: Option<LogSink>, + sink_context: *const u8, + ) -> bool; + #[link_name = "WinNet_ReleaseString"] pub fn WinNet_ReleaseString(string: *mut wchar_t); diff --git a/windows/winnet/src/winnet/netconfig.cpp b/windows/winnet/src/winnet/netconfig.cpp index 2bd96c907f..2a8e2e1c64 100644 --- a/windows/winnet/src/winnet/netconfig.cpp +++ b/windows/winnet/src/winnet/netconfig.cpp @@ -138,30 +138,11 @@ void SetIpv6BindingForBindName(INetCfg *netCfg, const std::wstring &bindName, bo } } -std::wstring FindAdapterGuidForAlias(const std::wstring &alias) -{ - const auto adapters = shared::network::InterfaceUtils::GetAllAdapters( - AF_UNSPEC, - GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST - ); - for (auto it = adapters.begin(); it != adapters.end(); ++it) - { - if (0 == it->alias().compare(alias)) - { - return it->guid(); - } - } - - throw std::runtime_error("Cannot find GUID for given alias"); -} - } // anonymous namespace -void EnableIpv6ForAdapter(const std::wstring &alias) +void EnableIpv6ForAdapter(const std::wstring &adapterGuid) { - std::wstring adapterGuid = FindAdapterGuidForAlias(alias); - // // Initialize COM // @@ -190,7 +171,7 @@ void EnableIpv6ForAdapter(const std::wstring &alias) nullptr, CLSCTX_INPROC_SERVER, IID_INetCfg, - reinterpret_cast<void**>(&netCfg) + reinterpret_cast<void **>(&netCfg) ); if (S_OK != result) @@ -204,7 +185,7 @@ void EnableIpv6ForAdapter(const std::wstring &alias) scopeDest += [&netCfg]() { netCfg->Release(); }; INetCfgLock *netCfgLock = nullptr; - result = netCfg->QueryInterface(IID_INetCfgLock, reinterpret_cast<void**>(&netCfgLock)); + result = netCfg->QueryInterface(IID_INetCfgLock, reinterpret_cast<void **>(&netCfgLock)); if (S_OK != result) { diff --git a/windows/winnet/src/winnet/netconfig.h b/windows/winnet/src/winnet/netconfig.h index a729d98629..b2849857a2 100644 --- a/windows/winnet/src/winnet/netconfig.h +++ b/windows/winnet/src/winnet/netconfig.h @@ -2,4 +2,4 @@ #include <string> -void EnableIpv6ForAdapter(const std::wstring &alias); +void EnableIpv6ForAdapter(const std::wstring &guid); diff --git a/windows/winnet/src/winnet/winnet.cpp b/windows/winnet/src/winnet/winnet.cpp index 5f9d20f583..6a37b100f6 100644 --- a/windows/winnet/src/winnet/winnet.cpp +++ b/windows/winnet/src/winnet/winnet.cpp @@ -69,19 +69,19 @@ WINNET_LINKAGE bool
WINNET_API
WinNet_EnableIpv6ForAdapter(
- const wchar_t *deviceAlias,
+ const wchar_t *deviceGuid,
MullvadLogSink logSink,
void *logSinkContext
)
{
try
{
- if (nullptr == deviceAlias)
+ if (nullptr == deviceGuid)
{
- THROW_ERROR("Invalid argument: deviceAlias");
+ THROW_ERROR("Invalid argument: deviceGuid");
}
- EnableIpv6ForAdapter(deviceAlias);
+ EnableIpv6ForAdapter(deviceGuid);
return true;
}
catch (const std::exception & err)
@@ -172,6 +172,60 @@ WinNet_GetTapInterfaceAlias( extern "C"
WINNET_LINKAGE
+bool
+WINNET_API
+WinNet_InterfaceAliasToGuid(
+ const wchar_t *alias,
+ wchar_t **guid,
+ MullvadLogSink logSink,
+ void *logSinkContext
+)
+{
+ try
+ {
+ if (nullptr == guid)
+ {
+ THROW_ERROR("Invalid argument: guid");
+ }
+ if (nullptr == alias)
+ {
+ THROW_ERROR("Invalid argument: alias");
+ }
+
+ GUID tempGuid = { 0 };
+ NET_LUID luid = { 0 };
+
+ if (NO_ERROR != ConvertInterfaceAliasToLuid(alias, &luid))
+ {
+ THROW_ERROR("ConvertInterfaceAliasToLuid: invalid parameter");
+ }
+
+ if (NO_ERROR != ConvertInterfaceLuidToGuid(&luid, &tempGuid))
+ {
+ THROW_ERROR("ConvertInterfaceLuidToGuid: invalid parameter");
+ }
+
+ const auto guidStr = common::string::FormatGuid(tempGuid);
+
+ auto guidBuffer = new wchar_t[guidStr.size() + 1];
+ wcscpy(guidBuffer, guidStr.c_str());
+ *guid = guidBuffer;
+
+ return true;
+ }
+ catch (const std::exception & err)
+ {
+ shared::logging::UnwindAndLog(logSink, logSinkContext, err);
+ return false;
+ }
+ catch (...)
+ {
+ return false;
+ }
+}
+
+extern "C"
+WINNET_LINKAGE
void
WINNET_API
WinNet_ReleaseString(
diff --git a/windows/winnet/src/winnet/winnet.def b/windows/winnet/src/winnet/winnet.def index 29a19dffe5..c281e481f5 100644 --- a/windows/winnet/src/winnet/winnet.def +++ b/windows/winnet/src/winnet/winnet.def @@ -1,6 +1,7 @@ LIBRARY winnet EXPORTS WinNet_EnsureBestMetric + WinNet_InterfaceAliasToGuid WinNet_EnableIpv6ForAdapter WinNet_GetTapInterfaceIpv6Status WinNet_GetTapInterfaceAlias diff --git a/windows/winnet/src/winnet/winnet.h b/windows/winnet/src/winnet/winnet.h index 885ed8ef90..f084f0e737 100644 --- a/windows/winnet/src/winnet/winnet.h +++ b/windows/winnet/src/winnet/winnet.h @@ -38,7 +38,7 @@ WINNET_LINKAGE bool WINNET_API WinNet_EnableIpv6ForAdapter( - const wchar_t *deviceAlias, + const wchar_t *deviceGuid, MullvadLogSink logSink, void *logSinkContext ); @@ -69,6 +69,17 @@ WinNet_GetTapInterfaceAlias( void *logSinkContext ); +extern "C" +WINNET_LINKAGE +bool +WINNET_API +WinNet_InterfaceAliasToGuid( + const wchar_t *alias, + wchar_t **guid, + MullvadLogSink logSink, + void *logSinkContext +); + // // This is a companion function to the above function. // Generically named in case we need other functions here that return strings. |
