source: MondoRescue/branches/3.3/mindi-busybox/networking/route.c@ 3734

Last change on this file since 3734 was 3621, checked in by Bruno Cornec, 10 years ago

New 3?3 banch for incorporation of latest busybox 1.25. Changing minor version to handle potential incompatibilities.

File size: 17.9 KB
Line 
1/* vi: set sw=4 ts=4: */
2/* route
3 *
4 * Similar to the standard Unix route, but with only the necessary
5 * parts for AF_INET and AF_INET6
6 *
7 * Bjorn Wesen, Axis Communications AB
8 *
9 * Author of the original route:
10 * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
11 * (derived from FvK's 'route.c 1.70 01/04/94')
12 *
13 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
14 *
15 *
16 * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
17 * adjustments by Larry Doolittle <LRDoolittle@lbl.gov>
18 *
19 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
20 */
21
22/* 2004/03/09 Manuel Novoa III <mjn3@codepoet.org>
23 *
24 * Rewritten to fix several bugs, add additional error checking, and
25 * remove ridiculous amounts of bloat.
26 */
27
28//usage:#define route_trivial_usage
29//usage: "[{add|del|delete}]"
30//usage:#define route_full_usage "\n\n"
31//usage: "Edit kernel routing tables\n"
32//usage: "\n -n Don't resolve names"
33//usage: "\n -e Display other/more information"
34//usage: "\n -A inet" IF_FEATURE_IPV6("{6}") " Select address family"
35
36#include <net/route.h>
37#include <net/if.h>
38
39#include "libbb.h"
40#include "inet_common.h"
41
42
43#ifndef RTF_UP
44/* Keep this in sync with /usr/src/linux/include/linux/route.h */
45#define RTF_UP 0x0001 /* route usable */
46#define RTF_GATEWAY 0x0002 /* destination is a gateway */
47#define RTF_HOST 0x0004 /* host entry (net otherwise) */
48#define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
49#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
50#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
51#define RTF_MTU 0x0040 /* specific MTU for this route */
52#ifndef RTF_MSS
53#define RTF_MSS RTF_MTU /* Compatibility :-( */
54#endif
55#define RTF_WINDOW 0x0080 /* per route window clamping */
56#define RTF_IRTT 0x0100 /* Initial round trip time */
57#define RTF_REJECT 0x0200 /* Reject route */
58#define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */
59#endif
60
61#if defined(SIOCADDRTOLD) || defined(RTF_IRTT) /* route */
62#define HAVE_NEW_ADDRT 1
63#endif
64
65#if HAVE_NEW_ADDRT
66#define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
67#define full_mask(x) (x)
68#else
69#define mask_in_addr(x) ((x).rt_genmask)
70#define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
71#endif
72
73/* The RTACTION entries must agree with tbl_verb[] below! */
74#define RTACTION_ADD 1
75#define RTACTION_DEL 2
76
77/* For the various tbl_*[] arrays, the 1st byte is the offset to
78 * the next entry and the 2nd byte is return value. */
79
80#define NET_FLAG 1
81#define HOST_FLAG 2
82
83/* We remap '-' to '#' to avoid problems with getopt. */
84static const char tbl_hash_net_host[] ALIGN1 =
85 "\007\001#net\0"
86/* "\010\002#host\0" */
87 "\007\002#host" /* Since last, we can save a byte. */
88;
89
90#define KW_TAKES_ARG 020
91#define KW_SETS_FLAG 040
92
93#define KW_IPVx_METRIC 020
94#define KW_IPVx_NETMASK 021
95#define KW_IPVx_GATEWAY 022
96#define KW_IPVx_MSS 023
97#define KW_IPVx_WINDOW 024
98#define KW_IPVx_IRTT 025
99#define KW_IPVx_DEVICE 026
100
101#define KW_IPVx_FLAG_ONLY 040
102#define KW_IPVx_REJECT 040
103#define KW_IPVx_MOD 041
104#define KW_IPVx_DYN 042
105#define KW_IPVx_REINSTATE 043
106
107static const char tbl_ipvx[] ALIGN1 =
108 /* 020 is the "takes an arg" bit */
109#if HAVE_NEW_ADDRT
110 "\011\020metric\0"
111#endif
112 "\012\021netmask\0"
113 "\005\022gw\0"
114 "\012\022gateway\0"
115 "\006\023mss\0"
116 "\011\024window\0"
117#ifdef RTF_IRTT
118 "\007\025irtt\0"
119#endif
120 "\006\026dev\0"
121 "\011\026device\0"
122 /* 040 is the "sets a flag" bit - MUST match flags_ipvx[] values below. */
123#ifdef RTF_REJECT
124 "\011\040reject\0"
125#endif
126 "\006\041mod\0"
127 "\006\042dyn\0"
128/* "\014\043reinstate\0" */
129 "\013\043reinstate" /* Since last, we can save a byte. */
130;
131
132static const uint16_t flags_ipvx[] = { /* MUST match tbl_ipvx[] values above. */
133#ifdef RTF_REJECT
134 RTF_REJECT,
135#endif
136 RTF_MODIFIED,
137 RTF_DYNAMIC,
138 RTF_REINSTATE
139};
140
141static int kw_lookup(const char *kwtbl, char ***pargs)
142{
143 if (**pargs) {
144 do {
145 if (strcmp(kwtbl+2, **pargs) == 0) { /* Found a match. */
146 *pargs += 1;
147 if (kwtbl[1] & KW_TAKES_ARG) {
148 if (!**pargs) { /* No more args! */
149 bb_show_usage();
150 }
151 *pargs += 1; /* Calling routine will use args[-1]. */
152 }
153 return kwtbl[1];
154 }
155 kwtbl += *kwtbl;
156 } while (*kwtbl);
157 }
158 return 0;
159}
160
161/* Add or delete a route, depending on action. */
162
163static NOINLINE void INET_setroute(int action, char **args)
164{
165 /* char buffer instead of bona-fide struct avoids aliasing warning */
166 char rt_buf[sizeof(struct rtentry)];
167 struct rtentry *const rt = (void *)rt_buf;
168
169 const char *netmask = NULL;
170 int skfd, isnet, xflag;
171
172 /* Grab the -net or -host options. Remember they were transformed. */
173 xflag = kw_lookup(tbl_hash_net_host, &args);
174
175 /* If we did grab -net or -host, make sure we still have an arg left. */
176 if (*args == NULL) {
177 bb_show_usage();
178 }
179
180 /* Clean out the RTREQ structure. */
181 memset(rt, 0, sizeof(*rt));
182
183 {
184 const char *target = *args++;
185 char *prefix;
186
187 /* recognize x.x.x.x/mask format. */
188 prefix = strchr(target, '/');
189 if (prefix) {
190 int prefix_len;
191
192 prefix_len = xatoul_range(prefix+1, 0, 32);
193 mask_in_addr(*rt) = htonl( ~(0xffffffffUL >> prefix_len));
194 *prefix = '\0';
195#if HAVE_NEW_ADDRT
196 rt->rt_genmask.sa_family = AF_INET;
197#endif
198 } else {
199 /* Default netmask. */
200 netmask = "default";
201 }
202 /* Prefer hostname lookup is -host flag (xflag==1) was given. */
203 isnet = INET_resolve(target, (struct sockaddr_in *) &rt->rt_dst,
204 (xflag & HOST_FLAG));
205 if (isnet < 0) {
206 bb_error_msg_and_die("resolving %s", target);
207 }
208 if (prefix) {
209 /* do not destroy prefix for process args */
210 *prefix = '/';
211 }
212 }
213
214 if (xflag) { /* Reinit isnet if -net or -host was specified. */
215 isnet = (xflag & NET_FLAG);
216 }
217
218 /* Fill in the other fields. */
219 rt->rt_flags = ((isnet) ? RTF_UP : (RTF_UP | RTF_HOST));
220
221 while (*args) {
222 int k = kw_lookup(tbl_ipvx, &args);
223 const char *args_m1 = args[-1];
224
225 if (k & KW_IPVx_FLAG_ONLY) {
226 rt->rt_flags |= flags_ipvx[k & 3];
227 continue;
228 }
229
230#if HAVE_NEW_ADDRT
231 if (k == KW_IPVx_METRIC) {
232 rt->rt_metric = xatoul(args_m1) + 1;
233 continue;
234 }
235#endif
236
237 if (k == KW_IPVx_NETMASK) {
238 struct sockaddr mask;
239
240 if (mask_in_addr(*rt)) {
241 bb_show_usage();
242 }
243
244 netmask = args_m1;
245 isnet = INET_resolve(netmask, (struct sockaddr_in *) &mask, 0);
246 if (isnet < 0) {
247 bb_error_msg_and_die("resolving %s", netmask);
248 }
249 rt->rt_genmask = full_mask(mask);
250 continue;
251 }
252
253 if (k == KW_IPVx_GATEWAY) {
254 if (rt->rt_flags & RTF_GATEWAY) {
255 bb_show_usage();
256 }
257
258 isnet = INET_resolve(args_m1,
259 (struct sockaddr_in *) &rt->rt_gateway, 1);
260 rt->rt_flags |= RTF_GATEWAY;
261
262 if (isnet) {
263 if (isnet < 0) {
264 bb_error_msg_and_die("resolving %s", args_m1);
265 }
266 bb_error_msg_and_die("gateway %s is a NETWORK", args_m1);
267 }
268 continue;
269 }
270
271 if (k == KW_IPVx_MSS) { /* Check valid MSS bounds. */
272 rt->rt_flags |= RTF_MSS;
273 rt->rt_mss = xatoul_range(args_m1, 64, 32768);
274 continue;
275 }
276
277 if (k == KW_IPVx_WINDOW) { /* Check valid window bounds. */
278 rt->rt_flags |= RTF_WINDOW;
279 rt->rt_window = xatoul_range(args_m1, 128, INT_MAX);
280 continue;
281 }
282
283#ifdef RTF_IRTT
284 if (k == KW_IPVx_IRTT) {
285 rt->rt_flags |= RTF_IRTT;
286 rt->rt_irtt = xatoul(args_m1);
287 rt->rt_irtt *= (bb_clk_tck() / 100); /* FIXME */
288#if 0 /* FIXME: do we need to check anything of this? */
289 if (rt->rt_irtt < 1 || rt->rt_irtt > (120 * HZ)) {
290 bb_error_msg_and_die("bad irtt");
291 }
292#endif
293 continue;
294 }
295#endif
296
297 /* Device is special in that it can be the last arg specified
298 * and doesn't requre the dev/device keyword in that case. */
299 if (!rt->rt_dev && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) {
300 /* Don't use args_m1 here since args may have changed! */
301 rt->rt_dev = args[-1];
302 continue;
303 }
304
305 /* Nothing matched. */
306 bb_show_usage();
307 }
308
309#ifdef RTF_REJECT
310 if ((rt->rt_flags & RTF_REJECT) && !rt->rt_dev) {
311 rt->rt_dev = (char*)"lo";
312 }
313#endif
314
315 /* sanity checks.. */
316 if (mask_in_addr(*rt)) {
317 uint32_t mask = mask_in_addr(*rt);
318
319 mask = ~ntohl(mask);
320 if ((rt->rt_flags & RTF_HOST) && mask != 0xffffffff) {
321 bb_error_msg_and_die("netmask %.8x and host route conflict",
322 (unsigned int) mask);
323 }
324 if (mask & (mask + 1)) {
325 bb_error_msg_and_die("bogus netmask %s", netmask);
326 }
327 mask = ((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr;
328 if (mask & ~(uint32_t)mask_in_addr(*rt)) {
329 bb_error_msg_and_die("netmask and route address conflict");
330 }
331 }
332
333 /* Fill out netmask if still unset */
334 if ((action == RTACTION_ADD) && (rt->rt_flags & RTF_HOST)) {
335 mask_in_addr(*rt) = 0xffffffff;
336 }
337
338 /* Create a socket to the INET kernel. */
339 skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
340
341 if (action == RTACTION_ADD)
342 xioctl(skfd, SIOCADDRT, rt);
343 else
344 xioctl(skfd, SIOCDELRT, rt);
345
346 if (ENABLE_FEATURE_CLEAN_UP) close(skfd);
347}
348
349#if ENABLE_FEATURE_IPV6
350
351static NOINLINE void INET6_setroute(int action, char **args)
352{
353 struct sockaddr_in6 sa6;
354 struct in6_rtmsg rt;
355 int prefix_len, skfd;
356 const char *devname;
357
358 /* We know args isn't NULL from the check in route_main. */
359 const char *target = *args++;
360
361 if (strcmp(target, "default") == 0) {
362 prefix_len = 0;
363 memset(&sa6, 0, sizeof(sa6));
364 } else {
365 char *cp;
366 cp = strchr(target, '/'); /* Yes... const to non is ok. */
367 if (cp) {
368 *cp = '\0';
369 prefix_len = xatoul_range(cp + 1, 0, 128);
370 } else {
371 prefix_len = 128;
372 }
373 if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) {
374 bb_error_msg_and_die("resolving %s", target);
375 }
376 }
377
378 /* Clean out the RTREQ structure. */
379 memset(&rt, 0, sizeof(rt));
380
381 memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
382
383 /* Fill in the other fields. */
384 rt.rtmsg_dst_len = prefix_len;
385 rt.rtmsg_flags = ((prefix_len == 128) ? (RTF_UP|RTF_HOST) : RTF_UP);
386 rt.rtmsg_metric = 1;
387
388 devname = NULL;
389
390 while (*args) {
391 int k = kw_lookup(tbl_ipvx, &args);
392 const char *args_m1 = args[-1];
393
394 if ((k == KW_IPVx_MOD) || (k == KW_IPVx_DYN)) {
395 rt.rtmsg_flags |= flags_ipvx[k & 3];
396 continue;
397 }
398
399 if (k == KW_IPVx_METRIC) {
400 rt.rtmsg_metric = xatoul(args_m1);
401 continue;
402 }
403
404 if (k == KW_IPVx_GATEWAY) {
405 if (rt.rtmsg_flags & RTF_GATEWAY) {
406 bb_show_usage();
407 }
408
409 if (INET6_resolve(args_m1, (struct sockaddr_in6 *) &sa6) < 0) {
410 bb_error_msg_and_die("resolving %s", args_m1);
411 }
412 memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
413 sizeof(struct in6_addr));
414 rt.rtmsg_flags |= RTF_GATEWAY;
415 continue;
416 }
417
418 /* Device is special in that it can be the last arg specified
419 * and doesn't requre the dev/device keyword in that case. */
420 if (!devname && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) {
421 /* Don't use args_m1 here since args may have changed! */
422 devname = args[-1];
423 continue;
424 }
425
426 /* Nothing matched. */
427 bb_show_usage();
428 }
429
430 /* Create a socket to the INET6 kernel. */
431 skfd = xsocket(AF_INET6, SOCK_DGRAM, 0);
432
433 rt.rtmsg_ifindex = 0;
434
435 if (devname) {
436 struct ifreq ifr;
437 memset(&ifr, 0, sizeof(ifr));
438 strncpy_IFNAMSIZ(ifr.ifr_name, devname);
439 xioctl(skfd, SIOCGIFINDEX, &ifr);
440 rt.rtmsg_ifindex = ifr.ifr_ifindex;
441 }
442
443 /* Tell the kernel to accept this route. */
444 if (action == RTACTION_ADD)
445 xioctl(skfd, SIOCADDRT, &rt);
446 else
447 xioctl(skfd, SIOCDELRT, &rt);
448
449 if (ENABLE_FEATURE_CLEAN_UP) close(skfd);
450}
451#endif
452
453static const
454IF_NOT_FEATURE_IPV6(uint16_t)
455IF_FEATURE_IPV6(unsigned)
456flagvals[] = { /* Must agree with flagchars[]. */
457 RTF_UP,
458 RTF_GATEWAY,
459 RTF_HOST,
460 RTF_REINSTATE,
461 RTF_DYNAMIC,
462 RTF_MODIFIED,
463#if ENABLE_FEATURE_IPV6
464 RTF_DEFAULT,
465 RTF_ADDRCONF,
466 RTF_CACHE,
467 RTF_REJECT,
468 RTF_NONEXTHOP, /* this one doesn't fit into 16 bits */
469#endif
470};
471/* Must agree with flagvals[]. */
472static const char flagchars[] ALIGN1 =
473 "UGHRDM"
474#if ENABLE_FEATURE_IPV6
475 "DAC!n"
476#endif
477;
478#define IPV4_MASK (RTF_UP|RTF_GATEWAY|RTF_HOST|RTF_REINSTATE|RTF_DYNAMIC|RTF_MODIFIED)
479#define IPV6_MASK (RTF_UP|RTF_GATEWAY|RTF_HOST|RTF_DEFAULT|RTF_ADDRCONF|RTF_CACHE|RTF_REJECT|RTF_NONEXTHOP)
480
481static void set_flags(char *flagstr, int flags)
482{
483 int i;
484
485 for (i = 0; (*flagstr = flagchars[i]) != 0; i++) {
486 if (flags & flagvals[i]) {
487 ++flagstr;
488 }
489 }
490}
491
492/* also used in netstat */
493void FAST_FUNC bb_displayroutes(int noresolve, int netstatfmt)
494{
495 char devname[64], flags[16], *sdest, *sgw;
496 unsigned long d, g, m;
497 int r;
498 int flgs, ref, use, metric, mtu, win, ir;
499 struct sockaddr_in s_addr;
500 struct in_addr mask;
501
502 FILE *fp = xfopen_for_read("/proc/net/route");
503
504 printf("Kernel IP routing table\n"
505 "Destination Gateway Genmask Flags %s Iface\n",
506 netstatfmt ? " MSS Window irtt" : "Metric Ref Use");
507
508 /* Skip the first line. */
509 r = fscanf(fp, "%*[^\n]\n");
510 if (r < 0) {
511 /* Empty line, read error, or EOF. Yes, if routing table
512 * is completely empty, /proc/net/route has no header.
513 */
514 goto ERROR;
515 }
516 while (1) {
517 r = fscanf(fp, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n",
518 devname, &d, &g, &flgs, &ref, &use, &metric, &m,
519 &mtu, &win, &ir);
520 if (r != 11) {
521 ERROR:
522 if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */
523 break;
524 }
525 bb_perror_msg_and_die(bb_msg_read_error);
526 }
527
528 if (!(flgs & RTF_UP)) { /* Skip interfaces that are down. */
529 continue;
530 }
531
532 set_flags(flags, (flgs & IPV4_MASK));
533#ifdef RTF_REJECT
534 if (flgs & RTF_REJECT) {
535 flags[0] = '!';
536 }
537#endif
538
539 memset(&s_addr, 0, sizeof(struct sockaddr_in));
540 s_addr.sin_family = AF_INET;
541 s_addr.sin_addr.s_addr = d;
542 sdest = INET_rresolve(&s_addr, (noresolve | 0x8000), m); /* 'default' instead of '*' */
543 s_addr.sin_addr.s_addr = g;
544 sgw = INET_rresolve(&s_addr, (noresolve | 0x4000), m); /* Host instead of net */
545 mask.s_addr = m;
546 /* "%15.15s" truncates hostnames, do we really want that? */
547 printf("%-15.15s %-15.15s %-16s%-6s", sdest, sgw, inet_ntoa(mask), flags);
548 free(sdest);
549 free(sgw);
550 if (netstatfmt) {
551 printf("%5d %-5d %6d %s\n", mtu, win, ir, devname);
552 } else {
553 printf("%-6d %-2d %7d %s\n", metric, ref, use, devname);
554 }
555 }
556 fclose(fp);
557}
558
559#if ENABLE_FEATURE_IPV6
560
561static void INET6_displayroutes(void)
562{
563 char addr6[128], *naddr6;
564 /* In addr6x, we store both 40-byte ':'-delimited ipv6 addresses.
565 * We read the non-delimited strings into the tail of the buffer
566 * using fscanf and then modify the buffer by shifting forward
567 * while inserting ':'s and the nul terminator for the first string.
568 * Hence the strings are at addr6x and addr6x+40. This generates
569 * _much_ less code than the previous (upstream) approach. */
570 char addr6x[80];
571 char iface[16], flags[16];
572 int iflags, metric, refcnt, use, prefix_len, slen;
573 struct sockaddr_in6 snaddr6;
574
575 FILE *fp = xfopen_for_read("/proc/net/ipv6_route");
576
577 printf("Kernel IPv6 routing table\n%-44s%-40s"
578 "Flags Metric Ref Use Iface\n",
579 "Destination", "Next Hop");
580
581 while (1) {
582 int r;
583 r = fscanf(fp, "%32s%x%*s%x%32s%x%x%x%x%s\n",
584 addr6x+14, &prefix_len, &slen, addr6x+40+7,
585 &metric, &refcnt, &use, &iflags, iface);
586 if (r != 9) {
587 if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */
588 break;
589 }
590 ERROR:
591 bb_perror_msg_and_die(bb_msg_read_error);
592 }
593
594 /* Do the addr6x shift-and-insert changes to ':'-delimit addresses.
595 * For now, always do this to validate the proc route format, even
596 * if the interface is down. */
597 {
598 int i = 0;
599 char *p = addr6x+14;
600
601 do {
602 if (!*p) {
603 if (i == 40) { /* nul terminator for 1st address? */
604 addr6x[39] = 0; /* Fixup... need 0 instead of ':'. */
605 ++p; /* Skip and continue. */
606 continue;
607 }
608 goto ERROR;
609 }
610 addr6x[i++] = *p++;
611 if (!((i+1) % 5)) {
612 addr6x[i++] = ':';
613 }
614 } while (i < 40+28+7);
615 }
616
617 set_flags(flags, (iflags & IPV6_MASK));
618
619 r = 0;
620 while (1) {
621 inet_pton(AF_INET6, addr6x + r,
622 (struct sockaddr *) &snaddr6.sin6_addr);
623 snaddr6.sin6_family = AF_INET6;
624 naddr6 = INET6_rresolve((struct sockaddr_in6 *) &snaddr6,
625 0x0fff /* Apparently, upstream never resolves. */
626 );
627
628 if (!r) { /* 1st pass */
629 snprintf(addr6, sizeof(addr6), "%s/%d", naddr6, prefix_len);
630 r += 40;
631 free(naddr6);
632 } else { /* 2nd pass */
633 /* Print the info. */
634 printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
635 addr6, naddr6, flags, metric, refcnt, use, iface);
636 free(naddr6);
637 break;
638 }
639 }
640 }
641 fclose(fp);
642}
643
644#endif
645
646#define ROUTE_OPT_A 0x01
647#define ROUTE_OPT_n 0x02
648#define ROUTE_OPT_e 0x04
649#define ROUTE_OPT_INET6 0x08 /* Not an actual option. See below. */
650
651/* 1st byte is offset to next entry offset. 2nd byte is return value. */
652/* 2nd byte matches RTACTION_* code */
653static const char tbl_verb[] ALIGN1 =
654 "\006\001add\0"
655 "\006\002del\0"
656/* "\011\002delete\0" */
657 "\010\002delete" /* Since it's last, we can save a byte. */
658;
659
660int route_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
661int route_main(int argc UNUSED_PARAM, char **argv)
662{
663 unsigned opt;
664 int what;
665 char *family;
666 char **p;
667
668 /* First, remap '-net' and '-host' to avoid getopt problems. */
669 p = argv;
670 while (*++p) {
671 if (strcmp(*p, "-net") == 0 || strcmp(*p, "-host") == 0) {
672 p[0][0] = '#';
673 }
674 }
675
676 opt = getopt32(argv, "A:ne", &family);
677
678 if ((opt & ROUTE_OPT_A) && strcmp(family, "inet") != 0) {
679#if ENABLE_FEATURE_IPV6
680 if (strcmp(family, "inet6") == 0) {
681 opt |= ROUTE_OPT_INET6; /* Set flag for ipv6. */
682 } else
683#endif
684 bb_show_usage();
685 }
686
687 argv += optind;
688
689 /* No more args means display the routing table. */
690 if (!*argv) {
691 int noresolve = (opt & ROUTE_OPT_n) ? 0x0fff : 0;
692#if ENABLE_FEATURE_IPV6
693 if (opt & ROUTE_OPT_INET6)
694 INET6_displayroutes();
695 else
696#endif
697 bb_displayroutes(noresolve, opt & ROUTE_OPT_e);
698
699 fflush_stdout_and_exit(EXIT_SUCCESS);
700 }
701
702 /* Check verb. At the moment, must be add, del, or delete. */
703 what = kw_lookup(tbl_verb, &argv);
704 if (!what || !*argv) { /* Unknown verb or no more args. */
705 bb_show_usage();
706 }
707
708#if ENABLE_FEATURE_IPV6
709 if (opt & ROUTE_OPT_INET6)
710 INET6_setroute(what, argv);
711 else
712#endif
713 INET_setroute(what, argv);
714
715 return EXIT_SUCCESS;
716}
Note: See TracBrowser for help on using the repository browser.