]>
git.proxmox.com Git - mirror_iproute2.git/blob - ip/iprule.c
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.
9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
17 #include <sys/socket.h>
18 #include <netinet/in.h>
19 #include <netinet/ip.h>
20 #include <arpa/inet.h>
23 #include <linux/fib_rules.h>
28 #include "ip_common.h"
29 #include "json_print.h"
37 extern struct rtnl_handle rth
;
39 static void usage(void) __attribute__((noreturn
));
41 static void usage(void)
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"
53 " [ realms [SRCREALM/]DSTREALM ]\n"
56 "SUPPRESSOR := [ suppress_prefixlength NUMBER ]\n"
57 " [ suppress_ifgroup DEVGROUP ]\n"
58 "TABLE_ID := [ local | main | default | NUMBER ]\n");
66 int iifmask
, oifmask
, uidrange
;
68 unsigned int tos
, tosmask
;
69 unsigned int pref
, prefmask
;
70 unsigned int fwmark
, fwmask
;
73 struct fib_rule_uid_range range
;
80 static inline int frh_get_table(struct fib_rule_hdr
*frh
, struct rtattr
**tb
)
82 __u32 table
= frh
->table
;
84 table
= rta_getattr_u32(tb
[RTA_TABLE
]);
88 static bool filter_nlmsg(struct nlmsghdr
*n
, struct rtattr
**tb
, int host_len
)
90 struct fib_rule_hdr
*frh
= NLMSG_DATA(n
);
93 if (preferred_family
!= AF_UNSPEC
&& frh
->family
!= preferred_family
)
96 if (filter
.prefmask
&&
97 filter
.pref
^ (tb
[FRA_PRIORITY
] ? rta_getattr_u32(tb
[FRA_PRIORITY
]) : 0))
99 if (filter
.not && !(frh
->flags
& FIB_RULE_INVERT
))
102 if (filter
.src
.family
) {
103 inet_prefix
*f_src
= &filter
.src
;
105 if (f_src
->family
!= frh
->family
||
106 f_src
->bitlen
> frh
->src_len
)
109 if (inet_addr_match_rta(f_src
, tb
[FRA_SRC
]))
113 if (filter
.dst
.family
) {
114 inet_prefix
*f_dst
= &filter
.dst
;
116 if (f_dst
->family
!= frh
->family
||
117 f_dst
->bitlen
> frh
->dst_len
)
120 if (inet_addr_match_rta(f_dst
, tb
[FRA_DST
]))
124 if (filter
.tosmask
&& filter
.tos
^ frh
->tos
)
131 mark
= rta_getattr_u32(tb
[FRA_FWMARK
]);
132 if (filter
.fwmark
^ mark
)
139 mask
= rta_getattr_u32(tb
[FRA_FWMASK
]);
140 if (filter
.fwmask
^ mask
)
144 if (filter
.iifmask
) {
145 if (tb
[FRA_IFNAME
]) {
146 if (strcmp(filter
.iif
, rta_getattr_str(tb
[FRA_IFNAME
])) != 0)
153 if (filter
.oifmask
) {
154 if (tb
[FRA_OIFNAME
]) {
155 if (strcmp(filter
.oif
, rta_getattr_str(tb
[FRA_OIFNAME
])) != 0)
162 if (filter
.l3mdev
&& !(tb
[FRA_L3MDEV
] && rta_getattr_u8(tb
[FRA_L3MDEV
])))
165 if (filter
.uidrange
) {
166 struct fib_rule_uid_range
*r
= RTA_DATA(tb
[FRA_UID_RANGE
]);
168 if (!tb
[FRA_UID_RANGE
] ||
169 r
->start
!= filter
.range
.start
||
170 r
->end
!= filter
.range
.end
)
174 table
= frh_get_table(frh
, tb
);
175 if (filter
.tb
> 0 && filter
.tb
^ table
)
181 int print_rule(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
, void *arg
)
184 struct fib_rule_hdr
*frh
= NLMSG_DATA(n
);
185 int len
= n
->nlmsg_len
;
187 __u32 table
, prio
= 0;
188 struct rtattr
*tb
[FRA_MAX
+1];
191 if (n
->nlmsg_type
!= RTM_NEWRULE
&& n
->nlmsg_type
!= RTM_DELRULE
)
194 len
-= NLMSG_LENGTH(sizeof(*frh
));
198 parse_rtattr(tb
, FRA_MAX
, RTM_RTA(frh
), len
);
200 host_len
= af_bit_len(frh
->family
);
202 if (!filter_nlmsg(n
, tb
, host_len
))
205 open_json_object(NULL
);
206 if (n
->nlmsg_type
== RTM_DELRULE
)
207 print_bool(PRINT_ANY
, "deleted", "Deleted ", true);
209 if (tb
[FRA_PRIORITY
])
210 prio
= rta_getattr_u32(tb
[FRA_PRIORITY
]);
212 print_uint(PRINT_ANY
, "priority", "%u:\t", prio
);
214 if (frh
->flags
& FIB_RULE_INVERT
)
215 print_null(PRINT_ANY
, "not", "not ", NULL
);
218 const char *src
= rt_addr_n2a_rta(frh
->family
, tb
[FRA_SRC
]);
220 print_string(PRINT_FP
, NULL
, "from ", NULL
);
221 print_color_string(PRINT_ANY
, ifa_family_color(frh
->family
),
223 if (frh
->src_len
!= host_len
)
224 print_uint(PRINT_ANY
, "srclen", "/%u ", frh
->src_len
);
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
);
231 print_string(PRINT_ANY
, "src", "from %s ", "all");
235 const char *dst
= rt_addr_n2a_rta(frh
->family
, tb
[FRA_DST
]);
237 print_string(PRINT_FP
, NULL
, "to ", NULL
);
238 print_color_string(PRINT_ANY
, ifa_family_color(frh
->family
),
240 if (frh
->dst_len
!= host_len
)
241 print_uint(PRINT_ANY
, "dstlen", "/%u ", frh
->dst_len
);
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
);
250 print_string(PRINT_ANY
, "tos",
252 rtnl_dsfield_n2a(frh
->tos
, b1
, sizeof(b1
)));
255 if (tb
[FRA_FWMARK
] || tb
[FRA_FWMASK
]) {
256 __u32 mark
= 0, mask
= 0;
259 mark
= rta_getattr_u32(tb
[FRA_FWMARK
]);
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
);
266 print_0xhex(PRINT_ANY
, "fwmark", "fwmark 0x%x ", mark
);
270 if (tb
[FRA_IFNAME
]) {
271 if (!is_json_context())
273 print_color_string(PRINT_ANY
, COLOR_IFNAME
,
275 rta_getattr_str(tb
[FRA_IFNAME
]));
277 if (frh
->flags
& FIB_RULE_IIF_DETACHED
)
278 print_null(PRINT_ANY
, "iif_detached", "[detached] ",
282 if (tb
[FRA_OIFNAME
]) {
283 if (!is_json_context())
286 print_color_string(PRINT_ANY
, COLOR_IFNAME
, "oif", "%s ",
287 rta_getattr_str(tb
[FRA_OIFNAME
]));
289 if (frh
->flags
& FIB_RULE_OIF_DETACHED
)
290 print_null(PRINT_ANY
, "oif_detached", "[detached] ",
294 if (tb
[FRA_L3MDEV
]) {
295 __u8 mdev
= rta_getattr_u8(tb
[FRA_L3MDEV
]);
298 print_null(PRINT_ANY
, "l3mdev",
299 "lookup [l3mdev-table] ", NULL
);
302 if (tb
[FRA_UID_RANGE
]) {
303 struct fib_rule_uid_range
*r
= RTA_DATA(tb
[FRA_UID_RANGE
]);
305 print_uint(PRINT_ANY
, "uid_start", "uidrange %u", r
->start
);
306 print_uint(PRINT_ANY
, "uid_end", "-%u ", r
->end
);
309 table
= frh_get_table(frh
, tb
);
311 print_string(PRINT_ANY
, "table",
313 rtnl_rttable_n2a(table
, b1
, sizeof(b1
)));
315 if (tb
[FRA_SUPPRESS_PREFIXLEN
]) {
316 int pl
= rta_getattr_u32(tb
[FRA_SUPPRESS_PREFIXLEN
]);
319 print_int(PRINT_ANY
, "suppress_prefixlen",
320 "suppress_prefixlength %d ", pl
);
323 if (tb
[FRA_SUPPRESS_IFGROUP
]) {
324 int group
= rta_getattr_u32(tb
[FRA_SUPPRESS_IFGROUP
]);
328 = rtnl_group_n2a(group
, b1
, sizeof(b1
));
330 print_string(PRINT_ANY
, "suppress_ifgroup",
331 "suppress_ifgroup %s ", grname
);
337 __u32 to
= rta_getattr_u32(tb
[FRA_FLOW
]);
342 print_string(PRINT_ANY
,
343 "flow_from", "realms %s/",
344 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
346 print_string(PRINT_ANY
, "flow_to", "%s ",
347 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
350 if (frh
->action
== RTN_NAT
) {
351 if (tb
[RTA_GATEWAY
]) {
354 gateway
= format_host_rta(frh
->family
, tb
[RTA_GATEWAY
]);
356 print_string(PRINT_ANY
, "nat_gateway",
357 "map-to %s ", gateway
);
359 print_null(PRINT_ANY
, "masquerade", "masquerade", NULL
);
361 } else if (frh
->action
== FR_ACT_GOTO
) {
363 print_uint(PRINT_ANY
, "goto", "goto %u",
364 rta_getattr_u32(tb
[FRA_GOTO
]));
366 print_string(PRINT_ANY
, "goto", "goto %s", "none");
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
)));
377 if (tb
[FRA_PROTOCOL
]) {
378 __u8 protocol
= rta_getattr_u8(tb
[FRA_PROTOCOL
]);
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
)));
385 print_string(PRINT_FP
, NULL
, "\n", "");
391 static __u32 rule_dump_magic
= 0x71706986;
393 static int save_rule_prep(void)
397 if (isatty(STDOUT_FILENO
)) {
398 fprintf(stderr
, "Not sending a binary stream to stdout\n");
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");
411 static int save_rule(const struct sockaddr_nl
*who
,
412 struct nlmsghdr
*n
, void *arg
)
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");
422 return ret
== n
->nlmsg_len
? 0 : ret
;
425 static int flush_rule(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
,
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];
433 len
-= NLMSG_LENGTH(sizeof(*frh
));
437 parse_rtattr(tb
, FRA_MAX
, RTM_RTA(frh
), len
);
439 if (tb
[FRA_PROTOCOL
]) {
440 __u8 protocol
= rta_getattr_u8(tb
[FRA_PROTOCOL
]);
442 if ((filter
.protocol
^ protocol
) & filter
.protocolmask
)
446 if (tb
[FRA_PRIORITY
]) {
447 n
->nlmsg_type
= RTM_DELRULE
;
448 n
->nlmsg_flags
= NLM_F_REQUEST
;
450 if (rtnl_open(&rth2
, 0) < 0)
453 if (rtnl_talk(&rth2
, n
, NULL
) < 0)
462 static int iprule_list_flush_or_save(int argc
, char **argv
, int action
)
464 rtnl_filter_t filter_fn
;
465 int af
= preferred_family
;
470 if (action
== IPRULE_SAVE
&& argc
> 0) {
471 fprintf(stderr
, "\"ip rule save\" does not take any arguments.\n");
477 if (save_rule_prep())
479 filter_fn
= save_rule
;
482 filter_fn
= flush_rule
;
485 filter_fn
= print_rule
;
488 memset(&filter
, 0, sizeof(filter
));
491 if (matches(*argv
, "preference") == 0 ||
492 matches(*argv
, "order") == 0 ||
493 matches(*argv
, "priority") == 0) {
497 if (get_u32(&pref
, *argv
, 0))
498 invarg("preference value is invalid\n", *argv
);
501 } else if (strcmp(*argv
, "not") == 0) {
503 } else if (strcmp(*argv
, "tos") == 0) {
507 if (rtnl_dsfield_a2n(&tos
, *argv
))
508 invarg("TOS value is invalid\n", *argv
);
511 } else if (strcmp(*argv
, "fwmark") == 0) {
513 __u32 fwmark
, fwmask
;
516 slash
= strchr(*argv
, '/');
519 if (get_u32(&fwmark
, *argv
, 0))
520 invarg("fwmark value is invalid\n", *argv
);
521 filter
.fwmark
= fwmark
;
523 if (get_u32(&fwmask
, slash
+1, 0))
524 invarg("fwmask value is invalid\n",
526 filter
.fwmask
= fwmask
;
528 } else if (strcmp(*argv
, "dev") == 0 ||
529 strcmp(*argv
, "iif") == 0) {
531 if (get_ifname(filter
.iif
, *argv
))
532 invarg("\"iif\"/\"dev\" not a valid ifname", *argv
);
534 } else if (strcmp(*argv
, "oif") == 0) {
536 if (get_ifname(filter
.oif
, *argv
))
537 invarg("\"oif\" not a valid ifname", *argv
);
539 } else if (strcmp(*argv
, "l3mdev") == 0) {
541 } else if (strcmp(*argv
, "uidrange") == 0) {
544 if (sscanf(*argv
, "%u-%u",
546 &filter
.range
.end
) != 2)
547 invarg("invalid UID range\n", *argv
);
549 } else if (matches(*argv
, "lookup") == 0 ||
550 matches(*argv
, "table") == 0) {
554 if (rtnl_rttable_a2n(&tid
, *argv
))
555 invarg("table id value is invalid\n", *argv
);
557 } else if (matches(*argv
, "from") == 0 ||
558 matches(*argv
, "src") == 0) {
560 if (get_prefix(&filter
.src
, *argv
, af
))
561 invarg("from value is invalid\n", *argv
);
562 } else if (matches(*argv
, "protocol") == 0) {
565 filter
.protocolmask
= -1;
566 if (rtnl_rtprot_a2n(&prot
, *argv
)) {
567 if (strcmp(*argv
, "all") != 0)
568 invarg("invalid \"protocol\"\n", *argv
);
570 filter
.protocolmask
= 0;
572 filter
.protocol
= prot
;
574 if (matches(*argv
, "dst") == 0 ||
575 matches(*argv
, "to") == 0) {
578 if (get_prefix(&filter
.dst
, *argv
, af
))
579 invarg("to value is invalid\n", *argv
);
584 if (rtnl_wilddump_request(&rth
, af
, RTM_GETRULE
) < 0) {
585 perror("Cannot send dump request");
590 if (rtnl_dump_filter(&rth
, filter_fn
, stdout
) < 0) {
591 fprintf(stderr
, "Dump terminated\n");
599 static int rule_dump_check_magic(void)
604 if (isatty(STDIN_FILENO
)) {
605 fprintf(stderr
, "Can't restore rule dump from a terminal\n");
609 ret
= fread(&magic
, sizeof(magic
), 1, stdin
);
610 if (magic
!= rule_dump_magic
) {
611 fprintf(stderr
, "Magic mismatch (%d elems, %x magic)\n",
619 static int restore_handler(const struct sockaddr_nl
*nl
,
620 struct rtnl_ctrl_data
*ctrl
,
621 struct nlmsghdr
*n
, void *arg
)
625 n
->nlmsg_flags
|= NLM_F_REQUEST
| NLM_F_CREATE
| NLM_F_ACK
;
629 ret
= rtnl_talk(&rth
, n
, NULL
);
630 if ((ret
< 0) && (errno
== EEXIST
))
637 static int iprule_restore(void)
639 if (rule_dump_check_magic())
642 exit(rtnl_from_file(stdin
, &restore_handler
, NULL
));
645 static int iprule_modify(int cmd
, int argc
, char **argv
)
652 struct fib_rule_hdr frh
;
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
,
662 if (cmd
== RTM_NEWRULE
) {
663 req
.n
.nlmsg_flags
|= NLM_F_CREATE
|NLM_F_EXCL
;
664 req
.frh
.action
= FR_ACT_TO_TBL
;
667 if (cmd
== RTM_DELRULE
&& argc
== 0) {
668 fprintf(stderr
, "\"ip rule del\" requires arguments.\n");
673 if (strcmp(*argv
, "not") == 0) {
674 req
.frh
.flags
|= FIB_RULE_INVERT
;
675 } else if (strcmp(*argv
, "from") == 0) {
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) {
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) {
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) {
705 if (rtnl_dsfield_a2n(&tos
, *argv
))
706 invarg("TOS value is invalid\n", *argv
);
708 } else if (strcmp(*argv
, "fwmark") == 0) {
710 __u32 fwmark
, fwmask
;
714 slash
= strchr(*argv
, '/');
717 if (get_u32(&fwmark
, *argv
, 0))
718 invarg("fwmark value is invalid\n", *argv
);
719 addattr32(&req
.n
, sizeof(req
), FRA_FWMARK
, fwmark
);
721 if (get_u32(&fwmask
, slash
+1, 0))
722 invarg("fwmask value is invalid\n",
724 addattr32(&req
.n
, sizeof(req
),
727 } else if (matches(*argv
, "realms") == 0) {
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) {
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) {
744 if (rtnl_rttable_a2n(&tid
, *argv
))
745 invarg("invalid table ID\n", *argv
);
749 req
.frh
.table
= RT_TABLE_UNSPEC
;
750 addattr32(&req
.n
, sizeof(req
), FRA_TABLE
, tid
);
753 } else if (matches(*argv
, "suppress_prefixlength") == 0 ||
754 strcmp(*argv
, "sup_pl") == 0) {
758 if (get_s32(&pl
, *argv
, 0) || pl
< 0)
759 invarg("suppress_prefixlength value is invalid\n",
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) {
768 if (rtnl_group_a2n(&group
, *argv
))
769 invarg("Invalid \"suppress_ifgroup\" value\n",
771 addattr32(&req
.n
, sizeof(req
),
772 FRA_SUPPRESS_IFGROUP
, group
);
773 } else if (strcmp(*argv
, "dev") == 0 ||
774 strcmp(*argv
, "iif") == 0) {
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) {
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);
790 } else if (strcmp(*argv
, "uidrange") == 0) {
791 struct fib_rule_uid_range r
;
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
,
798 } else if (strcmp(*argv
, "nat") == 0 ||
799 matches(*argv
, "map-to") == 0) {
801 fprintf(stderr
, "Warning: route NAT is deprecated\n");
802 addattr32(&req
.n
, sizeof(req
), RTA_GATEWAY
,
804 req
.frh
.action
= RTN_NAT
;
808 if (strcmp(*argv
, "type") == 0)
811 if (matches(*argv
, "help") == 0)
813 else if (matches(*argv
, "goto") == 0) {
818 if (get_u32(&target
, *argv
, 0))
819 invarg("invalid target\n", *argv
);
820 addattr32(&req
.n
, sizeof(req
),
822 } else if (matches(*argv
, "nop") == 0)
824 else if (rtnl_rtntype_a2n(&type
, *argv
))
825 invarg("Failed to parse rule type", *argv
);
826 req
.frh
.action
= type
;
833 if (l3mdev_rule
&& tid
!= 0) {
835 "table can not be specified for l3mdev rules\n");
839 if (req
.frh
.family
== AF_UNSPEC
)
840 req
.frh
.family
= AF_INET
;
842 if (!table_ok
&& cmd
== RTM_NEWRULE
)
843 req
.frh
.table
= RT_TABLE_MAIN
;
845 if (rtnl_talk(&rth
, &req
.n
, NULL
) < 0)
851 int do_iprule(int argc
, char **argv
)
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)
873 "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv
);
877 int do_multirule(int argc
, char **argv
)
879 switch (preferred_family
) {
882 preferred_family
= RTNL_FAMILY_IPMR
;
885 preferred_family
= RTNL_FAMILY_IP6MR
;
887 case RTNL_FAMILY_IPMR
:
888 case RTNL_FAMILY_IP6MR
:
892 "Multicast rules are only supported for IPv4/IPv6, was: %i\n",
897 return do_iprule(argc
, argv
);