]> git.ipfire.org Git - thirdparty/strongswan.git/commitdiff
kernel-netlink: Add manager for XFRM interfaces
authorTobias Brunner <tobias@strongswan.org>
Mon, 11 Jul 2022 11:12:46 +0000 (13:12 +0200)
committerTobias Brunner <tobias@strongswan.org>
Wed, 22 Feb 2023 12:37:45 +0000 (13:37 +0100)
The manager will allow charon-nm to create XFRM interfaces if supported
by the kernel instead of creating an unused dummy TUN interface.

The xfrmi tool is mostly obsolete nowadays as iproute2 supports creating
XFRM interfaces since 5.1.0 (2019-05).  Older Debians don't ship that and
early versions didn't list the interface IDs.  So there might still be
some uses for this tool.

12 files changed:
src/libcharon/plugins/kernel_netlink/Makefile.am
src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c
src/libcharon/plugins/kernel_netlink/kernel_netlink_xfrmi.c [new file with mode: 0644]
src/libcharon/plugins/kernel_netlink/kernel_netlink_xfrmi.h [new file with mode: 0644]
src/xfrmi/xfrmi.c
testing/tests/route-based/net2net-xfrmi-ike/hosts/sun/etc/updown.py
testing/tests/route-based/net2net-xfrmi-ike/pretest.dat
testing/tests/route-based/net2net-xfrmi-netns/hosts/sun/etc/updown
testing/tests/route-based/net2net-xfrmi-netns/pretest.dat
testing/tests/route-based/net2net-xfrmi/hosts/sun/etc/updown
testing/tests/route-based/net2net-xfrmi/pretest.dat
testing/tests/route-based/rw-shared-xfrmi/pretest.dat

index 71bc09d5ba2dc4de4fec98f4af0e77f478b80dfd..3db1971420e73d8206b024815d4c3f8f396ab0e6 100644 (file)
@@ -18,7 +18,8 @@ libstrongswan_kernel_netlink_la_SOURCES = \
        kernel_netlink_plugin.h kernel_netlink_plugin.c \
        kernel_netlink_ipsec.h kernel_netlink_ipsec.c \
        kernel_netlink_net.h kernel_netlink_net.c \
-       kernel_netlink_shared.h kernel_netlink_shared.c
+       kernel_netlink_shared.h kernel_netlink_shared.c \
+       kernel_netlink_xfrmi.h kernel_netlink_xfrmi.c
 
 libstrongswan_kernel_netlink_la_LIBADD = $(DLLIB)
 
index 6580c91384e4d348b6a8dc5927198784189580c5..229d9d7188ec3a2b78ce45f7ff6e28cba2b73097 100644 (file)
@@ -63,6 +63,7 @@
 
 #include "kernel_netlink_ipsec.h"
 #include "kernel_netlink_shared.h"
+#include "kernel_netlink_xfrmi.h"
 
 #include <daemon.h>
 #include <utils/debug.h>
@@ -337,6 +338,11 @@ struct private_kernel_netlink_ipsec_t {
         */
        netlink_socket_t *socket_xfrm;
 
+       /**
+        * XFRM interface manager
+        */
+       kernel_netlink_xfrmi_t *xfrmi;
+
        /**
         * Netlink xfrm socket to receive acquire and expire events
         */
@@ -3949,6 +3955,11 @@ METHOD(kernel_ipsec_t, destroy, void,
        DESTROY_IF(this->socket_link_events);
        DESTROY_IF(this->socket_xfrm_events);
        array_destroy_function(this->bypass, remove_port_bypass, this);
+       if (this->xfrmi)
+       {
+               lib->set(lib, KERNEL_NETLINK_XFRMI_MANAGER, NULL);
+               kernel_netlink_xfrmi_destroy(this->xfrmi);
+       }
        DESTROY_IF(this->socket_xfrm);
        enumerator = this->policies->create_enumerator(this->policies);
        while (enumerator->enumerate(enumerator, NULL, &policy))
@@ -4188,5 +4199,11 @@ kernel_netlink_ipsec_t *kernel_netlink_ipsec_create()
                        return NULL;
                }
        }
