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:
		| @@ -344,6 +344,9 @@ | ||||
| #ifdef CONFIG_PING | ||||
| 	APPLET(ping, ping_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||||
| #endif | ||||
| #ifdef CONFIG_PING6 | ||||
| 	APPLET(ping6, ping6_main, _BB_DIR_BIN, _BB_SUID_NEVER) | ||||
| #endif | ||||
| #ifdef CONFIG_PIVOT_ROOT | ||||
|  	APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN, _BB_SUID_NEVER) | ||||
| #endif | ||||
|   | ||||
| @@ -4,7 +4,7 @@ | ||||
|  * | ||||
|  * Heavily modified by Manuel Novoa III       Mar 12, 2001 | ||||
|  * | ||||
|  * Version:     $Id: inet_common.h,v 1.1 2001/11/10 12:18:42 andersen Exp $ | ||||
|  * Version:     $Id: inet_common.h,v 1.2 2002/07/03 11:46:38 andersen Exp $ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| @@ -28,3 +28,6 @@ extern int INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirs | ||||
|  */ | ||||
| extern int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in, | ||||
| 			 int numeric, unsigned int netmask); | ||||
|  | ||||
| extern int INET6_resolve(char *name, struct sockaddr_in6 *sin6); | ||||
| extern int INET6_rresolve(char *name, size_t len, struct sockaddr_in6 *sin6, int numeric); | ||||
|   | ||||
| @@ -233,7 +233,10 @@ extern void gz_close(int gunzip_pid); | ||||
| extern FILE *gz_open(FILE *compressed_file, int *pid); | ||||
|  | ||||
| extern struct hostent *xgethostbyname(const char *name); | ||||
| extern struct hostent *xgethostbyname2(const char *name, int af); | ||||
| extern int create_icmp_socket(void); | ||||
| extern int create_icmp6_socket(void); | ||||
| extern int xconnect(const char *host, const char *port); | ||||
|  | ||||
| char *dirname (char *path); | ||||
|  | ||||
|   | ||||
| @@ -733,12 +733,19 @@ | ||||
| #else | ||||
|   #define USAGE_IFCONFIG_OPT_A(a) | ||||
| #endif | ||||
| #ifdef CONFIG_FEATURE_IPV6 | ||||
|   #define USAGE_IPV6(a) a | ||||
| #else | ||||
|   #define USAGE_IPV6(a) | ||||
| #endif | ||||
|  | ||||
| #define ifconfig_trivial_usage \ | ||||
| 	USAGE_IFCONFIG_OPT_A("[-a]") " <interface> [<address>]" | ||||
| #define ifconfig_full_usage \ | ||||
| 	"configure a network interface\n\n" \ | ||||
| 	"Options:\n" \ | ||||
| 	USAGE_IPV6("[add <address>[/<prefixlen>]]\n") \ | ||||
| 	USAGE_IPV6("[del <address>[/<prefixlen>]]\n") \ | ||||
| 	"\t[[-]broadcast [<address>]]  [[-]pointopoint [<address>]]\n" \ | ||||
| 	"\t[netmask <address>]  [dstaddr <address>]\n" \ | ||||
| 	USAGE_SIOCSKEEPALIVE("\t[outfill <NN>] [keepalive <NN>]\n") \ | ||||
| @@ -1370,6 +1377,29 @@ | ||||
| 	"1 packets transmitted, 1 packets received, 0% packet loss\n" \ | ||||
| 	"round-trip min/avg/max = 20.1/20.1/20.1 ms\n"  | ||||
|  | ||||
| #ifndef CONFIG_FEATURE_FANCY_PING6 | ||||
| #define ping6_trivial_usage "host" | ||||
| #define ping6_full_usage    "Send ICMP ECHO_REQUEST packets to network hosts" | ||||
| #else | ||||
| #define ping6_trivial_usage \ | ||||
| 	"[OPTION]... host" | ||||
| #define ping6_full_usage \ | ||||
| 	"Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \ | ||||
| 	"Options:\n" \ | ||||
| 	"\t-c COUNT\tSend only COUNT pings.\n" \ | ||||
| 	"\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \ | ||||
| 	"\t-q\t\tQuiet mode, only displays output at start\n" \ | ||||
| 	"\t\t\tand when finished." | ||||
| #endif | ||||
| #define ping6_example_usage \ | ||||
| 	"$ ping6 ip6-localhost\n" \ | ||||
| 	"PING ip6-localhost (::1): 56 data bytes\n" \ | ||||
| 	"64 bytes from ::1: icmp6_seq=0 ttl=64 time=20.1 ms\n" \ | ||||
| 	"\n" \ | ||||
| 	"--- ip6-localhost ping statistics ---\n" \ | ||||
| 	"1 packets transmitted, 1 packets received, 0% packet loss\n" \ | ||||
| 	"round-trip min/avg/max = 20.1/20.1/20.1 ms\n"  | ||||
|  | ||||
| #define pivot_root_trivial_usage \ | ||||
| 	"NEW_ROOT PUT_OLD" | ||||
| #define pivot_root_full_usage \ | ||||
|   | ||||
| @@ -40,7 +40,9 @@ LIBBB_SRC:= \ | ||||
| 	dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \ | ||||
| 	simplify_path.c inet_common.c inode_hash.c obscure.c pwd2spwd.c xfuncs.c \ | ||||
| 	correct_password.c change_identity.c setup_environment.c run_shell.c \ | ||||
| 	pw_encrypt.c restricted_shell.c | ||||
| 	pw_encrypt.c restricted_shell.c xgethostbyname2.c create_icmp6_socket.c \ | ||||
| 	xconnect.c | ||||
|  | ||||
| LIBBB_OBJS=$(patsubst %.c,$(LIBBB_DIR)%.o, $(LIBBB_SRC)) | ||||
|  | ||||
| LIBBB_MSRC:=$(LIBBB_DIR)messages.c | ||||
|   | ||||
							
								
								
									
										39
									
								
								libbb/create_icmp6_socket.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								libbb/create_icmp6_socket.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * Utility routines. | ||||
