#include "memdbg.h"
static void delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
-static bool get_default_gateway (in_addr_t *ret);
static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags);
#ifdef ENABLE_DEBUG
rl->spec.default_metric_defined = true;
}
- rl->spec.net_gateway_defined = get_default_gateway (&rl->spec.net_gateway);
+ 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_DEBUG, "ROUTE DEBUG: default_gateway=%s", print_in_addr_t (rl->spec.net_gateway, 0, &gc));
+ dmsg (D_ROUTE, "ROUTE default_gateway=%s", print_in_addr_t (rl->spec.net_gateway, 0, &gc));
}
else
{
for (i = 0; i < rl->n; ++i)
{
+ struct route *r = &rl->routes[i];
+ check_subnet_conflict (r->network, r->netmask, "route");
if (flags & ROUTE_DELETE_FIRST)
- delete_route (&rl->routes[i], tt, flags, es);
- add_route (&rl->routes[i], tt, flags, es);
+ delete_route (r, tt, flags, es);
+ add_route (r, tt, flags, es);
}
rl->routes_added = true;
}
DWORD *index)
{
int count = 0;
- DWORD i = adapter_index_of_ip (adapters, gateway, &count);
+ DWORD i = adapter_index_of_ip (adapters, gateway, &count, NULL);
if (index)
*index = i;
return count;
return ret;
}
-static bool
-get_default_gateway (in_addr_t *ret)
+bool
+get_default_gateway (in_addr_t *gw, in_addr_t *netmask)
{
struct gc_arena gc = gc_new ();
bool ret_bool = false;
+ const IP_ADAPTER_INFO *adapters = get_adapter_info_list (&gc);
const MIB_IPFORWARDTABLE *routes = get_windows_routing_table (&gc);
const MIB_IPFORWARDROW *row = get_default_gateway_row (routes);
if (row)
{
- *ret = ntohl (row->dwForwardNextHop);
+ *gw = ntohl (row->dwForwardNextHop);
+ if (netmask)
+ {
+ if (adapter_index_of_ip (adapters, *gw, NULL, netmask) == ~0)
+ *netmask = ~0;
+ }
ret_bool = true;
}
#elif defined(TARGET_LINUX)
-static bool
-get_default_gateway (in_addr_t *gateway)
+bool
+get_default_gateway (in_addr_t *gateway, in_addr_t *netmask)
{
struct gc_arena gc = gc_new ();
bool ret = false;
if (best_gw)
{
*gateway = best_gw;
+ if (netmask)
+ {
+ *netmask = 0xFFFFFF00; // FIXME -- get the real netmask of the adapter containing the default gateway
+ }
ret = true;
}
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-static bool
-get_default_gateway (in_addr_t *ret)
+bool
+get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
{
struct gc_arena gc = gc_new ();
int s, seq, l, pid, rtm_addrs, i;
if (gate != NULL )
{
*ret = ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr);
-#if 1
+#if 0
msg (M_INFO, "gw %s",
print_in_addr_t ((in_addr_t) *ret, 0, &gc));
#endif
+ if (netmask)
+ {
+ *netmask = 0xFFFFFF00; // FIXME -- get the real netmask of the adapter containing the default gateway
+ }
+
gc_free (&gc);
return true;
}
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-static bool
-get_default_gateway (in_addr_t *ret)
+bool
+get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
{
struct gc_arena gc = gc_new ();
int s, seq, l, pid, rtm_addrs, i;
if (gate != NULL )
{
*ret = ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr);
-#if 1
+#if 0
msg (M_INFO, "gw %s",
print_in_addr_t ((in_addr_t) *ret, 0, &gc));
#endif
+ if (netmask)
+ {
+ *netmask = 0xFFFFFF00; // FIXME -- get the real netmask of the adapter containing the default gateway
+ }
+
gc_free (&gc);
return true;
}
#define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-static bool
-get_default_gateway (in_addr_t *ret)
+bool
+get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
{
struct gc_arena gc = gc_new ();
int s, seq, l, rtm_addrs, i;
if (gate != NULL )
{
*ret = ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr);
-#if 1
+#if 0
msg (M_INFO, "gw %s",
print_in_addr_t ((in_addr_t) *ret, 0, &gc));
#endif
+ if (netmask)
+ {
+ *netmask = 0xFFFFFF00; // FIXME -- get the real netmask of the adapter containing the default gateway
+ }
+
gc_free (&gc);
return true;
}
#else
-static bool
-get_default_gateway (in_addr_t *ret)
+bool
+get_default_gateway (in_addr_t *ret, in_addr_t *netmask)
{
return false;
}
in_addr_t gwip = 0;
bool ret = false;
- if (!get_default_gateway (&gwip))
+ if (!get_default_gateway (&gwip, NULL))
{
msg (M_WARN, "GDGMA: get_default_gateway failed");
goto err;
DWORD a_index;
const IP_ADAPTER_INFO *ai;
- if (!get_default_gateway (&gwip))
+ if (!get_default_gateway (&gwip, NULL))
{
msg (M_WARN, "GDGMA: get_default_gateway failed");
goto err;
}
- a_index = adapter_index_of_ip (adapters, gwip, NULL);
+ a_index = adapter_index_of_ip (adapters, gwip, NULL, NULL);
ai = get_adapter (adapters, a_index);
if (!ai)
gc_free (&gc);
}
+/*
+ * Issue a warning if ip/netmask (on the virtual IP network) conflicts with
+ * the settings on the local LAN. This is designed to flag issues where
+ * (for example) the OpenVPN server LAN is running on 192.168.1.x, but then
+ * an OpenVPN client tries to connect from a public location that is also running
+ * off of a router set to 192.168.1.x.
+ */
+void
+check_subnet_conflict (const in_addr_t ip,
+ const in_addr_t netmask,
+ const char *prefix)
+{
+ struct gc_arena gc = gc_new ();
+ in_addr_t lan_gw = 0;
+ 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 network = ip & netmask;
+
+ /* do the two subnets defined by network/netmask and lan_network/lan_netmask intersect? */
+ if ((network & lan_netmask) == lan_network
+ || (lan_network & netmask) == network)
+ {
+ msg (M_WARN, "WARNING: potential %s subnet conflict between local LAN [%s/%s] and remote VPN [%s/%s]",
+ prefix,
+ print_in_addr_t (lan_network, 0, &gc),
+ print_in_addr_t (lan_netmask, 0, &gc),
+ print_in_addr_t (network, 0, &gc),
+ print_in_addr_t (netmask, 0, &gc));
+ }
+ }
+ gc_free (&gc);
+}
+
+void
+warn_on_use_of_common_subnets (void)
+{
+ struct gc_arena gc = gc_new ();
+ in_addr_t lan_gw = 0;
+ in_addr_t lan_netmask = 0;
+
+ if (get_default_gateway (&lan_gw, &lan_netmask))
+ {
+ const in_addr_t lan_network = lan_gw & 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.");
+ }
+ gc_free (&gc);
+}
+
/*
* Complain if --dev tap and --ifconfig is used on an OS for which
* we don't have a custom tap ifconfig template below.
remote_public,
tt->local,
tt->remote_netmask);
+
+ if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET))
+ check_subnet_conflict (tt->local, tt->remote_netmask, "TUN/TAP adapter");
+ else if (tt->type == DEV_TYPE_TUN)
+ check_subnet_conflict (tt->local, ~0, "TUN/TAP adapter");
}
/*
}
DWORD
-adapter_index_of_ip (const IP_ADAPTER_INFO *list, const in_addr_t ip, int *count)
+adapter_index_of_ip (const IP_ADAPTER_INFO *list,
+ const in_addr_t ip,
+ int *count,
+ in_addr_t *netmask)
{
struct gc_arena gc = gc_new ();
DWORD ret = ~0;
if (ret == ~0 && count)
*count = 0;
+ if (netmask)
+ *netmask = highest_netmask;
+
gc_free (&gc);
return ret;
}