+
+       this->xfrmi = kernel_netlink_xfrmi_create(TRUE);
+       if (this->xfrmi)
+       {
+               lib->set(lib, KERNEL_NETLINK_XFRMI_MANAGER, this->xfrmi);
+       }
        return &this->public;
 }
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_xfrmi.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_xfrmi.c
new file mode 100644 (file)
index 0000000..1bdd95e
--- /dev/null
@@ -0,0 +1,413 @@
+/*
+ * Copyright (C) 2019-2023 Tobias Brunner
+ *
+ * Copyright (C) secunet Security Networks AG
+ *
+ * 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+#include <net/if.h>
+
+#include "kernel_netlink_xfrmi.h"
+#include "kernel_netlink_shared.h"
+
+#ifndef IFLA_XFRM_MAX
+enum {
+       IFLA_XFRM_UNSPEC,
+       IFLA_XFRM_LINK,
+       IFLA_XFRM_IF_ID,
+       __IFLA_XFRM_MAX
+};
+#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1)
+#endif
+
+typedef struct private_kernel_netlink_xfrmi_t private_kernel_netlink_xfrmi_t;
+
+/**
+ * Private data
+ */
+struct private_kernel_netlink_xfrmi_t {
+
+       /**
+        * Public interface
+        */
+       kernel_netlink_xfrmi_t public;
+
+       /**
+        * Netlink socket
+        */
+       netlink_socket_t *socket;
+};
+
+METHOD(kernel_netlink_xfrmi_t, create, bool,
+       private_kernel_netlink_xfrmi_t *this, char *name, uint32_t if_id,
+       char *phys, uint32_t mtu)
+{
+       netlink_buf_t request;
+       struct nlmsghdr *hdr;
+       struct ifinfomsg *msg;
+       struct rtattr *linkinfo, *info_data;
+       uint32_t ifindex = 0;
+
+       if (phys)
+       {
+               ifindex = if_nametoindex(phys);
+               if (!ifindex)
+               {
+                       DBG1(DBG_KNL, "physical interface '%s' not found", phys);
+                       return FALSE;
+               }
+       }
+
+       memset(&request, 0, sizeof(request));
+
+       hdr = &request.hdr;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
+       hdr->nlmsg_type = RTM_NEWLINK;
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+
+       msg = NLMSG_DATA(hdr);
+       msg->ifi_family = AF_UNSPEC;
+
+       netlink_add_attribute(hdr, IFLA_IFNAME, chunk_from_str(name),
+                                                 sizeof(request));
+       if (mtu)
+       {
+               netlink_add_attribute(hdr, IFLA_MTU, chunk_from_thing(mtu),
+                                                         sizeof(request));
+       }
+
+       linkinfo = netlink_nested_start(hdr, sizeof(request), IFLA_LINKINFO);
+
+       netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"),
+                                                 sizeof(request));
+
+       info_data = netlink_nested_start(hdr, sizeof(request), IFLA_INFO_DATA);
+
+       netlink_add_attribute(hdr, IFLA_XFRM_IF_ID, chunk_from_thing(if_id),
+                                                 sizeof(request));
+       if (ifindex)
+       {
+               netlink_add_attribute(hdr, IFLA_XFRM_LINK, chunk_from_thing(ifindex),
+                                                         sizeof(request));
+       }
+
+       netlink_nested_end(hdr, info_data);
+       netlink_nested_end(hdr, linkinfo);
+
+       switch (this->socket->send_ack(this->socket, hdr))
+       {
+               case SUCCESS:
+                       return TRUE;
+               case ALREADY_DONE:
+                       DBG1(DBG_KNL, "XFRM interface '%s' already exists", name);
+                       break;
+               default:
+                       DBG1(DBG_KNL, "failed to create XFRM interface '%s'", name);
+                       break;
+       }
+       return FALSE;
+}
+
+/** enumerator over XFRM interfaces */
+typedef struct {
+       /** public interface */
+       enumerator_t public;
+       /** message from the kernel */
+       struct nlmsghdr *msg;
+       /** current message from the kernel */
+       struct nlmsghdr *current;
+       /** remaining length */
+       size_t len;
+       /** current physical interface (if any) */
+       char phys[IFNAMSIZ];
+} interface_enumerator_t;
+
+METHOD(enumerator_t, destroy_enumerator, void,
+       interface_enumerator_t *this)
+{
+       free(this->msg);
+       free(this);
+}
+
+/**
+ * Parse attributes nested in IFLA_INFO_DATA
+ */
+static void parse_info_data(struct rtattr *rta, size_t rtasize, bool *has_phys,
+                                                       char *phys, uint32_t *if_id)
+{
+       uint32_t ifindex;
+
+       while (RTA_OK(rta, rtasize))
+       {
+               switch (rta->rta_type)
+               {
+                       case IFLA_XFRM_IF_ID:
+                               if (RTA_PAYLOAD(rta) == sizeof(*if_id))
+                               {
+                                       *if_id = *(uint32_t*)RTA_DATA(rta);
+                               }
+                               break;
+                       case IFLA_XFRM_LINK:
+                               if (RTA_PAYLOAD(rta) == sizeof(ifindex))
+                               {
+                                       ifindex = *(uint32_t*)RTA_DATA(rta);
+                                       if (ifindex)
+                                       {
+                                               if_indextoname(ifindex, phys);
+                                               *has_phys = TRUE;
+                                       }
+                               }
+                               break;
+                       default:
+                               break;
+               }
+               rta = RTA_NEXT(rta, rtasize);
+       }
+}
+
+/**
+ * Parse attributes nested in IFLA_LINKINFO
+ */
+static void parse_linkinfo(struct rtattr *rta, size_t rtasize, bool *type_match,
+                                                  bool *has_phys, char *phys, uint32_t *if_id)
+{
+       while (RTA_OK(rta, rtasize))
+       {
+               switch (rta->rta_type)
+               {
+                       case IFLA_INFO_KIND:
+                               *type_match = streq("xfrm", RTA_DATA(rta));
+                               break;
+                       case IFLA_INFO_DATA:
+                               parse_info_data(RTA_DATA(rta), RTA_PAYLOAD(rta), has_phys,
+                                                               phys, if_id);
+                               break;
+                       default:
+                               break;
+               }
+               rta = RTA_NEXT(rta, rtasize);
+       }
+}
+
+METHOD(enumerator_t, enumerate, bool,
+       interface_enumerator_t *this, va_list args)
+{
+       char **name;
+       uint32_t *if_id, *mtu;
+       char **phys;
+
+       VA_ARGS_VGET(args, name, if_id, phys, mtu);
+
+       if (!this->current)
+       {
+               this->current = this->msg;
+       }
+       else
+       {
+               this->current = NLMSG_NEXT(this->current, this->len);
+       }
+
+       while (NLMSG_OK(this->current, this->len))
+       {
+               switch (this->current->nlmsg_type)
+               {
+                       case NLMSG_DONE:
+                               break;
+                       case RTM_NEWLINK:
+                       {
+                               struct ifinfomsg *msg = NLMSG_DATA(this->current);
+                               struct rtattr *rta = IFLA_RTA(msg);
+                               size_t rtasize = IFLA_PAYLOAD(this->current);
+                               bool type_match = FALSE, has_phys = FALSE;
+
+                               *name = NULL;
+
+                               while (RTA_OK(rta, rtasize))
+                               {
+                                       switch (rta->rta_type)
+                                       {
+                                               case IFLA_IFNAME:
+                                                       *name = RTA_DATA(rta);
+                                                       break;
+                                               case IFLA_MTU:
+                                                       if (mtu && RTA_PAYLOAD(rta) == sizeof(*mtu))
+                                                       {
+                                                               *mtu = *(uint32_t*)RTA_DATA(rta);
+                                                       }
+                                                       break;
+                                               case IFLA_LINKINFO:
+                                                       parse_linkinfo(RTA_DATA(rta), RTA_PAYLOAD(rta),
+                                                                                  &type_match, &has_phys, this->phys,
+                                                                                  if_id);
+                                                       break;
+                                               default:
+                                                       break;
+                                       }
+                                       rta = RTA_NEXT(rta, rtasize);
+                               }
+                               if (*name && type_match)
+                               {
+                                       if (phys)
+                                       {
+                                               *phys = has_phys ? this->phys : NULL;
+                                       }
+                                       return TRUE;
+                               }
+                               /* fall-through */
+                       }
+                       default:
+                               this->current = NLMSG_NEXT(this->current, this->len);
+                               continue;
+               }
+               break;
+       }
+       return FALSE;
+}
+
+METHOD(kernel_netlink_xfrmi_t, create_enumerator, enumerator_t*,
+       private_kernel_netlink_xfrmi_t *this)
+{
+       netlink_buf_t request;
+       struct nlmsghdr *hdr, *out;
+       struct ifinfomsg *msg;
+       struct rtattr *linkinfo;
+       size_t len;
+       interface_enumerator_t *enumerator;
+
+       memset(&request, 0, sizeof(request));
+
+       hdr = &request.hdr;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
+       hdr->nlmsg_type = RTM_GETLINK;
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+
+       msg = NLMSG_DATA(hdr);
+       msg->ifi_family = AF_UNSPEC;
+
+       /* if the kernel doesn't know the type we set here, it will just return all
+        * interfaces, so we filter the type ourselves too in the callback */
+       linkinfo = netlink_nested_start(hdr, sizeof(request), IFLA_LINKINFO);
+
+       netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"),
+                                                 sizeof(request));
+
+       netlink_nested_end(hdr, linkinfo);
+
+       if (this->socket->send(this->socket, hdr, &out, &len) != SUCCESS)
+       {
+               DBG2(DBG_KNL, "enumerating XFRM interfaces failed");
+               return enumerator_create_empty();
+       }
+
+       INIT(enumerator,
+               .public = {
+                       .enumerate = enumerator_enumerate_default,
+                       .venumerate = _enumerate,
+                       .destroy = _destroy_enumerator,
+               },
+               .msg = out,
+               .len = len,
+       );
+       return &enumerator->public;
+}
+
+METHOD(kernel_netlink_xfrmi_t, delete, bool,
+       private_kernel_netlink_xfrmi_t *this, char *name)
+{
+       netlink_buf_t request;
+       struct nlmsghdr *hdr;
+       struct ifinfomsg *msg;
+       struct rtattr *linkinfo;
+
+       memset(&request, 0, sizeof(request));
+
+       hdr = &request.hdr;
+       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK;
+       hdr->nlmsg_type = RTM_DELLINK;
+       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+
+       msg = NLMSG_DATA(hdr);
+       msg->ifi_family = AF_UNSPEC;
+
+       netlink_add_attribute(hdr, IFLA_IFNAME, chunk_from_str(name),
+                                                 sizeof(request));
+
+       /* the type doesn't seem to matter, but let's still set it */
+       linkinfo = netlink_nested_start(hdr, sizeof(request), IFLA_LINKINFO);
+
+       netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"),
+                                                 sizeof(request));
+
+       netlink_nested_end(hdr, linkinfo);
+
+       switch (this->socket->send_ack(this->socket, hdr))
+       {
+               case SUCCESS:
+                       return TRUE;
+               case NOT_FOUND:
+                       DBG1(DBG_KNL, "XFRM interface '%s' not found to delete", name);
+                       break;
+               default:
+                       DBG1(DBG_KNL, "failed to delete XFRM interface '%s'", name);
+                       break;
+       }
+       return FALSE;
+}
+
+void kernel_netlink_xfrmi_destroy(kernel_netlink_xfrmi_t *pub)
+{
+       private_kernel_netlink_xfrmi_t *this = (private_kernel_netlink_xfrmi_t*)pub;
+
+       this->socket->destroy(this->socket);
+       free(this);
+}
+
+/*
+ * Described in header
+ */
+kernel_netlink_xfrmi_t *kernel_netlink_xfrmi_create(bool test)
+{
+       private_kernel_netlink_xfrmi_t *this;
+       char name[IFNAMSIZ] = {};
+       uint32_t if_id;
+
+       INIT(this,
+               .public = {
+                       .create = _create,
+                       .create_enumerator = _create_enumerator,
+                       .delete = _delete,
+               },
+               .socket = netlink_socket_create(NETLINK_ROUTE, NULL, FALSE),
+       );
+
+       if (!this->socket)
+       {
+               free(this);
+               return NULL;
+       }
+       if (test)
+       {
+               /* try to create an XFRM interface to see if the kernel supports it, use
+                * a random ID and name for the test to avoid conflicts */
+               if_id = random();
+               snprintf(name, sizeof(name), "xfrmi-test-%u", if_id);
+
+               if (!create(this, name, if_id, NULL, 0))
+               {
+                       kernel_netlink_xfrmi_destroy(&this->public);
+                       return NULL;
+               }
+               DBG2(DBG_KNL, "XFRM interfaces supported by kernel");
+               delete(this, name);
+       }
+       return &this->public;
+}
diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_xfrmi.h b/src/libcharon/plugins/kernel_netlink/kernel_netlink_xfrmi.h
new file mode 100644 (file)
index 0000000..a590a92
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2022-2023 Tobias Brunner
+ *
+ * Copyright (C) secunet Security Networks AG
+ *
+ * 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 the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * for more details.
+ */
+
+/**
+ * @defgroup kernel_netlink_xfrmi kernel_netlink_xfrmi
+ * @{ @ingroup kernel_netlink
+ */
+
+#ifndef KERNEL_NETLINK_XFRMI_H_
+#define KERNEL_NETLINK_XFRMI_H_
+
+#include <library.h>
+
+#define KERNEL_NETLINK_XFRMI_MANAGER "kernel-netlink-xfrmi"
+
+typedef struct kernel_netlink_xfrmi_t kernel_netlink_xfrmi_t;
+
+/**
+ * Simple manager for XFRM interfaces. An instance can be retrieved via
+ * lib::get() under the key "kernel-netlink-xfrmi" if the kernel-netlink plugin
+ * is loaded and XFRM interfaces are supported by the kernel.
+ */
+struct kernel_netlink_xfrmi_t {
+
+       /**
+        * Creates an XFRM interface with the given name, interface ID and
+        * optional underlying physical interface and MTU.
+        *
+        * @param name                  name of the XFRM interface
+        * @param if_id                 interface ID (has to match SAs/policies)
+        * @param phys                  name of the underlying physical interface (optional)
+        * @param mtu                   MTU of the interface (optional, 0 for default)
+        * @return                              TRUE if interface was successfully created
+        */
+       bool (*create)(kernel_netlink_xfrmi_t *this, char *name, uint32_t if_id,
+                                  char *phys, uint32_t mtu);
+
+       /**
+        * Enumerate existing XFRM interfaces.
+        *
+        * @return                              enumerator over (char *name, uint32_t if_id,
+        *                                              char *phys, u_int mtu)
+        */
+       enumerator_t *(*create_enumerator)(kernel_netlink_xfrmi_t *this);
+
+       /**
+        * Deletes the XFRM interface with the given name.
+        *
+        * @note This deletes any type of interface with the given name.
+        *
+        * @param name                  name of the XFRM interface
+        * @return                              TRUE if interface was successfully deleted
+        */
+       bool (*delete)(kernel_netlink_xfrmi_t *this, char *name);
+};
+
+/**
+ * Create the manager.
+ *
+ * @param test         test if XFRM interfaces can be created (requires CAP_NET_ADMIN)
+ * @return                     kernel_netlink_xfrmi_t instance, or NULL if test failed
+ */
+kernel_netlink_xfrmi_t *kernel_netlink_xfrmi_create(bool test);
+
+/**
+ * Destroy the given manager. Not a method in the interface above to prevent
+ * users from destroying the manager.
+ */
+void kernel_netlink_xfrmi_destroy(kernel_netlink_xfrmi_t *this);
+
+#endif /** KERNEL_NETLINK_XFRMI_H_ @}*/
index 82d19fd903dddfd1c315b4049c9e06d5f26b95a1..946402ed32eea6d89f144296b8d9c2cc877bf3ea 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 Tobias Brunner
+ * Copyright (C) 2019-2023 Tobias Brunner
  *
  * Copyright (C) secunet Security Networks AG
  *
 #include <getopt.h>
 #include <errno.h>
 #include <net/if.h>
