This option blocks all out-of-tunnel communication on TCP/UDP port 53
(except for OpenVPN itself), preventing DNS Leaks on Windows 8.1 and 10.
This is the same patch as dd628d2e0d786e4 in release/2.3, except that it
is always compiled (on WIN32) here - we already require compilation for
Vista+ in master (-> 2.4).
Reviewed-by: Selva Nair <selva.nair@gmail.com>
Reviewed-by: Lev Stipakov <lstipakov@gmail.com>
Reviewed-by: James Yonan <james@openvpn.net>
Acked-by: Gert Doering <gert@greenie.muc.de>
Message-Id: <1449780715-4027-1-git-send-email-iam@valdikss.org.ru>
URL: http://article.gmane.org/gmane.network.openvpn.devel/10744
Signed-off-by: Gert Doering <gert@greenie.muc.de>
... | ... |
@@ -1129,8 +1129,8 @@ When used with |
1129 | 1129 |
.B \-\-client |
1130 | 1130 |
or |
1131 | 1131 |
.B \-\-pull, |
1132 |
-accept options pushed by server EXCEPT for routes and dhcp options |
|
1133 |
-like DNS servers. |
|
1132 |
+accept options pushed by server EXCEPT for routes, block-outside-dns and dhcp |
|
1133 |
+options like DNS servers. |
|
1134 | 1134 |
|
1135 | 1135 |
When used on the client, this option effectively bars the |
1136 | 1136 |
server from adding routes to the client's routing table, |
... | ... |
@@ -5568,6 +5568,14 @@ adapter list to the syslog or log file after the TUN/TAP adapter |
5568 | 5568 |
has been brought up and any routes have been added. |
5569 | 5569 |
.\"********************************************************* |
5570 | 5570 |
.TP |
5571 |
+.B \-\-block\-outside\-dns |
|
5572 |
+Block DNS servers on other network adapters to prevent |
|
5573 |
+DNS leaks. This option prevents any application from accessing |
|
5574 |
+TCP or UDP port 53 except one inside the tunnel. It uses |
|
5575 |
+Windows Filtering Platform (WFP) and works on Windows Vista or |
|
5576 |
+later. |
|
5577 |
+.\"********************************************************* |
|
5578 |
+.TP |
|
5571 | 5579 |
.B \-\-dhcp\-renew |
5572 | 5580 |
Ask Windows to renew the TAP adapter lease on startup. |
5573 | 5581 |
This option is normally unnecessary, as Windows automatically |
... | ... |
@@ -127,5 +127,5 @@ openvpn_LDADD = \ |
127 | 127 |
$(OPTIONAL_DL_LIBS) |
128 | 128 |
if WIN32 |
129 | 129 |
openvpn_SOURCES += openvpn_win32_resources.rc |
130 |
-openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm |
|
130 |
+openvpn_LDADD += -lgdi32 -lws2_32 -lwininet -lcrypt32 -liphlpapi -lwinmm -lfwpuclnt -lrpcrt4 |
|
131 | 131 |
endif |
... | ... |
@@ -1495,6 +1495,15 @@ do_open_tun (struct context *c) |
1495 | 1495 |
"up", |
1496 | 1496 |
c->c2.es); |
1497 | 1497 |
|
1498 |
+#if defined(WIN32) |
|
1499 |
+ if (c->options.block_outside_dns) |
|
1500 |
+ { |
|
1501 |
+ dmsg (D_LOW, "Blocking outside DNS"); |
|
1502 |
+ if (!win_wfp_block_dns(c->c1.tuntap->adapter_index)) |
|
1503 |
+ msg (M_FATAL, "Blocking DNS failed!"); |
|
1504 |
+ } |
|
1505 |
+#endif |
|
1506 |
+ |
|
1498 | 1507 |
/* possibly add routes */ |
1499 | 1508 |
if ((route_order() == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined)) |
1500 | 1509 |
do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list, |
... | ... |
@@ -1623,6 +1632,14 @@ do_close_tun (struct context *c, bool force) |
1623 | 1623 |
"down", |
1624 | 1624 |
c->c2.es); |
1625 | 1625 |
|
1626 |
+#if defined(WIN32) |
|
1627 |
+ if (c->options.block_outside_dns) |
|
1628 |
+ { |
|
1629 |
+ if (!win_wfp_uninit()) |
|
1630 |
+ msg (M_FATAL, "Uninitialising WFP failed!"); |
|
1631 |
+ } |
|
1632 |
+#endif |
|
1633 |
+ |
|
1626 | 1634 |
/* actually close tun/tap device based on --down-pre flag */ |
1627 | 1635 |
if (c->options.down_pre) |
1628 | 1636 |
do_close_tun_simple (c); |
1629 | 1637 |
old mode 100755 |
1630 | 1638 |
new mode 100644 |
... | ... |
@@ -64,7 +64,7 @@ |
64 | 64 |
<AdditionalIncludeDirectories>$(SOURCEBASE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
65 | 65 |
</ResourceCompile> |
66 | 66 |
<Link> |
67 |
- <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> |
|
67 |
+ <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> |
|
68 | 68 |
<AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> |
69 | 69 |
<GenerateDebugInformation>true</GenerateDebugInformation> |
70 | 70 |
<SubSystem>Console</SubSystem> |
... | ... |
@@ -89,7 +89,7 @@ |
89 | 89 |
<AdditionalIncludeDirectories>$(SOURCEBASE);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> |
90 | 90 |
</ResourceCompile> |
91 | 91 |
<Link> |
92 |
- <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> |
|
92 |
+ <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> |
|
93 | 93 |
<AdditionalLibraryDirectories>$(OPENSSL_HOME)/lib;$(LZO_HOME)/lib;$(PKCS11H_HOME)/lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories> |
94 | 94 |
<GenerateDebugInformation>true</GenerateDebugInformation> |
95 | 95 |
<SubSystem>Console</SubSystem> |
... | ... |
@@ -704,6 +704,9 @@ static const char usage_message[] = |
704 | 704 |
" optional parameter controls the initial state of ex.\n" |
705 | 705 |
"--show-net-up : Show " PACKAGE_NAME "'s view of routing table and net adapter list\n" |
706 | 706 |
" after TAP adapter is up and routes have been added.\n" |
707 |
+#ifdef WIN32 |
|
708 |
+ "--block-outside-dns : Block DNS on other network adapters to prevent DNS leaks\n" |
|
709 |
+#endif |
|
707 | 710 |
"Windows Standalone Options:\n" |
708 | 711 |
"\n" |
709 | 712 |
"--show-adapters : Show all TAP-Windows adapters.\n" |
... | ... |
@@ -805,6 +808,7 @@ init_options (struct options *o, const bool init_gc) |
805 | 805 |
o->tuntap_options.dhcp_lease_time = 31536000; /* one year */ |
806 | 806 |
o->tuntap_options.dhcp_masq_offset = 0; /* use network address as internal DHCP server address */ |
807 | 807 |
o->route_method = ROUTE_METHOD_ADAPTIVE; |
808 |
+ o->block_outside_dns = false; |
|
808 | 809 |
#endif |
809 | 810 |
#if P2MP_SERVER |
810 | 811 |
o->real_hash_size = 256; |
... | ... |
@@ -1673,6 +1677,7 @@ show_settings (const struct options *o) |
1673 | 1673 |
#ifdef WIN32 |
1674 | 1674 |
SHOW_BOOL (show_net_up); |
1675 | 1675 |
SHOW_INT (route_method); |
1676 |
+ SHOW_BOOL (block_outside_dns); |
|
1676 | 1677 |
show_tuntap_options (&o->tuntap_options); |
1677 | 1678 |
#endif |
1678 | 1679 |
#endif |
... | ... |
@@ -6196,6 +6201,11 @@ add_option (struct options *options, |
6196 | 6196 |
VERIFY_PERMISSION (OPT_P_IPWIN32); |
6197 | 6197 |
options->tuntap_options.register_dns = true; |
6198 | 6198 |
} |
6199 |
+ else if (streq (p[0], "block-outside-dns") && !p[1]) |
|
6200 |
+ { |
|
6201 |
+ VERIFY_PERMISSION (OPT_P_IPWIN32); |
|
6202 |
+ options->block_outside_dns = true; |
|
6203 |
+ } |
|
6199 | 6204 |
else if (streq (p[0], "rdns-internal") && !p[1]) |
6200 | 6205 |
/* standalone method for internal use |
6201 | 6206 |
* |
... | ... |
@@ -47,6 +47,73 @@ |
47 | 47 |
#include "memdbg.h" |
48 | 48 |
|
49 | 49 |
/* |
50 |
+ * WFP-related defines and GUIDs. |
|
51 |
+ */ |
|
52 |
+#include <fwpmu.h> |
|
53 |
+#include <initguid.h> |
|
54 |
+#include <fwpmtypes.h> |
|
55 |
+#include <iphlpapi.h> |
|
56 |
+ |
|
57 |
+#ifndef FWPM_SESSION_FLAG_DYNAMIC |
|
58 |
+#define FWPM_SESSION_FLAG_DYNAMIC 0x00000001 |
|
59 |
+#endif |
|
60 |
+ |
|
61 |
+// c38d57d1-05a7-4c33-904f-7fbceee60e82 |
|
62 |
+DEFINE_GUID( |
|
63 |
+ FWPM_LAYER_ALE_AUTH_CONNECT_V4, |
|
64 |
+ 0xc38d57d1, |
|
65 |
+ 0x05a7, |
|
66 |
+ 0x4c33, |
|
67 |
+ 0x90, 0x4f, 0x7f, 0xbc, 0xee, 0xe6, 0x0e, 0x82 |
|
68 |
+); |
|
69 |
+ |
|
70 |
+// 4a72393b-319f-44bc-84c3-ba54dcb3b6b4 |
|
71 |
+DEFINE_GUID( |
|
72 |
+ FWPM_LAYER_ALE_AUTH_CONNECT_V6, |
|
73 |
+ 0x4a72393b, |
|
74 |
+ 0x319f, |
|
75 |
+ 0x44bc, |
|
76 |
+ 0x84, 0xc3, 0xba, 0x54, 0xdc, 0xb3, 0xb6, 0xb4 |
|
77 |
+); |
|
78 |
+ |
|
79 |
+// d78e1e87-8644-4ea5-9437-d809ecefc971 |
|
80 |
+DEFINE_GUID( |
|
81 |
+ FWPM_CONDITION_ALE_APP_ID, |
|
82 |
+ 0xd78e1e87, |
|
83 |
+ 0x8644, |
|
84 |
+ 0x4ea5, |
|
85 |
+ 0x94, 0x37, 0xd8, 0x09, 0xec, 0xef, 0xc9, 0x71 |
|
86 |
+); |
|
87 |
+ |
|
88 |
+// c35a604d-d22b-4e1a-91b4-68f674ee674b |
|
89 |
+DEFINE_GUID( |
|
90 |
+ FWPM_CONDITION_IP_REMOTE_PORT, |
|
91 |
+ 0xc35a604d, |
|
92 |
+ 0xd22b, |
|
93 |
+ 0x4e1a, |
|
94 |
+ 0x91, 0xb4, 0x68, 0xf6, 0x74, 0xee, 0x67, 0x4b |
|
95 |
+); |
|
96 |
+ |
|
97 |
+// 4cd62a49-59c3-4969-b7f3-bda5d32890a4 |
|
98 |
+DEFINE_GUID( |
|
99 |
+ FWPM_CONDITION_IP_LOCAL_INTERFACE, |
|
100 |
+ 0x4cd62a49, |
|
101 |
+ 0x59c3, |
|
102 |
+ 0x4969, |
|
103 |
+ 0xb7, 0xf3, 0xbd, 0xa5, 0xd3, 0x28, 0x90, 0xa4 |
|
104 |
+); |
|
105 |
+ |
|
106 |
+/* |
|
107 |
+ * WFP firewall name. |
|
108 |
+ */ |
|
109 |
+WCHAR * FIREWALL_NAME = L"OpenVPN"; /* GLOBAL */ |
|
110 |
+ |
|
111 |
+/* |
|
112 |
+ * WFP handle and GUID. |
|
113 |
+ */ |
|
114 |
+static HANDLE m_hEngineHandle = NULL; /* GLOBAL */ |
|
115 |
+ |
|
116 |
+/* |
|
50 | 117 |
* Windows internal socket API state (opaque). |
51 | 118 |
*/ |
52 | 119 |
static struct WSAData wsa_state; /* GLOBAL */ |
... | ... |
@@ -1077,4 +1144,148 @@ win_get_tempdir() |
1077 | 1077 |
WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof (tmpdir), NULL, NULL); |
1078 | 1078 |
return tmpdir; |
1079 | 1079 |
} |
1080 |
+ |
|
1081 |
+bool |
|
1082 |
+win_wfp_add_filter (HANDLE engineHandle, |
|
1083 |
+ const FWPM_FILTER0 *filter, |
|
1084 |
+ PSECURITY_DESCRIPTOR sd, |
|
1085 |
+ UINT64 *id) |
|
1086 |
+{ |
|
1087 |
+ if (FwpmFilterAdd0(engineHandle, filter, sd, id) != ERROR_SUCCESS) |
|
1088 |
+ { |
|
1089 |
+ msg (M_NONFATAL, "Can't add WFP filter"); |
|
1090 |
+ return false; |
|
1091 |
+ } |
|
1092 |
+ return true; |
|
1093 |
+} |
|
1094 |
+ |
|
1095 |
+bool |
|
1096 |
+win_wfp_block_dns (const NET_IFINDEX index) |
|
1097 |
+{ |
|
1098 |
+ FWPM_SESSION0 session = {0}; |
|
1099 |
+ FWPM_SUBLAYER0 SubLayer = {0}; |
|
1100 |
+ NET_LUID tapluid; |
|
1101 |
+ UINT64 filterid; |
|
1102 |
+ WCHAR openvpnpath[MAX_PATH]; |
|
1103 |
+ FWP_BYTE_BLOB *openvpnblob = NULL; |
|
1104 |
+ FWPM_FILTER0 Filter = {0}; |
|
1105 |
+ FWPM_FILTER_CONDITION0 Condition[2] = {0}; |
|
1106 |
+ |
|
1107 |
+ /* Add temporary filters which don't survive reboots or crashes. */ |
|
1108 |
+ session.flags = FWPM_SESSION_FLAG_DYNAMIC; |
|
1109 |
+ |
|
1110 |
+ dmsg (D_LOW, "Opening WFP engine"); |
|
1111 |
+ |
|
1112 |
+ if (FwpmEngineOpen0(NULL, RPC_C_AUTHN_WINNT, NULL, &session, &m_hEngineHandle) != ERROR_SUCCESS) |
|
1113 |
+ { |
|
1114 |
+ msg (M_NONFATAL, "Can't open WFP engine"); |
|
1115 |
+ return false; |
|
1116 |
+ } |
|
1117 |
+ |
|
1118 |
+ if (UuidCreate(&SubLayer.subLayerKey) != NO_ERROR) |
|
1119 |
+ return false; |
|
1120 |
+ |
|
1121 |
+ /* Populate packet filter layer information. */ |
|
1122 |
+ SubLayer.displayData.name = FIREWALL_NAME; |
|
1123 |
+ SubLayer.displayData.description = FIREWALL_NAME; |
|
1124 |
+ SubLayer.flags = 0; |
|
1125 |
+ SubLayer.weight = 0x100; |
|
1126 |
+ |
|
1127 |
+ /* Add packet filter to our interface. */ |
|
1128 |
+ dmsg (D_LOW, "Adding WFP sublayer"); |
|
1129 |
+ if (FwpmSubLayerAdd0(m_hEngineHandle, &SubLayer, NULL) != ERROR_SUCCESS) |
|
1130 |
+ { |
|
1131 |
+ msg (M_NONFATAL, "Can't add WFP sublayer"); |
|
1132 |
+ return false; |
|
1133 |
+ } |
|
1134 |
+ |
|
1135 |
+ dmsg (D_LOW, "Blocking DNS using WFP"); |
|
1136 |
+ if (ConvertInterfaceIndexToLuid(index, &tapluid) != NO_ERROR) |
|
1137 |
+ { |
|
1138 |
+ msg (M_NONFATAL, "Can't convert interface index to LUID"); |
|
1139 |
+ return false; |
|
1140 |
+ } |
|
1141 |
+ dmsg (D_LOW, "Tap Luid: %I64d", tapluid.Value); |
|
1142 |
+ |
|
1143 |
+ /* Get OpenVPN path. */ |
|
1144 |
+ GetModuleFileNameW(NULL, openvpnpath, MAX_PATH); |
|
1145 |
+ |
|
1146 |
+ if (FwpmGetAppIdFromFileName0(openvpnpath, &openvpnblob) != ERROR_SUCCESS) |
|
1147 |
+ return false; |
|
1148 |
+ |
|
1149 |
+ /* Prepare filter. */ |
|
1150 |
+ Filter.subLayerKey = SubLayer.subLayerKey; |
|
1151 |
+ Filter.displayData.name = FIREWALL_NAME; |
|
1152 |
+ Filter.weight.type = FWP_EMPTY; |
|
1153 |
+ Filter.filterCondition = Condition; |
|
1154 |
+ Filter.numFilterConditions = 2; |
|
1155 |
+ |
|
1156 |
+ /* First filter. Block IPv4 DNS queries except from OpenVPN itself. */ |
|
1157 |
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; |
|
1158 |
+ Filter.action.type = FWP_ACTION_BLOCK; |
|
1159 |
+ |
|
1160 |
+ Condition[0].fieldKey = FWPM_CONDITION_IP_REMOTE_PORT; |
|
1161 |
+ Condition[0].matchType = FWP_MATCH_EQUAL; |
|
1162 |
+ Condition[0].conditionValue.type = FWP_UINT16; |
|
1163 |
+ Condition[0].conditionValue.uint16 = 53; |
|
1164 |
+ |
|
1165 |
+ Condition[1].fieldKey = FWPM_CONDITION_ALE_APP_ID; |
|
1166 |
+ Condition[1].matchType = FWP_MATCH_NOT_EQUAL; |
|
1167 |
+ Condition[1].conditionValue.type = FWP_BYTE_BLOB_TYPE; |
|
1168 |
+ Condition[1].conditionValue.byteBlob = openvpnblob; |
|
1169 |
+ |
|
1170 |
+ /* Add filter condition to our interface. */ |
|
1171 |
+ if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) |
|
1172 |
+ goto err; |
|
1173 |
+ dmsg (D_LOW, "Filter (Block IPv4 DNS) added with ID=%I64d", filterid); |
|
1174 |
+ |
|
1175 |
+ /* Second filter. Block IPv6 DNS queries except from OpenVPN itself. */ |
|
1176 |
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; |
|
1177 |
+ |
|
1178 |
+ /* Add filter condition to our interface. */ |
|
1179 |
+ if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) |
|
1180 |
+ goto err; |
|
1181 |
+ dmsg (D_LOW, "Filter (Block IPv6 DNS) added with ID=%I64d", filterid); |
|
1182 |
+ |
|
1183 |
+ /* Third filter. Permit IPv4 DNS queries from TAP. */ |
|
1184 |
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V4; |
|
1185 |
+ Filter.action.type = FWP_ACTION_PERMIT; |
|
1186 |
+ |
|
1187 |
+ Condition[1].fieldKey = FWPM_CONDITION_IP_LOCAL_INTERFACE; |
|
1188 |
+ Condition[1].matchType = FWP_MATCH_EQUAL; |
|
1189 |
+ Condition[1].conditionValue.type = FWP_UINT64; |
|
1190 |
+ Condition[1].conditionValue.uint64 = &tapluid.Value; |
|
1191 |
+ |
|
1192 |
+ /* Add filter condition to our interface. */ |
|
1193 |
+ if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) |
|
1194 |
+ goto err; |
|
1195 |
+ dmsg (D_LOW, "Filter (Permit IPv4 DNS queries from TAP) added with ID=%I64d", filterid); |
|
1196 |
+ |
|
1197 |
+ /* Forth filter. Permit IPv6 DNS queries from TAP. */ |
|
1198 |
+ Filter.layerKey = FWPM_LAYER_ALE_AUTH_CONNECT_V6; |
|
1199 |
+ |
|
1200 |
+ /* Add filter condition to our interface. */ |
|
1201 |
+ if (!win_wfp_add_filter(m_hEngineHandle, &Filter, NULL, &filterid)) |
|
1202 |
+ goto err; |
|
1203 |
+ dmsg (D_LOW, "Filter (Permit IPv6 DNS queries from TAP) added with ID=%I64d", filterid); |
|
1204 |
+ |
|
1205 |
+ FwpmFreeMemory0((void **)&openvpnblob); |
|
1206 |
+ return true; |
|
1207 |
+ |
|
1208 |
+ err: |
|
1209 |
+ FwpmFreeMemory0((void **)&openvpnblob); |
|
1210 |
+ return false; |
|
1211 |
+} |
|
1212 |
+ |
|
1213 |
+bool |
|
1214 |
+win_wfp_uninit() |
|
1215 |
+{ |
|
1216 |
+ dmsg (D_LOW, "Uninitializing WFP"); |
|
1217 |
+ if (m_hEngineHandle) { |
|
1218 |
+ FwpmEngineClose0(m_hEngineHandle); |
|
1219 |
+ m_hEngineHandle = NULL; |
|
1220 |
+ } |
|
1221 |
+ return true; |
|
1222 |
+} |
|
1223 |
+ |
|
1080 | 1224 |
#endif |
... | ... |
@@ -271,5 +271,8 @@ const char *win_get_tempdir(); |
271 | 271 |
/* Convert a string from UTF-8 to UCS-2 */ |
272 | 272 |
WCHAR *wide_string (const char* utf8, struct gc_arena *gc); |
273 | 273 |
|
274 |
+bool win_wfp_block_dns(const NET_IFINDEX index); |
|
275 |
+bool win_wfp_uninit(); |
|
276 |
+ |
|
274 | 277 |
#endif |
275 | 278 |
#endif |