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