-#include <linux/netlink.h>
-#include <linux/rtnetlink.h>
 
-#include "kernel_netlink_shared.h"
-
-#ifndef IFLA_XFRM_MAX
-enum {
-       IFLA_XFRM_UNSPEC,
-       IFLA_XFRM_LINK,
-       IFLA_XFRM_IF_ID,
-       __IFLA_XFRM_MAX
-};
-#define IFLA_XFRM_MAX (__IFLA_XFRM_MAX - 1)
-#endif
+#include "kernel_netlink_xfrmi.h"
 
 /**
- * Create an XFRM interface with the given ID and underlying interface
+ * Default MTU
  */
-static int add_xfrm_interface(char *name, uint32_t xfrm_id, uint32_t ifindex)
-{
-       netlink_buf_t request;
-       struct nlmsghdr *hdr;
-       struct ifinfomsg *msg;
-       struct rtattr *linkinfo, *info_data;
-       netlink_socket_t *socket;
-       int status = 1;
-
-       socket = netlink_socket_create(NETLINK_ROUTE, NULL, FALSE);
-       if (!socket)
-       {
-               return 1;
-       }
-
-       memset(&request, 0, sizeof(request));
-
-       hdr = &request.hdr;
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | NLM_F_CREATE | NLM_F_EXCL;
-       hdr->nlmsg_type = RTM_NEWLINK;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-
-       msg = NLMSG_DATA(hdr);
-       msg->ifi_family = AF_UNSPEC;
-
-       netlink_add_attribute(hdr, IFLA_IFNAME, chunk_from_str(name),
-                                                 sizeof(request));
-
-       linkinfo = netlink_nested_start(hdr, sizeof(request), IFLA_LINKINFO);
-
-       netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"),
-                                                 sizeof(request));
-
-       info_data = netlink_nested_start(hdr, sizeof(request), IFLA_INFO_DATA);
-
-       netlink_add_attribute(hdr, IFLA_XFRM_IF_ID, chunk_from_thing(xfrm_id),
-                                                 sizeof(request));
-       netlink_add_attribute(hdr, IFLA_XFRM_LINK, chunk_from_thing(ifindex),
-                                                 sizeof(request));
-
-       netlink_nested_end(hdr, info_data);
-       netlink_nested_end(hdr, linkinfo);
-
-       switch (socket->send_ack(socket, hdr))
-       {
-               case SUCCESS:
-                       status = 0;
-                       break;
-               case ALREADY_DONE:
-                       fprintf(stderr, "XFRM interface already exists\n");
-                       break;
-               default:
-                       fprintf(stderr, "failed to create XFRM interface\n");
-                       break;
-       }
-
-       socket->destroy(socket);
-       return status;
-}
+#define XFRMI_DEFAULT_MTU 1400
 
 /**
- * Parse attributes nested in IFLA_INFO_DATA
+ * Manager for XFRM interfaces
  */
