From: Tobias Brunner Date: Mon, 11 Jul 2022 11:12:46 +0000 (+0200) Subject: kernel-netlink: Add manager for XFRM interfaces X-Git-Tag: 5.9.10rc1~5^2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e1ff1eefcffb356213a3e119de19149fcc2474cd;p=thirdparty%2Fstrongswan.git kernel-netlink: Add manager for XFRM interfaces 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. --- diff --git a/src/libcharon/plugins/kernel_netlink/Makefile.am b/src/libcharon/plugins/kernel_netlink/Makefile.am index 71bc09d5ba..3db1971420 100644 --- a/src/libcharon/plugins/kernel_netlink/Makefile.am +++ b/src/libcharon/plugins/kernel_netlink/Makefile.am @@ -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) diff --git a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c index 6580c91384..229d9d7188 100644 --- a/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_ipsec.c @@ -63,6 +63,7 @@ #include "kernel_netlink_ipsec.h" #include "kernel_netlink_shared.h" +#include "kernel_netlink_xfrmi.h" #include #include @@ -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 index 0000000000..1bdd95edd8 --- /dev/null +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_xfrmi.c @@ -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 . + * + * 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 + +#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 index 0000000000..a590a9246c --- /dev/null +++ b/src/libcharon/plugins/kernel_netlink/kernel_netlink_xfrmi.h @@ -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 . + * + * 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 + +#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_ @}*/ diff --git a/src/xfrmi/xfrmi.c b/src/xfrmi/xfrmi.c index 82d19fd903..946402ed32 100644 --- a/src/xfrmi/xfrmi.c +++ b/src/xfrmi/xfrmi.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 Tobias Brunner + * Copyright (C) 2019-2023 Tobias Brunner * * Copyright (C) secunet Security Networks AG * @@ -19,222 +19,46 @@ #include #include #include -#include -#include -#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); } diff --git a/testing/tests/route-based/net2net-xfrmi-ike/hosts/sun/etc/updown.py b/testing/tests/route-based/net2net-xfrmi-ike/hosts/sun/etc/updown.py index 67985a4054..4abc1aa548 100755 --- a/testing/tests/route-based/net2net-xfrmi-ike/hosts/sun/etc/updown.py +++ b/testing/tests/route-based/net2net-xfrmi-ike/hosts/sun/etc/updown.py @@ -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, diff --git a/testing/tests/route-based/net2net-xfrmi-ike/pretest.dat b/testing/tests/route-based/net2net-xfrmi-ike/pretest.dat index a314a34673..062b127747 100644 --- a/testing/tests/route-based/net2net-xfrmi-ike/pretest.dat +++ b/testing/tests/route-based/net2net-xfrmi-ike/pretest.dat @@ -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 diff --git a/testing/tests/route-based/net2net-xfrmi-netns/hosts/sun/etc/updown b/testing/tests/route-based/net2net-xfrmi-netns/hosts/sun/etc/updown index 71e904dfc3..f018d03604 100755 --- a/testing/tests/route-based/net2net-xfrmi-netns/hosts/sun/etc/updown +++ b/testing/tests/route-based/net2net-xfrmi-netns/hosts/sun/etc/updown @@ -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 diff --git a/testing/tests/route-based/net2net-xfrmi-netns/pretest.dat b/testing/tests/route-based/net2net-xfrmi-netns/pretest.dat index 54f302e08a..b70aac6674 100644 --- a/testing/tests/route-based/net2net-xfrmi-netns/pretest.dat +++ b/testing/tests/route-based/net2net-xfrmi-netns/pretest.dat @@ -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 diff --git a/testing/tests/route-based/net2net-xfrmi/hosts/sun/etc/updown b/testing/tests/route-based/net2net-xfrmi/hosts/sun/etc/updown index bf0d0b86ae..2a220b598f 100755 --- a/testing/tests/route-based/net2net-xfrmi/hosts/sun/etc/updown +++ b/testing/tests/route-based/net2net-xfrmi/hosts/sun/etc/updown @@ -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}" diff --git a/testing/tests/route-based/net2net-xfrmi/pretest.dat b/testing/tests/route-based/net2net-xfrmi/pretest.dat index b7ca425d05..cd7f2ca0e1 100644 --- a/testing/tests/route-based/net2net-xfrmi/pretest.dat +++ b/testing/tests/route-based/net2net-xfrmi/pretest.dat @@ -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 diff --git a/testing/tests/route-based/rw-shared-xfrmi/pretest.dat b/testing/tests/route-based/rw-shared-xfrmi/pretest.dat index f4104cf32e..76d75f8759 100644 --- a/testing/tests/route-based/rw-shared-xfrmi/pretest.dat +++ b/testing/tests/route-based/rw-shared-xfrmi/pretest.dat @@ -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