Merge branch 'nm-ipv6'
authorTobias Brunner <tobias@strongswan.org>
Thu, 14 Mar 2019 12:46:33 +0000 (13:46 +0100)
committerTobias Brunner <tobias@strongswan.org>
Thu, 14 Mar 2019 12:46:33 +0000 (13:46 +0100)
Adds support for IPv6 to the NetworkManager backend and plugin.

Fixes #1143, #2586.

src/charon-nm/nm/nm_handler.c
src/charon-nm/nm/nm_handler.h
src/charon-nm/nm/nm_service.c
src/frontends/gnome/autogen.sh
src/frontends/gnome/properties/nm-strongswan.c

index aa7bb5b..3561e70 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (C) 2016 Tobias Brunner
  * Copyright (C) 2009 Martin Willi
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -16,6 +17,7 @@
 #include "nm_handler.h"
 
 #include <daemon.h>
+#include <collections/array.h>
 
 typedef struct private_nm_handler_t private_nm_handler_t;
 
@@ -30,38 +32,56 @@ struct private_nm_handler_t {
        nm_handler_t public;
 
        /**
-        * list of received DNS server attributes, pointer to 4 byte data
+        * Received DNS server attributes, chunk_t
         */
-       linked_list_t *dns;
+       array_t *dns;
 
        /**
-        * list of received NBNS server attributes, pointer to 4 byte data
+        * Received IPv6 DNS server attributes, chunk_t
         */
-       linked_list_t *nbns;
+       array_t *dns6;
+
+       /**
+        * Received NBNS server attributes, chunk_t
+        */
+       array_t *nbns;
 };
 
 METHOD(attribute_handler_t, handle, bool,
        private_nm_handler_t *this, ike_sa_t *ike_sa,
        configuration_attribute_type_t type, chunk_t data)
 {
-       linked_list_t *list;
+       array_t *list;
 
        switch (type)
        {
                case INTERNAL_IP4_DNS:
                        list = this->dns;
                        break;
+               case INTERNAL_IP6_DNS:
+                       list = this->dns6;
+                       break;
                case INTERNAL_IP4_NBNS:
                        list = this->nbns;
                        break;
                default:
                        return FALSE;
        }
-       if (data.len != 4)
-       {
-               return FALSE;
-       }
-       list->insert_last(list, chunk_clone(data).ptr);
+       data = chunk_clone(data);
+       array_insert(list, ARRAY_TAIL, &data);
+       return TRUE;
+}
+
+METHOD(enumerator_t, enumerate_dns6, bool,
+       enumerator_t *this, va_list args)
+{
+       configuration_attribute_type_t *type;
+       chunk_t *data;
+
+       VA_ARGS_VGET(args, type, data);
+       *type = INTERNAL_IP6_DNS;
+       *data = chunk_empty;
+       this->venumerate = (void*)return_false;
        return TRUE;
 }
 
@@ -74,7 +94,8 @@ METHOD(enumerator_t, enumerate_nbns, bool,
        VA_ARGS_VGET(args, type, data);
        *type = INTERNAL_IP4_NBNS;
        *data = chunk_empty;
-       this->venumerate = (void*)return_false;
+       /* enumerate IPv6 DNS server as next attribute ... */
+       this->venumerate = _enumerate_dns6;
        return TRUE;
 }
 
@@ -113,54 +134,44 @@ METHOD(attribute_handler_t, create_attribute_enumerator, enumerator_t*,
        return enumerator_create_empty();
 }
 
-CALLBACK(filter_chunks, bool,
-       void *null, enumerator_t *orig, va_list args)
-{
-       chunk_t *out;
-       char *ptr;
-
-       VA_ARGS_VGET(args, out);
-
-       if (orig->enumerate(orig, &ptr))
-       {
-               *out = chunk_create(ptr, 4);
-               return TRUE;
-       }
-       return FALSE;
-}
-
 METHOD(nm_handler_t, create_enumerator, enumerator_t*,
        private_nm_handler_t *this, configuration_attribute_type_t type)
 {
-       linked_list_t *list;
+       array_t *list;
 
        switch (type)
        {
                case INTERNAL_IP4_DNS:
                        list = this->dns;
                        break;
+               case INTERNAL_IP6_DNS:
+                       list = this->dns6;
+                       break;
                case INTERNAL_IP4_NBNS:
                        list = this->nbns;
                        break;
                default:
                        return enumerator_create_empty();
        }
-       return enumerator_create_filter(list->create_enumerator(list),
-                                                                       filter_chunks, NULL, NULL);
+       return array_create_enumerator(list);
 }
 
 METHOD(nm_handler_t, reset, void,
        private_nm_handler_t *this)
 {
-       void *data;
+       chunk_t chunk;
 
-       while (this->dns->remove_last(this->dns, (void**)&data) == SUCCESS)
+       while (array_remove(this->dns, ARRAY_TAIL, &chunk))
+       {
+               chunk_free(&chunk);
+       }
+       while (array_remove(this->dns6, ARRAY_TAIL, &chunk))
        {
-               free(data);
+               chunk_free(&chunk);
        }
-       while (this->nbns->remove_last(this->nbns, (void**)&data) == SUCCESS)
+       while (array_remove(this->nbns, ARRAY_TAIL, &chunk))
        {
-               free(data);
+               chunk_free(&chunk);
        }
 }
 