-static void parse_info_data(struct rtattr *rta, size_t rtasize, char *phys,
-                                                       uint32_t *if_id)
-{
-       uint32_t ifindex;
-
-       while (RTA_OK(rta, rtasize))
-       {
-               switch (rta->rta_type)
-               {
-                       case IFLA_XFRM_IF_ID:
-                               if (RTA_PAYLOAD(rta) == sizeof(*if_id))
-                               {
-                                       *if_id = *(uint32_t*)RTA_DATA(rta);
-                               }
-                               break;
-                       case IFLA_XFRM_LINK:
-                               if (RTA_PAYLOAD(rta) == sizeof(ifindex))
-                               {
-                                       ifindex = *(uint32_t*)RTA_DATA(rta);
-                                       if_indextoname(ifindex, phys);
-                               }
-                               break;
-                       default:
-                               break;
-               }
-               rta = RTA_NEXT(rta, rtasize);
-       }
-}
+static kernel_netlink_xfrmi_t *manager;
 
 /**
- * Parse attributes nested in IFLA_LINKINFO
+ * Destroy the allocated manager
  */
-static void parse_linkinfo(struct rtattr *rta, size_t rtasize, char *phys,
-                                                  uint32_t *if_id)
+static void destroy_manager()
 {
-       while (RTA_OK(rta, rtasize))
+       if (manager)
        {
-               switch (rta->rta_type)
-               {
-                       case IFLA_INFO_DATA:
-                               parse_info_data(RTA_DATA(rta), RTA_PAYLOAD(rta), phys, if_id);
-                               break;
-                       default:
-                               break;
-               }
-               rta = RTA_NEXT(rta, rtasize);
+               kernel_netlink_xfrmi_destroy(manager);
        }
 }
 
 /**
  * List all installed XFRM interfaces
  */
