Set a low interface metric for tap adapter when block-outside-dns is in use
PATCH v2 1/1 Set a low interface metric for tap adapter when block-outside-dns is in use
From: ValdikSS <[email protected]...>
Windows 10 before Creators Update used to resolve DNS using all available adapters and IP addresses in parallel. Now it still resolves addresses using all available adapters but in a round-robin way, beginning with random adapter.
This behaviour introduces significant delay when block-outside-dns is in use. Fortunately, setting low metric for the TAP interface solves this issue, making Windows always pick TAP adapter first and disable round-robin.
--- src/openvpn/block_dns.c | 78 +++++++++++++++++++++++++++++++++++++++++++ src/openvpn/block_dns.h | 30 +++++++++++++++++ src/openvpn/init.c | 4 +-- src/openvpn/win32.c | 39 ++++++++++++++++++++-- src/openvpn/win32.h | 2 +- src/openvpnserv/interactive.c | 70 +++++++++++++++++++++++++++++++++++--- 6 files changed, 213 insertions(+), 10 deletions(-)
src/openvpn/block_dns.c +78 -0
@@ -110,6 +110,9 @@ DEFINE_GUID(static WCHAR *FIREWALL_NAME =L"OpenVPN" ; +VOID NETIOAPI_API_ +InitializeIpInterfaceEntry (PMIB_IPINTERFACE_ROW Row); +/* * Default msg handler does nothing */
@@ -341,4 +344,79 @@ delete_block_dns_filters(HANDLE engine_handle) return err; } +/* +* Returns interface metric value for specified interface index. +* +* Arguments: +* index : The index of TAP adapter. +* family : Address family (AF_INET for IPv4 and AF_INET6 for IPv6). +* Returns positive metric value or zero for automatic metric on success, +* a less then zero error code on failure. +*/ + +int +get_interface_metric (const NET_IFINDEX index,const ADDRESS_FAMILY family) +{ +DWORD err =0 ; +MIB_IPINTERFACE_ROW ipiface; +InitializeIpInterfaceEntry (&ipiface); + ipiface.Family = family; + ipiface.InterfaceIndex = index; + err =GetIpInterfaceEntry (&ipiface); +if (err ==NO_ERROR ) + { +if (ipiface.UseAutomaticMetric) + { +return 0 ; + } +return ipiface.Metric; + } +return -err; +} + +/* +* Sets interface metric value for specified interface index. +* +* Arguments: +* index : The index of TAP adapter. +* family : Address family (AF_INET for IPv4 and AF_INET6 for IPv6). +* metric : Metric value. 0 for automatic metric. +* Returns 0 on success, a non-zero status code of the last failed action on failure. +*/ + +DWORD +set_interface_metric (const NET_IFINDEX index,const ADDRESS_FAMILY family, +const ULONG metric) +{ +DWORD err =0 ; +MIB_IPINTERFACE_ROW ipiface; +InitializeIpInterfaceEntry (&ipiface); + ipiface.Family = family; + ipiface.InterfaceIndex = index; + err =GetIpInterfaceEntry (&ipiface); +if (err ==NO_ERROR ) + { +if (family ==AF_INET ) + { +/* required for IPv4 as per MSDN */ + ipiface.SitePrefixLength =0 ; + } + ipiface.Metric = metric; +if (metric ==0 ) + { + ipiface.UseAutomaticMetric = TRUE; + } +else + { + ipiface.UseAutomaticMetric = FALSE; + } + err =SetIpInterfaceEntry (&ipiface); +if (err ==NO_ERROR ) + { +return 0 ; + } + } +return err; +} +#endif /* ifdef _WIN32 */
src/openvpn/block_dns.h +30 -0
@@ -27,6 +27,9 @@#ifndef OPENVPN_BLOCK_DNS_H #define OPENVPN_BLOCK_DNS_H +/* Any value less than 5 should work fine. 3 is choosen without any real reason. */ +#define BLOCK_DNS_IFACE_METRIC 3 +typedef void (*block_dns_msg_handler_t ) (DWORD err,const char *msg);DWORD
@@ -36,5 +39,32 @@ DWORD add_block_dns_filters(HANDLE *engine, int iface_index, const WCHAR *exe_path, block_dns_msg_handler_t msg_handler_callback); +/** +* Returns interface metric value for specified interface index. +* +* @param index The index of TAP adapter +* @param family Address family (AF_INET for IPv4 and AF_INET6 for IPv6) +* +* @return positive metric value or zero for automatic metric on success, +* a less then zero error code on failure. +*/ + +int +get_interface_metric (const NET_IFINDEX index,const ADDRESS_FAMILY family); + +/** +* Sets interface metric value for specified interface index. +* +* @param index The index of TAP adapter +* @param family Address family (AF_INET for IPv4 and AF_INET6 for IPv6) +* @param metric Metric value. 0 for automatic metric +* +* @return 0 on success, a non-zero status code of the last failed action on failure. +*/ + +DWORD +set_interface_metric (const NET_IFINDEX index,const ADDRESS_FAMILY family, +const ULONG metric); +#endif #endif
src/openvpn/init.c +2 -2
@@ -1837,7 +1837,7 @@ do_close_tun(struct context *c, bool force)#if defined(_WIN32)if (c->options.block_outside_dns) { -if (!win_wfp_uninit (c->options.msg_channel)) +if (!win_wfp_uninit (adapter_index, c->options.msg_channel)) {msg (M_FATAL ,"Uninitialising WFP failed!" ); }
@@ -1877,7 +1877,7 @@ do_close_tun(struct context *c, bool force)#if defined(_WIN32)if (c->options.block_outside_dns) { -if (!win_wfp_uninit (c->options.msg_channel)) +if (!win_wfp_uninit (adapter_index, c->options.msg_channel)) {msg (M_FATAL ,"Uninitialising WFP failed!" ); }
src/openvpn/win32.c +37 -2
@@ -61,6 +61,12 @@static HANDLE m_hEngineHandle =NULL ;/* GLOBAL */ /* +* TAP adapter original metric value +*/ +static int tap_metric_v4 =-1 ;/* GLOBAL */ +static int tap_metric_v6 =-1 ;/* GLOBAL */ + +/* * Windows internal socket API state (opaque). */ static struct WSAData wsa_state;/* GLOBAL */
@@ -1337,6 +1343,27 @@ win_wfp_block_dns(const NET_IFINDEX index, const HANDLE msg_channel) status =add_block_dns_filters (&m_hEngineHandle, index, openvpnpath, block_dns_msg_handler); +if (status ==0 ) + { + tap_metric_v4 =get_interface_metric (index,AF_INET ); + tap_metric_v6 =get_interface_metric (index,AF_INET6 ); +if (tap_metric_v4 <0 ) + { +/* error, should not restore metric */ + tap_metric_v4 =-1 ; + } +if (tap_metric_v6 <0 ) + { +/* error, should not restore metric */ + tap_metric_v6 =-1 ; + } + status =set_interface_metric (index,AF_INET ,BLOCK_DNS_IFACE_METRIC ); +if (!status) + { +set_interface_metric (index,AF_INET6 ,BLOCK_DNS_IFACE_METRIC ); + } + } + ret = (status ==0 ); out:
@@ -1345,19 +1372,27 @@ out: }bool -win_wfp_uninit (const HANDLE msg_channel) +win_wfp_uninit (const NET_IFINDEX index,const HANDLE msg_channel) {dmsg (D_LOW ,"Uninitializing WFP" );if (msg_channel) {msg (D_LOW ,"Using service to delete block dns filters" ); -win_block_dns_service (false,-1 , msg_channel); +win_block_dns_service (false, index, msg_channel); }else {delete_block_dns_filters (m_hEngineHandle); m_hEngineHandle =NULL ; +if (tap_metric_v4 >=0 ) + { +set_interface_metric (index,AF_INET , tap_metric_v4); + } +if (tap_metric_v6 >=0 ) + { +set_interface_metric (index,AF_INET6 , tap_metric_v6); + } }return true;
src/openvpn/win32.h +1 -1
@@ -293,7 +293,7 @@ WCHAR *wide_string(const char *utf8, struct gc_arena *gc);bool win_wfp_block_dns (const NET_IFINDEX index,const HANDLE msg_channel); -bool win_wfp_uninit (const HANDLE msg_channel); +bool win_wfp_uninit (const NET_IFINDEX index,const HANDLE msg_channel);#define WIN_XP 0#define WIN_VISTA 1
src/openvpnserv/interactive.c +65 -5
107 lines not on this page · raw message
Signature · 1 line
2.9.3
Quoted 9 lines · ValdikSS
Windows 10 before Creators Update used to resolve DNS using all available adapters and IP addresses in parallel. Now it still resolves addresses using all available adapters but in a round-robin way, beginning with random adapter.
This behaviour introduces significant delay when block-outside-dns is in use. Fortunately, setting low metric for the TAP interface solves this issue, making Windows always pick TAP adapter first and disable round-robin.
Quoted 9 lines
--- src/openvpn/block_dns.c | 78 ++++++++++++++++++++++++++++++ +++++++++++++ src/openvpn/block_dns.h | 30 +++++++++++++++++ src/openvpn/init.c | 4 +-- src/openvpn/win32.c | 39 ++++++++++++++++++++-- src/openvpn/win32.h | 2 +- src/openvpnserv/interactive.c | 70 +++++++++++++++++++++++++++++++++++--- 6 files changed, 213 insertions(+), 10 deletions(-)
Looks good now. ACK from me.
Did a quick test on Win7 -- metric changes to 3 and gets restored independently for v4 and v6. No idea whether this resolves the Win 10 issue, but should not have any adverse effects except for the metric change which will also affect the metric of routes added.
Cross compiles without issues for 32 bit and 64 bit -- tested on Debain 8.7 with
mingw32-w64 included in the distribution.
Selva
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA256
Your patch has been applied to the following branches
commit 27aa87283f6e766507287649aa5a63f1f5172645 (master) commit 3c28855760c389d15384238d0e089132da98949b (release/2.4)
Author: ValdikSS Date: Wed May 10 21:47:53 2017 +0300
Set a low interface metric for tap adapter when block-outside-dns is in use
Signed-off-by: ValdikSS <[email protected]...>
Acked-by: Selva Nair <[email protected]...>
Message-Id: <[email protected]...>
URL: https://www.mail-archive.com/[email protected]/msg14624.html
Signed-off-by: David Sommerseth <[email protected]...>- --
kind regards,
David Sommerseth
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.22 (GNU/Linux)
iQIcBAEBCAAGBQJZFJZzAAoJEIbPlEyWcf3yr9YP/0/A0C1Zpn9KyddaZzNi8WJt 8ehpNeSX7zqWw8vhQeYeiEmLQPjnt+UHnaa5VG65TaVDc02HQgo/ULmq+yL2MJoE HxNiCpHQwVNMbhrV678lwrqkO8zUSL2LN2j0mSOkzRnrT/Y8b8Ldg7ZuRKWlOupL fqzoIdT8z/K0ON8Z+NAwuIhhn6Pa/9vgFgN2PEcpd3iI8XD3yBG3qiJc8TtEzG0H v9/HJcKkBO54mcl8d3dLa27zoERylcGu03vqj5KmpJyjzHVf3KkP9tEs1napAd8D O+FYrSTaUZwB8BXl9p3CgGD0SkWiDWyLkI3v9lU3b/vT7ZZtZEle3dHVDhliKnSW vg70UbfOm/4WMWEler/TZTwyD52Tt8/239NsqMYGxjYql0KP9V5A77ueZjEqbr4S vSzwPz1CAzvvP5vG+o+2hioyTvus4muwHRwsLcBf/aXxV12cZLJHlUDt6ue6XBGP x3t41BHs+6BV1oe5Hltb//Kshmb3GgbvWqF3jn9mXqrtbSUtksCe+CKbyv7NYxs4 0np5i2g+rbhSBvN3/H91Lg3DOLIYCtAc1xQLf/JJiP+F1ck2QljxzoZnVpPV3iot 9baMhFuAXz1mJ5XFhDUiNpSvkAKeXKYu1hiw2zubwH2Y3+tSj3OU9NgQwswR3Ivf yBuyT3Ocp5Wv8lkD6UyB
=ebI3
-----END PGP SIGNATURE-----