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