-static int list_xfrm_interfaces()
+static void list_xfrm_interfaces(kernel_netlink_xfrmi_t *manager)
 {
-       netlink_buf_t request;
-       struct nlmsghdr *hdr, *out, *current;
-       struct ifinfomsg *msg;
-       struct rtattr *linkinfo;
-       netlink_socket_t *socket;
-       size_t len;
-       int status = 0;
+       enumerator_t *enumerator;
+       char *name, *dev;
+       uint32_t xfrm_id, mtu;
 
-       socket = netlink_socket_create(NETLINK_ROUTE, NULL, FALSE);
-       if (!socket)
+       enumerator = manager->create_enumerator(manager);
+       while (enumerator->enumerate(enumerator, &name, &xfrm_id, &dev, &mtu))
        {
-               return 1;
-       }
-
-       memset(&request, 0, sizeof(request));
-
-       hdr = &request.hdr;
-       hdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
-       hdr->nlmsg_type = RTM_GETLINK;
-       hdr->nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
-
-       msg = NLMSG_DATA(hdr);
-       msg->ifi_family = AF_UNSPEC;
-
-       linkinfo = netlink_nested_start(hdr, sizeof(request), IFLA_LINKINFO);
-
-       netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"),
-                                                 sizeof(request));
-
-       netlink_nested_end(hdr, linkinfo);
-
-       if (socket->send(socket, hdr, &out, &len) != SUCCESS)
-       {
-               return FAILED;
-       }
-       current = out;
-       while (NLMSG_OK(current, len))
-       {
-               switch (current->nlmsg_type)
-               {
-                       case NLMSG_DONE:
-                               break;
-                       case RTM_NEWLINK:
-                               msg = NLMSG_DATA(current);
-                               struct rtattr *rta = IFLA_RTA(msg);
-                               size_t rtasize = IFLA_PAYLOAD(current);
-                               char *name = NULL, phys[IF_NAMESIZE] = {};
-                               uint32_t if_id = 0;
-
-                               while (RTA_OK(rta, rtasize))
-                               {
-                                       switch (rta->rta_type)
-                                       {
-                                               case IFLA_IFNAME:
-                                                       name = RTA_DATA(rta);
-                                                       break;
-                                               case IFLA_LINKINFO:
-                                                       parse_linkinfo(RTA_DATA(rta), RTA_PAYLOAD(rta),
-                                                                                  phys, &if_id);
-                                                       break;
-                                               default:
-                                                       break;
-                                       }
-                                       rta = RTA_NEXT(rta, rtasize);
-                               }
-                               if (name)
-                               {
-                                       printf("%2u: %-16s dev %-8s if_id 0x%.8x [%u]\n",
-                                                  msg->ifi_index, name, phys, if_id, if_id);
-                               }
-                               /* fall through */
-                       default:
-                               current = NLMSG_NEXT(current, len);
-                               continue;
-               }
-               break;
+               printf("%2u: %-16s dev %-12s if_id 0x%.8x [%10u] mtu %u\n",
+                          if_nametoindex(name), name, dev ?: "-", xfrm_id, xfrm_id, mtu);
        }
