aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/applets.h1
-rw-r--r--include/usage.h17
-rw-r--r--networking/Config.in12
-rw-r--r--networking/Kbuild1
-rw-r--r--networking/ip.c20
-rw-r--r--networking/iprule.c25
-rw-r--r--networking/libiproute/Kbuild8
-rw-r--r--networking/libiproute/ipaddress.c2
-rw-r--r--networking/libiproute/iprule.c331
-rw-r--r--networking/libiproute/libnetlink.c8
-rw-r--r--networking/libiproute/libnetlink.h14
-rw-r--r--networking/libiproute/rt_names.c81
-rw-r--r--networking/libiproute/rt_names.h3
-rw-r--r--scripts/defconfig2
14 files changed, 497 insertions, 28 deletions
diff --git a/include/applets.h b/include/applets.h
index 1d6cc932e..80ee222d8 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -164,6 +164,7 @@ USE_IPCRM(APPLET(ipcrm, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
164USE_IPCS(APPLET(ipcs, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS)) 164USE_IPCS(APPLET(ipcs, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
165USE_IPLINK(APPLET(iplink, _BB_DIR_BIN, _BB_SUID_NEVER)) 165USE_IPLINK(APPLET(iplink, _BB_DIR_BIN, _BB_SUID_NEVER))
166USE_IPROUTE(APPLET(iproute, _BB_DIR_BIN, _BB_SUID_NEVER)) 166USE_IPROUTE(APPLET(iproute, _BB_DIR_BIN, _BB_SUID_NEVER))
167USE_IPRULE(APPLET(iprule, _BB_DIR_BIN, _BB_SUID_NEVER))
167USE_IPTUNNEL(APPLET(iptunnel, _BB_DIR_BIN, _BB_SUID_NEVER)) 168USE_IPTUNNEL(APPLET(iptunnel, _BB_DIR_BIN, _BB_SUID_NEVER))
168USE_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_NEVER)) 169USE_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_NEVER))
169USE_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_NEVER, killall)) 170USE_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_NEVER, killall))
diff --git a/include/usage.h b/include/usage.h
index 7898473a6..2a6e335ba 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -1453,10 +1453,10 @@ USE_FEATURE_DATE_ISOFMT( \
1453 "\t-s\tstrip symbol tables" 1453 "\t-s\tstrip symbol tables"
1454 1454
1455#define ip_trivial_usage \ 1455#define ip_trivial_usage \
1456 "[ OPTIONS ] { address | link | route | tunnel } { COMMAND | help }" 1456 "[OPTIONS] {address | link | route | tunnel | rule} {COMMAND}"
1457#define ip_full_usage \ 1457#define ip_full_usage \
1458 "ip [ OPTIONS ] OBJECT { COMMAND | help }\n" \ 1458 "ip [OPTIONS] OBJECT {COMMAND}\n" \
1459 "where OBJECT := { link | addr | route | tunnel }\n" \ 1459 "where OBJECT := {link | addr | route | tunnel |rule}\n" \
1460 "OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }" 1460 "OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }"
1461 1461
1462#define ipaddr_trivial_usage \ 1462#define ipaddr_trivial_usage \
@@ -1529,6 +1529,17 @@ USE_FEATURE_DATE_ISOFMT( \
1529 "\t\t\tSELECTOR := [ root PREFIX ] [ match PREFIX ] [ proto RTPROTO ]\n" \ 1529 "\t\t\tSELECTOR := [ root PREFIX ] [ match PREFIX ] [ proto RTPROTO ]\n" \
1530 "\t\t\tROUTE := [ TYPE ] PREFIX [ tos TOS ] [ proto RTPROTO ]" 1530 "\t\t\tROUTE := [ TYPE ] PREFIX [ tos TOS ] [ proto RTPROTO ]"
1531 1531
1532#define iprule_trivial_usage \
1533 "{[ list | add | del ] RULE}"
1534#define iprule_full_usage \
1535 "iprule [ list | add | del ] SELECTOR ACTION\n" \
1536 "\tSELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK ]\n" \
1537 "\t\t\t[ dev STRING ] [ pref NUMBER ]\n" \
1538 "\tACTION := [ table TABLE_ID ] [ nat ADDRESS ]\n" \
1539 "\t\t\t[ prohibit | reject | unreachable ]\n" \
1540 "\t\t\t[ realms [SRCREALM/]DSTREALM ]\n" \
1541 "\tTABLE_ID := [ local | main | default | NUMBER ]"
1542
1532#define iptunnel_trivial_usage \ 1543#define iptunnel_trivial_usage \
1533 "{ add | change | del | show } [ NAME ]\n" \ 1544 "{ add | change | del | show } [ NAME ]\n" \
1534 "\t\t[ mode { ipip | gre | sit } ]\n" \ 1545 "\t\t[ mode { ipip | gre | sit } ]\n" \
diff --git a/networking/Config.in b/networking/Config.in
index 34847a14b..ba41ab119 100644
--- a/networking/Config.in
+++ b/networking/Config.in
@@ -364,6 +364,13 @@ config FEATURE_IP_TUNNEL
364 help 364 help
365 Add support for tunneling commands to "ip". 365 Add support for tunneling commands to "ip".
366 366
367config FEATURE_IP_RULE
368 bool "ip rule"
369 default n
370 depends on IP
371 help
372 Add support for rule commands to "ip".
373
367config FEATURE_IP_SHORT_FORMS 374config FEATURE_IP_SHORT_FORMS
368 bool "Support short forms of ip commands." 375 bool "Support short forms of ip commands."
369 default n 376 default n
@@ -398,6 +405,11 @@ config IPTUNNEL
398 default y 405 default y
399 depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_TUNNEL 406 depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_TUNNEL
400 407
408config IPRULE
409 bool
410 default y
411 depends on FEATURE_IP_SHORT_FORMS && FEATURE_IP_RULE
412
401config IPCALC 413config IPCALC
402 bool "ipcalc" 414 bool "ipcalc"
403 default n 415 default n
diff --git a/networking/Kbuild b/networking/Kbuild
index 066475925..a9a51fc2e 100644
--- a/networking/Kbuild
+++ b/networking/Kbuild
@@ -21,6 +21,7 @@ lib-$(CONFIG_IPCALC) += ipcalc.o
21lib-$(CONFIG_IPADDR) += ipaddr.o 21lib-$(CONFIG_IPADDR) += ipaddr.o
22lib-$(CONFIG_IPLINK) += iplink.o 22lib-$(CONFIG_IPLINK) += iplink.o
23lib-$(CONFIG_IPROUTE) += iproute.o 23lib-$(CONFIG_IPROUTE) += iproute.o
24lib-$(CONFIG_IPRULE) += iprule.o
24lib-$(CONFIG_IPTUNNEL) += iptunnel.o 25lib-$(CONFIG_IPTUNNEL) += iptunnel.o
25lib-$(CONFIG_NAMEIF) += nameif.o 26lib-$(CONFIG_NAMEIF) += nameif.o
26lib-$(CONFIG_NC) += nc.o 27lib-$(CONFIG_NC) += nc.o
diff --git a/networking/ip.c b/networking/ip.c
index 636315597..4c8b89e2f 100644
--- a/networking/ip.c
+++ b/networking/ip.c
@@ -24,26 +24,22 @@ int ip_main(int argc, char **argv)
24 ip_parse_common_args(&argc, &argv); 24 ip_parse_common_args(&argc, &argv);
25 25
26 if (argc > 1) { 26 if (argc > 1) {
27#ifdef CONFIG_FEATURE_IP_ADDRESS 27 if (ENABLE_FEATURE_IP_ADDRESS && matches(argv[1], "address") == 0) {
28 if (matches(argv[1], "address") == 0) {
29 ret = do_ipaddr(argc-2, argv+2); 28 ret = do_ipaddr(argc-2, argv+2);
30 } 29 }
31#endif 30 if (ENABLE_FEATURE_IP_ROUTE && matches(argv[1], "route") == 0) {
32#ifdef CONFIG_FEATURE_IP_ROUTE
33 if (matches(argv[1], "route") == 0) {
34 ret = do_iproute(argc-2, argv+2); 31 ret = do_iproute(argc-2, argv+2);
35 } 32 }
36#endif 33 if (ENABLE_FEATURE_IP_LINK && matches(argv[1], "link") == 0) {
37#ifdef CONFIG_FEATURE_IP_LINK
38 if (matches(argv[1], "link") == 0) {
39 ret = do_iplink(argc-2, argv+2); 34 ret = do_iplink(argc-2, argv+2);
40 } 35 }
41#endif 36 if (ENABLE_FEATURE_IP_TUNNEL &&
42#ifdef CONFIG_FEATURE_IP_TUNNEL 37 (matches(argv[1], "tunnel") == 0 || strcmp(argv[1], "tunl") == 0)) {
43 if (matches(argv[1], "tunnel") == 0 || strcmp(argv[1], "tunl") == 0) {
44 ret = do_iptunnel(argc-2, argv+2); 38 ret = do_iptunnel(argc-2, argv+2);
45 } 39 }
46#endif 40 if (ENABLE_FEATURE_IP_RULE && matches(argv[1], "rule") == 0) {
41 ret = do_iprule(argc-2, argv+2);
42 }
47 } 43 }
48 if (ret) { 44 if (ret) {
49 bb_show_usage(); 45 bb_show_usage();
diff --git a/networking/iprule.c b/networking/iprule.c
new file mode 100644
index 000000000..43eaea633
--- /dev/null
+++ b/networking/iprule.c
@@ -0,0 +1,25 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ip.c "ip" utility frontend.
4 *
5 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
6 *
7 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
8 *
9 *
10 * Changes:
11 *
12 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
13 */
14
15#include "libiproute/utils.h"
16#include "libiproute/ip_common.h"
17
18#include "busybox.h"
19
20int iprule_main(int argc, char **argv)
21{
22 ip_parse_common_args(&argc, &argv);
23
24 return do_iprule(argc-1, argv+1);
25}
diff --git a/networking/libiproute/Kbuild b/networking/libiproute/Kbuild
index 476374e19..8383630f2 100644
--- a/networking/libiproute/Kbuild
+++ b/networking/libiproute/Kbuild
@@ -12,6 +12,7 @@ lib-$(CONFIG_IP) += \
12 iplink.o \ 12 iplink.o \
13 iproute.o \ 13 iproute.o \
14 iptunnel.o \ 14 iptunnel.o \
15 iprule.o \
15 libnetlink.o \ 16 libnetlink.o \
16 ll_addr.o \ 17 ll_addr.o \
17 ll_map.o \ 18 ll_map.o \
@@ -56,3 +57,10 @@ lib-$(CONFIG_IPTUNNEL) += \
56 iptunnel.o \ 57 iptunnel.o \
57 rt_names.o \ 58 rt_names.o \
58 utils.o 59 utils.o
60
61lib-$(CONFIG_IPRULE) += \
62 ip_parse_common_args.o \
63 iprule.o \
64 rt_names.o \
65 utils.o
66
diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c
index fc6cf7beb..42cf629c6 100644
--- a/networking/libiproute/ipaddress.c
+++ b/networking/libiproute/ipaddress.c
@@ -99,7 +99,7 @@ static void print_queuelen(char *name)
99} 99}
100 100
101static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who, 101static int print_linkinfo(struct sockaddr_nl ATTRIBUTE_UNUSED *who,
102 struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg) 102 const struct nlmsghdr *n, void ATTRIBUTE_UNUSED *arg)
103{ 103{
104 FILE *fp = (FILE*)arg; 104 FILE *fp = (FILE*)arg;
105 struct ifinfomsg *ifi = NLMSG_DATA(n); 105 struct ifinfomsg *ifi = NLMSG_DATA(n);
diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c
new file mode 100644
index 000000000..19338770f
--- /dev/null
+++ b/networking/libiproute/iprule.c
@@ -0,0 +1,331 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * iprule.c "ip rule".
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version
8 * 2 of the License, or (at your option) any later version.
9 *
10 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
11 *
12 *
13 * Changes:
14 *
15 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
16 */
17
18#include "libbb.h"
19#include <syslog.h>
20#include <sys/socket.h>
21#include <netinet/in.h>
22#include <netinet/ip.h>
23#include <arpa/inet.h>
24
25#include "rt_names.h"
26#include "utils.h"
27/*
28static void usage(void) __attribute__((noreturn));
29
30static void usage(void)
31{
32 fprintf(stderr, "Usage: ip rule [ list | add | del ] SELECTOR ACTION\n");
33 fprintf(stderr, "SELECTOR := [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK ]\n");
34 fprintf(stderr, " [ dev STRING ] [ pref NUMBER ]\n");
35 fprintf(stderr, "ACTION := [ table TABLE_ID ] [ nat ADDRESS ]\n");
36 fprintf(stderr, " [ prohibit | reject | unreachable ]\n");
37 fprintf(stderr, " [ realms [SRCREALM/]DSTREALM ]\n");
38 fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n");
39 exit(-1);
40}
41*/
42static int print_rule(struct sockaddr_nl *who ATTRIBUTE_UNUSED,
43 struct nlmsghdr *n, void *arg)
44{
45 FILE *fp = (FILE*)arg;
46 struct rtmsg *r = NLMSG_DATA(n);
47 int len = n->nlmsg_len;
48 int host_len = -1;
49 struct rtattr * tb[RTA_MAX+1];
50 char abuf[256];
51 SPRINT_BUF(b1);
52
53 if (n->nlmsg_type != RTM_NEWRULE)
54 return 0;
55
56 len -= NLMSG_LENGTH(sizeof(*r));
57 if (len < 0)
58 return -1;
59
60 memset(tb, 0, sizeof(tb));
61 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
62
63 if (r->rtm_family == AF_INET)
64 host_len = 32;
65 else if (r->rtm_family == AF_INET6)
66 host_len = 128;
67/* else if (r->rtm_family == AF_DECnet)
68 host_len = 16;
69 else if (r->rtm_family == AF_IPX)
70 host_len = 80;
71*/
72 if (tb[RTA_PRIORITY])
73 fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[RTA_PRIORITY]));
74 else
75 fprintf(fp, "0:\t");
76
77 fprintf(fp, "from ");
78 if (tb[RTA_SRC]) {
79 if (r->rtm_src_len != host_len) {
80 fprintf(fp, "%s/%u", rt_addr_n2a(r->rtm_family,
81 RTA_PAYLOAD(tb[RTA_SRC]),
82 RTA_DATA(tb[RTA_SRC]),
83 abuf, sizeof(abuf)),
84 r->rtm_src_len
85 );
86 } else {
87 fprintf(fp, "%s", format_host(r->rtm_family,
88 RTA_PAYLOAD(tb[RTA_SRC]),
89 RTA_DATA(tb[RTA_SRC]),
90 abuf, sizeof(abuf))
91 );
92 }
93 } else if (r->rtm_src_len) {
94 fprintf(fp, "0/%d", r->rtm_src_len);
95 } else {
96 fprintf(fp, "all");
97 }
98 fprintf(fp, " ");
99
100 if (tb[RTA_DST]) {
101 if (r->rtm_dst_len != host_len) {
102 fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family,
103 RTA_PAYLOAD(tb[RTA_DST]),
104 RTA_DATA(tb[RTA_DST]),
105 abuf, sizeof(abuf)),
106 r->rtm_dst_len
107 );
108 } else {
109 fprintf(fp, "to %s ", format_host(r->rtm_family,
110 RTA_PAYLOAD(tb[RTA_DST]),
111 RTA_DATA(tb[RTA_DST]),
112 abuf, sizeof(abuf)));
113 }
114 } else if (r->rtm_dst_len) {
115 fprintf(fp, "to 0/%d ", r->rtm_dst_len);
116 }
117
118 if (r->rtm_tos) {
119 fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1)));
120 }
121 if (tb[RTA_PROTOINFO]) {
122 fprintf(fp, "fwmark %#x ", *(__u32*)RTA_DATA(tb[RTA_PROTOINFO]));
123 }
124
125 if (tb[RTA_IIF]) {
126 fprintf(fp, "iif %s ", (char*)RTA_DATA(tb[RTA_IIF]));
127 }
128
129 if (r->rtm_table)
130 fprintf(fp, "lookup %s ", rtnl_rttable_n2a(r->rtm_table, b1, sizeof(b1)));
131
132 if (tb[RTA_FLOW]) {
133 __u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]);
134 __u32 from = to>>16;
135 to &= 0xFFFF;
136 if (from) {
137 fprintf(fp, "realms %s/",
138 rtnl_rtrealm_n2a(from, b1, sizeof(b1)));
139 }
140 fprintf(fp, "%s ",
141 rtnl_rtrealm_n2a(to, b1, sizeof(b1)));
142 }
143
144 if (r->rtm_type == RTN_NAT) {
145 if (tb[RTA_GATEWAY]) {
146 fprintf(fp, "map-to %s ",
147 format_host(r->rtm_family,
148 RTA_PAYLOAD(tb[RTA_GATEWAY]),
149 RTA_DATA(tb[RTA_GATEWAY]),
150 abuf, sizeof(abuf)));
151 } else
152 fprintf(fp, "masquerade");
153 } else if (r->rtm_type != RTN_UNICAST)
154 fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
155
156 fprintf(fp, "\n");
157 fflush(fp);
158 return 0;
159}
160
161int iprule_list(int argc, char **argv)
162{
163 struct rtnl_handle rth;
164 int af = preferred_family;
165
166 if (af == AF_UNSPEC)
167 af = AF_INET;
168
169 if (argc > 0) {
170 bb_error_msg("\"rule show\" needs no arguments");
171 return -1;
172 }
173
174 if (rtnl_open(&rth, 0) < 0)
175 return 1;
176
177 if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) {
178 bb_perror_msg("Cannot send dump request");
179 return 1;
180 }
181
182 if (rtnl_dump_filter(&rth, print_rule, stdout, NULL, NULL) < 0) {
183 bb_error_msg("Dump terminated");
184 return 1;
185 }
186
187 return 0;
188}
189
190
191int iprule_modify(int cmd, int argc, char **argv)
192{
193 int table_ok = 0;
194 struct rtnl_handle rth;
195 struct {
196 struct nlmsghdr n;
197 struct rtmsg r;
198 char buf[1024];
199 } req;
200
201 memset(&req, 0, sizeof(req));
202
203 req.n.nlmsg_type = cmd;
204 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
205 req.n.nlmsg_flags = NLM_F_REQUEST;
206 req.r.rtm_family = preferred_family;
207 req.r.rtm_protocol = RTPROT_BOOT;
208 req.r.rtm_scope = RT_SCOPE_UNIVERSE;
209 req.r.rtm_table = 0;
210 req.r.rtm_type = RTN_UNSPEC;
211
212 if (cmd == RTM_NEWRULE) {
213 req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL;
214 req.r.rtm_type = RTN_UNICAST;
215 }
216
217 while (argc > 0) {
218 if (strcmp(*argv, "from") == 0) {
219 inet_prefix dst;
220 NEXT_ARG();
221 get_prefix(&dst, *argv, req.r.rtm_family);
222 req.r.rtm_src_len = dst.bitlen;
223 addattr_l(&req.n, sizeof(req), RTA_SRC, &dst.data, dst.bytelen);
224 } else if (strcmp(*argv, "to") == 0) {
225 inet_prefix dst;
226 NEXT_ARG();
227 get_prefix(&dst, *argv, req.r.rtm_family);
228 req.r.rtm_dst_len = dst.bitlen;
229 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
230 } else if (matches(*argv, "preference") == 0 ||
231 matches(*argv, "order") == 0 ||
232 matches(*argv, "priority") == 0) {
233 __u32 pref;
234 NEXT_ARG();
235 if (get_u32(&pref, *argv, 0))
236 invarg("preference value", *argv);
237 addattr32(&req.n, sizeof(req), RTA_PRIORITY, pref);
238 } else if (strcmp(*argv, "tos") == 0) {
239 __u32 tos;
240 NEXT_ARG();
241 if (rtnl_dsfield_a2n(&tos, *argv))
242 invarg("TOS value", *argv);
243 req.r.rtm_tos = tos;
244 } else if (strcmp(*argv, "fwmark") == 0) {
245 __u32 fwmark;
246 NEXT_ARG();
247 if (get_u32(&fwmark, *argv, 0))
248 invarg("fwmark value", *argv);
249 addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark);
250 } else if (matches(*argv, "realms") == 0) {
251 __u32 realm;
252 NEXT_ARG();
253 if (get_rt_realms(&realm, *argv))
254 invarg("realms", *argv);
255 addattr32(&req.n, sizeof(req), RTA_FLOW, realm);
256 } else if (matches(*argv, "table") == 0 ||
257 strcmp(*argv, "lookup") == 0) {
258 int tid;
259 NEXT_ARG();
260 if (rtnl_rttable_a2n(&tid, *argv))
261 invarg("table ID", *argv);
262 req.r.rtm_table = tid;
263 table_ok = 1;
264 } else if (strcmp(*argv, "dev") == 0 ||
265 strcmp(*argv, "iif") == 0) {
266 NEXT_ARG();
267 addattr_l(&req.n, sizeof(req), RTA_IIF, *argv, strlen(*argv)+1);
268 } else if (strcmp(*argv, "nat") == 0 ||
269 matches(*argv, "map-to") == 0) {
270 NEXT_ARG();
271 addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv));
272 req.r.rtm_type = RTN_NAT;
273 } else {
274 int type;
275
276 if (strcmp(*argv, "type") == 0) {
277 NEXT_ARG();
278 }
279 if (matches(*argv, "help") == 0)
280 bb_show_usage();
281 if (rtnl_rtntype_a2n(&type, *argv))
282 invarg("Failed to parse rule type", *argv);
283 req.r.rtm_type = type;
284 }
285 argc--;
286 argv++;
287 }
288
289 if (req.r.rtm_family == AF_UNSPEC)
290 req.r.rtm_family = AF_INET;
291
292 if (!table_ok && cmd == RTM_NEWRULE)
293 req.r.rtm_table = RT_TABLE_MAIN;
294
295 if (rtnl_open(&rth, 0) < 0)
296 return 1;
297
298 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0)
299 return 2;
300
301 return 0;
302}
303
304int do_iprule(int argc, char **argv)
305{
306 static const char * const ip_rule_commands[] =
307 {"add", "delete", "list", "show", 0};
308 int command_num = 2;
309 int cmd;
310
311 if (argc < 1)
312 return iprule_list(0, NULL);
313 if (*argv)
314 command_num = index_in_substr_array(ip_rule_commands, *argv);
315 switch (command_num) {
316 case 0: /* add */
317 cmd = RTM_NEWRULE;
318 break;
319 case 1: /* delete */
320 cmd = RTM_DELRULE;
321 break;
322 case 2: /* list */
323 case 3: /* show */
324 return iprule_list(argc-1, argv+1);
325 break;
326 default:
327 bb_error_msg_and_die("unknown command %s", *argv);
328 }
329 return iprule_modify(cmd, argc-1, argv+1);
330}
331
diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c
index ec52cff73..c7e17e1dd 100644
--- a/networking/libiproute/libnetlink.c
+++ b/networking/libiproute/libnetlink.c
@@ -121,10 +121,10 @@ int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len)
121} 121}
122 122
123int rtnl_dump_filter(struct rtnl_handle *rth, 123int rtnl_dump_filter(struct rtnl_handle *rth,
124 int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), 124 int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
125 void *arg1, 125 void *arg1,
126 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), 126 int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
127 void *arg2) 127 void *arg2)
128{ 128{
129 char buf[8192]; 129 char buf[8192];
130 struct sockaddr_nl nladdr; 130 struct sockaddr_nl nladdr;
diff --git a/networking/libiproute/libnetlink.h b/networking/libiproute/libnetlink.h
index c2ef984c4..7cfcd2042 100644
--- a/networking/libiproute/libnetlink.h
+++ b/networking/libiproute/libnetlink.h
@@ -20,14 +20,14 @@ extern void rtnl_close(struct rtnl_handle *rth);
20extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type); 20extern int rtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type);
21extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len); 21extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len);
22extern int rtnl_dump_filter(struct rtnl_handle *rth, 22extern int rtnl_dump_filter(struct rtnl_handle *rth,
23 int (*filter)(struct sockaddr_nl *, struct nlmsghdr *n, void *), 23 int (*filter)(struct sockaddr_nl*, struct nlmsghdr *n, void*),
24 void *arg1, 24 void *arg1,
25 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), 25 int (*junk)(struct sockaddr_nl *, struct nlmsghdr *n, void *),
26 void *arg2); 26 void *arg2);
27extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer, 27extern int rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, pid_t peer,
28 unsigned groups, struct nlmsghdr *answer, 28 unsigned groups, struct nlmsghdr *answer,
29 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *), 29 int (*junk)(struct sockaddr_nl *,struct nlmsghdr *n, void *),
30 void *jarg); 30 void *jarg);
31extern int rtnl_send(struct rtnl_handle *rth, char *buf, int); 31extern int rtnl_send(struct rtnl_handle *rth, char *buf, int);
32 32
33 33
diff --git a/networking/libiproute/rt_names.c b/networking/libiproute/rt_names.c
index c0f790754..ed21fbe26 100644
--- a/networking/libiproute/rt_names.c
+++ b/networking/libiproute/rt_names.c
@@ -240,7 +240,23 @@ int rtnl_rtrealm_a2n(uint32_t *id, char *arg)
240 return 0; 240 return 0;
241} 241}
242 242
243 243#if ENABLE_FEATURE_IP_RULE
244const char * rtnl_rtrealm_n2a(int id, char *buf, int len)
245{
246 if (id<0 || id>=256) {
247 snprintf(buf, len, "%d", id);
248 return buf;
249 }
250 if (!rtnl_rtrealm_tab[id]) {
251 if (!rtnl_rtrealm_init)
252 rtnl_rtrealm_initialize();
253 }
254 if (rtnl_rtrealm_tab[id])
255 return rtnl_rtrealm_tab[id];
256 snprintf(buf, len, "%d", id);
257 return buf;
258}
259#endif
244 260
245static const char * rtnl_rtdsfield_tab[256] = { 261static const char * rtnl_rtdsfield_tab[256] = {
246 "0", 262 "0",
@@ -303,3 +319,66 @@ int rtnl_dsfield_a2n(uint32_t *id, char *arg)
303 *id = res; 319 *id = res;
304 return 0; 320 return 0;
305} 321}
322
323#if ENABLE_FEATURE_IP_RULE
324static int rtnl_rttable_init;
325static const char * rtnl_rttable_tab[256] = {
326 "unspec",
327};
328static void rtnl_rttable_initialize(void)
329{
330 rtnl_rttable_init = 1;
331 rtnl_rttable_tab[255] = "local";
332 rtnl_rttable_tab[254] = "main";
333 rtnl_rttable_tab[253] = "default";
334 rtnl_tab_initialize("/etc/iproute2/rt_tables", rtnl_rttable_tab, 256);
335}
336
337const char *rtnl_rttable_n2a(int id, char *buf, int len)
338{
339 if (id < 0 || id >= 256) {
340 snprintf(buf, len, "%d", id);
341 return buf;
342 }
343 if (!rtnl_rttable_tab[id]) {
344 if (!rtnl_rttable_init)
345 rtnl_rttable_initialize();
346 }
347 if (rtnl_rttable_tab[id])
348 return rtnl_rttable_tab[id];
349 snprintf(buf, len, "%d", id);
350 return buf;
351}
352
353int rtnl_rttable_a2n(uint32_t * id, char *arg)
354{
355 static char *cache = NULL;
356 static unsigned long res;
357 char *end;
358 int i;
359
360 if (cache && strcmp(cache, arg) == 0) {
361 *id = res;
362 return 0;
363 }
364
365 if (!rtnl_rttable_init)
366 rtnl_rttable_initialize();
367
368 for (i = 0; i < 256; i++) {
369 if (rtnl_rttable_tab[i] && strcmp(rtnl_rttable_tab[i], arg) == 0) {
370 cache = (char*)rtnl_rttable_tab[i];
371 res = i;
372 *id = res;
373 return 0;
374 }
375 }
376
377 i = strtoul(arg, &end, 0);
378 if (!end || end == arg || *end || i > 255)
379 return -1;
380 *id = i;
381 return 0;
382}
383
384#endif
diff --git a/networking/libiproute/rt_names.h b/networking/libiproute/rt_names.h
index 41afeed63..92b807f3d 100644
--- a/networking/libiproute/rt_names.h
+++ b/networking/libiproute/rt_names.h
@@ -6,11 +6,14 @@
6 6
7extern const char* rtnl_rtprot_n2a(int id, char *buf, int len); 7extern const char* rtnl_rtprot_n2a(int id, char *buf, int len);
8extern const char* rtnl_rtscope_n2a(int id, char *buf, int len); 8extern const char* rtnl_rtscope_n2a(int id, char *buf, int len);
9extern const char* rtnl_rtrealm_n2a(int id, char *buf, int len);
9extern const char* rtnl_dsfield_n2a(int id, char *buf, int len); 10extern const char* rtnl_dsfield_n2a(int id, char *buf, int len);
11extern const char* rtnl_rttable_n2a(int id, char *buf, int len);
10extern int rtnl_rtprot_a2n(uint32_t *id, char *arg); 12extern int rtnl_rtprot_a2n(uint32_t *id, char *arg);
11extern int rtnl_rtscope_a2n(uint32_t *id, char *arg); 13extern int rtnl_rtscope_a2n(uint32_t *id, char *arg);
12extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg); 14extern int rtnl_rtrealm_a2n(uint32_t *id, char *arg);
13extern int rtnl_dsfield_a2n(uint32_t *id, char *arg); 15extern int rtnl_dsfield_a2n(uint32_t *id, char *arg);
16extern int rtnl_rttable_a2n(uint32_t *id, char *arg);
14 17
15 18
16extern const char * ll_type_n2a(int type, char *buf, int len); 19extern const char * ll_type_n2a(int type, char *buf, int len);
diff --git a/scripts/defconfig b/scripts/defconfig
index ab50409d4..11361dc42 100644
--- a/scripts/defconfig
+++ b/scripts/defconfig
@@ -535,11 +535,13 @@ CONFIG_FEATURE_IP_ADDRESS=y
535CONFIG_FEATURE_IP_LINK=y 535CONFIG_FEATURE_IP_LINK=y
536CONFIG_FEATURE_IP_ROUTE=y 536CONFIG_FEATURE_IP_ROUTE=y
537CONFIG_FEATURE_IP_TUNNEL=y 537CONFIG_FEATURE_IP_TUNNEL=y
538CONFIG_FEATURE_IP_RULE=y
538CONFIG_FEATURE_IP_SHORT_FORMS=y 539CONFIG_FEATURE_IP_SHORT_FORMS=y
539CONFIG_IPADDR=y 540CONFIG_IPADDR=y
540CONFIG_IPLINK=y 541CONFIG_IPLINK=y
541CONFIG_IPROUTE=y 542CONFIG_IPROUTE=y
542CONFIG_IPTUNNEL=y 543CONFIG_IPTUNNEL=y
544CONFIG_IPRULE=y
543CONFIG_IPCALC=y 545CONFIG_IPCALC=y
544CONFIG_FEATURE_IPCALC_FANCY=y 546CONFIG_FEATURE_IPCALC_FANCY=y
545CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y 547CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y