Hi,
NetBSD, and I suspect others BSDs, and maybe other systems too, have v4-mapped
addresses support disabled by default (because it can lead to misconfigurations,
with security issues, search  draft-itojun-v6ops-v4mapped-harmful on google
for details). This means that, on these systems, a v6-enabled wget can't
talk to v4 servers.

The attached patches are what I commited to the NetBSD pkgsrc system.
They make wget use INET4 sockets for ipv4 addresses. I tested this
with both v6 and v4, http and ftp active and passive) servers. I don't
think it would cause problems on others systems either.

-- 
Manuel Bouyer <[EMAIL PROTECTED]>
     NetBSD: 26 ans d'experience feront toujours la difference
--
$NetBSD: patch-aa,v 1.7 2005/01/25 20:07:25 bouyer Exp $

--- src/connect.c.orig  Sat Nov  1 15:08:22 2003
+++ src/connect.c       Sun Jan 23 22:11:24 2005
@@ -155,11 +155,11 @@
   int sock, save_errno;
 
   /* Set port and protocol */
-  wget_sockaddr_set_address (&sa, ip_default_family, port, addr);
+  wget_sockaddr_set_address (&sa, port, addr, addr->family);
 
   if (!silent)
     {
-      char *pretty_addr = pretty_print_address (addr);
+      char *pretty_addr = pretty_print_address (addr->bytes);
       if (connection_host_name
          && 0 != strcmp (connection_host_name, pretty_addr))
        logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "),
@@ -170,7 +170,7 @@
     }
 
   /* Make an internet socket, stream type.  */
-  sock = socket (ip_default_family, SOCK_STREAM, 0);
+  sock = socket (addr->family, SOCK_STREAM, 0);
   if (sock < 0)
     goto out;
 