-       free(out);
-
-       socket->destroy(socket);
-       return status;
+       enumerator->destroy(enumerator);
 }
 
 static void usage(FILE *out, char *name)
@@ -247,19 +71,22 @@ static void usage(FILE *out, char *name)
        fprintf(out, "  -l, --list          list XFRM interfaces.\n");
        fprintf(out, "  -n, --name=NAME     name of the XFRM interface.\n");
        fprintf(out, "  -i, --id=ID         optional numeric XFRM ID.\n");
-       fprintf(out, "  -d, --dev=DEVICE    underlying physical interface.\n");
+       fprintf(out, "  -d, --dev=DEVICE    optional underlying physical interface.\n");
+       fprintf(out, "  -m, --mtu=MTU       optional MTU, default: 1400 (use 0 for kernel default).\n");
        fprintf(out, "\n");
 }
 
 int main(int argc, char *argv[])
 {
        char *name = NULL, *dev = NULL, *end;
-       uint32_t xfrm_id = 0;
-       u_int ifindex;
+       uint32_t xfrm_id = 0, mtu = XFRMI_DEFAULT_MTU;
 
        library_init(NULL, "xfrmi");
        atexit(library_deinit);
 
+       manager = kernel_netlink_xfrmi_create(FALSE);
+       atexit(destroy_manager);
+
        while (true)
        {
                struct option long_opts[] = {
@@ -269,9 +96,10 @@ int main(int argc, char *argv[])
                        {"name",                required_argument,      NULL,   'n' },
                        {"id",                  required_argument,      NULL,   'i' },
                        {"dev",                 required_argument,      NULL,   'd' },
+                       {"mtu",                 required_argument,      NULL,   'm' },
                        {0,0,0,0 },
                };
-               switch (getopt_long(argc, argv, "hvln:i:d:", long_opts, NULL))
+               switch (getopt_long(argc, argv, "hvln:i:d:m:", long_opts, NULL))
                {
                        case EOF:
                                break;
@@ -279,7 +107,7 @@ int main(int argc, char *argv[])
                                usage(stdout, argv[0]);
                                return 0;
                        case 'l':
-                               list_xfrm_interfaces();
+                               list_xfrm_interfaces(manager);
                                return 0;
                        case 'v':
                                dbg_default_set_level(atoi(optarg));
@@ -300,24 +128,26 @@ int main(int argc, char *argv[])
                        case 'd':
                                dev = optarg;
                                continue;
+                       case 'm':
+                               errno = 0;
+                               mtu = strtoul(optarg, &end, 0);
+                               if (errno || *end)
+                               {
+                                       fprintf(stderr, "invalid MTU: %s\n",
+                                                       errno ? strerror(errno) : end);
+                                       return 1;
+                               }
+                               continue;
                        default:
                                usage(stderr, argv[0]);
                                return 1;
                }
                break;
        }
-
-       if (!name || !dev)
+       if (!name)
        {
-               fprintf(stderr, "please specify a name and a physical interface\n");
+               fprintf(stderr, "please specify a name\n");
                return 1;
        }
-       ifindex = if_nametoindex(dev);
-       if (!ifindex)
-       {
-               fprintf(stderr, "physical interface %s not found\n", dev);
-               return 1;
-       }
-
-       return add_xfrm_interface(name, xfrm_id, ifindex);
+       return !manager->create(manager, name, xfrm_id, dev, mtu);
 }
