]>
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)
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");
65 unsigned int tos
, tosmask
;
66 unsigned int pref
, prefmask
;
67 unsigned int fwmark
, fwmask
;
74 static bool filter_nlmsg(struct nlmsghdr
*n
, struct rtattr
**tb
, int host_len
)
76 struct rtmsg
*r
= NLMSG_DATA(n
);
77 inet_prefix src
= { .family
= r
->rtm_family
};
78 inet_prefix dst
= { .family
= r
->rtm_family
};
81 if (preferred_family
!= AF_UNSPEC
&& r
->rtm_family
!= preferred_family
)
84 if (filter
.prefmask
&&
85 filter
.pref
^ (tb
[FRA_PRIORITY
] ? rta_getattr_u32(tb
[FRA_PRIORITY
]) : 0))
87 if (filter
.not && !(r
->rtm_flags
& FIB_RULE_INVERT
))
90 if (filter
.src
.family
) {
92 memcpy(&src
.data
, RTA_DATA(tb
[FRA_SRC
]),
93 (r
->rtm_src_len
+ 7) / 8);
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
))
101 if (filter
.dst
.family
) {
103 memcpy(&dst
.data
, RTA_DATA(tb
[FRA_DST
]),
104 (r
->rtm_dst_len
+ 7) / 8);
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
))
112 if (filter
.tosmask
&& filter
.tos
^ r
->rtm_tos
)
118 mark
= rta_getattr_u32(tb
[FRA_FWMARK
]);
119 if (filter
.fwmark
^ mark
)
125 mask
= rta_getattr_u32(tb
[FRA_FWMASK
]);
126 if (filter
.fwmask
^ mask
)
130 if (filter
.iifmask
) {
131 if (tb
[FRA_IFNAME
]) {
132 if (strcmp(filter
.iif
, rta_getattr_str(tb
[FRA_IFNAME
])) != 0)
139 if (filter
.oifmask
) {
140 if (tb
[FRA_OIFNAME
]) {
141 if (strcmp(filter
.oif
, rta_getattr_str(tb
[FRA_OIFNAME
])) != 0)
148 if (filter
.l3mdev
&& !(tb
[FRA_L3MDEV
] && rta_getattr_u8(tb
[FRA_L3MDEV
])))
151 table
= rtm_get_table(r
, tb
);
152 if (filter
.tb
> 0 && filter
.tb
^ table
)
158 int print_rule(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
, void *arg
)
160 FILE *fp
= (FILE *)arg
;
161 struct rtmsg
*r
= NLMSG_DATA(n
);
162 int len
= n
->nlmsg_len
;
165 struct rtattr
*tb
[FRA_MAX
+1];
169 if (n
->nlmsg_type
!= RTM_NEWRULE
&& n
->nlmsg_type
!= RTM_DELRULE
)
172 len
-= NLMSG_LENGTH(sizeof(*r
));
176 parse_rtattr(tb
, FRA_MAX
, RTM_RTA(r
), len
);
178 host_len
= af_bit_len(r
->rtm_family
);
180 if(!filter_nlmsg(n
, tb
, host_len
))
183 if (n
->nlmsg_type
== RTM_DELRULE
)
184 fprintf(fp
, "Deleted ");
186 if (tb
[FRA_PRIORITY
])
188 rta_getattr_u32(tb
[FRA_PRIORITY
]));
192 if (r
->rtm_flags
& FIB_RULE_INVERT
)
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
]),
201 fprintf(fp
, "from %s ",
202 format_host_rta(r
->rtm_family
, tb
[FRA_SRC
]));
204 } else if (r
->rtm_src_len
) {
205 fprintf(fp
, "from 0/%d ", r
->rtm_src_len
);
207 fprintf(fp
, "from all ");
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
]),
216 fprintf(fp
, "to %s ",
217 format_host_rta(r
->rtm_family
, tb
[FRA_DST
]));
219 } else if (r
->rtm_dst_len
) {
220 fprintf(fp
, "to 0/%d ", r
->rtm_dst_len
);
225 fprintf(fp
, "tos %s ",
226 rtnl_dsfield_n2a(r
->rtm_tos
, b1
, sizeof(b1
)));
229 if (tb
[FRA_FWMARK
] || tb
[FRA_FWMASK
]) {
230 __u32 mark
= 0, mask
= 0;
233 mark
= rta_getattr_u32(tb
[FRA_FWMARK
]);
235 if (tb
[FRA_FWMASK
] &&
236 (mask
= rta_getattr_u32(tb
[FRA_FWMASK
])) != 0xFFFFFFFF)
237 fprintf(fp
, "fwmark 0x%x/0x%x ", mark
, mask
);
239 fprintf(fp
, "fwmark 0x%x ", mark
);
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] ");
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] ");
254 if (tb
[FRA_L3MDEV
]) {
255 if (rta_getattr_u8(tb
[FRA_L3MDEV
]))
256 fprintf(fp
, "lookup [l3mdev-table] ");
259 table
= rtm_get_table(r
, tb
);
261 fprintf(fp
, "lookup %s ",
262 rtnl_rttable_n2a(table
, b1
, sizeof(b1
)));
264 if (tb
[FRA_SUPPRESS_PREFIXLEN
]) {
265 int pl
= rta_getattr_u32(tb
[FRA_SUPPRESS_PREFIXLEN
]);
268 fprintf(fp
, "suppress_prefixlength %d ", pl
);
270 if (tb
[FRA_SUPPRESS_IFGROUP
]) {
271 int group
= rta_getattr_u32(tb
[FRA_SUPPRESS_IFGROUP
]);
275 fprintf(fp
, "suppress_ifgroup %s ",
276 rtnl_group_n2a(group
, b1
, sizeof(b1
)));
282 __u32 to
= rta_getattr_u32(tb
[FRA_FLOW
]);
287 fprintf(fp
, "realms %s/",
288 rtnl_rtrealm_n2a(from
, b1
, sizeof(b1
)));
291 rtnl_rtrealm_n2a(to
, b1
, sizeof(b1
)));
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
,
300 fprintf(fp
, "masquerade");
301 } else if (r
->rtm_type
== FR_ACT_GOTO
) {
302 fprintf(fp
, "goto ");
304 fprintf(fp
, "%u", rta_getattr_u32(tb
[FRA_GOTO
]));
307 if (r
->rtm_flags
& FIB_RULE_UNRESOLVED
)
308 fprintf(fp
, " [unresolved]");
309 } else if (r
->rtm_type
== FR_ACT_NOP
)
311 else if (r
->rtm_type
!= RTN_UNICAST
)
313 rtnl_rtntype_n2a(r
->rtm_type
,
321 static __u32 rule_dump_magic
= 0x71706986;
323 static int save_rule_prep(void)
327 if (isatty(STDOUT_FILENO
)) {
328 fprintf(stderr
, "Not sending a binary stream to stdout\n");
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");
341 static int save_rule(const struct sockaddr_nl
*who
,
342 struct nlmsghdr
*n
, void *arg
)
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");
352 return ret
== n
->nlmsg_len
? 0 : ret
;
355 static int flush_rule(const struct sockaddr_nl
*who
, struct nlmsghdr
*n
,
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];
363 len
-= NLMSG_LENGTH(sizeof(*r
));
367 parse_rtattr(tb
, FRA_MAX
, RTM_RTA(r
), len
);
369 if (tb
[FRA_PRIORITY
]) {
370 n
->nlmsg_type
= RTM_DELRULE
;
371 n
->nlmsg_flags
= NLM_F_REQUEST
;
373 if (rtnl_open(&rth2
, 0) < 0)
376 if (rtnl_talk(&rth2
, n
, NULL
, 0) < 0)
385 static int iprule_list_flush_or_save(int argc
, char **argv
, int action
)
387 rtnl_filter_t filter_fn
;
388 int af
= preferred_family
;
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");
401 if (save_rule_prep())
403 filter_fn
= save_rule
;
406 filter_fn
= flush_rule
;
409 filter_fn
= print_rule
;
412 memset(&filter
, 0, sizeof(filter
));
415 if (matches(*argv
, "preference") == 0 ||
416 matches(*argv
, "order") == 0 ||
417 matches(*argv
, "priority") == 0) {
420 if (get_u32(&pref
, *argv
, 0))
421 invarg("preference value is invalid\n", *argv
);
424 } else if (strcmp(*argv
, "not") == 0) {
426 } else if (strcmp(*argv
, "tos") == 0) {
429 if (rtnl_dsfield_a2n(&tos
, *argv
))
430 invarg("TOS value is invalid\n", *argv
);
433 } else if (strcmp(*argv
, "fwmark") == 0) {
435 __u32 fwmark
, fwmask
;
437 slash
= strchr(*argv
, '/');
440 if (get_u32(&fwmark
, *argv
, 0))
441 invarg("fwmark value is invalid\n", *argv
);
442 filter
.fwmark
= fwmark
;
444 if (get_u32(&fwmask
, slash
+1, 0))
445 invarg("fwmask value is invalid\n",
447 filter
.fwmask
= fwmask
;
449 } else if (strcmp(*argv
, "dev") == 0 ||
450 strcmp(*argv
, "iif") == 0) {
452 strncpy(filter
.iif
, *argv
, IFNAMSIZ
);
454 } else if (strcmp(*argv
, "oif") == 0) {
456 strncpy(filter
.oif
, *argv
, IFNAMSIZ
);
458 } else if (strcmp(*argv
, "l3mdev") == 0) {
460 } else if (matches(*argv
, "lookup") == 0 ||
461 matches(*argv
, "table") == 0 ) {
464 if (rtnl_rttable_a2n(&tid
, *argv
))
465 invarg("table id value is invalid\n", *argv
);
467 } else if (matches(*argv
, "from") == 0 ||
468 matches(*argv
, "src") == 0) {
470 get_prefix(&filter
.src
, *argv
, af
);
472 if (matches(*argv
, "dst") == 0 ||
473 matches(*argv
, "to") == 0) {
476 get_prefix(&filter
.dst
, *argv
, af
);
481 if (rtnl_wilddump_request(&rth
, af
, RTM_GETRULE
) < 0) {
482 perror("Cannot send dump request");
486 if (rtnl_dump_filter(&rth
, filter_fn
, stdout
) < 0) {
487 fprintf(stderr
, "Dump terminated\n");
494 static int rule_dump_check_magic(void)
499 if (isatty(STDIN_FILENO
)) {
500 fprintf(stderr
, "Can't restore rule dump from a terminal\n");
504 ret
= fread(&magic
, sizeof(magic
), 1, stdin
);
505 if (magic
!= rule_dump_magic
) {
506 fprintf(stderr
, "Magic mismatch (%d elems, %x magic)\n",
514 static int restore_handler(const struct sockaddr_nl
*nl
,
515 struct rtnl_ctrl_data
*ctrl
,
516 struct nlmsghdr
*n
, void *arg
)
520 n
->nlmsg_flags
|= NLM_F_REQUEST
| NLM_F_CREATE
| NLM_F_ACK
;
524 ret
= rtnl_talk(&rth
, n
, n
, sizeof(*n
));
525 if ((ret
< 0) && (errno
== EEXIST
))
532 static int iprule_restore(void)
534 if (rule_dump_check_magic())
537 exit(rtnl_from_file(stdin
, &restore_handler
, NULL
));
540 static int iprule_modify(int cmd
, int argc
, char **argv
)
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
,
559 if (cmd
== RTM_NEWRULE
) {
560 req
.n
.nlmsg_flags
|= NLM_F_CREATE
|NLM_F_EXCL
;
561 req
.r
.rtm_type
= RTN_UNICAST
;
564 if (cmd
== RTM_DELRULE
&& argc
== 0) {
565 fprintf(stderr
, "\"ip rule del\" requires arguments.\n");
570 if (strcmp(*argv
, "not") == 0) {
571 req
.r
.rtm_flags
|= FIB_RULE_INVERT
;
572 } else if (strcmp(*argv
, "from") == 0) {
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) {
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) {
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) {
602 if (rtnl_dsfield_a2n(&tos
, *argv
))
603 invarg("TOS value is invalid\n", *argv
);
605 } else if (strcmp(*argv
, "fwmark") == 0) {
607 __u32 fwmark
, fwmask
;
611 slash
= strchr(*argv
, '/');
614 if (get_u32(&fwmark
, *argv
, 0))
615 invarg("fwmark value is invalid\n", *argv
);
616 addattr32(&req
.n
, sizeof(req
), FRA_FWMARK
, fwmark
);
618 if (get_u32(&fwmask
, slash
+1, 0))
619 invarg("fwmask value is invalid\n",
621 addattr32(&req
.n
, sizeof(req
),
624 } else if (matches(*argv
, "realms") == 0) {
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) {
634 if (rtnl_rttable_a2n(&tid
, *argv
))
635 invarg("invalid table ID\n", *argv
);
637 req
.r
.rtm_table
= tid
;
639 req
.r
.rtm_table
= RT_TABLE_UNSPEC
;
640 addattr32(&req
.n
, sizeof(req
), FRA_TABLE
, tid
);
643 } else if (matches(*argv
, "suppress_prefixlength") == 0 ||
644 strcmp(*argv
, "sup_pl") == 0) {
648 if (get_s32(&pl
, *argv
, 0) || pl
< 0)
649 invarg("suppress_prefixlength value is invalid\n",
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) {
658 if (rtnl_group_a2n(&group
, *argv
))
659 invarg("Invalid \"suppress_ifgroup\" value\n",
661 addattr32(&req
.n
, sizeof(req
),
662 FRA_SUPPRESS_IFGROUP
, group
);
663 } else if (strcmp(*argv
, "dev") == 0 ||
664 strcmp(*argv
, "iif") == 0) {
666 addattr_l(&req
.n
, sizeof(req
), FRA_IFNAME
,
667 *argv
, strlen(*argv
)+1);
668 } else if (strcmp(*argv
, "oif") == 0) {
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);
676 } else if (strcmp(*argv
, "nat") == 0 ||
677 matches(*argv
, "map-to") == 0) {
679 fprintf(stderr
, "Warning: route NAT is deprecated\n");
680 addattr32(&req
.n
, sizeof(req
), RTA_GATEWAY
,
682 req
.r
.rtm_type
= RTN_NAT
;
686 if (strcmp(*argv
, "type") == 0)
689 if (matches(*argv
, "help") == 0)
691 else if (matches(*argv
, "goto") == 0) {
696 if (get_u32(&target
, *argv
, 0))
697 invarg("invalid target\n", *argv
);
698 addattr32(&req
.n
, sizeof(req
),
700 } else if (matches(*argv
, "nop") == 0)
702 else if (rtnl_rtntype_a2n(&type
, *argv
))
703 invarg("Failed to parse rule type", *argv
);
704 req
.r
.rtm_type
= type
;
711 if (l3mdev_rule
&& tid
!= 0) {
713 "table can not be specified for l3mdev rules\n");
717 if (req
.r
.rtm_family
== AF_UNSPEC
)
718 req
.r
.rtm_family
= AF_INET
;
720 if (!table_ok
&& cmd
== RTM_NEWRULE
)
721 req
.r
.rtm_table
= RT_TABLE_MAIN
;
723 if (rtnl_talk(&rth
, &req
.n
, NULL
, 0) < 0)
729 int do_iprule(int argc
, char **argv
)
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)
751 "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv
);
755 int do_multirule(int argc
, char **argv
)
757 switch (preferred_family
) {
760 preferred_family
= RTNL_FAMILY_IPMR
;
763 preferred_family
= RTNL_FAMILY_IP6MR
;
765 case RTNL_FAMILY_IPMR
:
766 case RTNL_FAMILY_IP6MR
:
770 "Multicast rules are only supported for IPv4/IPv6, was: %i\n",
775 return do_iprule(argc
, argv
);