diff options
| author | David Lönnhager <david.l@mullvad.net> | 2020-10-14 15:24:18 +0200 |
|---|---|---|
| committer | David Lönnhager <david.l@mullvad.net> | 2020-10-22 09:33:58 +0200 |
| commit | e7890e727d7075ec7a41b02147e74e12bbf3f966 (patch) | |
| tree | 1613b71cb7ff8448491ca0b6cc144c5682bce275 | |
| parent | 846e1c35246b8e72cfadfb95e3b80bbafe03bac4 (diff) | |
| download | mullvadvpn-e7890e727d7075ec7a41b02147e74e12bbf3f966.tar.xz mullvadvpn-e7890e727d7075ec7a41b02147e74e12bbf3f966.zip | |
Specify DNS servers in WinFw
| -rw-r--r-- | talpid-core/src/firewall/windows.rs | 18 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/fwcontext.cpp | 19 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/fwcontext.h | 3 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/winfw.cpp | 74 | ||||
| -rw-r--r-- | windows/winfw/src/winfw/winfw.h | 13 |
5 files changed, 108 insertions, 19 deletions
diff --git a/talpid-core/src/firewall/windows.rs b/talpid-core/src/firewall/windows.rs index 70af82942e..90f1d73c78 100644 --- a/talpid-core/src/firewall/windows.rs +++ b/talpid-core/src/firewall/windows.rs @@ -1,6 +1,6 @@ use crate::logging::windows::log_sink; -use std::{net::IpAddr, path::Path, ptr}; +use std::{ffi::OsString, iter, net::IpAddr, path::Path, ptr}; use self::winfw::*; use super::{FirewallArguments, FirewallPolicy, FirewallT}; @@ -230,6 +230,18 @@ impl Firewall { let mut relay_client: Vec<u16> = relay_client.as_os_str().encode_wide().collect(); relay_client.push(0u16); + let dns_servers: Vec<Vec<u16>> = dns_servers + .iter() + .map(|ip| { + OsString::from(ip.to_string()) + .as_os_str() + .encode_wide() + .chain(iter::once(0u16)) + .collect() + }) + .collect(); + let dns_servers: Vec<*const u16> = dns_servers.iter().map(|ip| ip.as_ptr()).collect(); + unsafe { WinFw_ApplyPolicyConnected( winfw_settings, @@ -238,6 +250,8 @@ impl Firewall { tunnel_alias.as_ptr(), v4_gateway.as_ptr(), v6_gateway_ptr, + dns_servers.as_ptr(), + dns_servers.len(), ) .into_result() .map_err(Error::ApplyingConnectedPolicy) @@ -394,6 +408,8 @@ mod winfw { tunnelIfaceAlias: *const libc::wchar_t, v4Gateway: *const libc::wchar_t, v6Gateway: *const libc::wchar_t, + dnsServers: *const *const libc::wchar_t, + numDnsServers: usize, ) -> WinFwPolicyStatus; #[link_name = "WinFw_ApplyPolicyBlocked"] diff --git a/windows/winfw/src/winfw/fwcontext.cpp b/windows/winfw/src/winfw/fwcontext.cpp index 65b5762500..b8959cfc01 100644 --- a/windows/winfw/src/winfw/fwcontext.cpp +++ b/windows/winfw/src/winfw/fwcontext.cpp @@ -17,6 +17,7 @@ #include "rules/baseline/permitdns.h" #include "rules/dns/blockall.h" #include "rules/dns/permittunnel.h" +#include "rules/dns/permitnontunnel.h" #include "rules/multi/permitvpnrelay.h" #include <libwfp/transaction.h> #include <libwfp/filterengine.h> @@ -210,7 +211,8 @@ bool FwContext::applyPolicyConnected const WinFwRelay &relay, const std::wstring &relayClient, const std::wstring &tunnelInterfaceAlias, - const std::vector<wfp::IpAddress> &tunnelDnsServers + const std::vector<wfp::IpAddress> &tunnelDnsServers, + const std::vector<wfp::IpAddress> &nonTunnelDnsServers ) { Ruleset ruleset; @@ -219,9 +221,18 @@ bool FwContext::applyPolicyConnected AppendSettingsRules(ruleset, settings); AppendRelayRules(ruleset, relay, relayClient); - ruleset.emplace_back(std::make_unique<dns::PermitTunnel>( - tunnelInterfaceAlias, tunnelDnsServers - )); + if (!tunnelDnsServers.empty()) + { + ruleset.emplace_back(std::make_unique<dns::PermitTunnel>( + tunnelInterfaceAlias, tunnelDnsServers + )); + } + if (!nonTunnelDnsServers.empty()) + { + ruleset.emplace_back(std::make_unique<dns::PermitNonTunnel>( + tunnelInterfaceAlias, nonTunnelDnsServers + )); + } ruleset.emplace_back(std::make_unique<baseline::PermitVpnTunnel>( tunnelInterfaceAlias diff --git a/windows/winfw/src/winfw/fwcontext.h b/windows/winfw/src/winfw/fwcontext.h index e342f52fe5..100672073a 100644 --- a/windows/winfw/src/winfw/fwcontext.h +++ b/windows/winfw/src/winfw/fwcontext.h @@ -43,7 +43,8 @@ public: const WinFwRelay &relay, const std::wstring &relayClient, const std::wstring &tunnelInterfaceAlias, - const std::vector<wfp::IpAddress> &tunnelDnsServers + const std::vector<wfp::IpAddress> &tunnelDnsServers, + const std::vector<wfp::IpAddress> &nonTunnelDnsServers ); bool applyPolicyBlocked(const WinFwSettings &settings); diff --git a/windows/winfw/src/winfw/winfw.cpp b/windows/winfw/src/winfw/winfw.cpp index 4998feef7f..705ee689c8 100644 --- a/windows/winfw/src/winfw/winfw.cpp +++ b/windows/winfw/src/winfw/winfw.cpp @@ -4,6 +4,7 @@ #include "objectpurger.h" #include "mullvadobjects.h" #include "rules/persistent/blockall.h" +#include "libwfp/ipnetwork.h" #include <windows.h> #include <libcommon/error.h> #include <optional> @@ -63,6 +64,23 @@ HandlePolicyException(const common::error::WindowsException &err) return WINFW_POLICY_STATUS_GENERAL_FAILURE; } +// +// Networks for which DNS requests can be made on all network adapters. +// +// This should be synchronized with `ALLOWED_LAN_NETS` in talpid-core, +// but it also includes loopback addresses. +// +wfp::IpNetwork g_privateIpRanges[] = { + wfp::IpNetwork(wfp::IpAddress::Literal{127, 0, 0, 0}, 8), + wfp::IpNetwork(wfp::IpAddress::Literal{10, 0, 0, 0}, 8), + wfp::IpNetwork(wfp::IpAddress::Literal{176, 16, 0, 0}, 12), + wfp::IpNetwork(wfp::IpAddress::Literal{192, 168, 0, 0}, 16), + wfp::IpNetwork(wfp::IpAddress::Literal{169, 254, 0, 0}, 16), + wfp::IpNetwork(wfp::IpAddress::Literal6{0, 0, 0, 0, 0, 0, 0, 1}, 128), + wfp::IpNetwork(wfp::IpAddress::Literal6{0xfe80, 0, 0, 0, 0, 0, 0, 0}, 10), + wfp::IpNetwork(wfp::IpAddress::Literal6{0xfc80, 0, 0, 0, 0, 0, 0, 0}, 7) +}; + } // anonymous namespace WINFW_LINKAGE @@ -289,8 +307,10 @@ WinFw_ApplyPolicyConnected( const WinFwRelay *relay, const wchar_t *relayClient, const wchar_t *tunnelInterfaceAlias, - const wchar_t *v4DnsHost, - const wchar_t *v6DnsHost + const wchar_t *v4Gateway, + const wchar_t *v6Gateway, + const wchar_t **dnsServers, + size_t numDnsServers ) { if (nullptr == g_fwContext) @@ -320,16 +340,53 @@ WinFw_ApplyPolicyConnected( THROW_ERROR("Invalid argument: tunnelInterfaceAlias"); } - if (nullptr == v4DnsHost) + if (nullptr == v4Gateway) + { + THROW_ERROR("Invalid argument: v4Gateway"); + } + + if (nullptr == dnsServers || 0 == numDnsServers) { - THROW_ERROR("Invalid argument: v4DnsHost"); + THROW_ERROR("Invalid argument: dnsServers"); } - std::vector<wfp::IpAddress> tunnelDnsServers = { wfp::IpAddress(v4DnsHost) }; + std::vector<wfp::IpAddress> tunnelDnsServers; + std::vector<wfp::IpAddress> nonTunnelDnsServers; + + const auto v4GatewayIp = wfp::IpAddress(v4Gateway); + const auto v6GatewayIp = (nullptr != v6Gateway) + ? std::make_optional(wfp::IpAddress(v6Gateway)) + : std::nullopt; + + const auto addToDnsCollection = [&](const std::optional<wfp::IpAddress> &gatewayIp, wfp::IpAddress &&ip) + { + if (gatewayIp.has_value() && *gatewayIp == ip) + { + // Requests to the gateway IP of the tunnel are only allowed on the tunnel interface. + tunnelDnsServers.emplace_back(ip); + return; + } + + for (const auto &network : g_privateIpRanges) + { + if (network.includes(ip)) + { + // + // Resolvers on the LAN must be accessible outside the tunnel. + // + + nonTunnelDnsServers.emplace_back(ip); + return; + } + } + + tunnelDnsServers.emplace_back(ip); + }; - if (nullptr != v6DnsHost) + for (size_t i = 0; i < numDnsServers; i++) { - tunnelDnsServers.emplace_back(wfp::IpAddress(v6DnsHost)); + auto ip = wfp::IpAddress(dnsServers[i]); + addToDnsCollection(ip.type() == wfp::IpAddress::Type::Ipv4 ? v4GatewayIp : v6GatewayIp, std::move(ip)); } return g_fwContext->applyPolicyConnected( @@ -337,7 +394,8 @@ WinFw_ApplyPolicyConnected( *relay, relayClient, tunnelInterfaceAlias, - tunnelDnsServers + tunnelDnsServers, + nonTunnelDnsServers ) ? WINFW_POLICY_STATUS_SUCCESS : WINFW_POLICY_STATUS_GENERAL_FAILURE; } catch (common::error::WindowsException &err) diff --git a/windows/winfw/src/winfw/winfw.h b/windows/winfw/src/winfw/winfw.h index b3f95a2cbf..f0a487cb12 100644 --- a/windows/winfw/src/winfw/winfw.h +++ b/windows/winfw/src/winfw/winfw.h @@ -167,14 +167,15 @@ WinFw_ApplyPolicyConnecting( // - What is specified by settings // - Communication with the relay server // - Non-DNS traffic inside the VPN tunnel -// - DNS requests inside the VPN tunnel, to the specified DNS server +// - DNS requests inside the VPN tunnel to any specified remote DNS server +// - DNS requests outside the VPN tunnel to any specified local DNS servers // // Parameters: // // tunnelInterfaceAlias: // Friendly name of VPN tunnel interface -// v4DnsHost/v6DnsHost: -// String encoded IP address of DNS to use inside tunnel +// dnsServers: +// Array of string-encoded IP addresses of DNS servers to use // extern "C" WINFW_LINKAGE @@ -185,8 +186,10 @@ WinFw_ApplyPolicyConnected( const WinFwRelay *relay, const wchar_t *relayClient, const wchar_t *tunnelInterfaceAlias, - const wchar_t *v4DnsHost, - const wchar_t *v6DnsHost + const wchar_t *v4Gateway, + const wchar_t *v6Gateway, + const wchar_t **dnsServers, + size_t numDnsServers ); // |
