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