Based on release/2.3 branch, this patch is cross-compiled in MinGW and tested on Windows XP/10. The VC project file is left untouched - you might want to add rpcrt4.lib to compile and link it under MSVC.
Also, I didn't figure out how to keep ValdikSS's authorship of his code in the patch (sorry :-( ). Definitely no expert in git... Maybe I should generate a patch on top of his latest patch? Take ValdikSS<i...@valdikss.org.ru>'s patch for "block-outside-dns" option and make it Windows-version-agnostic. My code is pretty messy right now, will send out a secondary patch later after tidying WFP-related code. --- doc/openvpn.8 | 12 +- src/openvpn/Makefile.am | 2 +- src/openvpn/init.c | 13 ++ src/openvpn/openvpn.vcxproj | 0 src/openvpn/options.c | 11 + src/openvpn/options.h | 1 + src/openvpn/win32.c | 520 ++++++++++++++++++++++++++++++++++++++++++++ src/openvpn/win32.h | 4 + 8 files changed, 560 insertions(+), 3 deletions(-) mode change 100755 => 100644 src/openvpn/openvpn.vcxproj diff --git a/doc/openvpn.8 b/doc/openvpn.8 index 8968c2e..9e4b01e 100644 --- a/doc/openvpn.8 +++ b/doc/openvpn.8 @@ -1119,8 +1119,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, @@ -5448,6 +5448,14 @@ 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 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 +Windows Filtering Platform (WFP) and works on Windows Vista or +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 2e602f1..149a533 100644 --- a/src/openvpn/Makefile.am +++ b/src/openvpn/Makefile.am @@ -123,5 +123,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 -lrpcrt4 -lwinmm endif diff --git a/src/openvpn/init.c b/src/openvpn/init.c index ceef4f7..960535d 100644 --- a/src/openvpn/init.c +++ b/src/openvpn/init.c @@ -1468,6 +1468,13 @@ do_open_tun (struct context *c) "up", c->c2.es); + if (c->options.block_outside_dns) + { + dmsg (D_LOW, "Blocking outside DNS"); + if (!win_wfp_block_dns(c->c1.tuntap->adapter_index)) + msg (M_FATAL, "Blocking DNS failed!"); + } + /* possibly add routes */ if (!c->options.route_delay_defined) do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, @@ -1594,6 +1601,12 @@ do_close_tun (struct context *c, bool force) "down", c->c2.es); + if (c->options.block_outside_dns) + { + if (!win_wfp_uninit()) + msg (M_FATAL, "Uninitialising WFP failed!"); + } + /* 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 diff --git a/src/openvpn/options.c b/src/openvpn/options.c index f609aa6..564e670 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -715,6 +715,7 @@ 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" + "--block-outside-dns : Block DNS on other network adapters to prevent DNS leaks\n" "Windows Standalone Options:\n" "\n" "--show-adapters : Show all TAP-Windows adapters.\n" @@ -814,6 +815,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; @@ -1678,6 +1680,7 @@ show_settings (const struct options *o) #ifdef WIN32 SHOW_BOOL (show_net_up); SHOW_INT (route_method); + SHOW_BOOL (block_outside_dns); show_tuntap_options (&o->tuntap_options); #endif #endif @@ -6241,6 +6244,14 @@ add_option (struct options *options, VERIFY_PERMISSION (OPT_P_IPWIN32); options->tuntap_options.register_dns = true; } + else if (streq (p[0], "block-outside-dns") && !p[1]) + { + VERIFY_PERMISSION (OPT_P_IPWIN32); + if (win_wfp_init_funcs()) + { + options->block_outside_dns = true; + } + } else if (streq (p[0], "rdns-internal")) /* standalone method for internal use * diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 40cf71e..622706a 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -593,6 +593,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 5e7f13c..55eec95 100644 --- a/src/openvpn/win32.c +++ b/src/openvpn/win32.c @@ -47,6 +47,74 @@ #include "memdbg.h" /* + * WFP-related defines and GUIDs. + */ +// #include <fwpmu.h> +#include <initguid.h> +// #include <fwpmtypes.h> +#include <iphlpapi.h> + +#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 +); + +/* + * WFP firewall name. + */ +WCHAR * FIREWALL_NAME = L"OpenVPN"; /* GLOBAL */ + +/* + * WFP handle and GUID. + */ +static HANDLE m_hEngineHandle = NULL; /* GLOBAL */ +static GUID m_subLayerGUID; /* GLOBAL */ + +/* * Windows internal socket API state (opaque). */ static struct WSAData wsa_state; /* GLOBAL */ @@ -1077,4 +1145,456 @@ win_get_tempdir() WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof (tmpdir), NULL, NULL); return tmpdir; } + +/* From fwptypes.h */ + +#define FWP_ACTION_FLAG_TERMINATING (0x00001000) +#define FWP_ACTION_FLAG_NON_TERMINATING (0x00002000) + +#define FWP_ACTION_BLOCK (0x1 | FWP_ACTION_FLAG_TERMINATING) +#define FWP_ACTION_PERMIT (0x2 | FWP_ACTION_FLAG_TERMINATING) + +typedef UINT32 FWP_ACTION_TYPE; + +typedef enum FWP_DATA_TYPE_ { + FWP_EMPTY = 0, + FWP_UINT8 = 1, + FWP_UINT16 = 2, + FWP_UINT32 = 3, + FWP_UINT64 = 4, + FWP_INT8 = 5, + FWP_INT16 = 6, + FWP_INT32 = 7, + FWP_INT64 = 8, + FWP_FLOAT = 9, + FWP_DOUBLE = 10, + FWP_BYTE_ARRAY16_TYPE = 11, + FWP_BYTE_BLOB_TYPE = 12, + FWP_SID = 13, + FWP_SECURITY_DESCRIPTOR_TYPE = 14, + FWP_TOKEN_INFORMATION_TYPE = 15, + FWP_TOKEN_ACCESS_INFORMATION_TYPE = 16, + FWP_UNICODE_STRING_TYPE = 17, + FWP_BYTE_ARRAY6_TYPE = 18, + FWP_SINGLE_DATA_TYPE_MAX = 0xff, + FWP_V4_ADDR_MASK = 0x100, + FWP_V6_ADDR_MASK = 0x101, + FWP_RANGE_TYPE = 0x102, + FWP_DATA_TYPE_MAX = 0x103 +} FWP_DATA_TYPE; + +typedef enum FWP_MATCH_TYPE_ { + FWP_MATCH_EQUAL = 0, + FWP_MATCH_GREATER = 1, + FWP_MATCH_LESS = 2, + FWP_MATCH_GREATER_OR_EQUAL = 3, + FWP_MATCH_LESS_OR_EQUAL = 4, + FWP_MATCH_RANGE = 5, + FWP_MATCH_FLAGS_ALL_SET = 6, + FWP_MATCH_FLAGS_ANY_SET = 7, + FWP_MATCH_FLAGS_NONE_SET = 8, + FWP_MATCH_EQUAL_CASE_INSENSITIVE = 9, + FWP_MATCH_NOT_EQUAL = 10, + FWP_MATCH_TYPE_MAX = 11 +} FWP_MATCH_TYPE; + +typedef struct FWP_BYTE_ARRAY6_ { + UINT8 byteArray6[6]; +} FWP_BYTE_ARRAY6; + +typedef struct FWP_BYTE_ARRAY16_ { + UINT8 byteArray16[16]; +} FWP_BYTE_ARRAY16; + +typedef struct FWP_BYTE_BLOB_ { + UINT32 size; + UINT8 *data; +} FWP_BYTE_BLOB; + +typedef struct FWP_TOKEN_INFORMATION_ { + ULONG sidCount; + PSID_AND_ATTRIBUTES sids; + ULONG restrictedSidCount; + PSID_AND_ATTRIBUTES restrictedSids; +} FWP_TOKEN_INFORMATION; + +typedef struct FWP_VALUE0_ { + FWP_DATA_TYPE type; + __C89_NAMELESS union { + UINT8 uint8; + UINT16 uint16; + UINT32 uint32; + UINT64 *uint64; + INT8 int8; + INT16 int16; + INT32 int32; + INT64 *int64; + float float32; + double *double64; + FWP_BYTE_ARRAY16 *byteArray16; + FWP_BYTE_BLOB *byteBlob; + SID *sid; + FWP_BYTE_BLOB *sd; + FWP_TOKEN_INFORMATION *tokenInformation; + FWP_BYTE_BLOB *tokenAccessInformation; + LPWSTR unicodeString; + FWP_BYTE_ARRAY6 *byteArray6; + } __C89_NAMELESSUNIONNAME; +} FWP_VALUE0; + +typedef struct FWP_V4_ADDR_AND_MASK_ { + UINT32 addr; + UINT32 mask; +} FWP_V4_ADDR_AND_MASK; + +typedef struct FWP_V6_ADDR_AND_MASK_ { + UINT8 addr[16]; + UINT8 prefixLength; +} FWP_V6_ADDR_AND_MASK; + +typedef struct FWP_RANGE0_ { + FWP_VALUE0 valueLow; + FWP_VALUE0 valueHigh; +} FWP_RANGE0; + +typedef struct FWP_CONDITION_VALUE0_ { + FWP_DATA_TYPE type; + __C89_NAMELESS union { + UINT8 uint8; + UINT16 uint16; + UINT32 uint32; + UINT64 *uint64; + INT8 int8; + INT16 int16; + INT32 int32; + INT64 *int64; + float float32; + double *double64; + FWP_BYTE_ARRAY16 *byteArray16; + FWP_BYTE_BLOB *byteBlob; + SID *sid; + FWP_BYTE_BLOB *sd; + FWP_TOKEN_INFORMATION *tokenInformation; + FWP_BYTE_BLOB *tokenAccessInformation; + LPWSTR unicodeString; + FWP_BYTE_ARRAY6 *byteArray6; + FWP_V4_ADDR_AND_MASK *v4AddrMask; + FWP_V6_ADDR_AND_MASK *v6AddrMask; + FWP_RANGE0 *rangeValue; + } __C89_NAMELESSUNIONNAME; +} FWP_CONDITION_VALUE0; + +typedef struct FWPM_DISPLAY_DATA0_ { + wchar_t *name; + wchar_t *description; +} FWPM_DISPLAY_DATA0; + +/* From fwpmtypes.h */ + +typedef struct FWPM_ACTION0_ { + FWP_ACTION_TYPE type; + __C89_NAMELESS union { + GUID filterType; + GUID calloutKey; + }; +} FWPM_ACTION0; + +typedef struct FWPM_SESSION0_ { + GUID sessionKey; + FWPM_DISPLAY_DATA0 displayData; + UINT32 flags; + UINT32 txnWaitTimeoutInMSec; + DWORD processId; + SID *sid; + wchar_t *username; + WINBOOL kernelMode; +} FWPM_SESSION0; + +typedef struct FWPM_SUBLAYER0_ { + GUID subLayerKey; + FWPM_DISPLAY_DATA0 displayData; + UINT16 flags; + GUID *providerKey; + FWP_BYTE_BLOB providerData; + UINT16 weight; +} FWPM_SUBLAYER0; + +typedef struct FWPM_FILTER_CONDITION0_ { + GUID fieldKey; + FWP_MATCH_TYPE matchType; + FWP_CONDITION_VALUE0 conditionValue; +} FWPM_FILTER_CONDITION0; + +typedef struct FWPM_FILTER0_ { + GUID filterKey; + FWPM_DISPLAY_DATA0 displayData; + UINT32 flags; + GUID *providerKey; + FWP_BYTE_BLOB providerData; + GUID layerKey; + GUID subLayerKey; + FWP_VALUE0 weight; + UINT32 numFilterConditions; + FWPM_FILTER_CONDITION0 *filterCondition; + FWPM_ACTION0 action; + __C89_NAMELESS union { + UINT64 rawContext; + GUID providerContextKey; + }; + GUID *reserved; + UINT64 filterId; + FWP_VALUE0 effectiveWeight; +} FWPM_FILTER0; + +#include <rpc.h> +#include <rpcdce.h> + +/* Typedefs of WFP functions */ + +#define NETIO_STATUS DWORD + +typedef NETIO_STATUS WINAPI *(*func_ConvertInterfaceIndexToLuid)( + NET_IFINDEX InterfaceIndex, + PNET_LUID InterfaceLuid +); + +typedef DWORD WINAPI *(*func_FwpmEngineOpen0)( + const wchar_t *serverName, + UINT32 authnService, + SEC_WINNT_AUTH_IDENTITY_W *authIdentity, + const FWPM_SESSION0 *session, + HANDLE *engineHandle +); + +typedef DWORD WINAPI *(*func_FwpmEngineClose0)( + HANDLE engineHandle +); + +typedef DWORD WINAPI *(*func_FwpmFilterAdd0)( + HANDLE engineHandle, + const FWPM_FILTER0 *filter, + PSECURITY_DESCRIPTOR sd, + UINT64 *id +); + +typedef DWORD WINAPI *(*func_FwpmSubLayerAdd0)( + HANDLE engineHandle, + const FWPM_SUBLAYER0 *subLayer, + PSECURITY_DESCRIPTOR sd +); + +typedef DWORD WINAPI *(*func_FwpmSubLayerDeleteByKey0)( + HANDLE engineHandle, + const GUID *key +); + +typedef void WINAPI *(*func_FwpmFreeMemory0)( + void **p +); + +typedef DWORD WINAPI *(*func_FwpmGetAppIdFromFileName0)( + const wchar_t *fileName, + FWP_BYTE_BLOB **appId +); + +/* WFP function pointers */ +func_ConvertInterfaceIndexToLuid ConvertInterfaceIndexToLuid = NULL; +func_FwpmEngineOpen0 FwpmEngineOpen0 = NULL; +func_FwpmEngineClose0 FwpmEngineClose0 = NULL; +func_FwpmFilterAdd0 FwpmFilterAdd0 = NULL; +func_FwpmSubLayerAdd0 FwpmSubLayerAdd0 = NULL; +func_FwpmSubLayerDeleteByKey0 FwpmSubLayerDeleteByKey0 = NULL; +func_FwpmFreeMemory0 FwpmFreeMemory0 = NULL; +func_FwpmGetAppIdFromFileName0 FwpmGetAppIdFromFileName0 = NULL; + +bool +win_wfp_init_funcs () +{ + /* Initialize all WFP-related function pointers */ + HMODULE iphlpapiHandle = LoadLibrary("iphlpapi.dll"); + if (iphlpapiHandle == NULL) + { + msg (M_NONFATAL, "Can't load iphlpapi.dll"); + return false; + } + + HMODULE fwpuclntHandle = LoadLibrary("fwpuclnt.dll"); + if (fwpuclntHandle == NULL) + { + msg (M_NONFATAL, "Can't load fwpuclnt.dll"); + return false; + } + + ConvertInterfaceIndexToLuid = (func_ConvertInterfaceIndexToLuid)GetProcAddress(iphlpapiHandle, "ConvertInterfaceIndexToLuid"); + FwpmFilterAdd0 = (func_FwpmFilterAdd0)GetProcAddress(fwpuclntHandle, "FwpmFilterAdd0"); + FwpmEngineOpen0 = (func_FwpmEngineOpen0)GetProcAddress(fwpuclntHandle, "FwpmEngineOpen0"); + FwpmEngineClose0 = (func_FwpmEngineClose0)GetProcAddress(fwpuclntHandle, "FwpmEngineClose0"); + FwpmSubLayerAdd0 = (func_FwpmSubLayerAdd0)GetProcAddress(fwpuclntHandle, "FwpmSubLayerAdd0"); + FwpmSubLayerDeleteByKey0 = (func_FwpmSubLayerDeleteByKey0)GetProcAddress(fwpuclntHandle, "FwpmSubLayerDeleteByKey0"); + FwpmFreeMemory0 = (func_FwpmFreeMemory0)GetProcAddress(fwpuclntHandle, "FwpmFreeMemory0"); + FwpmGetAppIdFromFileName0 = (func_FwpmGetAppIdFromFileName0)GetProcAddress(fwpuclntHandle, "FwpmGetAppIdFromFileName0"); + + if (!ConvertInterfaceIndexToLuid || + !FwpmFilterAdd0 || + !FwpmEngineOpen0 || + !FwpmEngineClose0 || + !FwpmSubLayerAdd0 || + !FwpmSubLayerDeleteByKey0 || + !FwpmFreeMemory0 || + !FwpmGetAppIdFromFileName0) + { + msg (M_NONFATAL, "Can't get address for all WFP-related procedures."); + return false; + } + + 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) +{ + CLEAR(m_subLayerGUID); + FWPM_SESSION0 session = {0}; + FWPM_SUBLAYER0 SubLayer = {0}; + NET_LUID tapluid; + UINT64 filterid; + WCHAR openvpnpath[MAX_PATH]; + FWP_BYTE_BLOB *openvpnblob = NULL; + FWPM_FILTER0 Filter = {0}; + FWPM_FILTER_CONDITION0 Condition[2] = {0}; + + /* Add temporary filters which don't survive reboots or crashes. */ + session.flags = FWPM_SESSION_FLAG_DYNAMIC; + + dmsg (D_LOW, "Opening WFP engine"); + + if (FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &m_hEngineHandle) != ERROR_SUCCESS) + { + msg (M_NONFATAL, "Can't open WFP engine"); + return false; + } + + if (UuidCreate(&SubLayer.subLayerKey) != NO_ERROR) + return false; + memcpy(&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"); + if (FwpmSubLayerAdd0(m_hEngineHandle, &SubLayer, NULL) != ERROR_SUCCESS) + { + msg (M_NONFATAL, "Can't add WFP sublayer"); + return false; + } + + dmsg (D_LOW, "Blocking DNS using WFP"); + if (ConvertInterfaceIndexToLuid(index, &tapluid) != NO_ERROR) + { + msg (M_NONFATAL, "Can't convert interface index to LUID"); + return false; + } + 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)) + goto err; + 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)) + goto err; + 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)) + goto err; + 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)) + goto err; + dmsg (D_LOW, "Filter (Permit IPv6 DNS queries from TAP) added with ID=%I64d", filterid); + + FwpmFreeMemory0((void **)&openvpnblob); + return true; + + err: + FwpmFreeMemory0((void **)&openvpnblob); + return false; +} + +bool +win_wfp_uninit() +{ + dmsg (D_LOW, "Uninitializing WFP"); + if (m_hEngineHandle) { + FwpmSubLayerDeleteByKey0(m_hEngineHandle, &m_subLayerGUID); + CLEAR(m_subLayerGUID); + FwpmEngineClose0(m_hEngineHandle); + m_hEngineHandle = NULL; + } + return true; +} + #endif diff --git a/src/openvpn/win32.h b/src/openvpn/win32.h index cc18f02..776ef36 100644 --- a/src/openvpn/win32.h +++ b/src/openvpn/win32.h @@ -271,5 +271,9 @@ const char *win_get_tempdir(); /* Convert a string from UTF-8 to UCS-2 */ WCHAR *wide_string (const char* utf8, struct gc_arena *gc); +bool win_wfp_init_funcs(); +bool win_wfp_block_dns(const NET_IFINDEX index); +bool win_wfp_uninit(); + #endif #endif -- 1.9.1