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!
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
/* route
|
||||
*
|
||||
* Similar to the standard Unix route, but with only the necessary
|
||||
* parts for AF_INET
|
||||
* parts for AF_INET and AF_INET6
|
||||
*
|
||||
* Bjorn Wesen, Axis Communications AB
|
||||
*
|
||||
@ -15,16 +15,19 @@
|
||||
* Foundation; either version 2 of the License, or (at
|
||||
* your option) any later version.
|
||||
*
|
||||
* $Id: route.c,v 1.16 2002/05/16 19:14:15 sandman Exp $
|
||||
* $Id: route.c,v 1.17 2002/07/03 11:46:34 andersen Exp $
|
||||
*
|
||||
* displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
|
||||
* adjustments by Larry Doolittle <LRDoolittle@lbl.gov>
|
||||
*
|
||||
* IPV6 support added by Bart Visscher <magick@linux-fan.com>
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include "inet_common.h"
|
||||
#include <net/route.h>
|
||||
#include <net/if.h>
|
||||
#include <linux/param.h> // HZ
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
@ -325,6 +328,139 @@ INET_setroute(int action, int options, char **args)
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
#if CONFIG_FEATURE_IPV6
|
||||
static int INET6_setroute(int action, int options, char **args)
|
||||
{
|
||||
struct in6_rtmsg rt;
|
||||
struct ifreq ifr;
|
||||
struct sockaddr_in6 sa6;
|
||||
char target[128], gateway[128] = "NONE";
|
||||
int metric, prefix_len;
|
||||
char *devname = NULL;
|
||||
char *cp;
|
||||
int skfd;
|
||||
|
||||
if (*args == NULL)
|
||||
show_usage();
|
||||
|
||||
strcpy(target, *args++);
|
||||
if (!strcmp(target, "default")) {
|
||||
prefix_len = 0;
|
||||
memset(&sa6, 0, sizeof(sa6));
|
||||
} else {
|
||||
if ((cp = strchr(target, '/'))) {
|
||||
prefix_len = atol(cp + 1);
|
||||
if ((prefix_len < 0) || (prefix_len > 128))
|
||||
show_usage();
|
||||
*cp = 0;
|
||||
} else {
|
||||
prefix_len = 128;
|
||||
}
|
||||
if (INET6_resolve(target, (struct sockaddr_in6 *)&sa6) < 0) {
|
||||
error_msg(_("can't resolve %s"), target);
|
||||
return EXIT_FAILURE; /* XXX change to E_something */
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean out the RTREQ structure. */
|
||||
memset((char *) &rt, 0, sizeof(struct in6_rtmsg));
|
||||
|
||||
memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
|
||||
|
||||
/* Fill in the other fields. */
|
||||
rt.rtmsg_flags = RTF_UP;
|
||||
if (prefix_len == 128)
|
||||
rt.rtmsg_flags |= RTF_HOST;
|
||||
rt.rtmsg_metric = 1;
|
||||
rt.rtmsg_dst_len = prefix_len;
|
||||
|
||||
while (*args) {
|
||||
if (!strcmp(*args, "metric")) {
|
||||
|
||||
args++;
|
||||
if (!*args || !isdigit(**args))
|
||||
show_usage();
|
||||
metric = atoi(*args);
|
||||
rt.rtmsg_metric = metric;
|
||||
args++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(*args, "gw") || !strcmp(*args, "gateway")) {
|
||||
args++;
|
||||
if (!*args)
|
||||
show_usage();
|
||||
if (rt.rtmsg_flags & RTF_GATEWAY)
|
||||
show_usage();
|
||||
strcpy(gateway, *args);
|
||||
if (INET6_resolve(gateway, (struct sockaddr_in6 *)&sa6) < 0) {
|
||||
error_msg(_("can't resolve gw %s"), gateway);
|
||||
return (E_LOOKUP);
|
||||
}
|
||||
memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
|
||||
sizeof(struct in6_addr));
|
||||
rt.rtmsg_flags |= RTF_GATEWAY;
|
||||
args++;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(*args, "mod")) {
|
||||
args++;
|
||||
rt.rtmsg_flags |= RTF_MODIFIED;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(*args, "dyn")) {
|
||||
args++;
|
||||
rt.rtmsg_flags |= RTF_DYNAMIC;
|
||||
continue;
|
||||
}
|
||||
if (!strcmp(*args, "device") || !strcmp(*args, "dev")) {
|
||||
args++;
|
||||
if (!*args)
|
||||
show_usage();
|
||||
} else if (args[1])
|
||||
show_usage();
|
||||
|
||||
devname = *args;
|
||||
args++;
|
||||
}
|
||||
|
||||
/* Create a socket to the INET6 kernel. */
|
||||
if ((skfd = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
|
||||
perror("socket");
|
||||
return (E_SOCK);
|
||||
}
|
||||
if (devname) {
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, devname);
|
||||
|
||||
if (ioctl(skfd, SIOGIFINDEX, &ifr) < 0) {
|
||||
perror("SIOGIFINDEX");
|
||||
return (E_SOCK);
|
||||
}
|
||||
rt.rtmsg_ifindex = ifr.ifr_ifindex;
|
||||
} else
|
||||
rt.rtmsg_ifindex = 0;
|
||||
|
||||
/* Tell the kernel to accept this route. */
|
||||
if (action == RTACTION_DEL) {
|
||||
if (ioctl(skfd, SIOCDELRT, &rt) < 0) {
|
||||
perror("SIOCDELRT");
|
||||
close(skfd);
|
||||
return (E_SOCK);
|
||||
}
|
||||
} else {
|
||||
if (ioctl(skfd, SIOCADDRT, &rt) < 0) {
|
||||
perror("SIOCADDRT");
|
||||
close(skfd);
|
||||
return (E_SOCK);
|
||||
}
|
||||
}
|
||||
|
||||
/* Close the socket. */
|
||||
(void) close(skfd);
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef RTF_UP
|
||||
/* Keep this in sync with /usr/src/linux/include/linux/route.h */
|
||||
#define RTF_UP 0x0001 /* route usable */
|
||||
@ -418,17 +554,103 @@ void displayroutes(int noresolve, int netstatfmt)
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_FEATURE_IPV6
|
||||
static void INET6_displayroutes(int noresolve)
|
||||
{
|
||||
char buff[256];
|
||||
char iface[16], flags[16];
|
||||
char addr6[128], naddr6[128];
|
||||
struct sockaddr_in6 saddr6, snaddr6;
|
||||
int iflags, metric, refcnt, use, prefix_len, slen;
|
||||
int numeric;
|
||||
|
||||
char addr6p[8][5], saddr6p[8][5], naddr6p[8][5];
|
||||
|
||||
FILE *fp = xfopen("/proc/net/ipv6_route", "r");
|
||||
flags[0]='U';
|
||||
|
||||
if(noresolve)
|
||||
noresolve = 0x0fff;
|
||||
numeric = noresolve | 0x8000; /* default instead of * */
|
||||
|
||||
printf("Kernel IPv6 routing table\n"
|
||||
"Destination "
|
||||
"Next Hop "
|
||||
"Flags Metric Ref Use Iface\n");
|
||||
|
||||
while( fgets(buff, sizeof(buff), fp) != NULL ) {
|
||||
int ifl;
|
||||
|
||||
if(sscanf(buff, "%4s%4s%4s%4s%4s%4s%4s%4s %02x "
|
||||
"%4s%4s%4s%4s%4s%4s%4s%4s %02x "
|
||||
"%4s%4s%4s%4s%4s%4s%4s%4s %08x %08x %08x %08x %s\n",
|
||||
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
|
||||
addr6p[4], addr6p[5], addr6p[6], addr6p[7],
|
||||
&prefix_len,
|
||||
saddr6p[0], saddr6p[1], saddr6p[2], saddr6p[3],
|
||||
saddr6p[4], saddr6p[5], saddr6p[6], saddr6p[7],
|
||||
&slen,
|
||||
naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
|
||||
naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7],
|
||||
&metric, &use, &refcnt, &iflags, iface)!=31) {
|
||||
error_msg_and_die( "Unsuported kernel route format\n");
|
||||
}
|
||||
|
||||
ifl = 1; /* parse flags */
|
||||
if (!(iflags & RTF_UP))
|
||||
continue;
|
||||
if (iflags & RTF_GATEWAY)
|
||||
flags[ifl++]='G';
|
||||
if (iflags & RTF_HOST)
|
||||
flags[ifl++]='H';
|
||||
if (iflags & RTF_DEFAULT)
|
||||
flags[ifl++]='D';
|
||||
if (iflags & RTF_ADDRCONF)
|
||||
flags[ifl++]='A';
|
||||
if (iflags & RTF_CACHE)
|
||||
flags[ifl++]='C';
|
||||
flags[ifl]=0;
|
||||
|
||||
/* Fetch and resolve the target address. */
|
||||
snprintf(addr6, sizeof(addr6), "%s:%s:%s:%s:%s:%s:%s:%s",
|
||||
addr6p[0], addr6p[1], addr6p[2], addr6p[3],
|
||||
addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
|
||||
inet_pton(AF_INET6, addr6, (struct sockaddr *) &saddr6.sin6_addr);
|
||||
saddr6.sin6_family=AF_INET6;
|
||||
|
||||
INET6_rresolve(addr6, sizeof(addr6), (struct sockaddr_in6 *) &saddr6, numeric);
|
||||
snprintf(addr6, sizeof(addr6), "%s/%d", addr6, prefix_len);
|
||||
|
||||
/* Fetch and resolve the nexthop address. */
|
||||
snprintf(naddr6, sizeof(naddr6), "%s:%s:%s:%s:%s:%s:%s:%s",
|
||||
naddr6p[0], naddr6p[1], naddr6p[2], naddr6p[3],
|
||||
naddr6p[4], naddr6p[5], naddr6p[6], naddr6p[7]);
|
||||
inet_pton(AF_INET6, naddr6, (struct sockaddr *) &snaddr6.sin6_addr);
|
||||
snaddr6.sin6_family=AF_INET6;
|
||||
|
||||
INET6_rresolve(naddr6, sizeof(naddr6), (struct sockaddr_in6 *) &snaddr6, numeric);
|
||||
|
||||
/* Print the info. */
|
||||
printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
|
||||
addr6, naddr6, flags, metric, refcnt, use, iface);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
int route_main(int argc, char **argv)
|
||||
{
|
||||
int opt;
|
||||
int what = 0;
|
||||
#if CONFIG_FEATURE_IPV6
|
||||
int af=AF_INET;
|
||||
#endif
|
||||
|
||||
if ( !argv [1] || ( argv [1][0] == '-' )) {
|
||||
/* check options */
|
||||
int noresolve = 0;
|
||||
int extended = 0;
|
||||
|
||||
while ((opt = getopt(argc, argv, "ne")) > 0) {
|
||||
while ((opt = getopt(argc, argv, "A:ne")) > 0) {
|
||||
switch (opt) {
|
||||
case 'n':
|
||||
noresolve = 1;
|
||||
@ -436,11 +658,22 @@ int route_main(int argc, char **argv)
|
||||
case 'e':
|
||||
extended = 1;
|
||||
break;
|
||||
case 'A':
|
||||
#if CONFIG_FEATURE_IPV6
|
||||
if (strcmp(optarg, "inet6")==0)
|
||||
af=AF_INET6;
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
show_usage ( );
|
||||
}
|
||||
}
|
||||
|
||||
#if CONFIG_FEATURE_IPV6
|
||||
if (af==AF_INET6)
|
||||
INET6_displayroutes(*argv != NULL);
|
||||
else
|
||||
#endif
|
||||
displayroutes ( noresolve, extended );
|
||||
return EXIT_SUCCESS;
|
||||
} else {
|
||||
@ -455,5 +688,9 @@ int route_main(int argc, char **argv)
|
||||
show_usage();
|
||||
}
|
||||
|
||||
#if CONFIG_FEATURE_IPV6
|
||||
if (af==AF_INET6)
|
||||
return INET6_setroute(what, 0, argv+2);
|
||||
#endif
|
||||
return INET_setroute(what, 0, argv+2 );
|
||||
}
|
||||
|
Reference in New Issue
Block a user