@@ -196,8 +196,8 @@
     {
       /* Bind the client side to the requested address. */
       wget_sockaddr bsa;
-      wget_sockaddr_set_address (&bsa, ip_default_family, 0, &bind_address);
-      if (bind (sock, &bsa.sa, sockaddr_len ()))
+      wget_sockaddr_set_address (&bsa, 0, &bind_address, bind_address.family);
+      if (bind (sock, &bsa.sa, sockaddr_len (bind_address.family)))
        {
          CLOSE (sock);
          sock = -1;
@@ -206,7 +206,7 @@
     }
 
   /* Connect the socket to the remote host.  */
-  if (connect_with_timeout (sock, &sa.sa, sockaddr_len (),
+  if (connect_with_timeout (sock, &sa.sa, sockaddr_len (addr->family),
                            opt.connect_timeout) < 0)
     {
       CLOSE (sock);
@@ -248,8 +248,11 @@
 
       sock = connect_to_one (&addr, port, silent);
       if (sock >= 0)
-       /* Success. */
-       return sock;
+        {
+         /* Success. */
+          ip_default_family = addr.family;
+         return sock;
+        }
 
       address_list_set_faulty (al, i);
 
@@ -316,9 +319,10 @@
 #endif
 
   resolve_bind_address ();
-  wget_sockaddr_set_address (&srv, ip_default_family, htons (*port),
-                            bind_address_resolved ? &bind_address : NULL);
-  if (bind (msock, &srv.sa, sockaddr_len ()) < 0)
+  wget_sockaddr_set_address (&srv, htons (*port),
+                            bind_address_resolved ? &bind_address : NULL,
+                             family);
+  if (bind (msock, &srv.sa, sockaddr_len (family)) < 0)
     {
       CLOSE (msock);
       msock = -1;
@@ -327,7 +331,7 @@
   DEBUGP (("Master socket fd %d bound.\n", msock));
   if (!*port)
     {
-      socklen_t sa_len = sockaddr_len ();
+      socklen_t sa_len = sockaddr_len (family);
       if (getsockname (msock, &srv.sa, &sa_len) < 0)
        {
          CLOSE (msock);
@@ -389,7 +393,7 @@
 uerr_t
 acceptport (int *sock)
 {
-  socklen_t addrlen = sockaddr_len ();
+  socklen_t addrlen = sockaddr_len (ip_default_family);
 
 #ifdef HAVE_SELECT
   if (opt.connect_timeout)
@@ -429,11 +433,13 @@
     {
 #ifdef ENABLE_IPV6
     case AF_INET6:
-      memcpy (ip, &mysrv.sin6.sin6_addr, 16);
+      memcpy (ip->bytes, &mysrv.sin6.sin6_addr, 16);
+      ip->family = AF_INET6;
       return 1;
 #endif
     case AF_INET:
-      map_ipv4_to_ip ((ip4_address *)&mysrv.sin.sin_addr, ip);
+      memcpy (ip->bytes, &mysrv.sin.sin_addr, 4);
+      ip->family = AF_INET;
       return 1;
     default:
       abort ();
$NetBSD: patch-ab,v 1.7 2005/01/25 20:07:25 bouyer Exp $

--- src/ftp-basic.c.orig        Sat Nov  8 20:17:55 2003
+++ src/ftp-basic.c     Sun Jan 23 22:20:35 2005
@@ -267,7 +267,7 @@
 
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
-  err = bindport (&port, ip_default_family);
+  err = bindport (&port, AF_INET6);
   if (err != BINDOK)   /* Bind the port.  */
     return err;
 
@@ -275,7 +275,8 @@
   if (!conaddr (RBUF_FD (rbuf), &in_addr))
     /* Huh?  This is not BINDERR! */
     return BINDERR;
-  inet_ntop (AF_INET6, &in_addr, ipv6, sizeof (ipv6));
+  inet_ntop (AF_INET6, in_addr.bytes, ipv6, sizeof (ipv6));
+  in_addr.family = AF_INET6;
 
   /* Construct the argument of EPRT (of the form |2|IPv6.ascii|PORT.ascii|). */
   bytes = alloca (3 + strlen (ipv6) + 1 + numdigit (port) + 1 + 1);
@@ -319,8 +320,6 @@
   char bytes[6 * 4 +1];
 
   ip_address in_addr;
-  ip4_address in_addr_4;
-  unsigned char *in_addr4_ptr = (unsigned char *)&in_addr_4;
 
   int nwritten;
   unsigned short port;
@@ -347,16 +346,14 @@
   if (!conaddr (RBUF_FD (rbuf), &in_addr))
     /* Huh?  This is not BINDERR! */
     return BINDERR;
-  if (!map_ip_to_ipv4 (&in_addr, &in_addr_4))
-    return BINDERR;
 
   /* Construct the argument of PORT (of the form a,b,c,d,e,f).  Port
      is unsigned short so (unsigned) (port & 0xff000) >> 8 is the same
      like port >> 8
    */
   sprintf (bytes, "%d,%d,%d,%d,%d,%d",
-          in_addr4_ptr[0], in_addr4_ptr[1], in_addr4_ptr[2], in_addr4_ptr[3],
-          port >> 8, port & 0xff);
+          in_addr.bytes[0], in_addr.bytes[1], in_addr.bytes[2],
+           in_addr.bytes[3], port >> 8, port & 0xff);
   /* Send PORT request.  */
   request = ftp_request ("PORT", bytes);
   nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
@@ -426,10 +423,12 @@
     switch(remote.sa.sa_family)
       {
         case AF_INET6:
-          memcpy (addr, &remote.sin6.sin6_addr, 16);
+          memcpy (&addr->bytes[0], &remote.sin6.sin6_addr, 16);
+          addr->family =   AF_INET6;
          break;
        case AF_INET:  
-          map_ipv4_to_ip ((ip4_address *)&ipv4_sock->sin_addr, addr);
+          memcpy (&addr->bytes[0], &remote.sin.sin_addr, 4);
+          addr->family =   AF_INET;
          break;
        default:
          abort();
@@ -454,15 +453,12 @@
   unsigned char addr4[4];
 
 #ifdef ENABLE_IPV6
-  if (ip_default_family == AF_INET6) 
-    {
       err = ftp_epsv (rbuf, addr, port, "2");  /* try IPv6 with EPSV */
       if (FTPOK == err) 
         return FTPOK;
       err = ftp_epsv (rbuf, addr, port, "1");  /* try IPv4 with EPSV */
       if (FTPOK == err) 
         return FTPOK;
-    }
 #endif  
   /* Form the request.  */
   request = ftp_request ("PASV", NULL);
@@ -505,9 +501,8 @@
           return FTPINVPASV;
         }
     }
-
-  /* Eventually make an IPv4 in IPv6 adress if needed */
-  map_ipv4_to_ip ((ip4_address *)addr4, addr);
+  memcpy(addr->bytes, addr4, 4);
+  addr->family = AF_INET;
 
   *port=0;
   for (; ISDIGIT (*s); s++)
@@ -526,7 +521,7 @@
       port2 = (*s - '0') + 10 * port2;
     *port = (*port) * 256 + port2;
   }
-  xfree (respline);
+  xfree (respline); 
   return FTPOK;
 }
 
$NetBSD: patch-ac,v 1.7 2005/01/25 20:07:25 bouyer Exp $

--- src/host.c.orig     Sun Oct 26 02:38:25 2003
+++ src/host.c  Sun Jan 23 21:23:28 2005
@@ -189,13 +189,15 @@
     if (ai->ai_family == AF_INET6) 
       {
        struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
-       memcpy (al->addresses + i, &sin6->sin6_addr, 16);
+       memcpy (al->addresses[i].bytes, &sin6->sin6_addr, 16);
+       al->addresses[i].family = AF_INET6;
        ++i;
       } 
     else if (ai->ai_family == AF_INET)
       {
        struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr;
-        map_ipv4_to_ip ((ip4_address *)&sin->sin_addr, al->addresses + i);
+       memcpy (al->addresses[i].bytes, &sin->sin_addr, 4);
+       al->addresses[i].family = AF_INET;
        ++i;
       }
   assert (i == cnt);
@@ -219,8 +221,11 @@
   al->addresses = xmalloc (count * sizeof (ip_address));
   al->refcount  = 1;
 
-  for (i = 0; i < count; i++)
-    map_ipv4_to_ip ((ip4_address *)h_addr_list[i], al->addresses + i);
+  for (i = 0; i < count; i++) {
+    memcpy (al->addresses[i].bytes, h_addr_list[i], 4);
+    al->addresses[i].family = AF_INET;
+  }
+
 
   return al;
 }
@@ -279,33 +284,29 @@
   */
 void
 wget_sockaddr_set_address (wget_sockaddr *sa, 
-                          int ip_family, unsigned short port, ip_address *addr)
+                          unsigned short port, ip_address *addr, int family)
 {
-  if (ip_family == AF_INET) 
+  if (family == AF_INET)
     {
-      sa->sin.sin_family = ip_family;
+      sa->sin.sin_family = AF_INET;
       sa->sin.sin_port = htons (port);
       if (addr == NULL) 
        memset (&sa->sin.sin_addr, 0,      sizeof(ip4_address));
       else
        {
-         ip4_address addr4;
-         if (!map_ip_to_ipv4 (addr, &addr4))
-           /* should the callers have prevented this? */
-           abort ();
-         memcpy (&sa->sin.sin_addr, &addr4, sizeof(ip4_address));
+         memcpy (&sa->sin.sin_addr, addr->bytes, sizeof(ip4_address));
        }
       return;
     }
 #ifdef ENABLE_IPV6
-  if (ip_family == AF_INET6) 
+  if (family == AF_INET6)
     {
-      sa->sin6.sin6_family = ip_family;
+      sa->sin6.sin6_family = AF_INET6;
       sa->sin6.sin6_port = htons (port);
       if (addr == NULL) 
        memset (&sa->sin6.sin6_addr, 0   , 16);
       else          
-       memcpy (&sa->sin6.sin6_addr, addr, 16);
+       memcpy (&sa->sin6.sin6_addr, addr->bytes, 16);
       return;
     }
 #endif  
@@ -422,12 +423,12 @@
   * socklen_t  structure length for socket options
   */
 socklen_t
-sockaddr_len () 
+sockaddr_len (int family) 
 {
-  if (ip_default_family == AF_INET) 
+  if (family == AF_INET) 
     return sizeof (struct sockaddr_in);
 #ifdef ENABLE_IPV6
-  if (ip_default_family == AF_INET6) 
+  if (family == AF_INET6) 
     return sizeof (struct sockaddr_in6);
 #endif
   abort();
@@ -435,42 +436,6 @@
   return 0;
 }
 
-/**
-  * Map an IPv4 adress to the internal adress format.
-  */
-void 
-map_ipv4_to_ip (ip4_address *ipv4, ip_address *ip) 
-{
-#ifdef ENABLE_IPV6
-  static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
-  memcpy ((char *)ip + 12, ipv4 , 4);
-  memcpy ((char *)ip + 0, ipv64, 12);
-#else
-  if ((char *)ip != (char *)ipv4)
-    memcpy (ip, ipv4, 4);
-#endif
-}
-
-/* Detect whether an IP adress represents an IPv4 address and, if so,
-   copy it to IPV4.  0 is returned on failure.
-   This operation always succeeds when Wget is compiled without IPv6.
-   If IPV4 is NULL, don't copy, just detect.  */
-
-int 
-map_ip_to_ipv4 (ip_address *ip, ip4_address *ipv4) 
-{
-#ifdef ENABLE_IPV6
-  static unsigned char ipv64[12] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff};
-  if (0 != memcmp (ip, ipv64, 12))
-    return 0;
-  if (ipv4)
-    memcpy (ipv4, (char *)ip + 12, 4);
-#else
-  if (ipv4)
-    memcpy (ipv4, (char *)ip, 4);
-#endif
-  return 1;
-}
 
 /* Versions of gethostbyname and getaddrinfo that support timeout. */
 
@@ -559,17 +524,16 @@
 pretty_print_address (ip_address *addr)
 {
 #ifdef ENABLE_IPV6
-  ip4_address addr4;
   static char buf[128];
 
-  if (map_ip_to_ipv4 (addr, &addr4))
-    return inet_ntoa (*(struct in_addr *)&addr4);
-
-  if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf)))
-    return "<unknown>";
-  return buf;
+  if (addr->family == AF_INET6)
+    {
+      if (!inet_ntop (AF_INET6, addr->bytes, buf, sizeof (buf)))
+        return "<unknown>";
+      return buf;
+    }
 #endif
-  return inet_ntoa (*(struct in_addr *)addr);
+  return inet_ntoa (*(struct in_addr *)addr->bytes);
 }
 
 /* Add host name HOST with the address ADDR_TEXT to the cache.
@@ -601,23 +565,27 @@
 lookup_host (const char *host, int silent)
 {
   struct address_list *al = NULL;
-  uint32_t addr_ipv4;
   ip_address addr;
+  u_int32_t addr4;
 
   /* First, try to check whether the address is already a numeric
      address.  */
 
 #ifdef ENABLE_IPV6