index 67985a40542633daf15460775acfe99ed80aef98..4abc1aa5489e6aa5a67f4a844e007e9c4430a333 100755 (executable)
@@ -27,10 +27,10 @@ def handle_interfaces(ike_sa, up):
 
     if up:
         logger.info("add XFRM interfaces %s and %s", ifname_in, ifname_out)
-        subprocess.call(["/usr/local/libexec/ipsec/xfrmi", "-n", ifname_out,
-                         "-i", str(if_id_out), "-d", "eth0"])
-        subprocess.call(["/usr/local/libexec/ipsec/xfrmi", "-n", ifname_in,
-                         "-i", str(if_id_in), "-d", "eth0"])
+        subprocess.call(["ip", "link", "add", ifname_out, "type", "xfrm",
+                         "if_id", str(if_id_out), "dev", "eth0"])
+        subprocess.call(["ip", "link", "add", ifname_in, "type", "xfrm",
+                         "if_id", str(if_id_in), "dev", "eth0"])
         subprocess.call(["ip", "link", "set", ifname_out, "up"])
         subprocess.call(["ip", "link", "set", ifname_in, "up"])
         subprocess.call(["iptables", "-A", "FORWARD", "-o", ifname_out,
index a314a346730515374142bd75fc2e31d70d7c48ce..062b127747945c401e1666edea977fe998b9789c 100644 (file)
@@ -1,7 +1,7 @@
 moon::iptables-restore < /etc/iptables.rules
 sun::iptables-restore < /etc/iptables.rules
-moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon-out -d eth0 -i 1337
-moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon-in  -d eth0 -i 42
+moon::ip link add xfrm-moon-out type xfrm dev eth0 if_id 1337
+moon::ip link add xfrm-moon-in type xfrm dev eth0 if_id 42
 moon::ip link set xfrm-moon-out up
 moon::ip link set xfrm-moon-in up
 moon::ip route add 10.2.0.0/16 dev xfrm-moon-out
index 71e904dfc3dc1daa3dddcc15e5931cda5c95259f..f018d036046ac2089ed7b878dea3e8be4e74bc40 100755 (executable)
@@ -4,7 +4,7 @@ IF_NAME="xfrmi-${PLUTO_IF_ID_IN}"
 
 case "${PLUTO_VERB}" in
     up-client)
-        /usr/local/libexec/ipsec/xfrmi -n "${IF_NAME}" -i "${PLUTO_IF_ID_IN}" -d eth0
+        ip link add "${IF_NAME}" type xfrm if_id "${PLUTO_IF_ID_IN}" dev eth0
         ip link set "${IF_NAME}" up
         ip route add 10.1.0.0/16 dev "${IF_NAME}"
         iptables -A FORWARD -i "${IF_NAME}" -j ACCEPT
index 54f302e08ab31e0b3af789dac73f5dda133a3c6b..b70aac667460b83366c87bad7e07448e6b408e8a 100644 (file)
@@ -1,6 +1,6 @@
 moon::iptables-restore < /etc/iptables.rules
 sun::iptables-restore < /etc/iptables.rules
-moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon -i 42 -d eth0
+moon::ip link add xfrm-moon type xfrm if_id 42 dev eth0
 moon::ip link set xfrm-moon up
 moon::ip route add 10.2.0.0/16 dev xfrm-moon
 moon::iptables -A FORWARD -i xfrm-moon -j ACCEPT
index bf0d0b86aecef1fc050666974e60e6ec567899e3..2a220b598fa30327325db943a4c40f065fbe3827 100755 (executable)
@@ -6,8 +6,8 @@ IF_NAME_OUT="${IF_NAME}${PLUTO_IF_ID_OUT}-out"
 
 case "${PLUTO_VERB}" in
     up-client)
