summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKarsten Keil <kkeil@suse.de>2008-07-23 17:05:24 +0200
committerH. Peter Anvin <hpa@zytor.com>2008-07-23 14:24:19 -0400
commit7fe0fb941cb8ee2562cae02028df4e80f61548f4 (patch)
tree99655ebf9ae9396096b5b72fa0303892668dce9e
parent57ca2819802b3263da69976a4c3f1496e76f677f (diff)
downloadtftp-hpa-7fe0fb941cb8ee2562cae02028df4e80f61548f4.tar.gz
IPv6 infrastructure support
Add autoconf rules to detect IPv6 availability and some of the neeeded support functions. Add stubs for getaddrinfo and inet_ntop. You can disable IPv6 at compile time with ./configure --without-ipv6 Signed-off-by: Karsten Keil <kkeil@suse.de> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--aclocal.m489
-rw-r--r--config.h46
-rw-r--r--configure.in53
-rw-r--r--lib/getaddrinfo.c121
-rw-r--r--lib/inet_ntop.c52
5 files changed, 355 insertions, 6 deletions
diff --git a/aclocal.m4 b/aclocal.m4
index 0ea5f1d..c07702c 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -87,6 +87,71 @@ AC_DEFUN(PA_STRUCT_IN_PKTINFO,
#include <sys/uio.h>
])])
+
+dnl ------------------------------------------------------------------------
+dnl PA_STRUCT_SOCKADDR_IN6
+dnl
+dnl Look for definition of struct sockaddr_in6, which at least has an
+dnl sin6_addr member
+dnl
+AH_TEMPLATE([HAVE_STRUCT_SOCKADDR_IN6],
+[Define if struct sockaddr_in6 is defined.])
+
+AC_DEFUN(PA_STRUCT_SOCKADDR_IN6,
+ [AC_CHECK_MEMBER(struct sockaddr_in6.sin6_addr,
+ [
+ AC_DEFINE(HAVE_STRUCT_SOCKADDR_IN6)
+ HAVE_INET6=true;
+ ],
+ [
+ HAVE_INET6=false;
+ ],
+ [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+ ])])
+
+dnl ------------------------------------------------------------------------
+dnl PA_STRUCT_ADDRINFO
+dnl
+dnl Look for definition of struct addrinfo, which at least has an
+dnl ai_addr member
+dnl
+AH_TEMPLATE([HAVE_STRUCT_ADDRINFO],
+[Define if struct addrinfo is defined.])
+
+AC_DEFUN(PA_STRUCT_ADDRINFO,
+ [AC_CHECK_MEMBER(struct addrinfo.ai_addr,
+ [AC_DEFINE(HAVE_STRUCT_ADDRINFO)],
+ [],
+ [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+ ])])
+
+dnl ------------------------------------------------------------------------
+dnl PA_STRUCT_IN6_PKTINFO
+dnl
+dnl Look for definition of struct in6_pktinfo, which at least has an
+dnl ipi6_addr member
+dnl
+AH_TEMPLATE([HAVE_STRUCT_IN6_PKTINFO],
+[Define if struct in6_pktinfo is defined.])
+
+AC_DEFUN(PA_STRUCT_IN6_PKTINFO,
+ [AC_CHECK_MEMBER(struct in6_pktinfo.ipi6_addr,
+ [AC_DEFINE(HAVE_STRUCT_IN6_PKTINFO)],
+ [],
+ [
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+ ])])
+
dnl --------------------------------------------------------------------------
dnl PA_HAVE_TCPWRAPPERS
dnl
@@ -189,3 +254,27 @@ int main()
[
AC_MSG_RESULT(no)
])])
+
+dnl --------------------------------------------------------------------------
+dnl PA_SEARCH_LIBS_AND_ADD
+dnl
+dnl PA_SEARCH_LIBS_AND_ADD(function, libraries [,function to add])
+dnl --------------------------------------------------------------------------
+
+AC_DEFUN(PA_SEARCH_LIBS_AND_ADD,
+ [
+ AH_TEMPLATE(AS_TR_CPP(HAVE_$1), [Define if $1 function was found])
+ AC_SEARCH_LIBS($1, $2,
+ [
+ AC_DEFINE_UNQUOTED(AS_TR_CPP(HAVE_$1))
+ pa_add_$1=false;
+ ],
+ [
+ XTRA=true;
+ if test $# -eq 3; then
+ AC_LIBOBJ($3)
+ else
+ AC_LIBOBJ($1)
+ fi
+ pa_add_$1=true;
+ ])])
diff --git a/config.h b/config.h
index ed1e39a..38be517 100644
--- a/config.h
+++ b/config.h
@@ -106,6 +106,9 @@
#endif
#endif
#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
#ifdef HAVE_GETOPT_H
#include <getopt.h>
@@ -301,6 +304,49 @@ int dup2(int, int);
int daemon(int, int);
#endif
+#ifndef HAVE_GETADDRINFO
+#ifndef HAVE_STRUCT_ADDRINFO
+struct addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ size_t ai_addrlen;
+ struct sockaddr *ai_addr;
+ char *ai_canonname;
+ struct addrinfo *ai_next;
+};
+#endif
+int getaddrinfo(const char *, const char *, const struct addrinfo *,
+ struct addrinfo **);
+void freeaddrinfo(struct addrinfo *);
+const char *gai_strerror(int);
+
+#ifndef AI_CANONNAME
+#define AI_CANONNAME 0x0002 /* Request for canonical name. */
+#endif
+
+#ifndef EAI_NONAME
+#define EAI_NONAME -2 /* NAME or SERVICE is unknown. */
+#endif
+#ifndef EAI_ADDRFAMILY
+#define EAI_ADDRFAMILY -9 /* Address family for NAME not supported. */
+#endif
+#ifndef EAI_MEMORY
+#define EAI_MEMORY -10 /* Memory allocation failure. */
+#endif
+#ifndef EAI_SYSTEM
+#define EAI_SYSTEM -11 /* System error returned in rrno'. */
+#endif
+#endif
+
+#ifndef HAVE_INET_NTOP
+const char *inet_ntop(int, const void *, char *, socklen_t);
+#ifndef INET6_ADDRSTRLEN
+#define INET6_ADDRSTRLEN 48
+#endif
+#endif
+
/* tftp-hpa version and configuration strings */
#include "version.h"
diff --git a/configure.in b/configure.in
index ddd11da..91fd889 100644
--- a/configure.in
+++ b/configure.in
@@ -52,6 +52,7 @@ AC_CHECK_HEADERS(sys/stat.h)
AC_CHECK_HEADERS(sys/time.h)
AC_CHECK_HEADERS(sys/types.h)
AC_CHECK_HEADERS(arpa/inet.h)
+AC_CHECK_HEADERS(netdb.h)
AC_HEADER_TIME
dnl This is needed on some versions of FreeBSD...
AC_CHECK_HEADERS(machine/param.h)
@@ -118,9 +119,6 @@ AC_CHECK_TYPES(socklen_t,,,
])
AC_SEARCH_LIBS(socket, [socket ws2_32 wsock32], , [AC_MSG_ERROR(socket library not found)])
-AC_SEARCH_LIBS(gethostbyname, [nsl resolv], , [AC_MSG_ERROR(gethostbyname not found)])
-AC_SEARCH_LIBS(inet_aton, [nsl resolv], , [AC_MSG_ERROR(inet_aton not found)])
-AC_SEARCH_LIBS(herror, [nsl resolv], , [AC_MSG_ERROR(herror not found)])
AC_CHECK_FUNCS(fcntl)
AC_CHECK_FUNCS(setsid)
@@ -137,6 +135,7 @@ AC_CHECK_FUNCS(strtoull)
PA_MSGHDR_MSG_CONTROL
PA_STRUCT_IN_PKTINFO
+PA_STRUCT_ADDRINFO
PA_HEADER_DEFINES(fcntl.h, int, O_NONBLOCK)
PA_HEADER_DEFINES(fcntl.h, int, O_BINARY)
@@ -153,9 +152,30 @@ SRCROOT=`cd $srcdir && pwd`
OBJROOT=`pwd`
XTRA=false
-AC_SEARCH_LIBS(xmalloc, iberty, , [XTRA=true; AC_LIBOBJ(xmalloc)])
-AC_SEARCH_LIBS(xstrdup, iberty, , [XTRA=true; AC_LIBOBJ(xstrdup)])
-AC_SEARCH_LIBS(bsd_signal, bsd, , [XTRA=true; AC_LIBOBJ(bsdsignal)])
+PA_SEARCH_LIBS_AND_ADD(xmalloc, iberty)
+PA_SEARCH_LIBS_AND_ADD(xstrdup, iberty)
+PA_SEARCH_LIBS_AND_ADD(bsd_signal, bsd, bsdsignal)
+PA_SEARCH_LIBS_AND_ADD(getaddrinfo, [nsl resolv])
+if $pa_add_getaddrinfo
+then
+ AC_SEARCH_LIBS(gethostbyname, [nsl resolv],
+ [AC_SEARCH_LIBS(herror, [nsl resolv], ,
+ [AC_MSG_ERROR(herror not found)])],
+ [AC_MSG_ERROR(gethostbyname not found)])
+else
+ AC_SEARCH_LIBS(freeaddrinfo, [nsl resolv], ,
+ [AC_MSG_ERROR(getaddrinfo but not freeaddrinfo found)])
+ AC_SEARCH_LIBS(gai_strerror, [nsl resolv], ,
+ [AC_MSG_ERROR(getaddrinfo but not gai_strerror found)])
+fi
+
+PA_SEARCH_LIBS_AND_ADD(inet_ntop, [nsl resolv])
+if $pa_add_inet_ntop
+then
+ AC_SEARCH_LIBS(inet_ntoa, [nsl resolv], ,
+ [AC_MSG_ERROR(inet_ntoa not found)])
+fi
+
AC_CHECK_FUNCS(daemon, , [XTRA=true; AC_LIBOBJ(daemon)])
AC_CHECK_FUNCS(dup2, , [XTRA=true; AC_LIBOBJ(dup2)])
if $XTRA
@@ -226,6 +246,27 @@ PA_WITH_BOOL(readline, 1,
TFTP_LIBS="$LIBS $XTRALIBS"
LIBS="$common_libs"
+dnl
+dnl Check for IPV6 and disable-ipv6
+dnl
+PA_STRUCT_SOCKADDR_IN6
+AC_MSG_CHECKING([for IPv6 support])
+PA_WITH_BOOL(ipv6, 1,
+[ --without-ipv6 disable the support for IPv6],
+[
+ if $HAVE_INET6
+ then
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_IPV6, 1, [Define if IPv6 support is enabled.])
+ PA_STRUCT_IN6_PKTINFO
+ else
+ AC_MSG_RESULT(no)
+ AC_MSG_WARN([*** we do not have required IPv6 structs - IPv6 will be disabled])
+ fi
+],
+[AC_MSG_RESULT(disabled)])
+
+
AC_SUBST(SRCROOT)
AC_SUBST(OBJROOT)
diff --git a/lib/getaddrinfo.c b/lib/getaddrinfo.c
new file mode 100644
index 0000000..ef7c9ae
--- /dev/null
+++ b/lib/getaddrinfo.c
@@ -0,0 +1,121 @@
+/*
+ * getaddrinfo.c
+ *
+ * Simple version of getaddrinfo()
+ *
+ */
+
+#include "config.h"
+
+extern int errno;
+extern int h_errno;
+
+void freeaddrinfo(struct addrinfo *res)
+{
+ if (!res)
+ return;
+ if (res->ai_next)
+ freeaddrinfo(res->ai_next);
+ if (res->ai_addr)
+ free(res->ai_addr);
+ if (res->ai_canonname)
+ free(res->ai_canonname);
+ free(res);
+}
+
+int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints,
+ struct addrinfo **res)
+{
+ struct hostent *host;
+ struct sockaddr *sa;
+ int err, size = 0;
+
+ if ((!node) || (!res)) {
+ errno = EINVAL;
+ return EAI_SYSTEM;
+ }
+ *res = NULL;
+ /* we do not support service in this version */
+ if (service) {
+ errno = EINVAL;
+ return EAI_SYSTEM;
+ }
+ host = gethostbyname(node);
+ if (!host)
+ return EAI_NONAME;
+ if (hints) {
+ if (hints->ai_family != AF_UNSPEC) {
+ if (hints->ai_family != host->h_addrtype)
+ return EAI_ADDRFAMILY;
+ }
+ }
+ *res = malloc(sizeof(struct addrinfo));
+ if (!*res) {
+ return EAI_MEMORY;
+ }
+ memset(*res, 0, sizeof(struct addrinfo));
+ (*res)->ai_family = host->h_addrtype;
+ if (host->h_length) {
+ if (host->h_addrtype == AF_INET)
+ size = sizeof(struct sockaddr_in);
+#ifdef HAVE_IPV6
+ else if (host->h_addrtype == AF_INET6)
+ size = sizeof(struct sockaddr_in6);
+#endif
+ else {
+ free(*res);
+ *res = NULL;
+ return EAI_ADDRFAMILY;
+ }
+ sa = malloc(size);
+ if (!sa) {
+ free(*res);
+ *res = NULL;
+ return EAI_MEMORY;
+ }
+ memset(sa, 0, size);
+ (*res)->ai_addr = sa;
+ (*res)->ai_addrlen = size;
+ sa->sa_family = host->h_addrtype;
+ if (host->h_addrtype == AF_INET)
+ memcpy(&((struct sockaddr_in *)sa)->sin_addr, host->h_addr, host->h_length);
+#ifdef HAVE_IPV6
+ else
+ memcpy(&((struct sockaddr_in6 *)sa)->sin6_addr, host->h_addr, host->h_length);
+#endif
+ }
+ if (host->h_name)
+ (*res)->ai_canonname = strdup(host->h_name);
+
+ /* we only handle the first address entry and do not build a list now */
+ return 0;
+}
+
+
+
+const char *gai_strerror(int errcode)
+{
+ const char *s = NULL;
+
+ switch(errcode) {
+ case 0:
+ s = "no error";
+ break;
+ case EAI_MEMORY:
+ s = "no memory";
+ break;
+ case EAI_SYSTEM:
+ s = strerror(errno);
+ break;
+ case EAI_NONAME:
+ s = hstrerror(h_errno);
+ break;
+ case EAI_ADDRFAMILY:
+ s = "address does not match address family";
+ break;
+ default:
+ s = "unknown error code";
+ break;
+ }
+ return s;
+}
diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c
new file mode 100644
index 0000000..fe8e560
--- /dev/null
+++ b/lib/inet_ntop.c
@@ -0,0 +1,52 @@
+/*
+ * inet_ntop.c
+ *
+ * Simple version of inet_ntop()
+ *
+ */
+
+#include "config.h"
+
+extern int errno;
+
+const char *inet_ntop(int af, const void *src,
+ char *dst, socklen_t cnt)
+{
+ char *p;
+
+ switch(af) {
+ case AF_INET:
+ p = inet_ntoa(*((struct in_addr *)src));
+ if (p) {
+ if (cnt <= strlen(p)) {
+ errno = ENOSPC;
+ dst = NULL;
+ } else
+ strcpy(dst, p);
+ } else
+ dst = NULL;
+ break;
+#ifdef HAVE_IPV6
+ case AF_INET6:
+ if (cnt < 40) {
+ errno = ENOSPC;
+ dst = NULL;
+ } else {
+ struct in6_addr *a = src;
+ int i;
+
+ p = (char *)dst;
+ /* we do not compress :0: to :: */
+ for (i = 0; i < 8; i++)
+ p += sprintf(p, "%x:", ntohs(a->s6_addr16[i]));
+ p--;
+ *p = 0;
+ }
+ break;
+#endif
+ default:
+ errno = EAFNOSUPPORT;
+ dst = NULL;
+ }
+ return dst;
+}