]> git.proxmox.com Git - mirror_iproute2.git/blob - ip/iprule.c
iprule: add json support
[mirror_iproute2.git] / ip / iprule.c
1 /*
2 * iprule.c "ip rule".
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: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
10 *
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <netinet/ip.h>
20 #include <arpa/inet.h>
21 #include <string.h>
22 #include <linux/if.h>
23 #include <linux/fib_rules.h>
24 #include <errno.h>
25
26 #include "rt_names.h"
27 #include "utils.h"
28 #include "ip_common.h"
29 #include "json_print.h"
30
31 enum list_action {
32 IPRULE_LIST,
33 IPRULE_FLUSH,
34 IPRULE_SAVE,
35 };
36
37 extern struct rtnl_handle rth;
38
39 static void usage(void) __attribute__((noreturn));
40
41 static void usage(void)
42 {
43 fprintf(stderr,
44 "Usage: ip rule { add | del } SELECTOR ACTION\n"
45 " ip rule { flush | save | restore }\n"
46 " ip rule [ list [ SELECTOR ]]\n"
47 "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"
48 " [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ l3mdev ]\n"
49 " [ uidrange NUMBER-NUMBER ]\n"
50 "ACTION := [ table TABLE_ID ]\n"
51 " [ protocol PROTO ]\n"
52 " [ nat ADDRESS ]\n"
53 " [ realms [SRCREALM/]DSTREALM ]\n"
54 " [ goto NUMBER ]\n"
55 " SUPPRESSOR\n"
56 "SUPPRESSOR := [ suppress_prefixlength NUMBER ]\n"
57 " [ suppress_ifgroup DEVGROUP ]\n"
58 "TABLE_ID := [ local | main | default | NUMBER ]\n");
59 exit(-1);
60 }
61
62 static struct
63 {
64 int not;
65 int l3mdev;
66 int iifmask, oifmask, uidrange;
67 unsigned int tb;
68 unsigned int tos, tosmask;
69 unsigned int pref, prefmask;
70 unsigned int fwmark, fwmask;
71 char iif[IFNAMSIZ];
72 char oif[IFNAMSIZ];
73 struct fib_rule_uid_range range;
74 inet_prefix src;
75 inet_prefix dst;
76 int protocol;
77 int protocolmask;
78 } filter;
79
80 static inline int frh_get_table(struct fib_rule_hdr *frh, struct rtattr **tb)
81 {
82 __u32 table = frh->table;
83 if (tb[RTA_TABLE])
84 table = rta_getattr_u32(tb[RTA_TABLE]);
85 return table;
86 }
87
88 static bool filter_nlmsg(struct nlmsghdr *n, struct rtattr **tb, int host_len)
89 {
90 struct fib_rule_hdr *frh = NLMSG_DATA(n);
91 __u32 table;
92
93 if (preferred_family != AF_UNSPEC && frh->family != preferred_family)
94 return false;
95
96 if (filter.prefmask &&
97 filter.pref ^ (tb[FRA_PRIORITY] ? rta_getattr_u32(tb[FRA_PRIORITY]) : 0))
98 return false;
99 if (filter.not && !(frh->flags & FIB_RULE_INVERT))
100 return false;
101
102 if (filter.src.family) {
103 inet_prefix *f_src = &filter.src;
104
105 if (f_src->family != frh->family ||
106 f_src->bitlen > frh->src_len)
107 return false;
108
109 if (inet_addr_match_rta(f_src, tb[FRA_SRC]))
110 return false;
111 }
112
113 if (filter.dst.family) {
114 inet_prefix *f_dst = &filter.dst;
115
116 if (f_dst->family != frh->family ||
117 f_dst->bitlen > frh->dst_len)
118 return false;
119
120 if (inet_addr_match_rta(f_dst, tb[FRA_DST]))
121 return false;
122 }
123
124 if (filter.tosmask && filter.tos ^ frh->tos)
125 return false;
126
127 if (filter.fwmark) {
128 __u32 mark = 0;
129
130 if (tb[FRA_FWMARK])
131 mark = rta_getattr_u32(tb[FRA_FWMARK]);
132 if (filter.fwmark ^ mark)
133 return false;
134 }
135 if (filter.fwmask) {
136 __u32 mask = 0;
137
138 if (tb[FRA_FWMASK])
139 mask = rta_getattr_u32(tb[FRA_FWMASK]);
140 if (filter.fwmask ^ mask)
141 return false;
142 }
143
144 if (filter.iifmask) {
145 if (tb[FRA_IFNAME]) {
146 if (strcmp(filter.iif, rta_getattr_str(tb[FRA_IFNAME])) != 0)
147 return false;
148 } else {
149 return false;
150 }
151 }
152
153 if (filter.oifmask) {
154 if (tb[FRA_OIFNAME]) {
155 if (strcmp(filter.oif, rta_getattr_str(tb[FRA_OIFNAME])) != 0)
156 return false;
157 } else {
158 return false;
159 }
160 }
161
162 if (filter.l3mdev && !(tb[FRA_L3MDEV] && rta_getattr_u8(tb[FRA_L3MDEV])))
163 return false;
164
165 if (filter.uidrange) {
166 struct fib_rule_uid_range *r = RTA_DATA(tb[FRA_UID_RANGE]);
167
168 if (!tb[FRA_UID_RANGE] ||
169 r->start != filter.range.start ||
170 r->end != filter.range.end)
171 return false;
172 }
173
174 table = frh_get_table(frh, tb);
175 if (filter.tb > 0 && filter.tb ^ table)
176 return false;
177
178 return true;
179 }
180
181 int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
182 {
183 FILE *fp = arg;
184 struct fib_rule_hdr *frh = NLMSG_DATA(n);
185 int len = n->nlmsg_len;
186 int host_len = -1;
187 __u32 table, prio = 0;
188 struct rtattr *tb[FRA_MAX+1];
189 SPRINT_BUF(b1);
190
191 if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE)
192 return 0;
193
194 len -= NLMSG_LENGTH(sizeof(*frh));
195 if (len < 0)
196 return -1;
197
198 parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
199
200 host_len = af_bit_len(frh->family);
201
202 if (!filter_nlmsg(n, tb, host_len))
203 return 0;
204
205 open_json_object(NULL);
206 if (n->nlmsg_type == RTM_DELRULE)
207 print_bool(PRINT_ANY, "deleted", "Deleted ", true);
208
209 if (tb[FRA_PRIORITY])
210 prio = rta_getattr_u32(tb[FRA_PRIORITY]);
211
212 print_uint(PRINT_ANY, "priority", "%u:\t", prio);
213
214 if (frh->flags & FIB_RULE_INVERT)
215 print_null(PRINT_ANY, "not", "not ", NULL);
216
217 if (tb[FRA_SRC]) {
218 const char *src = rt_addr_n2a_rta(frh->family, tb[FRA_SRC]);
219
220 print_string(PRINT_FP, NULL, "from ", NULL);
221 print_color_string(PRINT_ANY, ifa_family_color(frh->family),
222 "src", "%s", src);
223 if (frh->src_len != host_len)
224 print_uint(PRINT_ANY, "srclen", "/%u ", frh->src_len);
225 else
226 print_string(PRINT_FP, NULL, " ", NULL);
227 } else if (frh->src_len) {
228 print_string(PRINT_ANY, "src", "from %s", "0");
229 print_uint(PRINT_ANY, "srclen", "/%u ", frh->src_len);
230 } else {
231 print_string(PRINT_ANY, "src", "from %s ", "all");
232 }
233
234 if (tb[FRA_DST]) {
235 const char *dst = rt_addr_n2a_rta(frh->family, tb[FRA_DST]);
236
237 print_string(PRINT_FP, NULL, "to ", NULL);
238 print_color_string(PRINT_ANY, ifa_family_color(frh->family),
239 "dst", "%s ", dst);
240 if (frh->dst_len != host_len)
241 print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len);
242 else
243 print_string(PRINT_FP, NULL, " ", NULL);
244 } else if (frh->dst_len) {
245 print_string(PRINT_ANY, "dst", "to %s", "0");
246 print_uint(PRINT_ANY, "dstlen", "/%u ", frh->dst_len);
247 }
248
249 if (frh->tos) {
250 print_string(PRINT_ANY, "tos",
251 "tos %s ",
252 rtnl_dsfield_n2a(frh->tos, b1, sizeof(b1)));
253 }
254
255 if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
256 __u32 mark = 0, mask = 0;
257
258 if (tb[FRA_FWMARK])
259 mark = rta_getattr_u32(tb[FRA_FWMARK]);
260
261 if (tb[FRA_FWMASK] &&
262 (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF) {
263 print_0xhex(PRINT_ANY, "fwmark", "fwmark 0x%x", mark);
264 print_0xhex(PRINT_ANY, "fwmask", "/0x%x ", mask);
265 } else {
266 print_0xhex(PRINT_ANY, "fwmark", "fwmark 0x%x ", mark);
267 }
268 }
269
270 if (tb[FRA_IFNAME]) {
271 if (!is_json_context())
272 fprintf(fp, "iif ");
273 print_color_string(PRINT_ANY, COLOR_IFNAME,
274 "iif", "%s ",
275 rta_getattr_str(tb[FRA_IFNAME]));
276
277 if (frh->flags & FIB_RULE_IIF_DETACHED)
278 print_null(PRINT_ANY, "iif_detached", "[detached] ",
279 NULL);
280 }
281
282 if (tb[FRA_OIFNAME]) {
283 if (!is_json_context())
284 fprintf(fp, "oif ");
285
286 print_color_string(PRINT_ANY, COLOR_IFNAME, "oif", "%s ",
287 rta_getattr_str(tb[FRA_OIFNAME]));
288
289 if (frh->flags & FIB_RULE_OIF_DETACHED)
290 print_null(PRINT_ANY, "oif_detached", "[detached] ",
291 NULL);
292 }
293
294 if (tb[FRA_L3MDEV]) {
295 __u8 mdev = rta_getattr_u8(tb[FRA_L3MDEV]);
296
297 if (mdev)
298 print_null(PRINT_ANY, "l3mdev",
299 "lookup [l3mdev-table] ", NULL);
300 }
301
302 if (tb[FRA_UID_RANGE]) {
303 struct fib_rule_uid_range *r = RTA_DATA(tb[FRA_UID_RANGE]);
304
305 print_uint(PRINT_ANY, "uid_start", "uidrange %u", r->start);
306 print_uint(PRINT_ANY, "uid_end", "-%u ", r->end);
307 }
308
309 table = frh_get_table(frh, tb);
310 if (table) {
311 print_string(PRINT_ANY, "table",
312 "lookup %s ",
313 rtnl_rttable_n2a(table, b1, sizeof(b1)));
314
315 if (tb[FRA_SUPPRESS_PREFIXLEN]) {
316 int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]);
317
318 if (pl != -1)
319 print_int(PRINT_ANY, "suppress_prefixlen",
320 "suppress_prefixlength %d ", pl);
321 }
322
323 if (tb[FRA_SUPPRESS_IFGROUP]) {
324 int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]);
325
326 if (group != -1) {
327 const char *grname
328 = rtnl_group_n2a(group, b1, sizeof(b1));
329
330 print_string(PRINT_ANY, "suppress_ifgroup",
331 "suppress_ifgroup %s ", grname);
332 }
333 }
334 }
335
336 if (tb[FRA_FLOW]) {
337 __u32 to = rta_getattr_u32(tb[FRA_FLOW]);
338 __u32 from = to>>16;
339
340 to &= 0xFFFF;
341 if (from)
342 print_string(PRINT_ANY,
343 "flow_from", "realms %s/",
344 rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
345
346 print_string(PRINT_ANY, "flow_to", "%s ",
347 rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
348 }
349
350 if (frh->action == RTN_NAT) {
351 if (tb[RTA_GATEWAY]) {
352 const char *gateway;
353
354 gateway = format_host_rta(frh->family, tb[RTA_GATEWAY]);
355
356 print_string(PRINT_ANY, "nat_gateway",
357 "map-to %s ", gateway);
358 } else {
359 print_null(PRINT_ANY, "masquerade", "masquerade", NULL);
360 }
361 } else if (frh->action == FR_ACT_GOTO) {
362 if (tb[FRA_GOTO])
363 print_uint(PRINT_ANY, "goto", "goto %u",
364 rta_getattr_u32(tb[FRA_GOTO]));
365 else
366 print_string(PRINT_ANY, "goto", "goto %s", "none");
367
368 if (frh->flags & FIB_RULE_UNRESOLVED)
369 print_null(PRINT_ANY, "unresolved", "unresolved", NULL);
370 } else if (frh->action == FR_ACT_NOP) {
371 print_null(PRINT_ANY, "nop", "nop", NULL);
372 } else if (frh->action != FR_ACT_TO_TBL) {
373 print_string(PRINT_ANY, "to_tbl", "%s",
374 rtnl_rtntype_n2a(frh->action, b1, sizeof(b1)));
375 }
376
377 if (tb[FRA_PROTOCOL]) {
378 __u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
379
380 if ((protocol && protocol != RTPROT_KERNEL) || show_details > 0) {
381 print_string(PRINT_ANY, "protocol", " proto %s ",
382 rtnl_rtprot_n2a(protocol, b1, sizeof(b1)));
383 }
384 }
385 print_string(PRINT_FP, NULL, "\n", "");
386 close_json_object();
387 fflush(fp);
388 return 0;
389 }
390
391 static __u32 rule_dump_magic = 0x71706986;
392
393 static int save_rule_prep(void)
394 {
395 int ret;
396
397 if (isatty(STDOUT_FILENO)) {
398 fprintf(stderr, "Not sending a binary stream to stdout\n");
399 return -1;
400 }
401
402 ret = write(STDOUT_FILENO, &rule_dump_magic, sizeof(rule_dump_magic));
403 if (ret != sizeof(rule_dump_magic)) {
404 fprintf(stderr, "Can't write magic to dump file\n");
405 return -1;
406 }
407
408 return 0;
409 }
410
411 static int save_rule(const struct sockaddr_nl *who,
412 struct nlmsghdr *n, void *arg)
413 {
414 int ret;
415
416 ret = write(STDOUT_FILENO, n, n->nlmsg_len);
417 if ((ret > 0) && (ret != n->nlmsg_len)) {
418 fprintf(stderr, "Short write while saving nlmsg\n");
419 ret = -EIO;
420 }
421
422 return ret == n->nlmsg_len ? 0 : ret;
423 }
424
425 static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n,
426 void *arg)
427 {
428 struct rtnl_handle rth2;
429 struct fib_rule_hdr *frh = NLMSG_DATA(n);
430 int len = n->nlmsg_len;
431 struct rtattr *tb[FRA_MAX+1];
432
433 len -= NLMSG_LENGTH(sizeof(*frh));
434 if (len < 0)
435 return -1;
436
437 parse_rtattr(tb, FRA_MAX, RTM_RTA(frh), len);
438
439 if (tb[FRA_PROTOCOL]) {
440 __u8 protocol = rta_getattr_u8(tb[FRA_PROTOCOL]);
441
442 if ((filter.protocol ^ protocol) & filter.protocolmask)
443 return 0;
444 }
445
446 if (tb[FRA_PRIORITY]) {
447 n->nlmsg_type = RTM_DELRULE;
448 n->nlmsg_flags = NLM_F_REQUEST;
449
450 if (rtnl_open(&rth2, 0) < 0)
451 return -1;
452
453 if (rtnl_talk(&rth2, n, NULL) < 0)
454 return -2;
455
456 rtnl_close(&rth2);
457 }
458
459 return 0;
460 }
461
462 static int iprule_list_flush_or_save(int argc, char **argv, int action)
463 {
464 rtnl_filter_t filter_fn;
465 int af = preferred_family;
466
467 if (af == AF_UNSPEC)
468 af = AF_INET;
469
470 if (action == IPRULE_SAVE && argc > 0) {
471 fprintf(stderr, "\"ip rule save\" does not take any arguments.\n");
472 return -1;
473 }
474
475 switch (action) {
476 case IPRULE_SAVE:
477 if (save_rule_prep())
478 return -1;
479 filter_fn = save_rule;
480 break;
481 case IPRULE_FLUSH:
482 filter_fn = flush_rule;
483 break;
484 default:
485 filter_fn = print_rule;
486 }
487
488 memset(&filter, 0, sizeof(filter));
489
490 while (argc > 0) {
491 if (matches(*argv, "preference") == 0 ||
492 matches(*argv, "order") == 0 ||
493 matches(*argv, "priority") == 0) {
494 __u32 pref;
495
496 NEXT_ARG();
497 if (get_u32(&pref, *argv, 0))
498 invarg("preference value is invalid\n", *argv);
499 filter.pref = pref;
500 filter.prefmask = 1;
501 } else if (strcmp(*argv, "not") == 0) {
502 filter.not = 1;
503 } else if (strcmp(*argv, "tos") == 0) {
504 __u32 tos;
505
506 NEXT_ARG();
507 if (rtnl_dsfield_a2n(&tos, *argv))
508 invarg("TOS value is invalid\n", *argv);
509 filter.tos = tos;
510 filter.tosmask = 1;
511 } else if (strcmp(*argv, "fwmark") == 0) {
512 char *slash;
513 __u32 fwmark, fwmask;
514
515 NEXT_ARG();
516 slash = strchr(*argv, '/');
517 if (slash != NULL)
518 *slash = '\0';
519 if (get_u32(&fwmark, *argv, 0))
520 invarg("fwmark value is invalid\n", *argv);
521 filter.fwmark = fwmark;
522 if (slash) {
523 if (get_u32(&fwmask, slash+1, 0))
524 invarg("fwmask value is invalid\n",
525 slash+1);
526 filter.fwmask = fwmask;
527 }
528 } else if (strcmp(*argv, "dev") == 0 ||
529 strcmp(*argv, "iif") == 0) {
530 NEXT_ARG();
531 if (get_ifname(filter.iif, *argv))
532 invarg("\"iif\"/\"dev\" not a valid ifname", *argv);
533 filter.iifmask = 1;
534 } else if (strcmp(*argv, "oif") == 0) {
535 NEXT_ARG();
536 if (get_ifname(filter.oif, *argv))
537 invarg("\"oif\" not a valid ifname", *argv);
538 filter.oifmask = 1;
539 } else if (strcmp(*argv, "l3mdev") == 0) {
540 filter.l3mdev = 1;
541 } else if (strcmp(*argv, "uidrange") == 0) {
542 NEXT_ARG();
543 filter.uidrange = 1;
544 if (sscanf(*argv, "%u-%u",
545 &filter.range.start,
546 &filter.range.end) != 2)
547 invarg("invalid UID range\n", *argv);
548
549 } else if (matches(*argv, "lookup") == 0 ||
550 matches(*argv, "table") == 0) {
551 __u32 tid;
552
553 NEXT_ARG();
554 if (rtnl_rttable_a2n(&tid, *argv))
555 invarg("table id value is invalid\n", *argv);
556 filter.tb = tid;
557 } else if (matches(*argv, "from") == 0 ||
558 matches(*argv, "src") == 0) {
559 NEXT_ARG();
560 if (get_prefix(&filter.src, *argv, af))
561 invarg("from value is invalid\n", *argv);
562 } else if (matches(*argv, "protocol") == 0) {
563 __u32 prot;
564 NEXT_ARG();
565 filter.protocolmask = -1;
566 if (rtnl_rtprot_a2n(&prot, *argv)) {
567 if (strcmp(*argv, "all") != 0)
568 invarg("invalid \"protocol\"\n", *argv);
569 prot = 0;
570 filter.protocolmask = 0;
571 }
572 filter.protocol = prot;
573 } else{
574 if (matches(*argv, "dst") == 0 ||
575 matches(*argv, "to") == 0) {
576 NEXT_ARG();
577 }
578 if (get_prefix(&filter.dst, *argv, af))
579 invarg("to value is invalid\n", *argv);
580 }
581 argc--; argv++;
582 }
583
584 if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) {
585 perror("Cannot send dump request");
586 return 1;
587 }
588
589 new_json_obj(json);
590 if (rtnl_dump_filter(&rth, filter_fn, stdout) < 0) {
591 fprintf(stderr, "Dump terminated\n");
592 return 1;
593 }
594 delete_json_obj();
595
596 return 0;
597 }
598
599 static int rule_dump_check_magic(void)
600 {
601 int ret;
602 __u32 magic = 0;
603
604 if (isatty(STDIN_FILENO)) {
605 fprintf(stderr, "Can't restore rule dump from a terminal\n");
606 return -1;
607 }
608
609 ret = fread(&magic, sizeof(magic), 1, stdin);
610 if (magic != rule_dump_magic) {
611 fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n",
612 ret, magic);
613 return -1;
614 }
615
616 return 0;
617 }
618
619 static int restore_handler(const struct sockaddr_nl *nl,
620 struct rtnl_ctrl_data *ctrl,
621 struct nlmsghdr *n, void *arg)
622 {
623 int ret;
624
625 n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK;
626
627 ll_init_map(&rth);
628
629 ret = rtnl_talk(&rth, n, NULL);
630 if ((ret < 0) && (errno == EEXIST))
631 ret = 0;
632
633 return ret;
634 }
635
636
637 static int iprule_restore(void)
638 {
639 if (rule_dump_check_magic())
640 exit(-1);
641
642 exit(rtnl_from_file(stdin, &restore_handler, NULL));
643 }
644
645 static int iprule_modify(int cmd, int argc, char **argv)
646 {
647 int l3mdev_rule = 0;
648 int table_ok = 0;
649 __u32 tid = 0;
650 struct {
651 struct nlmsghdr n;
652 struct fib_rule_hdr frh;
653 char buf[1024];
654 } req = {
655 .n.nlmsg_type = cmd,
656 .n.nlmsg_len = NLMSG_LENGTH(sizeof(struct fib_rule_hdr)),
657 .n.nlmsg_flags = NLM_F_REQUEST,
658 .frh.family = preferred_family,
659 .frh.action = FR_ACT_UNSPEC,
660 };
661
662 if (cmd == RTM_NEWRULE) {
663 req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
664 req.frh.action = FR_ACT_TO_TBL;
665 }
666
667 if (cmd == RTM_DELRULE && argc == 0) {
668 fprintf(stderr, "\"ip rule del\" requires arguments.\n");
669 return -1;
670 }
671
672 while (argc > 0) {
673 if (strcmp(*argv, "not") == 0) {
674 req.frh.flags |= FIB_RULE_INVERT;
675 } else if (strcmp(*argv, "from") == 0) {
676 inet_prefix dst;
677
678 NEXT_ARG();
679 get_prefix(&dst, *argv, req.frh.family);
680 req.frh.src_len = dst.bitlen;
681 addattr_l(&req.n, sizeof(req), FRA_SRC,
682 &dst.data, dst.bytelen);
683 } else if (strcmp(*argv, "to") == 0) {
684 inet_prefix dst;
685
686 NEXT_ARG();
687 get_prefix(&dst, *argv, req.frh.family);
688 req.frh.dst_len = dst.bitlen;
689 addattr_l(&req.n, sizeof(req), FRA_DST,
690 &dst.data, dst.bytelen);
691 } else if (matches(*argv, "preference") == 0 ||
692 matches(*argv, "order") == 0 ||
693 matches(*argv, "priority") == 0) {
694 __u32 pref;
695
696 NEXT_ARG();
697 if (get_u32(&pref, *argv, 0))
698 invarg("preference value is invalid\n", *argv);
699 addattr32(&req.n, sizeof(req), FRA_PRIORITY, pref);
700 } else if (strcmp(*argv, "tos") == 0 ||
701 matches(*argv, "dsfield") == 0) {
702 __u32 tos;
703
704 NEXT_ARG();
705 if (rtnl_dsfield_a2n(&tos, *argv))
706 invarg("TOS value is invalid\n", *argv);
707 req.frh.tos = tos;
708 } else if (strcmp(*argv, "fwmark") == 0) {
709 char *slash;
710 __u32 fwmark, fwmask;
711
712 NEXT_ARG();
713
714 slash = strchr(*argv, '/');
715 if (slash != NULL)
716 *slash = '\0';
717 if (get_u32(&fwmark, *argv, 0))
718 invarg("fwmark value is invalid\n", *argv);
719 addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark);
720 if (slash) {
721 if (get_u32(&fwmask, slash+1, 0))
722 invarg("fwmask value is invalid\n",
723 slash+1);
724 addattr32(&req.n, sizeof(req),
725 FRA_FWMASK, fwmask);
726 }
727 } else if (matches(*argv, "realms") == 0) {
728 __u32 realm;
729
730 NEXT_ARG();
731 if (get_rt_realms_or_raw(&realm, *argv))
732 invarg("invalid realms\n", *argv);
733 addattr32(&req.n, sizeof(req), FRA_FLOW, realm);
734 } else if (matches(*argv, "protocol") == 0) {
735 __u32 proto;
736
737 NEXT_ARG();
738 if (rtnl_rtprot_a2n(&proto, *argv))
739 invarg("\"protocol\" value is invalid\n", *argv);
740 addattr8(&req.n, sizeof(req), FRA_PROTOCOL, proto);
741 } else if (matches(*argv, "table") == 0 ||
742 strcmp(*argv, "lookup") == 0) {
743 NEXT_ARG();
744 if (rtnl_rttable_a2n(&tid, *argv))
745 invarg("invalid table ID\n", *argv);
746 if (tid < 256)
747 req.frh.table = tid;
748 else {
749 req.frh.table = RT_TABLE_UNSPEC;
750 addattr32(&req.n, sizeof(req), FRA_TABLE, tid);
751 }
752 table_ok = 1;
753 } else if (matches(*argv, "suppress_prefixlength") == 0 ||
754 strcmp(*argv, "sup_pl") == 0) {
755 int pl;
756
757 NEXT_ARG();
758 if (get_s32(&pl, *argv, 0) || pl < 0)
759 invarg("suppress_prefixlength value is invalid\n",
760 *argv);
761 addattr32(&req.n, sizeof(req),
762 FRA_SUPPRESS_PREFIXLEN, pl);
763 } else if (matches(*argv, "suppress_ifgroup") == 0 ||
764 strcmp(*argv, "sup_group") == 0) {
765 NEXT_ARG();
766 int group;
767
768 if (rtnl_group_a2n(&group, *argv))
769 invarg("Invalid \"suppress_ifgroup\" value\n",
770 *argv);
771 addattr32(&req.n, sizeof(req),
772 FRA_SUPPRESS_IFGROUP, group);
773 } else if (strcmp(*argv, "dev") == 0 ||
774 strcmp(*argv, "iif") == 0) {
775 NEXT_ARG();
776 if (check_ifname(*argv))
777 invarg("\"iif\"/\"dev\" not a valid ifname", *argv);
778 addattr_l(&req.n, sizeof(req), FRA_IFNAME,
779 *argv, strlen(*argv)+1);
780 } else if (strcmp(*argv, "oif") == 0) {
781 NEXT_ARG();
782 if (check_ifname(*argv))
783 invarg("\"oif\" not a valid ifname", *argv);
784 addattr_l(&req.n, sizeof(req), FRA_OIFNAME,
785 *argv, strlen(*argv)+1);
786 } else if (strcmp(*argv, "l3mdev") == 0) {
787 addattr8(&req.n, sizeof(req), FRA_L3MDEV, 1);
788 table_ok = 1;
789 l3mdev_rule = 1;
790 } else if (strcmp(*argv, "uidrange") == 0) {
791 struct fib_rule_uid_range r;
792
793 NEXT_ARG();
794 if (sscanf(*argv, "%u-%u", &r.start, &r.end) != 2)
795 invarg("invalid UID range\n", *argv);
796 addattr_l(&req.n, sizeof(req), FRA_UID_RANGE, &r,
797 sizeof(r));
798 } else if (strcmp(*argv, "nat") == 0 ||
799 matches(*argv, "map-to") == 0) {
800 NEXT_ARG();
801 fprintf(stderr, "Warning: route NAT is deprecated\n");
802 addattr32(&req.n, sizeof(req), RTA_GATEWAY,
803 get_addr32(*argv));
804 req.frh.action = RTN_NAT;
805 } else {
806 int type;
807
808 if (strcmp(*argv, "type") == 0)
809 NEXT_ARG();
810
811 if (matches(*argv, "help") == 0)
812 usage();
813 else if (matches(*argv, "goto") == 0) {
814 __u32 target;
815
816 type = FR_ACT_GOTO;
817 NEXT_ARG();
818 if (get_u32(&target, *argv, 0))
819 invarg("invalid target\n", *argv);
820 addattr32(&req.n, sizeof(req),
821 FRA_GOTO, target);
822 } else if (matches(*argv, "nop") == 0)
823 type = FR_ACT_NOP;
824 else if (rtnl_rtntype_a2n(&type, *argv))
825 invarg("Failed to parse rule type", *argv);
826 req.frh.action = type;
827 table_ok = 1;
828 }
829 argc--;
830 argv++;
831 }
832
833 if (l3mdev_rule && tid != 0) {
834 fprintf(stderr,
835 "table can not be specified for l3mdev rules\n");
836 return -EINVAL;
837 }
838
839 if (req.frh.family == AF_UNSPEC)
840 req.frh.family = AF_INET;
841
842 if (!table_ok && cmd == RTM_NEWRULE)
843 req.frh.table = RT_TABLE_MAIN;
844
845 if (rtnl_talk(&rth, &req.n, NULL) < 0)
846 return -2;
847
848 return 0;
849 }
850
851 int do_iprule(int argc, char **argv)
852 {
853 if (argc < 1) {
854 return iprule_list_flush_or_save(0, NULL, IPRULE_LIST);
855 } else if (matches(argv[0], "list") == 0 ||
856 matches(argv[0], "lst") == 0 ||
857 matches(argv[0], "show") == 0) {
858 return iprule_list_flush_or_save(argc-1, argv+1, IPRULE_LIST);
859 } else if (matches(argv[0], "save") == 0) {
860 return iprule_list_flush_or_save(argc-1, argv+1, IPRULE_SAVE);
861 } else if (matches(argv[0], "restore") == 0) {
862 return iprule_restore();
863 } else if (matches(argv[0], "add") == 0) {
864 return iprule_modify(RTM_NEWRULE, argc-1, argv+1);
865 } else if (matches(argv[0], "delete") == 0) {
866 return iprule_modify(RTM_DELRULE, argc-1, argv+1);
867 } else if (matches(argv[0], "flush") == 0) {
868 return iprule_list_flush_or_save(argc-1, argv+1, IPRULE_FLUSH);
869 } else if (matches(argv[0], "help") == 0)
870 usage();
871
872 fprintf(stderr,
873 "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv);
874 exit(-1);
875 }
876
877 int do_multirule(int argc, char **argv)
878 {
879 switch (preferred_family) {
880 case AF_UNSPEC:
881 case AF_INET:
882 preferred_family = RTNL_FAMILY_IPMR;
883 break;
884 case AF_INET6:
885 preferred_family = RTNL_FAMILY_IP6MR;
886 break;
887 case RTNL_FAMILY_IPMR:
888 case RTNL_FAMILY_IP6MR:
889 break;
890 default:
891 fprintf(stderr,
892 "Multicast rules are only supported for IPv4/IPv6, was: %i\n",
893 preferred_family);
894 exit(-1);
895 }
896
897 return do_iprule(argc, argv);
898 }