-        /usr/local/libexec/ipsec/xfrmi -n "${IF_NAME_OUT}" -i "${PLUTO_IF_ID_OUT}" -d eth0
-        /usr/local/libexec/ipsec/xfrmi -n "${IF_NAME_IN}" -i "${PLUTO_IF_ID_IN}" -d eth0
+        ip link add "${IF_NAME_OUT}" type xfrm if_id "${PLUTO_IF_ID_OUT}" dev eth0
+        ip link add "${IF_NAME_IN}" type xfrm if_id "${PLUTO_IF_ID_IN}" dev eth0
         ip link set "${IF_NAME_OUT}" up
         ip link set "${IF_NAME_IN}" up
         ip route add 10.1.0.0/16 dev "${IF_NAME_OUT}"
index b7ca425d056baa437ae1e5aa035bc300fc7d6899..cd7f2ca0e129febf8786acf1af1fce4e3c8c37bc 100644 (file)
@@ -1,7 +1,7 @@
 moon::iptables-restore < /etc/iptables.rules
 sun::iptables-restore < /etc/iptables.rules
-moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon-out -d eth0 -i 1337
-moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon-in  -d eth0 -i 42
+moon::ip link add xfrm-moon-out type xfrm dev eth0 if_id 1337
+moon::ip link add xfrm-moon-in type xfrm dev eth0 if_id 42
 moon::ip link set xfrm-moon-out up
 moon::ip link set xfrm-moon-in up
 moon::ip route add 10.2.0.0/16 dev xfrm-moon-out
index f4104cf32ebd9503b4017c52560417e1dd8cf7b5..76d75f8759413615b52b07fc12c94fa4504a7756 100644 (file)
@@ -1,7 +1,7 @@
 moon::iptables-restore < /etc/iptables.rules
 carol::iptables-restore < /etc/iptables.rules
 dave::iptables-restore < /etc/iptables.rules
-moon::/usr/local/libexec/ipsec/xfrmi -n xfrm-moon -i 42 -d eth0
+moon::ip link add xfrm-moon type xfrm if_id 42 dev eth0
 moon::ip link set xfrm-moon up
 moon::ip route add 10.3.0.0/28 dev xfrm-moon
 moon::iptables -A FORWARD -i xfrm-moon -j ACCEPT