]>
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>
18 #include <sys/socket.h>
19 #include <netinet/in.h>
20 #include <netinet/ip.h>
21 #include <arpa/inet.h>
24 #include <linux/fib_rules.h>
29 #include "ip_common.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"
52 " [ realms [SRCREALM/]DSTREALM ]\n"
55 "SUPPRESSOR := [ suppress_prefixlength NUMBER ]\n"
56 " [ suppress_ifgroup DEVGROUP ]\n"
57 "TABLE_ID := [ local | main | default | NUMBER ]\n");
65 int iifmask
, oifmask
, uidrange
;
67 unsigned int tos
, tosmask
;
68 unsigned int pref
, prefmask
;
69 unsigned int fwmark
, fwmask
;
72 struct fib_rule_uid_range range
;
77 static bool filter_nlmsg(struct nlmsghdr
*n
, struct rtattr
**tb
, int host_len
)
79 struct rtmsg
*r
= NLMSG_DATA(n
);
80 inet_prefix src
= { .family
= r
->rtm_family
};
81 inet_prefix dst
= { .family
= r
->rtm_family
};
84 if (preferred_family
!= AF_UNSPEC
&& r
->rtm_family
!= preferred_family
)
87 if (filter
.prefmask
&&
88 filter
.pref
^ (tb
[FRA_PRIORITY
] ? rta_getattr_u32(tb
[FRA_PRIORITY
]) : 0))
90 if (filter
.not && !(r
->rtm_flags
& FIB_RULE_INVERT
))
93 if (filter
.src
.family
) {
95 memcpy(&src
.data
, RTA_DATA(tb
[FRA_SRC
]),
96 (r
->rtm_src_len
+ 7) / 8);
98 if (filter
.src
.family
!= r
->rtm_family
||
99 filter
.src
.bitlen
> r
->rtm_src_len
||
100 inet_addr_match(&src
, &filter
.src
, filter
.src
.bitlen
))
104 if (filter
.dst
.family
) {
106 memcpy(&dst
.data
, RTA_DATA(tb
[FRA_DST
]),
107 (r
->rtm_dst_len
+ 7) / 8);
109 if (filter
.dst
.family
!= r
->rtm_family
||
110 filter
.dst
.bitlen
> r
->rtm_dst_len
||
111 inet_addr_match(&dst
, &filter
.dst
, filter
.dst
.bitlen
))
115 if (filter
.tosmask
&& filter
.tos
^ r
->rtm_tos
)
122 mark
= rta_getattr_u32(tb
[FRA_FWMARK
]);
123 if (filter
.fwmark
^ mark
)
130 mask
= rta_getattr_u32(tb
[FRA_FWMASK
]);
131 if (filter
.fwmask
^ mask
)
135 if (filter
.iifmask
) {
136 if (tb
[FRA_IFNAME
]) {
137 if (strcmp(filter
.iif
, rta_getattr_str(tb
[FRA_IFNAME
])) != 0)
144 if (filter
.oifmask
) {
145 if (tb
[FRA_OIFNAME
]) {
146 if (strcmp(filter
.oif
, rta_getattr_str(tb
[FRA_OIFNAME
])) != 0)
153 if (filter
.l3mdev
&& !(tb
[FRA_L3MDEV
] && rta_getattr_u8(tb
[FRA_L3MDEV
])))
156 if (filter
.uidrange
) {
157 struct fib_rule_uid_range
*r
= RTA_DATA(tb
[FRA_UID_RANGE
]);
159 if (!tb
[FRA_UID_RANGE
] ||
160 r
->start
!= filter
.range
.start
||
161 r
->end
!= filter
.range
.end
)
165 table
= rtm_get_table(r
, tb
);
166 if (filter
.tb
> 0 && filter
.tb
^ table
)
172 int print_rule(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
, void *arg
)
174 FILE *fp
= (FILE *)arg
;
175 struct rtmsg
*r
= NLMSG_DATA(n
);
176 int len
= n
->nlmsg_len
;
179 struct rtattr
*tb
[FRA_MAX
+1];
183 if (n
->nlmsg_type
!= RTM_NEWRULE
&& n
->nlmsg_type
!= RTM_DELRULE
)
186 len
-= NLMSG_LENGTH(sizeof(*r
));
190 parse_rtattr(tb
, FRA_MAX
, RTM_RTA(r
), len
);
192 host_len
= af_bit_len(r
->rtm_family
);
194 if (!filter_nlmsg(n
, tb
, host_len
))
197 if (n
->nlmsg_type
== RTM_DELRULE
)
198 fprintf(fp
, "Deleted ");
200 if (tb
[FRA_PRIORITY
])
202 rta_getattr_u32(tb
[FRA_PRIORITY
]));
206 if (r
->rtm_flags
& FIB_RULE_INVERT
)
210 if (r
->rtm_src_len
!= host_len
) {
211 fprintf(fp
, "from %s/%u ",
212 rt_addr_n2a_rta(r
->rtm_family
, tb
[FRA_SRC
]),
215 fprintf(fp
, "from %s ",
216 format_host_rta(r
->rtm_family
, tb
[FRA_SRC
]));
218 } else if (r
->rtm_src_len
) {
219 fprintf(fp
, "from 0/%d ", r
->rtm_src_len
);
221 fprintf(fp
, "from all ");
225 if (r
->rtm_dst_len
!= host_len
) {
226 fprintf(fp
, "to %s/%u ",
227 rt_addr_n2a_rta(r
->rtm_family
, tb
[FRA_DST
]),
230 fprintf(fp
, "to %s ",
231 format_host_rta(r
->rtm_family
, tb
[FRA_DST
]));
233 } else if (r
->rtm_dst_len
) {
234 fprintf(fp
, "to 0/%d ", r
->rtm_dst_len
);
239 fprintf(fp
, "tos %s ",
240 rtnl_dsfield_n2a(r
->rtm_tos
, b1
, sizeof(b1
)));
243 if (tb
[FRA_FWMARK
] || tb
[FRA_FWMASK
]) {
244 __u32 mark
= 0, mask
= 0;
247 mark
= rta_getattr_u32(tb
[FRA_FWMARK
]);
249 if (tb
[FRA_FWMASK
] &&
250 (mask
= rta_getattr_u32(tb
[FRA_FWMASK
])) != 0xFFFFFFFF)
251 fprintf(fp
, "fwmark 0x%x/0x%x ", mark
, mask
);
253 fprintf(fp
, "fwmark 0x%x ", mark
);
256 if (tb
[FRA_IFNAME
]) {
257 fprintf(fp
, "iif %s ", rta_getattr_str(tb
[FRA_IFNAME
]));
258 if (r
->rtm_flags
& FIB_RULE_IIF_DETACHED
)
259 fprintf(fp
, "[detached] ");
262 if (tb
[FRA_OIFNAME
]) {
263 fprintf(fp
, "oif %s ", rta_getattr_str(tb
[FRA_OIFNAME
]));
264 if (r
->rtm_flags
& FIB_RULE_OIF_DETACHED
)
265 fprintf(fp
, "[detached] ");
268 if (tb
[FRA_L3MDEV
]) {
269 if (rta_getattr_u8(tb
[FRA_L3MDEV
]))
270 fprintf(fp
, "lookup [l3mdev-table] ");
273 if (tb
[FRA_UID_RANGE
]) {
274 struct fib_rule_uid_range
*r
= RTA_DATA(tb
[FRA_UID_RANGE
]);
276 fprintf(fp
, "uidrange %u-%u ", r
->start
, r
->end
);
279 table
= rtm_get_table(r
, tb
);
281 fprintf(fp
, "lookup %s ",
282 rtnl_rttable_n2a(table
, b1
, sizeof(b1
)));
284 if (tb
[FRA_SUPPRESS_PREFIXLEN
]) {
285 int pl
= rta_getattr_u32(tb
[FRA_SUPPRESS_PREFIXLEN
]);
288 fprintf(fp
, "suppress_prefixlength %d ", pl
);
290 if (tb
[FRA_SUPPRESS_IFGROUP
]) {
291 int group
= rta_getattr_u32(tb
[FRA_SUPPRESS_IFGROUP
]);
295 fprintf(fp
, "suppress_ifgroup %s ",
296 rtnl_group_n2a(group
, b1
, sizeof(b1
)));
302 __u32 to
= rta_getattr_u32(tb
[FRA_FLOW
]);
307 fprintf(fp
, "realms %s/",
308 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
311 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
314 if (r
->rtm_type
== RTN_NAT
) {
315 if (tb
[RTA_GATEWAY
]) {
316 fprintf(fp
, "map-to %s ",
317 format_host_rta(r
->rtm_family
,
320 fprintf(fp
, "masquerade");
321 } else if (r
->rtm_type
== FR_ACT_GOTO
) {
322 fprintf(fp
, "goto ");
324 fprintf(fp
, "%u", rta_getattr_u32(tb
[FRA_GOTO
]));
327 if (r
->rtm_flags
& FIB_RULE_UNRESOLVED
)
328 fprintf(fp
, " [unresolved]");
329 } else if (r
->rtm_type
== FR_ACT_NOP
)
331 else if (r
->rtm_type
!= RTN_UNICAST
)
333 rtnl_rtntype_n2a(r
->rtm_type
,
341 static __u32 rule_dump_magic
= 0x71706986;
343 static int save_rule_prep(void)
347 if (isatty(STDOUT_FILENO
)) {
348 fprintf(stderr
, "Not sending a binary stream to stdout\n");
352 ret
= write(STDOUT_FILENO
, &rule_dump_magic
, sizeof(rule_dump_magic
));
353 if (ret
!= sizeof(rule_dump_magic
)) {
354 fprintf(stderr
, "Can't write magic to dump file\n");
361 static int save_rule(const struct sockaddr_nl
*who
,
362 struct nlmsghdr
*n
, void *arg
)
366 ret
= write(STDOUT_FILENO
, n
, n
->nlmsg_len
);
367 if ((ret
> 0) && (ret
!= n
->nlmsg_len
)) {
368 fprintf(stderr
, "Short write while saving nlmsg\n");
372 return ret
== n
->nlmsg_len
? 0 : ret
;
375 static int flush_rule(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
,
378 struct rtnl_handle rth2
;
379 struct rtmsg
*r
= NLMSG_DATA(n
);
380 int len
= n
->nlmsg_len
;
381 struct rtattr
*tb
[FRA_MAX
+1];
383 len
-= NLMSG_LENGTH(sizeof(*r
));
387 parse_rtattr(tb
, FRA_MAX
, RTM_RTA(r
), len
);
389 if (tb
[FRA_PRIORITY
]) {
390 n
->nlmsg_type
= RTM_DELRULE
;
391 n
->nlmsg_flags
= NLM_F_REQUEST
;
393 if (rtnl_open(&rth2
, 0) < 0)
396 if (rtnl_talk(&rth2
, n
, NULL
) < 0)
405 static int iprule_list_flush_or_save(int argc
, char **argv
, int action
)
407 rtnl_filter_t filter_fn
;
408 int af
= preferred_family
;
413 if (action
!= IPRULE_LIST
&& argc
> 0) {
414 fprintf(stderr
, "\"ip rule %s\" does not take any arguments.\n",
415 action
== IPRULE_SAVE
? "save" : "flush");
421 if (save_rule_prep())
423 filter_fn
= save_rule
;
426 filter_fn
= flush_rule
;
429 filter_fn
= print_rule
;
432 memset(&filter
, 0, sizeof(filter
));
435 if (matches(*argv
, "preference") == 0 ||
436 matches(*argv
, "order") == 0 ||
437 matches(*argv
, "priority") == 0) {
441 if (get_u32(&pref
, *argv
, 0))
442 invarg("preference value is invalid\n", *argv
);
445 } else if (strcmp(*argv
, "not") == 0) {
447 } else if (strcmp(*argv
, "tos") == 0) {
451 if (rtnl_dsfield_a2n(&tos
, *argv
))
452 invarg("TOS value is invalid\n", *argv
);
455 } else if (strcmp(*argv
, "fwmark") == 0) {
457 __u32 fwmark
, fwmask
;
460 slash
= strchr(*argv
, '/');
463 if (get_u32(&fwmark
, *argv
, 0))
464 invarg("fwmark value is invalid\n", *argv
);
465 filter
.fwmark
= fwmark
;
467 if (get_u32(&fwmask
, slash
+1, 0))
468 invarg("fwmask value is invalid\n",
470 filter
.fwmask
= fwmask
;
472 } else if (strcmp(*argv
, "dev") == 0 ||
473 strcmp(*argv
, "iif") == 0) {
475 if (get_ifname(filter
.iif
, *argv
))
476 invarg("\"iif\"/\"dev\" not a valid ifname", *argv
);
478 } else if (strcmp(*argv
, "oif") == 0) {
480 if (get_ifname(filter
.oif
, *argv
))
481 invarg("\"oif\" not a valid ifname", *argv
);
483 } else if (strcmp(*argv
, "l3mdev") == 0) {
485 } else if (strcmp(*argv
, "uidrange") == 0) {
488 if (sscanf(*argv
, "%u-%u",
490 &filter
.range
.end
) != 2)
491 invarg("invalid UID range\n", *argv
);
493 } else if (matches(*argv
, "lookup") == 0 ||
494 matches(*argv
, "table") == 0) {
498 if (rtnl_rttable_a2n(&tid
, *argv
))
499 invarg("table id value is invalid\n", *argv
);
501 } else if (matches(*argv
, "from") == 0 ||
502 matches(*argv
, "src") == 0) {
504 get_prefix(&filter
.src
, *argv
, af
);
506 if (matches(*argv
, "dst") == 0 ||
507 matches(*argv
, "to") == 0) {
510 get_prefix(&filter
.dst
, *argv
, af
);
515 if (rtnl_wilddump_request(&rth
, af
, RTM_GETRULE
) < 0) {
516 perror("Cannot send dump request");
520 if (rtnl_dump_filter(&rth
, filter_fn
, stdout
) < 0) {
521 fprintf(stderr
, "Dump terminated\n");
528 static int rule_dump_check_magic(void)
533 if (isatty(STDIN_FILENO
)) {
534 fprintf(stderr
, "Can't restore rule dump from a terminal\n");
538 ret
= fread(&magic
, sizeof(magic
), 1, stdin
);
539 if (magic
!= rule_dump_magic
) {
540 fprintf(stderr
, "Magic mismatch (%d elems, %x magic)\n",
548 static int restore_handler(const struct sockaddr_nl
*nl
,
549 struct rtnl_ctrl_data
*ctrl
,
550 struct nlmsghdr
*n
, void *arg
)
554 n
->nlmsg_flags
|= NLM_F_REQUEST
| NLM_F_CREATE
| NLM_F_ACK
;
558 ret
= rtnl_talk(&rth
, n
, NULL
);
559 if ((ret
< 0) && (errno
== EEXIST
))
566 static int iprule_restore(void)
568 if (rule_dump_check_magic())
571 exit(rtnl_from_file(stdin
, &restore_handler
, NULL
));
574 static int iprule_modify(int cmd
, int argc
, char **argv
)
585 .n
.nlmsg_len
= NLMSG_LENGTH(sizeof(struct rtmsg
)),
586 .n
.nlmsg_flags
= NLM_F_REQUEST
,
587 .r
.rtm_family
= preferred_family
,
588 .r
.rtm_protocol
= RTPROT_BOOT
,
589 .r
.rtm_scope
= RT_SCOPE_UNIVERSE
,
590 .r
.rtm_type
= RTN_UNSPEC
,
593 if (cmd
== RTM_NEWRULE
) {
594 req
.n
.nlmsg_flags
|= NLM_F_CREATE
|NLM_F_EXCL
;
595 req
.r
.rtm_type
= RTN_UNICAST
;
598 if (cmd
== RTM_DELRULE
&& argc
== 0) {
599 fprintf(stderr
, "\"ip rule del\" requires arguments.\n");
604 if (strcmp(*argv
, "not") == 0) {
605 req
.r
.rtm_flags
|= FIB_RULE_INVERT
;
606 } else if (strcmp(*argv
, "from") == 0) {
610 get_prefix(&dst
, *argv
, req
.r
.rtm_family
);
611 req
.r
.rtm_src_len
= dst
.bitlen
;
612 addattr_l(&req
.n
, sizeof(req
), FRA_SRC
,
613 &dst
.data
, dst
.bytelen
);
614 } else if (strcmp(*argv
, "to") == 0) {
618 get_prefix(&dst
, *argv
, req
.r
.rtm_family
);
619 req
.r
.rtm_dst_len
= dst
.bitlen
;
620 addattr_l(&req
.n
, sizeof(req
), FRA_DST
,
621 &dst
.data
, dst
.bytelen
);
622 } else if (matches(*argv
, "preference") == 0 ||
623 matches(*argv
, "order") == 0 ||
624 matches(*argv
, "priority") == 0) {
628 if (get_u32(&pref
, *argv
, 0))
629 invarg("preference value is invalid\n", *argv
);
630 addattr32(&req
.n
, sizeof(req
), FRA_PRIORITY
, pref
);
631 } else if (strcmp(*argv
, "tos") == 0 ||
632 matches(*argv
, "dsfield") == 0) {
636 if (rtnl_dsfield_a2n(&tos
, *argv
))
637 invarg("TOS value is invalid\n", *argv
);
639 } else if (strcmp(*argv
, "fwmark") == 0) {
641 __u32 fwmark
, fwmask
;
645 slash
= strchr(*argv
, '/');
648 if (get_u32(&fwmark
, *argv
, 0))
649 invarg("fwmark value is invalid\n", *argv
);
650 addattr32(&req
.n
, sizeof(req
), FRA_FWMARK
, fwmark
);
652 if (get_u32(&fwmask
, slash
+1, 0))
653 invarg("fwmask value is invalid\n",
655 addattr32(&req
.n
, sizeof(req
),
658 } else if (matches(*argv
, "realms") == 0) {
662 if (get_rt_realms_or_raw(&realm
, *argv
))
663 invarg("invalid realms\n", *argv
);
664 addattr32(&req
.n
, sizeof(req
), FRA_FLOW
, realm
);
665 } else if (matches(*argv
, "table") == 0 ||
666 strcmp(*argv
, "lookup") == 0) {
668 if (rtnl_rttable_a2n(&tid
, *argv
))
669 invarg("invalid table ID\n", *argv
);
671 req
.r
.rtm_table
= tid
;
673 req
.r
.rtm_table
= RT_TABLE_UNSPEC
;
674 addattr32(&req
.n
, sizeof(req
), FRA_TABLE
, tid
);
677 } else if (matches(*argv
, "suppress_prefixlength") == 0 ||
678 strcmp(*argv
, "sup_pl") == 0) {
682 if (get_s32(&pl
, *argv
, 0) || pl
< 0)
683 invarg("suppress_prefixlength value is invalid\n",
685 addattr32(&req
.n
, sizeof(req
),
686 FRA_SUPPRESS_PREFIXLEN
, pl
);
687 } else if (matches(*argv
, "suppress_ifgroup") == 0 ||
688 strcmp(*argv
, "sup_group") == 0) {
692 if (rtnl_group_a2n(&group
, *argv
))
693 invarg("Invalid \"suppress_ifgroup\" value\n",
695 addattr32(&req
.n
, sizeof(req
),
696 FRA_SUPPRESS_IFGROUP
, group
);
697 } else if (strcmp(*argv
, "dev") == 0 ||
698 strcmp(*argv
, "iif") == 0) {
700 if (check_ifname(*argv
))
701 invarg("\"iif\"/\"dev\" not a valid ifname", *argv
);
702 addattr_l(&req
.n
, sizeof(req
), FRA_IFNAME
,
703 *argv
, strlen(*argv
)+1);
704 } else if (strcmp(*argv
, "oif") == 0) {
706 if (check_ifname(*argv
))
707 invarg("\"oif\" not a valid ifname", *argv
);
708 addattr_l(&req
.n
, sizeof(req
), FRA_OIFNAME
,
709 *argv
, strlen(*argv
)+1);
710 } else if (strcmp(*argv
, "l3mdev") == 0) {
711 addattr8(&req
.n
, sizeof(req
), FRA_L3MDEV
, 1);
714 } else if (strcmp(*argv
, "uidrange") == 0) {
715 struct fib_rule_uid_range r
;
718 if (sscanf(*argv
, "%u-%u", &r
.start
, &r
.end
) != 2)
719 invarg("invalid UID range\n", *argv
);
720 addattr_l(&req
.n
, sizeof(req
), FRA_UID_RANGE
, &r
,
722 } else if (strcmp(*argv
, "nat") == 0 ||
723 matches(*argv
, "map-to") == 0) {
725 fprintf(stderr
, "Warning: route NAT is deprecated\n");
726 addattr32(&req
.n
, sizeof(req
), RTA_GATEWAY
,
728 req
.r
.rtm_type
= RTN_NAT
;
732 if (strcmp(*argv
, "type") == 0)
735 if (matches(*argv
, "help") == 0)
737 else if (matches(*argv
, "goto") == 0) {
742 if (get_u32(&target
, *argv
, 0))
743 invarg("invalid target\n", *argv
);
744 addattr32(&req
.n
, sizeof(req
),
746 } else if (matches(*argv
, "nop") == 0)
748 else if (rtnl_rtntype_a2n(&type
, *argv
))
749 invarg("Failed to parse rule type", *argv
);
750 req
.r
.rtm_type
= type
;
757 if (l3mdev_rule
&& tid
!= 0) {
759 "table can not be specified for l3mdev rules\n");
763 if (req
.r
.rtm_family
== AF_UNSPEC
)
764 req
.r
.rtm_family
= AF_INET
;
766 if (!table_ok
&& cmd
== RTM_NEWRULE
)
767 req
.r
.rtm_table
= RT_TABLE_MAIN
;
769 if (rtnl_talk(&rth
, &req
.n
, NULL
) < 0)
775 int do_iprule(int argc
, char **argv
)
778 return iprule_list_flush_or_save(0, NULL
, IPRULE_LIST
);
779 } else if (matches(argv
[0], "list") == 0 ||
780 matches(argv
[0], "lst") == 0 ||
781 matches(argv
[0], "show") == 0) {
782 return iprule_list_flush_or_save(argc
-1, argv
+1, IPRULE_LIST
);
783 } else if (matches(argv
[0], "save") == 0) {
784 return iprule_list_flush_or_save(argc
-1, argv
+1, IPRULE_SAVE
);
785 } else if (matches(argv
[0], "restore") == 0) {
786 return iprule_restore();
787 } else if (matches(argv
[0], "add") == 0) {
788 return iprule_modify(RTM_NEWRULE
, argc
-1, argv
+1);
789 } else if (matches(argv
[0], "delete") == 0) {
790 return iprule_modify(RTM_DELRULE
, argc
-1, argv
+1);
791 } else if (matches(argv
[0], "flush") == 0) {
792 return iprule_list_flush_or_save(argc
-1, argv
+1, IPRULE_FLUSH
);
793 } else if (matches(argv
[0], "help") == 0)
797 "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv
);
801 int do_multirule(int argc
, char **argv
)
803 switch (preferred_family
) {
806 preferred_family
= RTNL_FAMILY_IPMR
;
809 preferred_family
= RTNL_FAMILY_IP6MR
;
811 case RTNL_FAMILY_IPMR
:
812 case RTNL_FAMILY_IP6MR
:
816 "Multicast rules are only supported for IPv4/IPv6, was: %i\n",
821 return do_iprule(argc
, argv
);