kernel-netlink: Add --list option to XFRM interfaces utility
authorTobias Brunner <tobias@strongswan.org>
Tue, 12 Feb 2019 17:26:43 +0000 (18:26 +0100)
committerTobias Brunner <tobias@strongswan.org>
Thu, 4 Apr 2019 07:31:38 +0000 (09:31 +0200)
src/libcharon/plugins/kernel_netlink/xfrmi.c

index 0555ac4..d2d0e80 100644 (file)
@@ -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);
 }