@@ -168,8 +179,9 @@ METHOD(nm_handler_t, destroy, void,
        private_nm_handler_t *this)
 {
        reset(this);
-       this->dns->destroy(this->dns);
-       this->nbns->destroy(this->nbns);
+       array_destroy(this->dns);
+       array_destroy(this->dns6);
+       array_destroy(this->nbns);
        free(this);
 }
 
@@ -191,8 +203,9 @@ nm_handler_t *nm_handler_create()
                        .reset = _reset,
                        .destroy = _destroy,
                },
-               .dns = linked_list_create(),
-               .nbns = linked_list_create(),
+               .dns = array_create(sizeof(chunk_t), 0),
+               .dns6 = array_create(sizeof(chunk_t), 0),
+               .nbns = array_create(sizeof(chunk_t), 0),
        );
 
        return &this->public;
index f4103e6..91b0d10 100644 (file)
@@ -39,10 +39,11 @@ struct nm_handler_t {
         * Create an enumerator over received attributes of a given kind.
         *
         * @param type          type of attributes to enumerate
-        * @return                      enumerator over attribute data (chunk_t)
+        * @return                      enumerator over attribute data (chunk_t*)
         */
        enumerator_t* (*create_enumerator)(nm_handler_t *this,
                                                                           configuration_attribute_type_t type);
+
        /**
         * Reset state, flush all received attributes.
         */
index fb9044d..e207ac8 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2017 Lubomir Rintel
  *
- * Copyright (C) 2013 Tobias Brunner
+ * Copyright (C) 2013-2019 Tobias Brunner
  * Copyright (C) 2008-2009 Martin Willi
  * HSR Hochschule fuer Technik Rapperswil
  *
@@ -51,21 +51,54 @@ typedef struct {
                                NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate))
 
 /**
- * convert enumerated handler chunks to a UINT_ARRAY GValue
+ * Convert an address chunk to a GValue
  */
