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