summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDavid Lönnhager <david.l@mullvad.net>2020-10-14 15:24:18 +0200
committerDavid Lönnhager <david.l@mullvad.net>2020-10-22 09:33:58 +0200
commite7890e727d7075ec7a41b02147e74e12bbf3f966 (patch)
tree1613b71cb7ff8448491ca0b6cc144c5682bce275
parent846e1c35246b8e72cfadfb95e3b80bbafe03bac4 (diff)
downloadmullvadvpn-e7890e727d7075ec7a41b02147e74e12bbf3f966.tar.xz
mullvadvpn-e7890e727d7075ec7a41b02147e74e12bbf3f966.zip
Specify DNS servers in WinFw
-rw-r--r--talpid-core/src/firewall/windows.rs18
-rw-r--r--windows/winfw/src/winfw/fwcontext.cpp19
-rw-r--r--windows/winfw/src/winfw/fwcontext.h3
-rw-r--r--windows/winfw/src/winfw/winfw.cpp74
-rw-r--r--windows/winfw/src/winfw/winfw.h13
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
);
//