iproute2/ip/ipseg6.c
<<
>>
Prefs
   1/*
   2 * seg6.c "ip sr/seg6"
   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 *        version 2 as published by the Free Software Foundation;
   7 *
   8 * Author: David Lebrun <david.lebrun@uclouvain.be>
   9 */
  10
  11#include <stdio.h>
  12#include <stdlib.h>
  13#include <string.h>
  14#include <unistd.h>
  15#include <errno.h>
  16#include <sys/types.h>
  17#include <sys/socket.h>
  18#include <arpa/inet.h>
  19#include <sys/ioctl.h>
  20#include <linux/if.h>
  21
  22#include <linux/genetlink.h>
  23#include <linux/seg6_genl.h>
  24#include <linux/seg6_hmac.h>
  25
  26#include "utils.h"
  27#include "ip_common.h"
  28#include "libgenl.h"
  29#include "json_print.h"
  30
  31#define HMAC_KEY_PROMPT "Enter secret for HMAC key ID (blank to delete): "
  32
  33static void usage(void)
  34{
  35        fprintf(stderr,
  36                "Usage: ip sr { COMMAND | help }\n"
  37                "          ip sr hmac show\n"
  38                "          ip sr hmac set KEYID ALGO\n"
  39                "          ip sr tunsrc show\n"
  40                "          ip sr tunsrc set ADDRESS\n"
  41                "where  ALGO := { sha1 | sha256 }\n");
  42        exit(-1);
  43}
  44
  45static struct rtnl_handle grth = { .fd = -1 };
  46static int genl_family = -1;
  47
  48#define SEG6_REQUEST(_req, _bufsiz, _cmd, _flags) \
  49        GENL_REQUEST(_req, _bufsiz, genl_family, 0, \
  50                                SEG6_GENL_VERSION, _cmd, _flags)
  51
  52static struct {
  53        unsigned int cmd;
  54        inet_prefix addr;
  55        __u32 keyid;
  56        const char *pass;
  57        __u8 alg_id;
  58} opts;
  59
  60static void print_dumphmac(struct rtattr *attrs[])
  61{
  62        char secret[64];
  63        char *algstr;
  64        __u8 slen = rta_getattr_u8(attrs[SEG6_ATTR_SECRETLEN]);
  65        __u8 alg_id = rta_getattr_u8(attrs[SEG6_ATTR_ALGID]);
  66
  67        memset(secret, 0, 64);
  68
  69        if (slen > 63) {
  70                fprintf(stderr, "HMAC secret length %d > 63, truncated\n", slen);
  71                slen = 63;
  72        }
  73
  74        memcpy(secret, RTA_DATA(attrs[SEG6_ATTR_SECRET]), slen);
  75
  76        switch (alg_id) {
  77        case SEG6_HMAC_ALGO_SHA1:
  78                algstr = "sha1";
  79                break;
  80        case SEG6_HMAC_ALGO_SHA256:
  81                algstr = "sha256";
  82                break;
  83        default:
  84                algstr = "<unknown>";
  85        }
  86
  87        print_uint(PRINT_ANY, "hmac", "hmac %u ",
  88                   rta_getattr_u32(attrs[SEG6_ATTR_HMACKEYID]));
  89        print_string(PRINT_ANY, "algo", "algo %s ", algstr);
  90        print_string(PRINT_ANY, "secret", "secret \"%s\"\n", secret);
  91}
  92
  93static void print_tunsrc(struct rtattr *attrs[])
  94{
  95        const char *dst
  96                = rt_addr_n2a(AF_INET6, 16,
  97                              RTA_DATA(attrs[SEG6_ATTR_DST]));
  98
  99        print_string(PRINT_ANY, "tunsrc",
 100                     "tunsrc addr %s\n", dst);
 101}
 102
 103static int process_msg(struct nlmsghdr *n, void *arg)
 104{
 105        struct rtattr *attrs[SEG6_ATTR_MAX + 1];
 106        struct genlmsghdr *ghdr;
 107        int len = n->nlmsg_len;
 108
 109        if (n->nlmsg_type != genl_family)
 110                return -1;
 111
 112        len -= NLMSG_LENGTH(GENL_HDRLEN);
 113        if (len < 0)
 114                return -1;
 115
 116        ghdr = NLMSG_DATA(n);
 117
 118        parse_rtattr(attrs, SEG6_ATTR_MAX, (void *)ghdr + GENL_HDRLEN, len);
 119
 120        open_json_object(NULL);
 121        switch (ghdr->cmd) {
 122        case SEG6_CMD_DUMPHMAC:
 123                print_dumphmac(attrs);
 124                break;
 125
 126        case SEG6_CMD_GET_TUNSRC:
 127                print_tunsrc(attrs);
 128                break;
 129        }
 130        close_json_object();
 131
 132        return 0;
 133}
 134
 135static int seg6_do_cmd(void)
 136{
 137        SEG6_REQUEST(req, 1024, opts.cmd, NLM_F_REQUEST);
 138        struct nlmsghdr *answer;
 139        int repl = 0, dump = 0;
 140
 141        if (genl_family < 0) {
 142                if (rtnl_open_byproto(&grth, 0, NETLINK_GENERIC) < 0) {
 143                        fprintf(stderr, "Cannot open generic netlink socket\n");
 144                        exit(1);
 145                }
 146                genl_family = genl_resolve_family(&grth, SEG6_GENL_NAME);
 147                if (genl_family < 0)
 148                        exit(1);
 149                req.n.nlmsg_type = genl_family;
 150        }
 151
 152        switch (opts.cmd) {
 153        case SEG6_CMD_SETHMAC:
 154        {
 155                addattr32(&req.n, sizeof(req), SEG6_ATTR_HMACKEYID, opts.keyid);
 156                addattr8(&req.n, sizeof(req), SEG6_ATTR_SECRETLEN,
 157                         strlen(opts.pass));
 158                addattr8(&req.n, sizeof(req), SEG6_ATTR_ALGID, opts.alg_id);
 159                if (strlen(opts.pass))
 160                        addattr_l(&req.n, sizeof(req), SEG6_ATTR_SECRET,
 161                                  opts.pass, strlen(opts.pass));
 162                break;
 163        }
 164        case SEG6_CMD_SET_TUNSRC:
 165                addattr_l(&req.n, sizeof(req), SEG6_ATTR_DST, opts.addr.data,
 166                          sizeof(struct in6_addr));
 167                break;
 168        case SEG6_CMD_DUMPHMAC:
 169                dump = 1;
 170                break;
 171        case SEG6_CMD_GET_TUNSRC:
 172                repl = 1;
 173                break;
 174        }
 175
 176        if (!repl && !dump) {
 177                if (rtnl_talk(&grth, &req.n, NULL) < 0)
 178                        return -1;
 179        } else if (repl) {
 180                if (rtnl_talk(&grth, &req.n, &answer) < 0)
 181                        return -2;
 182                new_json_obj(json);
 183                if (process_msg(answer, stdout) < 0) {
 184                        fprintf(stderr, "Error parsing reply\n");
 185                        exit(1);
 186                }
 187                delete_json_obj();
 188                free(answer);
 189        } else {
 190                req.n.nlmsg_flags |= NLM_F_DUMP;
 191                req.n.nlmsg_seq = grth.dump = ++grth.seq;
 192                if (rtnl_send(&grth, &req, req.n.nlmsg_len) < 0) {
 193                        perror("Failed to send dump request");
 194                        exit(1);
 195                }
 196
 197                new_json_obj(json);
 198                if (rtnl_dump_filter(&grth, process_msg, stdout) < 0) {
 199                        fprintf(stderr, "Dump terminated\n");
 200                        exit(1);
 201                }
 202                delete_json_obj();
 203                fflush(stdout);
 204        }
 205
 206        return 0;
 207}
 208
 209int do_seg6(int argc, char **argv)
 210{
 211        if (argc < 1 || matches(*argv, "help") == 0)
 212                usage();
 213
 214        memset(&opts, 0, sizeof(opts));
 215
 216        if (matches(*argv, "hmac") == 0) {
 217                NEXT_ARG();
 218                if (matches(*argv, "show") == 0) {
 219                        opts.cmd = SEG6_CMD_DUMPHMAC;
 220                } else if (matches(*argv, "set") == 0) {
 221                        NEXT_ARG();
 222                        if (get_u32(&opts.keyid, *argv, 0) || opts.keyid == 0)
 223                                invarg("hmac KEYID value is invalid", *argv);
 224                        NEXT_ARG();
 225                        if (strcmp(*argv, "sha1") == 0) {
 226                                opts.alg_id = SEG6_HMAC_ALGO_SHA1;
 227                        } else if (strcmp(*argv, "sha256") == 0) {
 228                                opts.alg_id = SEG6_HMAC_ALGO_SHA256;
 229                        } else {
 230                                invarg("hmac ALGO value is invalid", *argv);
 231                        }
 232                        opts.cmd = SEG6_CMD_SETHMAC;
 233                        opts.pass = getpass(HMAC_KEY_PROMPT);
 234                } else {
 235                        invarg("unknown", *argv);
 236                }
 237        } else if (matches(*argv, "tunsrc") == 0) {
 238                NEXT_ARG();
 239                if (matches(*argv, "show") == 0) {
 240                        opts.cmd = SEG6_CMD_GET_TUNSRC;
 241                } else if (matches(*argv, "set") == 0) {
 242                        NEXT_ARG();
 243                        opts.cmd = SEG6_CMD_SET_TUNSRC;
 244                        get_addr(&opts.addr, *argv, AF_INET6);
 245                } else {
 246                        invarg("unknown", *argv);
 247                }
 248        } else {
 249                invarg("unknown", *argv);
 250        }
 251
 252        return seg6_do_cmd();
 253}
 254