|  * | ||||
|  * create raw socket for icmp (IPv6 version) protocol test permision | ||||
|  * and drop root privilegies if running setuid | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <sys/types.h> | ||||
| #include <netdb.h> | ||||
| #include <sys/socket.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include "libbb.h" | ||||
|  | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| int create_icmp6_socket(void) | ||||
| { | ||||
| 	struct protoent *proto; | ||||
| 	int sock; | ||||
|  | ||||
| 	proto = getprotobyname("ipv6-icmp"); | ||||
| 	/* if getprotobyname failed, just silently force | ||||
| 	 * proto->p_proto to have the correct value for "ipv6-icmp" */ | ||||
| 	if ((sock = socket(AF_INET6, SOCK_RAW, | ||||
| 			(proto ? proto->p_proto : IPPROTO_ICMPV6))) < 0) { | ||||
| 		if (errno == EPERM) | ||||
| 			error_msg_and_die("permission denied. (are you root?)"); | ||||
| 		else | ||||
| 			perror_msg_and_die(can_not_create_raw_socket); | ||||
| 	} | ||||
|  | ||||
| 	/* drop root privs if running setuid */ | ||||
| 	setuid(getuid()); | ||||
|  | ||||
| 	return sock; | ||||
| } | ||||
| #endif | ||||
| @@ -4,7 +4,7 @@ | ||||
|  * | ||||
|  * Heavily modified by Manuel Novoa III       Mar 12, 2001 | ||||
|  * | ||||
|  * Version:     $Id: inet_common.c,v 1.2 2002/06/06 12:11:55 andersen Exp $ | ||||
|  * Version:     $Id: inet_common.c,v 1.3 2002/07/03 11:46:36 andersen Exp $ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| @@ -177,3 +177,65 @@ int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in, | ||||
|  | ||||
|     return (0); | ||||
| } | ||||
|  | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
|  | ||||
| int INET6_resolve(char *name, struct sockaddr_in6 *sin6) | ||||
| { | ||||
|     struct addrinfo req, *ai; | ||||
|     int s; | ||||
|  | ||||
|     memset (&req, '\0', sizeof req); | ||||
|     req.ai_family = AF_INET6; | ||||
|     if ((s = getaddrinfo(name, NULL, &req, &ai))) { | ||||
| 	fprintf(stderr, "getaddrinfo: %s: %d\n", name, s); | ||||
| 	return -1; | ||||
|     } | ||||
|     memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6)); | ||||
|  | ||||
|     freeaddrinfo(ai); | ||||
|  | ||||
|     return (0); | ||||
| } | ||||
|  | ||||
| #ifndef IN6_IS_ADDR_UNSPECIFIED | ||||
| #define IN6_IS_ADDR_UNSPECIFIED(a) \ | ||||
|         (((__u32 *) (a))[0] == 0 && ((__u32 *) (a))[1] == 0 && \ | ||||
|          ((__u32 *) (a))[2] == 0 && ((__u32 *) (a))[3] == 0) | ||||
| #endif | ||||
|  | ||||
|  | ||||
| int INET6_rresolve(char *name, size_t len, struct sockaddr_in6 *sin6, int numeric) | ||||
| { | ||||
|     int s; | ||||
|  | ||||
|     /* Grmpf. -FvK */ | ||||
|     if (sin6->sin6_family != AF_INET6) { | ||||
| #ifdef DEBUG | ||||
| 	fprintf(stderr, _("rresolve: unsupport address family %d !\n"), | ||||
| 		sin6->sin6_family); | ||||
| #endif | ||||
| 	errno = EAFNOSUPPORT; | ||||
| 	return (-1); | ||||
|     } | ||||
|     if (numeric & 0x7FFF) { | ||||
| 	inet_ntop(AF_INET6, &sin6->sin6_addr, name, len); | ||||
| 	return (0); | ||||
|     } | ||||
|     if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { | ||||
|         if (numeric & 0x8000) | ||||
| 	    strcpy(name, "default"); | ||||
| 	else | ||||
| 	    strcpy(name, "*"); | ||||
| 	return (0); | ||||
|     } | ||||
|  | ||||
|     if ((s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6), | ||||
| 			 name, len , NULL, 0, 0))) { | ||||
| 	fputs("getnameinfo failed\n", stderr); | ||||
| 	return -1; | ||||
|     } | ||||
|     return (0); | ||||
| } | ||||
|  | ||||
| #endif	/* CONFIG_FEATURE_IPV6 */ | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|  *              that either displays or sets the characteristics of | ||||
|  *              one or more of the system's networking interfaces. | ||||
|  * | ||||
|  * Version:     $Id: interface.c,v 1.7 2001/11/10 11:22:46 andersen Exp $ | ||||
|  * Version:     $Id: interface.c,v 1.8 2002/07/03 11:46:36 andersen Exp $ | ||||
|  * | ||||
|  * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> | ||||
|  *              and others.  Copyright 1993 MicroWalt Corporation | ||||
| @@ -52,6 +52,10 @@ | ||||
| #undef HAVE_AFECONET | ||||
| #undef HAVE_AFASH | ||||
|  | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| #define HAVE_AFINET6 1 | ||||
| #endif | ||||
|  | ||||
| /*  | ||||
|  *  | ||||
|  * Device Hardware types. | ||||
| @@ -77,6 +81,7 @@ | ||||
|  | ||||
| #define _(x) x | ||||
| #define _PATH_PROCNET_DEV               "/proc/net/dev" | ||||
| #define _PATH_PROCNET_IFINET6           "/proc/net/if_inet6" | ||||
| #define new(p) ((p) = xcalloc(1,sizeof(*(p)))) | ||||
| #define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch)) | ||||
|  | ||||
| @@ -425,6 +430,76 @@ static struct aftype inet_aftype = | ||||
|  | ||||
| #endif				/* HAVE_AFINET */ | ||||
|  | ||||
| #if HAVE_AFINET6 | ||||
|  | ||||
| #ifdef KEEP_UNUSED | ||||
| static void INET6_reserror(char *text) | ||||
| { | ||||
|     herror(text); | ||||
| } | ||||
|  | ||||
| /* Display an Internet socket address. */ | ||||
| static char *INET6_print(unsigned char *ptr) | ||||
| { | ||||
|     static char name[80]; | ||||
|  | ||||
|     inet_ntop(AF_INET6, (struct in6_addr *) ptr, name, 80); | ||||
|     return name; | ||||
| } | ||||
| #endif /* KEEP_UNUSED */ | ||||
|  | ||||
| /* Display an Internet socket address. */ | ||||
| /* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */ | ||||
| static char *INET6_sprint(struct sockaddr *sap, int numeric) | ||||
| { | ||||
|     static char buff[128]; | ||||
|  | ||||
|     if (sap->sa_family == 0xFFFF || sap->sa_family == 0) | ||||
| 	return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff)); | ||||
|     if (INET6_rresolve(buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0) | ||||
| 	return safe_strncpy(buff, _("[UNKNOWN]"), sizeof(buff)); | ||||
|     return (buff); | ||||
| } | ||||
|  | ||||
| #ifdef KEEP_UNUSED | ||||
| static int INET6_getsock(char *bufp, struct sockaddr *sap) | ||||
| { | ||||
|     struct sockaddr_in6 *sin6; | ||||
|  | ||||
|     sin6 = (struct sockaddr_in6 *) sap; | ||||
|     sin6->sin6_family = AF_INET6; | ||||
|     sin6->sin6_port = 0; | ||||
|  | ||||
|     if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0) | ||||
| 	return (-1); | ||||
|  | ||||
|     return 16;			/* ?;) */ | ||||
| } | ||||
|  | ||||
| static int INET6_input(int type, char *bufp, struct sockaddr *sap) | ||||
| { | ||||
|     switch (type) { | ||||
|     case 1: | ||||
| 	return (INET6_getsock(bufp, sap)); | ||||
|     default: | ||||
| 	return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap)); | ||||
|     } | ||||
| } | ||||
| #endif /* KEEP_UNUSED */ | ||||
|  | ||||
| static struct aftype inet6_aftype = | ||||
| { | ||||
|     "inet6", "IPv6", AF_INET6, sizeof(struct in6_addr), | ||||
|     NULL /* UNUSED INET6_print */, INET6_sprint, | ||||
| 	NULL /* UNUSED INET6_input */, NULL /* UNUSED INET6_reserror */, | ||||
|     NULL /*INET6_rprint */ , NULL /*INET6_rinput */ , | ||||
|     NULL /* UNUSED INET6_getnetmask */, | ||||
|     -1, | ||||
|     NULL | ||||
| }; | ||||
|  | ||||
| #endif				/* HAVE_AFINET6 */ | ||||
|  | ||||
| /* Display an UNSPEC address. */ | ||||
| static char *UNSPEC_print(unsigned char *ptr) | ||||
| { | ||||
| @@ -1709,7 +1784,6 @@ static void ife_print(struct interface *ptr) | ||||
|     char addr6[40], devname[20]; | ||||
|     struct sockaddr_in6 sap; | ||||
|     int plen, scope, dad_status, if_idx; | ||||
|     extern struct aftype inet6_aftype; | ||||
|     char addr6p[8][5]; | ||||
| #endif | ||||
|  | ||||
| @@ -1756,8 +1830,24 @@ static void ife_print(struct interface *ptr) | ||||
| #endif | ||||
|  | ||||
| #if HAVE_AFINET6 | ||||
|     /* FIXME: should be integrated into interface.c.   */ | ||||
|  | ||||
| #define IPV6_ADDR_ANY           0x0000U | ||||
|  | ||||
| #define IPV6_ADDR_UNICAST       0x0001U | ||||
| #define IPV6_ADDR_MULTICAST     0x0002U | ||||
| #define IPV6_ADDR_ANYCAST       0x0004U | ||||
|  | ||||
| #define IPV6_ADDR_LOOPBACK      0x0010U | ||||
| #define IPV6_ADDR_LINKLOCAL     0x0020U | ||||
| #define IPV6_ADDR_SITELOCAL     0x0040U | ||||
|    | ||||
| #define IPV6_ADDR_COMPATv4      0x0080U | ||||
|      | ||||
| #define IPV6_ADDR_SCOPE_MASK    0x00f0U | ||||
|      | ||||
| #define IPV6_ADDR_MAPPED        0x1000U | ||||
| #define IPV6_ADDR_RESERVED      0x2000U         /* reserved address space */ | ||||
|      | ||||
|     if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { | ||||
| 	while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", | ||||
| 		      addr6p[0], addr6p[1], addr6p[2], addr6p[3], | ||||
| @@ -1767,11 +1857,12 @@ static void ife_print(struct interface *ptr) | ||||
| 		sprintf(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]); | ||||
| 		inet6_aftype.input(1, addr6, (struct sockaddr *) &sap); | ||||
| 		inet_pton(AF_INET6, addr6, (struct sockaddr *) &sap.sin6_addr); | ||||
| 		sap.sin6_family=AF_INET6; | ||||
| 		printf(_("          inet6 addr: %s/%d"), | ||||
| 		 inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen); | ||||
| 		printf(_(" Scope:")); | ||||
| 		switch (scope) { | ||||
| 		switch (scope & IPV6_ADDR_SCOPE_MASK) { | ||||
| 		case 0: | ||||
| 		    printf(_("Global")); | ||||
| 		    break; | ||||
|   | ||||
							
								
								
									
										37
									
								
								libbb/xgethostbyname2.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								libbb/xgethostbyname2.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * Mini xgethostbyname2 implementation. | ||||
|  * | ||||
|  * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>. | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <netdb.h> | ||||
| #include "libbb.h" | ||||
|  | ||||
|  | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| struct hostent *xgethostbyname2(const char *name, int af) | ||||
| { | ||||
| 	struct hostent *retval; | ||||
|  | ||||
| 	if ((retval = gethostbyname2(name, af)) == NULL) | ||||
| 		herror_msg_and_die("%s", name); | ||||
|  | ||||
| 	return retval; | ||||
| } | ||||
| #endif | ||||
| @@ -29,6 +29,7 @@ NETWORKING-$(CONFIG_NC)			+= nc.o | ||||
| NETWORKING-$(CONFIG_NETSTAT)		+= netstat.o | ||||
| NETWORKING-$(CONFIG_NSLOOKUP)		+= nslookup.o | ||||
| NETWORKING-$(CONFIG_PING)		+= ping.o | ||||
| NETWORKING-$(CONFIG_PING6)		+= ping6.o | ||||
| NETWORKING-$(CONFIG_ROUTE)		+= route.o | ||||
| NETWORKING-$(CONFIG_TELNET)		+= telnet.o | ||||
| NETWORKING-$(CONFIG_TFTP)		+= tftp.o | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| mainmenu_option next_comment | ||||
| comment 'Networking Utilities' | ||||
|  | ||||
| bool 'Enable IPv6 support'						CONFIG_FEATURE_IPV6 | ||||
| bool 'hostname'	    CONFIG_HOSTNAME | ||||
| bool 'ifconfig'	    CONFIG_IFCONFIG | ||||
| if [ "$CONFIG_IFCONFIG" = "y" ]; then | ||||
| @@ -22,6 +23,12 @@ bool 'ping'	    CONFIG_PING | ||||
| if [ "$CONFIG_PING" = "y" ]; then | ||||
|     bool '  Enable fancy ping output'		CONFIG_FEATURE_FANCY_PING | ||||
| fi | ||||
| if [ "$CONFIG_FEATURE_IPV6" = "y" ]; then | ||||
|     bool 'ping6'	    CONFIG_PING6 | ||||
|     if [ "$CONFIG_PING6" = "y" ]; then | ||||
|         bool '  Enable fancy ping6 output'		CONFIG_FEATURE_FANCY_PING6 | ||||
|     fi | ||||
| fi | ||||
| bool 'route'	    CONFIG_ROUTE | ||||
| bool 'telnet'	    CONFIG_TELNET | ||||
| if [ "$CONFIG_TELNET" = "y" ]; then | ||||
|   | ||||
| @@ -15,7 +15,7 @@ | ||||
|  * Foundation;  either  version 2 of the License, or  (at | ||||
|  * your option) any later version. | ||||
|  * | ||||
|  * $Id: ifconfig.c,v 1.16 2001/11/10 11:22:43 andersen Exp $ | ||||
|  * $Id: ifconfig.c,v 1.17 2002/07/03 11:46:34 andersen Exp $ | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| @@ -27,6 +27,9 @@ | ||||
|  * args missing from initial port. | ||||
|  * | ||||
|  * Still missing:  media, tunnel. | ||||
|  * | ||||
|  * 2002-04-20 | ||||
|  * IPV6 support added by Bart Visscher <magick@linux-fan.com> | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| @@ -65,6 +68,14 @@ | ||||
| #define IFF_DYNAMIC     0x8000  /* dialup device with changing addresses */ | ||||
| #endif | ||||
|  | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| struct in6_ifreq { | ||||
| 	struct in6_addr	ifr6_addr; | ||||
| 	uint32_t	ifr6_prefixlen; | ||||
| 	int		ifr6_ifindex;  | ||||
| }; | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * Here are the bit masks for the "flags" member of struct options below. | ||||
|  * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'. | ||||
| @@ -143,6 +154,7 @@ | ||||
| #define ARG_KEEPALIVE    (A_ARG_REQ | A_CAST_CHAR_PTR) | ||||
| #define ARG_OUTFILL      (A_ARG_REQ | A_CAST_CHAR_PTR) | ||||
| #define ARG_HOSTNAME     (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK) | ||||
| #define ARG_ADD_DEL      (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) | ||||
|  | ||||
|  | ||||
| /* | ||||
| @@ -187,6 +199,10 @@ static const struct arg1opt Arg1Opt[] = { | ||||
| 	{"SIOCSIFMAP",     SIOCSIFMAP,     ifreq_offsetof(ifr_map.irq)}, | ||||
| #endif | ||||
| 	/* Last entry if for unmatched (possibly hostname) arg. */ | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	{"SIOCSIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */ | ||||
| 	{"SIOCDIFADDR",    SIOCDIFADDR,    ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */ | ||||
| #endif | ||||
| 	{"SIOCSIFADDR",    SIOCSIFADDR,    ifreq_offsetof(ifr_addr)}, | ||||
| }; | ||||
|  | ||||
| @@ -211,6 +227,10 @@ static const struct options OptArray[] = { | ||||
| 	{"mem_start",    N_ARG,         ARG_MEM_START,   0}, | ||||
| 	{"io_addr",      N_ARG,         ARG_IO_ADDR,     0}, | ||||
| 	{"irq",          N_ARG,         ARG_IRQ,         0}, | ||||
| #endif | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	{"add",          N_ARG,         ARG_ADD_DEL,     0}, | ||||
| 	{"del",          N_ARG,         ARG_ADD_DEL,     0}, | ||||
| #endif | ||||
| 	{"arp",          N_CLR | M_SET, 0,               IFF_NOARP}, | ||||
| 	{"trailers",     N_CLR | M_SET, 0,               IFF_NOTRAILERS}, | ||||
| @@ -244,6 +264,9 @@ int ifconfig_main(int argc, char **argv) | ||||
| { | ||||
| 	struct ifreq ifr; | ||||
| 	struct sockaddr_in sai; | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	struct sockaddr_in6 sai6; | ||||
| #endif | ||||
| #ifdef CONFIG_FEATURE_IFCONFIG_HW | ||||
| 	struct sockaddr sa; | ||||
| #endif | ||||
| @@ -334,12 +357,54 @@ int ifconfig_main(int argc, char **argv) | ||||
| #ifdef CONFIG_FEATURE_IFCONFIG_HW | ||||
| 					if (mask & A_CAST_RESOLVE) { | ||||
| #endif | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 						char *prefix; | ||||
| 						int prefix_len=0; | ||||
| #endif | ||||
|  | ||||
| 						safe_strncpy(host, *argv, (sizeof host)); | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 						if ((prefix = strchr(host, '/'))) { | ||||
| 							prefix_len = atol(prefix + 1); | ||||
| 							if ((prefix_len < 0) || (prefix_len > 128)) { | ||||
| 								++goterr; | ||||
| 								goto LOOP; | ||||
| 							} | ||||
| 							*prefix = 0; | ||||
| 						} | ||||
| #endif | ||||
|  | ||||
| 						sai.sin_family = AF_INET; | ||||
| 						sai.sin_port = 0; | ||||
| 						if (!strcmp(host, bb_INET_default)) { | ||||
| 							/* Default is special, meaning 0.0.0.0. */ | ||||
| 							sai.sin_addr.s_addr = INADDR_ANY; | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 						} else | ||||
| 						if (inet_pton(AF_INET6, host, &sai6.sin6_addr) > 0) { | ||||
| 							int sockfd6; | ||||
| 							struct in6_ifreq ifr6; | ||||
| 							 | ||||
| 							memcpy((char *) &ifr6.ifr6_addr, (char *) &sai6.sin6_addr, | ||||
| 							                              sizeof(struct in6_addr)); | ||||
|  | ||||
| 							/* Create a channel to the NET kernel. */ | ||||
| 							if ((sockfd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { | ||||
| 								perror_msg_and_die("socket6"); | ||||
| 							} | ||||
| 							if (ioctl(sockfd6, SIOGIFINDEX, &ifr) < 0) { | ||||
| 								perror("SIOGIFINDEX"); | ||||
| 								++goterr; | ||||
| 							continue; | ||||
| 							} | ||||
| 							ifr6.ifr6_ifindex = ifr.ifr_ifindex; | ||||
| 							ifr6.ifr6_prefixlen = prefix_len; | ||||
| 							if (ioctl(sockfd6, a1op->selector, &ifr6) < 0) { | ||||
| 								perror(a1op->name); | ||||
| 								++goterr; | ||||
| 							} | ||||
| 							continue; | ||||
| #endif | ||||
| 						} else if (inet_aton(host, &sai.sin_addr) == 0) { | ||||
| 							/* It's not a dotted quad. */ | ||||
| 							++goterr; | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
|  * Mini netstat implementation(s) for busybox | ||||
|  * based in part on the netstat implementation from net-tools. | ||||
|  * | ||||
|  * Copyright (C) 2001 by Bart Visscher <magick@linux-fan.com> | ||||
|  * Copyright (C) 2002 by Bart Visscher <magick@linux-fan.com> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
| @@ -18,6 +18,9 @@ | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
|  * | ||||
|  * 2002-04-20 | ||||
|  * IPV6 support added by Bart Visscher <magick@linux-fan.com> | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| @@ -128,9 +131,17 @@ static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int | ||||
| { | ||||
| 	char *port_name; | ||||
|  | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	if (addr->sa_family == AF_INET6) { | ||||
| 		INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr, | ||||
| 					   (numeric&NETSTAT_NUMERIC) ? 0x0fff : 0); | ||||
| 	} else | ||||
| #endif | ||||
| 	{ | ||||
| 	INET_rresolve(ip_port, size, (struct sockaddr_in *)addr, | ||||
| 		0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0), | ||||
| 		0xffffffff); | ||||
| 	} | ||||
| 	port_name=get_sname(htons(port), proto, numeric); | ||||
| 	if ((strlen(ip_port) + strlen(port_name)) > 22) | ||||
| 		ip_port[22 - strlen(port_name)] = '\0'; | ||||
| @@ -145,7 +156,13 @@ static void tcp_do_one(int lnr, const char *line) | ||||
| 	const char *state_str; | ||||
| 	char more[512]; | ||||
| 	int num, local_port, rem_port, d, state, timer_run, uid, timeout; | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	struct sockaddr_in6 localaddr, remaddr; | ||||
| 	char addr6[INET6_ADDRSTRLEN]; | ||||
| 	struct in6_addr in6; | ||||
| #else | ||||
| 	struct sockaddr_in localaddr, remaddr; | ||||
| #endif | ||||
| 	unsigned long rxq, txq, time_len, retr, inode; | ||||
|  | ||||
| 	if (lnr == 0) | ||||
| @@ -159,6 +176,20 @@ static void tcp_do_one(int lnr, const char *line) | ||||
| 				 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); | ||||
|  | ||||
| 	if (strlen(local_addr) > 8) { | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 		sscanf(local_addr, "%08X%08X%08X%08X", | ||||
| 			   &in6.s6_addr32[0], &in6.s6_addr32[1], | ||||
| 			   &in6.s6_addr32[2], &in6.s6_addr32[3]); | ||||
| 		inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); | ||||
| 		inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr); | ||||
| 		sscanf(rem_addr, "%08X%08X%08X%08X", | ||||
| 			   &in6.s6_addr32[0], &in6.s6_addr32[1], | ||||
| 			   &in6.s6_addr32[2], &in6.s6_addr32[3]); | ||||
| 		inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); | ||||
| 		inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr); | ||||
| 		localaddr.sin6_family = AF_INET6; | ||||
| 		remaddr.sin6_family = AF_INET6; | ||||
| #endif | ||||
| 	} else { | ||||
| 		sscanf(local_addr, "%X", | ||||
| 			   &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); | ||||
| @@ -195,7 +226,13 @@ static void udp_do_one(int lnr, const char *line) | ||||
| 	char local_addr[64], rem_addr[64]; | ||||
| 	char *state_str, more[512]; | ||||
| 	int num, local_port, rem_port, d, state, timer_run, uid, timeout; | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	struct sockaddr_in6 localaddr, remaddr; | ||||
| 	char addr6[INET6_ADDRSTRLEN]; | ||||
| 	struct in6_addr in6; | ||||
| #else | ||||
| 	struct sockaddr_in localaddr, remaddr; | ||||
| #endif | ||||
| 	unsigned long rxq, txq, time_len, retr, inode; | ||||
|  | ||||
| 	if (lnr == 0) | ||||
| @@ -209,6 +246,21 @@ static void udp_do_one(int lnr, const char *line) | ||||
| 				 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); | ||||
|  | ||||
| 	if (strlen(local_addr) > 8) { | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
|         /* Demangle what the kernel gives us */ | ||||
| 		sscanf(local_addr, "%08X%08X%08X%08X", | ||||
| 			   &in6.s6_addr32[0], &in6.s6_addr32[1], | ||||
| 			   &in6.s6_addr32[2], &in6.s6_addr32[3]); | ||||
| 		inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); | ||||
| 		inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr); | ||||
| 		sscanf(rem_addr, "%08X%08X%08X%08X", | ||||
| 			   &in6.s6_addr32[0], &in6.s6_addr32[1], | ||||
| 			   &in6.s6_addr32[2], &in6.s6_addr32[3]); | ||||
| 		inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); | ||||
| 		inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr); | ||||
| 		localaddr.sin6_family = AF_INET6; | ||||
| 		remaddr.sin6_family = AF_INET6; | ||||
| #endif | ||||
| 	} else { | ||||
| 		sscanf(local_addr, "%X", | ||||
| 			   &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); | ||||
| @@ -236,7 +288,17 @@ static void udp_do_one(int lnr, const char *line) | ||||
| 			break; | ||||
| 	} | ||||
|  | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| #define notnull(A) (((A.sin6_family == AF_INET6) &&            \ | ||||
| 					 ((A.sin6_addr.s6_addr32[0]) ||            \ | ||||
| 					  (A.sin6_addr.s6_addr32[1]) ||            \ | ||||
| 					  (A.sin6_addr.s6_addr32[2]) ||            \ | ||||
| 					  (A.sin6_addr.s6_addr32[3]))) ||          \ | ||||
| 					((A.sin6_family == AF_INET) &&             \ | ||||
| 					 ((struct sockaddr_in *) &A)->sin_addr.s_addr)) | ||||
| #else | ||||
| #define notnull(A) (A.sin_addr.s_addr) | ||||
| #endif | ||||
| 	if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) || | ||||
| 		(!notnull(remaddr) && (flags&NETSTAT_LISTENING))) | ||||
| 	{ | ||||
| @@ -259,7 +321,13 @@ static void raw_do_one(int lnr, const char *line) | ||||
| 	char local_addr[64], rem_addr[64]; | ||||
| 	char *state_str, more[512]; | ||||
| 	int num, local_port, rem_port, d, state, timer_run, uid, timeout; | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	struct sockaddr_in6 localaddr, remaddr; | ||||
| 	char addr6[INET6_ADDRSTRLEN]; | ||||
| 	struct in6_addr in6; | ||||
| #else | ||||
| 	struct sockaddr_in localaddr, remaddr; | ||||
| #endif | ||||
| 	unsigned long rxq, txq, time_len, retr, inode; | ||||
|  | ||||
| 	if (lnr == 0) | ||||
| @@ -273,6 +341,20 @@ static void raw_do_one(int lnr, const char *line) | ||||
| 				 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); | ||||
|  | ||||
| 	if (strlen(local_addr) > 8) { | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 		sscanf(local_addr, "%08X%08X%08X%08X", | ||||
| 			   &in6.s6_addr32[0], &in6.s6_addr32[1], | ||||
| 			   &in6.s6_addr32[2], &in6.s6_addr32[3]); | ||||
| 		inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); | ||||
| 		inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr); | ||||
| 		sscanf(rem_addr, "%08X%08X%08X%08X", | ||||
| 			   &in6.s6_addr32[0], &in6.s6_addr32[1], | ||||
| 			   &in6.s6_addr32[2], &in6.s6_addr32[3]); | ||||
| 		inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6)); | ||||
| 		inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr); | ||||
| 		localaddr.sin6_family = AF_INET6; | ||||
| 		remaddr.sin6_family = AF_INET6; | ||||
| #endif | ||||
| 	} else { | ||||
| 		sscanf(local_addr, "%X", | ||||
| 			   &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); | ||||
| @@ -288,7 +370,17 @@ static void raw_do_one(int lnr, const char *line) | ||||
| 	} | ||||
| 	state_str=itoa(state); | ||||
|  | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| #define notnull(A) (((A.sin6_family == AF_INET6) &&            \ | ||||
| 					 ((A.sin6_addr.s6_addr32[0]) ||            \ | ||||
| 					  (A.sin6_addr.s6_addr32[1]) ||            \ | ||||
| 					  (A.sin6_addr.s6_addr32[2]) ||            \ | ||||
| 					  (A.sin6_addr.s6_addr32[3]))) ||          \ | ||||
| 					((A.sin6_family == AF_INET) &&             \ | ||||
| 					 ((struct sockaddr_in *) &A)->sin_addr.s_addr)) | ||||
| #else | ||||
| #define notnull(A) (A.sin_addr.s_addr) | ||||
| #endif | ||||
| 	if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) || | ||||
| 		(!notnull(remaddr) && (flags&NETSTAT_LISTENING))) | ||||
| 	{ | ||||
| @@ -429,8 +521,11 @@ static void unix_do_one(int nr, const char *line) | ||||
| } | ||||
|  | ||||
| #define _PATH_PROCNET_UDP "/proc/net/udp" | ||||
| #define _PATH_PROCNET_UDP6 "/proc/net/udp6" | ||||
| #define _PATH_PROCNET_TCP "/proc/net/tcp" | ||||
| #define _PATH_PROCNET_TCP6 "/proc/net/tcp6" | ||||
| #define _PATH_PROCNET_RAW "/proc/net/raw" | ||||
| #define _PATH_PROCNET_RAW6 "/proc/net/raw6" | ||||
| #define _PATH_PROCNET_UNIX "/proc/net/unix" | ||||
|  | ||||
| static void do_info(const char *file, const char *name, void (*proc)(int, const char *)) | ||||
| @@ -464,6 +559,13 @@ int netstat_main(int argc, char **argv) | ||||
| 	int opt; | ||||
| 	int new_flags=0; | ||||
| 	int showroute = 0, extended = 0;  | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	int inet=1; | ||||
| 	int inet6=1; | ||||
| #else | ||||
| #define inet 1 | ||||
| #define inet6 0 | ||||
| #endif | ||||
| 	while ((opt = getopt(argc, argv, "laenrtuwx")) != -1) | ||||
| 		switch (opt) { | ||||
| 		case 'l': | ||||
| @@ -523,12 +625,24 @@ int netstat_main(int argc, char **argv) | ||||
| 		} | ||||
| 		printf("\nProto Recv-Q Send-Q Local Address           Foreign Address         State      \n"); | ||||
| 	} | ||||
| 	if (flags&NETSTAT_TCP) | ||||
| 	if (inet && flags&NETSTAT_TCP) | ||||
| 		do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one); | ||||
| 	if (flags&NETSTAT_UDP) | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	if (inet6 && flags&NETSTAT_TCP) | ||||
| 		do_info(_PATH_PROCNET_TCP6,"AF INET6 (tcp)",tcp_do_one); | ||||
| #endif | ||||
| 	if (inet && flags&NETSTAT_UDP) | ||||
| 		do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one); | ||||
| 	if (flags&NETSTAT_RAW) | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	if (inet6 && flags&NETSTAT_UDP) | ||||
| 		do_info(_PATH_PROCNET_UDP6,"AF INET6 (udp)",udp_do_one); | ||||
| #endif | ||||
| 	if (inet && flags&NETSTAT_RAW) | ||||
| 		do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one); | ||||
| #if CONFIG_FEATURE_IPV6 | ||||
| 	if (inet6 && flags&NETSTAT_RAW) | ||||
| 		do_info(_PATH_PROCNET_RAW6,"AF INET6 (raw)",raw_do_one); | ||||
| #endif | ||||
| 	if (flags&NETSTAT_UNIX) { | ||||
| 		printf("Active UNIX domain sockets "); | ||||
| 		if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED)) | ||||
|   | ||||
							
								
								
									
										515
									
								
								networking/ping6.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										515
									
								
								networking/ping6.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,515 @@ | ||||
