diff options
20 files changed, 540 insertions, 120 deletions
diff --git a/talpid-core/src/lib.rs b/talpid-core/src/lib.rs index ecc530aec3..54e3ef08ef 100644 --- a/talpid-core/src/lib.rs +++ b/talpid-core/src/lib.rs @@ -35,6 +35,8 @@ extern crate uuid; #[cfg(target_os = "linux")] extern crate which; #[cfg(windows)] +extern crate widestring; +#[cfg(windows)] extern crate winreg; extern crate openvpn_plugin; @@ -45,6 +47,9 @@ extern crate talpid_types; #[macro_use] extern crate nftnl; +#[cfg(windows)] +mod winnet; + /// Working with processes. pub mod process; diff --git a/talpid-core/src/security/windows/dns.rs b/talpid-core/src/security/windows/dns.rs index d068cb4151..4904946c98 100644 --- a/talpid-core/src/security/windows/dns.rs +++ b/talpid-core/src/security/windows/dns.rs @@ -1,16 +1,14 @@ -extern crate widestring; - -use super::ffi; -use super::system_state::SystemStateWriter; - -use self::widestring::WideCString; -use libc; use std::net::IpAddr; use std::path::Path; use std::ptr; use std::slice; use error_chain::ChainedError; +use libc; +use widestring::WideCString; + +use super::system_state::SystemStateWriter; +use winnet; const DNS_STATE_FILENAME: &'static str = "dns-state-backup"; @@ -49,7 +47,7 @@ pub struct WinDns { impl WinDns { pub fn new<P: AsRef<Path>>(cache_dir: P) -> Result<Self> { - unsafe { WinDns_Initialize(Some(ffi::error_sink), ptr::null_mut()).into_result()? }; + unsafe { WinDns_Initialize(Some(winnet::error_sink), ptr::null_mut()).into_result()? }; let backup_writer = SystemStateWriter::new( cache_dir @@ -191,7 +189,7 @@ extern "system" { #[link_name(WinDns_Initialize)] pub fn WinDns_Initialize( - sink: Option<ffi::ErrorSink>, + sink: Option<winnet::ErrorSink>, sink_context: *mut libc::c_void, ) -> InitializationResult; diff --git a/talpid-core/src/security/windows/ffi.rs b/talpid-core/src/security/windows/ffi.rs index 029989359e..2362876897 100644 --- a/talpid-core/src/security/windows/ffi.rs +++ b/talpid-core/src/security/windows/ffi.rs @@ -1,16 +1,3 @@ -use libc::{c_char, c_void}; - -pub type ErrorSink = extern "system" fn(msg: *const c_char, ctx: *mut c_void); - -pub extern "system" fn error_sink(msg: *const c_char, _ctx: *mut c_void) { - use std::ffi::CStr; - if msg.is_null() { - error!("Log message from FFI boundary is NULL"); - } else { - error!("{}", unsafe { CStr::from_ptr(msg).to_string_lossy() }); - } -} - #[macro_export] macro_rules! ffi_error { ($result:ident, $error:expr) => { diff --git a/talpid-core/src/security/windows/mod.rs b/talpid-core/src/security/windows/mod.rs index e762a4887a..6ecca8988b 100644 --- a/talpid-core/src/security/windows/mod.rs +++ b/talpid-core/src/security/windows/mod.rs @@ -1,24 +1,21 @@ -extern crate widestring; - -use super::{NetworkSecurityT, SecurityPolicy}; use std::net::IpAddr; use std::path::Path; use std::ptr; -use self::winfw::*; use talpid_types::net::Endpoint; +use widestring::WideCString; -use self::widestring::WideCString; - +use self::dns::WinDns; +use self::winfw::*; +use super::{NetworkSecurityT, SecurityPolicy}; +use winnet; #[macro_use] mod ffi; + mod dns; -mod route; mod system_state; -use self::dns::WinDns; - error_chain! { errors { /// Failure to initialize windows firewall module @@ -50,11 +47,15 @@ error_chain! { ResettingPolicy { description("Failed to reset firewall policies") } + + /// Failure to set TAP adapter metric + SetTapMetric { + description("Unable to set TAP adapter metric") + } } links { WinDns(dns::Error, dns::ErrorKind) #[doc = "WinDNS failure"]; - WinRoute(route::Error, route::ErrorKind) #[doc = "Failure to modify system routing metrics"]; } } @@ -73,7 +74,7 @@ impl NetworkSecurityT for NetworkSecurity { unsafe { WinFw_Initialize( WINFW_TIMEOUT_SECONDS, - Some(ffi::error_sink), + Some(winnet::error_sink), ptr::null_mut(), ).into_result()? }; @@ -168,14 +169,15 @@ impl NetworkSecurity { self.dns.set_dns(&vec![tunnel_metadata.gateway.into()])?; - let metrics_set = route::ensure_top_metric_for_interface(&tunnel_metadata.interface)?; + let metrics_set = winnet::ensure_top_metric_for_interface(&tunnel_metadata.interface) + .chain_err(|| ErrorKind::SetTapMetric)?; + if metrics_set { debug!("Network interface metrics were changed"); } else { debug!("Network interface metrics were not changed"); } - unsafe { WinFw_ApplyPolicyConnected( winfw_settings, @@ -195,10 +197,12 @@ impl NetworkSecurity { #[allow(non_snake_case)] mod winfw { - use super::{ffi, ErrorKind, Result}; use libc; use talpid_types::net::TransportProtocol; + use super::{ErrorKind, Result}; + use winnet; + #[repr(C)] pub struct WinFwRelay { pub ip: *const libc::wchar_t, @@ -254,7 +258,7 @@ mod winfw { #[link_name(WinFw_Initialize)] pub fn WinFw_Initialize( timeout: libc::c_uint, - sink: Option<ffi::ErrorSink>, + sink: Option<winnet::ErrorSink>, sink_context: *mut libc::c_void, ) -> InitializationResult; diff --git a/talpid-core/src/security/windows/route.rs b/talpid-core/src/security/windows/route.rs deleted file mode 100644 index 6ecf336956..0000000000 --- a/talpid-core/src/security/windows/route.rs +++ /dev/null @@ -1,63 +0,0 @@ -use super::ffi; -use super::widestring::WideCString; -use libc; -use std::ptr; - -error_chain!{ - errors{ - /// Failure to set metrics of network interfaces - MetricApplication{ - description("Failed to set the metrics for a network interface") - } - InvalidInterfaceAlias{ - description("Supplied interface alias is invalid") - } - } -} - -/// Returns true if metrics were changed, false otherwise -pub fn ensure_top_metric_for_interface(interface_alias: &str) -> Result<bool> { - let interface_alias_ws = - WideCString::from_str(interface_alias).chain_err(|| ErrorKind::InvalidInterfaceAlias)?; - unsafe { - WinRoute_EnsureTopMetric( - interface_alias_ws.as_wide_c_str().as_ptr(), - Some(ffi::error_sink), - ptr::null_mut(), - ).into() - } -} - -// Allowing dead code here as this type should only ever be constructed by an -// FFI function. -#[allow(dead_code)] -#[repr(u32)] -enum MetricResult { - MetricsUnchanged = 0u32, - MetricsChanged = 1u32, - Failure = 2u32, - UnexpectedValue, -} - -impl Into<Result<bool>> for MetricResult { - fn into(self) -> Result<bool> { - match self { - MetricResult::MetricsUnchanged => Ok(false), - MetricResult::MetricsChanged => Ok(true), - MetricResult::Failure => Err(Error::from(ErrorKind::MetricApplication)), - MetricResult::UnexpectedValue => { - error!("Unexpected return code from WinRoute_EnsureTopMetric"); - Err(Error::from(ErrorKind::MetricApplication)) - } - } - } -} - -extern "system" { - #[link_name(WinRoute_EnsureTopMetric)] - fn WinRoute_EnsureTopMetric( - tunnel_interface_alias: *const libc::wchar_t, - sink: Option<ffi::ErrorSink>, - sink_context: *mut libc::c_void, - ) -> MetricResult; -} diff --git a/talpid-core/src/tunnel/mod.rs b/talpid-core/src/tunnel/mod.rs index 59f032b286..36b3ff654b 100644 --- a/talpid-core/src/tunnel/mod.rs +++ b/talpid-core/src/tunnel/mod.rs @@ -322,13 +322,26 @@ fn is_ipv6_enabled_in_os() -> bool { use winreg::enums::*; use winreg::RegKey; - const IPV6_DISABLED: u8 = 0xFF; + const IPV6_DISABLED_ON_TUNNELS_MASK: u32 = 0x01; - RegKey::predef(HKEY_LOCAL_MACHINE) + // Check registry if IPv6 is disabled on tunnel interfaces, as documented in + // https://support.microsoft.com/en-us/help/929852/guidance-for-configuring-ipv6-in-windows-for-advanced-users + let globally_enabled = RegKey::predef(HKEY_LOCAL_MACHINE) .open_subkey(r#"SYSTEM\CurrentControlSet\Services\Tcpip6\Parameters"#) .and_then(|ipv6_config| ipv6_config.get_value("DisabledComponents")) - .map(|ipv6_disabled_bits: u32| (ipv6_disabled_bits & 0xFF) == IPV6_DISABLED as u32) - .unwrap_or(false) + .map(|ipv6_disabled_bits: u32| { + (ipv6_disabled_bits & IPV6_DISABLED_ON_TUNNELS_MASK) == 0 + }).unwrap_or(true); + let enabled_on_tap = ::winnet::get_tap_interface_ipv6_status().unwrap_or(false); + + if !globally_enabled { + debug!("IPv6 disabled in tunnel interfaces"); + } + if !enabled_on_tap { + debug!("IPv6 disabled in TAP adapter"); + } + + globally_enabled && enabled_on_tap } #[cfg(target_os = "linux")] { diff --git a/talpid-core/src/winnet.rs b/talpid-core/src/winnet.rs new file mode 100644 index 0000000000..ef3930649c --- /dev/null +++ b/talpid-core/src/winnet.rs @@ -0,0 +1,92 @@ +use std::ptr; + +use libc::{c_char, c_void, wchar_t}; +use widestring::WideCString; + +error_chain!{ + errors{ + /// Failure to set metrics of network interfaces + MetricApplication{ + description("Failed to set the metrics for a network interface") + } + InvalidInterfaceAlias{ + description("Supplied interface alias is invalid") + } + GetIpv6Status { + description("Failed to read IPv6 status on the TAP network interface") + } + } +} + +pub type ErrorSink = extern "system" fn(msg: *const c_char, ctx: *mut c_void); + +pub extern "system" fn error_sink(msg: *const c_char, _ctx: *mut c_void) { + use std::ffi::CStr; + if msg.is_null() { + error!("Log message from FFI boundary is NULL"); + } else { + error!("{}", unsafe { CStr::from_ptr(msg).to_string_lossy() }); + } +} + +/// Returns true if metrics were changed, false otherwise +pub fn ensure_top_metric_for_interface(interface_alias: &str) -> Result<bool> { + let interface_alias_ws = + WideCString::from_str(interface_alias).chain_err(|| ErrorKind::InvalidInterfaceAlias)?; + + let metric_result = unsafe { + WinRoute_EnsureTopMetric( + interface_alias_ws.as_wide_c_str().as_ptr(), + Some(error_sink), + ptr::null_mut(), + ) + }; + + match metric_result { + // Metrics didn't change + 0 => Ok(false), + // Metrics changed + 1 => Ok(true), + // Failure + 2 => Err(Error::from(ErrorKind::MetricApplication)), + // Unexpected value + _ => { + error!("Unexpected return code from WinRoute_EnsureTopMetric"); + Err(Error::from(ErrorKind::MetricApplication)) + } + } +} + +extern "system" { + #[link_name(WinRoute_EnsureTopMetric)] + fn WinRoute_EnsureTopMetric( + tunnel_interface_alias: *const wchar_t, + sink: Option<ErrorSink>, + sink_context: *mut c_void, + ) -> u32; +} + + +/// Checks if IPv6 is enabled for the TAP interface +pub fn get_tap_interface_ipv6_status() -> Result<bool> { + let tap_ipv6_status = unsafe { GetTapInterfaceIpv6Status(Some(error_sink), ptr::null_mut()) }; + + match tap_ipv6_status { + // Enabled + 0 => Ok(true), + // Disabled + 1 => Ok(false), + // Failure + 2 => Err(Error::from(ErrorKind::GetIpv6Status)), + // Unexpected value + _ => { + error!("Unexpected return code from GetTapInterfaceIpv6Status"); + Err(Error::from(ErrorKind::GetIpv6Status)) + } + } +} + +extern "system" { + #[link_name(GetTapInterfaceIpv6Status)] + fn GetTapInterfaceIpv6Status(sink: Option<ErrorSink>, sink_context: *mut c_void) -> u32; +} diff --git a/windows/winroute/extras.sln b/windows/winroute/extras.sln new file mode 100644 index 0000000000..28d1d51341 --- /dev/null +++ b/windows/winroute/extras.sln @@ -0,0 +1,57 @@ +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loader", "src\extras\loader\loader.vcxproj", "{227C50F4-D9F6-4D9A-84A0-33CE84432D0D}" + ProjectSection(ProjectDependencies) = postProject + {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} + {89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4} = {89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "winroute", "src\winroute\winroute.vcxproj", "{89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4}" + ProjectSection(ProjectDependencies) = postProject + {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcommon", "..\windows-libraries\src\libcommon\libcommon.vcxproj", "{B52E2D10-A94A-4605-914A-2DCEF6A757EF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {227C50F4-D9F6-4D9A-84A0-33CE84432D0D}.Debug|x64.ActiveCfg = Debug|x64 + {227C50F4-D9F6-4D9A-84A0-33CE84432D0D}.Debug|x64.Build.0 = Debug|x64 + {227C50F4-D9F6-4D9A-84A0-33CE84432D0D}.Debug|x86.ActiveCfg = Debug|Win32 + {227C50F4-D9F6-4D9A-84A0-33CE84432D0D}.Debug|x86.Build.0 = Debug|Win32 + {227C50F4-D9F6-4D9A-84A0-33CE84432D0D}.Release|x64.ActiveCfg = Release|x64 + {227C50F4-D9F6-4D9A-84A0-33CE84432D0D}.Release|x64.Build.0 = Release|x64 + {227C50F4-D9F6-4D9A-84A0-33CE84432D0D}.Release|x86.ActiveCfg = Release|Win32 + {227C50F4-D9F6-4D9A-84A0-33CE84432D0D}.Release|x86.Build.0 = Release|Win32 + {89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4}.Debug|x64.ActiveCfg = Debug|x64 + {89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4}.Debug|x64.Build.0 = Debug|x64 + {89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4}.Debug|x86.ActiveCfg = Debug|Win32 + {89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4}.Debug|x86.Build.0 = Debug|Win32 + {89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4}.Release|x64.ActiveCfg = Release|x64 + {89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4}.Release|x64.Build.0 = Release|x64 + {89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4}.Release|x86.ActiveCfg = Release|Win32 + {89C5CDE8-04DB-4D9C-A8D8-7F786DAFB6D4}.Release|x86.Build.0 = Release|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x64.ActiveCfg = Debug|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x64.Build.0 = Debug|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x86.ActiveCfg = Debug|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Debug|x86.Build.0 = Debug|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x64.ActiveCfg = Release|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x64.Build.0 = Release|x64 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x86.ActiveCfg = Release|Win32 + {B52E2D10-A94A-4605-914A-2DCEF6A757EF}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {B11B65B3-3DA6-495C-B0F5-5ACBB2F1743D} + EndGlobalSection +EndGlobal diff --git a/windows/winroute/src/extras/loader/loader.cpp b/windows/winroute/src/extras/loader/loader.cpp new file mode 100644 index 0000000000..cb775538f9 --- /dev/null +++ b/windows/winroute/src/extras/loader/loader.cpp @@ -0,0 +1,10 @@ +#include "stdafx.h" +#include "../../winroute/winroute.h" + +int main() +{ + const auto status = GetTapInterfaceIpv6Status(nullptr, nullptr); + + return 0; +} + diff --git a/windows/winroute/src/extras/loader/loader.vcxproj b/windows/winroute/src/extras/loader/loader.vcxproj new file mode 100644 index 0000000000..bf010c1fd0 --- /dev/null +++ b/windows/winroute/src/extras/loader/loader.vcxproj @@ -0,0 +1,176 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup Label="ProjectConfigurations"> + <ProjectConfiguration Include="Debug|Win32"> + <Configuration>Debug</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|Win32"> + <Configuration>Release</Configuration> + <Platform>Win32</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Debug|x64"> + <Configuration>Debug</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + <ProjectConfiguration Include="Release|x64"> + <Configuration>Release</Configuration> + <Platform>x64</Platform> + </ProjectConfiguration> + </ItemGroup> + <ItemGroup> + <ClCompile Include="loader.cpp" /> + <ClCompile Include="stdafx.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + </ItemGroup> + <PropertyGroup Label="Globals"> + <VCProjectVersion>15.0</VCProjectVersion> + <ProjectGuid>{227C50F4-D9F6-4D9A-84A0-33CE84432D0D}</ProjectGuid> + <Keyword>Win32Proj</Keyword> + <RootNamespace>loader</RootNamespace> + <WindowsTargetPlatformVersion>10.0.16299.0</WindowsTargetPlatformVersion> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>true</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> + <ConfigurationType>Application</ConfigurationType> + <UseDebugLibraries>false</UseDebugLibraries> + <PlatformToolset>v141</PlatformToolset> + <WholeProgramOptimization>true</WholeProgramOptimization> + <CharacterSet>Unicode</CharacterSet> + </PropertyGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" /> + <ImportGroup Label="ExtensionSettings"> + </ImportGroup> + <ImportGroup Label="Shared"> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> + </ImportGroup> + <PropertyGroup Label="UserMacros" /> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <LinkIncremental>true</LinkIncremental> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <LinkIncremental>true</LinkIncremental> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <LinkIncremental>false</LinkIncremental> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <LinkIncremental>false</LinkIncremental> + <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> + <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> + </PropertyGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> + <ClCompile> + <PrecompiledHeader>Create</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories> + <AdditionalDependencies>winroute.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <ClCompile> + <PrecompiledHeader>Create</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>Disabled</Optimization> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories> + <AdditionalDependencies>winroute.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> + <ClCompile> + <PrecompiledHeader>Create</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories> + <AdditionalDependencies>winroute.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <ClCompile> + <PrecompiledHeader>Create</PrecompiledHeader> + <WarningLevel>Level4</WarningLevel> + <Optimization>MaxSpeed</Optimization> + <FunctionLevelLinking>true</FunctionLevelLinking> + <IntrinsicFunctions>true</IntrinsicFunctions> + <SDLCheck>true</SDLCheck> + <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> + <ConformanceMode>true</ConformanceMode> + </ClCompile> + <Link> + <SubSystem>Console</SubSystem> + <EnableCOMDATFolding>true</EnableCOMDATFolding> + <OptimizeReferences>true</OptimizeReferences> + <GenerateDebugInformation>true</GenerateDebugInformation> + <AdditionalLibraryDirectories>$(SolutionDir)/bin/$(Platform)-$(Configuration)</AdditionalLibraryDirectories> + <AdditionalDependencies>winroute.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies> + </Link> + </ItemDefinitionGroup> + <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> + <ImportGroup Label="ExtensionTargets"> + </ImportGroup> +</Project>
\ No newline at end of file diff --git a/windows/winroute/src/extras/loader/loader.vcxproj.filters b/windows/winroute/src/extras/loader/loader.vcxproj.filters new file mode 100644 index 0000000000..cd0f4643c7 --- /dev/null +++ b/windows/winroute/src/extras/loader/loader.vcxproj.filters @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <ItemGroup> + <ClCompile Include="loader.cpp" /> + <ClCompile Include="stdafx.cpp" /> + </ItemGroup> + <ItemGroup> + <ClInclude Include="stdafx.h" /> + <ClInclude Include="targetver.h" /> + </ItemGroup> +</Project>
\ No newline at end of file diff --git a/windows/winroute/src/extras/loader/stdafx.cpp b/windows/winroute/src/extras/loader/stdafx.cpp new file mode 100644 index 0000000000..8d6fa45555 --- /dev/null +++ b/windows/winroute/src/extras/loader/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// loader.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/windows/winroute/src/extras/loader/stdafx.h b/windows/winroute/src/extras/loader/stdafx.h new file mode 100644 index 0000000000..b005a839de --- /dev/null +++ b/windows/winroute/src/extras/loader/stdafx.h @@ -0,0 +1,15 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#include <stdio.h> +#include <tchar.h> + + + +// TODO: reference additional headers your program requires here diff --git a/windows/winroute/src/extras/loader/targetver.h b/windows/winroute/src/extras/loader/targetver.h new file mode 100644 index 0000000000..87c0086de7 --- /dev/null +++ b/windows/winroute/src/extras/loader/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include <SDKDDKVer.h> diff --git a/windows/winroute/src/winroute/InterfacePair.h b/windows/winroute/src/winroute/InterfacePair.h index 3926ba0430..9582bac3cd 100644 --- a/windows/winroute/src/winroute/InterfacePair.h +++ b/windows/winroute/src/winroute/InterfacePair.h @@ -14,8 +14,8 @@ public: private: - MIB_IPINTERFACE_ROW IPv4Iface; - MIB_IPINTERFACE_ROW IPv6Iface; + MIB_IPINTERFACE_ROW IPv4Iface = { 0 }; + MIB_IPINTERFACE_ROW IPv6Iface = { 0 }; void InitializeInterface(PMIB_IPINTERFACE_ROW iface); bool HasIPv4(); diff --git a/windows/winroute/src/winroute/NetworkInterfaces.cpp b/windows/winroute/src/winroute/NetworkInterfaces.cpp index a0a4d53db8..2aa352de27 100644 --- a/windows/winroute/src/winroute/NetworkInterfaces.cpp +++ b/windows/winroute/src/winroute/NetworkInterfaces.cpp @@ -74,19 +74,7 @@ NetworkInterfaces::NetworkInterfaces() bool NetworkInterfaces::SetTopMetricForInterfacesByAlias(const wchar_t * deviceAlias) { - NET_LUID targetIfaceLuid; - DWORD success = 0; - success = ConvertInterfaceAliasToLuid(deviceAlias, &targetIfaceLuid); - if (success != NO_ERROR) - { - std::wstringstream ss; - ss << L"Failed to convert interface alias '" - << deviceAlias - << "' into LUID: " - << success; - throw std::runtime_error(common::string::ToAnsi(ss.str())); - } - return SetTopMetricForInterfacesWithLuid(targetIfaceLuid); + return SetTopMetricForInterfacesWithLuid(GetInterfaceLuid(deviceAlias)); } bool NetworkInterfaces::SetTopMetricForInterfacesWithLuid(NET_LUID targetIfaceId) @@ -107,3 +95,41 @@ NetworkInterfaces::~NetworkInterfaces() { FreeMibTable(mInterfaces); } + +//static +NET_LUID NetworkInterfaces::GetInterfaceLuid(const std::wstring &interfaceAlias) +{ + NET_LUID interfaceLuid; + + const auto status = ConvertInterfaceAliasToLuid(interfaceAlias.c_str(), &interfaceLuid); + + if (status != NO_ERROR) + { + std::wstringstream ss; + + ss << L"Failed to convert interface alias '" + << interfaceAlias + << "' into LUID. Error: " + << status; + + throw std::runtime_error(common::string::ToAnsi(ss.str())); + } + + return interfaceLuid; +} + +const MIB_IPINTERFACE_ROW *NetworkInterfaces::GetInterface(NET_LUID interfaceLuid, ADDRESS_FAMILY interfaceFamily) +{ + for (unsigned int i = 0; i < mInterfaces->NumEntries; ++i) + { + MIB_IPINTERFACE_ROW &candidateInterface = mInterfaces->Table[i]; + + if (candidateInterface.InterfaceLuid.Value == interfaceLuid.Value + && candidateInterface.Family == interfaceFamily) + { + return &candidateInterface; + } + } + + return nullptr; +} diff --git a/windows/winroute/src/winroute/NetworkInterfaces.h b/windows/winroute/src/winroute/NetworkInterfaces.h index b29ce0fa44..bf1d53dddf 100644 --- a/windows/winroute/src/winroute/NetworkInterfaces.h +++ b/windows/winroute/src/winroute/NetworkInterfaces.h @@ -6,6 +6,7 @@ #include <iphlpapi.h> #include <netioapi.h> #include <cstdint> +#include <string> class NetworkInterfaces { @@ -15,11 +16,17 @@ private: bool HasHighestMetric(PMIB_IPINTERFACE_ROW targetIface); public: + NetworkInterfaces(const NetworkInterfaces &) = delete; + NetworkInterfaces &operator=(const NetworkInterfaces &) = delete; + void EnsureIfaceMetricIsHighest(NET_LUID interfaceLuid); NetworkInterfaces(); bool SetTopMetricForInterfacesByAlias(const wchar_t *deviceAlias); bool SetTopMetricForInterfacesWithLuid(NET_LUID targetIface); ~NetworkInterfaces(); + + static NET_LUID GetInterfaceLuid(const std::wstring &interfaceAlias); + const MIB_IPINTERFACE_ROW *GetInterface(NET_LUID interfaceLuid, ADDRESS_FAMILY interfaceFamily); }; const static uint32_t MAX_METRIC = 1; diff --git a/windows/winroute/src/winroute/winroute.cpp b/windows/winroute/src/winroute/winroute.cpp index c417bd44ea..b9f10e3786 100644 --- a/windows/winroute/src/winroute/winroute.cpp +++ b/windows/winroute/src/winroute/winroute.cpp @@ -1,6 +1,7 @@ #include "stdafx.h"
#include "winroute.h"
#include "NetworkInterfaces.h"
+#include "libcommon/error.h"
#include <cstdint>
#include <stdexcept>
@@ -35,3 +36,47 @@ WinRoute_EnsureTopMetric( }
};
+extern "C"
+WINROUTE_LINKAGE
+TAP_IPV6_STATUS
+WINROUTE_API
+GetTapInterfaceIpv6Status(
+ WinRouteErrorSink errorSink,
+ void* errorSinkContext
+)
+{
+ try
+ {
+ MIB_IPINTERFACE_ROW interface = { 0 };
+
+ interface.InterfaceLuid = NetworkInterfaces::GetInterfaceLuid(L"Mullvad");
+ interface.Family = AF_INET6;
+
+ const auto status = GetIpInterfaceEntry(&interface);
+
+ if (NO_ERROR == status)
+ {
+ return TAP_IPV6_STATUS::ENABLED;
+ }
+
+ if (ERROR_NOT_FOUND == status)
+ {
+ return TAP_IPV6_STATUS::DISABLED;
+ }
+
+ common::error::Throw("Resolve TAP IPv6 interface", status);
+ }
+ catch (std::exception &err)
+ {
+ if (nullptr != errorSink)
+ {
+ errorSink(err.what(), errorSinkContext);
+ }
+
+ return TAP_IPV6_STATUS::FAILURE;
+ }
+ catch (...)
+ {
+ return TAP_IPV6_STATUS::FAILURE;
+ }
+}
diff --git a/windows/winroute/src/winroute/winroute.def b/windows/winroute/src/winroute/winroute.def index d409889c50..2ea9222482 100644 --- a/windows/winroute/src/winroute/winroute.def +++ b/windows/winroute/src/winroute/winroute.def @@ -1,3 +1,4 @@ LIBRARY winroute EXPORTS - WinRoute_EnsureTopMetric
\ No newline at end of file + WinRoute_EnsureTopMetric + GetTapInterfaceIpv6Status diff --git a/windows/winroute/src/winroute/winroute.h b/windows/winroute/src/winroute/winroute.h index 6bf0c3b882..6b500cee7e 100644 --- a/windows/winroute/src/winroute/winroute.h +++ b/windows/winroute/src/winroute/winroute.h @@ -28,3 +28,23 @@ WinRoute_EnsureTopMetric( WinRouteErrorSink errorSink, void* errorSinkContext ); + +enum class TAP_IPV6_STATUS : uint32_t +{ + ENABLED = 0, + DISABLED = 1, + FAILURE = 2, +}; + +// +// This has nothing to do with routing. +// We should probably rename this module and use it to gather one-off network functions. +// +extern "C" +WINROUTE_LINKAGE +TAP_IPV6_STATUS +WINROUTE_API +GetTapInterfaceIpv6Status( + WinRouteErrorSink errorSink, + void* errorSinkContext +); |
