123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322 |
- /*
- * Copyright (C) 2019 Tobias Brunner
- * HSR Hochschule fuer Technik Rapperswil
- *
- * 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 <stdio.h>
- #include <unistd.h>
- #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
- /**
- * Create an XFRM interface with the given ID and underlying interface
- */
- 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;
- }
- /**
- * Parse attributes nested in IFLA_INFO_DATA
- */
- 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);
- }
- }
- /**
- * Parse attributes nested in IFLA_LINKINFO
- */
- static void parse_linkinfo(struct rtattr *rta, size_t rtasize, char *phys,
- uint32_t *if_id)
- {
- while (RTA_OK(rta, rtasize))
- {
- 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);
- }
- }
- /**
- * List all installed XFRM interfaces
- */
- static int list_xfrm_interfaces()
- {
- 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;
- 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_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;
- }
- static void usage(FILE *out, char *name)
- {
- fprintf(out, "Create XFRM interfaces\n\n");
- fprintf(out, "%s [OPTIONS]\n\n", name);
- fprintf(out, "Options:\n");
- fprintf(out, " -h, --help print this help.\n");
- fprintf(out, " -v, --debug set debug level, default: 1.\n");
- 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, "\n");
- }
- int main(int argc, char *argv[])
- {
- char *name = NULL, *dev = NULL, *end;
- uint32_t xfrm_id = 0;
- u_int ifindex;
- library_init(NULL, "xfrmi");
- atexit(library_deinit);
- while (true)
- {
- struct option long_opts[] = {
- {"help", no_argument, NULL, 'h' },
- {"debug", no_argument, NULL, 'v' },
- {"list", no_argument, NULL, 'l' },
- {"name", required_argument, NULL, 'n' },
- {"id", required_argument, NULL, 'i' },
- {"dev", required_argument, NULL, 'd' },
- {0,0,0,0 },
- };
- switch (getopt_long(argc, argv, "hvln:i:d:", long_opts, NULL))
- {
- case EOF:
- break;
- case 'h':
- usage(stdout, argv[0]);
- return 0;
- case 'l':
- list_xfrm_interfaces();
- return 0;
- case 'v':
- dbg_default_set_level(atoi(optarg));
- continue;
- case 'n':
- name = optarg;
- continue;
- case 'i':
- errno = 0;
- xfrm_id = strtoul(optarg, &end, 0);
- if (errno || *end)
- {
- fprintf(stderr, "invalid XFRM ID: %s\n",
- errno ? strerror(errno) : end);
- return 1;
- }
- continue;
- case 'd':
- dev = optarg;
- continue;
- default:
- usage(stderr, argv[0]);
- return 1;
- }
- break;
- }
- if (!name || !dev)
- {
- fprintf(stderr, "please specify a name and a physical interface\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);
- }
|