From 775a6ac2796a55bad3489d8532fd138d232fd2c4 Mon Sep 17 00:00:00 2001 From: james Date: Sun, 24 May 2009 09:13:58 +0000 Subject: Added new 'autolocal' redirect-gateway flag. When enabled, the OpenVPN client will examine the routing table and determine whether (a) the OpenVPN server is reachable via a locally connected interface, or (b) traffic to the server must be forwarded through the default router. Only add a special bypass route for the OpenVPN server if (b) is true. If (a) is true, behave as if the 'local' flag is specified, and do not add a bypass route. The new 'autolocal' flag depends on the non-portable test_local_addr() function in route.c, which is currently only implemented for Windows. The 'autolocal' flag will act as a no-op on platforms that have not yet defined a test_local_addr() function. Increased TLS_CHANNEL_BUF_SIZE to 2048 from 1024 (this will allow for more option content to be pushed from server to client). Raised D_MULTI_DROPPED debug level to 4 from 3. Version 2.1_rc16b. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@4446 e7ae566f-a301-0410-adde-c780ea21d3b5 --- common.h | 2 +- errlevel.h | 16 ++++----- options.c | 2 ++ route.c | 117 +++++++++++++++++++++++++++++++++++++++++++++++++------------ route.h | 13 +++++++ version.m4 | 2 +- 6 files changed, 119 insertions(+), 33 deletions(-) diff --git a/common.h b/common.h index bc38699..69cae4c 100644 --- a/common.h +++ b/common.h @@ -79,7 +79,7 @@ typedef unsigned long ptr_type; * the full --push/--pull list. If you increase it, do so * on both server and client. */ -#define TLS_CHANNEL_BUF_SIZE 1024 +#define TLS_CHANNEL_BUF_SIZE 2048 /* * A sort of pseudo-filename for data provided inline within diff --git a/errlevel.h b/errlevel.h index 1abe21d..ed64516 100644 --- a/errlevel.h +++ b/errlevel.h @@ -88,14 +88,13 @@ #define D_BACKTRACK LOGLEV(3, 36, 0) /* show replay backtracks */ #define D_AUTH LOGLEV(3, 37, 0) /* show user/pass auth info */ #define D_MULTI_LOW LOGLEV(3, 38, 0) /* show point-to-multipoint low-freq debug info */ -#define D_MULTI_DROPPED LOGLEV(3, 39, 0) /* show point-to-multipoint packet drops */ -#define D_PLUGIN LOGLEV(3, 40, 0) /* show plugin calls */ -#define D_MANAGEMENT LOGLEV(3, 41, 0) /* show --management info */ -#define D_SCHED_EXIT LOGLEV(3, 42, 0) /* show arming of scheduled exit */ -#define D_ROUTE_QUOTA LOGLEV(3, 43, 0) /* show route quota exceeded messages */ -#define D_OSBUF LOGLEV(3, 44, 0) /* show socket/tun/tap buffer sizes */ -#define D_PS_PROXY LOGLEV(3, 45, 0) /* messages related to --port-share option */ -#define D_PF_INFO LOGLEV(3, 46, 0) /* packet filter informational messages */ +#define D_PLUGIN LOGLEV(3, 39, 0) /* show plugin calls */ +#define D_MANAGEMENT LOGLEV(3, 40, 0) /* show --management info */ +#define D_SCHED_EXIT LOGLEV(3, 41, 0) /* show arming of scheduled exit */ +#define D_ROUTE_QUOTA LOGLEV(3, 42, 0) /* show route quota exceeded messages */ +#define D_OSBUF LOGLEV(3, 43, 0) /* show socket/tun/tap buffer sizes */ +#define D_PS_PROXY LOGLEV(3, 44, 0) /* messages related to --port-share option */ +#define D_PF_INFO LOGLEV(3, 45, 0) /* packet filter informational messages */ #define D_SHOW_PARMS LOGLEV(4, 50, 0) /* show all parameters on program initiation */ #define D_SHOW_OCC LOGLEV(4, 51, 0) /* show options compatibility string */ @@ -104,6 +103,7 @@ #define D_MBUF LOGLEV(4, 54, 0) /* mbuf.[ch] routines */ #define D_PACKET_TRUNC_ERR LOGLEV(4, 55, 0) /* PACKET_TRUNCATION_CHECK */ #define D_PF_DROPPED LOGLEV(4, 56, 0) /* packet filter dropped a packet */ +#define D_MULTI_DROPPED LOGLEV(4, 57, 0) /* show point-to-multipoint packet drops */ #define D_LOG_RW LOGLEV(5, 0, 0) /* Print 'R' or 'W' to stdout for read/write */ diff --git a/options.c b/options.c index ab75f6a..ddf9f35 100644 --- a/options.c +++ b/options.c @@ -4404,6 +4404,8 @@ add_option (struct options *options, options->routes->flags |= RG_REROUTE_GW; if (streq (p[j], "local")) options->routes->flags |= RG_LOCAL; + else if (streq (p[j], "autolocal")) + options->routes->flags |= RG_AUTO_LOCAL; else if (streq (p[j], "def1")) options->routes->flags |= RG_DEF1; else if (streq (p[j], "bypass-dhcp")) diff --git a/route.c b/route.c index 68b0fa3..8eccbc1 100644 --- a/route.c +++ b/route.c @@ -50,7 +50,7 @@ print_bypass_addresses (const struct route_bypass *rb) int i; for (i = 0; i < rb->n_bypass; ++i) { - msg (D_ROUTE_DEBUG, "ROUTE DEBUG: bypass_host_route[%d]=%s", + msg (D_ROUTE, "ROUTE: bypass_host_route[%d]=%s", i, print_in_addr_t (rb->bypass[i], 0, &gc)); } @@ -379,7 +379,7 @@ init_route_list (struct route_list *rl, } else { - dmsg (D_ROUTE_DEBUG, "ROUTE DEBUG: default_gateway=UNDEF"); + dmsg (D_ROUTE, "ROUTE: default_gateway=UNDEF"); } if (rl->flags & RG_ENABLE) @@ -531,14 +531,31 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u } else { - /* route remote host to original default gateway */ - if (!(rl->flags & RG_LOCAL)) - add_route3 (rl->spec.remote_host, - ~0, - rl->spec.net_gateway, - tt, - flags, - es); + bool local = BOOL_CAST(rl->flags & RG_LOCAL); + if (rl->flags & RG_AUTO_LOCAL) { + const int tla = test_local_addr (rl->spec.remote_host); + if (tla == TLA_NONLOCAL) + { + dmsg (D_ROUTE, "ROUTE remote_host is NOT LOCAL"); + local = false; + } + else if (tla == TLA_LOCAL) + { + dmsg (D_ROUTE, "ROUTE remote_host is LOCAL"); + local = true; + } + } + if (!local) + { + /* route remote host to original default gateway */ + add_route3 (rl->spec.remote_host, + ~0, + rl->spec.net_gateway, + tt, + flags, + es); + rl->did_local = true; + } /* route DHCP/DNS server traffic through original default gateway */ add_bypass_routes (&rl->spec.bypass, rl->spec.net_gateway, tt, flags, es); @@ -595,13 +612,16 @@ undo_redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap * if (rl->did_redirect_default_gateway) { /* delete remote host route */ - if (!(rl->flags & RG_LOCAL)) - del_route3 (rl->spec.remote_host, - ~0, - rl->spec.net_gateway, - tt, - flags, - es); + if (rl->did_local) + { + del_route3 (rl->spec.remote_host, + ~0, + rl->spec.net_gateway, + tt, + flags, + es); + rl->did_local = false; + } /* delete special DHCP/DNS bypass route */ del_bypass_routes (&rl->spec.bypass, rl->spec.net_gateway, tt, flags, es); @@ -2080,14 +2100,14 @@ netmask_to_netbits (const in_addr_t network, const in_addr_t netmask, int *netbi #if defined(WIN32) static void -add_host_route_if_nonlocal (struct route_bypass *rb, const in_addr_t addr, const IP_ADAPTER_INFO *dgi) +add_host_route_if_nonlocal (struct route_bypass *rb, const in_addr_t addr) { - if (!is_ip_in_adapter_subnet (dgi, addr, NULL) && addr != 0 && addr != ~0) + if (test_local_addr(addr) == TLA_NONLOCAL && addr != 0 && addr != ~0) add_bypass_address (rb, addr); } static void -add_host_route_array (struct route_bypass *rb, const IP_ADAPTER_INFO *dgi, const IP_ADDR_STRING *iplist) +add_host_route_array (struct route_bypass *rb, const IP_ADDR_STRING *iplist) { while (iplist) { @@ -2095,7 +2115,7 @@ add_host_route_array (struct route_bypass *rb, const IP_ADAPTER_INFO *dgi, const const in_addr_t ip = getaddr (GETADDR_HOST_ORDER, iplist->IpAddress.String, 0, &succeed, NULL); if (succeed) { - add_host_route_if_nonlocal (rb, ip, dgi); + add_host_route_if_nonlocal (rb, ip); } iplist = iplist->Next; } @@ -2123,11 +2143,11 @@ get_bypass_addresses (struct route_bypass *rb, const unsigned int flags) /* Bypass DHCP server address */ if ((flags & RG_BYPASS_DHCP) && dgi && dgi->DhcpEnabled) - add_host_route_array (rb, dgi, &dgi->DhcpServer); + add_host_route_array (rb, &dgi->DhcpServer); /* Bypass DNS server addresses */ if ((flags & RG_BYPASS_DNS) && pai) - add_host_route_array (rb, dgi, &pai->DnsServerList); + add_host_route_array (rb, &pai->DnsServerList); } gc_free (&gc); @@ -2290,3 +2310,54 @@ get_default_gateway_mac_addr (unsigned char *macaddr) #endif #endif /* AUTO_USERID */ + +/* + * Test if addr is reachable via a local interface (return ILA_LOCAL), + * or if it needs to be routed via the default gateway (return + * ILA_NONLOCAL). If the target platform doesn't implement this + * function, return ILA_NOT_IMPLEMENTED. + * + * Used by redirect-gateway autolocal feature + */ + +#if defined(WIN32) + +int +test_local_addr (const in_addr_t addr) +{ + struct gc_arena gc = gc_new (); + const in_addr_t nonlocal_netmask = 0x80000000L; /* routes with netmask <= to this are considered non-local */ + bool ret = TLA_NONLOCAL; + + /* get full routing table */ + const MIB_IPFORWARDTABLE *rt = get_windows_routing_table (&gc); + if (rt) + { + int i; + for (i = 0; i < rt->dwNumEntries; ++i) + { + const MIB_IPFORWARDROW *row = &rt->table[i]; + const in_addr_t net = ntohl (row->dwForwardDest); + const in_addr_t mask = ntohl (row->dwForwardMask); + if (mask > nonlocal_netmask && (addr & mask) == net) + { + ret = TLA_LOCAL; + break; + } + } + } + + gc_free (&gc); + return ret; +} + +#else + + +int +test_local_addr (const in_addr_t addr) +{ + return TLA_NOT_IMPLEMENTED; +} + +#endif diff --git a/route.h b/route.h index 27ac623..a2654a20 100644 --- a/route.h +++ b/route.h @@ -83,6 +83,7 @@ struct route_option { #define RG_BYPASS_DHCP (1<<3) #define RG_BYPASS_DNS (1<<4) #define RG_REROUTE_GW (1<<5) +#define RG_AUTO_LOCAL (1<<6) struct route_option_list { int n; @@ -105,6 +106,7 @@ struct route_list { struct route_special_addr spec; unsigned int flags; bool did_redirect_default_gateway; + bool did_local; int n; struct route routes[MAX_ROUTES]; }; @@ -159,6 +161,17 @@ bool is_special_addr (const char *addr_str); bool get_default_gateway (in_addr_t *ip, in_addr_t *netmask); +/* + * Test if addr is reachable via a local interface (return ILA_LOCAL), + * or if it needs to be routed via the default gateway (return + * ILA_NONLOCAL). If the current platform doesn't implement this + * function, return ILA_NOT_IMPLEMENTED. + */ +#define TLA_NOT_IMPLEMENTED 0 +#define TLA_NONLOCAL 1 +#define TLA_LOCAL 2 +int test_local_addr (const in_addr_t addr); + #if AUTO_USERID bool get_default_gateway_mac_addr (unsigned char *macaddr); #endif diff --git a/version.m4 b/version.m4 index e98e330..6cf35d5 100644 --- a/version.m4 +++ b/version.m4 @@ -1,5 +1,5 @@ dnl define the OpenVPN version -define(PRODUCT_VERSION,[2.1_rc16]) +define(PRODUCT_VERSION,[2.1_rc16b]) dnl define the TAP version define(PRODUCT_TAP_ID,[tap0901]) define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9]) -- cgit