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