iproute2/ip/iptoken.c
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0-or-later */
   2/*
   3 * iptoken.c    "ip token"
   4 *
   5 * Authors:     Daniel Borkmann, <borkmann@redhat.com>
   6 */
   7
   8#include <stdio.h>
   9#include <stdlib.h>
  10#include <stdbool.h>
  11#include <unistd.h>
  12#include <fcntl.h>
  13#include <string.h>
  14#include <sys/socket.h>
  15#include <netinet/in.h>
  16#include <netinet/ip.h>
  17#include <arpa/inet.h>
  18#include <linux/types.h>
  19#include <linux/if.h>
  20
  21#include "rt_names.h"
  22#include "utils.h"
  23#include "ip_common.h"
  24#include "json_print.h"
  25
  26extern struct rtnl_handle rth;
  27
  28struct rtnl_dump_args {
  29        FILE *fp;
  30        int ifindex;
  31};
  32
  33static void usage(void) __attribute__((noreturn));
  34
  35static void usage(void)
  36{
  37        fprintf(stderr, "Usage: ip token [ list | set | del | get ] [ TOKEN ] [ dev DEV ]\n");
  38        exit(-1);
  39}
  40
  41static int print_token(struct nlmsghdr *n, void *arg)
  42{
  43        struct rtnl_dump_args *args = arg;
  44        FILE *fp = args->fp;
  45        int ifindex = args->ifindex;
  46        struct ifinfomsg *ifi = NLMSG_DATA(n);
  47        int len = n->nlmsg_len;
  48        struct rtattr *tb[IFLA_MAX + 1];
  49        struct rtattr *ltb[IFLA_INET6_MAX + 1];
  50
  51        if (n->nlmsg_type != RTM_NEWLINK)
  52                return -1;
  53
  54        len -= NLMSG_LENGTH(sizeof(*ifi));
  55        if (len < 0)
  56                return -1;
  57
  58        if (ifi->ifi_family != AF_INET6)
  59                return 0;
  60        if (ifi->ifi_index == 0)
  61                return 0;
  62        if (ifindex > 0 && ifi->ifi_index != ifindex)
  63                return 0;
  64        if (ifi->ifi_flags & (IFF_LOOPBACK | IFF_NOARP))
  65                return 0;
  66
  67        parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), len);
  68        if (!tb[IFLA_PROTINFO])
  69                return -1;
  70
  71        parse_rtattr_nested(ltb, IFLA_INET6_MAX, tb[IFLA_PROTINFO]);
  72        if (!ltb[IFLA_INET6_TOKEN]) {
  73                fprintf(stderr, "Seems there's no support for IPv6 token!\n");
  74                return -1;
  75        }
  76
  77        open_json_object(NULL);
  78        print_string(PRINT_FP, NULL, "token ", NULL);
  79        print_color_string(PRINT_ANY,
  80                           ifa_family_color(ifi->ifi_family),
  81                           "token", "%s",
  82                           format_host_rta(ifi->ifi_family, ltb[IFLA_INET6_TOKEN]));
  83        print_string(PRINT_FP, NULL, " dev ", NULL);
  84        print_color_string(PRINT_ANY, COLOR_IFNAME,
  85                           "ifname", "%s\n",
  86                           ll_index_to_name(ifi->ifi_index));
  87        close_json_object();
  88        fflush(fp);
  89
  90        return 0;
  91}
  92
  93static int iptoken_list(int argc, char **argv)
  94{
  95        int af = AF_INET6;
  96        struct rtnl_dump_args da = { .fp = stdout };
  97
  98        while (argc > 0) {
  99                if (strcmp(*argv, "dev") == 0) {
 100                        NEXT_ARG();
 101                        if ((da.ifindex = ll_name_to_index(*argv)) == 0)
 102                                invarg("dev is invalid\n", *argv);
 103                        break;
 104                }
 105                argc--; argv++;
 106        }
 107
 108        if (rtnl_linkdump_req(&rth, af) < 0) {
 109                perror("Cannot send dump request");
 110                return -1;
 111        }
 112
 113        new_json_obj(json);
 114        if (rtnl_dump_filter(&rth, print_token, &da) < 0) {
 115                delete_json_obj();
 116                fprintf(stderr, "Dump terminated\n");
 117                return -1;
 118        }
 119        delete_json_obj();
 120
 121        return 0;
 122}
 123
 124static int iptoken_set(int argc, char **argv, bool delete)
 125{
 126        struct {
 127                struct nlmsghdr n;
 128                struct ifinfomsg ifi;
 129                char buf[512];
 130        } req = {
 131                .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)),
 132                .n.nlmsg_flags = NLM_F_REQUEST,
 133                .n.nlmsg_type = RTM_SETLINK,
 134                .ifi.ifi_family = AF_INET6,
 135        };
 136        struct rtattr *afs, *afs6;
 137        bool have_token = delete, have_dev = false;
 138        inet_prefix addr = { .bytelen = 16, };
 139
 140        while (argc > 0) {
 141                if (strcmp(*argv, "dev") == 0) {
 142                        NEXT_ARG();
 143                        if (!have_dev) {
 144                                if ((req.ifi.ifi_index =
 145                                     ll_name_to_index(*argv)) == 0)
 146                                        invarg("dev is invalid\n", *argv);
 147                                have_dev = true;
 148                        }
 149                } else {
 150                        if (matches(*argv, "help") == 0)
 151                                usage();
 152                        if (!have_token) {
 153                                get_prefix(&addr, *argv, req.ifi.ifi_family);
 154                                have_token = true;
 155                        }
 156                }
 157                argc--; argv++;
 158        }
 159
 160        if (!have_token) {
 161                fprintf(stderr, "Not enough information: token is required.\n");
 162                return -1;
 163        }
 164        if (!have_dev) {
 165                fprintf(stderr, "Not enough information: \"dev\" argument is required.\n");
 166                return -1;
 167        }
 168
 169        afs = addattr_nest(&req.n, sizeof(req), IFLA_AF_SPEC);
 170        afs6 = addattr_nest(&req.n, sizeof(req), AF_INET6);
 171        addattr_l(&req.n, sizeof(req), IFLA_INET6_TOKEN,
 172                  &addr.data, addr.bytelen);
 173        addattr_nest_end(&req.n, afs6);
 174        addattr_nest_end(&req.n, afs);
 175
 176        if (rtnl_talk(&rth, &req.n, NULL) < 0)
 177                return -2;
 178
 179        return 0;
 180}
 181
 182int do_iptoken(int argc, char **argv)
 183{
 184        ll_init_map(&rth);
 185
 186        if (argc < 1) {
 187                return iptoken_list(0, NULL);
 188        } else if (matches(argv[0], "list") == 0 ||
 189                   matches(argv[0], "lst") == 0 ||
 190                   matches(argv[0], "show") == 0) {
 191                return iptoken_list(argc - 1, argv + 1);
 192        } else if (matches(argv[0], "set") == 0 ||
 193                   matches(argv[0], "add") == 0) {
 194                return iptoken_set(argc - 1, argv + 1, false);
 195        } else if (matches(argv[0], "delete") == 0) {
 196                return iptoken_set(argc - 1, argv + 1, true);
 197        } else if (matches(argv[0], "get") == 0) {
 198                return iptoken_list(argc - 1, argv + 1);
 199        } else if (matches(argv[0], "help") == 0)
 200                usage();
 201
 202        fprintf(stderr, "Command \"%s\" is unknown, try \"ip token help\".\n", *argv);
 203        exit(-1);
 204}
 205