Re[2]: NetworkManager VPN and routing in bridged mode
- From: Valentine Sinitsyn <valentine sinitsyn usu ru>
- To: NetworkManager-list gnome org, Dan Williams <dcbw redhat com>
- Subject: Re[2]: NetworkManager VPN and routing in bridged mode
- Date: Fri, 14 Mar 2008 00:41:11 +0500
Hello,
The attached is updated version of the patch I've sent yesterday. The
main changes are as follows:
* Ported to NM 0.6.6 (SVN rev 3381)
* Handle user-specified routes correctly too
There are some "architectural" issues with the code - I've implemented
them the way to be as much backward-compatible as possible, nevertheless
they should be probably refactored in future. They are:
- handling of 11th arg (remote_gateway) in D-BUS message in
nm-vpn-service.c: it's no different from 10th, 9th, ... arg, so it
should be sent by all VPN daemons (set to zero if there is no remote
gateway i.e. we are dealing with P-t-P device) and warning should be
generated if it can't be found. It's not difficult to implement but I
have no setup to test pptp/vpnc and modify them accordingly.
- nm_system_device_set_ip4_route_with_iface(). Essentially, I've
reworked the function to accept interface name instead of NMDevice *
and create routes without RTF_GATEWAY flag if necessary. For now, an
older nm_system_device_set_ip4_route() acts as a wrapper to this.
P.S. In the very side note - what about
http://bugzilla.gnome.org/show_bug.cgi?id=353265 ? It's fixed for 0.7
but still not committed to 0.6 branch.
--
Regards,
Valentine Sinitsyn
Index: src/nm-ip4-config.c
===================================================================
--- src/nm-ip4-config.c (revision 3447)
+++ src/nm-ip4-config.c (working copy)
@@ -43,6 +43,8 @@
guint32 mtu; /* Maximum Transmission Unit of the interface */
guint32 mss; /* Maximum Segment Size of the route */
+
+ guint32 remote_gateway; /* Used for VPN networks with tap-style virtual device */
GSList * nameservers;
GSList * domains;
@@ -56,6 +58,7 @@
* an IP4Config before it can be used.
*/
gboolean secondary;
+
};
@@ -357,6 +360,20 @@
config->mss = mss;
}
+guint32 nm_ip4_config_get_remote_gateway (NMIP4Config *config)
+{
+ g_return_val_if_fail (config != NULL, 0);
+
+ return config->remote_gateway;
+}
+
+void nm_ip4_config_set_remote_gateway (NMIP4Config *config, guint32 remote_gateway)
+{
+ g_return_if_fail (config != NULL);
+
+ config->remote_gateway = remote_gateway;
+}
+
/* libnl convenience/conversion functions */
static int ip4_addr_to_rtnl_local (guint32 ip4_address, struct rtnl_addr *addr)
Index: src/nm-ip4-config.h
===================================================================
--- src/nm-ip4-config.h (revision 3447)
+++ src/nm-ip4-config.h (working copy)
@@ -74,6 +74,9 @@
guint32 nm_ip4_config_get_mss (NMIP4Config *config);
void nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss);
+guint32 nm_ip4_config_get_remote_gateway (NMIP4Config *config);
+void nm_ip4_config_set_remote_gateway (NMIP4Config *config, guint32 remote_gateway);
+
/* Flags for nm_ip4_config_to_rtnl_addr() */
#define NM_RTNL_ADDR_NONE 0x0000
#define NM_RTNL_ADDR_ADDR 0x0001
Index: src/vpn-manager/nm-vpn-service.c
===================================================================
--- src/vpn-manager/nm-vpn-service.c (revision 3447)
+++ src/vpn-manager/nm-vpn-service.c (working copy)
@@ -841,6 +841,17 @@
if (!get_dbus_string_helper (&iter, &login_banner, "Login Banner"))
goto out;
+ /* Eleventh arg: Remote VPN Gateway (UINT32)
+ * For now, only OpenVPN service knows about it so we won't complain
+ * if it is absent from the message.
+ */
+ if (dbus_message_iter_next (&iter)
+ && (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_UINT32))
+ {
+ dbus_message_iter_get_basic (&iter, &num);
+ nm_ip4_config_set_remote_gateway (config, num);
+ }
+
#ifdef NM_DEBUG_VPN_CONFIG
print_vpn_config (ip4_vpn_gateway,
tundev,
Index: src/NetworkManagerSystem.c
===================================================================
--- src/NetworkManagerSystem.c (revision 3447)
+++ src/NetworkManagerSystem.c (working copy)
@@ -1,6 +1,7 @@
/* NetworkManager -- Network link manager
*
* Dan Williams <dcbw redhat com>
+
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -51,23 +52,19 @@
#include <netlink/utils.h>
#include <netlink/route/link.h>
-
/*
- * nm_system_device_set_ip4_route
+ * nm_system_device_set_ip4_route_with_iface
*
*/
-static gboolean nm_system_device_set_ip4_route (NMDevice *dev, int ip4_gateway, int ip4_dest, int ip4_netmask, int mss)
+static gboolean nm_system_device_set_ip4_route_with_iface (const char *iface, int ip4_gateway, int ip4_dest, int ip4_netmask, int mss)
{
NMSock * sk;
gboolean success = FALSE;
struct rtentry rtent;
struct sockaddr_in *p;
- const char * iface;
int err;
- NMIP4Config * config = NULL;
- iface = nm_device_get_iface (dev);
-
+#if 0
/*
* Zero is not a legal gateway and the ioctl will fail. But zero is a
* way of saying "no route" so we just return here. Hopefully the
@@ -75,33 +72,39 @@
*/
if (ip4_gateway == 0)
return TRUE;
-
+#endif
+
/*
- * Do not add the route if the destination is on the same subnet.
+ * -1 is passed by nm_system_device_set_ip4_route() to indicate
+ * there is no route to host. Previously, zero was used for this
+ * purpose (see above) but since nm_system_device_set_ip4_route_with_iface()
+ * can create routes without RTF_GATEWAY, the convention was changed.
+ * It's impossible to create route without gateway using
+ * nm_system_device_set_ip4_route() but noone expects this from it anyway.
*/
- config = nm_device_get_ip4_config(dev);
- if (config &&
- ((guint32)ip4_dest & nm_ip4_config_get_netmask(config)) ==
- (nm_ip4_config_get_address(config) & nm_ip4_config_get_netmask(config)))
+ if (ip4_gateway == -1)
return TRUE;
- if ((sk = nm_dev_sock_open (dev, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL)
+ if ((sk = nm_dev_sock_open (NULL, NETWORK_CONTROL, __FUNCTION__, NULL)) == NULL)
return FALSE;
memset (&rtent, 0, sizeof (struct rtentry));
p = (struct sockaddr_in *) &rtent.rt_dst;
p->sin_family = AF_INET;
p->sin_addr.s_addr = ip4_dest;
- p = (struct sockaddr_in *) &rtent.rt_gateway;
- p->sin_family = AF_INET;
- p->sin_addr.s_addr = ip4_gateway;
+ if (ip4_gateway)
+ {
+ p = (struct sockaddr_in *) &rtent.rt_gateway;
+ p->sin_family = AF_INET;
+ p->sin_addr.s_addr = ip4_gateway;
+ }
p = (struct sockaddr_in *) &rtent.rt_genmask;
p->sin_family = AF_INET;
p->sin_addr.s_addr = ip4_netmask;
rtent.rt_dev = (char *)iface;
rtent.rt_metric = 1;
rtent.rt_window = 0;
- rtent.rt_flags = RTF_UP | RTF_GATEWAY | (rtent.rt_window ? RTF_WINDOW : 0);
+ rtent.rt_flags = RTF_UP | (ip4_gateway ? RTF_GATEWAY : 0) | (rtent.rt_window ? RTF_WINDOW : 0);
if (mss)
{
@@ -176,6 +179,10 @@
return success;
}
+static gboolean nm_system_device_set_ip4_route (NMDevice *dev, int ip4_gateway, int ip4_dest, int ip4_netmask, int mss)
+{
+ return nm_system_device_set_ip4_route_with_iface (nm_device_get_iface (dev), ip4_gateway ? ip4_gateway : -1, ip4_dest, ip4_netmask, mss);
+}
static void iface_to_rtnl_index (const char *iface, struct nl_handle *nlh, struct rtnl_addr *addr)
{
@@ -458,6 +465,40 @@
/*
+ * parse_ip4_route
+ *
+ * Converts CIDR notation in two integers in network order.
+ *
+ */
+static gboolean parse_ip4_route(const char *addr, guint32 *network, guint32 *netmask)
+{
+ guint32 quads[4];
+ guint32 bits;
+ int i, count;
+
+ g_return_val_if_fail(addr != NULL, FALSE);
+
+ count = sscanf(addr, "%u.%u.%u.%u/%u",
+ &quads[0], &quads[1], &quads[2], &quads[3],
+ &bits);
+
+ if (count != 5)
+ return FALSE;
+ for (i = 0; i < 4; i++)
+ if (quads[i] > 255)
+ return FALSE;
+ if (bits > 32)
+ return FALSE;
+
+ *network = htonl((quads[0] << 24) + (quads[1] << 16) + (quads[2] << 8) + quads[3]);
+ *netmask = bits ? htonl(~0 << (32 - bits)) : 0;
+ *network &= *netmask;
+
+ return TRUE;
+}
+
+
+/*
* nm_system_vpn_device_set_from_ip4_config
*
* Set IPv4 configuration of a VPN device from an NMIP4Config object.
@@ -475,8 +516,13 @@
struct nl_handle * nlh = NULL;
struct rtnl_addr * addr = NULL;
struct rtnl_link * request = NULL;
+ guint32 remote_gateway = 0;
+ guint32 network = 0;
+ guint32 netmask = 0;
g_return_val_if_fail (config != NULL, FALSE);
+
+ remote_gateway = nm_ip4_config_get_remote_gateway (config);
/* Set up a route to the VPN gateway through the real network device */
if (active_device && (ad_config = nm_device_get_ip4_config (active_device)))
@@ -485,67 +531,92 @@
if (!iface || !strlen (iface))
goto done;
- nlh = new_nl_handle (FALSE);
- if (!nlh)
- goto done;
-
nm_system_device_set_up_down_with_iface (iface, TRUE);
- if ((addr = nm_ip4_config_to_rtnl_addr (config, NM_RTNL_ADDR_PTP_DEFAULT)))
+ if (!remote_gateway)
{
- int err = 0;
- iface_to_rtnl_index (iface, nlh, addr);
- if ((err = rtnl_addr_add (nlh, addr, 0)) < 0)
- nm_warning ("nm_system_device_set_from_ip4_config(): error %d returned from rtnl_addr_add():\n%s", err, nl_geterror());
- rtnl_addr_put (addr);
- }
- else
- nm_warning ("nm_system_vpn_device_set_from_ip4_config(): couldn't create rtnl address!\n");
+ nlh = new_nl_handle (FALSE);
+ if (!nlh)
+ goto done;
- /* Set the MTU */
- if ((request = rtnl_link_alloc ()))
- {
- struct rtnl_link * old;
+ if ((addr = nm_ip4_config_to_rtnl_addr (config, NM_RTNL_ADDR_PTP_DEFAULT)))
+ {
+ int err = 0;
+ iface_to_rtnl_index (iface, nlh, addr);
+ if ((err = rtnl_addr_add (nlh, addr, 0)) < 0)
+ nm_warning ("nm_system_device_set_from_ip4_config(): error %d returned from rtnl_addr_add():\n%s", err, nl_geterror());
+ rtnl_addr_put (addr);
+ }
+ else
+ nm_warning ("nm_system_vpn_device_set_from_ip4_config(): couldn't create rtnl address!\n");
- old = iface_to_rtnl_link (iface, nlh);
- rtnl_link_set_mtu (request, 1412);
- rtnl_link_change (nlh, old, request, 0);
+ /* Set the MTU */
+ if ((request = rtnl_link_alloc ()))
+ {
+ struct rtnl_link * old;
- rtnl_link_put (old);
- rtnl_link_put (request);
+ old = iface_to_rtnl_link (iface, nlh);
+ rtnl_link_set_mtu (request, 1412);
+ rtnl_link_change (nlh, old, request, 0);
+
+ rtnl_link_put (old);
+ rtnl_link_put (request);
+ }
+
+ destroy_nl_handle (nlh);
}
- destroy_nl_handle (nlh);
-
sleep (1);
nm_system_device_flush_routes_with_iface (iface);
+ if (remote_gateway)
+ {
+ /* Add route to remote network */
+ netmask = nm_ip4_config_get_netmask (config);
+ network = (nm_ip4_config_get_address (config) & netmask);
+ nm_system_device_set_ip4_route_with_iface (iface, 0, network, netmask, nm_ip4_config_get_mss (config));
+ }
if (num_routes <= 0)
{
nm_system_delete_default_route ();
- nm_system_device_add_default_route_via_device_with_iface (iface);
+ if (!remote_gateway)
+ nm_system_device_add_default_route_via_device_with_iface (iface);
+ else
+ nm_system_device_set_ip4_route_with_iface (iface, remote_gateway, 0, 0, nm_ip4_config_get_mss (config));
}
else
{
- int i;
- for (i = 0; i < num_routes; i++)
+ int i;
+
+ if (!remote_gateway)
{
- char *valid_ip4_route;
+ for (i = 0; i < num_routes; i++)
+ {
+ char *valid_ip4_route;
- /* Make sure the route is valid, otherwise it's a security risk as the route
- * text is simply taken from the user, and passed directly to system(). If
- * we did not check the route, think of:
- *
- * system("/sbin/ip route add `rm -rf /` dev eth0")
- *
- * where `rm -rf /` was the route text. As UID 0 (root), we have to be careful.
- */
- if ((valid_ip4_route = validate_ip4_route (routes[i])))
- {
- nm_system_device_add_route_via_device_with_iface (iface, valid_ip4_route);
- g_free (valid_ip4_route);
+ /* Make sure the route is valid, otherwise it's a security risk as the route
+ * text is simply taken from the user, and passed directly to system(). If
+ * we did not check the route, think of:
+ *
+ * system("/sbin/ip route add `rm -rf /` dev eth0")
+ *
+ * where `rm -rf /` was the route text. As UID 0 (root), we have to be careful.
+ */
+ if ((valid_ip4_route = validate_ip4_route (routes[i])))
+ {
+ nm_system_device_add_route_via_device_with_iface (iface, valid_ip4_route);
+ g_free (valid_ip4_route);
+ }
}
}
+ else
+ {
+
+
+ for (i = 0; i < num_routes; i++)
+ if (parse_ip4_route(routes[i], &network, &netmask))
+ nm_system_device_set_ip4_route_with_iface (iface, remote_gateway, network, netmask, nm_ip4_config_get_mss (config));
+ }
}
done:
Index: vpn-daemons/openvpn/src/nm-openvpn-service-openvpn-helper.c
===================================================================
--- vpn-daemons/openvpn/src/nm-openvpn-service-openvpn-helper.c (revision 3447)
+++ vpn-daemons/openvpn/src/nm-openvpn-service-openvpn-helper.c (working copy)
@@ -197,6 +197,7 @@
static gboolean
send_config_info (DBusConnection *con,
const char *str_vpn_gateway,
+ const char *str_remote_gateway,
const char *str_tundev,
const char *str_ip4_address,
const char *str_ip4_ptpaddr,
@@ -208,6 +209,7 @@
DBusMessage * message;
struct in_addr temp_addr;
guint32 uint_vpn_gateway = 0;
+ guint32 uint_remote_gateway = 0;
guint32 uint_ip4_address = 0;
guint32 uint_ip4_ptpaddr = 0;
guint32 uint_ip4_netmask = 0xFFFFFFFF; /* Default mask of 255.255.255.255 */
@@ -231,6 +233,12 @@
goto out;
}
+ if (strlen (str_remote_gateway) > 0 && ! ipstr_to_uint32 (str_remote_gateway, &uint_remote_gateway) ) {
+ nm_warning ("nm-openvpn-service-openvpn-helper didn't receive a valid Remote Gateway from openvpn.");
+ send_config_error (con, "Remote VPN Gateway");
+ goto out;
+ }
+
if (! ipstr_to_uint32 (str_ip4_address, &uint_ip4_address) ) {
nm_warning ("nm-openvpn-service-openvpn-helper didn't receive a valid Internal IP4 Address from openvpn.");
send_config_error (con, "IP4 Address");
@@ -257,6 +265,7 @@
DBUS_TYPE_UINT32, &uint_ip4_netmask,
DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &uint_ip4_dns, uint_ip4_dns_len,
DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &uint_ip4_nbns, uint_ip4_nbns_len,
+ DBUS_TYPE_UINT32, &uint_remote_gateway,
DBUS_TYPE_INVALID);
if (dbus_connection_send (con, message, NULL))
success = TRUE;
@@ -304,6 +313,7 @@
DBusConnection *con;
DBusError error;
char *vpn_gateway = NULL;
+ char *remote_gateway = NULL;
char *tundev = NULL;
char *ip4_address = NULL;
char *ip4_ptp = NULL;
@@ -339,14 +349,15 @@
// print_env();
- vpn_gateway = getenv( "trusted_ip" );
- tundev = getenv ("dev");
- ip4_ptp = getenv("ifconfig_remote");
- ip4_address = getenv("ifconfig_local");
- ip4_netmask = getenv("route_netmask_1");
+ vpn_gateway = getenv( "trusted_ip" );
+ remote_gateway = getenv( "route_vpn_gateway" );
+ tundev = getenv ("dev");
+ ip4_ptp = getenv("ifconfig_remote");
+ ip4_address = getenv("ifconfig_local");
+ ip4_netmask = getenv("ifconfig_netmask");
- ip4_dns = g_ptr_array_new();
- ip4_nbns = g_ptr_array_new();
+ ip4_dns = g_ptr_array_new();
+ ip4_nbns = g_ptr_array_new();
while (1) {
sprintf(envname, "foreign_option_%i", i++);
@@ -381,6 +392,7 @@
{
FILE *file = fopen ("/tmp/vpnstuff", "w");
fprintf (file, "VPNGATEWAY: '%s'\n", vpn_gateway);
+ fprintf (file, "REMOTEGATEWAY: '%s'\n", remote_gateway);
fprintf (file, "TUNDEV: '%s'\n", tundev);
fprintf (file, "IP4_ADDRESS: '%s'\n", ip4_address);
fprintf (file, "IP4_NETMASK: '%s'\n", ip4_netmask);
@@ -393,6 +405,17 @@
send_config_error (con, "VPN Gateway");
exit (1);
}
+ if (!remote_gateway) {
+/* if (ip4_netmask) {
+ nm_warning ("nm-openvpn-service-openvpn-helper received Remote VPN Gateway but no netmask from openvpn.");
+ send_config_error (con, "Remote VPN Gateway");
+ exit (1);
+ } else {
+ remote_gateway = g_strdup("");
+ }
+*/
+ remote_gateway = g_strdup ("");
+ }
if (!tundev || !g_utf8_validate (tundev, -1, NULL)) {
nm_warning ("nm-openvpn-service-openvpn-helper didn't receive a Tunnel Device from openvpn, or the tunnel device was not valid UTF-8.");
send_config_error (con, "Tunnel Device");
@@ -408,7 +431,7 @@
ip4_netmask = g_strdup ("");
}
- if (!send_config_info (con, vpn_gateway, tundev,
+ if (!send_config_info (con, vpn_gateway, remote_gateway, tundev,
ip4_address, ip4_ptp, ip4_netmask,
ip4_dns, ip4_nbns)) {
exit_code = 1;
Index: vpn-daemons/openvpn/src/nm-openvpn-service.c
===================================================================
--- vpn-daemons/openvpn/src/nm-openvpn-service.c (revision 3447)
+++ vpn-daemons/openvpn/src/nm-openvpn-service.c (working copy)
@@ -1266,6 +1266,7 @@
guint32 * ip4_nbns;
guint32 ip4_nbns_len;
guint32 mss;
+ guint32 remote_gateway;
gboolean success = FALSE;
char * empty = "";
@@ -1288,6 +1289,7 @@
DBUS_TYPE_UINT32, &ip4_netmask,
DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_dns, &ip4_dns_len,
DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &ip4_nbns, &ip4_nbns_len,
+ DBUS_TYPE_UINT32, &remote_gateway,
DBUS_TYPE_INVALID))
{
DBusMessage *signal;
@@ -1312,6 +1314,7 @@
DBUS_TYPE_UINT32, &mss,
DBUS_TYPE_STRING, &empty,
DBUS_TYPE_STRING, &empty,
+ DBUS_TYPE_UINT32, &remote_gateway,
DBUS_TYPE_INVALID);
if (!dbus_connection_send (data->con, signal, NULL))
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]