This commit was manufactured by cvs2svn to create tag 'busybox_1_00'.
[oweals/busybox.git] / busybox / 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 {
541                                 if (matches(*argv, "exact") == 0) {
542                                         NEXT_ARG();
543                                 }
544                                 get_prefix(&filter.mdst, *argv, do_ipv6);
545                                 filter.rdst = filter.mdst;
546                         }
547                 }
548                 argc--; argv++;
549         }
550
551         if (do_ipv6 == AF_UNSPEC && filter.tb) {
552                 do_ipv6 = AF_INET;
553         }
554
555         if (rtnl_open(&rth, 0) < 0) {
556                 exit(1);
557         }
558
559         ll_init_map(&rth);
560
561         if (id || od)  {
562                 int idx;
563
564                 if (id) {
565                         if ((idx = ll_name_to_index(id)) == 0) {
566                                 bb_error_msg("Cannot find device \"%s\"", id);
567                                 return -1;
568                         }
569                         filter.iif = idx;
570                         filter.iifmask = -1;
571                 }
572                 if (od) {
573                         if ((idx = ll_name_to_index(od)) == 0) {
574                                 bb_error_msg("Cannot find device \"%s\"", od);
575                         }
576                         filter.oif = idx;
577                         filter.oifmask = -1;
578                 }
579         }
580
581         if (flush) {
582                 int round = 0;
583                 char flushb[4096-512];
584
585                 if (filter.tb == -1) {
586                         if (do_ipv6 != AF_INET6)
587                                 iproute_flush_cache();
588                         if (do_ipv6 == AF_INET)
589                                 return 0;
590                 }
591
592                 filter.flushb = flushb;
593                 filter.flushp = 0;
594                 filter.flushe = sizeof(flushb);
595                 filter.rth = &rth;
596
597                 for (;;) {
598                         if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
599                                 perror("Cannot send dump request");
600                                 return -1;
601                         }
602                         filter.flushed = 0;
603                         if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
604                                 bb_error_msg("Flush terminated\n");
605                                 return -1;
606                         }
607                         if (filter.flushed == 0) {
608                                 if (round == 0) {
609                                         if (filter.tb != -1 || do_ipv6 == AF_INET6)
610                                                 fprintf(stderr, "Nothing to flush.\n");
611                                 }
612                                 fflush(stdout);
613                                 return 0;
614                         }
615                         round++;
616                         if (flush_update() < 0)
617                                 exit(1);
618                 }
619         }
620
621         if (filter.tb != -1) {
622                 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) {
623                         bb_perror_msg_and_die("Cannot send dump request");
624                 }
625         } else {
626                 if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
627                         bb_perror_msg_and_die("Cannot send dump request");
628                 }
629         }
630
631         if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) {
632                 bb_error_msg_and_die("Dump terminated");
633         }
634
635         exit(0);
636 }
637
638
639 static int iproute_get(int argc, char **argv)
640 {
641         struct rtnl_handle rth;
642         struct {
643                 struct nlmsghdr         n;
644                 struct rtmsg            r;
645                 char                    buf[1024];
646         } req;
647         char  *idev = NULL;
648         char  *odev = NULL;
649         int connected = 0;
650         int from_ok = 0;
651         const char *options[] = { "from", "iif", "oif", "dev", "notify", "connected", "to", 0 };
652
653         memset(&req, 0, sizeof(req));
654
655         iproute_reset_filter();
656
657         req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
658         req.n.nlmsg_flags = NLM_F_REQUEST;
659         req.n.nlmsg_type = RTM_GETROUTE;
660         req.r.rtm_family = preferred_family;
661         req.r.rtm_table = 0;
662         req.r.rtm_protocol = 0;
663         req.r.rtm_scope = 0;
664         req.r.rtm_type = 0;
665         req.r.rtm_src_len = 0;
666         req.r.rtm_dst_len = 0;
667         req.r.rtm_tos = 0;
668
669         while (argc > 0) {
670                 switch (compare_string_array(options, *argv)) {
671                         case 0: /* from */
672                         {
673                                 inet_prefix addr;
674                                 NEXT_ARG();
675                                 from_ok = 1;
676                                 get_prefix(&addr, *argv, req.r.rtm_family);
677                                 if (req.r.rtm_family == AF_UNSPEC) {
678                                         req.r.rtm_family = addr.family;
679                                 }
680                                 if (addr.bytelen) {
681                                         addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
682                                 }
683                                 req.r.rtm_src_len = addr.bitlen;
684                                 break;
685                         }
686                         case 1: /* iif */
687                                 NEXT_ARG();
688                                 idev = *argv;
689                                 break;
690                         case 2: /* oif */
691                         case 3: /* dev */
692                                 NEXT_ARG();
693                                 odev = *argv;
694                                 break;
695                         case 4: /* notify */
696                                 req.r.rtm_flags |= RTM_F_NOTIFY;
697                                 break;
698                         case 5: /* connected */
699                                 connected = 1;
700                                 break;
701                         case 6: /* to */
702                                 NEXT_ARG();
703                         default:
704                         {
705                                 inet_prefix addr;
706                                 get_prefix(&addr, *argv, req.r.rtm_family);
707                                 if (req.r.rtm_family == AF_UNSPEC) {
708                                         req.r.rtm_family = addr.family;
709                                 }
710                                 if (addr.bytelen) {
711                                         addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
712                                 }
713                                 req.r.rtm_dst_len = addr.bitlen;
714                         }
715                         argc--; argv++;
716                 }
717         }
718
719         if (req.r.rtm_dst_len == 0) {
720                 bb_error_msg_and_die("need at least destination address");
721         }
722
723         if (rtnl_open(&rth, 0) < 0)
724                 exit(1);
725
726         ll_init_map(&rth);
727
728         if (idev || odev)  {
729                 int idx;
730
731                 if (idev) {
732                         if ((idx = ll_name_to_index(idev)) == 0) {
733                                 bb_error_msg("Cannot find device \"%s\"", idev);
734                                 return -1;
735                         }
736                         addattr32(&req.n, sizeof(req), RTA_IIF, idx);
737                 }
738                 if (odev) {
739                         if ((idx = ll_name_to_index(odev)) == 0) {
740                                 bb_error_msg("Cannot find device \"%s\"", odev);
741                                 return -1;
742                         }
743                         addattr32(&req.n, sizeof(req), RTA_OIF, idx);
744                 }
745         }
746
747         if (req.r.rtm_family == AF_UNSPEC) {
748                 req.r.rtm_family = AF_INET;
749         }
750
751         if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
752                 exit(2);
753         }
754
755         if (connected && !from_ok) {
756                 struct rtmsg *r = NLMSG_DATA(&req.n);
757                 int len = req.n.nlmsg_len;
758                 struct rtattr * tb[RTA_MAX+1];
759
760                 if (print_route(NULL, &req.n, (void*)stdout) < 0) {
761                         bb_error_msg_and_die("An error :-)");
762                 }
763
764                 if (req.n.nlmsg_type != RTM_NEWROUTE) {
765                         bb_error_msg("Not a route?");
766                         return -1;
767                 }
768                 len -= NLMSG_LENGTH(sizeof(*r));
769                 if (len < 0) {
770                         bb_error_msg("Wrong len %d", len);
771                         return -1;
772                 }
773
774                 memset(tb, 0, sizeof(tb));
775                 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
776
777                 if (tb[RTA_PREFSRC]) {
778                         tb[RTA_PREFSRC]->rta_type = RTA_SRC;
779                         r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
780                 } else if (!tb[RTA_SRC]) {
781                         bb_error_msg("Failed to connect the route");
782                         return -1;
783                 }
784                 if (!odev && tb[RTA_OIF]) {
785                         tb[RTA_OIF]->rta_type = 0;
786                 }
787                 if (tb[RTA_GATEWAY]) {
788                         tb[RTA_GATEWAY]->rta_type = 0;
789                 }
790                 if (!idev && tb[RTA_IIF]) {
791                         tb[RTA_IIF]->rta_type = 0;
792                 }
793                 req.n.nlmsg_flags = NLM_F_REQUEST;
794                 req.n.nlmsg_type = RTM_GETROUTE;
795
796                 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
797                         exit(2);
798                 }
799         }
800
801         if (print_route(NULL, &req.n, (void*)stdout) < 0) {
802                 bb_error_msg_and_die("An error :-)");
803         }
804
805         exit(0);
806 }
807
808 int do_iproute(int argc, char **argv)
809 {
810         const char *ip_route_commands[] = { "add", "append", "change", "chg",
811                 "delete", "del", "get", "list", "show", "prepend", "replace", "test", "flush", 0 };
812         unsigned short command_num = 7;
813         unsigned int flags = 0;
814         int cmd = RTM_NEWROUTE;
815
816         if (*argv) {
817                 command_num = compare_string_array(ip_route_commands, *argv);
818         }
819         switch(command_num) {
820                 case 0: /* add*/
821                         flags = NLM_F_CREATE|NLM_F_EXCL;
822                         break;
823                 case 1: /* append */
824                         flags = NLM_F_CREATE|NLM_F_APPEND;
825                         break;
826                 case 2: /* change */
827                 case 3: /* chg */
828                         flags = NLM_F_REPLACE;
829                         break;
830                 case 4: /* delete */
831                 case 5: /* del */
832                         cmd = RTM_DELROUTE;
833                         break;
834                 case 6: /* get */
835                         return iproute_get(argc-1, argv+1);
836                 case 7: /* list */
837                 case 8: /* show */
838                         return iproute_list_or_flush(argc-1, argv+1, 0);
839                 case 9: /* prepend */
840                         flags = NLM_F_CREATE;
841                 case 10: /* replace */
842                         flags = NLM_F_CREATE|NLM_F_REPLACE;
843                 case 11: /* test */
844                         flags = NLM_F_EXCL;
845                 case 12: /* flush */
846                         return iproute_list_or_flush(argc-1, argv+1, 1);
847                 default:
848                         bb_error_msg_and_die("Unknown command %s", *argv);
849         }
850
851         return iproute_modify(cmd, flags, argc-1, argv+1);
852 }