Package: openvpn
Version: 2.1.0-3
Severity: normal
Tags: patch
In this situation:
mas...@doggy:~$ /sbin/ip route list exact 0.0.0.0/0
default dev ppp0 scope link
mas...@doggy:~$ head -n1 /proc/net/route; awk '$2==00000000' /proc/net/route
Iface Destination Gateway Flags RefCnt Use Metric Mask
MTU Window IRTT
ppp0 00000000 00000000 0001 0 0 0
00000000 0 0 0
the "redirect-gateway" option fails:
ovpn: NOTE: unable to redirect default gateway -- Cannot read current default
gateway from system
While that option is indeed called "redirect-gateway", I feel its
expected behaviour is better described by "redirect-default-route".
The attached patch makes it work in this scenario, on Linux only. It
makes the minimal work to make this scenario work cleanly; the full
work would probably be to expand the notion of route everywhere in the
code not to expect a gateway, but a gateway, a device or both.
-- System Information:
Debian Release: 5.0.5
APT prefers stable
APT policy: (500, 'stable'), (400, 'testing'), (300, 'unstable')
Architecture: amd64 (x86_64)
Kernel: Linux 2.6.32-5-amd64 (SMP w/2 CPU cores)
Locale: LANG=fr_LU.UTF-8, LC_CTYPE=fr_LU.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
Versions of packages openvpn depends on:
ii debconf [debconf-2.0] 1.5.24 Debian configuration management sy
ii libc6 2.11.2-2 Embedded GNU C Library: Shared lib
ii liblzo2-2 2.03-1 data compression library
ii libpam0g 1.0.1-5+lenny1 Pluggable Authentication Modules l
ii libpkcs11-helper1 1.05-1 library that simplifies the intera
ii libssl0.9.8 0.9.8o-1 SSL shared libraries
ii net-tools 1.60-22 The NET-3 networking toolkit
ii openssl-blacklist 0.5-2 list of blacklisted OpenSSL RSA ke
ii openvpn-blacklist 0.4 list of blacklisted OpenVPN RSA sh
openvpn recommends no packages.
Versions of packages openvpn suggests:
ii openssl 0.9.8g-15+lenny7 Secure Socket Layer (SSL) binary a
ii resolvconf 1.46 name server information handler
-- debconf information:
openvpn/vulnerable_prng:
openvpn/create_tun: false
Index: openvpn-2.1.0.lio/route.c
===================================================================
--- openvpn-2.1.0.lio.orig/route.c 2010-08-07 12:50:11.000000000 +0200
+++ openvpn-2.1.0.lio/route.c 2010-08-07 12:50:33.000000000 +0200
@@ -140,7 +140,7 @@
}
static void
-setenv_route_addr (struct env_set *es, const char *key, const in_addr_t addr,
int i)
+setenv_route_str (struct env_set *es, const char *key, const char *str, int i)
{
struct gc_arena gc = gc_new ();
struct buffer name = alloc_buf_gc (256, &gc);
@@ -148,7 +148,15 @@
buf_printf (&name, "route_%s_%d", key, i);
else
buf_printf (&name, "route_%s", key);
- setenv_str (es, BSTR (&name), print_in_addr_t (addr, 0, &gc));
+ setenv_str (es, BSTR (&name), str);
+ gc_free (&gc);
+}
+
+static void
+setenv_route_addr (struct env_set *es, const char *key, const in_addr_t addr,
int i)
+{
+ struct gc_arena gc = gc_new ();
+ setenv_route_str (es, key, print_in_addr_t (addr, 0, &gc), i);
gc_free (&gc);
}
@@ -180,7 +188,7 @@
if (spec)
{
if (spec->net_gateway_defined)
- *out = spec->net_gateway;
+ *out = spec->net_gateway.net_gateway_addr;
else
{
msg (M_INFO, PACKAGE_NAME " ROUTE: net_gateway undefined --
unable to get default gateway from system");
@@ -397,8 +405,12 @@
rl->spec.net_gateway_defined = get_default_gateway (&rl->spec.net_gateway,
NULL);
if (rl->spec.net_gateway_defined)
{
- setenv_route_addr (es, "net_gateway", rl->spec.net_gateway, -1);
- dmsg (D_ROUTE, "ROUTE default_gateway=%s", print_in_addr_t
(rl->spec.net_gateway, 0, &gc));
+ setenv_route_addr (es, "net_gateway",
rl->spec.net_gateway.net_gateway_addr, -1);
+ setenv_route_str (es, "net_gateway_dev",
rl->spec.net_gateway.net_gateway_dev, -1);
+ dmsg (D_ROUTE,
+ "ROUTE default_gateway=%s dev=%s",
+ print_in_addr_t (rl->spec.net_gateway.net_gateway_addr, 0, &gc),
+ rl->spec.net_gateway.net_gateway_dev);
}
else
{
@@ -474,6 +486,7 @@
r.network = network;
r.netmask = netmask;
r.gateway = gateway;
+ r.dev[0] = '\0';
add_route (&r, tt, flags, es);
}
@@ -495,8 +508,44 @@
}
static void
+add_route4 (in_addr_t network,
+ in_addr_t netmask,
+ net_gateway_t gateway,
+ const struct tuntap *tt,
+ unsigned int flags,
+ const struct env_set *es)
+{
+ struct route r;
+ CLEAR (r);
+ r.defined = true;
+ r.network = network;
+ r.netmask = netmask;
+ r.gateway = gateway.net_gateway_addr;
+ strncpy(r.dev,gateway.net_gateway_dev, IF_NAME_SIZE);
+ add_route (&r, tt, flags, es);
+}
+
+static void
+del_route4 (in_addr_t network,
+ in_addr_t netmask,
+ net_gateway_t gateway,
+ const struct tuntap *tt,
+ unsigned int flags,
+ const struct env_set *es)
+{
+ struct route r;
+ CLEAR (r);
+ r.defined = true;
+ r.network = network;
+ r.netmask = netmask;
+ r.gateway = gateway.net_gateway_addr;
+ strncpy(r.dev,gateway.net_gateway_dev, IF_NAME_SIZE);
+ delete_route (&r, tt, flags, es);
+}
+
+static void
add_bypass_routes (struct route_bypass *rb,
- in_addr_t gateway,
+ net_gateway_t gateway,
const struct tuntap *tt,
unsigned int flags,
const struct env_set *es)
@@ -504,8 +553,8 @@
int i;
for (i = 0; i < rb->n_bypass; ++i)
{
- if (rb->bypass[i] != gateway)
- add_route3 (rb->bypass[i],
+ if (rb->bypass[i] != gateway.net_gateway_addr)
+ add_route4 (rb->bypass[i],
~0,
gateway,
tt,
@@ -516,7 +565,7 @@
static void
del_bypass_routes (struct route_bypass *rb,
- in_addr_t gateway,
+ net_gateway_t gateway,
const struct tuntap *tt,
unsigned int flags,
const struct env_set *es)
@@ -524,8 +573,8 @@
int i;
for (i = 0; i < rb->n_bypass; ++i)
{
- if (rb->bypass[i] != gateway)
- del_route3 (rb->bypass[i],
+ if (rb->bypass[i] != gateway.net_gateway_addr)
+ del_route4 (rb->bypass[i],
~0,
gateway,
tt,
@@ -577,7 +626,7 @@
* adding this special /32 route */
if (rl->spec.remote_host != IPV4_INVALID_ADDR) {
#endif
- add_route3 (rl->spec.remote_host,
+ add_route4 (rl->spec.remote_host,
~0,
rl->spec.net_gateway,
tt,
@@ -617,7 +666,7 @@
else
{
/* delete default route */
- del_route3 (0,
+ del_route4 (0,
0,
rl->spec.net_gateway,
tt,
@@ -648,7 +697,7 @@
/* delete remote host route */
if (rl->did_local)
{
- del_route3 (rl->spec.remote_host,
+ del_route4 (rl->spec.remote_host,
~0,
rl->spec.net_gateway,
tt,
@@ -691,7 +740,7 @@
es);
/* restore original default route */
- add_route3 (0,
+ add_route4 (0,
0,
rl->spec.net_gateway,
tt,
@@ -814,6 +863,7 @@
setenv_route_addr (es, "network", r->network, i);
setenv_route_addr (es, "netmask", r->netmask, i);
setenv_route_addr (es, "gateway", r->gateway, i);
+ setenv_route_str (es, "device", r->dev, i);
if (r->metric_defined)
{
@@ -870,15 +920,20 @@
network,
count_netmask_bits(netmask),
gateway);
+ if (r->dev[0])
+ argv_printf_cat (&argv, "dev %s", r->dev);
if (r->metric_defined)
argv_printf_cat (&argv, "metric %d", r->metric);
#else
- argv_printf (&argv, "%s add -net %s netmask %s gw %s",
+ argv_printf (&argv, "%s add -net %s netmask %s",
ROUTE_PATH,
network,
- netmask,
- gateway);
+ netmask);
+ if (r->gateway)
+ argv_printf_cat (&argv, "gw %s", gateway);
+ if (r->dev[0])
+ argv_printf_cat (&argv, "dev %s", r->dev);
if (r->metric_defined)
argv_printf_cat (&argv, "metric %d", r->metric);
#endif /*CONFIG_FEATURE_IPROUTE*/
@@ -1313,7 +1368,7 @@
}
bool
-get_default_gateway (in_addr_t *gw, in_addr_t *netmask)
+get_default_gateway (net_gateway_t *gw, in_addr_t *netmask)
{
struct gc_arena gc = gc_new ();
bool ret_bool = false;
@@ -1535,7 +1590,7 @@
#elif defined(TARGET_LINUX)
bool
-get_default_gateway (in_addr_t *gateway, in_addr_t *netmask)
+get_default_gateway (net_gateway_t *gateway, in_addr_t *netmask)
{
struct gc_arena gc = gc_new ();
bool ret = false;
@@ -1546,7 +1601,7 @@
int count = 0;
int best_count = 0;
unsigned int lowest_metric = ~0;
- in_addr_t best_gw = 0;
+ net_gateway_t best_gw = NET_GATEWAY_NULL;
while (fgets (line, sizeof (line), fp) != NULL)
{
if (count)
@@ -1555,27 +1610,32 @@
unsigned int mask_x = 0;
unsigned int gw_x = 0;
unsigned int metric = 0;
- const int np = sscanf (line, "%*s\t%x\t%x\t%*s\t%*s\t%*s\t%d\t%x",
+ char dev[IF_NAME_SIZE];
+ dev[0] = '\0';
+ const int np = sscanf (line, "%s\t%x\t%x\t%*s\t%*s\t%*s\t%d\t%x",
+ dev,
&net_x,
&gw_x,
&metric,
&mask_x);
- if (np == 4)
+ if (np == 5)
{
const in_addr_t net = ntohl (net_x);
const in_addr_t mask = ntohl (mask_x);
- const in_addr_t gw = ntohl (gw_x);
+ const in_addr_t gw_addr = ntohl (gw_x);
- dmsg (D_ROUTE_DEBUG, "GDG: route[%d] %s/%s/%s m=%u",
+ dmsg (D_ROUTE_DEBUG, "GDG: route[%d] %s/%s/%s m=%u dev=%s",
count,
print_in_addr_t ((in_addr_t) net, 0, &gc),
print_in_addr_t ((in_addr_t) mask, 0, &gc),
- print_in_addr_t ((in_addr_t) gw, 0, &gc),
- metric);
+ print_in_addr_t ((in_addr_t) gw_addr, 0, &gc),
+ metric,
+ dev);
if (!net && !mask && metric < lowest_metric)
{
- best_gw = gw;
+ best_gw.net_gateway_addr = gw_addr;
+ strncpy(best_gw.net_gateway_dev, dev, IF_NAME_SIZE);
lowest_metric = metric;
best_count = count;
}
@@ -1585,7 +1645,7 @@
}
fclose (fp);
- if (best_gw)
+ if (best_gw.net_gateway_addr || best_gw.net_gateway_dev[0])
{
*gateway = best_gw;
if (netmask)
@@ -1595,8 +1655,9 @@
ret = true;
}
- dmsg (D_ROUTE_DEBUG, "GDG: best=%s[%d] lm=%u",
- print_in_addr_t ((in_addr_t) best_gw, 0, &gc),
+ dmsg (D_ROUTE_DEBUG, "GDG: best=%s dev '%s' [%d] lm=%u",
+ print_in_addr_t ((in_addr_t) best_gw.net_gateway_addr, 0, &gc),
+ best_gw.net_gateway_dev,
best_count,
(unsigned int)lowest_metric);
}
Index: openvpn-2.1.0.lio/route.h
===================================================================
--- openvpn-2.1.0.lio.orig/route.h 2010-08-07 12:50:11.000000000 +0200
+++ openvpn-2.1.0.lio/route.h 2010-08-07 12:50:33.000000000 +0200
@@ -56,11 +56,18 @@
in_addr_t bypass[N_ROUTE_BYPASS];
};
+#define IF_NAME_SIZE 128
+typedef struct {
+ in_addr_t net_gateway_addr;
+ char net_gateway_dev[IF_NAME_SIZE];
+} net_gateway_t;
+#define NET_GATEWAY_NULL {0, ""}
+
struct route_special_addr
{
in_addr_t remote_endpoint;
bool remote_endpoint_defined;
- in_addr_t net_gateway;
+ net_gateway_t net_gateway;
bool net_gateway_defined;
in_addr_t remote_host;
bool remote_host_defined;
@@ -98,6 +105,7 @@
in_addr_t network;
in_addr_t netmask;
in_addr_t gateway;
+ char dev[IF_NAME_SIZE];
bool metric_defined;
int metric;
};
@@ -161,7 +169,7 @@
bool is_special_addr (const char *addr_str);
-bool get_default_gateway (in_addr_t *ip, in_addr_t *netmask);
+bool get_default_gateway (net_gateway_t *gateway, in_addr_t *netmask);
/*
* Test if addr is reachable via a local interface (return ILA_LOCAL),
Index: openvpn-2.1.0.lio/tun.c
===================================================================
--- openvpn-2.1.0.lio.orig/tun.c 2010-08-07 12:56:04.000000000 +0200
+++ openvpn-2.1.0.lio/tun.c 2010-08-07 12:56:46.000000000 +0200
@@ -271,12 +271,12 @@
const char *prefix)
{
struct gc_arena gc = gc_new ();
- in_addr_t lan_gw = 0;
+ net_gateway_t lan_gw = NET_GATEWAY_NULL;
in_addr_t lan_netmask = 0;
if (get_default_gateway (&lan_gw, &lan_netmask))
{
- const in_addr_t lan_network = lan_gw & lan_netmask;
+ const in_addr_t lan_network = lan_gw.net_gateway_addr & lan_netmask;
const in_addr_t network = ip & netmask;
/* do the two subnets defined by network/netmask and
lan_network/lan_netmask intersect? */
@@ -298,12 +298,12 @@
warn_on_use_of_common_subnets (void)
{
struct gc_arena gc = gc_new ();
- in_addr_t lan_gw = 0;
+ net_gateway_t lan_gw = NET_GATEWAY_NULL;
in_addr_t lan_netmask = 0;
if (get_default_gateway (&lan_gw, &lan_netmask))
{
- const in_addr_t lan_network = lan_gw & lan_netmask;
+ const in_addr_t lan_network = lan_gw.net_gateway_addr & lan_netmask;
if (lan_network == 0xC0A80000 || lan_network == 0xC0A80100)
msg (M_WARN, "NOTE: your local LAN uses the extremely common subnet
address 192.168.0.x or 192.168.1.x. Be aware that this might create routing
conflicts if you connect to the VPN server from public locations such as
internet cafes that use the same subnet.");
}