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