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 <[EMAIL PROTECTED]>   
  * (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 <[EMAIL PROTECTED]>   
  * (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 <[EMAIL PROTECTED]>  
  * (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 <[EMAIL PROTECTED]>
+
  *
  * 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 <[EMAIL PROTECTED]> 
  * Copyright (C) 2004 Red Hat, Inc.
  * Copyright (C) 1996 - 1997 Yoichi Hariguchi <[EMAIL PROTECTED]>
  * Copyright (C) January, 1998 Sergei Viznyuk <[EMAIL PROTECTED]>
@@ -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 <[EMAIL PROTECTED]>   
  * (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 <[EMAIL PROTECTED]>
  * Based on work by Dan Williams <[EMAIL PROTECTED]>
+ * Updated by Valentine Sinitsyn <[EMAIL PROTECTED]>
  *
  * 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))

_______________________________________________
NetworkManager-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/networkmanager-list

Reply via email to