diff --git a/src/libcharon/plugins/kernel_netlink/Makefile.am b/src/libcharon/plugins/kernel_netlink/Makefile.am index 71bc09d5b..3db197142 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 6580c9138..229d9d718 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 000000000..1bdd95edd --- /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 000000000..a590a9246 --- /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 82d19fd90..946402ed3 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; + printf("%2u: %-16s dev %-12s if_id 0x%.8x [%10u] mtu %u\n", + if_nametoindex(name), name, dev ?: "-", xfrm_id, xfrm_id, mtu); } - - 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; - } - 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 67985a405..4abc1aa54 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 a314a3467..062b12774 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 71e904dfc..f018d0360 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 54f302e08..b70aac667 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 bf0d0b86a..2a220b598 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 b7ca425d0..cd7f2ca0e 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 f4104cf32..76d75f875 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