iproute2/tipc/node.c
<<
>>
Prefs
   1/*
   2 * node.c       TIPC node functionality.
   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:     Richard Alpe <richard.alpe@ericsson.com>
  10 */
  11
  12#include <stdio.h>
  13#include <stdlib.h>
  14#include <string.h>
  15#include <errno.h>
  16
  17#include <linux/tipc_netlink.h>
  18#include <linux/tipc.h>
  19#include <linux/genetlink.h>
  20#include <libmnl/libmnl.h>
  21
  22#include "cmdl.h"
  23#include "msg.h"
  24#include "misc.h"
  25#include "node.h"
  26
  27static int node_list_cb(const struct nlmsghdr *nlh, void *data)
  28{
  29        struct nlattr *info[TIPC_NLA_MAX + 1] = {};
  30        struct nlattr *attrs[TIPC_NLA_NODE_MAX + 1] = {};
  31        char str[33] = {};
  32        uint32_t addr;
  33
  34        mnl_attr_parse(nlh, sizeof(struct genlmsghdr), parse_attrs, info);
  35        if (!info[TIPC_NLA_NODE])
  36                return MNL_CB_ERROR;
  37
  38        mnl_attr_parse_nested(info[TIPC_NLA_NODE], parse_attrs, attrs);
  39        if (!attrs[TIPC_NLA_NODE_ADDR])
  40                return MNL_CB_ERROR;
  41
  42        addr = mnl_attr_get_u32(attrs[TIPC_NLA_NODE_ADDR]);
  43        hash2nodestr(addr, str);
  44        printf("%-32s %08x ", str, addr);
  45        if (attrs[TIPC_NLA_NODE_UP])
  46                printf("up\n");
  47        else
  48                printf("down\n");
  49        return MNL_CB_OK;
  50}
  51
  52static int cmd_node_list(struct nlmsghdr *nlh, const struct cmd *cmd,
  53                         struct cmdl *cmdl, void *data)
  54{
  55        char buf[MNL_SOCKET_BUFFER_SIZE];
  56
  57        if (help_flag) {
  58                fprintf(stderr, "Usage: %s node list\n", cmdl->argv[0]);
  59                return -EINVAL;
  60        }
  61
  62        if (!(nlh = msg_init(buf, TIPC_NL_NODE_GET))) {
  63                fprintf(stderr, "error, message initialisation failed\n");
  64                return -1;
  65        }
  66        printf("Node Identity                    Hash     State\n");
  67        return msg_dumpit(nlh, node_list_cb, NULL);
  68}
  69
  70static int cmd_node_set_addr(struct nlmsghdr *nlh, const struct cmd *cmd,
  71                             struct cmdl *cmdl, void *data)
  72{
  73        char *str;
  74        uint32_t addr;
  75        struct nlattr *nest;
  76        char buf[MNL_SOCKET_BUFFER_SIZE];
  77
  78        if (cmdl->argc != cmdl->optind + 1) {
  79                fprintf(stderr, "Usage: %s node set address ADDRESS\n",
  80                        cmdl->argv[0]);
  81                return -EINVAL;
  82        }
  83
  84        str = shift_cmdl(cmdl);
  85        addr = str2addr(str);
  86        if (!addr)
  87                return -1;
  88
  89        if (!(nlh = msg_init(buf, TIPC_NL_NET_SET))) {
  90                fprintf(stderr, "error, message initialisation failed\n");
  91                return -1;
  92        }
  93
  94        nest = mnl_attr_nest_start(nlh, TIPC_NLA_NET);
  95        mnl_attr_put_u32(nlh, TIPC_NLA_NET_ADDR, addr);
  96        mnl_attr_nest_end(nlh, nest);
  97
  98        return msg_doit(nlh, NULL, NULL);
  99}
 100
 101static int cmd_node_get_addr(struct nlmsghdr *nlh, const struct cmd *cmd,
 102                             struct cmdl *cmdl, void *data)
 103{
 104        int sk;
 105        socklen_t sz = sizeof(struct sockaddr_tipc);
 106        struct sockaddr_tipc addr;
 107
 108        sk = socket(AF_TIPC, SOCK_RDM, 0);
 109        if (sk < 0) {
 110                fprintf(stderr, "opening TIPC socket: %s\n", strerror(errno));
 111                return -1;
 112        }
 113
 114        if (getsockname(sk, (struct sockaddr *)&addr, &sz) < 0) {
 115                fprintf(stderr, "getting TIPC socket address: %s\n",
 116                        strerror(errno));
 117                close(sk);
 118                return -1;
 119        }
 120        close(sk);
 121
 122        printf("%08x\n", addr.addr.id.node);
 123        return 0;
 124}
 125
 126static int cmd_node_set_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd,
 127                               struct cmdl *cmdl, void *data)
 128{
 129        char buf[MNL_SOCKET_BUFFER_SIZE];
 130        uint8_t id[16] = {0,};
 131        uint64_t *w0 = (uint64_t *) &id[0];
 132        uint64_t *w1 = (uint64_t *) &id[8];
 133        struct nlattr *nest;
 134        char *str;
 135
 136        if (cmdl->argc != cmdl->optind + 1) {
 137                fprintf(stderr, "Usage: %s node set nodeid NODE_ID\n",
 138                        cmdl->argv[0]);
 139                return -EINVAL;
 140        }
 141
 142        str = shift_cmdl(cmdl);
 143        if (str2nodeid(str, id)) {
 144                fprintf(stderr, "Invalid node identity\n");
 145                return -EINVAL;
 146        }
 147
 148        nlh = msg_init(buf, TIPC_NL_NET_SET);
 149        if (!nlh) {
 150                fprintf(stderr, "error, message initialisation failed\n");
 151                return -1;
 152        }
 153        nest = mnl_attr_nest_start(nlh, TIPC_NLA_NET);
 154        mnl_attr_put_u64(nlh, TIPC_NLA_NET_NODEID, *w0);
 155        mnl_attr_put_u64(nlh, TIPC_NLA_NET_NODEID_W1, *w1);
 156        mnl_attr_nest_end(nlh, nest);
 157        return msg_doit(nlh, NULL, NULL);
 158}
 159
 160static void cmd_node_set_key_help(struct cmdl *cmdl)
 161{
 162        fprintf(stderr,
 163                "Usage: %s node set key KEY [algname ALGNAME] [PROPERTIES]\n"
 164                "       %s node set key rekeying REKEYING\n\n"
 165                "KEY\n"
 166                "  Symmetric KEY & SALT as a composite ASCII or hex string (0x...) in form:\n"
 167                "  [KEY: 16, 24 or 32 octets][SALT: 4 octets]\n\n"
 168                "ALGNAME\n"
 169                "  Cipher algorithm [default: \"gcm(aes)\"]\n\n"
 170                "PROPERTIES\n"
 171                "  master                - Set KEY as a cluster master key\n"
 172                "  <empty>               - Set KEY as a cluster key\n"
 173                "  nodeid NODEID         - Set KEY as a per-node key for own or peer\n\n"
 174                "REKEYING\n"
 175                "  INTERVAL              - Set rekeying interval (in minutes) [0: disable]\n"
 176                "  now                   - Trigger one (first) rekeying immediately\n\n"
 177                "EXAMPLES\n"
 178                "  %s node set key this_is_a_master_key master\n"
 179                "  %s node set key 0x746869735F69735F615F6B657931365F73616C74\n"
 180                "  %s node set key this_is_a_key16_salt algname \"gcm(aes)\" nodeid 1001002\n"
 181                "  %s node set key rekeying 600\n\n",
 182                cmdl->argv[0], cmdl->argv[0], cmdl->argv[0], cmdl->argv[0],
 183                cmdl->argv[0], cmdl->argv[0]);
 184}
 185
 186static int cmd_node_set_key(struct nlmsghdr *nlh, const struct cmd *cmd,
 187                            struct cmdl *cmdl, void *data)
 188{
 189        struct {
 190                union {
 191                        struct tipc_aead_key key;
 192                        char mem[TIPC_AEAD_KEY_SIZE_MAX];
 193                };
 194        } input = {};
 195        struct opt opts[] = {
 196                { "algname",    OPT_KEYVAL,     NULL },
 197                { "nodeid",     OPT_KEYVAL,     NULL },
 198                { "master",     OPT_KEY,        NULL },
 199                { "rekeying",   OPT_KEYVAL,     NULL },
 200                { NULL }
 201        };
 202        struct nlattr *nest;
 203        struct opt *opt_algname, *opt_nodeid, *opt_master, *opt_rekeying;
 204        char buf[MNL_SOCKET_BUFFER_SIZE];
 205        uint8_t id[TIPC_NODEID_LEN] = {0,};
 206        uint32_t rekeying = 0;
 207        bool has_key = false;
 208        int keysize;
 209        char *str;
 210
 211        if (help_flag || cmdl->optind >= cmdl->argc) {
 212                (cmd->help)(cmdl);
 213                return -EINVAL;
 214        }
 215
 216        /* Check if command starts with opts i.e. "rekeying" opt without key */
 217        if (find_opt(opts, cmdl->argv[cmdl->optind]))
 218                goto get_ops;
 219
 220        /* Get user key */
 221        has_key = true;
 222        str = shift_cmdl(cmdl);
 223        if (str2key(str, &input.key)) {
 224                fprintf(stderr, "error, invalid key input\n");
 225                return -EINVAL;
 226        }
 227
 228get_ops:
 229        if (parse_opts(opts, cmdl) < 0)
 230                return -EINVAL;
 231
 232        /* Get rekeying time */
 233        opt_rekeying = get_opt(opts, "rekeying");
 234        if (opt_rekeying) {
 235                if (!strcmp(opt_rekeying->val, "now"))
 236                        rekeying = TIPC_REKEYING_NOW;
 237                else
 238                        rekeying = atoi(opt_rekeying->val);
 239        }
 240
 241        /* Get algorithm name, default: "gcm(aes)" */
 242        opt_algname = get_opt(opts, "algname");
 243        if (!opt_algname)
 244                strcpy(input.key.alg_name, "gcm(aes)");
 245        else
 246                strcpy(input.key.alg_name, opt_algname->val);
 247
 248        /* Get node identity */
 249        opt_nodeid = get_opt(opts, "nodeid");
 250        if (opt_nodeid && str2nodeid(opt_nodeid->val, id)) {
 251                fprintf(stderr, "error, invalid node identity\n");
 252                return -EINVAL;
 253        }
 254
 255        /* Get master key indication */
 256        opt_master = get_opt(opts, "master");
 257
 258        /* Sanity check if wrong option */
 259        if (opt_nodeid && opt_master) {
 260                fprintf(stderr, "error, per-node key cannot be master\n");
 261                return -EINVAL;
 262        }
 263
 264        /* Init & do the command */
 265        nlh = msg_init(buf, TIPC_NL_KEY_SET);
 266        if (!nlh) {
 267                fprintf(stderr, "error, message initialisation failed\n");
 268                return -1;
 269        }
 270
 271        nest = mnl_attr_nest_start(nlh, TIPC_NLA_NODE);
 272        if (has_key) {
 273                keysize = tipc_aead_key_size(&input.key);
 274                mnl_attr_put(nlh, TIPC_NLA_NODE_KEY, keysize, &input.key);
 275                if (opt_nodeid)
 276                        mnl_attr_put(nlh, TIPC_NLA_NODE_ID, TIPC_NODEID_LEN, id);
 277                if (opt_master)
 278                        mnl_attr_put(nlh, TIPC_NLA_NODE_KEY_MASTER, 0, NULL);
 279        }
 280        if (opt_rekeying)
 281                mnl_attr_put_u32(nlh, TIPC_NLA_NODE_REKEYING, rekeying);
 282
 283        mnl_attr_nest_end(nlh, nest);
 284        return msg_doit(nlh, NULL, NULL);
 285}
 286
 287static int cmd_node_flush_key(struct nlmsghdr *nlh, const struct cmd *cmd,
 288                              struct cmdl *cmdl, void *data)
 289{
 290        char buf[MNL_SOCKET_BUFFER_SIZE];
 291
 292        if (help_flag) {
 293                (cmd->help)(cmdl);
 294                return -EINVAL;
 295        }
 296
 297        /* Init & do the command */
 298        nlh = msg_init(buf, TIPC_NL_KEY_FLUSH);
 299        if (!nlh) {
 300                fprintf(stderr, "error, message initialisation failed\n");
 301                return -1;
 302        }
 303        return msg_doit(nlh, NULL, NULL);
 304}
 305
 306static int nodeid_get_cb(const struct nlmsghdr *nlh, void *data)
 307{
 308        struct nlattr *info[TIPC_NLA_MAX + 1] = {};
 309        struct nlattr *attrs[TIPC_NLA_NET_MAX + 1] = {};
 310        char str[33] = {0,};
 311        uint8_t id[16] = {0,};
 312        uint64_t *w0 = (uint64_t *) &id[0];
 313        uint64_t *w1 = (uint64_t *) &id[8];
 314
 315        mnl_attr_parse(nlh, sizeof(struct genlmsghdr), parse_attrs, info);
 316        if (!info[TIPC_NLA_NET])
 317                return MNL_CB_ERROR;
 318
 319        mnl_attr_parse_nested(info[TIPC_NLA_NET], parse_attrs, attrs);
 320        if (!attrs[TIPC_NLA_NET_ID])
 321                return MNL_CB_ERROR;
 322
 323        *w0 = mnl_attr_get_u64(attrs[TIPC_NLA_NET_NODEID]);
 324        *w1 = mnl_attr_get_u64(attrs[TIPC_NLA_NET_NODEID_W1]);
 325        nodeid2str(id, str);
 326        printf("Node Identity                    Hash\n");
 327        printf("%-33s", str);
 328        cmd_node_get_addr(NULL, NULL, NULL, NULL);
 329        return MNL_CB_OK;
 330}
 331
 332static int cmd_node_get_nodeid(struct nlmsghdr *nlh, const struct cmd *cmd,
 333                               struct cmdl *cmdl, void *data)
 334{
 335        char buf[MNL_SOCKET_BUFFER_SIZE];
 336
 337        if (help_flag) {
 338                (cmd->help)(cmdl);
 339                return -EINVAL;
 340        }
 341
 342        nlh = msg_init(buf, TIPC_NL_NET_GET);
 343        if (!nlh) {
 344                fprintf(stderr, "error, message initialisation failed\n");
 345                return -1;
 346        }
 347
 348        return msg_dumpit(nlh, nodeid_get_cb, NULL);
 349}
 350
 351
 352static int netid_get_cb(const struct nlmsghdr *nlh, void *data)
 353{
 354        struct nlattr *info[TIPC_NLA_MAX + 1] = {};
 355        struct nlattr *attrs[TIPC_NLA_NET_MAX + 1] = {};
 356
 357        mnl_attr_parse(nlh, sizeof(struct genlmsghdr), parse_attrs, info);
 358        if (!info[TIPC_NLA_NET])
 359                return MNL_CB_ERROR;
 360
 361        mnl_attr_parse_nested(info[TIPC_NLA_NET], parse_attrs, attrs);
 362        if (!attrs[TIPC_NLA_NET_ID])
 363                return MNL_CB_ERROR;
 364
 365        printf("%u\n", mnl_attr_get_u32(attrs[TIPC_NLA_NET_ID]));
 366
 367        return MNL_CB_OK;
 368}
 369
 370static int cmd_node_get_netid(struct nlmsghdr *nlh, const struct cmd *cmd,
 371                              struct cmdl *cmdl, void *data)
 372{
 373        char buf[MNL_SOCKET_BUFFER_SIZE];
 374
 375        if (help_flag) {
 376                (cmd->help)(cmdl);
 377                return -EINVAL;
 378        }
 379
 380        if (!(nlh = msg_init(buf, TIPC_NL_NET_GET))) {
 381                fprintf(stderr, "error, message initialisation failed\n");
 382                return -1;
 383        }
 384
 385        return msg_dumpit(nlh, netid_get_cb, NULL);
 386}
 387
 388static int cmd_node_set_netid(struct nlmsghdr *nlh, const struct cmd *cmd,
 389                              struct cmdl *cmdl, void *data)
 390{
 391        int netid;
 392        char buf[MNL_SOCKET_BUFFER_SIZE];
 393        struct nlattr *nest;
 394
 395        if (help_flag) {
 396                (cmd->help)(cmdl);
 397                return -EINVAL;
 398        }
 399
 400        if (!(nlh = msg_init(buf, TIPC_NL_NET_SET))) {
 401                fprintf(stderr, "error, message initialisation failed\n");
 402                return -1;
 403        }
 404
 405        if (cmdl->argc != cmdl->optind + 1) {
 406                fprintf(stderr, "Usage: %s node set netid NETID\n",
 407                        cmdl->argv[0]);
 408                return -EINVAL;
 409        }
 410        netid = atoi(shift_cmdl(cmdl));
 411
 412        nest = mnl_attr_nest_start(nlh, TIPC_NLA_NET);
 413        mnl_attr_put_u32(nlh, TIPC_NLA_NET_ID, netid);
 414        mnl_attr_nest_end(nlh, nest);
 415
 416        return msg_doit(nlh, NULL, NULL);
 417}
 418
 419static void cmd_node_flush_help(struct cmdl *cmdl)
 420{
 421        fprintf(stderr,
 422                "Usage: %s node flush PROPERTY\n\n"
 423                "PROPERTIES\n"
 424                " key                   - Flush all symmetric-keys\n",
 425                cmdl->argv[0]);
 426}
 427
 428static int cmd_node_flush(struct nlmsghdr *nlh, const struct cmd *cmd,
 429                          struct cmdl *cmdl, void *data)
 430{
 431        const struct cmd cmds[] = {
 432                { "key",        cmd_node_flush_key,     NULL },
 433                { NULL }
 434        };
 435
 436        return run_cmd(nlh, cmd, cmds, cmdl, NULL);
 437}
 438
 439static void cmd_node_set_help(struct cmdl *cmdl)
 440{
 441        fprintf(stderr,
 442                "Usage: %s node set PROPERTY\n\n"
 443                "PROPERTIES\n"
 444                " identity NODEID       - Set node identity\n"
 445                " clusterid CLUSTERID   - Set local cluster id\n"
 446                " key PROPERTY          - Set symmetric-key\n",
 447                cmdl->argv[0]);
 448}
 449
 450static int cmd_node_set(struct nlmsghdr *nlh, const struct cmd *cmd,
 451                        struct cmdl *cmdl, void *data)
 452{
 453        const struct cmd cmds[] = {
 454                { "address",    cmd_node_set_addr,      NULL },
 455                { "identity",   cmd_node_set_nodeid,    NULL },
 456                { "netid",      cmd_node_set_netid,     NULL },
 457                { "clusterid",  cmd_node_set_netid,     NULL },
 458                { "key",        cmd_node_set_key,       cmd_node_set_key_help },
 459                { NULL }
 460        };
 461
 462        return run_cmd(nlh, cmd, cmds, cmdl, NULL);
 463}
 464
 465static void cmd_node_get_help(struct cmdl *cmdl)
 466{
 467        fprintf(stderr,
 468                "Usage: %s node get PROPERTY\n\n"
 469                "PROPERTIES\n"
 470                " identity              - Get node identity\n"
 471                " clusterid             - Get local clusterid\n",
 472                cmdl->argv[0]);
 473}
 474
 475static int cmd_node_get(struct nlmsghdr *nlh, const struct cmd *cmd,
 476                        struct cmdl *cmdl, void *data)
 477{
 478        const struct cmd cmds[] = {
 479                { "address",    cmd_node_get_addr,      NULL },
 480                { "identity",   cmd_node_get_nodeid,    NULL },
 481                { "netid",      cmd_node_get_netid,     NULL },
 482                { "clusterid",  cmd_node_get_netid,     NULL },
 483                { NULL }
 484        };
 485
 486        return run_cmd(nlh, cmd, cmds, cmdl, NULL);
 487}
 488
 489void cmd_node_help(struct cmdl *cmdl)
 490{
 491        fprintf(stderr,
 492                "Usage: %s node COMMAND [ARGS] ...\n\n"
 493                "COMMANDS\n"
 494                " list                  - List remote nodes\n"
 495                " get                   - Get local node parameters\n"
 496                " set                   - Set local node parameters\n"
 497                " flush                 - Flush local node parameters\n",
 498                cmdl->argv[0]);
 499}
 500
 501int cmd_node(struct nlmsghdr *nlh, const struct cmd *cmd, struct cmdl *cmdl,
 502             void *data)
 503{
 504        const struct cmd cmds[] = {
 505                { "list",       cmd_node_list,  NULL },
 506                { "get",        cmd_node_get,   cmd_node_get_help },
 507                { "set",        cmd_node_set,   cmd_node_set_help },
 508                { "flush",      cmd_node_flush, cmd_node_flush_help},
 509                { NULL }
 510        };
 511
 512        return run_cmd(nlh, cmd, cmds, cmdl, NULL);
 513}
 514