It seems that Thunderbird scrabbled the patch. Here is the attachment.

On 28.10.2015 10:47, ValdikSS wrote:
> This option is silently ignored on non-Windows platforms and works on Vista+.
> External DNS is blocked even if no DNS server configured (user may configure 
> it in the tap interface itself).
> This option could be ignored from server push using route-nopull.
>
> v2:
> * Add missing libs to MSVC project file.
> * Add ifndef for FWPM_SESSION_FLAG_DYNAMIC to silence warning in MSVC.
> * Use const WCHAR for firewall name.
> * Block all traffic to TCP/UDP port 53 except for OpenVPN itself. Blocking 
> only svchost.exe is not reliable as user could disable dnscache service 
> making all applications resolve DNS from their processes.
> ---
>  doc/openvpn.8               |  11 ++-
>  src/openvpn/Makefile.am     |   2 +-
>  src/openvpn/init.c          |  24 +++++++
>  src/openvpn/openvpn.vcxproj |   4 +-
>  src/openvpn/options.c       |  14 ++++
>  src/openvpn/options.h       |   1 +
>  src/openvpn/win32.c         | 172 
> ++++++++++++++++++++++++++++++++++++++++++++
>  src/openvpn/win32.h         |  64 +++++++++++++++++
>  8 files changed, 287 insertions(+), 5 deletions(-)
>  mode change 100755 => 100644 src/openvpn/openvpn.vcxproj
>
> diff --git a/doc/openvpn.8 b/doc/openvpn.8
> index b6d5aed..136473e 100644
> --- a/doc/openvpn.8
> +++ b/doc/openvpn.8
> @@ -1129,8 +1129,8 @@ When used with
>  .B \-\-client
>  or
>  .B \-\-pull,
> -accept options pushed by server EXCEPT for routes and dhcp options
> -like DNS servers.
> +accept options pushed by server EXCEPT for routes, block-outside-dns and dhcp
> +options like DNS servers.
>   When used on the client, this option effectively bars the
>  server from adding routes to the client's routing table,
> @@ -5517,6 +5517,13 @@ adapter list to the syslog or log file after the 
> TUN/TAP adapter
>  has been brought up and any routes have been added.
>  .\"*********************************************************
>  .TP
> +.B \-\-block\-outside\-dns
> +Block external DNS servers on other network adapters to prevent
> +DNS leaks. This option prevents any application from accessing
> +TCP or UDP port 53 except one inside the tunnel. It uses WFP and
> +works on Windows Vista and later.
> +.\"*********************************************************
> +.TP
>  .B \-\-dhcp\-renew
>  Ask Windows to renew the TAP adapter lease on startup.
>  This option is normally unnecessary, as Windows automatically
> diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
> index c840f16..c55a520 100644
> --- a/src/openvpn/Makefile.am
> +++ b/src/openvpn/Makefile.am
> @@ -127,5 +127,5 @@ openvpn_LDADD = \
>       $(OPTIONAL_DL_LIBS)
>  if WIN32
>  openvpn_SOURCES += openvpn_win32_resources.rc
> -openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm
> +openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm 
> -lfwpuclnt -lrpcrt4
>  endif
> diff --git a/src/openvpn/init.c b/src/openvpn/init.c
> index c5c0ab6..b1c23fd 100644
> --- a/src/openvpn/init.c
> +++ b/src/openvpn/init.c
> @@ -1468,6 +1468,22 @@ do_open_tun (struct context *c)
>                  "up",
>                  c->c2.es);
>  +#if _WIN32_WINNT >= 0x0600
> +      if (c->options.block_outside_dns)
> +      {
> +          if (!win_wfp_init())
> +            msg (M_NONFATAL, "Initialising WFP failed!");
> +            else
> +            {
> +                dmsg (D_LOW, "Blocking outside DNS");
> +                if (!win_wfp_block_dns(c->c1.tuntap->adapter_index))
> +                    msg (M_NONFATAL, "Blocking DNS failed!");
> +            }
> +      }
> +      else
> +           msg (M_NONFATAL, "Can't block outside DNS without configured DNS 
> server");
> +#endif
> +
>        /* possibly add routes */
>        if ((route_order() == ROUTE_AFTER_TUN) && 
> (!c->options.route_delay_defined))
>       do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
> @@ -1596,6 +1612,14 @@ do_close_tun (struct context *c, bool force)
>                      "down",
>                      c->c2.es);
>  +#if _WIN32_WINNT >= 0x0600
> +            if (c->options.block_outside_dns)
> +            {
> +                if (!win_wfp_uninit())
> +                    msg (M_NONFATAL, "Uninitialising WFP failed!");
> +            }
> +#endif
> +
>         /* actually close tun/tap device based on --down-pre flag */
>         if (c->options.down_pre)
>           do_close_tun_simple (c);
> diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj
> old mode 100755
> new mode 100644
> index b117b0b..821c46c
> --- a/src/openvpn/openvpn.vcxproj
> +++ b/src/openvpn/openvpn.vcxproj
> @@ -64,7 +64,7 @@
>        
> <AdditionalIncludeDirectories>$(SOURCEBASE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
>      </ResourceCompile>
>      <Link>
> -      
> <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
> +      
> <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
>        
> <AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
>        <GenerateDebugInformation>true</GenerateDebugInformation>
>        <SubSystem>Console</SubSystem>
> @@ -89,7 +89,7 @@
>        
> <AdditionalIncludeDirectories>$(SOURCEBASE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
>      </ResourceCompile>
>      <Link>
> -      
> <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
> +      
> <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
>        
> <AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
>        <GenerateDebugInformation>true</GenerateDebugInformation>
>        <SubSystem>Console</SubSystem>
> diff --git a/src/openvpn/options.c b/src/openvpn/options.c
> index 2f8915d..a7f50cc 100644
> --- a/src/openvpn/options.c
> +++ b/src/openvpn/options.c
> @@ -696,6 +696,9 @@ static const char usage_message[] =
>    "                       optional parameter controls the initial state of 
> ex.\n"
>    "--show-net-up   : Show " PACKAGE_NAME "'s view of routing table and net 
> adapter list\n"
>    "                  after TAP adapter is up and routes have been added.\n"
> +#if _WIN32_WINNT >= 0x0600
> +  "--block-outside-dns   : Block DNS on other network adapters to prevent 
> DNS leaks\n"
> +#endif
>    "Windows Standalone Options:\n"
>    "\n"
>    "--show-adapters : Show all TAP-Windows adapters.\n"
> @@ -797,6 +800,7 @@ init_options (struct options *o, const bool init_gc)
>    o->tuntap_options.dhcp_lease_time = 31536000; /* one year */
>    o->tuntap_options.dhcp_masq_offset = 0;       /* use network address as 
> internal DHCP server address */
>    o->route_method = ROUTE_METHOD_ADAPTIVE;
> +  o->block_outside_dns = false;
>  #endif
>  #if P2MP_SERVER
>    o->real_hash_size = 256;
> @@ -1651,6 +1655,9 @@ show_settings (const struct options *o)
>  #ifdef WIN32
>    SHOW_BOOL (show_net_up);
>    SHOW_INT (route_method);
> +#if _WIN32_WINNT >= 0x0600
> +  SHOW_BOOL (block_outside_dns);
> +#endif
>    show_tuntap_options (&o->tuntap_options);
>  #endif
>  #endif
> @@ -6222,6 +6229,13 @@ add_option (struct options *options,
>        VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
>      }
>  #endif
> +  else if (streq (p[0], "block-outside-dns") && !p[1])
> +    {
> +      VERIFY_PERMISSION (OPT_P_IPWIN32);
> +#if _WIN32_WINNT >= 0x0600
> +      options->block_outside_dns = true;
> +#endif
> +    }
>  #if PASSTOS_CAPABILITY
>    else if (streq (p[0], "passtos") && !p[1])
>      {
> diff --git a/src/openvpn/options.h b/src/openvpn/options.h
> index c642aa0..873c159 100644
> --- a/src/openvpn/options.h
> +++ b/src/openvpn/options.h
> @@ -587,6 +587,7 @@ struct options
>    bool exit_event_initial_state;
>    bool show_net_up;
>    int route_method;
> +  bool block_outside_dns;
>  #endif
>     bool use_peer_id;
> diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c
> index 7c89a5a..4c44901 100644
> --- a/src/openvpn/win32.c
> +++ b/src/openvpn/win32.c
> @@ -37,6 +37,10 @@
>   #ifdef WIN32
>  +#include <fwpmu.h>
> +#include <fwpmtypes.h>
> +#include <iphlpapi.h>
> +
>  #include "buffer.h"
>  #include "error.h"
>  #include "mtu.h"
> @@ -57,6 +61,17 @@ static struct WSAData wsa_state; /* GLOBAL */
>  static bool pause_exit_enabled = false; /* GLOBAL */
>   /*
> + * WFP firewall name.
> + */
> +const WCHAR * FIREWALL_NAME = L"OpenVPN"; /* GLOBAL */
> +
> +/*
> + * WFP handle and GUID.
> + */
> +static HANDLE m_hEngineHandle = NULL; /* GLOBAL */
> +static GUID m_subLayerGUID; /* GLOBAL */
> +
> +/*
>   * win32_signal is used to get input from the keyboard
>   * if we are running in a console, or get input from an
>   * event object if we are running as a service.
> @@ -1019,4 +1034,161 @@ win_get_tempdir()
>    WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof (tmpdir), 
> NULL, NULL);
>    return tmpdir;
>  }
> +
> +#if _WIN32_WINNT >= 0x0600
> +bool
> +win_wfp_init()
> +{
> +    ZeroMemory(&m_subLayerGUID, sizeof(GUID));
> +    DWORD dwFwAPiRetCode = ERROR_BAD_COMMAND;
> +    FWPM_SESSION0 session = {0};
> +    RPC_STATUS rpcStatus = {0};
> +    FWPM_SUBLAYER0 SubLayer = {0};
> +
> +    /* Add temporary filters which don't survive reboots or crashes. */
> +    session.flags = FWPM_SESSION_FLAG_DYNAMIC;
> +
> +    dmsg (D_LOW, "Opening WFP engine");
> +    dwFwAPiRetCode = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, 
> &session, &m_hEngineHandle);
> +
> +    if (dwFwAPiRetCode != ERROR_SUCCESS)
> +    {
> +        msg (M_NONFATAL, "Can't open WFP engine");
> +        return false;
> +    }
> +
> +    rpcStatus = UuidCreate(&SubLayer.subLayerKey);
> +    if (rpcStatus != NO_ERROR)
> +        return false;
> +    CopyMemory(&m_subLayerGUID, &SubLayer.subLayerKey, 
> sizeof(SubLayer.subLayerKey));
> +
> +    /* Populate packet filter layer information. */
> +    SubLayer.displayData.name = FIREWALL_NAME;
> +    SubLayer.displayData.description = FIREWALL_NAME;
> +    SubLayer.flags = 0;
> +    SubLayer.weight = 0x100;
> +
> +    /* Add packet filter to our interface. */
> +    dmsg (D_LOW, "Adding WFP sublayer");
> +    dwFwAPiRetCode = FwpmSubLayerAdd0(m_hEngineHandle, &SubLayer, NULL);
> +    if (dwFwAPiRetCode != ERROR_SUCCESS)
> +    {
> +        msg (M_NONFATAL, "Can't add WFP sublayer");
> +        return false;
> +    }
> +    return true;
> +}
> +
> +bool
> +win_wfp_uninit()
> +{
> +    dmsg (D_LOW, "Uninitializing WFP");
> +    DWORD dwFwAPiRetCode = ERROR_BAD_COMMAND;
> +    if (m_hEngineHandle) {
> +        FwpmSubLayerDeleteByKey0(m_hEngineHandle, &m_subLayerGUID);
> +        ZeroMemory(&m_subLayerGUID, sizeof(GUID));
> +        FwpmEngineClose0(m_hEngineHandle);
> +        m_hEngineHandle = NULL;
> +    }
> +    return true;
> +}
> +
> +bool
> +win_wfp_add_filter (HANDLE engineHandle,
> +                    const FWPM_FILTER0 *filter,
> +                    PSECURITY_DESCRIPTOR sd,
> +                    UINT64 *id)
> +{
> +    if (FwpmFilterAdd0(engineHandle, filter, sd, id) != ERROR_SUCCESS)
> +    {
> +        msg (M_NONFATAL, "Can't add WFP filter");
> +        return false;
> +    }
> +    return true;
> +}
> +
> +bool
> +win_wfp_block_dns (const NET_IFINDEX index)
> +{
> +    dmsg (D_LOW, "Blocking DNS using WFP");
> +    NET_LUID tapluid;
> +    NETIO_STATUS ret;
> +    DWORD dwFwAPiRetCode = ERROR_BAD_COMMAND;
> +    UINT64 filterid;
> +    WCHAR openvpnpath[MAX_PATH];
> +    FWP_BYTE_BLOB *openvpnblob = NULL;
> +
> +    FWPM_FILTER0 Filter = {0};
> +    FWPM_FILTER_CONDITION0 Condition[2] = {0};
> +
> +    ret = ConvertInterfaceIndexToLuid(index, &tapluid);
> +    if (ret == NO_ERROR)
> +        dmsg (D_LOW, "Tap Luid: %I64d", tapluid.Value);
> +
> +    /* Get OpenVPN path. */
> +    GetModuleFileNameW(NULL, openvpnpath, MAX_PATH);
> +
> +    if (FwpmGetAppIdFromFileName0(openvpnpath, &openvpnblob) != 
> ERROR_SUCCESS)
> +        return false;
> +
> +    /* Prepare filter. */
> +    Filter.subLayerKey = m_subLayerGUID;
> +    Filter.displayData.name = FIREWALL_NAME;
> +    Filter.weight.type = FWP_EMPTY;
> +    Filter.filterCondition = Condition;
> +    Filter.numFilterConditions = 2;
> +
> +    /* First filter. Block IPv4 DNS queries except from OpenVPN itself. */
> +    Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
> +    Filter.action.type = FWP_ACTION_BLOCK;
> +
> +    Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
> +    Condition[0].matchType = FWP_MATCH_EQUAL;
> +    Condition[0].conditionValue.type = FWP_UINT16;
> +    Condition[0].conditionValue.uint16 = 53;
> +
> +    Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID;
> +    Condition[1].matchType = FWP_MATCH_NOT_EQUAL;
> +    Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE;
> +    Condition[1].conditionValue.byteBlob = openvpnblob;
> +
> +    /* Add filter condition to our interface. */
> +    if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
> +        return false;
> +    dmsg (D_LOW, "Filter (Block IPv4 DNS) added with ID=%I64d", filterid);
> +
> +    /* Second filter. Block IPv6 DNS queries except from OpenVPN itself. */
> +    Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
> +
> +    /* Add filter condition to our interface. */
> +    if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
> +        return false;
> +    dmsg (D_LOW, "Filter (Block IPv6 DNS) added with ID=%I64d", filterid);
> +
> +    /* Third filter. Permit IPv4 DNS queries from TAP. */
> +    Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
> +    Filter.action.type = FWP_ACTION_PERMIT;
> +
> +    Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE;
> +    Condition[1].matchType = FWP_MATCH_EQUAL;
> +    Condition[1].conditionValue.type = FWP_UINT64;
> +    Condition[1].conditionValue.uint64 = &tapluid.Value;
> +
> +    /* Add filter condition to our interface. */
> +    if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
> +        return false;
> +    dmsg (D_LOW, "Filter (Permit IPv4 DNS queries from TAP) added with 
> ID=%I64d", filterid);
> +
> +    /* Forth filter. Permit IPv6 DNS queries from TAP. */
> +    Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
> +
> +    /* Add filter condition to our interface. */
> +    if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
> +        return false;
> +    dmsg (D_LOW, "Filter (Permit IPv6 DNS queries from TAP) added with 
> ID=%I64d", filterid);
> +
> +    return true;
> +}
> +
> +#endif
>  #endif
> diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h
> index cc18f02..d26b247 100644
> --- a/src/openvpn/win32.h
> +++ b/src/openvpn/win32.h
> @@ -27,6 +27,10 @@
>  #define OPENVPN_WIN32_H
>   #include "mtu.h"
> +#if _WIN32_WINNT >= 0x0600
> +#include <initguid.h>
> +#include <fwpmtypes.h>
> +#endif
>   /* location of executables */
>  #define SYS_PATH_ENV_VAR_NAME "SystemRoot"  /* environmental variable name 
> that normally contains the system path */
> @@ -271,5 +275,65 @@ const char *win_get_tempdir();
>  /* Convert a string from UTF-8 to UCS-2 */
>  WCHAR *wide_string (const char* utf8, struct gc_arena *gc);
>  +#if _WIN32_WINNT >= 0x0600
> +bool win_wfp_block_dns(const NET_IFINDEX index);
> +bool win_wfp_add_filter (HANDLE engineHandle,
> +                        const FWPM_FILTER0 *filter,
> +                        PSECURITY_DESCRIPTOR sd,
> +                        UINT64 *id);
> +bool win_wfp_uninit();
> +bool win_wfp_init();
> +
> +/* WFP-related define and GUIDs */
> +#ifndef FWPM_SESSION_FLAG_DYNAMIC
> +#define FWPM_SESSION_FLAG_DYNAMIC 0x00000001
> +#endif
> +
> +// c38d57d1-05a7-4c33-904f-7fbceee60e82
> +DEFINE_GUID(
> +   FWPM_LAYER_ALE_AUTH_CONNECT_V4,
> +   0xc38d57d1,
> +   0x05a7,
> +   0x4c33,
> +   0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82
> +);
> +
> +// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4
> +DEFINE_GUID(
> +   FWPM_LAYER_ALE_AUTH_CONNECT_V6,
> +   0x4a72393b,
> +   0x319f,
> +   0x44bc,
> +   0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4
> +);
> +
> +// d78e1e87-8644-4ea5-9437-d809ecefc971
> +DEFINE_GUID(
> +   FWPM_CONDITION_ALE_APP_ID,
> +   0xd78e1e87,
> +   0x8644,
> +   0x4ea5,
> +   0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71
> +);
> +
> +// c35a604d-d22b-4e1a-91b4-68f674ee674b
> +DEFINE_GUID(
> +   FWPM_CONDITION_IP_REMOTE_PORT,
> +   0xc35a604d,
> +   0xd22b,
> +   0x4e1a,
> +   0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b
> +);
> +
> +// 4cd62a49-59c3-4969-b7f3-bda5d32890a4
> +DEFINE_GUID(
> +   FWPM_CONDITION_IP_LOCAL_INTERFACE,
> +   0x4cd62a49,
> +   0x59c3,
> +   0x4969,
> +   0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4
> +);
> +
> +#endif
>  #endif
>  #endif

From 29891bb13c4a60743de2b002a474a51f3a8ad3b0 Mon Sep 17 00:00:00 2001
In-Reply-To: <562eb0a1.8010...@valdikss.org.ru>
References: <562eb0a1.8010...@valdikss.org.ru>
From: ValdikSS <i...@valdikss.org.ru>
List-Post: openvpn-devel@lists.sourceforge.net
Date: Tue, 27 Oct 2015 20:20:29 +0300
Subject: [PATCH v2] Add Windows DNS Leak fix using WFP ('block-outside-dns')

This option is silently ignored on non-Windows platforms and works on Vista+.
External DNS is blocked even if no DNS server configured (user may configure it in the tap interface itself).
This option could be ignored from server push using route-nopull.

v2:
* Add missing libs to MSVC project file.
* Add ifndef for FWPM_SESSION_FLAG_DYNAMIC to silence warning in MSVC.
* Use const WCHAR for firewall name.
* Block all traffic to TCP/UDP port 53 except for OpenVPN itself. Blocking only svchost.exe is not reliable as user could disable dnscache service making all applications resolve DNS from their processes.
---
 doc/openvpn.8               |  11 ++-
 src/openvpn/Makefile.am     |   2 +-
 src/openvpn/init.c          |  24 +++++++
 src/openvpn/openvpn.vcxproj |   4 +-
 src/openvpn/options.c       |  14 ++++
 src/openvpn/options.h       |   1 +
 src/openvpn/win32.c         | 172 ++++++++++++++++++++++++++++++++++++++++++++
 src/openvpn/win32.h         |  64 +++++++++++++++++
 8 files changed, 287 insertions(+), 5 deletions(-)
 mode change 100755 => 100644 src/openvpn/openvpn.vcxproj

diff --git a/doc/openvpn.8 b/doc/openvpn.8
index b6d5aed..136473e 100644
--- a/doc/openvpn.8
+++ b/doc/openvpn.8
@@ -1129,8 +1129,8 @@ When used with
 .B \-\-client
 or
 .B \-\-pull,
-accept options pushed by server EXCEPT for routes and dhcp options
-like DNS servers.
+accept options pushed by server EXCEPT for routes, block-outside-dns and dhcp
+options like DNS servers.
 
 When used on the client, this option effectively bars the
 server from adding routes to the client's routing table,
@@ -5517,6 +5517,13 @@ adapter list to the syslog or log file after the TUN/TAP adapter
 has been brought up and any routes have been added.
 .\"*********************************************************
 .TP
+.B \-\-block\-outside\-dns
+Block external DNS servers on other network adapters to prevent
+DNS leaks. This option prevents any application from accessing
+TCP or UDP port 53 except one inside the tunnel. It uses WFP and
+works on Windows Vista and later.
+.\"*********************************************************
+.TP
 .B \-\-dhcp\-renew
 Ask Windows to renew the TAP adapter lease on startup.
 This option is normally unnecessary, as Windows automatically
diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
index c840f16..c55a520 100644
--- a/src/openvpn/Makefile.am
+++ b/src/openvpn/Makefile.am
@@ -127,5 +127,5 @@ openvpn_LDADD = \
 	$(OPTIONAL_DL_LIBS)
 if WIN32
 openvpn_SOURCES += openvpn_win32_resources.rc
-openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm
+openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4
 endif
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index c5c0ab6..b1c23fd 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -1468,6 +1468,22 @@ do_open_tun (struct context *c)
 		   "up",
 		   c->c2.es);
 
+#if _WIN32_WINNT >= 0x0600
+      if (c->options.block_outside_dns)
+      {
+          if (!win_wfp_init())
+            msg (M_NONFATAL, "Initialising WFP failed!");
+            else
+            {
+                dmsg (D_LOW, "Blocking outside DNS");
+                if (!win_wfp_block_dns(c->c1.tuntap->adapter_index))
+                    msg (M_NONFATAL, "Blocking DNS failed!");
+            }
+      }
+      else
+           msg (M_NONFATAL, "Can't block outside DNS without configured DNS server");
+#endif
+
       /* possibly add routes */
       if ((route_order() == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined))
 	do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
@@ -1596,6 +1612,14 @@ do_close_tun (struct context *c, bool force)
 		       "down",
 		       c->c2.es);
 
+#if _WIN32_WINNT >= 0x0600
+            if (c->options.block_outside_dns)
+            {
+                if (!win_wfp_uninit())
+                    msg (M_NONFATAL, "Uninitialising WFP failed!");
+            }
+#endif
+
 	  /* actually close tun/tap device based on --down-pre flag */
 	  if (c->options.down_pre)
 	    do_close_tun_simple (c);
diff --git a/src/openvpn/openvpn.vcxproj b/src/openvpn/openvpn.vcxproj
old mode 100755
new mode 100644
index b117b0b..821c46c
--- a/src/openvpn/openvpn.vcxproj
+++ b/src/openvpn/openvpn.vcxproj
@@ -64,7 +64,7 @@
       <AdditionalIncludeDirectories>$(SOURCEBASE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ResourceCompile>
     <Link>
-      <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Console</SubSystem>
@@ -89,7 +89,7 @@
       <AdditionalIncludeDirectories>$(SOURCEBASE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
     </ResourceCompile>
     <Link>
-      <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      <AdditionalDependencies>libeay32.lib;ssleay32.lib;lzo2.lib;pkcs11-helper.dll.lib;gdi32.lib;ws2_32.lib;wininet.lib;crypt32.lib;iphlpapi.lib;winmm.lib;Fwpuclnt.lib;Rpcrt4.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
       <GenerateDebugInformation>true</GenerateDebugInformation>
       <SubSystem>Console</SubSystem>
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 2f8915d..a7f50cc 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -696,6 +696,9 @@ static const char usage_message[] =
   "                       optional parameter controls the initial state of ex.\n"
   "--show-net-up   : Show " PACKAGE_NAME "'s view of routing table and net adapter list\n"
   "                  after TAP adapter is up and routes have been added.\n"
+#if _WIN32_WINNT >= 0x0600
+  "--block-outside-dns   : Block DNS on other network adapters to prevent DNS leaks\n"
+#endif
   "Windows Standalone Options:\n"
   "\n"
   "--show-adapters : Show all TAP-Windows adapters.\n"
@@ -797,6 +800,7 @@ init_options (struct options *o, const bool init_gc)
   o->tuntap_options.dhcp_lease_time = 31536000; /* one year */
   o->tuntap_options.dhcp_masq_offset = 0;       /* use network address as internal DHCP server address */
   o->route_method = ROUTE_METHOD_ADAPTIVE;
+  o->block_outside_dns = false;
 #endif
 #if P2MP_SERVER
   o->real_hash_size = 256;
@@ -1651,6 +1655,9 @@ show_settings (const struct options *o)
 #ifdef WIN32
   SHOW_BOOL (show_net_up);
   SHOW_INT (route_method);
+#if _WIN32_WINNT >= 0x0600
+  SHOW_BOOL (block_outside_dns);
+#endif
   show_tuntap_options (&o->tuntap_options);
 #endif
 #endif
@@ -6222,6 +6229,13 @@ add_option (struct options *options,
       VERIFY_PERMISSION (OPT_P_ROUTE_EXTRAS);
     }
 #endif
+  else if (streq (p[0], "block-outside-dns") && !p[1])
+    {
+      VERIFY_PERMISSION (OPT_P_IPWIN32);
+#if _WIN32_WINNT >= 0x0600
+      options->block_outside_dns = true;
+#endif
+    }
 #if PASSTOS_CAPABILITY
   else if (streq (p[0], "passtos") && !p[1])
     {
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index c642aa0..873c159 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -587,6 +587,7 @@ struct options
   bool exit_event_initial_state;
   bool show_net_up;
   int route_method;
+  bool block_outside_dns;
 #endif
 
   bool use_peer_id;
diff --git a/src/openvpn/win32.c b/src/openvpn/win32.c
index 7c89a5a..4c44901 100644
--- a/src/openvpn/win32.c
+++ b/src/openvpn/win32.c
@@ -37,6 +37,10 @@
 
 #ifdef WIN32
 
+#include <fwpmu.h>
+#include <fwpmtypes.h>
+#include <iphlpapi.h>
+
 #include "buffer.h"
 #include "error.h"
 #include "mtu.h"
@@ -57,6 +61,17 @@ static struct WSAData wsa_state; /* GLOBAL */
 static bool pause_exit_enabled = false; /* GLOBAL */
 
 /*
+ * WFP firewall name.
+ */
+const WCHAR * FIREWALL_NAME = L"OpenVPN"; /* GLOBAL */
+
+/*
+ * WFP handle and GUID.
+ */
+static HANDLE m_hEngineHandle = NULL; /* GLOBAL */
+static GUID m_subLayerGUID; /* GLOBAL */
+
+/*
  * win32_signal is used to get input from the keyboard
  * if we are running in a console, or get input from an
  * event object if we are running as a service.
@@ -1019,4 +1034,161 @@ win_get_tempdir()
   WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof (tmpdir), NULL, NULL);
   return tmpdir;
 }
+
+#if _WIN32_WINNT >= 0x0600
+bool
+win_wfp_init()
+{
+    ZeroMemory(&m_subLayerGUID, sizeof(GUID));
+    DWORD dwFwAPiRetCode = ERROR_BAD_COMMAND;
+    FWPM_SESSION0 session = {0};
+    RPC_STATUS rpcStatus = {0};
+    FWPM_SUBLAYER0 SubLayer = {0};
+
+    /* Add temporary filters which don't survive reboots or crashes. */
+    session.flags = FWPM_SESSION_FLAG_DYNAMIC;
+
+    dmsg (D_LOW, "Opening WFP engine");
+    dwFwAPiRetCode = FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &m_hEngineHandle);
+
+    if (dwFwAPiRetCode != ERROR_SUCCESS)
+    {
+        msg (M_NONFATAL, "Can't open WFP engine");
+        return false;
+    }
+
+    rpcStatus = UuidCreate(&SubLayer.subLayerKey);
+    if (rpcStatus != NO_ERROR)
+        return false;
+    CopyMemory(&m_subLayerGUID, &SubLayer.subLayerKey, sizeof(SubLayer.subLayerKey));
+
+    /* Populate packet filter layer information. */
+    SubLayer.displayData.name = FIREWALL_NAME;
+    SubLayer.displayData.description = FIREWALL_NAME;
+    SubLayer.flags = 0;
+    SubLayer.weight = 0x100;
+
+    /* Add packet filter to our interface. */
+    dmsg (D_LOW, "Adding WFP sublayer");
+    dwFwAPiRetCode = FwpmSubLayerAdd0(m_hEngineHandle, &SubLayer, NULL);
+    if (dwFwAPiRetCode != ERROR_SUCCESS)
+    {
+        msg (M_NONFATAL, "Can't add WFP sublayer");
+        return false;
+    }
+    return true;
+}
+
+bool
+win_wfp_uninit()
+{
+    dmsg (D_LOW, "Uninitializing WFP");
+    DWORD dwFwAPiRetCode = ERROR_BAD_COMMAND;
+    if (m_hEngineHandle) {
+        FwpmSubLayerDeleteByKey0(m_hEngineHandle, &m_subLayerGUID);
+        ZeroMemory(&m_subLayerGUID, sizeof(GUID));
+        FwpmEngineClose0(m_hEngineHandle);
+        m_hEngineHandle = NULL;
+    }
+    return true;
+}
+
+bool
+win_wfp_add_filter (HANDLE engineHandle,
+                    const FWPM_FILTER0 *filter,
+                    PSECURITY_DESCRIPTOR sd,
+                    UINT64 *id)
+{
+    if (FwpmFilterAdd0(engineHandle, filter, sd, id) != ERROR_SUCCESS)
+    {
+        msg (M_NONFATAL, "Can't add WFP filter");
+        return false;
+    }
+    return true;
+}
+
+bool
+win_wfp_block_dns (const NET_IFINDEX index)
+{
+    dmsg (D_LOW, "Blocking DNS using WFP");
+    NET_LUID tapluid;
+    NETIO_STATUS ret;
+    DWORD dwFwAPiRetCode = ERROR_BAD_COMMAND;
+    UINT64 filterid;
+    WCHAR openvpnpath[MAX_PATH];
+    FWP_BYTE_BLOB *openvpnblob = NULL;
+
+    FWPM_FILTER0 Filter = {0};
+    FWPM_FILTER_CONDITION0 Condition[2] = {0};
+
+    ret = ConvertInterfaceIndexToLuid(index, &tapluid);
+    if (ret == NO_ERROR)
+        dmsg (D_LOW, "Tap Luid: %I64d", tapluid.Value);
+
+    /* Get OpenVPN path. */
+    GetModuleFileNameW(NULL, openvpnpath, MAX_PATH);
+
+    if (FwpmGetAppIdFromFileName0(openvpnpath, &openvpnblob) != ERROR_SUCCESS)
+        return false;
+
+    /* Prepare filter. */
+    Filter.subLayerKey = m_subLayerGUID;
+    Filter.displayData.name = FIREWALL_NAME;
+    Filter.weight.type = FWP_EMPTY;
+    Filter.filterCondition = Condition;
+    Filter.numFilterConditions = 2;
+
+    /* First filter. Block IPv4 DNS queries except from OpenVPN itself. */
+    Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
+    Filter.action.type = FWP_ACTION_BLOCK;
+
+    Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT;
+    Condition[0].matchType = FWP_MATCH_EQUAL;
+    Condition[0].conditionValue.type = FWP_UINT16;
+    Condition[0].conditionValue.uint16 = 53;
+
+    Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID;
+    Condition[1].matchType = FWP_MATCH_NOT_EQUAL;
+    Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE;
+    Condition[1].conditionValue.byteBlob = openvpnblob;
+
+    /* Add filter condition to our interface. */
+    if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
+        return false;
+    dmsg (D_LOW, "Filter (Block IPv4 DNS) added with ID=%I64d", filterid);
+
+    /* Second filter. Block IPv6 DNS queries except from OpenVPN itself. */
+    Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
+
+    /* Add filter condition to our interface. */
+    if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
+        return false;
+    dmsg (D_LOW, "Filter (Block IPv6 DNS) added with ID=%I64d", filterid);
+
+    /* Third filter. Permit IPv4 DNS queries from TAP. */
+    Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4;
+    Filter.action.type = FWP_ACTION_PERMIT;
+
+    Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE;
+    Condition[1].matchType = FWP_MATCH_EQUAL;
+    Condition[1].conditionValue.type = FWP_UINT64;
+    Condition[1].conditionValue.uint64 = &tapluid.Value;
+
+    /* Add filter condition to our interface. */
+    if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
+        return false;
+    dmsg (D_LOW, "Filter (Permit IPv4 DNS queries from TAP) added with ID=%I64d", filterid);
+
+    /* Forth filter. Permit IPv6 DNS queries from TAP. */
+    Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6;
+
+    /* Add filter condition to our interface. */
+    if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid))
+        return false;
+    dmsg (D_LOW, "Filter (Permit IPv6 DNS queries from TAP) added with ID=%I64d", filterid);
+
+    return true;
+}
+
+#endif
 #endif
diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h
index cc18f02..d26b247 100644
--- a/src/openvpn/win32.h
+++ b/src/openvpn/win32.h
@@ -27,6 +27,10 @@
 #define OPENVPN_WIN32_H
 
 #include "mtu.h"
+#if _WIN32_WINNT >= 0x0600
+#include <initguid.h>
+#include <fwpmtypes.h>
+#endif
 
 /* location of executables */
 #define SYS_PATH_ENV_VAR_NAME "SystemRoot"  /* environmental variable name that normally contains the system path */
@@ -271,5 +275,65 @@ const char *win_get_tempdir();
 /* Convert a string from UTF-8 to UCS-2 */
 WCHAR *wide_string (const char* utf8, struct gc_arena *gc);
 
+#if _WIN32_WINNT >= 0x0600
+bool win_wfp_block_dns(const NET_IFINDEX index);
+bool win_wfp_add_filter (HANDLE engineHandle,
+                        const FWPM_FILTER0 *filter,
+                        PSECURITY_DESCRIPTOR sd,
+                        UINT64 *id);
+bool win_wfp_uninit();
+bool win_wfp_init();
+
+/* WFP-related define and GUIDs */
+#ifndef FWPM_SESSION_FLAG_DYNAMIC
+#define FWPM_SESSION_FLAG_DYNAMIC 0x00000001
+#endif
+
+// c38d57d1-05a7-4c33-904f-7fbceee60e82
+DEFINE_GUID(
+   FWPM_LAYER_ALE_AUTH_CONNECT_V4,
+   0xc38d57d1,
+   0x05a7,
+   0x4c33,
+   0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82
+);
+
+// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4
+DEFINE_GUID(
+   FWPM_LAYER_ALE_AUTH_CONNECT_V6,
+   0x4a72393b,
+   0x319f,
+   0x44bc,
+   0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4
+);
+
+// d78e1e87-8644-4ea5-9437-d809ecefc971
+DEFINE_GUID(
+   FWPM_CONDITION_ALE_APP_ID,
+   0xd78e1e87,
+   0x8644,
+   0x4ea5,
+   0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71
+);
+
+// c35a604d-d22b-4e1a-91b4-68f674ee674b
+DEFINE_GUID(
+   FWPM_CONDITION_IP_REMOTE_PORT,
+   0xc35a604d,
+   0xd22b,
+   0x4e1a,
+   0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b
+);
+
+// 4cd62a49-59c3-4969-b7f3-bda5d32890a4
+DEFINE_GUID(
+   FWPM_CONDITION_IP_LOCAL_INTERFACE,
+   0x4cd62a49,
+   0x59c3,
+   0x4969,
+   0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4
+);
+
+#endif
 #endif
 #endif
-- 
2.6.2

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to