diff options
author | Eric Andersen <andersen@codepoet.org> | 2002-07-03 11:46:38 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2002-07-03 11:46:38 +0000 |
commit | 51b8bd68bb22b1cc5d95e418813c2f08a194ec2b (patch) | |
tree | 905d4f1b1e557950272ac98e1540fa06f732f42f /networking/route.c | |
parent | 599e3ce163c43c3dfb24d06f8f707c783bc9ab9c (diff) | |
download | busybox-w32-51b8bd68bb22b1cc5d95e418813c2f08a194ec2b.tar.gz busybox-w32-51b8bd68bb22b1cc5d95e418813c2f08a194ec2b.tar.bz2 busybox-w32-51b8bd68bb22b1cc5d95e418813c2f08a194ec2b.zip |
This patch from Bart Visscher <magick@linux-fan.com> adds
IPV6 support to busybox. This patch does the following:
* Add IPv6 support to libbb
* Enable IPv6 interface address display
* Add IPv6 config option
* Adds ping6, an adaptation of the ping applet for IPv6
* Adds support routines for ping6:
- xgethostbyname2
- create_icmp6_socket
* Adds ifconfig support for IPv6
* Add support IPv6 to netstat
* Add IPv6 support to route
Thanks Bart!
Diffstat (limited to 'networking/route.c')
-rw-r--r-- | networking/route.c | 243 |
1 files changed, 240 insertions, 3 deletions
diff --git a/networking/route.c b/networking/route.c index 26162ee87..76e76b4b7 100644 --- a/networking/route.c +++ b/networking/route.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* route | 1 | /* route |
2 | * | 2 | * |
3 | * Similar to the standard Unix route, but with only the necessary | 3 | * Similar to the standard Unix route, but with only the necessary |
4 | * parts for AF_INET | 4 | * parts for AF_INET and AF_INET6 |
5 | * | 5 | * |
6 | * Bjorn Wesen, Axis Communications AB | 6 | * Bjorn Wesen, Axis Communications AB |
7 | * | 7 | * |
@@ -15,16 +15,19 @@ | |||
15 | * Foundation; either version 2 of the License, or (at | 15 | * Foundation; either version 2 of the License, or (at |
16 | * your option) any later version. | 16 | * your option) any later version. |
17 | * | 17 | * |
18 | * $Id: route.c,v 1.16 2002/05/16 19:14:15 sandman Exp $ | 18 | * $Id: route.c,v 1.17 2002/07/03 11:46:34 andersen Exp $ |
19 | * | 19 | * |
20 | * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru> | 20 | * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru> |
21 | * adjustments by Larry Doolittle <LRDoolittle@lbl.gov> | 21 | * adjustments by Larry Doolittle <LRDoolittle@lbl.gov> |
22 | * | ||
23 | * IPV6 support added by Bart Visscher <magick@linux-fan.com> | ||
22 | */ | 24 | */ |
23 | 25 | ||
24 | #include <sys/types.h> | 26 | #include <sys/types.h> |
25 | #include <sys/ioctl.h> | 27 | #include <sys/ioctl.h> |
26 | #include "inet_common.h" | 28 | #include "inet_common.h" |
27 | #include <net/route.h> | 29 | #include <net/route.h> |
30 | #include <net/if.h> | ||
28 | #include <linux/param.h> // HZ | 31 | #include <linux/param.h> // HZ |
29 | #include <stdio.h> | 32 | #include <stdio.h> |
30 | #include <errno.h> | 33 | #include <errno.h> |
@@ -325,6 +328,139 @@ INET_setroute(int action, int options, char **args) | |||
325 | return EXIT_SUCCESS; | 328 | return EXIT_SUCCESS; |
326 | } | 329 | } |
327 | 330 | ||
331 | #if CONFIG_FEATURE_IPV6 | ||
332 | static int INET6_setroute(int action, int options, char **args) | ||
333 | { | ||
334 | struct in6_rtmsg rt; | ||
335 | struct ifreq ifr; | ||
336 | struct sockaddr_in6 sa6; | ||
337 | char target[128], gateway[128] = "NONE"; | ||
338 | int metric, prefix_len; | ||
339 | char *devname = NULL; | ||
340 | char *cp; | ||
341 | int skfd; | ||
342 | |||
343 | if (*args == NULL) | ||
344 | show_usage(); | ||
345 | |||
346 | strcpy(target, *args++); | ||
347 | if (!strcmp(target, "default")) { | ||
348 | prefix_len = 0; | ||
349 | memset(&sa6, 0, sizeof(sa6)); | ||
350 | } else { | ||
351 | if ((cp = strchr(target, '/'))) { | ||
352 | prefix_len = atol(cp + 1); | ||
353 | if ((prefix_len < 0) || (prefix_len > 128)) | ||
354 | show_usage(); | ||
355 | *cp = 0; | ||
356 | } else { | ||
357 | prefix_len = 128; | ||
358 | } | ||
359 | if (INET6_resolve(target, (struct sockaddr_in6 *)&sa6) < 0) { | ||
360 | error_msg(_("can't resolve %s"), target); | ||
361 | return EXIT_FAILURE; /* XXX change to E_something */ | ||
362 | } | ||
363 | } | ||
364 | |||
365 | /* Clean out the RTREQ structure. */ | ||
366 | memset((char *) &rt, 0, sizeof(struct in6_rtmsg)); | ||
367 | |||
368 | memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr)); | ||
369 | |||
370 | /* Fill in the other fields. */ | ||
371 | rt.rtmsg_flags = RTF_UP; | ||
372 | if (prefix_len == 128) | ||
373 | rt.rtmsg_flags |= RTF_HOST; | ||
374 | rt.rtmsg_metric = 1; | ||
375 | rt.rtmsg_dst_len = prefix_len; | ||
376 | |||
377 | while (*args) { | ||
378 | if (!strcmp(*args, "metric")) { | ||
379 | |||
380 | args++; | ||
381 | if (!*args || !isdigit(**args)) | ||
382 | show_usage(); | ||
383 | metric = atoi(*args); | ||
384 | rt.rtmsg_metric = metric; | ||
385 | args++; | ||
386 | continue; | ||
387 | } | ||
388 | if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) { | ||
389 | args++; | ||
390 | if (!*args) | ||
391 | show_usage(); | ||
392 | if (rt.rtmsg_flags & RTF_GATEWAY) | ||
393 | show_usage(); | ||
394 | strcpy(gateway, *args); | ||
395 | if (INET6_resolve(gateway, (struct sockaddr_in6 *)&sa6) < 0) { | ||
396 | error_msg(_("can't resolve gw %s"), gateway); | ||
397 | return (E_LOOKUP); | ||
398 | } | ||
399 | memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr, | ||
400 | sizeof(struct in6_addr)); | ||
401 | rt.rtmsg_flags |= RTF_GATEWAY; | ||
402 | args++; | ||
403 | continue; | ||
404 | } | ||
405 | if (!strcmp(*args, "mod")) { | ||
406 | args++; | ||
407 | rt.rtmsg_flags |= RTF_MODIFIED; | ||
408 | continue; | ||
409 | } | ||
410 | if (!strcmp(*args, "dyn")) { | ||
411 | args++; | ||
412 | rt.rtmsg_flags |= RTF_DYNAMIC; | ||
413 | continue; | ||
414 | } | ||
415 | if (!strcmp(*args, "device") || !strcmp(*args, "dev")) { | ||
416 | args++; | ||
417 | if (!*args) | ||
418 | show_usage(); | ||
419 | } else if (args[1]) | ||
420 | show_usage(); | ||
421 | |||
422 | devname = *args; | ||
423 | args++; | ||
424 | } | ||
425 | |||
426 | /* Create a socket to the INET6 kernel. */ | ||
427 | if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { | ||
428 | perror("socket"); | ||
429 | return (E_SOCK); | ||
430 | } | ||
431 | if (devname) { | ||
432 | memset(&ifr, 0, sizeof(ifr)); | ||
433 | strcpy(ifr.ifr_name, devname); | ||
434 | |||
435 | if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) { | ||
436 | perror("SIOGIFINDEX"); | ||
437 | return (E_SOCK); | ||
438 | } | ||
439 | rt.rtmsg_ifindex = ifr.ifr_ifindex; | ||
440 | } else | ||
441 | rt.rtmsg_ifindex = 0; | ||
442 | |||
443 | /* Tell the kernel to accept this route. */ | ||
444 | if (action == RTACTION_DEL) { | ||
445 | if (ioctl(skfd, SIOCDELRT, &rt) < 0) { | ||
446 | perror("SIOCDELRT"); | ||
447 | close(skfd); | ||
448 | return (E_SOCK); | ||
449 | } | ||
450 | } else { | ||
451 | if (ioctl(skfd, SIOCADDRT, &rt) < 0) { | ||
452 | perror("SIOCADDRT"); | ||
453 | close(skfd); | ||
454 | return (E_SOCK); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | /* Close the socket. */ | ||
459 | (void) close(skfd); | ||
460 | return (0); | ||
461 | } | ||
462 | #endif | ||
463 | |||
328 | #ifndef RTF_UP | 464 | #ifndef RTF_UP |
329 | /* Keep this in sync with /usr/src/linux/include/linux/route.h */ | 465 | /* Keep this in sync with /usr/src/linux/include/linux/route.h */ |
330 | #define RTF_UP 0x0001 /* route usable */ | 466 | #define RTF_UP 0x0001 /* route usable */ |
@@ -418,17 +554,103 @@ void displayroutes(int noresolve, int netstatfmt) | |||
418 | } | 554 | } |
419 | } | 555 | } |
420 | 556 | ||
557 | #if CONFIG_FEATURE_IPV6 | ||
558 | static void INET6_displayroutes(int noresolve) | ||
559 | { | ||
560 | char buff[256]; | ||
561 | char iface[16], flags[16]; | ||
562 | char addr6[128], naddr6[128]; | ||
563 | struct sockaddr_in6 saddr6, snaddr6; | ||
564 | int iflags, metric, refcnt, use, prefix_len, slen; | ||
565 | int numeric; | ||
566 | |||
567 | char addr6p[8][5], saddr6p[8][5], naddr6p[8][5]; | ||
568 | |||
569 | FILE *fp = xfopen("/proc/net/ipv6_route", "r"); | ||
570 | flags[0]='U'; | ||
571 | |||
572 | if(noresolve) | ||
573 | noresolve = 0x0fff; | ||
574 | numeric = noresolve | 0x8000; /* default instead of * */ | ||
575 | |||
576 | printf("Kernel IPv6 routing table\n" | ||
577 | "Destination " | ||
578 | "Next Hop " | ||
579 | "Flags Metric Ref Use Iface\n"); | ||
580 | |||
581 | while( fgets(buff, sizeof(buff), fp) != NULL ) { | ||
582 | int ifl; | ||
583 | |||
584 | if(sscanf(buff, "%4s%4s%4s%4s%4s%4s%4s%4s %02x " | ||
585 | "%4s%4s%4s%4s%4s%4s%4s%4s %02x " | ||
586 | "%4s%4s%4s%4s%4s%4s%4s%4s %08x %08x %08x %08x %s\n", | ||
587 | addr6p[0], addr6p[1], addr6p[2], addr6p[3], | ||
588 | addr6p[4], addr6p[5], addr6p[6], addr6p[7], | ||
589 | &prefix_len, | ||
590 | saddr6p[0], saddr6p[1], saddr6p[2], saddr6p[3], | ||
591 | saddr6p[4], saddr6p[5], saddr6p[6], saddr6p[7], | ||
592 | &slen, | ||
593 | naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3], | ||
594 | naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7], | ||
595 | &metric, &use, &refcnt, &iflags, iface)!=31) { | ||
596 | error_msg_and_die( "Unsuported kernel route format\n"); | ||
597 | } | ||
598 | |||
599 | ifl = 1; /* parse flags */ | ||
600 | if (!(iflags & RTF_UP)) | ||
601 | continue; | ||
602 | if (iflags & RTF_GATEWAY) | ||
603 | flags[ifl++]='G'; | ||
604 | if (iflags & RTF_HOST) | ||
605 | flags[ifl++]='H'; | ||
606 | if (iflags & RTF_DEFAULT) | ||
607 | flags[ifl++]='D'; | ||
608 | if (iflags & RTF_ADDRCONF) | ||
609 | flags[ifl++]='A'; | ||
610 | if (iflags & RTF_CACHE) | ||
611 | flags[ifl++]='C'; | ||
612 | flags[ifl]=0; | ||
613 | |||
614 | /* Fetch and resolve the target address. */ | ||
615 | snprintf(addr6, sizeof(addr6), "%s:%s:%s:%s:%s:%s:%s:%s", | ||
616 | addr6p[0], addr6p[1], addr6p[2], addr6p[3], | ||
617 | addr6p[4], addr6p[5], addr6p[6], addr6p[7]); | ||
618 | inet_pton(AF_INET6, addr6, (struct sockaddr *) &saddr6.sin6_addr); | ||
619 | saddr6.sin6_family=AF_INET6; | ||
620 | |||
621 | INET6_rresolve(addr6, sizeof(addr6), (struct sockaddr_in6 *) &saddr6, numeric); | ||
622 | snprintf(addr6, sizeof(addr6), "%s/%d", addr6, prefix_len); | ||
623 | |||
624 | /* Fetch and resolve the nexthop address. */ | ||
625 | snprintf(naddr6, sizeof(naddr6), "%s:%s:%s:%s:%s:%s:%s:%s", | ||
626 | naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3], | ||
627 | naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7]); | ||
628 | inet_pton(AF_INET6, naddr6, (struct sockaddr *) &snaddr6.sin6_addr); | ||
629 | snaddr6.sin6_family=AF_INET6; | ||
630 | |||
631 | INET6_rresolve(naddr6, sizeof(naddr6), (struct sockaddr_in6 *) &snaddr6, numeric); | ||
632 | |||
633 | /* Print the info. */ | ||
634 | printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n", | ||
635 | addr6, naddr6, flags, metric, refcnt, use, iface); | ||
636 | } | ||
637 | } | ||
638 | #endif | ||
639 | |||
421 | int route_main(int argc, char **argv) | 640 | int route_main(int argc, char **argv) |
422 | { | 641 | { |
423 | int opt; | 642 | int opt; |
424 | int what = 0; | 643 | int what = 0; |
644 | #if CONFIG_FEATURE_IPV6 | ||
645 | int af=AF_INET; | ||
646 | #endif | ||
425 | 647 | ||
426 | if ( !argv [1] || ( argv [1][0] == '-' )) { | 648 | if ( !argv [1] || ( argv [1][0] == '-' )) { |
427 | /* check options */ | 649 | /* check options */ |
428 | int noresolve = 0; | 650 | int noresolve = 0; |
429 | int extended = 0; | 651 | int extended = 0; |
430 | 652 | ||
431 | while ((opt = getopt(argc, argv, "ne")) > 0) { | 653 | while ((opt = getopt(argc, argv, "A:ne")) > 0) { |
432 | switch (opt) { | 654 | switch (opt) { |
433 | case 'n': | 655 | case 'n': |
434 | noresolve = 1; | 656 | noresolve = 1; |
@@ -436,11 +658,22 @@ int route_main(int argc, char **argv) | |||
436 | case 'e': | 658 | case 'e': |
437 | extended = 1; | 659 | extended = 1; |
438 | break; | 660 | break; |
661 | case 'A': | ||
662 | #if CONFIG_FEATURE_IPV6 | ||
663 | if (strcmp(optarg, "inet6")==0) | ||
664 | af=AF_INET6; | ||
665 | break; | ||
666 | #endif | ||
439 | default: | 667 | default: |
440 | show_usage ( ); | 668 | show_usage ( ); |
441 | } | 669 | } |
442 | } | 670 | } |
443 | 671 | ||
672 | #if CONFIG_FEATURE_IPV6 | ||
673 | if (af==AF_INET6) | ||
674 | INET6_displayroutes(*argv != NULL); | ||
675 | else | ||
676 | #endif | ||
444 | displayroutes ( noresolve, extended ); | 677 | displayroutes ( noresolve, extended ); |
445 | return EXIT_SUCCESS; | 678 | return EXIT_SUCCESS; |
446 | } else { | 679 | } else { |
@@ -455,5 +688,9 @@ int route_main(int argc, char **argv) | |||
455 | show_usage(); | 688 | show_usage(); |
456 | } | 689 | } |
457 | 690 | ||
691 | #if CONFIG_FEATURE_IPV6 | ||
692 | if (af==AF_INET6) | ||
693 | return INET6_setroute(what, 0, argv+2); | ||
694 | #endif | ||
458 | return INET_setroute(what, 0, argv+2 ); | 695 | return INET_setroute(what, 0, argv+2 ); |
459 | } | 696 | } |