2008-10-11 Dan Williams <dcbw@redhat.com>
authorDan Williams <dcbw@redhat.com>
Sat, 11 Oct 2008 14:26:41 +0000 (14:26 +0000)
committerDan Williams <dcbw@redhat.com>
Sat, 11 Oct 2008 14:26:41 +0000 (14:26 +0000)
Add support for VPN subnet gateways (bgo #549196)

* include/NetworkManager.h
- Add key for internal VPN subnet gateway

* src/vpn-manager/nm-vpn-connection.c
- (ip_address_to_string): return a const from a static buffer so we
don't leak a lot of strings
- (print_vpn_config): print internal VPN gateway as well
- (nm_vpn_connection_ip4_config_get): grab internal VPN gateway from
VPN service too
- (nm_vpn_connection_get_ip4_internal_gateway): new function

* src/NetworkManagerSystem.c
  src/NetworkManagerSystem.h
- (nm_system_device_replace_default_ip4_route): split into two, one for
VPN connections and one for normal devices
- (replace_default_ip4_route): break out route stuff into its own function
- (nm_system_replace_default_ip4_route_vpn,
   nm_system_replace_default_ip4_route): simplify by having two cases,
one for VPNs and one for normal devices

* src/NetworkManagerPolicy.c
- (update_routing_and_dns): simplify, use split default route replacement
functions

git-svn-id: http://svn-archive.gnome.org/svn/NetworkManager/trunk@4169 4912f4e0-d625-0410-9fb7-b9a5a253dbdc

ChangeLog
include/NetworkManagerVPN.h
src/NetworkManagerPolicy.c
src/NetworkManagerSystem.c
src/NetworkManagerSystem.h
src/vpn-manager/nm-vpn-connection.c
src/vpn-manager/nm-vpn-connection.h

index 4d08a21..d16e7c6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,31 @@
+2008-10-11  Dan Williams  <dcbw@redhat.com>
+
+       Add support for VPN subnet gateways (bgo #549196)
+
+       * include/NetworkManager.h
+               - Add key for internal VPN subnet gateway
+
+       * src/vpn-manager/nm-vpn-connection.c
+               - (ip_address_to_string): return a const from a static buffer so we
+                       don't leak a lot of strings
+               - (print_vpn_config): print internal VPN gateway as well
+               - (nm_vpn_connection_ip4_config_get): grab internal VPN gateway from
+                       VPN service too
+               - (nm_vpn_connection_get_ip4_internal_gateway): new function
+
+       * src/NetworkManagerSystem.c
+         src/NetworkManagerSystem.h
+               - (nm_system_device_replace_default_ip4_route): split into two, one for
+                       VPN connections and one for normal devices
+               - (replace_default_ip4_route): break out route stuff into its own function
+               - (nm_system_replace_default_ip4_route_vpn,
+                  nm_system_replace_default_ip4_route): simplify by having two cases,
+                       one for VPNs and one for normal devices
+
+       * src/NetworkManagerPolicy.c
+               - (update_routing_and_dns): simplify, use split default route replacement
+                       functions
+
 2008-10-10  Dan Williams  <dcbw@redhat.com>
 
        Rework default route handling to consolidate decisions in the policy,
index 8476654..952d08a 100644 (file)
@@ -112,17 +112,23 @@ typedef enum {
        NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG
 } NMVPNPluginFailure;
 
-#define NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY "gateway"
-#define NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS "address"
-#define NM_VPN_PLUGIN_IP4_CONFIG_PTP     "ptp"
-#define NM_VPN_PLUGIN_IP4_CONFIG_PREFIX  "prefix"
-#define NM_VPN_PLUGIN_IP4_CONFIG_DNS     "dns"
-#define NM_VPN_PLUGIN_IP4_CONFIG_NBNS    "nbns"
-#define NM_VPN_PLUGIN_IP4_CONFIG_MSS     "mss"
-#define NM_VPN_PLUGIN_IP4_CONFIG_MTU     "mtu"
-#define NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV  "tundev"
-#define NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN  "domain"
-#define NM_VPN_PLUGIN_IP4_CONFIG_BANNER  "banner"
-#define NM_VPN_PLUGIN_IP4_CONFIG_ROUTES  "routes"
+
+#define NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY "gateway"
+#define NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY "internal-gateway"
+#define NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS     "address"
+#define NM_VPN_PLUGIN_IP4_CONFIG_PTP         "ptp"
+#define NM_VPN_PLUGIN_IP4_CONFIG_PREFIX      "prefix"
+#define NM_VPN_PLUGIN_IP4_CONFIG_DNS         "dns"
+#define NM_VPN_PLUGIN_IP4_CONFIG_NBNS        "nbns"
+#define NM_VPN_PLUGIN_IP4_CONFIG_MSS         "mss"
+#define NM_VPN_PLUGIN_IP4_CONFIG_MTU         "mtu"
+#define NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV      "tundev"
+#define NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN      "domain"
+#define NM_VPN_PLUGIN_IP4_CONFIG_BANNER      "banner"
+#define NM_VPN_PLUGIN_IP4_CONFIG_ROUTES      "routes"
+
+/* Deprecated */
+#define NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY   NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY
+
 
 #endif /* NETWORK_MANAGER_VPN_H */
index 46c51e9..b4063eb 100644 (file)
@@ -475,13 +475,11 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
        NMNamedManager *named_mgr;
        GSList *devices = NULL, *iter, *vpns;
        NMIP4Config *ip4_config = NULL;
+       const NMSettingIP4Address *addr;
        const char *ip_iface = NULL;
-       const char *parent_iface = NULL;
        NMVPNConnection *vpn = NULL;
        NMConnection *connection = NULL;
        NMSettingConnection *s_con = NULL;
-       guint32 parent_mss = 0;
-       guint32 gateway = 0;
 
        best = get_best_device (policy->manager, &best_req);
        if (!best)
@@ -502,22 +500,24 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
 
        /* VPNs are the default route only if they don't have custom routes */
        if (vpn) {
-               NMIP4Config *vpn_config;
-
-               vpn_config = nm_vpn_connection_get_ip4_config (vpn);
-               if (nm_ip4_config_get_num_routes (vpn_config) == 0) {
+               ip4_config = nm_vpn_connection_get_ip4_config (vpn);
+               if (nm_ip4_config_get_num_routes (ip4_config) == 0) {
                        NMIP4Config *parent_ip4;
                        NMDevice *parent;
 
-                       connection = nm_vpn_connection_get_connection (vpn);
                        ip_iface = nm_vpn_connection_get_ip_iface (vpn);
-                       ip4_config = vpn_config;
+                       connection = nm_vpn_connection_get_connection (vpn);
+                       addr = nm_ip4_config_get_address (ip4_config, 0);
 
                        parent = nm_vpn_connection_get_parent_device (vpn);
-                       parent_iface = nm_device_get_ip_iface (parent);
                        parent_ip4 = nm_device_get_ip4_config (parent);
-                       if (parent_ip4)
-                               parent_mss = nm_ip4_config_get_mss (parent_ip4);
+
+                       nm_system_replace_default_ip4_route_vpn (ip_iface,
+                                                                addr->gateway,
+                                                                nm_vpn_connection_get_ip4_internal_gateway (vpn),
+                                                                nm_ip4_config_get_mss (ip4_config),
+                                                                nm_device_get_ip_iface (parent),
+                                                                nm_ip4_config_get_mss (parent_ip4));
 
                        dns_type = NM_NAMED_IP_CONFIG_TYPE_VPN;
                }
@@ -526,15 +526,13 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
 
        /* The best device gets the default route if a VPN connection didn't */
        if (!ip_iface || !ip4_config) {
-               const NMSettingIP4Address *addr;
-
                connection = nm_act_request_get_connection (best_req);
                ip_iface = nm_device_get_ip_iface (best);
                ip4_config = nm_device_get_ip4_config (best);
-               if (ip4_config) {
-                       addr = nm_ip4_config_get_address (ip4_config, 0);
-                       gateway = addr->gateway;
-               }
+               g_assert (ip4_config);
+               addr = nm_ip4_config_get_address (ip4_config, 0);
+
+               nm_system_replace_default_ip4_route (ip_iface, addr->gateway, nm_ip4_config_get_mss (ip4_config));
 
                dns_type = NM_NAMED_IP_CONFIG_TYPE_BEST_DEVICE;
        }
@@ -545,13 +543,6 @@ update_routing_and_dns (NMPolicy *policy, gboolean force_update)
                goto out;
        }
 
-       /* Set the new default route */
-       nm_system_device_replace_default_ip4_route (ip_iface,
-                                                   gateway,
-                                                   nm_ip4_config_get_mss (ip4_config),
-                                                   parent_iface,
-                                                   parent_mss);
-
        /* Update the default active connection.  Only mark the new default
         * active connection after setting default = FALSE on all other connections
         * first.  The order is important, we don't want two connections marked
index 653e90a..54861db 100644 (file)
@@ -533,35 +533,25 @@ error:
        return NULL;
 }
 
-/*
- * nm_system_replace_default_ip4_route
- *
- * Replace default IPv4 route with one via the current device
- *
- */
-void
-nm_system_device_replace_default_ip4_route (const char *iface,
-                                            guint32 gw,
-                                            guint32 mss,
-                                            const char *parent_iface,
-                                            guint32 parent_mss)
+static int
+replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
 {
        struct rtnl_route *route = NULL;
-       struct rtnl_route *gw_route = NULL;
        struct nl_handle *nlh;
        struct nl_addr *gw_addr = NULL;
-       int iface_idx, err;
-       gboolean success = FALSE;
+       int iface_idx, err = -1;
+
+       g_return_val_if_fail (iface != NULL, -1);
 
        nlh = nm_netlink_get_default_handle ();
-       g_return_if_fail (nlh != NULL);
+       g_return_val_if_fail (nlh != NULL, -1);
 
        iface_idx = nm_netlink_iface_to_index (iface);
        if (iface_idx < 0)
-               return;
+               return -1;
 
        route = rtnl_route_alloc();
-       g_return_if_fail (route != NULL);
+       g_return_val_if_fail (route != NULL, -1);
 
        rtnl_route_set_scope (route, RT_SCOPE_UNIVERSE);
        rtnl_route_set_oif (route, iface_idx);
@@ -580,36 +570,97 @@ nm_system_device_replace_default_ip4_route (const char *iface,
 
        /* Add the new default route */
        err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
-       if (err == 0) {
-               /* Everything good */
-               success = TRUE;
-               goto out;
-       } else if (err != -ESRCH) {
-               nm_warning ("rtnl_route_add() returned error %s (%d)\n%s",
-                           strerror (err), err, nl_geterror());
-               goto out;
+
+out:
+       rtnl_route_put (route);
+       return err;
+}
+
+/*
+ * nm_system_replace_default_ip4_route_vpn
+ *
+ * Replace default IPv4 route with one via the current device
+ *
+ */
+gboolean
+nm_system_replace_default_ip4_route_vpn (const char *iface,
+                                         guint32 ext_gw,
+                                         guint32 int_gw,
+                                         guint32 mss,
+                                         const char *parent_iface,
+                                         guint32 parent_mss)
+{
+       struct rtnl_route *gw_route = NULL;
+       struct nl_handle *nlh;
+       gboolean success = FALSE;
+       int err;
+
+       nlh = nm_netlink_get_default_handle ();
+       g_return_val_if_fail (nlh != NULL, FALSE);
+
+       err = replace_default_ip4_route (iface, int_gw, mss);
+       if (err != -ESRCH) {
+               nm_warning ("replace_default_ip4_route() returned error %s (%d)",
+                           strerror (err), err);
+               return FALSE;
        }
 
        /* Try adding a direct route to the gateway first */
-       gw_route = add_ip4_route_to_gateway (parent_iface ? parent_iface : iface,
-                                            gw,
-                                            parent_iface ? parent_mss : mss);
+       gw_route = add_ip4_route_to_gateway (parent_iface, ext_gw, parent_mss);
        if (!gw_route)
-               goto out;
+               return FALSE;
 
        /* Try adding the original route again */
-       err = rtnl_route_add (nlh, route, NLM_F_REPLACE);
+       err = replace_default_ip4_route (iface, int_gw, mss);
        if (err != 0) {
                rtnl_route_del (nlh, gw_route, 0);
                nm_warning ("Failed to set IPv4 default route on '%s': %s", iface, nl_geterror ());
+       } else
+               success = TRUE;
+
+       rtnl_route_put (gw_route);
+       return success;
+}
+
+/*
+ * nm_system_replace_default_ip4_route
+ *
+ * Replace default IPv4 route with one via the current device
+ *
+ */
+gboolean
+nm_system_replace_default_ip4_route (const char *iface, guint32 gw, guint32 mss)
+{
+       struct rtnl_route *gw_route = NULL;
+       struct nl_handle *nlh;
+       gboolean success = FALSE;
+       int err;
+
+       nlh = nm_netlink_get_default_handle ();
+       g_return_val_if_fail (nlh != NULL, FALSE);
+
+       err = replace_default_ip4_route (iface, gw, mss);
+       if (err != -ESRCH) {
+               nm_warning ("replace_default_ip4_route() returned error %s (%d)",
+                           strerror (err), err);
+               return FALSE;
        }
 
-out:
-       if (gw_route)
-               rtnl_route_put (gw_route);
+       /* Try adding a direct route to the gateway first */
+       gw_route = add_ip4_route_to_gateway (iface, gw, mss);
+       if (!gw_route)
+               return FALSE;
 
-       if (route)
-               rtnl_route_put (route);
+       /* Try adding the original route again */
+       err = replace_default_ip4_route (iface, gw, mss);
+       if (err != 0) {
+               rtnl_route_del (nlh, gw_route, 0);
+               nm_warning ("Failed to set IPv4 default route on '%s': %s", iface, nl_geterror ());
+       } else
+               success = TRUE;
+
+       rtnl_route_put (gw_route);
+       return success;
 }
 
 /*
index bd8df4a..a9d9276 100644 (file)
 void                   nm_system_device_flush_ip4_routes                               (NMDevice *dev);
 void                   nm_system_device_flush_ip4_routes_with_iface    (const char *iface);
 
-void                   nm_system_device_replace_default_ip4_route   (const char *iface,
-                                                             guint32 gw,
-                                                             guint32 mss,
-                                                             const char *parent_iface,
-                                                             guint32 parent_mss);
+gboolean               nm_system_replace_default_ip4_route   (const char *iface,
+                                                       guint32 gw,
+                                                       guint32 mss);
+
+gboolean               nm_system_replace_default_ip4_route_vpn (const char *iface,
+                                                         guint32 ext_gw,
+                                                         guint32 int_gw,
+                                                         guint32 mss,
+                                                         const char *parent_iface,
+                                                         guint32 parent_mss);
 
 void                   nm_system_device_flush_ip4_addresses                    (NMDevice *dev);
 void                   nm_system_device_flush_ip4_addresses_with_iface (const char *iface);
index 90c3691..77075a5 100644 (file)
@@ -71,6 +71,7 @@ typedef struct {
        DBusGProxy *proxy;
        guint ipconfig_timeout;
        NMIP4Config *ip4_config;
+       guint32 ip4_internal_gw;
        char *tundev;
        char *tapdev;
        char *banner;
@@ -293,13 +294,13 @@ static const char *
 ip_address_to_string (guint32 numeric)
 {
        struct in_addr temp_addr;
-       char buf[INET_ADDRSTRLEN+1];
+       static char buf[INET_ADDRSTRLEN + 1];
 
        memset (&buf, '\0', sizeof (buf));
        temp_addr.s_addr = numeric;
 
        if (inet_ntop (AF_INET, &temp_addr, buf, INET_ADDRSTRLEN)) {
-               return g_strdup (buf);
+               return buf;
        } else {
                nm_warning ("%s: error converting IP4 address 0x%X",
                            __func__, ntohl (temp_addr.s_addr));
@@ -309,8 +310,9 @@ ip_address_to_string (guint32 numeric)
 
 static void
 print_vpn_config (NMIP4Config *config,
-                          const char *tundev,
-                          const char *banner)
+                  guint32 internal_gw,
+                  const char *tundev,
+                  const char *banner)
 {
        const NMSettingIP4Address *addr;
        char *         dns_domain = NULL;
@@ -322,6 +324,8 @@ print_vpn_config (NMIP4Config *config,
        addr = nm_ip4_config_get_address (config, 0);
 
        nm_info ("VPN Gateway: %s", ip_address_to_string (addr->gateway));
+       if (internal_gw)
+               nm_info ("Internal Gateway: %s", ip_address_to_string (internal_gw));
        nm_info ("Tunnel Device: %s", tundev);
        nm_info ("Internal IP4 Address: %s", ip_address_to_string (addr->address));
        nm_info ("Internal IP4 Prefix: %d", addr->prefix);
@@ -385,7 +389,13 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
                goto error;
        }
 
-       val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY);
+       /* Internal address of the VPN subnet's gateway */
+       val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_INT_GATEWAY);
+       if (val)
+               priv->ip4_internal_gw = g_value_get_uint (val);
+
+       /* External world-visible address of the VPN server */
+       val = (GValue *) g_hash_table_lookup (config_hash, NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY);
        if (val)
                addr->gateway = g_value_get_uint (val);
 
@@ -456,7 +466,7 @@ nm_vpn_connection_ip4_config_get (DBusGProxy *proxy,
                g_slist_free (routes);
        }
 
-       print_vpn_config (config, priv->tundev, priv->banner);
+       print_vpn_config (config, priv->ip4_internal_gw, priv->tundev, priv->banner);
 
        /* Merge in user overrides from the NMConnection's IPv4 setting */
        s_ip4 = NM_SETTING_IP4_CONFIG (nm_connection_get_setting (priv->connection, NM_TYPE_SETTING_IP4_CONFIG));
@@ -672,6 +682,14 @@ nm_vpn_connection_get_parent_device (NMVPNConnection *connection)
        return NM_VPN_CONNECTION_GET_PRIVATE (connection)->parent_dev;
 }
 
+guint32
+nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection)
+{
+       g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), 0);
+
+       return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip4_internal_gw;
+}
+
 void
 nm_vpn_connection_fail (NMVPNConnection *connection,
                         NMVPNConnectionStateReason reason)
index 7007b0b..6c54d5e 100644 (file)
@@ -73,5 +73,6 @@ void                 nm_vpn_connection_disconnect      (NMVPNConnection *connect
 NMIP4Config *        nm_vpn_connection_get_ip4_config  (NMVPNConnection *connection);
 const char *         nm_vpn_connection_get_ip_iface    (NMVPNConnection *connection);
 NMDevice *           nm_vpn_connection_get_parent_device (NMVPNConnection *connection);
+guint32        nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection);
 
 #endif /* NM_VPN_CONNECTION_H */