You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@apr.apache.org by Jeff Trawick <tr...@attglobal.net> on 2004/05/18 22:58:14 UTC

unrecognized getnameinfo() bugs dealing with IPv4-mapped addresses

Previously we went through this mess on older Mac OS X (DNS queries only?)

I just realized that the glibc shipping with RHAS 2.1 and 3.0 (and surely many 
other Linux distros) has a problem with getnameinfo() for IPv4-mapped address 
for something defined in host file but not in DNS.

The configure check for this condition fails to note the problem because (at 
least in my environments) the DNS has a mapping for 127.0.0.1->localhost.

Shall we just assume that the GETNAMEINFO_IPV4_MAPPED_FAILS logic can be used 
on all platforms (incurring the minor overhead), instead of trying to be clever?

Re: unrecognized getnameinfo() bugs dealing with IPv4-mapped addresses

Posted by Joe Orton <jo...@manyfish.co.uk>.
On Thu, May 20, 2004 at 01:12:00PM +0100, Colm MacCarthaigh wrote:
> On Thu, May 20, 2004 at 07:37:00AM -0400, Jeff Trawick wrote:
> >      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];
> > +        struct sockaddr_in tmpsa;
> > +        tmpsa.sin_family = AF_INET;
> > +        tmpsa.sin_addr.s_addr = sockaddr->sa.sin6.sin6_addr.s6_addr[3];
> 
> I don't think that's correct, s6_addr is only 8-bits wide, but we need
> 32 bits here.  sockaddr->sa.sin6.sin6_addr.s6_addr[3] will get you bits
> 24 through 32 when we want 96 through 128 :)
> 
> We can't use the s6_addr32 because it's non-standard (and depends on
> _KERNEL on the BSD's I think - though havn't checked recently). I knew
> there was some reason I used the ipaddr_ptr the first time ;p

Ha, well spotted, teach me to try and "optimise" things. I really only
looked at the line after seeing the uint32_t there... so let's just use
the original with s/uint32_t/apr_uint32_t.

joe

Re: unrecognized getnameinfo() bugs dealing with IPv4-mapped addresses

Posted by Colm MacCarthaigh <co...@stdlib.net>.
On Thu, May 20, 2004 at 07:37:00AM -0400, Jeff Trawick wrote:
> updated patch attached to remove configure-time logic and protect 
> references to IPv6 goodies with APR_HAVE_IPV6...
> 
> any comments from the crowd before I commit to both branches?

> ? build-outputs.mk.python
> ? build-outputs.mk.tmp
> ? build.conf.headers
> ? build.conf.paths
> ? build.conf.platform_dirs
> ? gen-build.sh
> ? out
> ? stderr
> ? test.tar
> Index: build/apr_network.m4
> ===================================================================
> RCS file: /home/cvs/apr/build/apr_network.m4,v
> retrieving revision 1.30
> diff -u -r1.30 apr_network.m4
> --- build/apr_network.m4	23 Dec 2003 14:54:55 -0000	1.30
> +++ build/apr_network.m4	20 May 2004 11:33:55 -0000
> @@ -175,80 +175,6 @@
>  ])
>  
>  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
> -#ifdef HAVE_ARPA_INET_H
> -#include <arpa/inet.h>
> -#endif
> -
> -void main(void) {
> -    struct sockaddr_in6 sa = {0};
> -    struct in_addr ipv4;
> -#if defined(NI_MAXHOST)
> -    char hbuf[NI_MAXHOST];
> -#else
> -    char hbuf[256];
> -#endif
> -    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;
> -
> -#ifdef SIN6_LEN
> -    sa.sin6_len = sizeof(sa);
> -#endif
> -
> -    error = getnameinfo((const struct sockaddr *)&sa, sizeof(sa),
> -                        hbuf, sizeof(hbuf), NULL, 0,
> -                        NI_NAMEREQD);
> -    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 Checks the definition of gethostbyname_r and gethostbyaddr_r
>  dnl which are different for glibc, solaris and assorted other operating
>  dnl systems
> Index: network_io/unix/sockaddr.c
> ===================================================================
> RCS file: /home/cvs/apr/network_io/unix/sockaddr.c,v
> retrieving revision 1.49
> diff -u -r1.49 sockaddr.c
> --- network_io/unix/sockaddr.c	4 Mar 2004 16:17:25 -0000	1.49
> +++ network_io/unix/sockaddr.c	20 May 2004 11:33:56 -0000
> @@ -575,27 +575,26 @@
>       * 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().
> +     * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling
> +     * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc).
>       */
> -#ifdef GETNAMEINFO_IPV4_MAPPED_FAILS
> +#if APR_HAVE_IPV6
>      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];
> +        struct sockaddr_in tmpsa;
> +        tmpsa.sin_family = AF_INET;
> +        tmpsa.sin_addr.s_addr = sockaddr->sa.sin6.sin6_addr.s6_addr[3];

I don't think that's correct, s6_addr is only 8-bits wide, but we need
32 bits here.  sockaddr->sa.sin6.sin6_addr.s6_addr[3] will get you bits
24 through 32 when we want 96 through 128 :)

We can't use the s6_addr32 because it's non-standard (and depends on
_KERNEL on the BSD's I think - though havn't checked recently). I knew
there was some reason I used the ipaddr_ptr the first time ;p

-- 
Colm MacCárthaigh                        Public Key: colm+pgp@stdlib.net

Re: unrecognized getnameinfo() bugs dealing with IPv4-mapped addresses

Posted by Joe Orton <jo...@manyfish.co.uk>.
On Thu, May 20, 2004 at 07:37:00AM -0400, Jeff Trawick wrote:
> updated patch attached to remove configure-time logic and protect 
> references to IPv6 goodies with APR_HAVE_IPV6...
> 
> any comments from the crowd before I commit to both branches?

