summaryrefslogtreecommitdiff
path: root/libbb
diff options
context:
space:
mode:
authorEric Andersen2002-07-03 11:46:38 +0000
committerEric Andersen2002-07-03 11:46:38 +0000
commit51b8bd68bb22b1cc5d95e418813c2f08a194ec2b (patch)
tree905d4f1b1e557950272ac98e1540fa06f732f42f /libbb
parent599e3ce163c43c3dfb24d06f8f707c783bc9ab9c (diff)
downloadbusybox-51b8bd68bb22b1cc5d95e418813c2f08a194ec2b.zip
busybox-51b8bd68bb22b1cc5d95e418813c2f08a194ec2b.tar.gz
This patch from Bart Visscher <magick@linux-fan.com> adds
IPV6 support to busybox. This patch does the following: * Add IPv6 support to libbb * Enable IPv6 interface address display * Add IPv6 config option * Adds ping6, an adaptation of the ping applet for IPv6 * Adds support routines for ping6: - xgethostbyname2 - create_icmp6_socket * Adds ifconfig support for IPv6 * Add support IPv6 to netstat * Add IPv6 support to route Thanks Bart!
Diffstat (limited to 'libbb')
-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
5 files changed, 238 insertions, 7 deletions
diff --git a/libbb/Makefile.in b/libbb/Makefile.in
index 2af70f8..70cc26d 100644
--- a/libbb/Makefile.in
+++ b/libbb/Makefile.in
@@ -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
diff --git a/libbb/create_icmp6_socket.c b/libbb/create_icmp6_socket.c
new file mode 100644
index 0000000..a095656
--- /dev/null
+++ b/libbb/create_icmp6_socket.c
@@ -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
diff --git a/libbb/inet_common.c b/libbb/inet_common.c
index c1e5953..c7bf409 100644
--- a/libbb/inet_common.c
+++ b/libbb/inet_common.c
@@ -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 */
diff --git a/libbb/interface.c b/libbb/interface.c
index 9ecb81b..5800e0f 100644
--- a/libbb/interface.c
+++ b/libbb/interface.c
@@ -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;
diff --git a/libbb/xgethostbyname2.c b/libbb/xgethostbyname2.c
new file mode 100644
index 0000000..c66acfe
--- /dev/null
+++ b/libbb/xgethostbyname2.c
@@ -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