On Mon, Aug 25, 2003 at 12:19:27PM -0400, Jeff Trawick wrote:
> >IPv6 with Apache on tru64 has been broken for a while now, and I finally 
> >got round to figuring out what it was. It appears that Tru64's
> >getaddrinfo returns ai_addrlen of 32 for AF_INET6 address, but that
> >sizeof(struct sockaddr_in6) is 28.
> >
> >This meant that apr_sockaddr_vars_set() was blindly setting salen
> >to 28, and then later when Apache called bind( , , 28) Tru64 bombed
> >out in unpleasant error land. Patch attached. 
> 
> I'm not sure I would use the word "blindly", as we're using 
> sizeof(sockaddr_in6). 

True, but the return of getaddrinfo is being ignored is what I mean.

> If getaddrinfo() returns IPv6 addresses larger 
> than that, we're hosed at that point and shouldn't be copying into the 
> apr_sockaddr_info_t anyway.

We get away with it, just about. Allthough the full length is
copied; 

    429         new_sa->pool = p;
    430         memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen);
    431         apr_sockaddr_vars_set(new_sa, ai->ai_family, port);

it's salen itself that gets overwritten. This then gets reset back
to a sensible value with the assignment in vars_set and the patch.
It's moderately bold, but it works out fine.

Now, back to the reason why it does any of this; bind() is expecting
a struct sockaddr_in6.sin6_addr to be passed, which would make the
extra 4 bytes it's looking for correspond to sockaddr_in6.sin6_scope_id. 
This makes sense in a freaky-dec-developer kind of way, though it really 
is a bug. 

I'm guessing it means that the devlopers originally thought it might 
be useful to allow people to bind() to scoped addresses , and to do 
this you'd need an interface index (for the unitiated; IPv6 scoped 
addresses are interface-specific).

Now, because in Apache the address we pass is always global unicast
and IN6_IS_ADDR_LINKLOCAL/IN6_IS_ADDR_SITELOCAL/IN6_IS_ADDR_MULTICAST
are never going to evaluate to true, bind() never bothers looking
for the scope id. Which is a good thing since binding to the 32nd
system interface would probably not be the desired behaviour.

> Isn't the first step to see why getaddrinfo() is returning IPv6 
> addresses larger than sizeof(sockaddr_in6) and take it from there? 

I really should have included that. It's an OS bug, but it's 
a consistent one. bind() simply fails if passed 28, and works
fine with 32, so we might aswell pass it what it wants. I 
have it running right now at http://listserv.heanet.ie/ .

Actually now that I think about it, maybe the patch below is a
better idea. 

> (Alternatively, why am I confused?)

I am too, but I've been playing with it all day now and it really
does behave like this. Nothing on DU suprises me anymore.

-- 
Colm MacCárthaigh                        Public Key: [EMAIL PROTECTED]
[EMAIL PROTECTED]                                         http://www.stdlib.net/
Index: srclib/apr/network_io/unix/sockaddr.c
===================================================================
RCS file: /home/cvspublic/apr/network_io/unix/sockaddr.c,v
retrieving revision 1.42
diff -u -u -r1.42 sockaddr.c
--- srclib/apr/network_io/unix/sockaddr.c       15 Aug 2003 02:21:55 -0000      
1.42
+++ srclib/apr/network_io/unix/sockaddr.c       25 Aug 2003 16:55:21 -0000
@@ -429,6 +429,19 @@
         new_sa->pool = p;
         memcpy(&new_sa->sa, ai->ai_addr, ai->ai_addrlen);
         apr_sockaddr_vars_set(new_sa, ai->ai_family, port);
+    
+#if defined(OSF1) 
+        /* Tru64 has a getaddrinfo/bind bug in that that it
+         * returns and expects ai_addrlen = 32 for AF_INET6, 
+         * even though sizeof(struct sockaddr_in6) == 28. 
+         * Allthough the memcpy above has over-written salen, 
+         * which then got reset by apr_sockaddr_vars we get away 
+         * with it. Tru64 bind(), in it's infinite wisdom, 
+         * doesn't bother checking the extra 4 bytes for global 
+         * unicast IPv6 addresses. 
+         */ 
+        new_sa->salen = ai->ai_addrlen;
+#endif
 
         if (!prev_sa) { /* first element in new list */
             if (hostname) {

Reply via email to