+1 with the call removed from configure.in too.

joe

Re: unrecognized getnameinfo() bugs dealing with IPv4-mapped addresses

Posted by Jeff Trawick <tr...@attglobal.net>.
Joe Orton wrote:
> On Tue, May 18, 2004 at 04:58:14PM -0400, Jeff Trawick wrote:
> 
>>Previously we went through this mess on older Mac OS X (DNS queries only?)
>>
>>I just realized that the glibc shipping with RHAS 2.1 and 3.0 (and surely 
>>many other Linux distros) has a problem with getnameinfo() for IPv4-mapped 
>>address for something defined in host file but not in DNS.
...
>>Shall we just assume that the GETNAMEINFO_IPV4_MAPPED_FAILS logic can be 
>>used on all platforms (incurring the minor overhead), instead of trying to 
>>be clever?
> 
> 
> Sounds very sensible.  The code can be simplified to avoid a pointer
> dereference too...
> 
> --- network_io/unix/sockaddr.c	4 Mar 2004 16:17:25 -0000	1.49
> +++ network_io/unix/sockaddr.c	19 May 2004 09:19:07 -0000

updated patch attached to remove configure-time logic and protect references to 
IPv6 goodies with APR_HAVE_IPV6...

any comments from the crowd before I commit to both branches?

Re: unrecognized getnameinfo() bugs dealing with IPv4-mapped addresses

Posted by Jeff Trawick <tr...@attglobal.net>.
Joe Orton wrote:
> On Tue, May 18, 2004 at 04:58:14PM -0400, Jeff Trawick wrote:
> 
>>Previously we went through this mess on older Mac OS X (DNS queries only?)
>>
>>I just realized that the glibc shipping with RHAS 2.1 and 3.0 (and surely 
>>many other Linux distros) has a problem with getnameinfo() for IPv4-mapped 
>>address for something defined in host file but not in DNS.
> 
> 
> I'll file a bug on that if you haven't already.

I haven't.

> --- network_io/unix/sockaddr.c	4 Mar 2004 16:17:25 -0000	1.49
> +++ network_io/unix/sockaddr.c	19 May 2004 09:19:07 -0000
> @@ -575,27 +575,24 @@
>       * 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().
> +     * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling
> +     * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc).
>       */
> -#ifdef GETNAMEINFO_IPV4_MAPPED_FAILS

need #if APR_HAVE_IPV6 here since we use IPv6 macro and structures

>      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];
> +        struct sockaddr_in tmpsa;
> +        tmpsa.sin_family = AF_INET;
> +        tmpsa.sin_addr.s_addr = sockaddr->sa.sin6.sin6_addr.s6_addr[3];
>  
> -        rc = getnameinfo((const struct sockaddr *)&tmpsa.sa,
> -                         sizeof(struct sockaddr_in),
> +        rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa),
>                           tmphostname, sizeof(tmphostname), NULL, 0,
>                           flags != 0 ? flags : NI_NAMEREQD);
>      }
>      else
> -#endif

#endif /* APR_HAVE_IPV6 */
> -    rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen,
> -                     tmphostname, sizeof(tmphostname), NULL, 0,
> -                     flags != 0 ? flags : NI_NAMEREQD);
> +        rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen,
> +                         tmphostname, sizeof(tmphostname), NULL, 0,
> +                         flags != 0 ? flags : NI_NAMEREQD);
> +
>      if (rc != 0) {
>          *hostname = NULL;

Re: unrecognized getnameinfo() bugs dealing with IPv4-mapped addresses

Posted by Joe Orton <jo...@manyfish.co.uk>.
On Tue, May 18, 2004 at 04:58:14PM -0400, Jeff Trawick wrote:
> Previously we went through this mess on older Mac OS X (DNS queries only?)
> 
> I just realized that the glibc shipping with RHAS 2.1 and 3.0 (and surely 
> many other Linux distros) has a problem with getnameinfo() for IPv4-mapped 
> address for something defined in host file but not in DNS.

I'll file a bug on that if you haven't already.

> The configure check for this condition fails to note the problem because 
> (at least in my environments) the DNS has a mapping for 
> 127.0.0.1->localhost.
> 
> Shall we just assume that the GETNAMEINFO_IPV4_MAPPED_FAILS logic can be 
> used on all platforms (incurring the minor overhead), instead of trying to 
> be clever?

Sounds very sensible.  The code can be simplified to avoid a pointer
dereference too...

--- network_io/unix/sockaddr.c	4 Mar 2004 16:17:25 -0000	1.49
+++ network_io/unix/sockaddr.c	19 May 2004 09:19:07 -0000
@@ -575,27 +575,24 @@
      * 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().
+     * For IPv4-mapped IPv6 addresses, drop down to IPv4 before calling
+     * getnameinfo() to avoid getnameinfo bugs (MacOS X, glibc).
      */
-#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];
+        struct sockaddr_in tmpsa;
+        tmpsa.sin_family = AF_INET;
+        tmpsa.sin_addr.s_addr = sockaddr->sa.sin6.sin6_addr.s6_addr[3];
 
-        rc = getnameinfo((const struct sockaddr *)&tmpsa.sa,
-                         sizeof(struct sockaddr_in),
+        rc = getnameinfo((const struct sockaddr *)&tmpsa, sizeof(tmpsa),
                          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);
+        rc = getnameinfo((const struct sockaddr *)&sockaddr->sa, sockaddr->salen,
+                         tmphostname, sizeof(tmphostname), NULL, 0,
+                         flags != 0 ? flags : NI_NAMEREQD);
+
     if (rc != 0) {
         *hostname = NULL;