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