| /* vi: set sw=4 ts=4: */ | ||||
| /* | ||||
|  * $Id: ping6.c,v 1.1 2002/07/03 11:46:34 andersen Exp $ | ||||
|  * Mini ping implementation for busybox | ||||
|  * | ||||
|  * Copyright (C) 1999 by Randolph Chung <tausq@debian.org> | ||||
|  * | ||||
|  * This program is free software; you can redistribute it and/or modify | ||||
|  * it under the terms of the GNU General Public License as published by | ||||
|  * the Free Software Foundation; either version 2 of the License, or | ||||
|  * (at your option) any later version. | ||||
|  * | ||||
|  * This program is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||||
|  * General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU General Public License | ||||
|  * along with this program; if not, write to the Free Software | ||||
|  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||||
|  * | ||||
|  * This version of ping is adapted from the ping in netkit-base 0.10, | ||||
|  * which is: | ||||
|  * | ||||
|  * Copyright (c) 1989 The Regents of the University of California. | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * This code is derived from software contributed to Berkeley by | ||||
|  * Mike Muuss. | ||||
|  *  | ||||
|  * Original copyright notice is retained at the end of this file. | ||||
|  * | ||||
|  * This version is an adaptation of ping.c from busybox. | ||||
|  * The code was modified by Bart Visscher <magick@linux-fan.com> | ||||
|  */ | ||||
|  | ||||
| #include <sys/param.h> | ||||
| #include <sys/socket.h> | ||||
| #include <sys/file.h> | ||||
| #include <sys/time.h> | ||||
| #include <sys/times.h> | ||||
| #include <sys/signal.h> | ||||
|  | ||||
| #include <netinet/in.h> | ||||
| #include <netinet/ip6.h> | ||||
| #include <netinet/icmp6.h> | ||||
| #include <arpa/inet.h> | ||||
| #include <net/if.h> | ||||
| #include <netdb.h> | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <errno.h> | ||||
| #include <unistd.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <stddef.h>				/* offsetof */ | ||||
| #include "busybox.h" | ||||
|  | ||||
| static const int DEFDATALEN = 56; | ||||
| static const int MAXIPLEN = 60; | ||||
| static const int MAXICMPLEN = 76; | ||||
| static const int MAXPACKET = 65468; | ||||
| #define	MAX_DUP_CHK	(8 * 128) | ||||
| static const int MAXWAIT = 10; | ||||
| static const int PINGINTERVAL = 1;		/* second */ | ||||
|  | ||||
| #define O_QUIET         (1 << 0) | ||||
| #define O_VERBOSE       (1 << 1) | ||||
|  | ||||
| #define	A(bit)		rcvd_tbl[(bit)>>3]	/* identify byte in array */ | ||||
| #define	B(bit)		(1 << ((bit) & 0x07))	/* identify bit in byte */ | ||||
| #define	SET(bit)	(A(bit) |= B(bit)) | ||||
| #define	CLR(bit)	(A(bit) &= (~B(bit))) | ||||
| #define	TST(bit)	(A(bit) & B(bit)) | ||||
|  | ||||
| static void ping(const char *host); | ||||
|  | ||||
| /* simple version */ | ||||
| #ifndef CONFIG_FEATURE_FANCY_PING6 | ||||
|  | ||||
| static void ping(const char *host) | ||||
| { | ||||
| 	struct hostent *h; | ||||
| 	struct sockaddr_in6 pingaddr; | ||||
| 	struct icmp6_hdr *pkt; | ||||
| 	int pingsock, c; | ||||
| 	int sockopt; | ||||
| 	char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN]; | ||||
|  | ||||
| 	void noresp(int ign) | ||||
| 	{ | ||||
| 		printf("No response from %s\n", h->h_name); | ||||
| 		exit(0); | ||||
| 	} | ||||
|  | ||||
| 	pingsock = create_icmp6_socket(); | ||||
|  | ||||
| 	memset(&pingaddr, 0, sizeof(struct sockaddr_in)); | ||||
|  | ||||
| 	pingaddr.sin6_family = AF_INET6; | ||||
| 	h = xgethostbyname2(host, AF_INET6); | ||||
| 	memcpy(&pingaddr.sin6_addr, h->h_addr, sizeof(pingaddr.sin6_addr)); | ||||
|  | ||||
| 	pkt = (struct icmp6_hdr *) packet; | ||||
| 	memset(pkt, 0, sizeof(packet)); | ||||
| 	pkt->icmp6_type = ICMP6_ECHO_REQUEST; | ||||
|  | ||||
| 	sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); | ||||
| 	setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, (char *) &sockopt, | ||||
| 			   sizeof(sockopt)); | ||||
|  | ||||
| 	c = sendto(pingsock, packet, sizeof(packet), 0, | ||||
| 			   (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in6)); | ||||
|  | ||||
| 	if (c < 0 || c != sizeof(packet)) | ||||
| 		perror_msg_and_die("sendto"); | ||||
|  | ||||
| 	signal(SIGALRM, noresp); | ||||
| 	alarm(5);					/* give the host 5000ms to respond */ | ||||
| 	/* listen for replies */ | ||||
| 	while (1) { | ||||
| 		struct sockaddr_in6 from; | ||||
| 		size_t fromlen = sizeof(from); | ||||
|  | ||||
| 		if ((c = recvfrom(pingsock, packet, sizeof(packet), 0, | ||||
| 						  (struct sockaddr *) &from, &fromlen)) < 0) { | ||||
| 			if (errno == EINTR) | ||||
| 				continue; | ||||
| 			perror_msg("recvfrom"); | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (c >= 8) {			/* icmp6_hdr */ | ||||
| 			pkt = (struct icmp6_hdr *) packet; | ||||
| 			if (pkt->icmp6_type == ICMP6_ECHO_REPLY) | ||||
| 				break; | ||||
| 		} | ||||
| 	} | ||||
| 	printf("%s is alive!\n", h->h_name); | ||||
| 	return; | ||||
| } | ||||
|  | ||||
| extern int ping6_main(int argc, char **argv) | ||||
| { | ||||
| 	argc--; | ||||
| 	argv++; | ||||
| 	if (argc < 1) | ||||
| 		show_usage(); | ||||
| 	ping(*argv); | ||||
| 	return EXIT_SUCCESS; | ||||
| } | ||||
|  | ||||
| #else /* ! CONFIG_FEATURE_FANCY_PING6 */ | ||||
| /* full(er) version */ | ||||
| static struct sockaddr_in6 pingaddr; | ||||
| static int pingsock = -1; | ||||
| static int datalen; /* intentionally uninitialized to work around gcc bug */ | ||||
| static char* ifname; | ||||
|  | ||||
| static long ntransmitted, nreceived, nrepeats, pingcount; | ||||
| static int myid, options; | ||||
| static unsigned long tmin = ULONG_MAX, tmax, tsum; | ||||
| static char rcvd_tbl[MAX_DUP_CHK / 8]; | ||||
|  | ||||
| #if CONFIG_FEATURE_FANCY_PING | ||||
| extern  | ||||
| #endif | ||||
| 	struct hostent *hostent; | ||||
|  | ||||
| static void sendping(int); | ||||
| static void pingstats(int); | ||||
| static void unpack(char *, int, struct sockaddr_in6 *, int); | ||||
|  | ||||
| /**************************************************************************/ | ||||
|  | ||||
| static void pingstats(int junk) | ||||
| { | ||||
| 	int status; | ||||
|  | ||||
| 	signal(SIGINT, SIG_IGN); | ||||
|  | ||||
| 	printf("\n--- %s ping statistics ---\n", hostent->h_name); | ||||
| 	printf("%ld packets transmitted, ", ntransmitted); | ||||
| 	printf("%ld packets received, ", nreceived); | ||||
| 	if (nrepeats) | ||||
| 		printf("%ld duplicates, ", nrepeats); | ||||
| 	if (ntransmitted) | ||||
| 		printf("%ld%% packet loss\n", | ||||
| 			   (ntransmitted - nreceived) * 100 / ntransmitted); | ||||
| 	if (nreceived) | ||||
| 		printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n", | ||||
| 			   tmin / 10, tmin % 10, | ||||
| 			   (tsum / (nreceived + nrepeats)) / 10, | ||||
| 			   (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10); | ||||
| 	if (nreceived != 0) | ||||
| 		status = EXIT_SUCCESS; | ||||
| 	else | ||||
| 		status = EXIT_FAILURE; | ||||
| 	exit(status); | ||||
| } | ||||
|  | ||||
| static void sendping(int junk) | ||||
| { | ||||
| 	struct icmp6_hdr *pkt; | ||||
| 	int i; | ||||
| 	char packet[datalen + 8]; | ||||
|  | ||||
| 	pkt = (struct icmp6_hdr *) packet; | ||||
|  | ||||
| 	pkt->icmp6_type = ICMP6_ECHO_REQUEST; | ||||
| 	pkt->icmp6_code = 0; | ||||
| 	pkt->icmp6_cksum = 0; | ||||
| 	pkt->icmp6_seq = ntransmitted++; | ||||
| 	pkt->icmp6_id = myid; | ||||
| 	CLR(pkt->icmp6_seq % MAX_DUP_CHK); | ||||
|  | ||||
| 	gettimeofday((struct timeval *) &pkt->icmp6_data8[4], NULL); | ||||
|  | ||||
| 	i = sendto(pingsock, packet, sizeof(packet), 0, | ||||
| 			   (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in6)); | ||||
|  | ||||
| 	if (i < 0) | ||||
| 		perror_msg_and_die("sendto"); | ||||
| 	else if ((size_t)i != sizeof(packet)) | ||||
| 		error_msg_and_die("ping wrote %d chars; %d expected", i, | ||||
| 			   (int)sizeof(packet)); | ||||
|  | ||||
| 	signal(SIGALRM, sendping); | ||||
| 	if (pingcount == 0 || ntransmitted < pingcount) {	/* schedule next in 1s */ | ||||
| 		alarm(PINGINTERVAL); | ||||
| 	} else {					/* done, wait for the last ping to come back */ | ||||
| 		/* todo, don't necessarily need to wait so long... */ | ||||
| 		signal(SIGALRM, pingstats); | ||||
| 		alarm(MAXWAIT); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static char *icmp6_type_name (int id) | ||||
| { | ||||
| 	switch (id) { | ||||
| 	case ICMP6_DST_UNREACH:				return "Destination Unreachable"; | ||||
| 	case ICMP6_PACKET_TOO_BIG:			return "Packet too big"; | ||||
| 	case ICMP6_TIME_EXCEEDED:			return "Time Exceeded"; | ||||
| 	case ICMP6_PARAM_PROB:				return "Parameter Problem"; | ||||
| 	case ICMP6_ECHO_REPLY:				return "Echo Reply"; | ||||
| 	case ICMP6_ECHO_REQUEST:			return "Echo Request"; | ||||
| 	case ICMP6_MEMBERSHIP_QUERY:		return "Membership Query"; | ||||
| 	case ICMP6_MEMBERSHIP_REPORT:		return "Membership Report"; | ||||
| 	case ICMP6_MEMBERSHIP_REDUCTION:	return "Membership Reduction"; | ||||
| 	default: 							return "unknown ICMP type"; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void unpack(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) | ||||
| { | ||||
| 	struct icmp6_hdr *icmppkt; | ||||
| 	struct timeval tv, *tp; | ||||
| 	int dupflag; | ||||
| 	unsigned long triptime; | ||||
| 	char buf[INET6_ADDRSTRLEN]; | ||||
|  | ||||
| 	gettimeofday(&tv, NULL); | ||||
|  | ||||
| 	/* discard if too short */ | ||||
| 	if (sz < (datalen + sizeof(struct icmp6_hdr))) | ||||
| 		return; | ||||
|  | ||||
| 	icmppkt = (struct icmp6_hdr *) packet; | ||||
|  | ||||
| 	if (icmppkt->icmp6_id != myid) | ||||
| 	    return;				/* not our ping */ | ||||
|  | ||||
| 	if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) { | ||||
| 	    ++nreceived; | ||||
| 		tp = (struct timeval *) &icmppkt->icmp6_data8[4]; | ||||
|  | ||||
| 		if ((tv.tv_usec -= tp->tv_usec) < 0) { | ||||
| 			--tv.tv_sec; | ||||
| 			tv.tv_usec += 1000000; | ||||
| 		} | ||||
| 		tv.tv_sec -= tp->tv_sec; | ||||
|  | ||||
| 		triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100); | ||||
| 		tsum += triptime; | ||||
| 		if (triptime < tmin) | ||||
| 			tmin = triptime; | ||||
| 		if (triptime > tmax) | ||||
| 			tmax = triptime; | ||||
|  | ||||
| 		if (TST(icmppkt->icmp6_seq % MAX_DUP_CHK)) { | ||||
| 			++nrepeats; | ||||
| 			--nreceived; | ||||
| 			dupflag = 1; | ||||
| 		} else { | ||||
| 			SET(icmppkt->icmp6_seq % MAX_DUP_CHK); | ||||
| 			dupflag = 0; | ||||
| 		} | ||||
|  | ||||
| 		if (options & O_QUIET) | ||||
| 			return; | ||||
|  | ||||
| 		printf("%d bytes from %s: icmp6_seq=%u", sz, | ||||
| 			   inet_ntop(AF_INET6, (struct in_addr6 *) &pingaddr.sin6_addr, | ||||
| 						 buf, sizeof(buf)), | ||||
| 			   icmppkt->icmp6_seq); | ||||
| 		printf(" ttl=%d time=%lu.%lu ms", hoplimit,  | ||||
| 			   triptime / 10, triptime % 10); | ||||
| 		if (dupflag) | ||||
| 			printf(" (DUP!)"); | ||||
| 		printf("\n"); | ||||
| 	} else  | ||||
| 		if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) | ||||
| 			error_msg("Warning: Got ICMP %d (%s)", | ||||
| 					icmppkt->icmp6_type, icmp6_type_name (icmppkt->icmp6_type)); | ||||
| } | ||||
|  | ||||
| static void ping(const char *host) | ||||
| { | ||||
| 	char packet[datalen + MAXIPLEN + MAXICMPLEN]; | ||||
| 	char buf[INET6_ADDRSTRLEN]; | ||||
| 	int sockopt; | ||||
| 	struct msghdr msg; | ||||
| 	struct sockaddr_in6 from; | ||||
| 	struct iovec iov; | ||||
| 	char control_buf[CMSG_SPACE(36)]; | ||||
|  | ||||
| 	pingsock = create_icmp6_socket(); | ||||
|  | ||||
| 	memset(&pingaddr, 0, sizeof(struct sockaddr_in)); | ||||
|  | ||||
| 	pingaddr.sin6_family = AF_INET6; | ||||
| 	hostent = xgethostbyname2(host, AF_INET6); | ||||
| 	if (hostent->h_addrtype != AF_INET6) | ||||
| 		error_msg_and_die("unknown address type; only AF_INET6 is currently supported."); | ||||
|  | ||||
| 	memcpy(&pingaddr.sin6_addr, hostent->h_addr, sizeof(pingaddr.sin6_addr)); | ||||
|  | ||||
| #ifdef ICMP6_FILTER | ||||
| 	{ | ||||
| 		struct icmp6_filter filt; | ||||
| 		if (!(options & O_VERBOSE)) { | ||||
| 			ICMP6_FILTER_SETBLOCKALL(&filt); | ||||
| #if 0 | ||||
| 			if ((options & F_FQDN) || (options & F_FQDNOLD) || | ||||
| 				(options & F_NODEADDR) || (options & F_SUPTYPES)) | ||||
| 				ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt); | ||||
| 			else | ||||
| #endif | ||||
| 				ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt); | ||||
| 		} else { | ||||
| 			ICMP6_FILTER_SETPASSALL(&filt); | ||||
| 		} | ||||
| 		if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, | ||||
| 					   sizeof(filt)) < 0) | ||||
| 			error_msg_and_die("setsockopt(ICMP6_FILTER)"); | ||||
| 	} | ||||
| #endif /*ICMP6_FILTER*/ | ||||
|  | ||||
| 	/* enable broadcast pings */ | ||||
| 	sockopt = 1; | ||||
| 	setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt, | ||||
| 			   sizeof(sockopt)); | ||||
|  | ||||
| 	/* set recv buf for broadcast pings */ | ||||
| 	sockopt = 48 * 1024; | ||||
| 	setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt, | ||||
| 			   sizeof(sockopt)); | ||||
|  | ||||
| 	sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); | ||||
| 	setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, (char *) &sockopt, | ||||
| 			   sizeof(sockopt)); | ||||
|  | ||||
| 	sockopt = 1; | ||||
| 	setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, (char *) &sockopt, | ||||
| 			   sizeof(sockopt)); | ||||
|  | ||||
| 	if (ifname) { | ||||
| 		if ((pingaddr.sin6_scope_id = if_nametoindex(ifname)) == 0) | ||||
| 			error_msg_and_die("%s: invalid interface name", ifname); | ||||
| 	} | ||||
|  | ||||
| 	printf("PING %s (%s): %d data bytes\n", | ||||
| 	           hostent->h_name, | ||||
| 			   inet_ntop(AF_INET6, (struct in_addr6 *) &pingaddr.sin6_addr, | ||||
| 						 buf, sizeof(buf)), | ||||
| 		   datalen); | ||||
|  | ||||
| 	signal(SIGINT, pingstats); | ||||
|  | ||||
| 	/* start the ping's going ... */ | ||||
| 	sendping(0); | ||||
|  | ||||
| 	/* listen for replies */ | ||||
| 	msg.msg_name=&from; | ||||
| 	msg.msg_namelen=sizeof(from); | ||||
| 	msg.msg_iov=&iov; | ||||
| 	msg.msg_iovlen=1; | ||||
| 	msg.msg_control=control_buf; | ||||
| 	iov.iov_base=packet; | ||||
| 	iov.iov_len=sizeof(packet); | ||||
| 	while (1) { | ||||
| 		int c; | ||||
| 		struct cmsghdr *cmsgptr = NULL; | ||||
| 		int hoplimit=-1; | ||||
| 		msg.msg_controllen=sizeof(control_buf); | ||||
|  | ||||
| 		if ((c = recvmsg(pingsock, &msg, 0)) < 0) { | ||||
| 			if (errno == EINTR) | ||||
| 				continue; | ||||
| 			perror_msg("recvfrom"); | ||||
| 			continue; | ||||
| 		} | ||||
| 		for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL; | ||||
| 			 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) { | ||||
| 			if (cmsgptr->cmsg_level == SOL_IPV6 && | ||||
| 				cmsgptr->cmsg_type == IPV6_HOPLIMIT ) { | ||||
| 				hoplimit=*(int*)CMSG_DATA(cmsgptr); | ||||
| 			} | ||||
| 		} | ||||
| 		unpack(packet, c, &from, hoplimit); | ||||
| 		if (pingcount > 0 && nreceived >= pingcount) | ||||
| 			break; | ||||
| 	} | ||||
| 	pingstats(0); | ||||
| } | ||||
|  | ||||
| extern int ping6_main(int argc, char **argv) | ||||
| { | ||||
| 	char *thisarg; | ||||
|  | ||||
| 	datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */ | ||||
|  | ||||
| 	argc--; | ||||
| 	argv++; | ||||
| 	options = 0; | ||||
| 	/* Parse any options */ | ||||
| 	while (argc >= 1 && **argv == '-') { | ||||
| 		thisarg = *argv; | ||||
| 		thisarg++; | ||||
| 		switch (*thisarg) { | ||||
| 		case 'v': | ||||
| 			options &= ~O_QUIET; | ||||
| 			options |= O_VERBOSE; | ||||
| 			break; | ||||
| 		case 'q': | ||||
| 			options &= ~O_VERBOSE; | ||||
| 			options |= O_QUIET; | ||||
| 			break; | ||||
| 		case 'c': | ||||
| 			if (--argc <= 0) | ||||
| 			        show_usage(); | ||||
| 			argv++; | ||||
| 			pingcount = atoi(*argv); | ||||
| 			break; | ||||
| 		case 's': | ||||
| 			if (--argc <= 0) | ||||
| 			        show_usage(); | ||||
| 			argv++; | ||||
| 			datalen = atoi(*argv); | ||||
| 			break; | ||||
| 		case 'I': | ||||
| 			if (--argc <= 0) | ||||
| 			        show_usage(); | ||||
| 			argv++; | ||||
| 			ifname = *argv; | ||||
| 			break; | ||||
| 		default: | ||||
| 			show_usage(); | ||||
| 		} | ||||
| 		argc--; | ||||
| 		argv++; | ||||
| 	} | ||||
| 	if (argc < 1) | ||||
| 		show_usage(); | ||||
|  | ||||
| 	myid = getpid() & 0xFFFF; | ||||
| 	ping(*argv); | ||||
| 	return EXIT_SUCCESS; | ||||
| } | ||||
| #endif /* ! CONFIG_FEATURE_FANCY_PING6 */ | ||||
|  | ||||
| /* | ||||
|  * Copyright (c) 1989 The Regents of the University of California. | ||||
|  * All rights reserved. | ||||
|  * | ||||
|  * This code is derived from software contributed to Berkeley by | ||||
|  * Mike Muuss. | ||||
|  * | ||||
|  * Redistribution and use in source and binary forms, with or without | ||||
|  * modification, are permitted provided that the following conditions | ||||
|  * are met: | ||||
|  * 1. Redistributions of source code must retain the above copyright | ||||
|  *    notice, this list of conditions and the following disclaimer. | ||||
|  * 2. Redistributions in binary form must reproduce the above copyright | ||||
|  *    notice, this list of conditions and the following disclaimer in the | ||||
|  *    documentation and/or other materials provided with the distribution. | ||||
|  * | ||||
|  * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change  | ||||
|  *		ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>  | ||||
|  * | ||||
|  * 4. Neither the name of the University nor the names of its contributors | ||||
|  *    may be used to endorse or promote products derived from this software | ||||
|  *    without specific prior written permission. | ||||
|  * | ||||
|  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | ||||
|  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||||
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||||
|  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | ||||
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | ||||
|  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | ||||
|  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | ||||
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | ||||
|  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||
|  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | ||||
|  * SUCH DAMAGE. | ||||
|  */ | ||||
| @@ -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