diff options
-rw-r--r-- | CHANGES | 5 | ||||
-rw-r--r-- | build/apr_network.m4 | 68 | ||||
-rw-r--r-- | configure.in | 28 | ||||
-rw-r--r-- | network_io/unix/sockaddr.c | 19 |
4 files changed, 100 insertions, 20 deletions
@@ -1,7 +1,8 @@ Changes with APR 0.9.4 - *) Re-enable IPv6 on Darwin 6.6 (and higher) as getaddrinfo() looks to be - doing the right things with IPv4-mapped addresses. [Justin Erenkrantz] + *) Work around a bug in Darwin when calling getnameinfo() on IPv4-mapped + IPv6-addresses. [Colm MacCárthaigh <colm@stdlib.net>, Jeff Trawick, + Justin Erenkrantz] *) Add apr_temp_dir_get() for getting the most suitable temp directory [CMike Pilato <cmpilato@collab.net>, Thom May] diff --git a/build/apr_network.m4 b/build/apr_network.m4 index 73f69bfc6..9f2bb327e 100644 --- a/build/apr_network.m4 +++ b/build/apr_network.m4 @@ -141,6 +141,74 @@ fi ]) dnl +dnl check for getnameinfo() that properly resolves IPv4-mapped IPv6 addresses +dnl +dnl Darwin is known not to map them correctly +dnl +AC_DEFUN(APR_CHECK_GETNAMEINFO_IPV4_MAPPED,[ + AC_CACHE_CHECK(whether getnameinfo resolves IPv4-mapped IPv6 addresses, + ac_cv_getnameinfo_ipv4_mapped,[ + AC_TRY_RUN( [ +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +void main(void) { + struct sockaddr_in6 sa = {0}; + struct in_addr ipv4; + char hbuf[NI_MAXHOST]; + unsigned int *addr32; + int error; + + ipv4.s_addr = inet_addr("127.0.0.1"); + + sa.sin6_family = AF_INET6; + sa.sin6_port = 0; + + addr32 = (unsigned int *)&sa.sin6_addr; + addr32[2] = htonl(0x0000FFFF); + addr32[3] = ipv4.s_addr; + assert(IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)); + +#ifdef SIN6_LEN + sa.sin_len = sizeof(sa); +#endif + + error = getnameinfo((const struct sockaddr *)&sa, sizeof(sa), + hbuf, sizeof(hbuf), NULL, 0, + NI_NUMERICHOST); + if (error) { + exit(1); + } else { + exit(0); + } +} +],[ + ac_cv_getnameinfo_ipv4_mapped="yes" +],[ + ac_cv_getnameinfo_ipv4_mapped="no" +],[ + ac_cv_getnameinfo_ipv4_mapped="yes" +])]) +if test "$ac_cv_getnameinfo_ipv4_mapped" = "no"; then + AC_DEFINE(GETNAMEINFO_IPV4_MAPPED_FAILS, 1, + [Define if getnameinfo does not map IPv4 address correctly]) +fi +]) + +dnl dnl check for presence of retrans/retry variables in the res_state structure dnl AC_DEFUN(APR_CHECK_RESOLV_RETRANS,[ diff --git a/configure.in b/configure.in index 1b39a31a8..48b58bd4c 100644 --- a/configure.in +++ b/configure.in @@ -1797,17 +1797,6 @@ AC_ARG_ENABLE(ipv6, [ user_disabled_ipv6=0 ] ) case $host in - *apple-darwin*) - # It appears that Jaguar has all the right features, but - # getnameinfo() fails to find the hostname for an IPv4mapped - # address. - # All signs point that 6.6 (aka Mac OS 10.2.6+) is okay. - if test $os_version -lt "66"; then - broken_ipv6=1 - else - broken_ipv6=0 - fi - ;; *) broken_ipv6=0 esac @@ -1821,31 +1810,34 @@ APR_CHECK_NEGATIVE_EAI APR_CHECK_WORKING_GETNAMEINFO APR_CHECK_SOCKADDR_IN6 -AC_MSG_CHECKING(if APR supports IPv6) have_ipv6="0" if test "$user_disabled_ipv6" = 1; then - AC_MSG_RESULT([no -- disabled by user]) + ipv6_result="no -- disabled by user" else if test "x$broken_ipv6" = "x0"; then if test "x$have_sockaddr_in6" = "x1"; then if test "x$ac_cv_working_getaddrinfo" = "xyes"; then if test "x$ac_cv_working_getnameinfo" = "xyes"; then + APR_CHECK_GETNAMEINFO_IPV4_MAPPED have_ipv6="1" - AC_MSG_RESULT([yes]) + ipv6_result="yes" else - AC_MSG_RESULT([no -- no getnameinfo]) + ipv6_result="no -- no getnameinfo" fi else - AC_MSG_RESULT([no -- no working getaddrinfo]) + ipv6_result="no -- no working getaddrinfo" fi else - AC_MSG_RESULT([no -- no sockaddr_in6]) + ipv6_result="no -- no sockaddr_in6" fi else - AC_MSG_RESULT([no -- the platform has problems supporting IPv6]) + ipv6_result="no -- the platform has known problems supporting IPv6" fi fi +AC_MSG_CHECKING(if APR supports IPv6) +AC_MSG_RESULT($ipv6_result) + AC_SUBST(have_ipv6) dnl Check for langinfo support diff --git a/network_io/unix/sockaddr.c b/network_io/unix/sockaddr.c index 7e111db18..765252b2e 100644 --- a/network_io/unix/sockaddr.c +++ b/network_io/unix/sockaddr.c @@ -632,10 +632,29 @@ APR_DECLARE(apr_status_t) apr_getnameinfo(char **hostname, /* don't know if it is portable for getnameinfo() to set h_errno; * clear it then see if it was set */ SET_H_ERRNO(0); + /* default flags are NI_NAMREQD; otherwise, getnameinfo() will return * a numeric address string if it fails to resolve the host name; * that is *not* what we want here + * + * Additionally, if we know getnameinfo() doesn't handle IPv4-mapped + * IPv6 addresses correctly, drop down to IPv4 before calling + * getnameinfo(). */ +#ifdef GETNAMEINFO_IPV4_MAPPED_FAILS + if (sockaddr->family == AF_INET6 && + IN6_IS_ADDR_V4MAPPED(&sockaddr->sa.sin6.sin6_addr)) { + struct apr_sockaddr_t tmpsa; + tmpsa.sa.sin.sin_family = AF_INET; + tmpsa.sa.sin.sin_addr.s_addr = ((uint32_t *)sockaddr->ipaddr_ptr)[3]; + + rc = getnameinfo((const struct sockaddr *)&tmpsa.sa, + sizeof(struct sockaddr_in), + tmphostname, sizeof(tmphostname), NULL, 0, + flags != 0 ? flags : NI_NAMEREQD); + } + else +#endif rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen, tmphostname, sizeof(tmphostname), NULL, 0, flags != 0 ? flags : NI_NAMEREQD); |