summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES5
-rw-r--r--build/apr_network.m468
-rw-r--r--configure.in28
-rw-r--r--network_io/unix/sockaddr.c19
4 files changed, 100 insertions, 20 deletions
diff --git a/CHANGES b/CHANGES
index 2ecde95a2..95777f51b 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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);