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 " [ ipproto PROTOCOL ]\n"
51 " [ sport [ NUMBER | NUMBER-NUMBER ]\n"
52 " [ dport [ NUMBER | NUMBER-NUMBER ] ]\n"
53 "ACTION := [ table TABLE_ID ]\n"
54 " [ protocol PROTO ]\n"
56 " [ realms [SRCREALM/]DSTREALM ]\n"
59 "SUPPRESSOR := [ suppress_prefixlength NUMBER ]\n"
60 " [ suppress_ifgroup DEVGROUP ]\n"
61 "TABLE_ID := [ local | main | default | NUMBER ]\n");
69 int iifmask
, oifmask
, uidrange
;
71 unsigned int tos
, tosmask
;
72 unsigned int pref
, prefmask
;
73 unsigned int fwmark
, fwmask
;
77 struct fib_rule_uid_range range
;
82 struct fib_rule_port_range sport
;
83 struct fib_rule_port_range dport
;
87 static inline int frh_get_table(struct fib_rule_hdr
*frh
, struct rtattr
**tb
)
89 __u32 table
= frh
->table
;
91 table
= rta_getattr_u32(tb
[RTA_TABLE
]);
95 static bool filter_nlmsg(struct nlmsghdr
*n
, struct rtattr
**tb
, int host_len
)
97 struct fib_rule_hdr
*frh
= NLMSG_DATA(n
);
100 if (preferred_family
!= AF_UNSPEC
&& frh
->family
!= preferred_family
)
103 if (filter
.prefmask
&&
104 filter
.pref
^ (tb
[FRA_PRIORITY
] ? rta_getattr_u32(tb
[FRA_PRIORITY
]) : 0))
106 if (filter
.not && !(frh
->flags
& FIB_RULE_INVERT
))
109 if (filter
.src
.family
) {
110 inet_prefix
*f_src
= &filter
.src
;
112 if (f_src
->family
!= frh
->family
||
113 f_src
->bitlen
> frh
->src_len
)
116 if (inet_addr_match_rta(f_src
, tb
[FRA_SRC
]))
120 if (filter
.dst
.family
) {
121 inet_prefix
*f_dst
= &filter
.dst
;
123 if (f_dst
->family
!= frh
->family
||
124 f_dst
->bitlen
> frh
->dst_len
)
127 if (inet_addr_match_rta(f_dst
, tb
[FRA_DST
]))
131 if (filter
.tosmask
&& filter
.tos
^ frh
->tos
)
138 mark
= rta_getattr_u32(tb
[FRA_FWMARK
]);
139 if (filter
.fwmark
^ mark
)
146 mask
= rta_getattr_u32(tb
[FRA_FWMASK
]);
147 if (filter
.fwmask
^ mask
)
151 if (filter
.iifmask
) {
152 if (tb
[FRA_IFNAME
]) {
153 if (strcmp(filter
.iif
, rta_getattr_str(tb
[FRA_IFNAME
])) != 0)
160 if (filter
.oifmask
) {
161 if (tb
[FRA_OIFNAME
]) {
162 if (strcmp(filter
.oif
, rta_getattr_str(tb
[FRA_OIFNAME
])) != 0)
169 if (filter
.l3mdev
&& !(tb
[FRA_L3MDEV
] && rta_getattr_u8(tb
[FRA_L3MDEV
])))
172 if (filter
.uidrange
) {
173 struct fib_rule_uid_range
*r
= RTA_DATA(tb
[FRA_UID_RANGE
]);
175 if (!tb
[FRA_UID_RANGE
] ||
176 r
->start
!= filter
.range
.start
||
177 r
->end
!= filter
.range
.end
)
181 if (filter
.ipproto
) {
184 if (tb
[FRA_IP_PROTO
])
185 ipproto
= rta_getattr_u8(tb
[FRA_IP_PROTO
]);
186 if (filter
.ipproto
!= ipproto
)
190 if (filter
.sport
.start
) {
191 const struct fib_rule_port_range
*r
;
193 if (!tb
[FRA_SPORT_RANGE
])
196 r
= RTA_DATA(tb
[FRA_SPORT_RANGE
]);
197 if (r
->start
!= filter
.sport
.start
||
198 r
->end
!= filter
.sport
.end
)
202 if (filter
.dport
.start
) {
203 const struct fib_rule_port_range
*r
;
205 if (!tb
[FRA_DPORT_RANGE
])
208 r
= RTA_DATA(tb
[FRA_DPORT_RANGE
]);
209 if (r
->start
!= filter
.dport
.start
||
210 r
->end
!= filter
.dport
.end
)
217 if (tb
[FRA_TUN_ID
]) {
218 tun_id
= ntohll(rta_getattr_u64(tb
[FRA_TUN_ID
]));
219 if (filter
.tun_id
!= tun_id
)
226 table
= frh_get_table(frh
, tb
);
227 if (filter
.tb
> 0 && filter
.tb
^ table
)
233 int print_rule(struct nlmsghdr
*n
, void *arg
)
236 struct fib_rule_hdr
*frh
= NLMSG_DATA(n
);
237 int len
= n
->nlmsg_len
;
239 __u32 table
, prio
= 0;
240 struct rtattr
*tb
[FRA_MAX
+1];
243 if (n
->nlmsg_type
!= RTM_NEWRULE
&& n
->nlmsg_type
!= RTM_DELRULE
)
246 len
-= NLMSG_LENGTH(sizeof(*frh
));
250 parse_rtattr(tb
, FRA_MAX
, RTM_RTA(frh
), len
);
252 host_len
= af_bit_len(frh
->family
);
254 if (!filter_nlmsg(n
, tb
, host_len
))
257 open_json_object(NULL
);
258 if (n
->nlmsg_type
== RTM_DELRULE
)
259 print_bool(PRINT_ANY
, "deleted", "Deleted ", true);
261 if (tb
[FRA_PRIORITY
])
262 prio
= rta_getattr_u32(tb
[FRA_PRIORITY
]);
264 print_uint(PRINT_ANY
, "priority", "%u:\t", prio
);
266 if (frh
->flags
& FIB_RULE_INVERT
)
267 print_null(PRINT_ANY
, "not", "not ", NULL
);
270 const char *src
= rt_addr_n2a_rta(frh
->family
, tb
[FRA_SRC
]);
272 print_string(PRINT_FP
, NULL
, "from ", NULL
);
273 print_color_string(PRINT_ANY
, ifa_family_color(frh
->family
),
275 if (frh
->src_len
!= host_len
)
276 print_uint(PRINT_ANY
, "srclen", "/%u", frh
->src_len
);
277 } else if (frh
->src_len
) {
278 print_string(PRINT_ANY
, "src", "from %s", "0");
279 print_uint(PRINT_ANY
, "srclen", "/%u", frh
->src_len
);
281 print_string(PRINT_ANY
, "src", "from %s", "all");
285 const char *dst
= rt_addr_n2a_rta(frh
->family
, tb
[FRA_DST
]);
287 print_string(PRINT_FP
, NULL
, " to ", NULL
);
288 print_color_string(PRINT_ANY
, ifa_family_color(frh
->family
),
290 if (frh
->dst_len
!= host_len
)
291 print_uint(PRINT_ANY
, "dstlen", "/%u", frh
->dst_len
);
292 } else if (frh
->dst_len
) {
293 print_string(PRINT_ANY
, "dst", " to %s", "0");
294 print_uint(PRINT_ANY
, "dstlen", "/%u", frh
->dst_len
);
298 print_string(PRINT_ANY
, "tos",
300 rtnl_dsfield_n2a(frh
->tos
, b1
, sizeof(b1
)));
303 if (tb
[FRA_FWMARK
] || tb
[FRA_FWMASK
]) {
304 __u32 mark
= 0, mask
= 0;
307 mark
= rta_getattr_u32(tb
[FRA_FWMARK
]);
309 if (tb
[FRA_FWMASK
] &&
310 (mask
= rta_getattr_u32(tb
[FRA_FWMASK
])) != 0xFFFFFFFF) {
311 print_0xhex(PRINT_ANY
, "fwmark", " fwmark %#llx", mark
);
312 print_0xhex(PRINT_ANY
, "fwmask", "/%#llx", mask
);
314 print_0xhex(PRINT_ANY
, "fwmark", " fwmark %#llx", mark
);
318 if (tb
[FRA_IFNAME
]) {
319 if (!is_json_context())
320 fprintf(fp
, " iif ");
321 print_color_string(PRINT_ANY
, COLOR_IFNAME
,
323 rta_getattr_str(tb
[FRA_IFNAME
]));
325 if (frh
->flags
& FIB_RULE_IIF_DETACHED
)
326 print_null(PRINT_ANY
, "iif_detached", " [detached]",
330 if (tb
[FRA_OIFNAME
]) {
331 if (!is_json_context())
332 fprintf(fp
, " oif ");
334 print_color_string(PRINT_ANY
, COLOR_IFNAME
, "oif", "%s",
335 rta_getattr_str(tb
[FRA_OIFNAME
]));
337 if (frh
->flags
& FIB_RULE_OIF_DETACHED
)
338 print_null(PRINT_ANY
, "oif_detached", " [detached]",
342 if (tb
[FRA_L3MDEV
]) {
343 __u8 mdev
= rta_getattr_u8(tb
[FRA_L3MDEV
]);
346 print_null(PRINT_ANY
, "l3mdev",
347 " lookup [l3mdev-table]", NULL
);
350 if (tb
[FRA_UID_RANGE
]) {
351 struct fib_rule_uid_range
*r
= RTA_DATA(tb
[FRA_UID_RANGE
]);
353 print_uint(PRINT_ANY
, "uid_start", " uidrange %u", r
->start
);
354 print_uint(PRINT_ANY
, "uid_end", "-%u", r
->end
);
357 if (tb
[FRA_IP_PROTO
]) {
359 print_string(PRINT_ANY
, "ipproto", " ipproto %s",
360 inet_proto_n2a(rta_getattr_u8(tb
[FRA_IP_PROTO
]),
361 pbuf
, sizeof(pbuf
)));
364 if (tb
[FRA_SPORT_RANGE
]) {
365 struct fib_rule_port_range
*r
= RTA_DATA(tb
[FRA_SPORT_RANGE
]);
367 if (r
->start
== r
->end
) {
368 print_uint(PRINT_ANY
, "sport", " sport %u", r
->start
);
370 print_uint(PRINT_ANY
, "sport_start", " sport %u",
372 print_uint(PRINT_ANY
, "sport_end", "-%u", r
->end
);
376 if (tb
[FRA_DPORT_RANGE
]) {
377 struct fib_rule_port_range
*r
= RTA_DATA(tb
[FRA_DPORT_RANGE
]);
379 if (r
->start
== r
->end
) {
380 print_uint(PRINT_ANY
, "dport", " dport %u", r
->start
);
382 print_uint(PRINT_ANY
, "dport_start", " dport %u",
384 print_uint(PRINT_ANY
, "dport_end", "-%u", r
->end
);
388 if (tb
[FRA_TUN_ID
]) {
389 __u64 tun_id
= ntohll(rta_getattr_u64(tb
[FRA_TUN_ID
]));
391 print_u64(PRINT_ANY
, "tun_id", " tun_id %llu", tun_id
);
394 table
= frh_get_table(frh
, tb
);
396 print_string(PRINT_ANY
, "table",
398 rtnl_rttable_n2a(table
, b1
, sizeof(b1
)));
400 if (tb
[FRA_SUPPRESS_PREFIXLEN
]) {
401 int pl
= rta_getattr_u32(tb
[FRA_SUPPRESS_PREFIXLEN
]);
404 print_int(PRINT_ANY
, "suppress_prefixlen",
405 " suppress_prefixlength %d", pl
);
408 if (tb
[FRA_SUPPRESS_IFGROUP
]) {
409 int group
= rta_getattr_u32(tb
[FRA_SUPPRESS_IFGROUP
]);
413 = rtnl_group_n2a(group
, b1
, sizeof(b1
));
415 print_string(PRINT_ANY
, "suppress_ifgroup",
416 " suppress_ifgroup %s", grname
);
422 __u32 to
= rta_getattr_u32(tb
[FRA_FLOW
]);
427 print_string(PRINT_ANY
,
428 "flow_from", " realms %s/",
429 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
431 print_string(PRINT_FP
, NULL
, " realms ", NULL
);
433 print_string(PRINT_ANY
, "flow_to", "%s",
434 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
437 if (frh
->action
== RTN_NAT
) {
438 if (tb
[RTA_GATEWAY
]) {
441 gateway
= format_host_rta(frh
->family
, tb
[RTA_GATEWAY
]);
443 print_string(PRINT_ANY
, "nat_gateway",
444 " map-to %s", gateway
);
446 print_null(PRINT_ANY
, "masquerade", " masquerade", NULL
);
448 } else if (frh
->action
== FR_ACT_GOTO
) {
450 print_uint(PRINT_ANY
, "goto", " goto %u",
451 rta_getattr_u32(tb
[FRA_GOTO
]));
453 print_string(PRINT_ANY
, "goto", " goto %s", "none");
455 if (frh
->flags
& FIB_RULE_UNRESOLVED
)
456 print_null(PRINT_ANY
, "unresolved",
457 " [unresolved]", NULL
);
458 } else if (frh
->action
== FR_ACT_NOP
) {
459 print_null(PRINT_ANY
, "nop", " nop", NULL
);
460 } else if (frh
->action
!= FR_ACT_TO_TBL
) {
461 print_string(PRINT_ANY
, "action", " %s",
462 rtnl_rtntype_n2a(frh
->action
, b1
, sizeof(b1
)));
465 if (tb
[FRA_PROTOCOL
]) {
466 __u8 protocol
= rta_getattr_u8(tb
[FRA_PROTOCOL
]);
468 if ((protocol
&& protocol
!= RTPROT_KERNEL
) || show_details
> 0) {
469 print_string(PRINT_ANY
, "protocol", " proto %s",
470 rtnl_rtprot_n2a(protocol
, b1
, sizeof(b1
)));
473 print_string(PRINT_FP
, NULL
, "\n", "");
479 static __u32 rule_dump_magic
= 0x71706986;
481 static int save_rule_prep(void)
485 if (isatty(STDOUT_FILENO
)) {
486 fprintf(stderr
, "Not sending a binary stream to stdout\n");
490 ret
= write(STDOUT_FILENO
, &rule_dump_magic
, sizeof(rule_dump_magic
));
491 if (ret
!= sizeof(rule_dump_magic
)) {
492 fprintf(stderr
, "Can't write magic to dump file\n");
499 static int save_rule(struct nlmsghdr
*n
, void *arg
)
503 ret
= write(STDOUT_FILENO
, n
, n
->nlmsg_len
);
504 if ((ret
> 0) && (ret
!= n
->nlmsg_len
)) {
505 fprintf(stderr
, "Short write while saving nlmsg\n");
509 return ret
== n
->nlmsg_len
? 0 : ret
;
512 static int flush_rule(struct nlmsghdr
*n
, void *arg
)
514 struct rtnl_handle rth2
;
515 struct fib_rule_hdr
*frh
= NLMSG_DATA(n
);
516 int len
= n
->nlmsg_len
;
517 struct rtattr
*tb
[FRA_MAX
+1];
520 len
-= NLMSG_LENGTH(sizeof(*frh
));
524 parse_rtattr(tb
, FRA_MAX
, RTM_RTA(frh
), len
);
526 host_len
= af_bit_len(frh
->family
);
527 if (!filter_nlmsg(n
, tb
, host_len
))
530 if (tb
[FRA_PROTOCOL
]) {
531 __u8 protocol
= rta_getattr_u8(tb
[FRA_PROTOCOL
]);
533 if ((filter
.protocol
^ protocol
) & filter
.protocolmask
)
537 if (tb
[FRA_PRIORITY
]) {
538 n
->nlmsg_type
= RTM_DELRULE
;
539 n
->nlmsg_flags
= NLM_F_REQUEST
;
541 if (rtnl_open(&rth2
, 0) < 0)
544 if (rtnl_talk(&rth2
, n
, NULL
) < 0)
553 static int iprule_list_flush_or_save(int argc
, char **argv
, int action
)
555 rtnl_filter_t filter_fn
;
556 int af
= preferred_family
;
561 if (action
== IPRULE_SAVE
&& argc
> 0) {
562 fprintf(stderr
, "\"ip rule save\" does not take any arguments.\n");
568 if (save_rule_prep())
570 filter_fn
= save_rule
;
573 filter_fn
= flush_rule
;
576 filter_fn
= print_rule
;
579 memset(&filter
, 0, sizeof(filter
));
582 if (matches(*argv
, "preference") == 0 ||
583 matches(*argv
, "order") == 0 ||
584 matches(*argv
, "priority") == 0) {
588 if (get_u32(&pref
, *argv
, 0))
589 invarg("preference value is invalid\n", *argv
);
592 } else if (strcmp(*argv
, "not") == 0) {
594 } else if (strcmp(*argv
, "tos") == 0) {
598 if (rtnl_dsfield_a2n(&tos
, *argv
))
599 invarg("TOS value is invalid\n", *argv
);
602 } else if (strcmp(*argv
, "fwmark") == 0) {
604 __u32 fwmark
, fwmask
;
607 slash
= strchr(*argv
, '/');
610 if (get_u32(&fwmark
, *argv
, 0))
611 invarg("fwmark value is invalid\n", *argv
);
612 filter
.fwmark
= fwmark
;
614 if (get_u32(&fwmask
, slash
+1, 0))
615 invarg("fwmask value is invalid\n",
617 filter
.fwmask
= fwmask
;
619 } else if (strcmp(*argv
, "dev") == 0 ||
620 strcmp(*argv
, "iif") == 0) {
622 if (get_ifname(filter
.iif
, *argv
))
623 invarg("\"iif\"/\"dev\" not a valid ifname", *argv
);
625 } else if (strcmp(*argv
, "oif") == 0) {
627 if (get_ifname(filter
.oif
, *argv
))
628 invarg("\"oif\" not a valid ifname", *argv
);
630 } else if (strcmp(*argv
, "l3mdev") == 0) {
632 } else if (strcmp(*argv
, "uidrange") == 0) {
635 if (sscanf(*argv
, "%u-%u",
637 &filter
.range
.end
) != 2)
638 invarg("invalid UID range\n", *argv
);
640 } else if (matches(*argv
, "tun_id") == 0) {
644 if (get_u64(&tun_id
, *argv
, 0))
645 invarg("\"tun_id\" value is invalid\n", *argv
);
646 filter
.tun_id
= tun_id
;
647 } else if (matches(*argv
, "lookup") == 0 ||
648 matches(*argv
, "table") == 0) {
652 if (rtnl_rttable_a2n(&tid
, *argv
))
653 invarg("table id value is invalid\n", *argv
);
655 } else if (matches(*argv
, "from") == 0 ||
656 matches(*argv
, "src") == 0) {
658 if (get_prefix(&filter
.src
, *argv
, af
))
659 invarg("from value is invalid\n", *argv
);
660 } else if (matches(*argv
, "protocol") == 0) {
663 filter
.protocolmask
= -1;
664 if (rtnl_rtprot_a2n(&prot
, *argv
)) {
665 if (strcmp(*argv
, "all") != 0)
666 invarg("invalid \"protocol\"\n", *argv
);
668 filter
.protocolmask
= 0;
670 filter
.protocol
= prot
;
671 } else if (strcmp(*argv
, "ipproto") == 0) {
675 ipproto
= inet_proto_a2n(*argv
);
677 invarg("Invalid \"ipproto\" value\n", *argv
);
678 filter
.ipproto
= ipproto
;
679 } else if (strcmp(*argv
, "sport") == 0) {
680 struct fib_rule_port_range r
;
684 ret
= sscanf(*argv
, "%hu-%hu", &r
.start
, &r
.end
);
688 invarg("invalid port range\n", *argv
);
690 } else if (strcmp(*argv
, "dport") == 0) {
691 struct fib_rule_port_range r
;
695 ret
= sscanf(*argv
, "%hu-%hu", &r
.start
, &r
.end
);
699 invarg("invalid dport range\n", *argv
);
702 if (matches(*argv
, "dst") == 0 ||
703 matches(*argv
, "to") == 0) {
706 if (get_prefix(&filter
.dst
, *argv
, af
))
707 invarg("to value is invalid\n", *argv
);
712 if (rtnl_ruledump_req(&rth
, af
) < 0) {
713 perror("Cannot send dump request");
718 if (rtnl_dump_filter(&rth
, filter_fn
, stdout
) < 0) {
719 fprintf(stderr
, "Dump terminated\n");
727 static int rule_dump_check_magic(void)
732 if (isatty(STDIN_FILENO
)) {
733 fprintf(stderr
, "Can't restore rule dump from a terminal\n");
737 ret
= fread(&magic
, sizeof(magic
), 1, stdin
);
738 if (magic
!= rule_dump_magic
) {
739 fprintf(stderr
, "Magic mismatch (%d elems, %x magic)\n",
747 static int restore_handler(struct rtnl_ctrl_data
*ctrl
,
748 struct nlmsghdr
*n
, void *arg
)
752 n
->nlmsg_flags
|= NLM_F_REQUEST
| NLM_F_CREATE
| NLM_F_ACK
;
756 ret
= rtnl_talk(&rth
, n
, NULL
);
757 if ((ret
< 0) && (errno
== EEXIST
))
764 static int iprule_restore(void)
766 if (rule_dump_check_magic())
769 exit(rtnl_from_file(stdin
, &restore_handler
, NULL
));
772 static int iprule_modify(int cmd
, int argc
, char **argv
)
779 struct fib_rule_hdr frh
;
783 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct fib_rule_hdr
)),
784 .n
.nlmsg_flags
= NLM_F_REQUEST
,
785 .frh
.family
= preferred_family
,
786 .frh
.action
= FR_ACT_UNSPEC
,
789 if (cmd
== RTM_NEWRULE
) {
792 "\"ip rule add\" requires arguments.\n");
795 req
.n
.nlmsg_flags
|= NLM_F_CREATE
|NLM_F_EXCL
;
796 req
.frh
.action
= FR_ACT_TO_TBL
;
799 if (cmd
== RTM_DELRULE
&& argc
== 0) {
800 fprintf(stderr
, "\"ip rule del\" requires arguments.\n");
805 if (strcmp(*argv
, "not") == 0) {
806 req
.frh
.flags
|= FIB_RULE_INVERT
;
807 } else if (strcmp(*argv
, "from") == 0) {
811 get_prefix(&dst
, *argv
, req
.frh
.family
);
812 req
.frh
.src_len
= dst
.bitlen
;
813 addattr_l(&req
.n
, sizeof(req
), FRA_SRC
,
814 &dst
.data
, dst
.bytelen
);
815 } else if (strcmp(*argv
, "to") == 0) {
819 get_prefix(&dst
, *argv
, req
.frh
.family
);
820 req
.frh
.dst_len
= dst
.bitlen
;
821 addattr_l(&req
.n
, sizeof(req
), FRA_DST
,
822 &dst
.data
, dst
.bytelen
);
823 } else if (matches(*argv
, "preference") == 0 ||
824 matches(*argv
, "order") == 0 ||
825 matches(*argv
, "priority") == 0) {
829 if (get_u32(&pref
, *argv
, 0))
830 invarg("preference value is invalid\n", *argv
);
831 addattr32(&req
.n
, sizeof(req
), FRA_PRIORITY
, pref
);
832 } else if (strcmp(*argv
, "tos") == 0 ||
833 matches(*argv
, "dsfield") == 0) {
837 if (rtnl_dsfield_a2n(&tos
, *argv
))
838 invarg("TOS value is invalid\n", *argv
);
840 } else if (strcmp(*argv
, "fwmark") == 0) {
842 __u32 fwmark
, fwmask
;
846 slash
= strchr(*argv
, '/');
849 if (get_u32(&fwmark
, *argv
, 0))
850 invarg("fwmark value is invalid\n", *argv
);
851 addattr32(&req
.n
, sizeof(req
), FRA_FWMARK
, fwmark
);
853 if (get_u32(&fwmask
, slash
+1, 0))
854 invarg("fwmask value is invalid\n",
856 addattr32(&req
.n
, sizeof(req
),
859 } else if (matches(*argv
, "realms") == 0) {
863 if (get_rt_realms_or_raw(&realm
, *argv
))
864 invarg("invalid realms\n", *argv
);
865 addattr32(&req
.n
, sizeof(req
), FRA_FLOW
, realm
);
866 } else if (matches(*argv
, "protocol") == 0) {
870 if (rtnl_rtprot_a2n(&proto
, *argv
))
871 invarg("\"protocol\" value is invalid\n", *argv
);
872 addattr8(&req
.n
, sizeof(req
), FRA_PROTOCOL
, proto
);
873 } else if (matches(*argv
, "tun_id") == 0) {
877 if (get_be64(&tun_id
, *argv
, 0))
878 invarg("\"tun_id\" value is invalid\n", *argv
);
879 addattr64(&req
.n
, sizeof(req
), FRA_TUN_ID
, tun_id
);
880 } else if (matches(*argv
, "table") == 0 ||
881 strcmp(*argv
, "lookup") == 0) {
883 if (rtnl_rttable_a2n(&tid
, *argv
))
884 invarg("invalid table ID\n", *argv
);
888 req
.frh
.table
= RT_TABLE_UNSPEC
;
889 addattr32(&req
.n
, sizeof(req
), FRA_TABLE
, tid
);
892 } else if (matches(*argv
, "suppress_prefixlength") == 0 ||
893 strcmp(*argv
, "sup_pl") == 0) {
897 if (get_s32(&pl
, *argv
, 0) || pl
< 0)
898 invarg("suppress_prefixlength value is invalid\n",
900 addattr32(&req
.n
, sizeof(req
),
901 FRA_SUPPRESS_PREFIXLEN
, pl
);
902 } else if (matches(*argv
, "suppress_ifgroup") == 0 ||
903 strcmp(*argv
, "sup_group") == 0) {
907 if (rtnl_group_a2n(&group
, *argv
))
908 invarg("Invalid \"suppress_ifgroup\" value\n",
910 addattr32(&req
.n
, sizeof(req
),
911 FRA_SUPPRESS_IFGROUP
, group
);
912 } else if (strcmp(*argv
, "dev") == 0 ||
913 strcmp(*argv
, "iif") == 0) {
915 if (check_ifname(*argv
))
916 invarg("\"iif\"/\"dev\" not a valid ifname", *argv
);
917 addattr_l(&req
.n
, sizeof(req
), FRA_IFNAME
,
918 *argv
, strlen(*argv
)+1);
919 } else if (strcmp(*argv
, "oif") == 0) {
921 if (check_ifname(*argv
))
922 invarg("\"oif\" not a valid ifname", *argv
);
923 addattr_l(&req
.n
, sizeof(req
), FRA_OIFNAME
,
924 *argv
, strlen(*argv
)+1);
925 } else if (strcmp(*argv
, "l3mdev") == 0) {
926 addattr8(&req
.n
, sizeof(req
), FRA_L3MDEV
, 1);
929 } else if (strcmp(*argv
, "uidrange") == 0) {
930 struct fib_rule_uid_range r
;
933 if (sscanf(*argv
, "%u-%u", &r
.start
, &r
.end
) != 2)
934 invarg("invalid UID range\n", *argv
);
935 addattr_l(&req
.n
, sizeof(req
), FRA_UID_RANGE
, &r
,
937 } else if (strcmp(*argv
, "nat") == 0 ||
938 matches(*argv
, "map-to") == 0) {
940 fprintf(stderr
, "Warning: route NAT is deprecated\n");
941 addattr32(&req
.n
, sizeof(req
), RTA_GATEWAY
,
943 req
.frh
.action
= RTN_NAT
;
944 } else if (strcmp(*argv
, "ipproto") == 0) {
948 ipproto
= inet_proto_a2n(*argv
);
950 invarg("Invalid \"ipproto\" value\n",
952 addattr8(&req
.n
, sizeof(req
), FRA_IP_PROTO
, ipproto
);
953 } else if (strcmp(*argv
, "sport") == 0) {
954 struct fib_rule_port_range r
;
958 ret
= sscanf(*argv
, "%hu-%hu", &r
.start
, &r
.end
);
962 invarg("invalid port range\n", *argv
);
963 addattr_l(&req
.n
, sizeof(req
), FRA_SPORT_RANGE
, &r
,
965 } else if (strcmp(*argv
, "dport") == 0) {
966 struct fib_rule_port_range r
;
970 ret
= sscanf(*argv
, "%hu-%hu", &r
.start
, &r
.end
);
974 invarg("invalid dport range\n", *argv
);
975 addattr_l(&req
.n
, sizeof(req
), FRA_DPORT_RANGE
, &r
,
980 if (strcmp(*argv
, "type") == 0)
983 if (matches(*argv
, "help") == 0)
985 else if (matches(*argv
, "goto") == 0) {
990 if (get_u32(&target
, *argv
, 0))
991 invarg("invalid target\n", *argv
);
992 addattr32(&req
.n
, sizeof(req
),
994 } else if (matches(*argv
, "nop") == 0)
996 else if (rtnl_rtntype_a2n(&type
, *argv
))
997 invarg("Failed to parse rule type", *argv
);
998 req
.frh
.action
= type
;
1005 if (l3mdev_rule
&& tid
!= 0) {
1007 "table can not be specified for l3mdev rules\n");
1011 if (req
.frh
.family
== AF_UNSPEC
)
1012 req
.frh
.family
= AF_INET
;
1014 if (!table_ok
&& cmd
== RTM_NEWRULE
)
1015 req
.frh
.table
= RT_TABLE_MAIN
;
1017 if (rtnl_talk(&rth
, &req
.n
, NULL
) < 0)
1023 int do_iprule(int argc
, char **argv
)
1026 return iprule_list_flush_or_save(0, NULL
, IPRULE_LIST
);
1027 } else if (matches(argv
[0], "list") == 0 ||
1028 matches(argv
[0], "lst") == 0 ||
1029 matches(argv
[0], "show") == 0) {
1030 return iprule_list_flush_or_save(argc
-1, argv
+1, IPRULE_LIST
);
1031 } else if (matches(argv
[0], "save") == 0) {
1032 return iprule_list_flush_or_save(argc
-1, argv
+1, IPRULE_SAVE
);
1033 } else if (matches(argv
[0], "restore") == 0) {
1034 return iprule_restore();
1035 } else if (matches(argv
[0], "add") == 0) {
1036 return iprule_modify(RTM_NEWRULE
, argc
-1, argv
+1);
1037 } else if (matches(argv
[0], "delete") == 0) {
1038 return iprule_modify(RTM_DELRULE
, argc
-1, argv
+1);
1039 } else if (matches(argv
[0], "flush") == 0) {
1040 return iprule_list_flush_or_save(argc
-1, argv
+1, IPRULE_FLUSH
);
1041 } else if (matches(argv
[0], "help") == 0)
1045 "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv
);
1049 int do_multirule(int argc
, char **argv
)
1051 switch (preferred_family
) {
1054 preferred_family
= RTNL_FAMILY_IPMR
;
1057 preferred_family
= RTNL_FAMILY_IP6MR
;
1059 case RTNL_FAMILY_IPMR
:
1060 case RTNL_FAMILY_IP6MR
:
1064 "Multicast rules are only supported for IPv4/IPv6, was: %i\n",
1069 return do_iprule(argc
, argv
);