diff options
author | Eric Andersen | 2002-07-03 11:46:38 +0000 |
---|---|---|
committer | Eric Andersen | 2002-07-03 11:46:38 +0000 |
commit | 51b8bd68bb22b1cc5d95e418813c2f08a194ec2b (patch) | |
tree | 905d4f1b1e557950272ac98e1540fa06f732f42f /libbb | |
parent | 599e3ce163c43c3dfb24d06f8f707c783bc9ab9c (diff) | |
download | busybox-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.in | 4 | ||||
-rw-r--r-- | libbb/create_icmp6_socket.c | 39 | ||||
-rw-r--r-- | libbb/inet_common.c | 64 | ||||
-rw-r--r-- | libbb/interface.c | 101 | ||||
-rw-r--r-- | libbb/xgethostbyname2.c | 37 |
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 |