aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2002-07-03 11:46:38 +0000
committerEric Andersen <andersen@codepoet.org>2002-07-03 11:46:38 +0000
commit51b8bd68bb22b1cc5d95e418813c2f08a194ec2b (patch)
tree905d4f1b1e557950272ac98e1540fa06f732f42f
parent599e3ce163c43c3dfb24d06f8f707c783bc9ab9c (diff)
downloadbusybox-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!
-rw-r--r--include/applets.h3
-rw-r--r--include/inet_common.h5
-rw-r--r--include/libbb.h3
-rw-r--r--include/usage.h30
-rw-r--r--libbb/Makefile.in4
-rw-r--r--libbb/create_icmp6_socket.c39
-rw-r--r--libbb/inet_common.c64
-rw-r--r--libbb/interface.c101
-rw-r--r--libbb/xgethostbyname2.c37
-rw-r--r--networking/Makefile.in1
-rw-r--r--networking/config.in7
-rw-r--r--networking/ifconfig.c67
-rw-r--r--networking/netstat.c122
-rw-r--r--networking/ping6.c515
-rw-r--r--networking/route.c243
15 files changed, 1225 insertions, 16 deletions
diff --git a/include/applets.h b/include/applets.h
index c2d7acf4b..b6397a656 100644
--- a/include/applets.h
+++ b/include/applets.h
@@ -344,6 +344,9 @@
344#ifdef CONFIG_PING 344#ifdef CONFIG_PING
345 APPLET(ping, ping_main, _BB_DIR_BIN, _BB_SUID_NEVER) 345 APPLET(ping, ping_main, _BB_DIR_BIN, _BB_SUID_NEVER)
346#endif 346#endif
347#ifdef CONFIG_PING6
348 APPLET(ping6, ping6_main, _BB_DIR_BIN, _BB_SUID_NEVER)
349#endif
347#ifdef CONFIG_PIVOT_ROOT 350#ifdef CONFIG_PIVOT_ROOT
348 APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN, _BB_SUID_NEVER) 351 APPLET(pivot_root, pivot_root_main, _BB_DIR_SBIN, _BB_SUID_NEVER)
349#endif 352#endif
diff --git a/include/inet_common.h b/include/inet_common.h
index 2c5e8f673..8050afc67 100644
--- a/include/inet_common.h
+++ b/include/inet_common.h
@@ -4,7 +4,7 @@
4 * 4 *
5 * Heavily modified by Manuel Novoa III Mar 12, 2001 5 * Heavily modified by Manuel Novoa III Mar 12, 2001
6 * 6 *
7 * Version: $Id: inet_common.h,v 1.1 2001/11/10 12:18:42 andersen Exp $ 7 * Version: $Id: inet_common.h,v 1.2 2002/07/03 11:46:38 andersen Exp $
8 * 8 *
9 */ 9 */
10 10
@@ -28,3 +28,6 @@ extern int INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirs
28 */ 28 */
29extern int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in, 29extern int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in,
30 int numeric, unsigned int netmask); 30 int numeric, unsigned int netmask);
31
32extern int INET6_resolve(char *name, struct sockaddr_in6 *sin6);
33extern int INET6_rresolve(char *name, size_t len, struct sockaddr_in6 *sin6, int numeric);
diff --git a/include/libbb.h b/include/libbb.h
index 2b9fd5fd6..f83cc7623 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -233,7 +233,10 @@ extern void gz_close(int gunzip_pid);
233extern FILE *gz_open(FILE *compressed_file, int *pid); 233extern FILE *gz_open(FILE *compressed_file, int *pid);
234 234
235extern struct hostent *xgethostbyname(const char *name); 235extern struct hostent *xgethostbyname(const char *name);
236extern struct hostent *xgethostbyname2(const char *name, int af);
236extern int create_icmp_socket(void); 237extern int create_icmp_socket(void);
238extern int create_icmp6_socket(void);
239extern int xconnect(const char *host, const char *port);
237 240
238char *dirname (char *path); 241char *dirname (char *path);
239 242
diff --git a/include/usage.h b/include/usage.h
index 5feb3ac10..87678f5e9 100644
--- a/include/usage.h
+++ b/include/usage.h
@@ -733,12 +733,19 @@
733#else 733#else
734 #define USAGE_IFCONFIG_OPT_A(a) 734 #define USAGE_IFCONFIG_OPT_A(a)
735#endif 735#endif
736#ifdef CONFIG_FEATURE_IPV6
737 #define USAGE_IPV6(a) a
738#else
739 #define USAGE_IPV6(a)
740#endif
736 741
737#define ifconfig_trivial_usage \ 742#define ifconfig_trivial_usage \
738 USAGE_IFCONFIG_OPT_A("[-a]") " <interface> [<address>]" 743 USAGE_IFCONFIG_OPT_A("[-a]") " <interface> [<address>]"
739#define ifconfig_full_usage \ 744#define ifconfig_full_usage \
740 "configure a network interface\n\n" \ 745 "configure a network interface\n\n" \
741 "Options:\n" \ 746 "Options:\n" \
747 USAGE_IPV6("[add <address>[/<prefixlen>]]\n") \
748 USAGE_IPV6("[del <address>[/<prefixlen>]]\n") \
742 "\t[[-]broadcast [<address>]] [[-]pointopoint [<address>]]\n" \ 749 "\t[[-]broadcast [<address>]] [[-]pointopoint [<address>]]\n" \
743 "\t[netmask <address>] [dstaddr <address>]\n" \ 750 "\t[netmask <address>] [dstaddr <address>]\n" \
744 USAGE_SIOCSKEEPALIVE("\t[outfill <NN>] [keepalive <NN>]\n") \ 751 USAGE_SIOCSKEEPALIVE("\t[outfill <NN>] [keepalive <NN>]\n") \
@@ -1370,6 +1377,29 @@
1370 "1 packets transmitted, 1 packets received, 0% packet loss\n" \ 1377 "1 packets transmitted, 1 packets received, 0% packet loss\n" \
1371 "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" 1378 "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
1372 1379
1380#ifndef CONFIG_FEATURE_FANCY_PING6
1381#define ping6_trivial_usage "host"
1382#define ping6_full_usage "Send ICMP ECHO_REQUEST packets to network hosts"
1383#else
1384#define ping6_trivial_usage \
1385 "[OPTION]... host"
1386#define ping6_full_usage \
1387 "Send ICMP ECHO_REQUEST packets to network hosts.\n\n" \
1388 "Options:\n" \
1389 "\t-c COUNT\tSend only COUNT pings.\n" \
1390 "\t-s SIZE\t\tSend SIZE data bytes in packets (default=56).\n" \
1391 "\t-q\t\tQuiet mode, only displays output at start\n" \
1392 "\t\t\tand when finished."
1393#endif
1394#define ping6_example_usage \
1395 "$ ping6 ip6-localhost\n" \
1396 "PING ip6-localhost (::1): 56 data bytes\n" \
1397 "64 bytes from ::1: icmp6_seq=0 ttl=64 time=20.1 ms\n" \
1398 "\n" \
1399 "--- ip6-localhost ping statistics ---\n" \
1400 "1 packets transmitted, 1 packets received, 0% packet loss\n" \
1401 "round-trip min/avg/max = 20.1/20.1/20.1 ms\n"
1402
1373#define pivot_root_trivial_usage \ 1403#define pivot_root_trivial_usage \
1374 "NEW_ROOT PUT_OLD" 1404 "NEW_ROOT PUT_OLD"
1375#define pivot_root_full_usage \ 1405#define pivot_root_full_usage \
diff --git a/libbb/Makefile.in b/libbb/Makefile.in
index 2af70f8c7..70cc26dc1 100644
--- a/libbb/Makefile.in
+++ b/libbb/Makefile.in
@@ -40,7 +40,9 @@ LIBBB_SRC:= \
40 dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \ 40 dirname.c make_directory.c create_icmp_socket.c u_signal_names.c arith.c \
41 simplify_path.c inet_common.c inode_hash.c obscure.c pwd2spwd.c xfuncs.c \ 41 simplify_path.c inet_common.c inode_hash.c obscure.c pwd2spwd.c xfuncs.c \
42 correct_password.c change_identity.c setup_environment.c run_shell.c \ 42 correct_password.c change_identity.c setup_environment.c run_shell.c \
43 pw_encrypt.c restricted_shell.c 43 pw_encrypt.c restricted_shell.c xgethostbyname2.c create_icmp6_socket.c \
44 xconnect.c
45
44LIBBB_OBJS=$(patsubst %.c,$(LIBBB_DIR)%.o, $(LIBBB_SRC)) 46LIBBB_OBJS=$(patsubst %.c,$(LIBBB_DIR)%.o, $(LIBBB_SRC))
45 47
46LIBBB_MSRC:=$(LIBBB_DIR)messages.c 48LIBBB_MSRC:=$(LIBBB_DIR)messages.c
diff --git a/libbb/create_icmp6_socket.c b/libbb/create_icmp6_socket.c
new file mode 100644
index 000000000..a09565605
--- /dev/null
+++ b/libbb/create_icmp6_socket.c
@@ -0,0 +1,39 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * create raw socket for icmp (IPv6 version) protocol test permision
6 * and drop root privilegies if running setuid
7 *
8 */
9
10#include <sys/types.h>
11#include <netdb.h>
12#include <sys/socket.h>
13#include <errno.h>
14#include <unistd.h>
15#include "libbb.h"
16
17#if CONFIG_FEATURE_IPV6
18int create_icmp6_socket(void)
19{
20 struct protoent *proto;
21 int sock;
22
23 proto = getprotobyname("ipv6-icmp");
24 /* if getprotobyname failed, just silently force
25 * proto->p_proto to have the correct value for "ipv6-icmp" */
26 if ((sock = socket(AF_INET6, SOCK_RAW,
27 (proto ? proto->p_proto : IPPROTO_ICMPV6))) < 0) {
28 if (errno == EPERM)
29 error_msg_and_die("permission denied. (are you root?)");
30 else
31 perror_msg_and_die(can_not_create_raw_socket);
32 }
33
34 /* drop root privs if running setuid */
35 setuid(getuid());
36
37 return sock;
38}
39#endif
diff --git a/libbb/inet_common.c b/libbb/inet_common.c
index c1e5953fe..c7bf409c4 100644
--- a/libbb/inet_common.c
+++ b/libbb/inet_common.c
@@ -4,7 +4,7 @@
4 * 4 *
5 * Heavily modified by Manuel Novoa III Mar 12, 2001 5 * Heavily modified by Manuel Novoa III Mar 12, 2001
6 * 6 *
7 * Version: $Id: inet_common.c,v 1.2 2002/06/06 12:11:55 andersen Exp $ 7 * Version: $Id: inet_common.c,v 1.3 2002/07/03 11:46:36 andersen Exp $
8 * 8 *
9 */ 9 */
10 10
@@ -177,3 +177,65 @@ int INET_rresolve(char *name, size_t len, struct sockaddr_in *s_in,
177 177
178 return (0); 178 return (0);
179} 179}
180
181#if CONFIG_FEATURE_IPV6
182
183int INET6_resolve(char *name, struct sockaddr_in6 *sin6)
184{
185 struct addrinfo req, *ai;
186 int s;
187
188 memset (&req, '\0', sizeof req);
189 req.ai_family = AF_INET6;
190 if ((s = getaddrinfo(name, NULL, &req, &ai))) {
191 fprintf(stderr, "getaddrinfo: %s: %d\n", name, s);
192 return -1;
193 }
194 memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6));
195
196 freeaddrinfo(ai);
197
198 return (0);
199}
200
201#ifndef IN6_IS_ADDR_UNSPECIFIED
202#define IN6_IS_ADDR_UNSPECIFIED(a) \
203 (((__u32 *) (a))[0] == 0 && ((__u32 *) (a))[1] == 0 && \
204 ((__u32 *) (a))[2] == 0 && ((__u32 *) (a))[3] == 0)
205#endif
206
207
208int INET6_rresolve(char *name, size_t len, struct sockaddr_in6 *sin6, int numeric)
209{
210 int s;
211
212 /* Grmpf. -FvK */
213 if (sin6->sin6_family != AF_INET6) {
214#ifdef DEBUG
215 fprintf(stderr, _("rresolve: unsupport address family %d !\n"),
216 sin6->sin6_family);
217#endif
218 errno = EAFNOSUPPORT;
219 return (-1);
220 }
221 if (numeric & 0x7FFF) {
222 inet_ntop(AF_INET6, &sin6->sin6_addr, name, len);
223 return (0);
224 }
225 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
226 if (numeric & 0x8000)
227 strcpy(name, "default");
228 else
229 strcpy(name, "*");
230 return (0);
231 }
232
233 if ((s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6),
234 name, len , NULL, 0, 0))) {
235 fputs("getnameinfo failed\n", stderr);
236 return -1;
237 }
238 return (0);
239}
240
241#endif /* CONFIG_FEATURE_IPV6 */
diff --git a/libbb/interface.c b/libbb/interface.c
index 9ecb81b9f..5800e0f6a 100644
--- a/libbb/interface.c
+++ b/libbb/interface.c
@@ -15,7 +15,7 @@
15 * that either displays or sets the characteristics of 15 * that either displays or sets the characteristics of
16 * one or more of the system's networking interfaces. 16 * one or more of the system's networking interfaces.
17 * 17 *
18 * Version: $Id: interface.c,v 1.7 2001/11/10 11:22:46 andersen Exp $ 18 * Version: $Id: interface.c,v 1.8 2002/07/03 11:46:36 andersen Exp $
19 * 19 *
20 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org> 20 * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
21 * and others. Copyright 1993 MicroWalt Corporation 21 * and others. Copyright 1993 MicroWalt Corporation
@@ -52,6 +52,10 @@
52#undef HAVE_AFECONET 52#undef HAVE_AFECONET
53#undef HAVE_AFASH 53#undef HAVE_AFASH
54 54
55#if CONFIG_FEATURE_IPV6
56#define HAVE_AFINET6 1
57#endif
58
55/* 59/*
56 * 60 *
57 * Device Hardware types. 61 * Device Hardware types.
@@ -77,6 +81,7 @@
77 81
78#define _(x) x 82#define _(x) x
79#define _PATH_PROCNET_DEV "/proc/net/dev" 83#define _PATH_PROCNET_DEV "/proc/net/dev"
84#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
80#define new(p) ((p) = xcalloc(1,sizeof(*(p)))) 85#define new(p) ((p) = xcalloc(1,sizeof(*(p))))
81#define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch)) 86#define KRELEASE(maj,min,patch) ((maj) * 65536 + (min)*256 + (patch))
82 87
@@ -425,6 +430,76 @@ static struct aftype inet_aftype =
425 430
426#endif /* HAVE_AFINET */ 431#endif /* HAVE_AFINET */
427 432
433#if HAVE_AFINET6
434
435#ifdef KEEP_UNUSED
436static void INET6_reserror(char *text)
437{
438 herror(text);
439}
440
441/* Display an Internet socket address. */
442static char *INET6_print(unsigned char *ptr)
443{
444 static char name[80];
445
446 inet_ntop(AF_INET6, (struct in6_addr *) ptr, name, 80);
447 return name;
448}
449#endif /* KEEP_UNUSED */
450
451/* Display an Internet socket address. */
452/* dirty! struct sockaddr usually doesn't suffer for inet6 addresses, fst. */
453static char *INET6_sprint(struct sockaddr *sap, int numeric)
454{
455 static char buff[128];
456
457 if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
458 return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
459 if (INET6_rresolve(buff, sizeof(buff), (struct sockaddr_in6 *) sap, numeric) != 0)
460 return safe_strncpy(buff, _("[UNKNOWN]"), sizeof(buff));
461 return (buff);
462}
463
464#ifdef KEEP_UNUSED
465static int INET6_getsock(char *bufp, struct sockaddr *sap)
466{
467 struct sockaddr_in6 *sin6;
468
469 sin6 = (struct sockaddr_in6 *) sap;
470 sin6->sin6_family = AF_INET6;
471 sin6->sin6_port = 0;
472
473 if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
474 return (-1);
475
476 return 16; /* ?;) */
477}
478
479static int INET6_input(int type, char *bufp, struct sockaddr *sap)
480{
481 switch (type) {
482 case 1:
483 return (INET6_getsock(bufp, sap));
484 default:
485 return (INET6_resolve(bufp, (struct sockaddr_in6 *) sap));
486 }
487}
488#endif /* KEEP_UNUSED */
489
490static struct aftype inet6_aftype =
491{
492 "inet6", "IPv6", AF_INET6, sizeof(struct in6_addr),
493 NULL /* UNUSED INET6_print */, INET6_sprint,
494 NULL /* UNUSED INET6_input */, NULL /* UNUSED INET6_reserror */,
495 NULL /*INET6_rprint */ , NULL /*INET6_rinput */ ,
496 NULL /* UNUSED INET6_getnetmask */,
497 -1,
498 NULL
499};
500
501#endif /* HAVE_AFINET6 */
502
428/* Display an UNSPEC address. */ 503/* Display an UNSPEC address. */
429static char *UNSPEC_print(unsigned char *ptr) 504static char *UNSPEC_print(unsigned char *ptr)
430{ 505{
@@ -1709,7 +1784,6 @@ static void ife_print(struct interface *ptr)
1709 char addr6[40], devname[20]; 1784 char addr6[40], devname[20];
1710 struct sockaddr_in6 sap; 1785 struct sockaddr_in6 sap;
1711 int plen, scope, dad_status, if_idx; 1786 int plen, scope, dad_status, if_idx;
1712 extern struct aftype inet6_aftype;
1713 char addr6p[8][5]; 1787 char addr6p[8][5];
1714#endif 1788#endif
1715 1789
@@ -1756,8 +1830,24 @@ static void ife_print(struct interface *ptr)
1756#endif 1830#endif
1757 1831
1758#if HAVE_AFINET6 1832#if HAVE_AFINET6
1759 /* FIXME: should be integrated into interface.c. */
1760 1833
1834#define IPV6_ADDR_ANY 0x0000U
1835
1836#define IPV6_ADDR_UNICAST 0x0001U
1837#define IPV6_ADDR_MULTICAST 0x0002U
1838#define IPV6_ADDR_ANYCAST 0x0004U
1839
1840#define IPV6_ADDR_LOOPBACK 0x0010U
1841#define IPV6_ADDR_LINKLOCAL 0x0020U
1842#define IPV6_ADDR_SITELOCAL 0x0040U
1843
1844#define IPV6_ADDR_COMPATv4 0x0080U
1845
1846#define IPV6_ADDR_SCOPE_MASK 0x00f0U
1847
1848#define IPV6_ADDR_MAPPED 0x1000U
1849#define IPV6_ADDR_RESERVED 0x2000U /* reserved address space */
1850
1761 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { 1851 if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) {
1762 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", 1852 while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n",
1763 addr6p[0], addr6p[1], addr6p[2], addr6p[3], 1853 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
@@ -1767,11 +1857,12 @@ static void ife_print(struct interface *ptr)
1767 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s", 1857 sprintf(addr6, "%s:%s:%s:%s:%s:%s:%s:%s",
1768 addr6p[0], addr6p[1], addr6p[2], addr6p[3], 1858 addr6p[0], addr6p[1], addr6p[2], addr6p[3],
1769 addr6p[4], addr6p[5], addr6p[6], addr6p[7]); 1859 addr6p[4], addr6p[5], addr6p[6], addr6p[7]);
1770 inet6_aftype.input(1, addr6, (struct sockaddr *) &sap); 1860 inet_pton(AF_INET6, addr6, (struct sockaddr *) &sap.sin6_addr);
1861 sap.sin6_family=AF_INET6;
1771 printf(_(" inet6 addr: %s/%d"), 1862 printf(_(" inet6 addr: %s/%d"),
1772 inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen); 1863 inet6_aftype.sprint((struct sockaddr *) &sap, 1), plen);
1773 printf(_(" Scope:")); 1864 printf(_(" Scope:"));
1774 switch (scope) { 1865 switch (scope & IPV6_ADDR_SCOPE_MASK) {
1775 case 0: 1866 case 0:
1776 printf(_("Global")); 1867 printf(_("Global"));
1777 break; 1868 break;
diff --git a/libbb/xgethostbyname2.c b/libbb/xgethostbyname2.c
new file mode 100644
index 000000000..c66acfee1
--- /dev/null
+++ b/libbb/xgethostbyname2.c
@@ -0,0 +1,37 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini xgethostbyname2 implementation.
4 *
5 * Copyright (C) 2001 Matt Kraai <kraai@alumni.carnegiemellon.edu>.
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23#include <netdb.h>
24#include "libbb.h"
25
26
27#if CONFIG_FEATURE_IPV6
28struct hostent *xgethostbyname2(const char *name, int af)
29{
30 struct hostent *retval;
31
32 if ((retval = gethostbyname2(name, af)) == NULL)
33 herror_msg_and_die("%s", name);
34
35 return retval;
36}
37#endif
diff --git a/networking/Makefile.in b/networking/Makefile.in
index 6f3cc2189..be4b53b78 100644
--- a/networking/Makefile.in
+++ b/networking/Makefile.in
@@ -29,6 +29,7 @@ NETWORKING-$(CONFIG_NC) += nc.o
29NETWORKING-$(CONFIG_NETSTAT) += netstat.o 29NETWORKING-$(CONFIG_NETSTAT) += netstat.o
30NETWORKING-$(CONFIG_NSLOOKUP) += nslookup.o 30NETWORKING-$(CONFIG_NSLOOKUP) += nslookup.o
31NETWORKING-$(CONFIG_PING) += ping.o 31NETWORKING-$(CONFIG_PING) += ping.o
32NETWORKING-$(CONFIG_PING6) += ping6.o
32NETWORKING-$(CONFIG_ROUTE) += route.o 33NETWORKING-$(CONFIG_ROUTE) += route.o
33NETWORKING-$(CONFIG_TELNET) += telnet.o 34NETWORKING-$(CONFIG_TELNET) += telnet.o
34NETWORKING-$(CONFIG_TFTP) += tftp.o 35NETWORKING-$(CONFIG_TFTP) += tftp.o
diff --git a/networking/config.in b/networking/config.in
index b148eb57c..1edc1de7e 100644
--- a/networking/config.in
+++ b/networking/config.in
@@ -6,6 +6,7 @@
6mainmenu_option next_comment 6mainmenu_option next_comment
7comment 'Networking Utilities' 7comment 'Networking Utilities'
8 8
9bool 'Enable IPv6 support' CONFIG_FEATURE_IPV6
9bool 'hostname' CONFIG_HOSTNAME 10bool 'hostname' CONFIG_HOSTNAME
10bool 'ifconfig' CONFIG_IFCONFIG 11bool 'ifconfig' CONFIG_IFCONFIG
11if [ "$CONFIG_IFCONFIG" = "y" ]; then 12if [ "$CONFIG_IFCONFIG" = "y" ]; then
@@ -22,6 +23,12 @@ bool 'ping' CONFIG_PING
22if [ "$CONFIG_PING" = "y" ]; then 23if [ "$CONFIG_PING" = "y" ]; then
23 bool ' Enable fancy ping output' CONFIG_FEATURE_FANCY_PING 24 bool ' Enable fancy ping output' CONFIG_FEATURE_FANCY_PING
24fi 25fi
26if [ "$CONFIG_FEATURE_IPV6" = "y" ]; then
27 bool 'ping6' CONFIG_PING6
28 if [ "$CONFIG_PING6" = "y" ]; then
29 bool ' Enable fancy ping6 output' CONFIG_FEATURE_FANCY_PING6
30 fi
31fi
25bool 'route' CONFIG_ROUTE 32bool 'route' CONFIG_ROUTE
26bool 'telnet' CONFIG_TELNET 33bool 'telnet' CONFIG_TELNET
27if [ "$CONFIG_TELNET" = "y" ]; then 34if [ "$CONFIG_TELNET" = "y" ]; then
diff --git a/networking/ifconfig.c b/networking/ifconfig.c
index 0b834e7c7..9e87c8be5 100644
--- a/networking/ifconfig.c
+++ b/networking/ifconfig.c
@@ -15,7 +15,7 @@
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: ifconfig.c,v 1.16 2001/11/10 11:22:43 andersen Exp $ 18 * $Id: ifconfig.c,v 1.17 2002/07/03 11:46:34 andersen Exp $
19 * 19 *
20 */ 20 */
21 21
@@ -27,6 +27,9 @@
27 * args missing from initial port. 27 * args missing from initial port.
28 * 28 *
29 * Still missing: media, tunnel. 29 * Still missing: media, tunnel.
30 *
31 * 2002-04-20
32 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
30 */ 33 */
31 34
32#include <stdio.h> 35#include <stdio.h>
@@ -65,6 +68,14 @@
65#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */ 68#define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses */
66#endif 69#endif
67 70
71#if CONFIG_FEATURE_IPV6
72struct in6_ifreq {
73 struct in6_addr ifr6_addr;
74 uint32_t ifr6_prefixlen;
75 int ifr6_ifindex;
76};
77#endif
78
68/* 79/*
69 * Here are the bit masks for the "flags" member of struct options below. 80 * Here are the bit masks for the "flags" member of struct options below.
70 * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'. 81 * N_ signifies no arg prefix; M_ signifies arg prefixed by '-'.
@@ -143,6 +154,7 @@
143#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR) 154#define ARG_KEEPALIVE (A_ARG_REQ | A_CAST_CHAR_PTR)
144#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR) 155#define ARG_OUTFILL (A_ARG_REQ | A_CAST_CHAR_PTR)
145#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK) 156#define ARG_HOSTNAME (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER | A_COLON_CHK)
157#define ARG_ADD_DEL (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER)
146 158
147 159
148/* 160/*
@@ -187,6 +199,10 @@ static const struct arg1opt Arg1Opt[] = {
187 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)}, 199 {"SIOCSIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq)},
188#endif 200#endif
189 /* Last entry if for unmatched (possibly hostname) arg. */ 201 /* Last entry if for unmatched (possibly hostname) arg. */
202#if CONFIG_FEATURE_IPV6
203 {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
204 {"SIOCDIFADDR", SIOCDIFADDR, ifreq_offsetof(ifr_addr)}, /* IPv6 version ignores the offset */
205#endif
190 {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)}, 206 {"SIOCSIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr)},
191}; 207};
192 208
@@ -212,6 +228,10 @@ static const struct options OptArray[] = {
212 {"io_addr", N_ARG, ARG_IO_ADDR, 0}, 228 {"io_addr", N_ARG, ARG_IO_ADDR, 0},
213 {"irq", N_ARG, ARG_IRQ, 0}, 229 {"irq", N_ARG, ARG_IRQ, 0},
214#endif 230#endif
231#if CONFIG_FEATURE_IPV6
232 {"add", N_ARG, ARG_ADD_DEL, 0},
233 {"del", N_ARG, ARG_ADD_DEL, 0},
234#endif
215 {"arp", N_CLR | M_SET, 0, IFF_NOARP}, 235 {"arp", N_CLR | M_SET, 0, IFF_NOARP},
216 {"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS}, 236 {"trailers", N_CLR | M_SET, 0, IFF_NOTRAILERS},
217 {"promisc", N_SET | M_CLR, 0, IFF_PROMISC}, 237 {"promisc", N_SET | M_CLR, 0, IFF_PROMISC},
@@ -244,6 +264,9 @@ int ifconfig_main(int argc, char **argv)
244{ 264{
245 struct ifreq ifr; 265 struct ifreq ifr;
246 struct sockaddr_in sai; 266 struct sockaddr_in sai;
267#if CONFIG_FEATURE_IPV6
268 struct sockaddr_in6 sai6;
269#endif
247#ifdef CONFIG_FEATURE_IFCONFIG_HW 270#ifdef CONFIG_FEATURE_IFCONFIG_HW
248 struct sockaddr sa; 271 struct sockaddr sa;
249#endif 272#endif
@@ -334,12 +357,54 @@ int ifconfig_main(int argc, char **argv)
334#ifdef CONFIG_FEATURE_IFCONFIG_HW 357#ifdef CONFIG_FEATURE_IFCONFIG_HW
335 if (mask & A_CAST_RESOLVE) { 358 if (mask & A_CAST_RESOLVE) {
336#endif 359#endif
360#if CONFIG_FEATURE_IPV6
361 char *prefix;
362 int prefix_len=0;
363#endif
364
337 safe_strncpy(host, *argv, (sizeof host)); 365 safe_strncpy(host, *argv, (sizeof host));
366#if CONFIG_FEATURE_IPV6
367 if ((prefix = strchr(host, '/'))) {
368 prefix_len = atol(prefix + 1);
369 if ((prefix_len < 0) || (prefix_len > 128)) {
370 ++goterr;
371 goto LOOP;
372 }
373 *prefix = 0;
374 }
375#endif
376
338 sai.sin_family = AF_INET; 377 sai.sin_family = AF_INET;
339 sai.sin_port = 0; 378 sai.sin_port = 0;
340 if (!strcmp(host, bb_INET_default)) { 379 if (!strcmp(host, bb_INET_default)) {
341 /* Default is special, meaning 0.0.0.0. */ 380 /* Default is special, meaning 0.0.0.0. */
342 sai.sin_addr.s_addr = INADDR_ANY; 381 sai.sin_addr.s_addr = INADDR_ANY;
382#if CONFIG_FEATURE_IPV6
383 } else
384 if (inet_pton(AF_INET6, host, &sai6.sin6_addr) > 0) {
385 int sockfd6;
386 struct in6_ifreq ifr6;
387
388 memcpy((char *) &ifr6.ifr6_addr, (char *) &sai6.sin6_addr,
389 sizeof(struct in6_addr));
390
391 /* Create a channel to the NET kernel. */
392 if ((sockfd6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
393 perror_msg_and_die("socket6");
394 }
395 if (ioctl(sockfd6, SIOGIFINDEX, &ifr) < 0) {
396 perror("SIOGIFINDEX");
397 ++goterr;
398 continue;
399 }
400 ifr6.ifr6_ifindex = ifr.ifr_ifindex;
401 ifr6.ifr6_prefixlen = prefix_len;
402 if (ioctl(sockfd6, a1op->selector, &ifr6) < 0) {
403 perror(a1op->name);
404 ++goterr;
405 }
406 continue;
407#endif
343 } else if (inet_aton(host, &sai.sin_addr) == 0) { 408 } else if (inet_aton(host, &sai.sin_addr) == 0) {
344 /* It's not a dotted quad. */ 409 /* It's not a dotted quad. */
345 ++goterr; 410 ++goterr;
diff --git a/networking/netstat.c b/networking/netstat.c
index 00b58228e..67ecc0105 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -3,7 +3,7 @@
3 * Mini netstat implementation(s) for busybox 3 * Mini netstat implementation(s) for busybox
4 * based in part on the netstat implementation from net-tools. 4 * based in part on the netstat implementation from net-tools.
5 * 5 *
6 * Copyright (C) 2001 by Bart Visscher <magick@linux-fan.com> 6 * Copyright (C) 2002 by Bart Visscher <magick@linux-fan.com>
7 * 7 *
8 * This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
@@ -18,6 +18,9 @@
18 * You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * 2002-04-20
23 * IPV6 support added by Bart Visscher <magick@linux-fan.com>
21 */ 24 */
22 25
23#include <stdio.h> 26#include <stdio.h>
@@ -128,9 +131,17 @@ static void snprint_ip_port(char *ip_port, int size, struct sockaddr *addr, int
128{ 131{
129 char *port_name; 132 char *port_name;
130 133
134#if CONFIG_FEATURE_IPV6
135 if (addr->sa_family == AF_INET6) {
136 INET6_rresolve(ip_port, size, (struct sockaddr_in6 *)addr,
137 (numeric&NETSTAT_NUMERIC) ? 0x0fff : 0);
138 } else
139#endif
140 {
131 INET_rresolve(ip_port, size, (struct sockaddr_in *)addr, 141 INET_rresolve(ip_port, size, (struct sockaddr_in *)addr,
132 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0), 142 0x4000 | ((numeric&NETSTAT_NUMERIC) ? 0x0fff : 0),
133 0xffffffff); 143 0xffffffff);
144 }
134 port_name=get_sname(htons(port), proto, numeric); 145 port_name=get_sname(htons(port), proto, numeric);
135 if ((strlen(ip_port) + strlen(port_name)) > 22) 146 if ((strlen(ip_port) + strlen(port_name)) > 22)
136 ip_port[22 - strlen(port_name)] = '\0'; 147 ip_port[22 - strlen(port_name)] = '\0';
@@ -145,7 +156,13 @@ static void tcp_do_one(int lnr, const char *line)
145 const char *state_str; 156 const char *state_str;
146 char more[512]; 157 char more[512];
147 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 158 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
159#if CONFIG_FEATURE_IPV6
160 struct sockaddr_in6 localaddr, remaddr;
161 char addr6[INET6_ADDRSTRLEN];
162 struct in6_addr in6;
163#else
148 struct sockaddr_in localaddr, remaddr; 164 struct sockaddr_in localaddr, remaddr;
165#endif
149 unsigned long rxq, txq, time_len, retr, inode; 166 unsigned long rxq, txq, time_len, retr, inode;
150 167
151 if (lnr == 0) 168 if (lnr == 0)
@@ -159,6 +176,20 @@ static void tcp_do_one(int lnr, const char *line)
159 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 176 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
160 177
161 if (strlen(local_addr) > 8) { 178 if (strlen(local_addr) > 8) {
179#if CONFIG_FEATURE_IPV6
180 sscanf(local_addr, "%08X%08X%08X%08X",
181 &in6.s6_addr32[0], &in6.s6_addr32[1],
182 &in6.s6_addr32[2], &in6.s6_addr32[3]);
183 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
184 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
185 sscanf(rem_addr, "%08X%08X%08X%08X",
186 &in6.s6_addr32[0], &in6.s6_addr32[1],
187 &in6.s6_addr32[2], &in6.s6_addr32[3]);
188 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
189 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
190 localaddr.sin6_family = AF_INET6;
191 remaddr.sin6_family = AF_INET6;
192#endif
162 } else { 193 } else {
163 sscanf(local_addr, "%X", 194 sscanf(local_addr, "%X",
164 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 195 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
@@ -195,7 +226,13 @@ static void udp_do_one(int lnr, const char *line)
195 char local_addr[64], rem_addr[64]; 226 char local_addr[64], rem_addr[64];
196 char *state_str, more[512]; 227 char *state_str, more[512];
197 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 228 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
229#if CONFIG_FEATURE_IPV6
230 struct sockaddr_in6 localaddr, remaddr;
231 char addr6[INET6_ADDRSTRLEN];
232 struct in6_addr in6;
233#else
198 struct sockaddr_in localaddr, remaddr; 234 struct sockaddr_in localaddr, remaddr;
235#endif
199 unsigned long rxq, txq, time_len, retr, inode; 236 unsigned long rxq, txq, time_len, retr, inode;
200 237
201 if (lnr == 0) 238 if (lnr == 0)
@@ -209,6 +246,21 @@ static void udp_do_one(int lnr, const char *line)
209 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 246 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
210 247
211 if (strlen(local_addr) > 8) { 248 if (strlen(local_addr) > 8) {
249#if CONFIG_FEATURE_IPV6
250 /* Demangle what the kernel gives us */
251 sscanf(local_addr, "%08X%08X%08X%08X",
252 &in6.s6_addr32[0], &in6.s6_addr32[1],
253 &in6.s6_addr32[2], &in6.s6_addr32[3]);
254 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
255 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
256 sscanf(rem_addr, "%08X%08X%08X%08X",
257 &in6.s6_addr32[0], &in6.s6_addr32[1],
258 &in6.s6_addr32[2], &in6.s6_addr32[3]);
259 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
260 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
261 localaddr.sin6_family = AF_INET6;
262 remaddr.sin6_family = AF_INET6;
263#endif
212 } else { 264 } else {
213 sscanf(local_addr, "%X", 265 sscanf(local_addr, "%X",
214 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 266 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
@@ -236,7 +288,17 @@ static void udp_do_one(int lnr, const char *line)
236 break; 288 break;
237 } 289 }
238 290
291#if CONFIG_FEATURE_IPV6
292#define notnull(A) (((A.sin6_family == AF_INET6) && \
293 ((A.sin6_addr.s6_addr32[0]) || \
294 (A.sin6_addr.s6_addr32[1]) || \
295 (A.sin6_addr.s6_addr32[2]) || \
296 (A.sin6_addr.s6_addr32[3]))) || \
297 ((A.sin6_family == AF_INET) && \
298 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
299#else
239#define notnull(A) (A.sin_addr.s_addr) 300#define notnull(A) (A.sin_addr.s_addr)
301#endif
240 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) || 302 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
241 (!notnull(remaddr) && (flags&NETSTAT_LISTENING))) 303 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
242 { 304 {
@@ -259,7 +321,13 @@ static void raw_do_one(int lnr, const char *line)
259 char local_addr[64], rem_addr[64]; 321 char local_addr[64], rem_addr[64];
260 char *state_str, more[512]; 322 char *state_str, more[512];
261 int num, local_port, rem_port, d, state, timer_run, uid, timeout; 323 int num, local_port, rem_port, d, state, timer_run, uid, timeout;
324#if CONFIG_FEATURE_IPV6
325 struct sockaddr_in6 localaddr, remaddr;
326 char addr6[INET6_ADDRSTRLEN];
327 struct in6_addr in6;
328#else
262 struct sockaddr_in localaddr, remaddr; 329 struct sockaddr_in localaddr, remaddr;
330#endif
263 unsigned long rxq, txq, time_len, retr, inode; 331 unsigned long rxq, txq, time_len, retr, inode;
264 332
265 if (lnr == 0) 333 if (lnr == 0)
@@ -273,6 +341,20 @@ static void raw_do_one(int lnr, const char *line)
273 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more); 341 &txq, &rxq, &timer_run, &time_len, &retr, &uid, &timeout, &inode, more);
274 342
275 if (strlen(local_addr) > 8) { 343 if (strlen(local_addr) > 8) {
344#if CONFIG_FEATURE_IPV6
345 sscanf(local_addr, "%08X%08X%08X%08X",
346 &in6.s6_addr32[0], &in6.s6_addr32[1],
347 &in6.s6_addr32[2], &in6.s6_addr32[3]);
348 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
349 inet_pton(AF_INET6, addr6, (struct sockaddr *) &localaddr.sin6_addr);
350 sscanf(rem_addr, "%08X%08X%08X%08X",
351 &in6.s6_addr32[0], &in6.s6_addr32[1],
352 &in6.s6_addr32[2], &in6.s6_addr32[3]);
353 inet_ntop(AF_INET6, &in6, addr6, sizeof(addr6));
354 inet_pton(AF_INET6, addr6, (struct sockaddr *) &remaddr.sin6_addr);
355 localaddr.sin6_family = AF_INET6;
356 remaddr.sin6_family = AF_INET6;
357#endif
276 } else { 358 } else {
277 sscanf(local_addr, "%X", 359 sscanf(local_addr, "%X",
278 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr); 360 &((struct sockaddr_in *) &localaddr)->sin_addr.s_addr);
@@ -288,7 +370,17 @@ static void raw_do_one(int lnr, const char *line)
288 } 370 }
289 state_str=itoa(state); 371 state_str=itoa(state);
290 372
373#if CONFIG_FEATURE_IPV6
374#define notnull(A) (((A.sin6_family == AF_INET6) && \
375 ((A.sin6_addr.s6_addr32[0]) || \
376 (A.sin6_addr.s6_addr32[1]) || \
377 (A.sin6_addr.s6_addr32[2]) || \
378 (A.sin6_addr.s6_addr32[3]))) || \
379 ((A.sin6_family == AF_INET) && \
380 ((struct sockaddr_in *) &A)->sin_addr.s_addr))
381#else
291#define notnull(A) (A.sin_addr.s_addr) 382#define notnull(A) (A.sin_addr.s_addr)
383#endif
292 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) || 384 if ((notnull(remaddr) && (flags&NETSTAT_CONNECTED)) ||
293 (!notnull(remaddr) && (flags&NETSTAT_LISTENING))) 385 (!notnull(remaddr) && (flags&NETSTAT_LISTENING)))
294 { 386 {
@@ -429,8 +521,11 @@ static void unix_do_one(int nr, const char *line)
429} 521}
430 522
431#define _PATH_PROCNET_UDP "/proc/net/udp" 523#define _PATH_PROCNET_UDP "/proc/net/udp"
524#define _PATH_PROCNET_UDP6 "/proc/net/udp6"
432#define _PATH_PROCNET_TCP "/proc/net/tcp" 525#define _PATH_PROCNET_TCP "/proc/net/tcp"
526#define _PATH_PROCNET_TCP6 "/proc/net/tcp6"
433#define _PATH_PROCNET_RAW "/proc/net/raw" 527#define _PATH_PROCNET_RAW "/proc/net/raw"
528#define _PATH_PROCNET_RAW6 "/proc/net/raw6"
434#define _PATH_PROCNET_UNIX "/proc/net/unix" 529#define _PATH_PROCNET_UNIX "/proc/net/unix"
435 530
436static void do_info(const char *file, const char *name, void (*proc)(int, const char *)) 531static 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)
464 int opt; 559 int opt;
465 int new_flags=0; 560 int new_flags=0;
466 int showroute = 0, extended = 0; 561 int showroute = 0, extended = 0;
562#if CONFIG_FEATURE_IPV6
563 int inet=1;
564 int inet6=1;
565#else
566#define inet 1
567#define inet6 0
568#endif
467 while ((opt = getopt(argc, argv, "laenrtuwx")) != -1) 569 while ((opt = getopt(argc, argv, "laenrtuwx")) != -1)
468 switch (opt) { 570 switch (opt) {
469 case 'l': 571 case 'l':
@@ -523,12 +625,24 @@ int netstat_main(int argc, char **argv)
523 } 625 }
524 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n"); 626 printf("\nProto Recv-Q Send-Q Local Address Foreign Address State \n");
525 } 627 }
526 if (flags&NETSTAT_TCP) 628 if (inet && flags&NETSTAT_TCP)
527 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one); 629 do_info(_PATH_PROCNET_TCP,"AF INET (tcp)",tcp_do_one);
528 if (flags&NETSTAT_UDP) 630#if CONFIG_FEATURE_IPV6
631 if (inet6 && flags&NETSTAT_TCP)
632 do_info(_PATH_PROCNET_TCP6,"AF INET6 (tcp)",tcp_do_one);
633#endif
634 if (inet && flags&NETSTAT_UDP)
529 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one); 635 do_info(_PATH_PROCNET_UDP,"AF INET (udp)",udp_do_one);
530 if (flags&NETSTAT_RAW) 636#if CONFIG_FEATURE_IPV6
637 if (inet6 && flags&NETSTAT_UDP)
638 do_info(_PATH_PROCNET_UDP6,"AF INET6 (udp)",udp_do_one);
639#endif
640 if (inet && flags&NETSTAT_RAW)
531 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one); 641 do_info(_PATH_PROCNET_RAW,"AF INET (raw)",raw_do_one);
642#if CONFIG_FEATURE_IPV6
643 if (inet6 && flags&NETSTAT_RAW)
644 do_info(_PATH_PROCNET_RAW6,"AF INET6 (raw)",raw_do_one);
645#endif
532 if (flags&NETSTAT_UNIX) { 646 if (flags&NETSTAT_UNIX) {
533 printf("Active UNIX domain sockets "); 647 printf("Active UNIX domain sockets ");
534 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED)) 648 if ((flags&(NETSTAT_LISTENING|NETSTAT_CONNECTED))==(NETSTAT_LISTENING|NETSTAT_CONNECTED))
diff --git a/networking/ping6.c b/networking/ping6.c
new file mode 100644
index 000000000..bff700c0e
--- /dev/null
+++ b/networking/ping6.c
@@ -0,0 +1,515 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * $Id: ping6.c,v 1.1 2002/07/03 11:46:34 andersen Exp $
4 * Mini ping implementation for busybox
5 *
6 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 *
22 * This version of ping is adapted from the ping in netkit-base 0.10,
23 * which is:
24 *
25 * Copyright (c) 1989 The Regents of the University of California.
26 * All rights reserved.
27 *
28 * This code is derived from software contributed to Berkeley by
29 * Mike Muuss.
30 *
31 * Original copyright notice is retained at the end of this file.
32 *
33 * This version is an adaptation of ping.c from busybox.
34 * The code was modified by Bart Visscher <magick@linux-fan.com>
35 */
36
37#include <sys/param.h>
38#include <sys/socket.h>
39#include <sys/file.h>
40#include <sys/time.h>
41#include <sys/times.h>
42#include <sys/signal.h>
43
44#include <netinet/in.h>
45#include <netinet/ip6.h>
46#include <netinet/icmp6.h>
47#include <arpa/inet.h>
48#include <net/if.h>
49#include <netdb.h>
50#include <stdio.h>
51#include <stdlib.h>
52#include <errno.h>
53#include <unistd.h>
54#include <string.h>
55#include <stdlib.h>
56#include <stddef.h> /* offsetof */
57#include "busybox.h"
58
59static const int DEFDATALEN = 56;
60static const int MAXIPLEN = 60;
61static const int MAXICMPLEN = 76;
62static const int MAXPACKET = 65468;
63#define MAX_DUP_CHK (8 * 128)
64static const int MAXWAIT = 10;
65static const int PINGINTERVAL = 1; /* second */
66
67#define O_QUIET (1 << 0)
68#define O_VERBOSE (1 << 1)
69
70#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */
71#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */
72#define SET(bit) (A(bit) |= B(bit))
73#define CLR(bit) (A(bit) &= (~B(bit)))
74#define TST(bit) (A(bit) & B(bit))
75
76static void ping(const char *host);
77
78/* simple version */
79#ifndef CONFIG_FEATURE_FANCY_PING6
80
81static void ping(const char *host)
82{
83 struct hostent *h;
84 struct sockaddr_in6 pingaddr;
85 struct icmp6_hdr *pkt;
86 int pingsock, c;
87 int sockopt;
88 char packet[DEFDATALEN + MAXIPLEN + MAXICMPLEN];
89
90 void noresp(int ign)
91 {
92 printf("No response from %s\n", h->h_name);
93 exit(0);
94 }
95
96 pingsock = create_icmp6_socket();
97
98 memset(&pingaddr, 0, sizeof(struct sockaddr_in));
99
100 pingaddr.sin6_family = AF_INET6;
101 h = xgethostbyname2(host, AF_INET6);
102 memcpy(&pingaddr.sin6_addr, h->h_addr, sizeof(pingaddr.sin6_addr));
103
104 pkt = (struct icmp6_hdr *) packet;
105 memset(pkt, 0, sizeof(packet));
106 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
107
108 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
109 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, (char *) &sockopt,
110 sizeof(sockopt));
111
112 c = sendto(pingsock, packet, sizeof(packet), 0,
113 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in6));
114
115 if (c < 0 || c != sizeof(packet))
116 perror_msg_and_die("sendto");
117
118 signal(SIGALRM, noresp);
119 alarm(5); /* give the host 5000ms to respond */
120 /* listen for replies */
121 while (1) {
122 struct sockaddr_in6 from;
123 size_t fromlen = sizeof(from);
124
125 if ((c = recvfrom(pingsock, packet, sizeof(packet), 0,
126 (struct sockaddr *) &from, &fromlen)) < 0) {
127 if (errno == EINTR)
128 continue;
129 perror_msg("recvfrom");
130 continue;
131 }
132 if (c >= 8) { /* icmp6_hdr */
133 pkt = (struct icmp6_hdr *) packet;
134 if (pkt->icmp6_type == ICMP6_ECHO_REPLY)
135 break;
136 }
137 }
138 printf("%s is alive!\n", h->h_name);
139 return;
140}
141
142extern int ping6_main(int argc, char **argv)
143{
144 argc--;
145 argv++;
146 if (argc < 1)
147 show_usage();
148 ping(*argv);
149 return EXIT_SUCCESS;
150}
151
152#else /* ! CONFIG_FEATURE_FANCY_PING6 */
153/* full(er) version */
154static struct sockaddr_in6 pingaddr;
155static int pingsock = -1;
156static int datalen; /* intentionally uninitialized to work around gcc bug */
157static char* ifname;
158
159static long ntransmitted, nreceived, nrepeats, pingcount;
160static int myid, options;
161static unsigned long tmin = ULONG_MAX, tmax, tsum;
162static char rcvd_tbl[MAX_DUP_CHK / 8];
163
164#if CONFIG_FEATURE_FANCY_PING
165extern
166#endif
167 struct hostent *hostent;
168
169static void sendping(int);
170static void pingstats(int);
171static void unpack(char *, int, struct sockaddr_in6 *, int);
172
173/**************************************************************************/
174
175static void pingstats(int junk)
176{
177 int status;
178
179 signal(SIGINT, SIG_IGN);
180
181 printf("\n--- %s ping statistics ---\n", hostent->h_name);
182 printf("%ld packets transmitted, ", ntransmitted);
183 printf("%ld packets received, ", nreceived);
184 if (nrepeats)
185 printf("%ld duplicates, ", nrepeats);
186 if (ntransmitted)
187 printf("%ld%% packet loss\n",
188 (ntransmitted - nreceived) * 100 / ntransmitted);
189 if (nreceived)
190 printf("round-trip min/avg/max = %lu.%lu/%lu.%lu/%lu.%lu ms\n",
191 tmin / 10, tmin % 10,
192 (tsum / (nreceived + nrepeats)) / 10,
193 (tsum / (nreceived + nrepeats)) % 10, tmax / 10, tmax % 10);
194 if (nreceived != 0)
195 status = EXIT_SUCCESS;
196 else
197 status = EXIT_FAILURE;
198 exit(status);
199}
200
201static void sendping(int junk)
202{
203 struct icmp6_hdr *pkt;
204 int i;
205 char packet[datalen + 8];
206
207 pkt = (struct icmp6_hdr *) packet;
208
209 pkt->icmp6_type = ICMP6_ECHO_REQUEST;
210 pkt->icmp6_code = 0;
211 pkt->icmp6_cksum = 0;
212 pkt->icmp6_seq = ntransmitted++;
213 pkt->icmp6_id = myid;
214 CLR(pkt->icmp6_seq % MAX_DUP_CHK);
215
216 gettimeofday((struct timeval *) &pkt->icmp6_data8[4], NULL);
217
218 i = sendto(pingsock, packet, sizeof(packet), 0,
219 (struct sockaddr *) &pingaddr, sizeof(struct sockaddr_in6));
220
221 if (i < 0)
222 perror_msg_and_die("sendto");
223 else if ((size_t)i != sizeof(packet))
224 error_msg_and_die("ping wrote %d chars; %d expected", i,
225 (int)sizeof(packet));
226
227 signal(SIGALRM, sendping);
228 if (pingcount == 0 || ntransmitted < pingcount) { /* schedule next in 1s */
229 alarm(PINGINTERVAL);
230 } else { /* done, wait for the last ping to come back */
231 /* todo, don't necessarily need to wait so long... */
232 signal(SIGALRM, pingstats);
233 alarm(MAXWAIT);
234 }
235}
236
237static char *icmp6_type_name (int id)
238{
239 switch (id) {
240 case ICMP6_DST_UNREACH: return "Destination Unreachable";
241 case ICMP6_PACKET_TOO_BIG: return "Packet too big";
242 case ICMP6_TIME_EXCEEDED: return "Time Exceeded";
243 case ICMP6_PARAM_PROB: return "Parameter Problem";
244 case ICMP6_ECHO_REPLY: return "Echo Reply";
245 case ICMP6_ECHO_REQUEST: return "Echo Request";
246 case ICMP6_MEMBERSHIP_QUERY: return "Membership Query";
247 case ICMP6_MEMBERSHIP_REPORT: return "Membership Report";
248 case ICMP6_MEMBERSHIP_REDUCTION: return "Membership Reduction";
249 default: return "unknown ICMP type";
250 }
251}
252
253static void unpack(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit)
254{
255 struct icmp6_hdr *icmppkt;
256 struct timeval tv, *tp;
257 int dupflag;
258 unsigned long triptime;
259 char buf[INET6_ADDRSTRLEN];
260
261 gettimeofday(&tv, NULL);
262
263 /* discard if too short */
264 if (sz < (datalen + sizeof(struct icmp6_hdr)))
265 return;
266
267 icmppkt = (struct icmp6_hdr *) packet;
268
269 if (icmppkt->icmp6_id != myid)
270 return; /* not our ping */
271
272 if (icmppkt->icmp6_type == ICMP6_ECHO_REPLY) {
273 ++nreceived;
274 tp = (struct timeval *) &icmppkt->icmp6_data8[4];
275
276 if ((tv.tv_usec -= tp->tv_usec) < 0) {
277 --tv.tv_sec;
278 tv.tv_usec += 1000000;
279 }
280 tv.tv_sec -= tp->tv_sec;
281
282 triptime = tv.tv_sec * 10000 + (tv.tv_usec / 100);
283 tsum += triptime;
284 if (triptime < tmin)
285 tmin = triptime;
286 if (triptime > tmax)
287 tmax = triptime;
288
289 if (TST(icmppkt->icmp6_seq % MAX_DUP_CHK)) {
290 ++nrepeats;
291 --nreceived;
292 dupflag = 1;
293 } else {
294 SET(icmppkt->icmp6_seq % MAX_DUP_CHK);
295 dupflag = 0;
296 }
297
298 if (options & O_QUIET)
299 return;
300
301 printf("%d bytes from %s: icmp6_seq=%u", sz,
302 inet_ntop(AF_INET6, (struct in_addr6 *) &pingaddr.sin6_addr,
303 buf, sizeof(buf)),
304 icmppkt->icmp6_seq);
305 printf(" ttl=%d time=%lu.%lu ms", hoplimit,
306 triptime / 10, triptime % 10);
307 if (dupflag)
308 printf(" (DUP!)");
309 printf("\n");
310 } else
311 if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST)
312 error_msg("Warning: Got ICMP %d (%s)",
313 icmppkt->icmp6_type, icmp6_type_name (icmppkt->icmp6_type));
314}
315
316static void ping(const char *host)
317{
318 char packet[datalen + MAXIPLEN + MAXICMPLEN];
319 char buf[INET6_ADDRSTRLEN];
320 int sockopt;
321 struct msghdr msg;
322 struct sockaddr_in6 from;
323 struct iovec iov;
324 char control_buf[CMSG_SPACE(36)];
325
326 pingsock = create_icmp6_socket();
327
328 memset(&pingaddr, 0, sizeof(struct sockaddr_in));
329
330 pingaddr.sin6_family = AF_INET6;
331 hostent = xgethostbyname2(host, AF_INET6);
332 if (hostent->h_addrtype != AF_INET6)
333 error_msg_and_die("unknown address type; only AF_INET6 is currently supported.");
334
335 memcpy(&pingaddr.sin6_addr, hostent->h_addr, sizeof(pingaddr.sin6_addr));
336
337#ifdef ICMP6_FILTER
338 {
339 struct icmp6_filter filt;
340 if (!(options & O_VERBOSE)) {
341 ICMP6_FILTER_SETBLOCKALL(&filt);
342#if 0
343 if ((options & F_FQDN) || (options & F_FQDNOLD) ||
344 (options & F_NODEADDR) || (options & F_SUPTYPES))
345 ICMP6_FILTER_SETPASS(ICMP6_NI_REPLY, &filt);
346 else
347#endif
348 ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &filt);
349 } else {
350 ICMP6_FILTER_SETPASSALL(&filt);
351 }
352 if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt,
353 sizeof(filt)) < 0)
354 error_msg_and_die("setsockopt(ICMP6_FILTER)");
355 }
356#endif /*ICMP6_FILTER*/
357
358 /* enable broadcast pings */
359 sockopt = 1;
360 setsockopt(pingsock, SOL_SOCKET, SO_BROADCAST, (char *) &sockopt,
361 sizeof(sockopt));
362
363 /* set recv buf for broadcast pings */
364 sockopt = 48 * 1024;
365 setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, (char *) &sockopt,
366 sizeof(sockopt));
367
368 sockopt = offsetof(struct icmp6_hdr, icmp6_cksum);
369 setsockopt(pingsock, SOL_RAW, IPV6_CHECKSUM, (char *) &sockopt,
370 sizeof(sockopt));
371
372 sockopt = 1;
373 setsockopt(pingsock, SOL_IPV6, IPV6_HOPLIMIT, (char *) &sockopt,
374 sizeof(sockopt));
375
376 if (ifname) {
377 if ((pingaddr.sin6_scope_id = if_nametoindex(ifname)) == 0)
378 error_msg_and_die("%s: invalid interface name", ifname);
379 }
380
381 printf("PING %s (%s): %d data bytes\n",
382 hostent->h_name,
383 inet_ntop(AF_INET6, (struct in_addr6 *) &pingaddr.sin6_addr,
384 buf, sizeof(buf)),
385 datalen);
386
387 signal(SIGINT, pingstats);
388
389 /* start the ping's going ... */
390 sendping(0);
391
392 /* listen for replies */
393 msg.msg_name=&from;
394 msg.msg_namelen=sizeof(from);
395 msg.msg_iov=&iov;
396 msg.msg_iovlen=1;
397 msg.msg_control=control_buf;
398 iov.iov_base=packet;
399 iov.iov_len=sizeof(packet);
400 while (1) {
401 int c;
402 struct cmsghdr *cmsgptr = NULL;
403 int hoplimit=-1;
404 msg.msg_controllen=sizeof(control_buf);
405
406 if ((c = recvmsg(pingsock, &msg, 0)) < 0) {
407 if (errno == EINTR)
408 continue;
409 perror_msg("recvfrom");
410 continue;
411 }
412 for (cmsgptr = CMSG_FIRSTHDR(&msg); cmsgptr != NULL;
413 cmsgptr = CMSG_NXTHDR(&msg, cmsgptr)) {
414 if (cmsgptr->cmsg_level == SOL_IPV6 &&
415 cmsgptr->cmsg_type == IPV6_HOPLIMIT ) {
416 hoplimit=*(int*)CMSG_DATA(cmsgptr);
417 }
418 }
419 unpack(packet, c, &from, hoplimit);
420 if (pingcount > 0 && nreceived >= pingcount)
421 break;
422 }
423 pingstats(0);
424}
425
426extern int ping6_main(int argc, char **argv)
427{
428 char *thisarg;
429
430 datalen = DEFDATALEN; /* initialized here rather than in global scope to work around gcc bug */
431
432 argc--;
433 argv++;
434 options = 0;
435 /* Parse any options */
436 while (argc >= 1 && **argv == '-') {
437 thisarg = *argv;
438 thisarg++;
439 switch (*thisarg) {
440 case 'v':
441 options &= ~O_QUIET;
442 options |= O_VERBOSE;
443 break;
444 case 'q':
445 options &= ~O_VERBOSE;
446 options |= O_QUIET;
447 break;
448 case 'c':
449 if (--argc <= 0)
450 show_usage();
451 argv++;
452 pingcount = atoi(*argv);
453 break;
454 case 's':
455 if (--argc <= 0)
456 show_usage();
457 argv++;
458 datalen = atoi(*argv);
459 break;
460 case 'I':
461 if (--argc <= 0)
462 show_usage();
463 argv++;
464 ifname = *argv;
465 break;
466 default:
467 show_usage();
468 }
469 argc--;
470 argv++;
471 }
472 if (argc < 1)
473 show_usage();
474
475 myid = getpid() & 0xFFFF;
476 ping(*argv);
477 return EXIT_SUCCESS;
478}
479#endif /* ! CONFIG_FEATURE_FANCY_PING6 */
480
481/*
482 * Copyright (c) 1989 The Regents of the University of California.
483 * All rights reserved.
484 *
485 * This code is derived from software contributed to Berkeley by
486 * Mike Muuss.
487 *
488 * Redistribution and use in source and binary forms, with or without
489 * modification, are permitted provided that the following conditions
490 * are met:
491 * 1. Redistributions of source code must retain the above copyright
492 * notice, this list of conditions and the following disclaimer.
493 * 2. Redistributions in binary form must reproduce the above copyright
494 * notice, this list of conditions and the following disclaimer in the
495 * documentation and/or other materials provided with the distribution.
496 *
497 * 3. <BSD Advertising Clause omitted per the July 22, 1999 licensing change
498 * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change>
499 *
500 * 4. Neither the name of the University nor the names of its contributors
501 * may be used to endorse or promote products derived from this software
502 * without specific prior written permission.
503 *
504 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
505 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
506 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
507 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
508 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
509 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
510 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
511 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
512 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
513 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
514 * SUCH DAMAGE.
515 */
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
332static 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
558static 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
421int route_main(int argc, char **argv) 640int 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}