Magellan Linux

Annotation of /trunk/mkinitrd-magellan/busybox/networking/libiproute/iproute.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 984 - (hide annotations) (download)
Sun May 30 11:32:42 2010 UTC (14 years ago) by niro
File MIME type: text/plain
File size: 21602 byte(s)
-updated to busybox-1.16.1 and enabled blkid/uuid support in default config
1 niro 532 /* vi: set sw=4 ts=4: */
2     /*
3     * iproute.c "ip route".
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     * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
14     */
15    
16 niro 816 #include "ip_common.h" /* #include "libbb.h" is inside */
17 niro 532 #include "rt_names.h"
18     #include "utils.h"
19    
20     #ifndef RTAX_RTTVAR
21     #define RTAX_RTTVAR RTAX_HOPS
22     #endif
23    
24    
25 niro 816 typedef struct filter_t {
26 niro 532 int tb;
27 niro 816 smallint flushed;
28 niro 532 char *flushb;
29     int flushp;
30     int flushe;
31     struct rtnl_handle *rth;
32     int protocol, protocolmask;
33     int scope, scopemask;
34     int type, typemask;
35     int tos, tosmask;
36     int iif, iifmask;
37     int oif, oifmask;
38     int realm, realmmask;
39     inet_prefix rprefsrc;
40     inet_prefix rvia;
41     inet_prefix rdst;
42     inet_prefix mdst;
43     inet_prefix rsrc;
44     inet_prefix msrc;
45 niro 816 } filter_t;
46 niro 532
47 niro 816 #define filter (*(filter_t*)&bb_common_bufsiz1)
48    
49 niro 532 static int flush_update(void)
50     {
51     if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
52 niro 816 bb_perror_msg("failed to send flush request");
53 niro 532 return -1;
54     }
55     filter.flushp = 0;
56     return 0;
57     }
58    
59     static unsigned get_hz(void)
60     {
61     static unsigned hz_internal;
62     FILE *fp;
63    
64     if (hz_internal)
65     return hz_internal;
66    
67 niro 816 fp = fopen_for_read("/proc/net/psched");
68 niro 532 if (fp) {
69     unsigned nom, denom;
70    
71     if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
72     if (nom == 1000000)
73     hz_internal = denom;
74     fclose(fp);
75     }
76     if (!hz_internal)
77     hz_internal = sysconf(_SC_CLK_TCK);
78     return hz_internal;
79     }
80    
81 niro 984 static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM,
82 niro 816 struct nlmsghdr *n, void *arg UNUSED_PARAM)
83 niro 532 {
84     struct rtmsg *r = NLMSG_DATA(n);
85     int len = n->nlmsg_len;
86     struct rtattr * tb[RTA_MAX+1];
87     char abuf[256];
88     inet_prefix dst;
89     inet_prefix src;
90     int host_len = -1;
91     SPRINT_BUF(b1);
92    
93     if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
94     fprintf(stderr, "Not a route: %08x %08x %08x\n",
95     n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
96     return 0;
97     }
98     if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
99     return 0;
100     len -= NLMSG_LENGTH(sizeof(*r));
101 niro 816 if (len < 0)
102     bb_error_msg_and_die("wrong nlmsg len %d", len);
103 niro 532
104     if (r->rtm_family == AF_INET6)
105     host_len = 128;
106     else if (r->rtm_family == AF_INET)
107     host_len = 32;
108    
109     if (r->rtm_family == AF_INET6) {
110     if (filter.tb) {
111     if (filter.tb < 0) {
112 niro 816 if (!(r->rtm_flags & RTM_F_CLONED)) {
113 niro 532 return 0;
114     }
115     } else {
116 niro 816 if (r->rtm_flags & RTM_F_CLONED) {
117 niro 532 return 0;
118     }
119     if (filter.tb == RT_TABLE_LOCAL) {
120     if (r->rtm_type != RTN_LOCAL) {
121     return 0;
122     }
123     } else if (filter.tb == RT_TABLE_MAIN) {
124     if (r->rtm_type == RTN_LOCAL) {
125     return 0;
126     }
127     } else {
128     return 0;
129     }
130     }
131     }
132     } else {
133     if (filter.tb > 0 && filter.tb != r->rtm_table) {
134     return 0;
135     }
136     }
137     if (filter.rdst.family &&
138     (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) {
139     return 0;
140     }
141     if (filter.mdst.family &&
142     (r->rtm_family != filter.mdst.family ||
143     (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) {
144     return 0;
145     }
146     if (filter.rsrc.family &&
147     (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) {
148     return 0;
149     }
150     if (filter.msrc.family &&
151     (r->rtm_family != filter.msrc.family ||
152     (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) {
153     return 0;
154     }
155    
156     memset(tb, 0, sizeof(tb));
157     parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
158    
159     if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
160     return 0;
161     if (filter.mdst.family && filter.mdst.bitlen >= 0 &&
162     inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
163     return 0;
164    
165     if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen))
166     return 0;
167     if (filter.msrc.family && filter.msrc.bitlen >= 0 &&
168     inet_addr_match(&src, &filter.msrc, r->rtm_src_len))
169     return 0;
170    
171     if (filter.flushb &&
172     r->rtm_family == AF_INET6 &&
173     r->rtm_dst_len == 0 &&
174     r->rtm_type == RTN_UNREACHABLE &&
175     tb[RTA_PRIORITY] &&
176     *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1)
177     return 0;
178    
179     if (filter.flushb) {
180     struct nlmsghdr *fn;
181     if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
182     if (flush_update())
183 niro 816 bb_error_msg_and_die("flush");
184 niro 532 }
185     fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
186     memcpy(fn, n, n->nlmsg_len);
187     fn->nlmsg_type = RTM_DELROUTE;
188     fn->nlmsg_flags = NLM_F_REQUEST;
189     fn->nlmsg_seq = ++filter.rth->seq;
190     filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
191 niro 816 filter.flushed = 1;
192 niro 532 return 0;
193     }
194    
195     if (n->nlmsg_type == RTM_DELROUTE) {
196 niro 816 printf("Deleted ");
197 niro 532 }
198     if (r->rtm_type != RTN_UNICAST && !filter.type) {
199 niro 984 printf("%s ", rtnl_rtntype_n2a(r->rtm_type, b1));
200 niro 532 }
201    
202     if (tb[RTA_DST]) {
203     if (r->rtm_dst_len != host_len) {
204 niro 816 printf("%s/%u ", rt_addr_n2a(r->rtm_family,
205     RTA_DATA(tb[RTA_DST]),
206     abuf, sizeof(abuf)),
207     r->rtm_dst_len
208     );
209 niro 532 } else {
210 niro 816 printf("%s ", format_host(r->rtm_family,
211     RTA_PAYLOAD(tb[RTA_DST]),
212     RTA_DATA(tb[RTA_DST]),
213     abuf, sizeof(abuf))
214     );
215 niro 532 }
216     } else if (r->rtm_dst_len) {
217 niro 816 printf("0/%d ", r->rtm_dst_len);
218 niro 532 } else {
219 niro 816 printf("default ");
220 niro 532 }
221     if (tb[RTA_SRC]) {
222     if (r->rtm_src_len != host_len) {
223 niro 816 printf("from %s/%u ", rt_addr_n2a(r->rtm_family,
224     RTA_DATA(tb[RTA_SRC]),
225     abuf, sizeof(abuf)),
226     r->rtm_src_len
227     );
228 niro 532 } else {
229 niro 816 printf("from %s ", format_host(r->rtm_family,
230     RTA_PAYLOAD(tb[RTA_SRC]),
231     RTA_DATA(tb[RTA_SRC]),
232     abuf, sizeof(abuf))
233     );
234 niro 532 }
235     } else if (r->rtm_src_len) {
236 niro 816 printf("from 0/%u ", r->rtm_src_len);
237 niro 532 }
238     if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
239 niro 816 printf("via %s ", format_host(r->rtm_family,
240     RTA_PAYLOAD(tb[RTA_GATEWAY]),
241     RTA_DATA(tb[RTA_GATEWAY]),
242     abuf, sizeof(abuf)));
243 niro 532 }
244     if (tb[RTA_OIF] && filter.oifmask != -1) {
245 niro 816 printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
246 niro 532 }
247    
248     if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
249     /* Do not use format_host(). It is our local addr
250     and symbolic name will not be useful.
251     */
252 niro 816 printf(" src %s ", rt_addr_n2a(r->rtm_family,
253     RTA_DATA(tb[RTA_PREFSRC]),
254     abuf, sizeof(abuf)));
255 niro 532 }
256     if (tb[RTA_PRIORITY]) {
257 niro 816 printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
258 niro 532 }
259     if (r->rtm_family == AF_INET6) {
260     struct rta_cacheinfo *ci = NULL;
261     if (tb[RTA_CACHEINFO]) {
262     ci = RTA_DATA(tb[RTA_CACHEINFO]);
263     }
264     if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
265     if (r->rtm_flags & RTM_F_CLONED) {
266 niro 816 printf("%c cache ", _SL_);
267 niro 532 }
268     if (ci->rta_expires) {
269 niro 816 printf(" expires %dsec", ci->rta_expires / get_hz());
270 niro 532 }
271     if (ci->rta_error != 0) {
272 niro 816 printf(" error %d", ci->rta_error);
273 niro 532 }
274     } else if (ci) {
275     if (ci->rta_error != 0)
276 niro 816 printf(" error %d", ci->rta_error);
277 niro 532 }
278     }
279     if (tb[RTA_IIF] && filter.iifmask != -1) {
280 niro 816 printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
281 niro 532 }
282 niro 816 bb_putchar('\n');
283 niro 532 return 0;
284     }
285    
286 niro 816 /* Return value becomes exitcode. It's okay to not return at all */
287     static int iproute_modify(int cmd, unsigned flags, char **argv)
288 niro 532 {
289 niro 816 static const char keywords[] ALIGN1 =
290 niro 984 "src\0""via\0""mtu\0""lock\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
291 niro 816 "dev\0""oif\0""to\0""metric\0";
292     enum {
293     ARG_src,
294     ARG_via,
295     ARG_mtu, PARM_lock,
296     ARG_protocol,
297 niro 984 IF_FEATURE_IP_RULE(ARG_table,)
298 niro 816 ARG_dev,
299     ARG_oif,
300     ARG_to,
301     ARG_metric,
302     };
303     enum {
304     gw_ok = 1 << 0,
305     dst_ok = 1 << 1,
306     proto_ok = 1 << 2,
307     type_ok = 1 << 3
308     };
309 niro 532 struct rtnl_handle rth;
310     struct {
311     struct nlmsghdr n;
312     struct rtmsg r;
313     char buf[1024];
314     } req;
315 niro 816 char mxbuf[256];
316 niro 532 struct rtattr * mxrta = (void*)mxbuf;
317     unsigned mxlock = 0;
318 niro 816 char *d = NULL;
319     smalluint ok = 0;
320     int arg;
321 niro 532
322     memset(&req, 0, sizeof(req));
323    
324     req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
325 niro 816 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
326 niro 532 req.n.nlmsg_type = cmd;
327     req.r.rtm_family = preferred_family;
328 niro 816 if (RT_TABLE_MAIN) /* if it is zero, memset already did it */
329     req.r.rtm_table = RT_TABLE_MAIN;
330     if (RT_SCOPE_NOWHERE)
331     req.r.rtm_scope = RT_SCOPE_NOWHERE;
332 niro 532
333     if (cmd != RTM_DELROUTE) {
334     req.r.rtm_protocol = RTPROT_BOOT;
335     req.r.rtm_scope = RT_SCOPE_UNIVERSE;
336     req.r.rtm_type = RTN_UNICAST;
337     }
338    
339     mxrta->rta_type = RTA_METRICS;
340     mxrta->rta_len = RTA_LENGTH(0);
341    
342 niro 816 while (*argv) {
343     arg = index_in_substrings(keywords, *argv);
344     if (arg == ARG_src) {
345 niro 532 inet_prefix addr;
346     NEXT_ARG();
347     get_addr(&addr, *argv, req.r.rtm_family);
348 niro 816 if (req.r.rtm_family == AF_UNSPEC)
349 niro 532 req.r.rtm_family = addr.family;
350     addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
351 niro 816 } else if (arg == ARG_via) {
352 niro 532 inet_prefix addr;
353 niro 816 ok |= gw_ok;
354 niro 532 NEXT_ARG();
355     get_addr(&addr, *argv, req.r.rtm_family);
356     if (req.r.rtm_family == AF_UNSPEC) {
357     req.r.rtm_family = addr.family;
358     }
359     addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
360 niro 816 } else if (arg == ARG_mtu) {
361 niro 532 unsigned mtu;
362     NEXT_ARG();
363 niro 816 if (index_in_strings(keywords, *argv) == PARM_lock) {
364     mxlock |= (1 << RTAX_MTU);
365 niro 532 NEXT_ARG();
366     }
367 niro 984 mtu = get_unsigned(*argv, "mtu");
368 niro 532 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
369 niro 816 } else if (arg == ARG_protocol) {
370 niro 532 uint32_t prot;
371     NEXT_ARG();
372     if (rtnl_rtprot_a2n(&prot, *argv))
373     invarg(*argv, "protocol");
374     req.r.rtm_protocol = prot;
375 niro 816 ok |= proto_ok;
376 niro 532 #if ENABLE_FEATURE_IP_RULE
377 niro 816 } else if (arg == ARG_table) {
378 niro 532 uint32_t tid;
379     NEXT_ARG();
380     if (rtnl_rttable_a2n(&tid, *argv))
381     invarg(*argv, "table");
382     req.r.rtm_table = tid;
383     #endif
384 niro 816 } else if (arg == ARG_dev || arg == ARG_oif) {
385 niro 532 NEXT_ARG();
386     d = *argv;
387 niro 816 } else if (arg == ARG_metric) {
388     uint32_t metric;
389     NEXT_ARG();
390 niro 984 metric = get_u32(*argv, "metric");
391 niro 816 addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
392 niro 532 } else {
393     int type;
394     inet_prefix dst;
395    
396 niro 816 if (arg == ARG_to) {
397 niro 532 NEXT_ARG();
398     }
399 niro 816 if ((**argv < '0' || **argv > '9')
400     && rtnl_rtntype_a2n(&type, *argv) == 0) {
401 niro 532 NEXT_ARG();
402     req.r.rtm_type = type;
403 niro 816 ok |= type_ok;
404 niro 532 }
405    
406 niro 816 if (ok & dst_ok) {
407 niro 532 duparg2("to", *argv);
408     }
409     get_prefix(&dst, *argv, req.r.rtm_family);
410     if (req.r.rtm_family == AF_UNSPEC) {
411     req.r.rtm_family = dst.family;
412     }
413     req.r.rtm_dst_len = dst.bitlen;
414 niro 816 ok |= dst_ok;
415 niro 532 if (dst.bytelen) {
416     addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
417     }
418     }
419 niro 816 argv++;
420 niro 532 }
421    
422 niro 816 xrtnl_open(&rth);
423 niro 532
424     if (d) {
425     int idx;
426    
427     ll_init_map(&rth);
428    
429     if (d) {
430 niro 816 idx = xll_name_to_index(d);
431 niro 532 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
432     }
433     }
434    
435     if (mxrta->rta_len > RTA_LENGTH(0)) {
436     if (mxlock) {
437     rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
438     }
439     addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
440     }
441    
442 niro 816 if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
443     req.r.rtm_scope = RT_SCOPE_HOST;
444     else if (req.r.rtm_type == RTN_BROADCAST ||
445     req.r.rtm_type == RTN_MULTICAST ||
446     req.r.rtm_type == RTN_ANYCAST)
447     req.r.rtm_scope = RT_SCOPE_LINK;
448     else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
449     if (cmd == RTM_DELROUTE)
450     req.r.rtm_scope = RT_SCOPE_NOWHERE;
451     else if (!(ok & gw_ok))
452     req.r.rtm_scope = RT_SCOPE_LINK;
453     }
454    
455 niro 532 if (req.r.rtm_family == AF_UNSPEC) {
456     req.r.rtm_family = AF_INET;
457     }
458    
459     if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
460 niro 816 return 2;
461 niro 532 }
462    
463     return 0;
464     }
465    
466     static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
467     {
468     struct {
469     struct nlmsghdr nlh;
470     struct rtmsg rtm;
471     } req;
472     struct sockaddr_nl nladdr;
473    
474     memset(&nladdr, 0, sizeof(nladdr));
475     memset(&req, 0, sizeof(req));
476     nladdr.nl_family = AF_NETLINK;
477    
478     req.nlh.nlmsg_len = sizeof(req);
479 niro 816 if (RTM_GETROUTE)
480     req.nlh.nlmsg_type = RTM_GETROUTE;
481     if (NLM_F_ROOT | NLM_F_REQUEST)
482     req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
483     /*req.nlh.nlmsg_pid = 0; - memset did it already */
484 niro 532 req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
485     req.rtm.rtm_family = family;
486 niro 816 if (RTM_F_CLONED)
487     req.rtm.rtm_flags = RTM_F_CLONED;
488 niro 532
489 niro 816 return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr));
490 niro 532 }
491    
492 niro 816 static void iproute_flush_cache(void)
493 niro 532 {
494 niro 816 static const char fn[] ALIGN1 = "/proc/sys/net/ipv4/route/flush";
495     int flush_fd = open_or_warn(fn, O_WRONLY);
496 niro 532
497     if (flush_fd < 0) {
498 niro 816 return;
499 niro 532 }
500    
501 niro 816 if (write(flush_fd, "-1", 2) < 2) {
502 niro 984 bb_perror_msg("can't flush routing cache");
503 niro 816 return;
504 niro 532 }
505     close(flush_fd);
506     }
507    
508     static void iproute_reset_filter(void)
509     {
510     memset(&filter, 0, sizeof(filter));
511     filter.mdst.bitlen = -1;
512     filter.msrc.bitlen = -1;
513     }
514    
515 niro 816 /* Return value becomes exitcode. It's okay to not return at all */
516     static int iproute_list_or_flush(char **argv, int flush)
517 niro 532 {
518     int do_ipv6 = preferred_family;
519     struct rtnl_handle rth;
520     char *id = NULL;
521     char *od = NULL;
522 niro 816 static const char keywords[] ALIGN1 =
523     /* "ip route list/flush" parameters: */
524     "protocol\0" "dev\0" "oif\0" "iif\0"
525     "via\0" "table\0" "cache\0"
526     "from\0" "to\0"
527     /* and possible further keywords */
528     "all\0"
529     "root\0"
530     "match\0"
531     "exact\0"
532     "main\0"
533     ;
534     enum {
535     KW_proto, KW_dev, KW_oif, KW_iif,
536     KW_via, KW_table, KW_cache,
537     KW_from, KW_to,
538     /* */
539     KW_all,
540     KW_root,
541     KW_match,
542     KW_exact,
543     KW_main,
544     };
545     int arg, parm;
546 niro 532
547     iproute_reset_filter();
548     filter.tb = RT_TABLE_MAIN;
549    
550 niro 816 if (flush && !*argv)
551     bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\"");
552 niro 532
553 niro 816 while (*argv) {
554     arg = index_in_substrings(keywords, *argv);
555     if (arg == KW_proto) {
556 niro 532 uint32_t prot = 0;
557     NEXT_ARG();
558     filter.protocolmask = -1;
559     if (rtnl_rtprot_a2n(&prot, *argv)) {
560 niro 816 if (index_in_strings(keywords, *argv) != KW_all)
561 niro 532 invarg(*argv, "protocol");
562     prot = 0;
563     filter.protocolmask = 0;
564     }
565     filter.protocol = prot;
566 niro 816 } else if (arg == KW_dev || arg == KW_oif) {
567 niro 532 NEXT_ARG();
568     od = *argv;
569 niro 816 } else if (arg == KW_iif) {
570 niro 532 NEXT_ARG();
571     id = *argv;
572 niro 816 } else if (arg == KW_via) {
573 niro 532 NEXT_ARG();
574 niro 816 get_prefix(&filter.rvia, *argv, do_ipv6);
575     } else if (arg == KW_table) { /* table all/cache/main */
576     NEXT_ARG();
577     parm = index_in_substrings(keywords, *argv);
578     if (parm == KW_cache)
579     filter.tb = -1;
580     else if (parm == KW_all)
581     filter.tb = 0;
582     else if (parm != KW_main) {
583     #if ENABLE_FEATURE_IP_RULE
584     uint32_t tid;
585     if (rtnl_rttable_a2n(&tid, *argv))
586     invarg(*argv, "table");
587     filter.tb = tid;
588     #else
589     invarg(*argv, "table");
590     #endif
591     }
592     } else if (arg == KW_cache) {
593     /* The command 'ip route flush cache' is used by OpenSWAN.
594     * Assuming it's a synonym for 'ip route flush table cache' */
595     filter.tb = -1;
596     } else if (arg == KW_from) {
597     NEXT_ARG();
598     parm = index_in_substrings(keywords, *argv);
599     if (parm == KW_root) {
600 niro 532 NEXT_ARG();
601     get_prefix(&filter.rsrc, *argv, do_ipv6);
602 niro 816 } else if (parm == KW_match) {
603 niro 532 NEXT_ARG();
604     get_prefix(&filter.msrc, *argv, do_ipv6);
605     } else {
606 niro 816 if (parm == KW_exact)
607 niro 532 NEXT_ARG();
608     get_prefix(&filter.msrc, *argv, do_ipv6);
609     filter.rsrc = filter.msrc;
610     }
611 niro 816 } else { /* "to" is the default parameter */
612     if (arg == KW_to) {
613 niro 532 NEXT_ARG();
614 niro 816 arg = index_in_substrings(keywords, *argv);
615 niro 532 }
616 niro 816 /* parm = arg; - would be more plausible, but we reuse 'arg' here */
617     if (arg == KW_root) {
618 niro 532 NEXT_ARG();
619     get_prefix(&filter.rdst, *argv, do_ipv6);
620 niro 816 } else if (arg == KW_match) {
621 niro 532 NEXT_ARG();
622     get_prefix(&filter.mdst, *argv, do_ipv6);
623 niro 816 } else { /* "to exact" is the default */
624     if (arg == KW_exact)
625 niro 532 NEXT_ARG();
626     get_prefix(&filter.mdst, *argv, do_ipv6);
627     filter.rdst = filter.mdst;
628     }
629     }
630 niro 816 argv++;
631 niro 532 }
632    
633     if (do_ipv6 == AF_UNSPEC && filter.tb) {
634     do_ipv6 = AF_INET;
635     }
636    
637 niro 816 xrtnl_open(&rth);
638 niro 532 ll_init_map(&rth);
639    
640     if (id || od) {
641     int idx;
642    
643     if (id) {
644 niro 816 idx = xll_name_to_index(id);
645 niro 532 filter.iif = idx;
646     filter.iifmask = -1;
647     }
648     if (od) {
649 niro 816 idx = xll_name_to_index(od);
650 niro 532 filter.oif = idx;
651     filter.oifmask = -1;
652     }
653     }
654    
655     if (flush) {
656     char flushb[4096-512];
657    
658 niro 816 if (filter.tb == -1) { /* "flush table cache" */
659 niro 532 if (do_ipv6 != AF_INET6)
660     iproute_flush_cache();
661     if (do_ipv6 == AF_INET)
662     return 0;
663     }
664    
665     filter.flushb = flushb;
666     filter.flushp = 0;
667     filter.flushe = sizeof(flushb);
668     filter.rth = &rth;
669    
670     for (;;) {
671 niro 816 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
672 niro 532 filter.flushed = 0;
673 niro 816 xrtnl_dump_filter(&rth, print_route, NULL);
674     if (filter.flushed == 0)
675 niro 532 return 0;
676 niro 816 if (flush_update())
677     return 1;
678 niro 532 }
679     }
680    
681     if (filter.tb != -1) {
682 niro 816 xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
683     } else if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
684 niro 984 bb_perror_msg_and_die("can't send dump request");
685 niro 532 }
686 niro 816 xrtnl_dump_filter(&rth, print_route, NULL);
687 niro 532
688 niro 816 return 0;
689 niro 532 }
690    
691    
692 niro 816 /* Return value becomes exitcode. It's okay to not return at all */
693     static int iproute_get(char **argv)
694 niro 532 {
695     struct rtnl_handle rth;
696     struct {
697 niro 816 struct nlmsghdr n;
698     struct rtmsg r;
699     char buf[1024];
700 niro 532 } req;
701 niro 816 char *idev = NULL;
702     char *odev = NULL;
703     bool connected = 0;
704     bool from_ok = 0;
705     static const char options[] ALIGN1 =
706     "from\0""iif\0""oif\0""dev\0""notify\0""connected\0""to\0";
707 niro 532
708     memset(&req, 0, sizeof(req));
709    
710     iproute_reset_filter();
711    
712     req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
713 niro 816 if (NLM_F_REQUEST)
714     req.n.nlmsg_flags = NLM_F_REQUEST;
715     if (RTM_GETROUTE)
716     req.n.nlmsg_type = RTM_GETROUTE;
717 niro 532 req.r.rtm_family = preferred_family;
718 niro 816 /*req.r.rtm_table = 0; - memset did this already */
719     /*req.r.rtm_protocol = 0;*/
720     /*req.r.rtm_scope = 0;*/
721     /*req.r.rtm_type = 0;*/
722     /*req.r.rtm_src_len = 0;*/
723     /*req.r.rtm_dst_len = 0;*/
724     /*req.r.rtm_tos = 0;*/
725 niro 532
726 niro 816 while (*argv) {
727     switch (index_in_strings(options, *argv)) {
728 niro 532 case 0: /* from */
729     {
730     inet_prefix addr;
731     NEXT_ARG();
732     from_ok = 1;
733     get_prefix(&addr, *argv, req.r.rtm_family);
734     if (req.r.rtm_family == AF_UNSPEC) {
735     req.r.rtm_family = addr.family;
736     }
737     if (addr.bytelen) {
738     addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
739     }
740     req.r.rtm_src_len = addr.bitlen;
741     break;
742     }
743     case 1: /* iif */
744     NEXT_ARG();
745     idev = *argv;
746     break;
747     case 2: /* oif */
748     case 3: /* dev */
749     NEXT_ARG();
750     odev = *argv;
751     break;
752     case 4: /* notify */
753     req.r.rtm_flags |= RTM_F_NOTIFY;
754     break;
755     case 5: /* connected */
756     connected = 1;
757     break;
758     case 6: /* to */
759     NEXT_ARG();
760     default:
761     {
762     inet_prefix addr;
763     get_prefix(&addr, *argv, req.r.rtm_family);
764     if (req.r.rtm_family == AF_UNSPEC) {
765     req.r.rtm_family = addr.family;
766     }
767     if (addr.bytelen) {
768     addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
769     }
770     req.r.rtm_dst_len = addr.bitlen;
771     }
772 niro 816 argv++;
773 niro 532 }
774     }
775    
776     if (req.r.rtm_dst_len == 0) {
777     bb_error_msg_and_die("need at least destination address");
778     }
779    
780 niro 816 xrtnl_open(&rth);
781 niro 532
782     ll_init_map(&rth);
783    
784     if (idev || odev) {
785     int idx;
786    
787     if (idev) {
788 niro 816 idx = xll_name_to_index(idev);
789 niro 532 addattr32(&req.n, sizeof(req), RTA_IIF, idx);
790     }
791     if (odev) {
792 niro 816 idx = xll_name_to_index(odev);
793 niro 532 addattr32(&req.n, sizeof(req), RTA_OIF, idx);
794     }
795     }
796    
797     if (req.r.rtm_family == AF_UNSPEC) {
798     req.r.rtm_family = AF_INET;
799     }
800    
801     if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
802 niro 816 return 2;
803 niro 532 }
804    
805     if (connected && !from_ok) {
806     struct rtmsg *r = NLMSG_DATA(&req.n);
807     int len = req.n.nlmsg_len;
808     struct rtattr * tb[RTA_MAX+1];
809    
810 niro 816 print_route(NULL, &req.n, NULL);
811 niro 532
812     if (req.n.nlmsg_type != RTM_NEWROUTE) {
813 niro 816 bb_error_msg_and_die("not a route?");
814 niro 532 }
815     len -= NLMSG_LENGTH(sizeof(*r));
816     if (len < 0) {
817 niro 816 bb_error_msg_and_die("wrong len %d", len);
818 niro 532 }
819    
820     memset(tb, 0, sizeof(tb));
821     parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
822    
823     if (tb[RTA_PREFSRC]) {
824     tb[RTA_PREFSRC]->rta_type = RTA_SRC;
825     r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
826     } else if (!tb[RTA_SRC]) {
827 niro 816 bb_error_msg_and_die("failed to connect the route");
828 niro 532 }
829     if (!odev && tb[RTA_OIF]) {
830     tb[RTA_OIF]->rta_type = 0;
831     }
832     if (tb[RTA_GATEWAY]) {
833     tb[RTA_GATEWAY]->rta_type = 0;
834     }
835     if (!idev && tb[RTA_IIF]) {
836     tb[RTA_IIF]->rta_type = 0;
837     }
838     req.n.nlmsg_flags = NLM_F_REQUEST;
839     req.n.nlmsg_type = RTM_GETROUTE;
840    
841     if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
842 niro 816 return 2;
843 niro 532 }
844     }
845 niro 816 print_route(NULL, &req.n, NULL);
846     return 0;
847 niro 532 }
848    
849 niro 816 /* Return value becomes exitcode. It's okay to not return at all */
850     int do_iproute(char **argv)
851 niro 532 {
852 niro 816 static const char ip_route_commands[] ALIGN1 =
853     /*0-3*/ "add\0""append\0""change\0""chg\0"
854     /*4-7*/ "delete\0""get\0""list\0""show\0"
855     /*8..*/ "prepend\0""replace\0""test\0""flush\0";
856     int command_num;
857     unsigned flags = 0;
858 niro 532 int cmd = RTM_NEWROUTE;
859    
860 niro 816 if (!*argv)
861     return iproute_list_or_flush(argv, 0);
862    
863 niro 532 /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */
864     /* It probably means that it is using "first match" rule */
865 niro 816 command_num = index_in_substrings(ip_route_commands, *argv);
866    
867 niro 532 switch (command_num) {
868     case 0: /* add */
869     flags = NLM_F_CREATE|NLM_F_EXCL;
870     break;
871     case 1: /* append */
872     flags = NLM_F_CREATE|NLM_F_APPEND;
873     break;
874     case 2: /* change */
875     case 3: /* chg */
876     flags = NLM_F_REPLACE;
877     break;
878     case 4: /* delete */
879     cmd = RTM_DELROUTE;
880     break;
881     case 5: /* get */
882 niro 816 return iproute_get(argv+1);
883 niro 532 case 6: /* list */
884     case 7: /* show */
885 niro 816 return iproute_list_or_flush(argv+1, 0);
886 niro 532 case 8: /* prepend */
887     flags = NLM_F_CREATE;
888 niro 816 break;
889 niro 532 case 9: /* replace */
890     flags = NLM_F_CREATE|NLM_F_REPLACE;
891 niro 816 break;
892 niro 532 case 10: /* test */
893     flags = NLM_F_EXCL;
894 niro 816 break;
895 niro 532 case 11: /* flush */
896 niro 816 return iproute_list_or_flush(argv+1, 1);
897 niro 532 default:
898     bb_error_msg_and_die("unknown command %s", *argv);
899     }
900    
901 niro 816 return iproute_modify(cmd, flags, argv+1);
902 niro 532 }