From: Tobias Brunner Date: Tue, 12 Feb 2019 17:26:43 +0000 (+0100) Subject: kernel-netlink: Add --list option to XFRM interfaces utility X-Git-Tag: 5.8.0rc1~41^2~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=eef923660205a36ca736c4e229b4352d5d00dde8;p=thirdparty%2Fstrongswan.git kernel-netlink: Add --list option to XFRM interfaces utility --- diff --git a/src/libcharon/plugins/kernel_netlink/xfrmi.c b/src/libcharon/plugins/kernel_netlink/xfrmi.c index 0555ac4ce0..d2d0e80931 100644 --- a/src/libcharon/plugins/kernel_netlink/xfrmi.c +++ b/src/libcharon/plugins/kernel_netlink/xfrmi.c @@ -103,6 +103,148 @@ static int add_xfrm_interface(char *name, uint32_t xfrm_id, uint32_t ifindex) 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; + + /* the following attributes are nested under this one */ + linkinfo = netlink_reserve(hdr, sizeof(request), IFLA_LINKINFO, 0); + linkinfo = (void*)linkinfo - RTA_LENGTH(0); + + netlink_add_attribute(hdr, IFLA_INFO_KIND, chunk_from_str("xfrm"), + sizeof(request)); + + linkinfo->rta_len = NLMSG_TAIL(hdr) - (void*)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"); @@ -110,6 +252,7 @@ static void usage(FILE *out, char *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"); @@ -122,23 +265,30 @@ int main(int argc, char *argv[]) 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, "hvn:i:d:", long_opts, NULL)) + 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; @@ -177,8 +327,5 @@ int main(int argc, char *argv[]) return 1; } - library_init(NULL, "xfrmi"); - atexit(library_deinit); - return add_xfrm_interface(name, xfrm_id, ifindex); }