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 ])]) + +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 +#include +#include +#include + ])]) + +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 +#include +#include + ])]) + +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 +#include +#include +#include + ])]) + 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 +#endif #ifdef HAVE_GETOPT_H #include @@ -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; +}