]>
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"
36 extern struct rtnl_handle rth
;
38 static void usage(void) __attribute__((noreturn
));
40 static void usage(void)
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"
51 " [ realms [SRCREALM/]DSTREALM ]\n"
54 "SUPPRESSOR := [ suppress_prefixlength NUMBER ]\n"
55 " [ suppress_ifgroup DEVGROUP ]\n"
56 "TABLE_ID := [ local | main | default | NUMBER ]\n");
64 int iifmask
, oifmask
, uidrange
;
66 unsigned int tos
, tosmask
;
67 unsigned int pref
, prefmask
;
68 unsigned int fwmark
, fwmask
;
71 struct fib_rule_uid_range range
;
76 static bool filter_nlmsg(struct nlmsghdr
*n
, struct rtattr
**tb
, int host_len
)
78 struct rtmsg
*r
= NLMSG_DATA(n
);
79 inet_prefix src
= { .family
= r
->rtm_family
};
80 inet_prefix dst
= { .family
= r
->rtm_family
};
83 if (preferred_family
!= AF_UNSPEC
&& r
->rtm_family
!= preferred_family
)
86 if (filter
.prefmask
&&
87 filter
.pref
^ (tb
[FRA_PRIORITY
] ? rta_getattr_u32(tb
[FRA_PRIORITY
]) : 0))
89 if (filter
.not && !(r
->rtm_flags
& FIB_RULE_INVERT
))
92 if (filter
.src
.family
) {
94 memcpy(&src
.data
, RTA_DATA(tb
[FRA_SRC
]),
95 (r
->rtm_src_len
+ 7) / 8);
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
))
103 if (filter
.dst
.family
) {
105 memcpy(&dst
.data
, RTA_DATA(tb
[FRA_DST
]),
106 (r
->rtm_dst_len
+ 7) / 8);
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
))
114 if (filter
.tosmask
&& filter
.tos
^ r
->rtm_tos
)
121 mark
= rta_getattr_u32(tb
[FRA_FWMARK
]);
122 if (filter
.fwmark
^ mark
)
129 mask
= rta_getattr_u32(tb
[FRA_FWMASK
]);
130 if (filter
.fwmask
^ mask
)
134 if (filter
.iifmask
) {
135 if (tb
[FRA_IFNAME
]) {
136 if (strcmp(filter
.iif
, rta_getattr_str(tb
[FRA_IFNAME
])) != 0)
143 if (filter
.oifmask
) {
144 if (tb
[FRA_OIFNAME
]) {
145 if (strcmp(filter
.oif
, rta_getattr_str(tb
[FRA_OIFNAME
])) != 0)
152 if (filter
.l3mdev
&& !(tb
[FRA_L3MDEV
] && rta_getattr_u8(tb
[FRA_L3MDEV
])))
155 if (filter
.uidrange
) {
156 struct fib_rule_uid_range
*r
= RTA_DATA(tb
[FRA_UID_RANGE
]);
158 if (!tb
[FRA_UID_RANGE
] ||
159 r
->start
!= filter
.range
.start
||
160 r
->end
!= filter
.range
.end
)
164 table
= rtm_get_table(r
, tb
);
165 if (filter
.tb
> 0 && filter
.tb
^ table
)
171 int print_rule(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
, void *arg
)
173 FILE *fp
= (FILE *)arg
;
174 struct rtmsg
*r
= NLMSG_DATA(n
);
175 int len
= n
->nlmsg_len
;
178 struct rtattr
*tb
[FRA_MAX
+1];
182 if (n
->nlmsg_type
!= RTM_NEWRULE
&& n
->nlmsg_type
!= RTM_DELRULE
)
185 len
-= NLMSG_LENGTH(sizeof(*r
));
189 parse_rtattr(tb
, FRA_MAX
, RTM_RTA(r
), len
);
191 host_len
= af_bit_len(r
->rtm_family
);
193 if (!filter_nlmsg(n
, tb
, host_len
))
196 if (n
->nlmsg_type
== RTM_DELRULE
)
197 fprintf(fp
, "Deleted ");
199 if (tb
[FRA_PRIORITY
])
201 rta_getattr_u32(tb
[FRA_PRIORITY
]));
205 if (r
->rtm_flags
& FIB_RULE_INVERT
)
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
]),
214 fprintf(fp
, "from %s ",
215 format_host_rta(r
->rtm_family
, tb
[FRA_SRC
]));
217 } else if (r
->rtm_src_len
) {
218 fprintf(fp
, "from 0/%d ", r
->rtm_src_len
);
220 fprintf(fp
, "from all ");
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
]),
229 fprintf(fp
, "to %s ",
230 format_host_rta(r
->rtm_family
, tb
[FRA_DST
]));
232 } else if (r
->rtm_dst_len
) {
233 fprintf(fp
, "to 0/%d ", r
->rtm_dst_len
);
238 fprintf(fp
, "tos %s ",
239 rtnl_dsfield_n2a(r
->rtm_tos
, b1
, sizeof(b1
)));
242 if (tb
[FRA_FWMARK
] || tb
[FRA_FWMASK
]) {
243 __u32 mark
= 0, mask
= 0;
246 mark
= rta_getattr_u32(tb
[FRA_FWMARK
]);
248 if (tb
[FRA_FWMASK
] &&
249 (mask
= rta_getattr_u32(tb
[FRA_FWMASK
])) != 0xFFFFFFFF)
250 fprintf(fp
, "fwmark 0x%x/0x%x ", mark
, mask
);
252 fprintf(fp
, "fwmark 0x%x ", mark
);
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] ");
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] ");
267 if (tb
[FRA_L3MDEV
]) {
268 if (rta_getattr_u8(tb
[FRA_L3MDEV
]))
269 fprintf(fp
, "lookup [l3mdev-table] ");
272 if (tb
[FRA_UID_RANGE
]) {
273 struct fib_rule_uid_range
*r
= RTA_DATA(tb
[FRA_UID_RANGE
]);
275 fprintf(fp
, "uidrange %u-%u ", r
->start
, r
->end
);
278 table
= rtm_get_table(r
, tb
);
280 fprintf(fp
, "lookup %s ",
281 rtnl_rttable_n2a(table
, b1
, sizeof(b1
)));
283 if (tb
[FRA_SUPPRESS_PREFIXLEN
]) {
284 int pl
= rta_getattr_u32(tb
[FRA_SUPPRESS_PREFIXLEN
]);
287 fprintf(fp
, "suppress_prefixlength %d ", pl
);
289 if (tb
[FRA_SUPPRESS_IFGROUP
]) {
290 int group
= rta_getattr_u32(tb
[FRA_SUPPRESS_IFGROUP
]);
294 fprintf(fp
, "suppress_ifgroup %s ",
295 rtnl_group_n2a(group
, b1
, sizeof(b1
)));
301 __u32 to
= rta_getattr_u32(tb
[FRA_FLOW
]);
306 fprintf(fp
, "realms %s/",
307 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
310 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
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
,
319 fprintf(fp
, "masquerade");
320 } else if (r
->rtm_type
== FR_ACT_GOTO
) {
321 fprintf(fp
, "goto ");
323 fprintf(fp
, "%u", rta_getattr_u32(tb
[FRA_GOTO
]));
326 if (r
->rtm_flags
& FIB_RULE_UNRESOLVED
)
327 fprintf(fp
, " [unresolved]");
328 } else if (r
->rtm_type
== FR_ACT_NOP
)
330 else if (r
->rtm_type
!= RTN_UNICAST
)
332 rtnl_rtntype_n2a(r
->rtm_type
,
340 static __u32 rule_dump_magic
= 0x71706986;
342 static int save_rule_prep(void)
346 if (isatty(STDOUT_FILENO
)) {
347 fprintf(stderr
, "Not sending a binary stream to stdout\n");
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");
360 static int save_rule(const struct sockaddr_nl
*who
,
361 struct nlmsghdr
*n
, void *arg
)
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");
371 return ret
== n
->nlmsg_len
? 0 : ret
;
374 static int flush_rule(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
,
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];
382 len
-= NLMSG_LENGTH(sizeof(*r
));
386 parse_rtattr(tb
, FRA_MAX
, RTM_RTA(r
), len
);
388 if (tb
[FRA_PRIORITY
]) {
389 n
->nlmsg_type
= RTM_DELRULE
;
390 n
->nlmsg_flags
= NLM_F_REQUEST
;
392 if (rtnl_open(&rth2
, 0) < 0)
395 if (rtnl_talk(&rth2
, n
, NULL
) < 0)
404 static int iprule_list_flush_or_save(int argc
, char **argv
, int action
)
406 rtnl_filter_t filter_fn
;
407 int af
= preferred_family
;
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");
420 if (save_rule_prep())
422 filter_fn
= save_rule
;
425 filter_fn
= flush_rule
;
428 filter_fn
= print_rule
;
431 memset(&filter
, 0, sizeof(filter
));
434 if (matches(*argv
, "preference") == 0 ||
435 matches(*argv
, "order") == 0 ||
436 matches(*argv
, "priority") == 0) {
440 if (get_u32(&pref
, *argv
, 0))
441 invarg("preference value is invalid\n", *argv
);
444 } else if (strcmp(*argv
, "not") == 0) {
446 } else if (strcmp(*argv
, "tos") == 0) {
450 if (rtnl_dsfield_a2n(&tos
, *argv
))
451 invarg("TOS value is invalid\n", *argv
);
454 } else if (strcmp(*argv
, "fwmark") == 0) {
456 __u32 fwmark
, fwmask
;
459 slash
= strchr(*argv
, '/');
462 if (get_u32(&fwmark
, *argv
, 0))
463 invarg("fwmark value is invalid\n", *argv
);
464 filter
.fwmark
= fwmark
;
466 if (get_u32(&fwmask
, slash
+1, 0))
467 invarg("fwmask value is invalid\n",
469 filter
.fwmask
= fwmask
;
471 } else if (strcmp(*argv
, "dev") == 0 ||
472 strcmp(*argv
, "iif") == 0) {
474 if (get_ifname(filter
.iif
, *argv
))
475 invarg("\"iif\"/\"dev\" not a valid ifname", *argv
);
477 } else if (strcmp(*argv
, "oif") == 0) {
479 if (get_ifname(filter
.oif
, *argv
))
480 invarg("\"oif\" not a valid ifname", *argv
);
482 } else if (strcmp(*argv
, "l3mdev") == 0) {
484 } else if (strcmp(*argv
, "uidrange") == 0) {
487 if (sscanf(*argv
, "%u-%u",
489 &filter
.range
.end
) != 2)
490 invarg("invalid UID range\n", *argv
);
492 } else if (matches(*argv
, "lookup") == 0 ||
493 matches(*argv
, "table") == 0) {
497 if (rtnl_rttable_a2n(&tid
, *argv
))
498 invarg("table id value is invalid\n", *argv
);
500 } else if (matches(*argv
, "from") == 0 ||
501 matches(*argv
, "src") == 0) {
503 get_prefix(&filter
.src
, *argv
, af
);
505 if (matches(*argv
, "dst") == 0 ||
506 matches(*argv
, "to") == 0) {
509 get_prefix(&filter
.dst
, *argv
, af
);
514 if (rtnl_wilddump_request(&rth
, af
, RTM_GETRULE
) < 0) {
515 perror("Cannot send dump request");
519 if (rtnl_dump_filter(&rth
, filter_fn
, stdout
) < 0) {
520 fprintf(stderr
, "Dump terminated\n");
527 static int rule_dump_check_magic(void)
532 if (isatty(STDIN_FILENO
)) {
533 fprintf(stderr
, "Can't restore rule dump from a terminal\n");
537 ret
= fread(&magic
, sizeof(magic
), 1, stdin
);
538 if (magic
!= rule_dump_magic
) {
539 fprintf(stderr
, "Magic mismatch (%d elems, %x magic)\n",
547 static int restore_handler(const struct sockaddr_nl
*nl
,
548 struct rtnl_ctrl_data
*ctrl
,
549 struct nlmsghdr
*n
, void *arg
)
553 n
->nlmsg_flags
|= NLM_F_REQUEST
| NLM_F_CREATE
| NLM_F_ACK
;
557 ret
= rtnl_talk(&rth
, n
, NULL
);
558 if ((ret
< 0) && (errno
== EEXIST
))
565 static int iprule_restore(void)
567 if (rule_dump_check_magic())
570 exit(rtnl_from_file(stdin
, &restore_handler
, NULL
));
573 static int iprule_modify(int cmd
, int argc
, char **argv
)
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
,
592 if (cmd
== RTM_NEWRULE
) {
593 req
.n
.nlmsg_flags
|= NLM_F_CREATE
|NLM_F_EXCL
;
594 req
.r
.rtm_type
= RTN_UNICAST
;
597 if (cmd
== RTM_DELRULE
&& argc
== 0) {
598 fprintf(stderr
, "\"ip rule del\" requires arguments.\n");
603 if (strcmp(*argv
, "not") == 0) {
604 req
.r
.rtm_flags
|= FIB_RULE_INVERT
;
605 } else if (strcmp(*argv
, "from") == 0) {
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) {
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) {
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) {
635 if (rtnl_dsfield_a2n(&tos
, *argv
))
636 invarg("TOS value is invalid\n", *argv
);
638 } else if (strcmp(*argv
, "fwmark") == 0) {
640 __u32 fwmark
, fwmask
;
644 slash
= strchr(*argv
, '/');
647 if (get_u32(&fwmark
, *argv
, 0))
648 invarg("fwmark value is invalid\n", *argv
);
649 addattr32(&req
.n
, sizeof(req
), FRA_FWMARK
, fwmark
);
651 if (get_u32(&fwmask
, slash
+1, 0))
652 invarg("fwmask value is invalid\n",
654 addattr32(&req
.n
, sizeof(req
),
657 } else if (matches(*argv
, "realms") == 0) {
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) {
667 if (rtnl_rttable_a2n(&tid
, *argv
))
668 invarg("invalid table ID\n", *argv
);
670 req
.r
.rtm_table
= tid
;
672 req
.r
.rtm_table
= RT_TABLE_UNSPEC
;
673 addattr32(&req
.n
, sizeof(req
), FRA_TABLE
, tid
);
676 } else if (matches(*argv
, "suppress_prefixlength") == 0 ||
677 strcmp(*argv
, "sup_pl") == 0) {
681 if (get_s32(&pl
, *argv
, 0) || pl
< 0)
682 invarg("suppress_prefixlength value is invalid\n",
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) {
691 if (rtnl_group_a2n(&group
, *argv
))
692 invarg("Invalid \"suppress_ifgroup\" value\n",
694 addattr32(&req
.n
, sizeof(req
),
695 FRA_SUPPRESS_IFGROUP
, group
);
696 } else if (strcmp(*argv
, "dev") == 0 ||
697 strcmp(*argv
, "iif") == 0) {
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) {
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);
713 } else if (strcmp(*argv
, "uidrange") == 0) {
714 struct fib_rule_uid_range r
;
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
,
721 } else if (strcmp(*argv
, "nat") == 0 ||
722 matches(*argv
, "map-to") == 0) {
724 fprintf(stderr
, "Warning: route NAT is deprecated\n");
725 addattr32(&req
.n
, sizeof(req
), RTA_GATEWAY
,
727 req
.r
.rtm_type
= RTN_NAT
;
731 if (strcmp(*argv
, "type") == 0)
734 if (matches(*argv
, "help") == 0)
736 else if (matches(*argv
, "goto") == 0) {
741 if (get_u32(&target
, *argv
, 0))
742 invarg("invalid target\n", *argv
);
743 addattr32(&req
.n
, sizeof(req
),
745 } else if (matches(*argv
, "nop") == 0)
747 else if (rtnl_rtntype_a2n(&type
, *argv
))
748 invarg("Failed to parse rule type", *argv
);
749 req
.r
.rtm_type
= type
;
756 if (l3mdev_rule
&& tid
!= 0) {
758 "table can not be specified for l3mdev rules\n");
762 if (req
.r
.rtm_family
== AF_UNSPEC
)
763 req
.r
.rtm_family
= AF_INET
;
765 if (!table_ok
&& cmd
== RTM_NEWRULE
)
766 req
.r
.rtm_table
= RT_TABLE_MAIN
;
768 if (rtnl_talk(&rth
, &req
.n
, NULL
) < 0)
774 int do_iprule(int argc
, char **argv
)
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)
796 "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv
);
800 int do_multirule(int argc
, char **argv
)
802 switch (preferred_family
) {
805 preferred_family
= RTNL_FAMILY_IPMR
;
808 preferred_family
= RTNL_FAMILY_IP6MR
;
810 case RTNL_FAMILY_IPMR
:
811 case RTNL_FAMILY_IP6MR
:
815 "Multicast rules are only supported for IPv4/IPv6, was: %i\n",
820 return do_iprule(argc
, argv
);