diff options
34 files changed, 242 insertions, 1646 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dbdf18d11..a985a3d4a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -44,6 +44,9 @@ Line wrap the file at 100 chars. Th #### Windows - Be more scrupulous about removing temporary files used by the installer and uninstaller. +- Fix issue where local name resolution fails. This requires users to ensure that non-tunnel + interfaces are configured correctly to use local custom DNS. +- Configure DNS correctly when the DNS client service is disabled or not responding. #### Android - Fix unused dependencies loaded in the service/tile DI graph. @@ -448,11 +448,6 @@ echo "org.gradle.jvmargs=-Xmx4608M" >> ~/.gradle/gradle.properties * `TALPID_FORCE_USERSPACE_WIREGUARD` - Forces the daemon to use the userspace implementation of WireGuard on Linux. -* `TALPID_DNS_CACHE_POLICY` - On Windows, this changes how DNS is configured: - * `1`: The default. This sets a global list of DNS servers that `dnscache` will use instead of - the servers specified on each interface. - * `0`: Only set DNS servers on the tunnel interface. This will misbehave if local custom DNS - servers are used. * `TALPID_DISABLE_OFFLINE_MONITOR` - Forces the daemon to always assume the host is online. * `MULLVAD_MANAGEMENT_SOCKET_GROUP` - On Linux and macOS, this restricts access to the management diff --git a/build-windows-modules.sh b/build-windows-modules.sh index 8954ad6a72..023123efc7 100755 --- a/build-windows-modules.sh +++ b/build-windows-modules.sh @@ -84,11 +84,9 @@ function build_nsis_plugins { function main { local winfw_root_path=${CPP_ROOT_PATH:-"./windows/winfw"} - local windns_root_path=${CPP_ROOT_PATH:-"./windows/windns"} local winnet_root_path=${CPP_ROOT_PATH:-"./windows/winnet"} build_solution "$winfw_root_path" "winfw.sln" - build_solution "$windns_root_path" "windns.sln" build_solution "$winnet_root_path" "winnet.sln" local driverlogic_root_path=${CPP_ROOT_PATH:-"./windows/driverlogic"} @@ -317,7 +317,6 @@ if [[ "$(uname -s)" == "MINGW"* ]]; then if [[ "$SIGN" == "true" ]]; then CPP_BINARIES=( "windows/winfw/bin/x64-$CPP_BUILD_MODE/winfw.dll" - "windows/windns/bin/x64-$CPP_BUILD_MODE/windns.dll" "windows/winnet/bin/x64-$CPP_BUILD_MODE/winnet.dll" "windows/driverlogic/bin/x64-$CPP_BUILD_MODE/driverlogic.exe" # The nsis plugin is always built in 32 bit release mode diff --git a/gui/locales/messages.pot b/gui/locales/messages.pot index b204f818c8..9deffc1e8d 100644 --- a/gui/locales/messages.pot +++ b/gui/locales/messages.pot @@ -359,6 +359,10 @@ msgctxt "advanced-settings-view" msgid "The app’s built-in kill switch is always on. This setting will additionally block the internet if clicking Disconnect or Quit." msgstr "" +msgctxt "advanced-settings-view" +msgid "The DNS server you want to add is a private IP. You must ensure that your network interfaces are configured to use it." +msgstr "" + #. Available placeholders: #. %(tunnelProtocol)s - the name of the tunnel protocol setting #. %(wireguard)s - will be replaced with "WireGuard" diff --git a/gui/src/renderer/components/CustomDnsSettings.tsx b/gui/src/renderer/components/CustomDnsSettings.tsx index 9c976062c1..0e9dccc79e 100644 --- a/gui/src/renderer/components/CustomDnsSettings.tsx +++ b/gui/src/renderer/components/CustomDnsSettings.tsx @@ -43,6 +43,8 @@ export default function CustomDnsSettings() { const [savingAdd, setSavingAdd] = useState(false); const [savingEdit, setSavingEdit] = useState(false); const willShowConfirmationDialog = useRef(false); + const addingLocalIp = useRef(false); + const manualLocal = window.env.platform === 'win32' || window.env.platform === 'linux'; const featureAvailable = useMemo( () => @@ -121,8 +123,17 @@ export default function CustomDnsSettings() { try { const ipAddress = IpAddress.fromString(address); - if (ipAddress.isLocal()) { - await add(); + addingLocalIp.current = ipAddress.isLocal(); + if (addingLocalIp.current) { + if (manualLocal) { + willShowConfirmationDialog.current = true; + setConfirmAction(() => async () => { + willShowConfirmationDialog.current = false; + await add(); + }); + } else { + await add(); + } } else { willShowConfirmationDialog.current = true; setConfirmAction(() => async () => { @@ -160,8 +171,18 @@ export default function CustomDnsSettings() { const ipAddress = IpAddress.fromString(newAddress); return new Promise<void>((resolve) => { - if (ipAddress.isLocal()) { - void edit().then(resolve); + addingLocalIp.current = ipAddress.isLocal(); + if (addingLocalIp.current) { + if (manualLocal) { + willShowConfirmationDialog.current = true; + setConfirmAction(() => async () => { + willShowConfirmationDialog.current = false; + await edit(); + resolve(); + }); + } else { + void edit().then(resolve); + } } else { willShowConfirmationDialog.current = true; setConfirmAction(() => async () => { @@ -275,6 +296,7 @@ export default function CustomDnsSettings() { <ConfirmationDialog isOpen={confirmAction !== undefined} + isLocal={addingLocalIp} confirm={confirm} abort={abortConfirmation} /> @@ -386,11 +408,33 @@ function CellListItem(props: ICellListItemProps) { interface IConfirmationDialogProps { isOpen: boolean; + isLocal: React.RefObject<boolean>; confirm: () => void; abort: () => void; } function ConfirmationDialog(props: IConfirmationDialogProps) { + let message; + if (props.isLocal.current) { + message = messages.pgettext( + 'advanced-settings-view', + 'The DNS server you want to add is a private IP. You must ensure that your network interfaces are configured to use it.', + ); + } else { + message = sprintf( + // TRANSLATORS: Available placeholders: + // TRANSLATORS: %(tunnelProtocol)s - the name of the tunnel protocol setting + // TRANSLATORS: %(wireguard)s - will be replaced with "WireGuard" + messages.pgettext( + 'advanced-settings-view', + 'The DNS server you want to add is public and will only work with %(wireguard)s. To ensure that it always works, set the "%(tunnelProtocol)s" (in Advanced settings) to %(wireguard)s.', + ), + { + wireguard: strings.wireguard, + tunnelProtocol: messages.pgettext('advanced-settings-view', 'Tunnel protocol'), + }, + ); + } return ( <ModalAlert isOpen={props.isOpen} @@ -404,18 +448,6 @@ function ConfirmationDialog(props: IConfirmationDialogProps) { </AppButton.BlueButton>, ]} close={props.abort} - message={sprintf( - // TRANSLATORS: Available placeholders: - // TRANSLATORS: %(tunnelProtocol)s - the name of the tunnel protocol setting - // TRANSLATORS: %(wireguard)s - will be replaced with "WireGuard" - messages.pgettext( - 'advanced-settings-view', - 'The DNS server you want to add is public and will only work with %(wireguard)s. To ensure that it always works, set the "%(tunnelProtocol)s" (in Advanced settings) to %(wireguard)s.', - ), - { - wireguard: strings.wireguard, - tunnelProtocol: messages.pgettext('advanced-settings-view', 'Tunnel protocol'), - }, - )}></ModalAlert> + message={message}></ModalAlert> ); } diff --git a/gui/tasks/distribution.js b/gui/tasks/distribution.js index 24e3430b9e..dc9968dcb6 100644 --- a/gui/tasks/distribution.js +++ b/gui/tasks/distribution.js @@ -129,12 +129,6 @@ const config = { }, { from: root( - path.join('windows', 'windns', 'bin', 'x64-${env.CPP_BUILD_MODE}', 'windns.dll'), - ), - to: '.', - }, - { - from: root( path.join('windows', 'winnet', 'bin', 'x64-${env.CPP_BUILD_MODE}', 'winnet.dll'), ), to: '.', diff --git a/talpid-core/build.rs b/talpid-core/build.rs index c50f3411fd..8c5c74911b 100644 --- a/talpid-core/build.rs +++ b/talpid-core/build.rs @@ -6,7 +6,6 @@ mod win { use std::{env, path::PathBuf}; pub static WINFW_BUILD_DIR: &'static str = "..\\windows\\winfw\\bin"; - pub static WINDNS_BUILD_DIR: &'static str = "..\\windows\\windns\\bin"; pub static WINNET_BUILD_DIR: &'static str = "..\\windows\\winnet\\bin"; pub fn default_windows_build_artifact_dir(build_dir: &str) -> PathBuf { @@ -50,10 +49,8 @@ fn main() { use crate::win::*; const WINFW_DIR_VAR: &str = "WINFW_LIB_DIR"; - const WINDNS_DIR_VAR: &str = "WINDNS_LIB_DIR"; const WINNET_DIR_VAR: &str = "WINNET_LIB_DIR"; declare_library(WINFW_DIR_VAR, WINFW_BUILD_DIR, "winfw"); - declare_library(WINDNS_DIR_VAR, WINDNS_BUILD_DIR, "windns"); declare_library(WINNET_DIR_VAR, WINNET_BUILD_DIR, "winnet"); let lib_dir = manifest_dir().join("../build/lib/x86_64-pc-windows-msvc"); println!("cargo:rustc-link-search={}", &lib_dir.display()); diff --git a/talpid-core/src/dns/windows/mod.rs b/talpid-core/src/dns/windows/mod.rs index 8986c1d7ab..8cc8683d21 100644 --- a/talpid-core/src/dns/windows/mod.rs +++ b/talpid-core/src/dns/windows/mod.rs @@ -1,238 +1,162 @@ -use crate::{ - logging::windows::{log_sink, LogSink}, - windows::luid_from_alias, -}; - -use lazy_static::lazy_static; -use std::{env, io, net::IpAddr, path::Path}; +use crate::windows::{get_system_dir, guid_from_luid, luid_from_alias, string_from_guid}; +use std::{io, net::IpAddr, process::Command}; use talpid_types::ErrorExt; -use widestring::WideCString; -use winapi::shared::ifdef::NET_LUID; +use winapi::shared::guiddef::GUID; use winreg::{ - enums::{HKEY_LOCAL_MACHINE, REG_MULTI_SZ}, + enums::{HKEY_LOCAL_MACHINE, KEY_SET_VALUE}, transaction::Transaction, - RegKey, RegValue, + RegKey, }; -const DNS_CACHE_POLICY_GUID: &str = "{d57d2750-f971-408e-8e55-cfddb37e60ae}"; - -lazy_static! { - /// Specifies whether to override per-interface DNS resolvers with a global DNS policy. - static ref GLOBAL_DNS_CACHE_POLICY: bool = env::var("TALPID_DNS_CACHE_POLICY") - .map(|v| v != "0") - .unwrap_or(true); -} - /// Errors that can happen when configuring DNS on Windows. #[derive(err_derive::Error, Debug)] #[error(no_from)] pub enum Error { - /// Failure to initialize WinDns. - #[error(display = "Failed to initialize WinDns")] - Initialization, - - /// Failure to deinitialize WinDns. - #[error(display = "Failed to deinitialize WinDns")] - Deinitialization, - - /// Failure to set new DNS servers on the interface. - #[error(display = "Failed to set new DNS servers on interface")] - Setting, - /// Failure to obtain an interface LUID given an alias. #[error(display = "Failed to obtain LUID for the interface alias")] InterfaceLuidError(#[error(source)] io::Error), - /// Failure to set new DNS servers. - #[error(display = "Failed to update dnscache policy config")] - UpdateDnsCachePolicy(#[error(source)] io::Error), + /// Failure to obtain an interface GUID. + #[error(display = "Failed to obtain GUID for the interface")] + InterfaceGuidError(#[error(source)] io::Error), + + /// Failure to flush DNS cache. + #[error(display = "Failed to execute ipconfig")] + ExecuteIpconfigError(#[error(source)] io::Error), + + /// Failure to flush DNS cache. + #[error(display = "Failed to flush DNS resolver cache")] + FlushResolverCacheError, + + /// Failed to update DNS servers for interface. + #[error(display = "Failed to update interface DNS servers")] + SetResolversError(#[error(source)] io::Error), + + /// Failed to locate system dir. + #[error(display = "Failed to locate the system directory")] + SystemDirError(#[error(source)] io::Error), } -pub struct DnsMonitor {} +pub struct DnsMonitor { + current_guid: Option<GUID>, +} impl super::DnsMonitorT for DnsMonitor { type Error = Error; fn new() -> Result<Self, Error> { - unsafe { WinDns_Initialize(Some(log_sink), b"WinDns\0".as_ptr()).into_result()? }; - - let mut monitor = DnsMonitor {}; - monitor.reset()?; - - Ok(monitor) + Ok(DnsMonitor { current_guid: None }) } fn set(&mut self, interface: &str, servers: &[IpAddr]) -> Result<(), Error> { - let ipv4 = servers - .iter() - .filter(|ip| ip.is_ipv4()) - .map(ip_to_widestring) - .collect::<Vec<_>>(); - let ipv6 = servers - .iter() - .filter(|ip| ip.is_ipv6()) - .map(ip_to_widestring) - .collect::<Vec<_>>(); - - let mut ipv4_address_ptrs = ipv4 - .iter() - .map(|ip_cstr| ip_cstr.as_ptr()) - .collect::<Vec<_>>(); - let mut ipv6_address_ptrs = ipv6 - .iter() - .map(|ip_cstr| ip_cstr.as_ptr()) - .collect::<Vec<_>>(); - - log::trace!("ipv4 ips: {:?} ({})", ipv4, ipv4.len()); - log::trace!("ipv6 ips: {:?} ({})", ipv6, ipv6.len()); - - let luid = luid_from_alias(interface).map_err(Error::InterfaceLuidError)?; - - unsafe { - WinDns_Set( - &luid, - ipv4_address_ptrs.as_mut_ptr(), - ipv4_address_ptrs.len() as u32, - ipv6_address_ptrs.as_mut_ptr(), - ipv6_address_ptrs.len() as u32, - ) - .into_result() - }?; - - if *GLOBAL_DNS_CACHE_POLICY { - if let Err(error) = set_dns_cache_policy(servers) { - log::error!("{}", error.display_chain()); - log::warn!("DNS resolution may be slowed down"); - } - } - + let guid = guid_from_luid(&luid_from_alias(interface).map_err(Error::InterfaceLuidError)?) + .map_err(Error::InterfaceGuidError)?; + set_dns(&guid, servers)?; + self.current_guid = Some(guid); + flush_dns_cache()?; Ok(()) } fn reset(&mut self) -> Result<(), Error> { - if *GLOBAL_DNS_CACHE_POLICY { - reset_dns_cache_policy() - } else { - Ok(()) - } - } -} - -fn ip_to_widestring(ip: &IpAddr) -> WideCString { - WideCString::from_str_truncate(ip.to_string()) -} - -impl Drop for DnsMonitor { - fn drop(&mut self) { - if *GLOBAL_DNS_CACHE_POLICY { - if let Err(error) = reset_dns_cache_policy() { - log::warn!( - "{}", - error.display_chain_with_msg("Failed to reset DNS cache policy") - ); - } - } - - if unsafe { WinDns_Deinitialize().into_result().is_ok() } { - log::trace!("Successfully deinitialized WinDns"); - } else { - log::error!("Failed to deinitialize WinDns"); + if let Some(guid) = self.current_guid.take() { + return set_dns(&guid, &[]).and(flush_dns_cache()); } + Ok(()) } } -fn set_dns_cache_policy(servers: &[IpAddr]) -> Result<(), Error> { - let transaction = Transaction::new().map_err(Error::UpdateDnsCachePolicy)?; - let result = match set_dns_cache_policy_inner(&transaction, servers) { +fn set_dns(interface: &GUID, servers: &[IpAddr]) -> Result<(), Error> { + let transaction = Transaction::new().map_err(Error::SetResolversError)?; + let result = match set_dns_inner(&transaction, interface, servers) { Ok(()) => transaction.commit(), - Err(error) => transaction.rollback().and_then(|_| Err(error)), + Err(error) => transaction.rollback().and(Err(error)), }; - result.map_err(Error::UpdateDnsCachePolicy) + result.map_err(Error::SetResolversError) } -fn set_dns_cache_policy_inner(transaction: &Transaction, servers: &[IpAddr]) -> io::Result<()> { - let (dns_cache_parameters, _) = RegKey::predef(HKEY_LOCAL_MACHINE).create_subkey_transacted( - r#"SYSTEM\CurrentControlSet\Services\DnsCache\Parameters"#, +fn set_dns_inner( + transaction: &Transaction, + interface: &GUID, + servers: &[IpAddr], +) -> io::Result<()> { + let guid_str = string_from_guid(interface); + + config_interface( transaction, + &guid_str, + "Tcpip", + servers.iter().filter(|addr| addr.is_ipv4()), )?; - // Fall back on LLMNR and NetBIOS if DNS resolution fails - dns_cache_parameters.set_value("DnsSecureNameQueryFallback", &1u32)?; - - let policy_path = Path::new("DnsPolicyConfig").join(DNS_CACHE_POLICY_GUID); - let (policy_config, _) = - dns_cache_parameters.create_subkey_transacted(policy_path, transaction)?; - - // Enable only the "Generic DNS server" option - policy_config.set_value("ConfigOptions", &0x08u32)?; - let server_list: Vec<String> = servers.iter().map(|server| server.to_string()).collect(); - policy_config.set_value("GenericDNSServers", &server_list.join(";"))?; - policy_config.set_value("IPSECCARestriction", &"")?; - policy_config.set_raw_value( - "Name", - &RegValue { - // utf16 string: ".\0\0" - bytes: [0x2e, 0, 0, 0, 0, 0].to_vec(), - vtype: REG_MULTI_SZ, - }, + config_interface( + transaction, + &guid_str, + "Tcpip6", + servers.iter().filter(|addr| addr.is_ipv6()), )?; - policy_config.set_value("Version", &2u32)?; Ok(()) } -fn reset_dns_cache_policy() -> Result<(), Error> { - let (dns_cache_parameters, _) = RegKey::predef(HKEY_LOCAL_MACHINE) - .create_subkey(r#"SYSTEM\CurrentControlSet\Services\DnsCache\Parameters"#) - .map_err(Error::UpdateDnsCachePolicy)?; - match dns_cache_parameters.delete_value("DnsSecureNameQueryFallback") { - Ok(()) => Ok(()), +fn config_interface<'a>( + transaction: &Transaction, + guid: &str, + service: &str, + nameservers: impl Iterator<Item = &'a IpAddr>, +) -> io::Result<()> { + let nameservers = nameservers + .map(|addr| addr.to_string()) + .collect::<Vec<String>>(); + + let reg_path = + format!(r#"SYSTEM\CurrentControlSet\Services\{service}\Parameters\Interfaces\{guid}"#,); + let adapter_key = match RegKey::predef(HKEY_LOCAL_MACHINE).open_subkey_transacted_with_flags( + reg_path, + transaction, + KEY_SET_VALUE, + ) { + Ok(adapter_key) => Ok(adapter_key), Err(error) => { - if error.kind() == io::ErrorKind::NotFound { - Ok(()) - } else { - Err(Error::UpdateDnsCachePolicy(error)) + if nameservers.is_empty() && error.kind() == io::ErrorKind::NotFound { + return Ok(()); } + Err(error) } }?; - let policy_path = Path::new("DnsPolicyConfig").join(DNS_CACHE_POLICY_GUID); - match dns_cache_parameters.delete_subkey_all(policy_path) { - Ok(()) => Ok(()), - Err(error) => { + + if !nameservers.is_empty() { + adapter_key.set_value("NameServer", &nameservers.join(","))?; + } else { + adapter_key.delete_value("NameServer").or_else(|error| { if error.kind() == io::ErrorKind::NotFound { Ok(()) } else { - Err(Error::UpdateDnsCachePolicy(error)) + Err(error) } - } + })?; } -} -ffi_error!(InitializationResult, Error::Initialization); -ffi_error!(DeinitializationResult, Error::Deinitialization); -ffi_error!(SettingResult, Error::Setting); - -#[allow(non_snake_case)] -extern "stdcall" { - #[link_name = "WinDns_Initialize"] - pub fn WinDns_Initialize( - sink: Option<LogSink>, - sink_context: *const u8, - ) -> InitializationResult; + // Try to disable LLMNR on the interface + if let Err(error) = adapter_key.set_value("EnableMulticast", &0u32) { + log::error!( + "{}\nService: {service}", + error.display_chain_with_msg("Failed to disable LLMNR on the tunnel interface") + ); + } - // WinDns_Deinitialize: - // - // Call this function once before unloading WINDNS or exiting the process. - #[link_name = "WinDns_Deinitialize"] - pub fn WinDns_Deinitialize() -> DeinitializationResult; + Ok(()) +} - // Configure which DNS servers should be used and start enforcing these settings. - #[link_name = "WinDns_Set"] - pub fn WinDns_Set( - interface_luid: *const NET_LUID, - v4_ips: *mut *const u16, - v4_n_ips: u32, - v6_ips: *mut *const u16, - v6_n_ips: u32, - ) -> SettingResult; +fn flush_dns_cache() -> Result<(), Error> { + let sysdir = get_system_dir().map_err(Error::SystemDirError)?; + let mut ipconfig = Command::new(sysdir.join("ipconfig.exe")); + ipconfig.arg("/flushdns"); + let output = ipconfig.output().map_err(Error::ExecuteIpconfigError)?; + let output = String::from_utf8_lossy(&output.stdout); + // The exit code cannot be trusted + if !output.contains("Successfully flushed") { + log::error!("Failed to flush DNS cache: {}", output); + return Err(Error::FlushResolverCacheError); + } + Ok(()) } diff --git a/talpid-core/src/firewall/mod.rs b/talpid-core/src/firewall/mod.rs index de117d39ad..b23e16b017 100644 --- a/talpid-core/src/firewall/mod.rs +++ b/talpid-core/src/firewall/mod.rs @@ -1,14 +1,13 @@ -#[cfg(unix)] use ipnetwork::{IpNetwork, Ipv4Network, Ipv6Network}; -#[cfg(unix)] use lazy_static::lazy_static; -use std::fmt; #[cfg(not(target_os = "android"))] use std::net::IpAddr; -#[cfg(unix)] -use std::net::{Ipv4Addr, Ipv6Addr}; #[cfg(windows)] use std::path::PathBuf; +use std::{ + fmt, + net::{Ipv4Addr, Ipv6Addr}, +}; use talpid_types::net::{AllowedEndpoint, Endpoint}; #[cfg(target_os = "macos")] @@ -29,7 +28,6 @@ mod imp; pub use self::imp::Error; -#[cfg(unix)] lazy_static! { /// When "allow local network" is enabled the app will allow traffic to and from these networks. pub(crate) static ref ALLOWED_LAN_NETS: [IpNetwork; 6] = [ @@ -83,7 +81,7 @@ const DHCPV6_CLIENT_PORT: u16 = 546; #[cfg(all(unix, not(target_os = "android")))] const ROOT_UID: u32 = 0; -#[cfg(all(unix, not(target_os = "android")))] +#[cfg(any(all(unix, not(target_os = "android")), target_os = "windows"))] /// Returns whether an address belongs to a private subnet. pub fn is_local_address(address: &IpAddr) -> bool { let address = address.clone(); diff --git a/talpid-core/src/tunnel/openvpn/wintun.rs b/talpid-core/src/tunnel/openvpn/wintun.rs index a61b83643d..1746756db4 100644 --- a/talpid-core/src/tunnel/openvpn/wintun.rs +++ b/talpid-core/src/tunnel/openvpn/wintun.rs @@ -1,4 +1,6 @@ -use crate::windows::{get_ip_interface_entry, set_ip_interface_entry, AddressFamily}; +use crate::windows::{ + get_ip_interface_entry, set_ip_interface_entry, string_from_guid, AddressFamily, +}; use lazy_static::lazy_static; use std::{ ffi::CStr, @@ -483,24 +485,6 @@ impl Drop for WintunLoggerHandle { } } -/// Obtain a string representation for a GUID object. -fn string_from_guid(guid: &GUID) -> String { - use std::{ffi::OsString, os::windows::ffi::OsStringExt}; - use winapi::um::combaseapi::StringFromGUID2; - - let mut buffer = [0u16; 40]; - let length = unsafe { StringFromGUID2(guid, &mut buffer[0] as *mut _, buffer.len() as i32 - 1) } - as usize; - if length > 0 { - let length = length - 1; - OsString::from_wide(&buffer[0..length]) - .to_string_lossy() - .to_string() - } else { - "".to_string() - } -} - /// Returns the registry key for a network device identified by its GUID. fn find_adapter_registry_key(find_guid: &str, permissions: REGSAM) -> io::Result<RegKey> { let net_devs = RegKey::predef(HKEY_LOCAL_MACHINE).open_subkey_with_flags( diff --git a/talpid-core/src/tunnel_state_machine/connected_state.rs b/talpid-core/src/tunnel_state_machine/connected_state.rs index 80b6de8772..80e5e28957 100644 --- a/talpid-core/src/tunnel_state_machine/connected_state.rs +++ b/talpid-core/src/tunnel_state_machine/connected_state.rs @@ -123,7 +123,7 @@ impl ConnectedState { fn set_dns(&self, shared_values: &mut SharedTunnelStateValues) -> Result<(), BoxedError> { let dns_ips = self.get_dns_servers(shared_values); - #[cfg(target_os = "linux")] + #[cfg(any(target_os = "linux", target_os = "windows"))] let dns_ips = &dns_ips .into_iter() .filter(|ip| { diff --git a/talpid-core/src/windows/mod.rs b/talpid-core/src/windows/mod.rs index 4ec1fe19f3..115d8f5397 100644 --- a/talpid-core/src/windows/mod.rs +++ b/talpid-core/src/windows/mod.rs @@ -1,34 +1,48 @@ use socket2::SockAddr; use std::{ ffi::{OsStr, OsString}, - fmt, io, mem, + fmt, io, + mem::{self, MaybeUninit}, net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}, os::windows::{ ffi::{OsStrExt, OsStringExt}, io::RawHandle, }, + path::PathBuf, + ptr, sync::Mutex, time::{Duration, Instant}, }; -use winapi::shared::{ - ifdef::NET_LUID, - in6addr::IN6_ADDR, - inaddr::IN_ADDR, - netioapi::{ - CancelMibChangeNotify2, ConvertInterfaceAliasToLuid, ConvertInterfaceLuidToAlias, - FreeMibTable, GetIpInterfaceEntry, GetUnicastIpAddressEntry, GetUnicastIpAddressTable, - MibAddInstance, NotifyIpInterfaceChange, SetIpInterfaceEntry, MIB_IPINTERFACE_ROW, - MIB_UNICASTIPADDRESS_ROW, MIB_UNICASTIPADDRESS_TABLE, +use widestring::WideCStr; +use winapi::{ + shared::{ + guiddef::GUID, + ifdef::NET_LUID, + in6addr::IN6_ADDR, + inaddr::IN_ADDR, + netioapi::{ + CancelMibChangeNotify2, ConvertInterfaceAliasToLuid, ConvertInterfaceLuidToAlias, + ConvertInterfaceLuidToGuid, FreeMibTable, GetIpInterfaceEntry, + GetUnicastIpAddressEntry, GetUnicastIpAddressTable, MibAddInstance, + NotifyIpInterfaceChange, SetIpInterfaceEntry, MIB_IPINTERFACE_ROW, + MIB_UNICASTIPADDRESS_ROW, MIB_UNICASTIPADDRESS_TABLE, + }, + nldef::{IpDadStatePreferred, IpDadStateTentative, NL_DAD_STATE}, + ntddndis::NDIS_IF_MAX_STRING_SIZE, + ntdef::FALSE, + winerror::{ERROR_NOT_FOUND, NO_ERROR, S_OK}, + ws2def::{ + AF_INET, AF_INET6, AF_UNSPEC, SOCKADDR_IN as sockaddr_in, + SOCKADDR_STORAGE as sockaddr_storage, + }, + ws2ipdef::{SOCKADDR_IN6_LH as sockaddr_in6, SOCKADDR_INET}, }, - nldef::{IpDadStatePreferred, IpDadStateTentative, NL_DAD_STATE}, - ntddndis::NDIS_IF_MAX_STRING_SIZE, - ntdef::FALSE, - winerror::{ERROR_NOT_FOUND, NO_ERROR}, - ws2def::{ - AF_INET, AF_INET6, AF_UNSPEC, SOCKADDR_IN as sockaddr_in, - SOCKADDR_STORAGE as sockaddr_storage, + um::{ + combaseapi::{CoTaskMemFree, StringFromGUID2}, + knownfolders::FOLDERID_System, + shlobj::SHGetKnownFolderPath, + winnt::PWSTR, }, - ws2ipdef::{SOCKADDR_IN6_LH as sockaddr_in6, SOCKADDR_INET}, }; pub mod window; @@ -350,6 +364,27 @@ pub fn get_unicast_table( Ok(unicast_rows) } +/// Obtain a string representation for a GUID object. +pub fn string_from_guid(guid: &GUID) -> String { + let mut buffer = [0u16; 40]; + let length = unsafe { StringFromGUID2(guid, &mut buffer[0] as *mut _, buffer.len() as i32 - 1) } + as usize; + // cannot fail because `buffer` is large enough + assert!(length > 0); + let length = length - 1; + String::from_utf16(&buffer[0..length]).unwrap() +} + +/// Returns the GUID of a network interface given its LUID. +pub fn guid_from_luid(luid: &NET_LUID) -> io::Result<GUID> { + let mut guid = MaybeUninit::zeroed(); + let status = unsafe { ConvertInterfaceLuidToGuid(luid, guid.as_mut_ptr()) }; + if status != NO_ERROR { + return Err(io::Error::from_raw_os_error(status as i32)); + } + Ok(unsafe { guid.assume_init() }) +} + /// Returns the LUID of an interface given its alias. pub fn luid_from_alias<T: AsRef<OsStr>>(alias: T) -> io::Result<NET_LUID> { let alias_wide: Vec<u16> = alias @@ -435,6 +470,24 @@ pub fn try_socketaddr_from_inet_sockaddr(addr: SOCKADDR_INET) -> Result<SocketAd .ok_or(Error::UnknownAddressFamily(family)) } +/// Returns the system directory, i.e. `%windir%\system32`. +pub fn get_system_dir() -> io::Result<PathBuf> { + let mut folder_path: PWSTR = ptr::null_mut(); + let status = + unsafe { SHGetKnownFolderPath(&FOLDERID_System, 0, ptr::null_mut(), &mut folder_path) }; + let result = if status == S_OK { + let path = unsafe { WideCStr::from_ptr_str(folder_path) }; + Ok(path.to_ustring().to_os_string().into()) + } else { + Err(io::Error::new( + io::ErrorKind::NotFound, + "Cannot find the system directory", + )) + }; + unsafe { CoTaskMemFree(folder_path as *mut _) }; + result +} + /// Casts a struct to a slice of possibly uninitialized bytes. #[cfg(target_os = "windows")] pub fn as_uninit_byte_slice<T: Copy + Sized>(value: &T) -> &[mem::MaybeUninit<u8>] { diff --git a/windows/windns/extras.sln b/windows/windns/extras.sln deleted file mode 100644 index b65334eea0..0000000000 --- a/windows/windns/extras.sln +++ /dev/null @@ -1,72 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29324.140 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "loader", "src\extras\loader\loader.vcxproj", "{1476A8B9-4A9E-4358-8744-A350CB97E152}" - ProjectSection(ProjectDependencies) = postProject - {A5344205-FC37-4572-9C63-8564ECC410AC} = {A5344205-FC37-4572-9C63-8564ECC410AC} - {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D} = {EE69EA4A-CF71-4B88-866B-957F60C4CE0D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windns", "src\windns\windns.vcxproj", "{A5344205-FC37-4572-9C63-8564ECC410AC}" - ProjectSection(ProjectDependencies) = postProject - {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D} = {EE69EA4A-CF71-4B88-866B-957F60C4CE0D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcommon", "..\windows-libraries\src\libcommon\libcommon.vcxproj", "{B52E2D10-A94A-4605-914A-2DCEF6A757EF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libshared", "..\libshared\src\libshared\libshared.vcxproj", "{EE69EA4A-CF71-4B88-866B-957F60C4CE0D}" - ProjectSection(ProjectDependencies) = postProject - {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} - EndProjectSection -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 - {1476A8B9-4A9E-4358-8744-A350CB97E152}.Debug|x64.ActiveCfg = Debug|x64 - {1476A8B9-4A9E-4358-8744-A350CB97E152}.Debug|x64.Build.0 = Debug|x64 - {1476A8B9-4A9E-4358-8744-A350CB97E152}.Debug|x86.ActiveCfg = Debug|Win32 - {1476A8B9-4A9E-4358-8744-A350CB97E152}.Debug|x86.Build.0 = Debug|Win32 - {1476A8B9-4A9E-4358-8744-A350CB97E152}.Release|x64.ActiveCfg = Release|x64 - {1476A8B9-4A9E-4358-8744-A350CB97E152}.Release|x64.Build.0 = Release|x64 - {1476A8B9-4A9E-4358-8744-A350CB97E152}.Release|x86.ActiveCfg = Release|Win32 - {1476A8B9-4A9E-4358-8744-A350CB97E152}.Release|x86.Build.0 = Release|Win32 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x64.ActiveCfg = Debug|x64 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x64.Build.0 = Debug|x64 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x86.ActiveCfg = Debug|Win32 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x86.Build.0 = Debug|Win32 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x64.ActiveCfg = Release|x64 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x64.Build.0 = Release|x64 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x86.ActiveCfg = Release|Win32 - {A5344205-FC37-4572-9C63-8564ECC410AC}.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 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Debug|x64.ActiveCfg = Debug|x64 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Debug|x64.Build.0 = Debug|x64 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Debug|x86.ActiveCfg = Debug|Win32 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Debug|x86.Build.0 = Debug|Win32 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x64.ActiveCfg = Release|x64 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x64.Build.0 = Release|x64 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x86.ActiveCfg = Release|Win32 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {16D5A833-BF2F-4049-A7E1-570B792F8148} - EndGlobalSection -EndGlobal diff --git a/windows/windns/src/extras/loader/loader.cpp b/windows/windns/src/extras/loader/loader.cpp deleted file mode 100644 index d4e118e3a0..0000000000 --- a/windows/windns/src/extras/loader/loader.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "stdafx.h" -#include "windns/windns.h" -#include <libshared/logging/stdoutlogger.h> -#include <libcommon/trace/trace.h> -#include <libcommon/trace/consoletracesink.h> -#include <iostream> -#include <conio.h> -#include <vector> -#include <windows.h> - -int main() -{ - common::trace::Trace::RegisterSink(new common::trace::ConsoleTraceSink); - - std::wcout << L"WinDns_Initialize: " << std::boolalpha << WinDns_Initialize(shared::logging::StdoutLogger, nullptr) << std::endl; - - const wchar_t *servers[] = - { - L"8.8.8.8", - L"8.8.4.4" - }; - - const wchar_t *v6Servers[] = - { - L"2001:4860:4860::8888", - L"2001:4860:4860::8844" - }; - - auto status = WinDns_Set(L"Wi-Fi", servers, _countof(servers), v6Servers, _countof(v6Servers)); - - std::wcout << L"WinDns_Set: " << std::boolalpha << status << std::endl; - - std::wcout << L"WinDns_Deinitialize: " << std::boolalpha << WinDns_Deinitialize() << std::endl; - - return 0; -} diff --git a/windows/windns/src/extras/loader/loader.vcxproj b/windows/windns/src/extras/loader/loader.vcxproj deleted file mode 100644 index 43780ba0fd..0000000000 --- a/windows/windns/src/extras/loader/loader.vcxproj +++ /dev/null @@ -1,193 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="16.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> - <PropertyGroup Label="Globals"> - <VCProjectVersion>16.0</VCProjectVersion> - <ProjectGuid>{1476A8B9-4A9E-4358-8744-A350CB97E152}</ProjectGuid> - <Keyword>Win32Proj</Keyword> - <RootNamespace>loader</RootNamespace> - <WindowsTargetPlatformVersion>10.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>v142</PlatformToolset> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v142</PlatformToolset> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v142</PlatformToolset> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>Application</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v142</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|x64'"> - <LinkIncremental>true</LinkIncremental> - <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> - <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <LinkIncremental>true</LinkIncremental> - <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> - <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> - <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> - <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> - </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <PrecompiledHeader>Use</PrecompiledHeader> - <WarningLevel>Level4</WarningLevel> - <Optimization>Disabled</Optimization> - <SDLCheck>true</SDLCheck> - <PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <ConformanceMode>true</ConformanceMode> - <AdditionalIncludeDirectories>$(ProjectDir)../../../../libshared/src/;$(ProjectDir)../../;$(ProjectDir)../../../../windows-libraries/src/</AdditionalIncludeDirectories> - <LanguageStandard>stdcpplatest</LanguageStandard> - <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>libshared.lib;windns.lib;libcommon.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|Win32'"> - <ClCompile> - <PrecompiledHeader>Use</PrecompiledHeader> - <WarningLevel>Level4</WarningLevel> - <Optimization>Disabled</Optimization> - <SDLCheck>true</SDLCheck> - <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <ConformanceMode>true</ConformanceMode> - <AdditionalIncludeDirectories>$(ProjectDir)../../../../libshared/src/;$(ProjectDir)../../;$(ProjectDir)../../../../windows-libraries/src/</AdditionalIncludeDirectories> - <LanguageStandard>stdcpplatest</LanguageStandard> - <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>libshared.lib;windns.lib;libcommon.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>Use</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> - <AdditionalIncludeDirectories>$(ProjectDir)../../../../libshared/src/;$(ProjectDir)../../;$(ProjectDir)../../../../windows-libraries/src/</AdditionalIncludeDirectories> - <LanguageStandard>stdcpplatest</LanguageStandard> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>libshared.lib;windns.lib;libcommon.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>Use</PrecompiledHeader> - <WarningLevel>Level4</WarningLevel> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <SDLCheck>true</SDLCheck> - <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <ConformanceMode>true</ConformanceMode> - <AdditionalIncludeDirectories>$(ProjectDir)../../../../libshared/src/;$(ProjectDir)../../;$(ProjectDir)../../../../windows-libraries/src/</AdditionalIncludeDirectories> - <LanguageStandard>stdcpplatest</LanguageStandard> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - </ClCompile> - <Link> - <SubSystem>Console</SubSystem> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>libshared.lib;windns.lib;libcommon.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> - <ItemGroup> - <ClInclude Include="stdafx.h" /> - <ClInclude Include="targetver.h" /> - </ItemGroup> - <ItemGroup> - <ClCompile Include="loader.cpp" /> - <ClCompile Include="stdafx.cpp"> - <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> - <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> - <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> - <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> - </ClCompile> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project>
\ No newline at end of file diff --git a/windows/windns/src/extras/loader/loader.vcxproj.filters b/windows/windns/src/extras/loader/loader.vcxproj.filters deleted file mode 100644 index e29869c50f..0000000000 --- a/windows/windns/src/extras/loader/loader.vcxproj.filters +++ /dev/null @@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <ClInclude Include="stdafx.h" /> - <ClInclude Include="targetver.h" /> - </ItemGroup> - <ItemGroup> - <ClCompile Include="loader.cpp" /> - <ClCompile Include="stdafx.cpp" /> - </ItemGroup> -</Project>
\ No newline at end of file diff --git a/windows/windns/src/extras/loader/stdafx.cpp b/windows/windns/src/extras/loader/stdafx.cpp deleted file mode 100644 index e8a73894f3..0000000000 --- a/windows/windns/src/extras/loader/stdafx.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// stdafx.cpp : source file that includes just the standard includes -// dnstest.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/windns/src/extras/loader/stdafx.h b/windows/windns/src/extras/loader/stdafx.h deleted file mode 100644 index b005a839de..0000000000 --- a/windows/windns/src/extras/loader/stdafx.h +++ /dev/null @@ -1,15 +0,0 @@ -// 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/windns/src/extras/loader/targetver.h b/windows/windns/src/extras/loader/targetver.h deleted file mode 100644 index 87c0086de7..0000000000 --- a/windows/windns/src/extras/loader/targetver.h +++ /dev/null @@ -1,8 +0,0 @@ -#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/windns/src/windns/confineoperation.cpp b/windows/windns/src/windns/confineoperation.cpp deleted file mode 100644 index 5097986c0f..0000000000 --- a/windows/windns/src/windns/confineoperation.cpp +++ /dev/null @@ -1,33 +0,0 @@ -#include "stdafx.h" -#include "confineoperation.h" -#include "netsh.h" - -bool ConfineOperation -( - const char *literalOperation, - std::shared_ptr<common::logging::ILogSink> logSink, - std::function<void()> operation -) -{ - try - { - operation(); - return true; - } - catch (const std::exception &err) - { - const auto what = std::string(literalOperation).append(": ").append(err.what()); - - logSink->error(what.c_str()); - - return false; - } - catch (...) - { - const auto what = std::string(literalOperation).append(": Unspecified failure"); - - logSink->error(what.c_str()); - - return false; - } -} diff --git a/windows/windns/src/windns/confineoperation.h b/windows/windns/src/windns/confineoperation.h deleted file mode 100644 index 56aa48a929..0000000000 --- a/windows/windns/src/windns/confineoperation.h +++ /dev/null @@ -1,14 +0,0 @@ -#pragma once - -#include <libcommon/logging/ilogsink.h> -#include <functional> -#include <vector> -#include <string> -#include <cstdint> - -bool ConfineOperation -( - const char *literalOperation, - std::shared_ptr<common::logging::ILogSink> logSink, - std::function<void()> operation -); diff --git a/windows/windns/src/windns/dllmain.cpp b/windows/windns/src/windns/dllmain.cpp deleted file mode 100644 index f11c65c519..0000000000 --- a/windows/windns/src/windns/dllmain.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "stdafx.h" -#include <windows.h> - -BOOL APIENTRY DllMain(HMODULE, DWORD, LPVOID) -{ - // - // Avoid doing work in DllMain since the loader lock is held - // - - return TRUE; -} diff --git a/windows/windns/src/windns/netsh.cpp b/windows/windns/src/windns/netsh.cpp deleted file mode 100644 index 2a4162724d..0000000000 --- a/windows/windns/src/windns/netsh.cpp +++ /dev/null @@ -1,221 +0,0 @@ -#include "stdafx.h" -#include "netsh.h" -#include <libcommon/string.h> -#include <libcommon/error.h> -#include <libcommon/filesystem.h> -#include <libcommon/guid.h> -#include <sstream> -#include <stdexcept> -#include <filesystem> -#include <iphlpapi.h> - -namespace -{ - -__declspec(noreturn) void ThrowWithDetails(std::string &&error, common::process::ApplicationRunner &netsh) -{ - std::string details("Failed to capture output from 'netsh'"); - - std::string output; - - static const size_t MAX_CHARS = 2048; - static const size_t TIMEOUT_MILLISECONDS = 2000; - - if (netsh.read(output, MAX_CHARS, TIMEOUT_MILLISECONDS)) - { - details = std::move(output); - } - - const auto msg = std::string(error).append(": ").append(details); - - THROW_ERROR(msg.c_str()); -} - -} // anonymous namespace - -NetSh::NetSh(std::shared_ptr<common::logging::ILogSink> logSink) - : m_logSink(logSink) -{ - const auto system32 = common::fs::GetKnownFolderPath(FOLDERID_System); - m_netShPath = std::filesystem::path(system32).append(L"netsh.exe"); -} - -void NetSh::setIpv4StaticDns(uint32_t interfaceIndex, - const std::vector<std::wstring> &nameServers, uint32_t timeout) -{ - // - // Setting primary and secondary name server requires two invokations: - // - // netsh interface ipv4 set dnsservers name="Ethernet 2" source=static address=8.8.8.8 validate=no - // netsh interface ipv4 add dnsservers name="Ethernet 2" address=8.8.4.4 index=2 validate=no - // - // Note: we're specifying the interface by index instead. - // - - if (nameServers.empty()) - { - THROW_ERROR("Invalid list of name servers (zero length list)"); - } - - { - std::wstringstream ss; - - ss << L"interface ipv4 set dnsservers name=" - << interfaceIndex - << L" source=static address=" - << nameServers[0] - << L" validate=no"; - - auto netsh = common::process::ApplicationRunner::StartWithoutConsole(m_netShPath, ss.str()); - - validateShellOut(*netsh, timeout); - } - - // - // Set additional name servers. - // - - for (size_t i = 1; i < nameServers.size(); ++i) - { - std::wstringstream ss; - - ss << L"interface ipv4 add dnsservers name=" - << interfaceIndex - << L" address=" - << nameServers[i] - << L" index=" - << i + 1 - << L" validate=no"; - - auto netsh = common::process::ApplicationRunner::StartWithoutConsole(m_netShPath, ss.str()); - - validateShellOut(*netsh, timeout); - } -} - -void NetSh::setIpv4DhcpDns(uint32_t interfaceIndex, uint32_t timeout) -{ - // - // netsh interface ipv4 set dnsservers name="Ethernet 2" source=dhcp - // - // Note: we're specifying the interface by index instead. - // - - std::wstringstream ss; - - ss << L"interface ipv4 set dnsservers name=" - << interfaceIndex - << L" source=dhcp"; - - auto netsh = common::process::ApplicationRunner::StartWithoutConsole(m_netShPath, ss.str()); - - validateShellOut(*netsh, timeout); -} - -void NetSh::setIpv6StaticDns(uint32_t interfaceIndex, - const std::vector<std::wstring> &nameServers, uint32_t timeout) -{ - // - // Setting primary and secondary name server requires two invokations: - // - // netsh interface ipv6 set dnsservers name="Ethernet 2" source=static address=2001:4860:4860::8888 validate=no - // netsh interface ipv6 add dnsservers name="Ethernet 2" address=2001:4860:4860::8844 index=2 validate=no - // - // Note: we're specifying the interface by index instead. - // - - if (nameServers.empty()) - { - THROW_ERROR("Invalid list of name servers (zero length list)"); - } - - { - std::wstringstream ss; - - ss << L"interface ipv6 set dnsservers name=" - << interfaceIndex - << L" source=static address=" - << nameServers[0] - << L" validate=no"; - - auto netsh = common::process::ApplicationRunner::StartWithoutConsole(m_netShPath, ss.str()); - - validateShellOut(*netsh, timeout); - } - - // - // Set additional name servers. - // - - for (size_t i = 1; i < nameServers.size(); ++i) - { - std::wstringstream ss; - - ss << L"interface ipv6 add dnsservers name=" - << interfaceIndex - << L" address=" - << nameServers[i] - << L" index=" - << i + 1 - << L" validate=no"; - - auto netsh = common::process::ApplicationRunner::StartWithoutConsole(m_netShPath, ss.str()); - - validateShellOut(*netsh, timeout); - } -} - -void NetSh::setIpv6DhcpDns(uint32_t interfaceIndex, uint32_t timeout) -{ - // - // netsh interface ipv6 set dnsservers name="Ethernet 2" source=dhcp - // - // Note: we're specifying the interface by index instead. - // - - std::wstringstream ss; - - ss << L"interface ipv6 set dnsservers name=" - << interfaceIndex - << L" source=dhcp"; - - auto netsh = common::process::ApplicationRunner::StartWithoutConsole(m_netShPath, ss.str()); - - validateShellOut(*netsh, timeout); -} - -void NetSh::validateShellOut(common::process::ApplicationRunner &netsh, uint32_t timeout) -{ - const uint32_t actualTimeout = (0 == timeout ? 10000 : timeout); - - const auto startTime = GetTickCount64(); - - DWORD returnCode; - - if (false == netsh.join(returnCode, actualTimeout)) - { - ThrowWithDetails("'netsh' did not complete in a timely manner", netsh); - } - - if (returnCode != 0) - { - std::stringstream ss; - - ss << "'netsh' failed the requested operation. Error: " << returnCode; - - ThrowWithDetails(ss.str(), netsh); - } - - const auto elapsed = static_cast<uint32_t>(GetTickCount64() - startTime); - - if (elapsed > (actualTimeout / 2)) - { - std::stringstream ss; - - ss << "'netsh' completed successfully, albeit a little slowly. It consumed " - << elapsed << " ms of " - << actualTimeout << " ms max permitted execution time"; - - m_logSink->info(ss.str().c_str()); - } -} diff --git a/windows/windns/src/windns/netsh.h b/windows/windns/src/windns/netsh.h deleted file mode 100644 index 732a151a65..0000000000 --- a/windows/windns/src/windns/netsh.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once - -#include <libcommon/logging/ilogsink.h> -#include <libcommon/process/applicationrunner.h> -#include <string> -#include <vector> -#include <cstdint> -#include <stdexcept> -#include <memory> - -class NetSh -{ -public: - - NetSh(std::shared_ptr<common::logging::ILogSink> logSink); - - void setIpv4StaticDns(uint32_t interfaceIndex, - const std::vector<std::wstring> &nameServers, uint32_t timeout = 0); - - void setIpv4DhcpDns(uint32_t interfaceIndex, uint32_t timeout = 0); - - void setIpv6StaticDns(uint32_t interfaceIndex, - const std::vector<std::wstring> &nameServers, uint32_t timeout = 0); - - void setIpv6DhcpDns(uint32_t interfaceIndex, uint32_t timeout = 0); - -private: - - std::shared_ptr<common::logging::ILogSink> m_logSink; - std::wstring m_netShPath; - - void validateShellOut(common::process::ApplicationRunner &netsh, uint32_t timeout); -}; diff --git a/windows/windns/src/windns/stdafx.cpp b/windows/windns/src/windns/stdafx.cpp deleted file mode 100644 index 689eb89a7e..0000000000 --- a/windows/windns/src/windns/stdafx.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// stdafx.cpp : source file that includes just the standard includes -// windns.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/windns/src/windns/stdafx.h b/windows/windns/src/windns/stdafx.h deleted file mode 100644 index 6878f4de13..0000000000 --- a/windows/windns/src/windns/stdafx.h +++ /dev/null @@ -1,17 +0,0 @@ -// 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" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers - -#include <windows.h> -#include <sstream> -#include <string> -#include <vector> -#include <stdexcept> -#include <cstdint> diff --git a/windows/windns/src/windns/targetver.h b/windows/windns/src/windns/targetver.h deleted file mode 100644 index ae4a5c032c..0000000000 --- a/windows/windns/src/windns/targetver.h +++ /dev/null @@ -1,12 +0,0 @@ -#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 <WinSDKVer.h> - -#define _WIN32_WINNT _WIN32_WINNT_WIN7 - -#include <SDKDDKVer.h> diff --git a/windows/windns/src/windns/windns.cpp b/windows/windns/src/windns/windns.cpp deleted file mode 100644 index f7cc35f27f..0000000000 --- a/windows/windns/src/windns/windns.cpp +++ /dev/null @@ -1,321 +0,0 @@ -#include "stdafx.h" -#include <libcommon/guid.h> -#include <libcommon/string.h> -#include <libcommon/error.h> -#include <libshared/network/interfaceutils.h> -#include <libcommon/logging/ilogsink.h> -#include <libshared/logging/logsinkadapter.h> -#include "windns.h" -#include "confineoperation.h" -#include "netsh.h" -#include <memory> -#include <vector> -#include <string> -#include <sstream> -#include <ws2tcpip.h> -#include <ws2ipdef.h> -#include <winsock2.h> // magic order :-( -#include <iphlpapi.h> // if we don't do this then most of iphlpapi is not actually defined - -bool operator==(const IN_ADDR &lhs, const IN_ADDR &rhs) -{ - return 0 == memcmp(&lhs, &rhs, sizeof(IN_ADDR)); -} - -bool operator==(const IN6_ADDR &lhs, const IN6_ADDR &rhs) -{ - return 0 == memcmp(&lhs, &rhs, sizeof(IN6_ADDR)); -} - -namespace -{ - -std::shared_ptr<common::logging::ILogSink> g_LogSink; -std::shared_ptr<NetSh> g_NetSh; - -std::vector<std::wstring> MakeStringArray(const wchar_t **strings, uint32_t numStrings) -{ - std::vector<std::wstring> v; - - while (numStrings--) - { - v.emplace_back(*strings++); - } - - return v; -} - -uint32_t ConvertInterfaceLuidToIndex(const NET_LUID &luid) -{ - NET_IFINDEX index; - - if (NO_ERROR != ConvertInterfaceLuidToIndex(&luid, &index)) - { - std::wstringstream ss; - - ss << L"Could not resolve index of interface with LUID: 0x" - << std::hex << luid.Value; - - THROW_ERROR(common::string::ToAnsi(ss.str()).c_str()); - } - - return static_cast<uint32_t>(index); -} - -struct AdapterDnsAddresses -{ - std::vector<IN_ADDR> ipv4; - std::vector<IN6_ADDR> ipv6; -}; - -// -// The adapter structure that is returned has two fields for interface index. -// If IPv4 is enabled, 'IfIndex' will be set. Otherwise set to 0. -// If IPv6 is enabled, 'Ipv6IfIndex' will be set. Otherwise set to 0. -// If both IPv4 and IPv6 is enabled, then both fields will be set, and have the same value. -// -AdapterDnsAddresses GetAdapterDnsAddresses(const NET_LUID &adapterLuid) -{ - using shared::network::InterfaceUtils; - - const auto adapters = InterfaceUtils::GetAllAdapters( - AF_UNSPEC, - GAA_FLAG_SKIP_UNICAST | GAA_FLAG_SKIP_ANYCAST | GAA_FLAG_SKIP_MULTICAST - ); - - for (const auto adapter : adapters) - { - if (adapterLuid.Value != adapter.raw().Luid.Value) - { - continue; - } - - AdapterDnsAddresses out; - - for (auto server = adapter.raw().FirstDnsServerAddress; nullptr != server; server = server->Next) - { - if (AF_INET == server->Address.lpSockaddr->sa_family) - { - out.ipv4.push_back(((const SOCKADDR_IN*)server->Address.lpSockaddr)->sin_addr); - } - else if (AF_INET6 == server->Address.lpSockaddr->sa_family) - { - out.ipv6.push_back(((const SOCKADDR_IN6_LH*)server->Address.lpSockaddr)->sin6_addr); - } - } - - return out; - } - - std::stringstream ss; - ss << "Could not find interface with LUID: 0x" << std::hex << adapterLuid.Value; - THROW_ERROR(ss.str().c_str()); -} - -AdapterDnsAddresses ConvertAddresses( - const wchar_t **ipv4Servers, - uint32_t numIpv4Servers, - const wchar_t **ipv6Servers, - uint32_t numIpv6Servers -) -{ - AdapterDnsAddresses out; - - if (nullptr != ipv4Servers && 0 != numIpv4Servers) - { - for (uint32_t i = 0; i < numIpv4Servers; ++i) - { - IN_ADDR converted; - - if (1 != InetPtonW(AF_INET, ipv4Servers[i], &converted)) - { - THROW_ERROR("Failed to convert IPv4 address"); - } - - out.ipv4.push_back(converted); - } - } - - if (nullptr != ipv6Servers && 0 != numIpv6Servers) - { - for (uint32_t i = 0; i < numIpv6Servers; ++i) - { - IN6_ADDR converted; - - if (1 != InetPtonW(AF_INET6, ipv6Servers[i], &converted)) - { - THROW_ERROR("Failed to convert IPv6 address"); - } - - out.ipv6.push_back(converted); - } - } - - return out; -} - -bool Equal(const AdapterDnsAddresses &lhs, const AdapterDnsAddresses &rhs) -{ - return lhs.ipv4 == rhs.ipv4 - && lhs.ipv6 == rhs.ipv6; -} - -} // anonymous namespace - -WINDNS_LINKAGE -bool -WINDNS_API -WinDns_Initialize( - MullvadLogSink logSink, - void *logSinkContext -) -{ - if (g_LogSink) - { - return false; - } - - try - { - g_LogSink = std::make_shared<shared::logging::LogSinkAdapter>(logSink, logSinkContext); - - try - { - g_NetSh = std::make_shared<NetSh>(g_LogSink); - } - catch (...) - { - g_LogSink.reset(); - throw; - } - - return true; - } - catch (const std::exception &err) - { - if (nullptr != logSink) - { - const auto msg = std::string("Failed to initialize WinDns: ").append(err.what()); - logSink(MULLVAD_LOG_LEVEL_ERROR, msg.c_str(), logSinkContext); - } - - return false; - } - catch (...) - { - if (nullptr != logSink) - { - const std::string msg("Failed to initialize WinDns: Unspecified error"); - logSink(MULLVAD_LOG_LEVEL_ERROR, msg.c_str(), logSinkContext); - } - - return false; - } -} - -WINDNS_LINKAGE -bool -WINDNS_API -WinDns_Deinitialize( -) -{ - g_NetSh.reset(); - g_LogSink.reset(); - - return true; -} - -WINDNS_LINKAGE -bool -WINDNS_API -WinDns_Set( - const NET_LUID *interfaceLuid, - const wchar_t **ipv4Servers, - uint32_t numIpv4Servers, - const wchar_t **ipv6Servers, - uint32_t numIpv6Servers -) -{ - if (nullptr == g_LogSink) - { - return false; - } - - if (nullptr == interfaceLuid) - { - g_LogSink->error("Invalid argument: interfaceLuid"); - return false; - } - - // - // Check the settings on the adapter. - // If it already has the exact same settings we need, we're done. - // - try - { - const auto activeSettings = GetAdapterDnsAddresses(*interfaceLuid); - const auto wantedSetting = ConvertAddresses(ipv4Servers, numIpv4Servers, ipv6Servers, numIpv6Servers); - - if (Equal(activeSettings, wantedSetting)) - { - std::stringstream ss; - - ss << "DNS settings on adapter with LUID 0x" << std::hex << interfaceLuid->Value << " are up-to-date"; - - g_LogSink->info(ss.str().c_str()); - - return true; - } - } - catch (const std::exception &err) - { - std::stringstream ss; - - ss << "Failed to evaluate DNS settings on adapter with LUID 0x" - << std::hex << interfaceLuid->Value << ": " << err.what(); - - g_LogSink->info(ss.str().c_str()); - } - catch (...) - { - std::stringstream ss; - - ss << "Failed to evaluate DNS settings on adapter with LUID 0x" - << std::hex << interfaceLuid->Value << ": Unspecified failure"; - - g_LogSink->info(ss.str().c_str()); - } - - // - // Apply specified settings. - // - - std::stringstream operation; - operation << "Apply DNS settings on adapter with LUID 0x" - << std::hex << interfaceLuid->Value; - - return ConfineOperation(operation.str().c_str(), g_LogSink, [&]() - { - const auto interfaceIndex = ConvertInterfaceLuidToIndex(*interfaceLuid); - - if (nullptr != ipv4Servers && 0 != numIpv4Servers) - { - g_NetSh->setIpv4StaticDns(interfaceIndex, MakeStringArray(ipv4Servers, numIpv4Servers)); - } - else - { - // This is required to clear any current settings. - g_NetSh->setIpv4DhcpDns(interfaceIndex); - } - - if (nullptr != ipv6Servers && 0 != numIpv6Servers) - { - g_NetSh->setIpv6StaticDns(interfaceIndex, MakeStringArray(ipv6Servers, numIpv6Servers)); - } - else - { - // This is required to clear any current settings. - g_NetSh->setIpv6DhcpDns(interfaceIndex); - } - }); -} diff --git a/windows/windns/src/windns/windns.h b/windows/windns/src/windns/windns.h deleted file mode 100644 index a26d4a88d4..0000000000 --- a/windows/windns/src/windns/windns.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once - -#include <libshared/logging/logsink.h> -#include <stdint.h> - -// -// WINDNS public API -// - -#ifdef WINDNS_EXPORTS -#define WINDNS_LINKAGE __declspec(dllexport) -#else -#define WINDNS_LINKAGE __declspec(dllimport) -#endif - -#define WINDNS_API __stdcall - -/////////////////////////////////////////////////////////////////////////////// -// Functions -/////////////////////////////////////////////////////////////////////////////// - -// -// WinDns_Initialize: -// -// Call this function once at startup, to acquire resources etc. -// The error callback is OPTIONAL. -// -extern "C" -WINDNS_LINKAGE -bool -WINDNS_API -WinDns_Initialize( - MullvadLogSink logSink, - void *logSinkContext -); - -// -// WinDns_Deinitialize: -// -// Call this function once before unloading WINDNS or exiting the process. -// -extern "C" -WINDNS_LINKAGE -bool -WINDNS_API -WinDns_Deinitialize( -); - -// -// WinDns_Set: -// -// Configure DNS servers on given adapter. -// -extern "C" -WINDNS_LINKAGE -bool -WINDNS_API -WinDns_Set( - const NET_LUID *interfaceLuid, - const wchar_t **ipv4Servers, - uint32_t numIpv4Servers, - const wchar_t **ipv6Servers, - uint32_t numIpv6Servers -); diff --git a/windows/windns/src/windns/windns.rc b/windows/windns/src/windns/windns.rc deleted file mode 100644 index 41a4f71683..0000000000 --- a/windows/windns/src/windns/windns.rc +++ /dev/null @@ -1,25 +0,0 @@ -#include "../../../../dist-assets/windows/version.h" - -1 VERSIONINFO -FILEVERSION MAJOR_VERSION,MINOR_VERSION,PATCH_VERSION,0 -PRODUCTVERSION MAJOR_VERSION,MINOR_VERSION,PATCH_VERSION,0 -BEGIN -BLOCK "StringFileInfo" -BEGIN - BLOCK "040904E4" - BEGIN - VALUE "CompanyName", "Mullvad VPN AB" - VALUE "FileDescription", "Mullvad VPN DNS module" - VALUE "FileVersion", PRODUCT_VERSION - VALUE "InternalName", "windns" - VALUE "LegalCopyright", "(c) 2022 Mullvad VPN AB" - VALUE "OriginalFilename", "windns.dll" - VALUE "ProductName", "Mullvad VPN" - VALUE "ProductVersion", PRODUCT_VERSION - END -END -BLOCK "VarFileInfo" -BEGIN - VALUE "Translation", 0x409, 1252 -END -END diff --git a/windows/windns/src/windns/windns.vcxproj b/windows/windns/src/windns/windns.vcxproj deleted file mode 100644 index 05293ca9a4..0000000000 --- a/windows/windns/src/windns/windns.vcxproj +++ /dev/null @@ -1,202 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project DefaultTargets="Build" ToolsVersion="16.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> - <PropertyGroup Label="Globals"> - <VCProjectVersion>16.0</VCProjectVersion> - <ProjectGuid>{A5344205-FC37-4572-9C63-8564ECC410AC}</ProjectGuid> - <Keyword>Win32Proj</Keyword> - <RootNamespace>windns</RootNamespace> - <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion> - </PropertyGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v142</PlatformToolset> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v142</PlatformToolset> - <WholeProgramOptimization>true</WholeProgramOptimization> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <UseDebugLibraries>true</UseDebugLibraries> - <PlatformToolset>v142</PlatformToolset> - <CharacterSet>Unicode</CharacterSet> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration"> - <ConfigurationType>DynamicLibrary</ConfigurationType> - <UseDebugLibraries>false</UseDebugLibraries> - <PlatformToolset>v142</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|x64'"> - <LinkIncremental>true</LinkIncremental> - <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> - <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'"> - <LinkIncremental>true</LinkIncremental> - <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> - <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> - <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> - </PropertyGroup> - <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> - <LinkIncremental>false</LinkIncremental> - <OutDir>$(SolutionDir)bin\$(Platform)-$(Configuration)\</OutDir> - <IntDir>$(SolutionDir)bin\temp\$(Platform)-$(Configuration)\$(ProjectName)\</IntDir> - </PropertyGroup> - <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> - <ClCompile> - <PrecompiledHeader>Use</PrecompiledHeader> - <WarningLevel>Level4</WarningLevel> - <Optimization>Disabled</Optimization> - <SDLCheck>true</SDLCheck> - <PreprocessorDefinitions>_DEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <ConformanceMode>true</ConformanceMode> - <AdditionalIncludeDirectories>$(ProjectDir)../../../libshared/src/;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> - <LanguageStandard>stdcpplatest</LanguageStandard> - </ClCompile> - <Link> - <SubSystem>Windows</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>libshared.lib;libcommon.lib;Iphlpapi.lib;wbemuuid.lib;comsuppw.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|Win32'"> - <ClCompile> - <PrecompiledHeader>Use</PrecompiledHeader> - <WarningLevel>Level4</WarningLevel> - <Optimization>Disabled</Optimization> - <SDLCheck>true</SDLCheck> - <PreprocessorDefinitions>WIN32;_DEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <ConformanceMode>true</ConformanceMode> - <AdditionalIncludeDirectories>$(ProjectDir)../../../libshared/src/;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary> - <LanguageStandard>stdcpplatest</LanguageStandard> - </ClCompile> - <Link> - <SubSystem>Windows</SubSystem> - <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>libshared.lib;libcommon.lib;Iphlpapi.lib;wbemuuid.lib;comsuppw.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>Use</PrecompiledHeader> - <WarningLevel>Level4</WarningLevel> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <SDLCheck>true</SDLCheck> - <PreprocessorDefinitions>WIN32;NDEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <ConformanceMode>true</ConformanceMode> - <AdditionalIncludeDirectories>$(ProjectDir)../../../libshared/src/;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - <LanguageStandard>stdcpplatest</LanguageStandard> - </ClCompile> - <Link> - <SubSystem>Windows</SubSystem> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>libshared.lib;libcommon.lib;Iphlpapi.lib;wbemuuid.lib;comsuppw.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>Use</PrecompiledHeader> - <WarningLevel>Level4</WarningLevel> - <Optimization>MaxSpeed</Optimization> - <FunctionLevelLinking>true</FunctionLevelLinking> - <IntrinsicFunctions>true</IntrinsicFunctions> - <SDLCheck>true</SDLCheck> - <PreprocessorDefinitions>NDEBUG;WINDNS_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> - <ConformanceMode>true</ConformanceMode> - <AdditionalIncludeDirectories>$(ProjectDir)../../../libshared/src/;$(ProjectDir)../../../windows-libraries/src/</AdditionalIncludeDirectories> - <RuntimeLibrary>MultiThreaded</RuntimeLibrary> - <LanguageStandard>stdcpplatest</LanguageStandard> - </ClCompile> - <Link> - <SubSystem>Windows</SubSystem> - <EnableCOMDATFolding>true</EnableCOMDATFolding> - <OptimizeReferences>true</OptimizeReferences> - <GenerateDebugInformation>true</GenerateDebugInformation> - <AdditionalLibraryDirectories>$(SolutionDir)bin\$(Platform)-$(Configuration)\</AdditionalLibraryDirectories> - <AdditionalDependencies>libshared.lib;libcommon.lib;Iphlpapi.lib;wbemuuid.lib;comsuppw.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> - <ItemGroup> - <ClInclude Include="confineoperation.h" /> - <ClInclude Include="netsh.h" /> - <ClInclude Include="stdafx.h" /> - <ClInclude Include="targetver.h" /> - <ClInclude Include="windns.h" /> - </ItemGroup> - <ItemGroup> - <ClCompile Include="confineoperation.cpp" /> - <ClCompile Include="dllmain.cpp" /> - <ClCompile Include="netsh.cpp" /> - <ClCompile Include="stdafx.cpp"> - <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader> - <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader> - <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader> - <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader> - </ClCompile> - <ClCompile Include="windns.cpp" /> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="windns.rc" /> - </ItemGroup> - <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> - <ImportGroup Label="ExtensionTargets"> - </ImportGroup> -</Project>
\ No newline at end of file diff --git a/windows/windns/src/windns/windns.vcxproj.filters b/windows/windns/src/windns/windns.vcxproj.filters deleted file mode 100644 index 69449dc6c4..0000000000 --- a/windows/windns/src/windns/windns.vcxproj.filters +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> - <ItemGroup> - <ClInclude Include="stdafx.h" /> - <ClInclude Include="targetver.h" /> - <ClInclude Include="windns.h" /> - <ClInclude Include="netsh.h" /> - <ClInclude Include="confineoperation.h" /> - </ItemGroup> - <ItemGroup> - <ClCompile Include="dllmain.cpp" /> - <ClCompile Include="stdafx.cpp" /> - <ClCompile Include="windns.cpp" /> - <ClCompile Include="netsh.cpp" /> - <ClCompile Include="confineoperation.cpp" /> - </ItemGroup> - <ItemGroup> - <ResourceCompile Include="windns.rc" /> - </ItemGroup> -</Project>
\ No newline at end of file diff --git a/windows/windns/windns.sln b/windows/windns/windns.sln deleted file mode 100644 index efe218a454..0000000000 --- a/windows/windns/windns.sln +++ /dev/null @@ -1,61 +0,0 @@ -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29324.140 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libcommon", "..\windows-libraries\src\libcommon\libcommon.vcxproj", "{B52E2D10-A94A-4605-914A-2DCEF6A757EF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "windns", "src\windns\windns.vcxproj", "{A5344205-FC37-4572-9C63-8564ECC410AC}" - ProjectSection(ProjectDependencies) = postProject - {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D} = {EE69EA4A-CF71-4B88-866B-957F60C4CE0D} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libshared", "..\libshared\src\libshared\libshared.vcxproj", "{EE69EA4A-CF71-4B88-866B-957F60C4CE0D}" - ProjectSection(ProjectDependencies) = postProject - {B52E2D10-A94A-4605-914A-2DCEF6A757EF} = {B52E2D10-A94A-4605-914A-2DCEF6A757EF} - EndProjectSection -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 - {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 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x64.ActiveCfg = Debug|x64 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x64.Build.0 = Debug|x64 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x64.Deploy.0 = Debug|x64 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x86.ActiveCfg = Debug|Win32 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x86.Build.0 = Debug|Win32 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Debug|x86.Deploy.0 = Debug|Win32 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x64.ActiveCfg = Release|x64 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x64.Build.0 = Release|x64 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x64.Deploy.0 = Release|x64 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x86.ActiveCfg = Release|Win32 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x86.Build.0 = Release|Win32 - {A5344205-FC37-4572-9C63-8564ECC410AC}.Release|x86.Deploy.0 = Release|Win32 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Debug|x64.ActiveCfg = Debug|x64 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Debug|x64.Build.0 = Debug|x64 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Debug|x86.ActiveCfg = Debug|Win32 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Debug|x86.Build.0 = Debug|Win32 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x64.ActiveCfg = Release|x64 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x64.Build.0 = Release|x64 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x86.ActiveCfg = Release|Win32 - {EE69EA4A-CF71-4B88-866B-957F60C4CE0D}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {A28F3793-15A7-4EE5-A899-373DF084D91F} - EndGlobalSection -EndGlobal |
