Vodz, last_patch_104
[oweals/busybox.git] / networking / route.c
1 /* route
2  *
3  * Similar to the standard Unix route, but with only the necessary
4  * parts for AF_INET and AF_INET6
5  *
6  * Bjorn Wesen, Axis Communications AB
7  *
8  * Author of the original route:
9  *              Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
10  *              (derived from FvK's 'route.c     1.70    01/04/94')
11  *
12  * This program is free software; you can redistribute it
13  * and/or  modify it under  the terms of  the GNU General
14  * Public  License as  published  by  the  Free  Software
15  * Foundation;  either  version 2 of the License, or  (at
16  * your option) any later version.
17  *
18  * $Id: route.c,v 1.22 2003/03/19 09:12:39 mjn3 Exp $
19  *
20  * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
21  * adjustments by Larry Doolittle  <LRDoolittle@lbl.gov>
22  *
23  * IPV6 support added by Bart Visscher <magick@linux-fan.com>
24  */
25
26 #include <sys/types.h>
27 #include <sys/ioctl.h>
28 #include "inet_common.h"
29 #include <net/route.h>
30 #include <net/if.h>
31 #include <stdio.h>
32 #include <errno.h>
33 #include <fcntl.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <getopt.h>
37 #include <unistd.h>
38 #include <ctype.h>
39 #include "busybox.h"
40
41 #define _(x) x
42
43 #define RTACTION_ADD   1
44 #define RTACTION_DEL   2
45 #define RTACTION_HELP  3
46 #define RTACTION_FLUSH 4
47 #define RTACTION_SHOW  5
48
49 #define E_NOTFOUND      8
50 #define E_SOCK          7
51 #define E_LOOKUP        6
52 #define E_VERSION       5
53 #define E_USAGE         4
54 #define E_OPTERR        3
55 #define E_INTERN        2
56 #define E_NOSUPP        1
57
58 #if defined (SIOCADDRTOLD) || defined (RTF_IRTT)        /* route */
59 #define HAVE_NEW_ADDRT 1
60 #endif
61 #ifdef RTF_IRTT                 /* route */
62 #define HAVE_RTF_IRTT 1
63 #endif
64 #ifdef RTF_REJECT               /* route */
65 #define HAVE_RTF_REJECT 1
66 #endif
67
68 #if HAVE_NEW_ADDRT
69 #define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
70 #define full_mask(x) (x)
71 #else
72 #define mask_in_addr(x) ((x).rt_genmask)
73 #define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
74 #endif
75
76
77
78 /* add or delete a route depending on action */
79
80 static int INET_setroute(int action, int options, char **args)
81 {
82         struct rtentry rt;
83         char target[128], gateway[128] = "NONE";
84         const char *netmask = bb_INET_default;
85         int xflag, isnet;
86         int skfd;
87
88         xflag = 0;
89
90         if (*args == NULL)
91                 bb_show_usage();
92         if (strcmp(*args, "-net") == 0) {
93                 xflag = 1;
94                 args++;
95         } else if (strcmp(*args, "-host") == 0) {
96                 xflag = 2;
97                 args++;
98         }
99         if (*args == NULL)
100                 bb_show_usage();
101         safe_strncpy(target, *args++, (sizeof target));
102
103         /* Clean out the RTREQ structure. */
104         memset((char *) &rt, 0, sizeof(struct rtentry));
105
106
107         if ((isnet =
108                  INET_resolve(target, (struct sockaddr_in *) &rt.rt_dst,
109                                           xflag != 1)) < 0) {
110                 bb_error_msg(_("can't resolve %s"), target);
111                 return EXIT_FAILURE;    /* XXX change to E_something */
112         }
113
114         switch (xflag) {
115         case 1:
116                 isnet = 1;
117                 break;
118
119         case 2:
120                 isnet = 0;
121                 break;
122
123         default:
124                 break;
125         }
126
127         /* Fill in the other fields. */
128         rt.rt_flags = (RTF_UP | RTF_HOST);
129         if (isnet)
130                 rt.rt_flags &= ~RTF_HOST;
131
132         while (*args) {
133                 if (strcmp(*args, "metric") == 0) {
134                         int metric;
135
136                         args++;
137                         if (!*args || !isdigit(**args))
138                                 bb_show_usage();
139                         metric = atoi(*args);
140 #if HAVE_NEW_ADDRT
141                         rt.rt_metric = metric + 1;
142 #else
143                         ENOSUPP("inet_setroute", "NEW_ADDRT (metric)"); /* XXX Fixme */
144 #endif
145                         args++;
146                         continue;
147                 }
148
149                 if (strcmp(*args, "netmask") == 0) {
150                         struct sockaddr mask;
151
152                         args++;
153                         if (!*args || mask_in_addr(rt))
154                                 bb_show_usage();
155                         netmask = *args;
156                         if ((isnet =
157                                  INET_resolve(netmask, (struct sockaddr_in *) &mask,
158                                                           0)) < 0) {
159                                 bb_error_msg(_("can't resolve netmask %s"), netmask);
160                                 return E_LOOKUP;
161                         }
162                         rt.rt_genmask = full_mask(mask);
163                         args++;
164                         continue;
165                 }
166
167                 if (strcmp(*args, "gw") == 0 || strcmp(*args, "gateway") == 0) {
168                         args++;
169                         if (!*args)
170                                 bb_show_usage();
171                         if (rt.rt_flags & RTF_GATEWAY)
172                                 bb_show_usage();
173                         safe_strncpy(gateway, *args, (sizeof gateway));
174                         if ((isnet =
175                                  INET_resolve(gateway, (struct sockaddr_in *) &rt.rt_gateway,
176                                                           1)) < 0) {
177                                 bb_error_msg(_("can't resolve gw %s"), gateway);
178                                 return E_LOOKUP;
179                         }
180                         if (isnet) {
181                                 bb_error_msg(_("%s: cannot use a NETWORK as gateway!"), gateway);
182                                 return E_OPTERR;
183                         }
184                         rt.rt_flags |= RTF_GATEWAY;
185                         args++;
186                         continue;
187                 }
188
189                 if (strcmp(*args, "mss") == 0) {
190                         args++;
191                         rt.rt_flags |= RTF_MSS;
192                         if (!*args)
193                                 bb_show_usage();
194                         rt.rt_mss = atoi(*args);
195                         args++;
196                         if (rt.rt_mss < 64 || rt.rt_mss > 32768) {
197                                 bb_error_msg(_("Invalid MSS."));
198                                 return E_OPTERR;
199                         }
200                         continue;
201                 }
202
203                 if (strcmp(*args, "window") == 0) {
204                         args++;
205                         if (!*args)
206                                 bb_show_usage();
207                         rt.rt_flags |= RTF_WINDOW;
208                         rt.rt_window = atoi(*args);
209                         args++;
210                         if (rt.rt_window < 128) {
211                                 bb_error_msg(_("Invalid window."));
212                                 return E_OPTERR;
213                         }
214                         continue;
215                 }
216
217                 if (strcmp(*args, "irtt") == 0) {
218                         args++;
219                         if (!*args)
220                                 bb_show_usage();
221                         args++;
222 #if HAVE_RTF_IRTT
223                         rt.rt_flags |= RTF_IRTT;
224                         rt.rt_irtt = atoi(*(args - 1));
225                         rt.rt_irtt *= (sysconf(_SC_CLK_TCK) / 100);     /* FIXME */
226 #if 0                                   /* FIXME: do we need to check anything of this? */
227                         if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) {
228                                 bb_error_msg(_("Invalid initial rtt."));
229                                 return E_OPTERR;
230                         }
231 #endif
232 #else
233                         ENOSUPP("inet_setroute", "RTF_IRTT");   /* XXX Fixme */
234 #endif
235                         continue;
236                 }
237
238                 if (strcmp(*args, "reject") == 0) {
239                         args++;
240 #if HAVE_RTF_REJECT
241                         rt.rt_flags |= RTF_REJECT;
242 #else
243                         ENOSUPP("inet_setroute", "RTF_REJECT"); /* XXX Fixme */
244 #endif
245                         continue;
246                 }
247                 if (strcmp(*args, "mod") == 0) {
248                         args++;
249                         rt.rt_flags |= RTF_MODIFIED;
250                         continue;
251                 }
252                 if (strcmp(*args, "dyn") == 0) {
253                         args++;
254                         rt.rt_flags |= RTF_DYNAMIC;
255                         continue;
256                 }
257                 if (strcmp(*args, "reinstate") == 0) {
258                         args++;
259                         rt.rt_flags |= RTF_REINSTATE;
260                         continue;
261                 }
262                 if (strcmp(*args, "device") == 0 || strcmp(*args, "dev") == 0) {
263                         args++;
264                         if (rt.rt_dev || *args == NULL)
265                                 bb_show_usage();
266                         rt.rt_dev = *args++;
267                         continue;
268                 }
269                 /* nothing matches */
270                 if (!rt.rt_dev) {
271                         rt.rt_dev = *args++;
272                         if (*args)
273                                 bb_show_usage();        /* must be last to catch typos */
274                 } else {
275                         bb_show_usage();
276                 }
277         }
278
279 #if HAVE_RTF_REJECT
280         if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev)
281                 rt.rt_dev = "lo";
282 #endif
283
284         /* sanity checks.. */
285         if (mask_in_addr(rt)) {
286                 unsigned long mask = mask_in_addr(rt);
287
288                 mask = ~ntohl(mask);
289                 if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) {
290                         bb_error_msg(_("netmask %.8x doesn't make sense with host route"),
291                                           (unsigned int) mask);
292                         return E_OPTERR;
293                 }
294                 if (mask & (mask + 1)) {
295                         bb_error_msg(_("bogus netmask %s"), netmask);
296                         return E_OPTERR;
297                 }
298                 mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr;
299                 if (mask & ~mask_in_addr(rt)) {
300                         bb_error_msg(_("netmask doesn't match route address"));
301                         return E_OPTERR;
302                 }
303         }
304         /* Fill out netmask if still unset */
305         if ((action == RTACTION_ADD) && rt.rt_flags & RTF_HOST)
306                 mask_in_addr(rt) = 0xffffffff;
307
308         /* Create a socket to the INET kernel. */
309         if ((skfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
310                 perror("socket");
311                 return E_SOCK;
312         }
313         /* Tell the kernel to accept this route. */
314         if (action == RTACTION_DEL) {
315                 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
316                         perror("SIOCDELRT");
317                         close(skfd);
318                         return E_SOCK;
319                 }
320         } else {
321                 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
322                         perror("SIOCADDRT");
323                         close(skfd);
324                         return E_SOCK;
325                 }
326         }
327
328         /* Close the socket. */
329         (void) close(skfd);
330         return EXIT_SUCCESS;
331 }
332
333 #ifdef CONFIG_FEATURE_IPV6
334 static int INET6_setroute(int action, int options, char **args)
335 {
336         struct in6_rtmsg rt;
337         struct ifreq ifr;
338         struct sockaddr_in6 sa6;
339         char target[128], gateway[128] = "NONE";
340         int metric, prefix_len;
341         char *devname = NULL;
342         char *cp;
343         int skfd;
344
345         if (*args == NULL)
346                 bb_show_usage();
347
348         strcpy(target, *args++);
349         if (!strcmp(target, "default")) {
350                 prefix_len = 0;
351                 memset(&sa6, 0, sizeof(sa6));
352         } else {
353                 if ((cp = strchr(target, '/'))) {
354                         prefix_len = atol(cp + 1);
355                         if ((prefix_len < 0) || (prefix_len > 128))
356                                 bb_show_usage();
357                         *cp = 0;
358                 } else {
359                         prefix_len = 128;
360                 }
361                 if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) {
362                         bb_error_msg(_("can't resolve %s"), target);
363                         return EXIT_FAILURE;    /* XXX change to E_something */
364                 }
365         }
366
367         /* Clean out the RTREQ structure. */
368         memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
369
370         memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
371
372         /* Fill in the other fields. */
373         rt.rtmsg_flags = RTF_UP;
374         if (prefix_len == 128)
375                 rt.rtmsg_flags |= RTF_HOST;
376         rt.rtmsg_metric = 1;
377         rt.rtmsg_dst_len = prefix_len;
378
379         while (*args) {
380                 if (!strcmp(*args, "metric")) {
381
382                         args++;
383                         if (!*args || !isdigit(**args))
384                                 bb_show_usage();
385                         metric = atoi(*args);
386                         rt.rtmsg_metric = metric;
387                         args++;
388                         continue;
389                 }
390                 if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
391                         args++;
392                         if (!*args)
393                                 bb_show_usage();
394                         if (rt.rtmsg_flags & RTF_GATEWAY)
395                                 bb_show_usage();
396                         strcpy(gateway, *args);
397                         if (INET6_resolve(gateway, (struct sockaddr_in6 *) &sa6) < 0) {
398                                 bb_error_msg(_("can't resolve gw %s"), gateway);
399                                 return (E_LOOKUP);
400                         }
401                         memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
402                                    sizeof(struct in6_addr));
403                         rt.rtmsg_flags |= RTF_GATEWAY;
404                         args++;
405                         continue;
406                 }
407                 if (!strcmp(*args, "mod")) {
408                         args++;
409                         rt.rtmsg_flags |= RTF_MODIFIED;
410                         continue;
411                 }
412                 if (!strcmp(*args, "dyn")) {
413                         args++;
414                         rt.rtmsg_flags |= RTF_DYNAMIC;
415                         continue;
416                 }
417                 if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
418                         args++;
419                         if (!*args)
420                                 bb_show_usage();
421                 } else if (args[1])
422                         bb_show_usage();
423
424                 devname = *args;
425                 args++;
426         }
427
428         /* Create a socket to the INET6 kernel. */
429         if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
430                 perror("socket");
431                 return (E_SOCK);
432         }
433         if (devname) {
434                 memset(&ifr, 0, sizeof(ifr));
435                 strcpy(ifr.ifr_name, devname);
436
437                 if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
438                         perror("SIOGIFINDEX");
439                         return (E_SOCK);
440                 }
441                 rt.rtmsg_ifindex = ifr.ifr_ifindex;
442         } else
443                 rt.rtmsg_ifindex = 0;
444
445         /* Tell the kernel to accept this route. */
446         if (action == RTACTION_DEL) {
447                 if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
448                         perror("SIOCDELRT");
449                         close(skfd);
450                         return (E_SOCK);
451                 }
452         } else {
453                 if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
454                         perror("SIOCADDRT");
455                         close(skfd);
456                         return (E_SOCK);
457                 }
458         }
459
460         /* Close the socket. */
461         (void) close(skfd);
462         return (0);
463 }
464 #endif
465
466 #ifndef RTF_UP
467 /* Keep this in sync with /usr/src/linux/include/linux/route.h */
468 #define RTF_UP          0x0001  /* route usable                 */
469 #define RTF_GATEWAY     0x0002  /* destination is a gateway     */
470 #define RTF_HOST        0x0004  /* host entry (net otherwise)   */
471 #define RTF_REINSTATE   0x0008  /* reinstate route after tmout  */
472 #define RTF_DYNAMIC     0x0010  /* created dyn. (by redirect)   */
473 #define RTF_MODIFIED    0x0020  /* modified dyn. (by redirect)  */
474 #define RTF_MTU         0x0040  /* specific MTU for this route  */
475 #ifndef RTF_MSS
476 #define RTF_MSS         RTF_MTU /* Compatibility :-(            */
477 #endif
478 #define RTF_WINDOW      0x0080  /* per route window clamping    */
479 #define RTF_IRTT        0x0100  /* Initial round trip time      */
480 #define RTF_REJECT      0x0200  /* Reject route                 */
481 #endif
482
483 void displayroutes(int noresolve, int netstatfmt)
484 {
485         char buff[256];
486         int nl = 0;
487         struct in_addr dest;
488         struct in_addr gw;
489         struct in_addr mask;
490         int flgs, ref, use, metric, mtu, win, ir;
491         char flags[64];
492         unsigned long int d, g, m;
493
494         char sdest[16], sgw[16];
495
496         FILE *fp = bb_xfopen("/proc/net/route", "r");
497
498         if (noresolve)
499                 noresolve = 0x0fff;
500
501         printf("Kernel IP routing table\n");
502         printf
503                 ("Destination     Gateway         Genmask         Flags %s Iface\n",
504                  netstatfmt ? "  MSS Window  irtt" : "Metric Ref    Use");
505
506         while (fgets(buff, sizeof(buff), fp) != NULL) {
507                 if (nl) {
508                         int ifl = 0;
509                         int numeric;
510                         struct sockaddr_in s_addr;
511
512                         while (buff[ifl] != ' ' && buff[ifl] != '\t' && buff[ifl] != '\0')
513                                 ifl++;
514                         buff[ifl] = 0;  /* interface */
515                         if (sscanf(buff + ifl + 1, "%lx%lx%X%d%d%d%lx%d%d%d",
516                                            &d, &g, &flgs, &ref, &use, &metric, &m, &mtu, &win,
517                                            &ir) != 10) {
518                                 bb_error_msg_and_die("Unsuported kernel route format\n");
519                         }
520                         ifl = 0;        /* parse flags */
521                         if (flgs & RTF_UP) {
522                                 if (flgs & RTF_REJECT)
523                                         flags[ifl++] = '!';
524                                 else
525                                         flags[ifl++] = 'U';
526                                 if (flgs & RTF_GATEWAY)
527                                         flags[ifl++] = 'G';
528                                 if (flgs & RTF_HOST)
529                                         flags[ifl++] = 'H';
530                                 if (flgs & RTF_REINSTATE)
531                                         flags[ifl++] = 'R';
532                                 if (flgs & RTF_DYNAMIC)
533                                         flags[ifl++] = 'D';
534                                 if (flgs & RTF_MODIFIED)
535                                         flags[ifl++] = 'M';
536                                 flags[ifl] = 0;
537                                 dest.s_addr = d;
538                                 gw.s_addr = g;
539                                 mask.s_addr = m;
540                                 memset(&s_addr, 0, sizeof(struct sockaddr_in));
541                                 s_addr.sin_family = AF_INET;
542                                 s_addr.sin_addr = dest;
543                                 numeric = noresolve | 0x8000;   /* default instead of * */
544                                 INET_rresolve(sdest, sizeof(sdest), &s_addr, numeric, m);
545                                 numeric = noresolve | 0x4000;   /* host instead of net */
546                                 s_addr.sin_addr = gw;
547                                 INET_rresolve(sgw, sizeof(sgw), &s_addr, numeric, m);
548
549                                 printf("%-16s%-16s%-16s%-6s", sdest, sgw, inet_ntoa(mask),
550                                            flags);
551                                 if (netstatfmt)
552                                         printf("%5d %-5d %6d %s\n", mtu, win, ir, buff);
553                                 else
554                                         printf("%-6d %-2d %7d %s\n", metric, ref, use, buff);
555                         }
556                 }
557                 nl++;
558         }
559 }
560
561 #ifdef CONFIG_FEATURE_IPV6
562 static void INET6_displayroutes(int noresolve)
563 {
564         char buff[256];
565         char iface[16], flags[16];
566         char addr6[128], naddr6[128];
567         struct sockaddr_in6 saddr6, snaddr6;
568         int iflags, metric, refcnt, use, prefix_len, slen;
569         int numeric;
570
571         char addr6p[8][5], saddr6p[8][5], naddr6p[8][5];
572
573         FILE *fp = bb_xfopen("/proc/net/ipv6_route", "r");
574
575         flags[0] = 'U';
576
577         if (noresolve)
578                 noresolve = 0x0fff;
579         numeric = noresolve | 0x8000;   /* default instead of * */
580
581         printf("Kernel IPv6 routing table\n"
582                    "Destination                                 "
583                    "Next Hop                                "
584                    "Flags Metric Ref    Use Iface\n");
585
586         while (fgets(buff, sizeof(buff), fp) != NULL) {
587                 int ifl;
588
589                 if (sscanf(buff, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
590                                    "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
591                                    "%4s%4s%4s%4s%4s%4s%4s%4s %08x %08x %08x %08x %s\n",
592                                    addr6p[0], addr6p[1], addr6p[2], addr6p[3],
593                                    addr6p[4], addr6p[5], addr6p[6], addr6p[7],
594                                    &prefix_len,
595                                    saddr6p[0], saddr6p[1], saddr6p[2], saddr6p[3],
596                                    saddr6p[4], saddr6p[5], saddr6p[6], saddr6p[7],
597                                    &slen,
598                                    naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
599                                    naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7],
600                                    &metric, &use, &refcnt, &iflags, iface) != 31) {
601                         bb_error_msg_and_die("Unsuported kernel route format\n");
602                 }
603
604                 ifl = 1;                /* parse flags */
605                 if (!(iflags & RTF_UP))
606                         continue;
607                 if (iflags & RTF_GATEWAY)
608                         flags[ifl++] = 'G';
609                 if (iflags & RTF_HOST)
610                         flags[ifl++] = 'H';
611                 if (iflags & RTF_DEFAULT)
612                         flags[ifl++] = 'D';
613                 if (iflags & RTF_ADDRCONF)
614                         flags[ifl++] = 'A';
615                 if (iflags & RTF_CACHE)
616                         flags[ifl++] = 'C';
617                 flags[ifl] = 0;
618
619                 /* Fetch and resolve the target address. */
620                 snprintf(addr6, sizeof(addr6), "%s:%s:%s:%s:%s:%s:%s:%s",
621                                  addr6p[0], addr6p[1], addr6p[2], addr6p[3],
622                                  addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
623                 inet_pton(AF_INET6, addr6, (struct sockaddr *) &saddr6.sin6_addr);
624                 saddr6.sin6_family = AF_INET6;
625
626                 INET6_rresolve(addr6, sizeof(addr6), (struct sockaddr_in6 *) &saddr6,
627                                            numeric);
628                 snprintf(addr6, sizeof(addr6), "%s/%d", addr6, prefix_len);
629
630                 /* Fetch and resolve the nexthop address. */
631                 snprintf(naddr6, sizeof(naddr6), "%s:%s:%s:%s:%s:%s:%s:%s",
632                                  naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
633                                  naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7]);
634                 inet_pton(AF_INET6, naddr6, (struct sockaddr *) &snaddr6.sin6_addr);
635                 snaddr6.sin6_family = AF_INET6;
636
637                 INET6_rresolve(naddr6, sizeof(naddr6),
638                                            (struct sockaddr_in6 *) &snaddr6, numeric);
639
640                 /* Print the info. */
641                 printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
642                            addr6, naddr6, flags, metric, refcnt, use, iface);
643         }
644 }
645 #endif
646
647 int route_main(int argc, char **argv)
648 {
649         int opt;
650         int what = 0;
651
652 #ifdef CONFIG_FEATURE_IPV6
653         int af = AF_INET;
654 #endif
655
656         if (!argv[1] || (argv[1][0] == '-')) {
657                 /* check options */
658                 int noresolve = 0;
659                 int extended = 0;
660
661                 while ((opt = getopt(argc, argv, "A:ne")) > 0) {
662                         switch (opt) {
663                         case 'n':
664                                 noresolve = 1;
665                                 break;
666                         case 'e':
667                                 extended = 1;
668                                 break;
669                         case 'A':
670 #ifdef CONFIG_FEATURE_IPV6
671                                 if (strcmp(optarg, "inet6") == 0)
672                                         af = AF_INET6;
673                                 break;
674 #endif
675                         default:
676                                 bb_show_usage();
677                         }
678                 }
679
680 #ifdef CONFIG_FEATURE_IPV6
681                 if (af == AF_INET6)
682                         INET6_displayroutes(*argv != NULL);
683                 else
684 #endif
685                         displayroutes(noresolve, extended);
686                 return EXIT_SUCCESS;
687         } else {
688                 /* check verb */
689                 if (strcmp(argv[1], "add") == 0)
690                         what = RTACTION_ADD;
691                 else if (strcmp(argv[1], "del") == 0
692                                  || strcmp(argv[1], "delete") == 0)
693                         what = RTACTION_DEL;
694                 else if (strcmp(argv[1], "flush") == 0)
695                         what = RTACTION_FLUSH;
696                 else
697                         bb_show_usage();
698         }
699
700 #ifdef CONFIG_FEATURE_IPV6
701         if (af == AF_INET6)
702                 return INET6_setroute(what, 0, argv + 2);
703 #endif
704         return INET_setroute(what, 0, argv + 2);
705 }