Re: NetworkManager VPN and routing in bridged mode
- From: Valentine Sinitsyn <valentine sinitsyn usu ru>
- To: NetworkManager-list gnome org
- Subject: Re: NetworkManager VPN and routing in bridged mode
- Date: Thu, 13 Mar 2008 01:35:08 +0500
Hello,
The attached file is the patch against NETWORKMANAGER_0_6_5_RELEASE (rev
2558) which implements the logic for tap-based VPN networks. The code is
in "works for me" state. I understand that NM 0.6.5 isn't best codebase
but it's the version I use (which helps to test the patch) and given its
relatively small size it should be easy to port it to recently tagged 0_6_6.
Any feedback will be greatly appreciated.
Regards,
Valentine Sinitsyn
Index: src/nm-ip4-config.c
===================================================================
--- src/nm-ip4-config.c (revision 3427)
+++ src/nm-ip4-config.c (working copy)
@@ -16,6 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
+ * (C) Copyright 2008 Valentine Sinitsyn <e_val inbox ru>
* (C) Copyright 2005 Red Hat, Inc.
*/
@@ -43,6 +44,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 +59,7 @@
* an IP4Config before it can be used.
*/
gboolean secondary;
+
};
@@ -357,6 +361,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 3427)
+++ src/nm-ip4-config.h (working copy)
@@ -16,6 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
+ * (C) Copyright 2008 Valentine Sinitsyn <e_val inbox ru>
* (C) Copyright 2004 Red Hat, Inc.
*/
@@ -74,6 +75,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 3427)
+++ src/vpn-manager/nm-vpn-service.c (working copy)
@@ -16,6 +16,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
+ * (C) Copyright 2008 Valentine Sinitsyn <e_val inbox ru>
* (C) Copyright 2005 Red Hat, Inc.
*/
@@ -841,6 +842,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 3427)
+++ 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
@@ -16,6 +17,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
+ * Copyright (C) 2008 Valentine Sinitsyn <e_val inbox ru>
* Copyright (C) 2004 Red Hat, Inc.
* Copyright (C) 1996 - 1997 Yoichi Hariguchi <yoichi fore com>
* Copyright (C) January, 1998 Sergei Viznyuk <sv phystech com>
@@ -51,7 +53,123 @@
#include <netlink/utils.h>
#include <netlink/route/link.h>
+/*
+ * nm_system_device_set_ip4_route_with_iface
+ *
+ */
+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;
+ int err;
+ /*
+ * 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
+ * caller flushed the routes, first.
+ */
+ if (ip4_gateway == 0)
+ return TRUE;
+
+ 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;
+ 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);
+
+ if (mss)
+ {
+ rtent.rt_flags |= RTF_MTU;
+ rtent.rt_mtu = mss;
+ }
+
+#ifdef IOCTL_DEBUG
+ nm_info ("%s: About to CADDRT\n", nm_device_get_iface (dev));
+#endif
+ err = ioctl (nm_dev_sock_get_fd (sk), SIOCADDRT, &rtent);
+#ifdef IOCTL_DEBUG
+ nm_info ("%s: About to CADDRT\n", nm_device_get_iface (dev));
+#endif
+
+ if (err == -1)
+ {
+ if (errno == ENETUNREACH) /* possibly gateway is over the bridge */
+ { /* try adding a route to gateway first */
+ struct rtentry rtent2;
+
+ memset (&rtent2, 0, sizeof(struct rtentry));
+ p = (struct sockaddr_in *)&rtent2.rt_dst;
+ p->sin_family = AF_INET;
+ p = (struct sockaddr_in *)&rtent2.rt_gateway;
+ p->sin_family = AF_INET;
+ p->sin_addr.s_addr = ip4_gateway;
+ p = (struct sockaddr_in *)&rtent2.rt_genmask;
+ p->sin_family = AF_INET;
+ p->sin_addr.s_addr = 0xffffffff;
+ rtent2.rt_dev = (char *)iface;
+ rtent2.rt_metric = 0;
+ rtent2.rt_flags = RTF_UP | RTF_HOST;
+
+ if (mss)
+ {
+ rtent2.rt_flags |= RTF_MTU;
+ rtent2.rt_mtu = mss;
+ }
+
+#ifdef IOCTL_DEBUG
+ nm_info ("%s: About to CADDRT (2)\n", nm_device_get_iface (dev));
+#endif
+ err = ioctl (nm_dev_sock_get_fd (sk), SIOCADDRT, &rtent2);
+#ifdef IOCTL_DEBUG
+ nm_info ("%s: About to CADDRT (2)\n", nm_device_get_iface (dev));
+#endif
+
+ if (!err)
+ {
+#ifdef IOCTL_DEBUG
+ nm_info ("%s: About to CADDRT (3)\n", nm_device_get_iface (dev));
+#endif
+ err = ioctl (nm_dev_sock_get_fd (sk), SIOCADDRT, &rtent);
+#ifdef IOCTL_DEBUG
+ nm_info ("%s: About to CADDRT (3)\n", nm_device_get_iface (dev));
+#endif
+
+ if (!err)
+ success = TRUE;
+ else
+ nm_warning ("Failed to set IPv4 default route on '%s': %s", iface, strerror (errno));
+ }
+ }
+ else
+ nm_warning ("Failed to set IPv4 default route on '%s': %s", iface, strerror (errno));
+ }
+ else
+ success = TRUE;
+
+ nm_dev_sock_close (sk);
+ 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_dest, ip4_netmask, mss);
+}
+
+#if 0
/*
* nm_system_device_set_ip4_route
*
@@ -165,8 +283,8 @@
nm_dev_sock_close (sk);
return success;
}
+#endif
-
static struct nl_cache * get_link_cache (struct nl_handle *nlh)
{
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
@@ -420,56 +538,81 @@
struct nl_handle * nlh = NULL;
struct rtnl_addr * addr = NULL;
struct rtnl_link * request = NULL;
+ guint32 remote_gateway = 0;
+ guint32 remote_network = 0;
g_return_val_if_fail (config != NULL, FALSE);
+
+ remote_gateway = nm_ip4_config_get_remote_gateway (config);
+ if (remote_gateway)
+ remote_network = (nm_ip4_config_get_address (config) & nm_ip4_config_get_netmask (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)))
nm_system_device_set_ip4_route (active_device, nm_ip4_config_get_gateway (ad_config), nm_ip4_config_get_gateway (config), 0xFFFFFFFF, nm_ip4_config_get_mss (config));
+
if (iface != NULL && strlen (iface))
{
nm_system_device_set_up_down_with_iface (iface, TRUE);
- nlh = new_nl_handle ();
-
- 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 ();
- /* 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);
- rtnl_link_put (old);
- rtnl_link_put (request);
- }
+ /* Set the MTU */
+ if ((request = rtnl_link_alloc ()))
+ {
+ struct rtnl_link * old;
- nl_close (nlh);
- nl_handle_destroy (nlh);
+ 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);
+ }
+
+ nl_close (nlh);
+ nl_handle_destroy (nlh);
+ }
+
sleep (1);
nm_system_device_flush_routes_with_iface (iface);
if (num_routes <= 0)
{
- nm_system_delete_default_route ();
- nm_system_device_add_default_route_via_device_with_iface (iface);
+ nm_system_delete_default_route ();
+ if (!remote_gateway)
+ {
+ nm_system_device_add_default_route_via_device_with_iface (iface);
+ }
+ else
+ {
+ /* nm_system_device_set_ip4_route() doesn't accept 0.0.0.0 as gateway,
+ * so we specify ourselves to make it happy
+ */
+ nm_system_device_set_ip4_route_with_iface (iface, nm_ip4_config_get_address (config), remote_network, nm_ip4_config_get_netmask (config), nm_ip4_config_get_mss (config));
+ nm_system_device_set_ip4_route_with_iface (iface, remote_gateway, 0, 0, nm_ip4_config_get_mss (config));
+ }
}
else
{
+ /* FIXME: This will not work for tap-like devices (see above) */
int i;
for (i = 0; i < num_routes; i++)
{
Index: vpn-daemons/openvpn/src/nm-openvpn-service-openvpn-helper.c
===================================================================
--- vpn-daemons/openvpn/src/nm-openvpn-service-openvpn-helper.c (revision 3427)
+++ vpn-daemons/openvpn/src/nm-openvpn-service-openvpn-helper.c (working copy)
@@ -18,6 +18,7 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
+ * (C) Copyright 2008 Valentine Sinitsyn <e_val inbox ru>
* (C) Copyright 2005 Red Hat, Inc.
* (C) Copyright 2005 Tim Niemueller
*
@@ -197,6 +198,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 +210,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 +234,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 VPN 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 +266,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 +314,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 +350,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 +393,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 +406,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 +432,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 3427)
+++ vpn-daemons/openvpn/src/nm-openvpn-service.c (working copy)
@@ -2,6 +2,7 @@
*
* Tim Niemueller <tim niemueller de>
* Based on work by Dan Williams <dcbw redhat com>
+ * Updated by Valentine Sinitsyn <e_val inbox ru>
*
* 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
@@ -1266,6 +1267,7 @@
guint32 * ip4_nbns;
guint32 ip4_nbns_len;
guint32 mss;
+ guint32 remote_gateway;
gboolean success = FALSE;
char * empty = "";
@@ -1288,6 +1290,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 +1315,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]