-static GVariant* handler_to_variant(nm_handler_t *handler,
+static GVariant *addr_to_variant(chunk_t addr)
+{
+       GVariantBuilder builder;
+       int i;
+
+       switch (addr.len)
+       {
+               case 4:
+                       return g_variant_new_uint32 (*(uint32_t*)addr.ptr);
+               case 16:
+                       g_variant_builder_init (&builder, G_VARIANT_TYPE ("ay"));
+                       for (i = 0; i < addr.len; i++)
+                       {
+                               g_variant_builder_add (&builder, "y", addr.ptr[i]);
+
+                       }
+                       return g_variant_builder_end (&builder);
+               default:
+                       return NULL;
+       }
+}
+
+/**
+ * Convert a host to a GValue
+ */
+static GVariant *host_to_variant(host_t *host)
+{
+       return addr_to_variant(host->get_address(host));
+}
+
+/**
+ * Convert enumerated handler chunks to a GValue
+ */
+static GVariant* handler_to_variant(nm_handler_t *handler, char *variant_type,
                                                         configuration_attribute_type_t type)
 {
        GVariantBuilder builder;
        enumerator_t *enumerator;
-       chunk_t chunk;
+       chunk_t *chunk;
 
-       g_variant_builder_init (&builder, G_VARIANT_TYPE ("au"));
+       g_variant_builder_init (&builder, G_VARIANT_TYPE (variant_type));
 
        enumerator = handler->create_enumerator(handler, type);
        while (enumerator->enumerate(enumerator, &chunk))
        {
-               g_variant_builder_add (&builder, "u", *(uint32_t*)chunk.ptr);
+               g_variant_builder_add_value (&builder, addr_to_variant(*chunk));
        }
        enumerator->destroy(enumerator);
 
@@ -73,57 +106,132 @@ static GVariant* handler_to_variant(nm_handler_t *handler,
 }
 
 /**
- * signal IPv4 config to NM, set connection as established
+ * Signal IP config to NM, set connection as established
  */
-static void signal_ipv4_config(NMVpnServicePlugin *plugin,
-                                                          ike_sa_t *ike_sa, child_sa_t *child_sa)
+static void signal_ip_config(NMVpnServicePlugin *plugin,
+                                                        ike_sa_t *ike_sa, child_sa_t *child_sa)
 {
        NMStrongswanPluginPrivate *priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
-       GVariantBuilder builder;
+       GVariantBuilder builder, ip4builder, ip6builder;
+       GVariant *ip4config, *ip6config;
        enumerator_t *enumerator;
-       host_t *me, *other;
+       host_t *me, *other, *vip4 = NULL, *vip6 = NULL;
        nm_handler_t *handler;
 
        g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+       g_variant_builder_init (&ip4builder, G_VARIANT_TYPE_VARDICT);
+       g_variant_builder_init (&ip6builder, G_VARIANT_TYPE_VARDICT);
 
        handler = priv->handler;
 
        /* NM apparently requires to know the gateway */
        other = ike_sa->get_other_host(ike_sa);
-       g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY,
-                              g_variant_new_uint32 (*(uint32_t*)other->get_address(other).ptr));
+       g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY,
+                              host_to_variant(other));
 
-       /* NM installs this IP address on the interface above, so we use the VIP if
-        * we got one.
-        */
+       /* pass the first virtual IPs we got or use the physical IP */
        enumerator = ike_sa->create_virtual_ip_enumerator(ike_sa, TRUE);
-       if (!enumerator->enumerate(enumerator, &me))
+       while (enumerator->enumerate(enumerator, &me))
        {
-               me = ike_sa->get_my_host(ike_sa);
+               switch (me->get_family(me))
+               {
+                       case AF_INET:
+                               if (!vip4)
+                               {
+                                       vip4 = me;
+                               }
+                               break;
+                       case AF_INET6:
+                               if (!vip6)
+                               {
+                                       vip6 = me;
+                               }
+                               break;
+               }
        }
        enumerator->destroy(enumerator);
-       g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS,
-                              g_variant_new_uint32 (*(uint32_t*)other->get_address(me).ptr));
+       if (!vip4 && !vip6)
+       {
+               me = ike_sa->get_my_host(ike_sa);
+               switch (me->get_family(me))
+               {
+                       case AF_INET:
+                               vip4 = me;
+                               break;
+                       case AF_INET6:
+                               vip6 = me;
+                               break;
+               }
+       }
 
-       g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX,
-                              g_variant_new_uint32 (me->get_address(me).len * 8));
+       if (vip4)
+       {
+               g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS,
+                                                          host_to_variant(vip4));
+               g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_PREFIX,
+                                                          g_variant_new_uint32 (vip4->get_address(vip4).len * 8));
 
-       /* prevent NM from changing the default route. we set our own route in our
-        * own routing table
-        */
-       g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT,
-                              g_variant_new_boolean (TRUE));
+               /* prevent NM from changing the default route. we set our own route in our
+                * own routing table
+                */
+               g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NEVER_DEFAULT,
+                                                          g_variant_new_boolean (TRUE));
 
+               g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS,
+                                                          handler_to_variant(handler, "au", INTERNAL_IP4_DNS));
 
-       g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_DNS,
-                              handler_to_variant(handler, INTERNAL_IP4_DNS));
+               g_variant_builder_add (&ip4builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS,
+                                                          handler_to_variant(handler, "au", INTERNAL_IP4_NBNS));
+       }
+
+       if (vip6)
+       {
+               g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_ADDRESS,
+                                                          host_to_variant(vip6));
+               g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_PREFIX,
+                                                          g_variant_new_uint32 (vip6->get_address(vip6).len * 8));
+               g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_NEVER_DEFAULT,
+                                                          g_variant_new_boolean (TRUE));
+               g_variant_builder_add (&ip6builder, "{sv}", NM_VPN_PLUGIN_IP6_CONFIG_DNS,
+                                                          handler_to_variant(handler, "aay", INTERNAL_IP6_DNS));
+               /* NM_VPN_PLUGIN_IP6_CONFIG_NBNS is not defined */
+       }
+
+       ip4config = g_variant_builder_end (&ip4builder);
+       if (g_variant_n_children (ip4config))
+       {
+               g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP4,
+                                                          g_variant_new_boolean (TRUE));
+       }
+       else
+       {
+               g_variant_unref (ip4config);
+               ip4config = NULL;
+       }
 