-  if (inet_pton (AF_INET6, host, &addr) > 0)
-    return address_list_from_single (&addr);
+  if (inet_pton (AF_INET6, host, addr.bytes) > 0)
+    {
+      addr.family = AF_INET6;
+      return address_list_from_single (&addr);
+    }
 #endif
 
-  addr_ipv4 = (uint32_t)inet_addr (host);
-  if (addr_ipv4 != (uint32_t)-1)
+  addr4 = (uint32_t)inet_addr (host);
+  memcpy(addr.bytes, &addr4, 4);
+  addr.family = AF_INET;
+  if (addr4 != (uint32_t)-1)
     {
       /* ADDR is defined to be in network byte order, which is what
         this returns, so we can just copy it to STORE_IP.  */
-      map_ipv4_to_ip ((ip4_address *)&addr_ipv4, &addr);
       return address_list_from_single (&addr);
     }
 
$NetBSD: patch-ad,v 1.8 2005/01/25 20:07:25 bouyer Exp $

--- src/host.h.orig     Sat Oct 11 03:39:07 2003
+++ src/host.h  Sun Jan 23 21:22:57 2005
@@ -71,6 +71,7 @@
 
 typedef struct {
   unsigned char bytes[MAX_IP_ADDRESS_SIZE];
+  int family;
 } ip_address;
 
 /* Function declarations */
@@ -92,14 +93,12 @@
 
 void host_cleanup PARAMS ((void));
 
-void wget_sockaddr_set_address PARAMS((wget_sockaddr *, int, 
-                                      unsigned short, ip_address *));
+void wget_sockaddr_set_address PARAMS((wget_sockaddr *,
+                                      unsigned short, ip_address *, int));
 void wget_sockaddr_set_port PARAMS((wget_sockaddr *, unsigned short));
 void *wget_sockaddr_get_addr PARAMS((wget_sockaddr *));
 unsigned short wget_sockaddr_get_port PARAMS((const wget_sockaddr *));
-socklen_t sockaddr_len PARAMS(());
-void map_ipv4_to_ip PARAMS((ip4_address *, ip_address *));
-int  map_ip_to_ipv4 PARAMS((ip_address *, ip4_address *));
+socklen_t sockaddr_len PARAMS((int));
  
 extern int     ip_default_family;      /* defined in host.c */
 

Reply via email to