-       g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_NBNS,
-                              handler_to_variant(handler, INTERNAL_IP4_NBNS));
+       ip6config = g_variant_builder_end (&ip6builder);
+       if (g_variant_n_children (ip6config))
+       {
+               g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_CONFIG_HAS_IP6,
+                                                          g_variant_new_boolean (TRUE));
+       }
+       else
+       {
+               g_variant_unref (ip6config);
+               ip6config = NULL;
+       }
 
        handler->reset(handler);
 
-       nm_vpn_service_plugin_set_ip4_config(plugin, g_variant_builder_end (&builder));
+       nm_vpn_service_plugin_set_config (plugin, g_variant_builder_end (&builder));
+       if (ip4config)
+       {
+               nm_vpn_service_plugin_set_ip4_config (plugin, ip4config);
+       }
+       if (ip6config)
+       {
+               nm_vpn_service_plugin_set_ip6_config (plugin, ip6config);
+       }
 }
 
 /**
@@ -184,7 +292,7 @@ static bool child_updown(listener_t *listener, ike_sa_t *ike_sa,
                {       /* disable initiate-failure-detection hooks */
                        private->listener.ike_state_change = NULL;
                        private->listener.child_state_change = NULL;
-                       signal_ipv4_config(private->plugin, ike_sa, child_sa);
+                       signal_ip_config(private->plugin, ike_sa, child_sa);
                }
                else
                {
@@ -526,7 +634,7 @@ static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection,
        /**
         * Set up configurations
         */
-       ike_cfg = ike_cfg_create(IKEV2, TRUE, encap, "0.0.0.0",
+       ike_cfg = ike_cfg_create(IKEV2, TRUE, encap, "%any",
                                                         charon->socket->get_port(charon->socket, FALSE),
                                                        (char*)address, IKEV2_UDP_PORT,
                                                         FRAGMENTATION_YES, 0);
@@ -564,7 +672,8 @@ static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection,
        peer_cfg = peer_cfg_create(priv->name, ike_cfg, &peer);
        if (virtual)
        {
-               peer_cfg->add_virtual_ip(peer_cfg, host_create_from_string("0.0.0.0", 0));
+               peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET));
+               peer_cfg->add_virtual_ip(peer_cfg, host_create_any(AF_INET6));
        }
        auth = auth_cfg_create();
        auth->add(auth, AUTH_RULE_AUTH_CLASS, auth_class);
@@ -612,9 +721,9 @@ static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection,
        }
        ts = traffic_selector_create_dynamic(0, 0, 65535);
        child_cfg->add_traffic_selector(child_cfg, TRUE, ts);
-       ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE,
-                                                                                        "0.0.0.0", 0,
-                                                                                        "255.255.255.255", 65535);
+       ts = traffic_selector_create_from_cidr("0.0.0.0/0", 0, 0, 65535);
+       child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
+       ts = traffic_selector_create_from_cidr("::/0", 0, 0, 65535);
        child_cfg->add_traffic_selector(child_cfg, FALSE, ts);
        peer_cfg->add_child_cfg(peer_cfg, child_cfg);
 
index 25847e7..8a0435c 100755 (executable)
@@ -4,12 +4,11 @@
 srcdir=`dirname $0`
 test -z "$srcdir" && srcdir=.
 REQUIRED_AUTOMAKE_VERSION=1.7
-PKG_NAME=NetworkManager-strongswan
 
 which gnome-autogen.sh || {
     echo "You need to install gnome-common from the GNOME CVS"
     exit 1
 }
-USE_GNOME2_MACROS=1 . gnome-autogen.sh
+. gnome-autogen.sh
 
 
index 9369ddd..de15c42 100644 (file)
@@ -665,7 +665,7 @@ strongswan_plugin_ui_widget_interface_init (NMVpnEditorInterface *iface_class)
 static guint32
 get_capabilities (NMVpnEditorPlugin *iface)
 {
-       return 0;
+       return NM_VPN_EDITOR_PLUGIN_CAPABILITY_IPV6;
 }
 
 static NMVpnEditor *