]> sjero.net Git - wget/commitdiff
[svn] Imported Mauro's IPv6 changes.
authorhniksic <devnull@localhost>
Wed, 29 Oct 2003 18:23:56 +0000 (10:23 -0800)
committerhniksic <devnull@localhost>
Wed, 29 Oct 2003 18:23:56 +0000 (10:23 -0800)
src/connect.c
src/connect.h
src/ftp-basic.c
src/ftp.c
src/ftp.h
src/host.c
src/host.h
src/http.c

index 2fc232356ff07209d07122c4ce4c2963dbd93fee..252cf5126942ef622c8aa356901d0c494865a111 100644 (file)
@@ -67,32 +67,44 @@ extern int errno;
 
 /* Variables shared by bindport and acceptport: */
 static int msock = -1;
-static struct sockaddr *addr;
+/*static struct sockaddr *addr;*/
 
-static ip_address bind_address;
-static int bind_address_resolved;
-
-static void
-resolve_bind_address (void)
+static int
+resolve_bind_address (int flags, ip_address *addr)
 {
-  struct address_list *al;
+  struct address_list *al = NULL;
+  int bind_address_resolved = 0;
 
-  if (bind_address_resolved || opt.bind_address == NULL)
-    /* Nothing to do. */
-    return;
+  if (opt.bind_address != NULL)
+    {
+      al = lookup_host (opt.bind_address, flags | LH_SILENT | LH_PASSIVE);
+
+      if (al == NULL)
+        {
+          logprintf (LOG_NOTQUIET,
+                    _("Unable to convert `%s' to a bind address.  Reverting to ANY.\n"),
+                    opt.bind_address);
+       }
+      else 
+        bind_address_resolved = 1;
+    }
 
-  al = lookup_host (opt.bind_address, 1);
-  if (!al)
+  if (al == NULL)
     {
-      logprintf (LOG_NOTQUIET,
-                _("Unable to convert `%s' to a bind address.  Reverting to ANY.\n"),
-                opt.bind_address);
-      return;
+      const char *unspecified_address = "0.0.0.0";
+#ifdef ENABLE_IPV6
+      if (flags & BIND_ON_IPV6_ONLY)
+       unspecified_address = "::";
+#endif
+      al = lookup_host (unspecified_address, LH_SILENT | LH_PASSIVE);
     }
 
-  address_list_copy_one (al, 0, &bind_address);
+  assert (al != NULL);
+
+  address_list_copy_one (al, 0, addr);
   address_list_release (al);
-  bind_address_resolved = 1;
+
+  return bind_address_resolved;
 }
 \f
 struct cwt_context {
@@ -151,15 +163,16 @@ set_connection_host_name (const char *host)
 int
 connect_to_one (ip_address *addr, unsigned short port, int silent)
 {
-  wget_sockaddr sa;
+  struct sockaddr_storage ss;
+  struct sockaddr *sa = (struct sockaddr *)&ss;
   int sock, save_errno;
 
   /* Set port and protocol */
-  wget_sockaddr_set_address (&sa, ip_default_family, port, addr);
+  sockaddr_set_address (sa, port, addr);
 
   if (!silent)
     {
-      char *pretty_addr = pretty_print_address (addr);
+      const char *pretty_addr = pretty_print_address (addr);
       if (connection_host_name
          && 0 != strcmp (connection_host_name, pretty_addr))
        logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "),
@@ -170,7 +183,7 @@ connect_to_one (ip_address *addr, unsigned short port, int silent)
     }
 
   /* Make an internet socket, stream type.  */
-  sock = socket (ip_default_family, SOCK_STREAM, 0);
+  sock = socket (sa->sa_family, SOCK_STREAM, 0);
   if (sock < 0)
     goto out;
 
@@ -191,22 +204,26 @@ connect_to_one (ip_address *addr, unsigned short port, int silent)
         `--post-file', also set SO_SNDBUF here.  */
     }
 
-  resolve_bind_address ();
-  if (bind_address_resolved)
+  if (opt.bind_address)
     {
       /* 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 ()))
-       {
-         CLOSE (sock);
-         sock = -1;
-         goto out;
+      ip_address bind_address;
+      if (resolve_bind_address (0, &bind_address))
+        {
+          struct sockaddr_storage bss;
+          struct sockaddr *bsa = (struct sockaddr *)&bss;
+          sockaddr_set_address (bsa, 0, &bind_address);
+          if (bind (sock, bsa, sockaddr_len (bsa)))
+           {
+             CLOSE (sock);
+             sock = -1;
+             goto out;
+           }
        }
     }
 
   /* Connect the socket to the remote host.  */
-  if (connect_with_timeout (sock, &sa.sa, sockaddr_len (),
+  if (connect_with_timeout (sock, sa, sockaddr_len (sa),
                            opt.connect_timeout) < 0)
     {
       CLOSE (sock);
@@ -297,28 +314,47 @@ test_socket_open (int sock)
    chosen by the system, and its value is stored to *PORT.  The
    internal variable MPORT is set to the value of the ensuing master
    socket.  Call acceptport() to block for and accept a connection.  */
+
 uerr_t
-bindport (unsigned short *port, int family)
+bindport (const ip_address *bind_address, unsigned short *port)
 {
-  int optval = 1;
-  wget_sockaddr srv;
-  memset (&srv, 0, sizeof (wget_sockaddr));
+  int family = AF_INET;
+  int optval;
+  struct sockaddr_storage ss;
+  struct sockaddr *sa = (struct sockaddr *)&ss;
+  memset (&ss, 0, sizeof (ss));
 
   msock = -1;
 
+#ifdef ENABLE_IPV6
+  if (bind_address->type == IPv6_ADDRESS) 
+    family = AF_INET6;
+#endif
+  
   if ((msock = socket (family, SOCK_STREAM, 0)) < 0)
     return CONSOCKERR;
 
 #ifdef SO_REUSEADDR
+  optval = 1;
   if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR,
                  (char *)&optval, sizeof (optval)) < 0)
     return CONSOCKERR;
 #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)
+#ifdef ENABLE_IPV6
+# ifdef HAVE_IPV6_V6ONLY
+  if (family == AF_INET6)
+    {
+      optval = 1;
+      /* if setsockopt fails, go on anyway */
+      setsockopt (msock, IPPROTO_IPV6, IPV6_V6ONLY,
+                  (char *)&optval, sizeof (optval));
+    }
+# endif
+#endif
+  
+  sockaddr_set_address (sa, htons (*port), bind_address);
+  if (bind (msock, sa, sockaddr_len (sa)) < 0)
     {
       CLOSE (msock);
       msock = -1;
@@ -327,15 +363,16 @@ bindport (unsigned short *port, int family)
   DEBUGP (("Master socket fd %d bound.\n", msock));
   if (!*port)
     {
-      socklen_t sa_len = sockaddr_len ();
-      if (getsockname (msock, &srv.sa, &sa_len) < 0)
+      socklen_t sa_len = sockaddr_len (sa);
+      if (getsockname (msock, sa, &sa_len) < 0)
        {
          CLOSE (msock);
          msock = -1;
          return CONPORTERR;
        }
-      *port = wget_sockaddr_get_port (&srv);
-      DEBUGP (("using port %i.\n", *port));
+      *port = sockaddr_get_port (sa);
+      DEBUGP (("binding to address %s using port %i.\n", 
+              pretty_print_address (bind_address), *port));
     }
   if (listen (msock, 1) < 0)
     {
@@ -389,13 +426,15 @@ select_fd (int fd, double maxtime, int writep)
 uerr_t
 acceptport (int *sock)
 {
-  socklen_t addrlen = sockaddr_len ();
+  struct sockaddr_storage ss;
+  struct sockaddr *sa = (struct sockaddr *)&ss;
+  socklen_t addrlen = sizeof (ss);
 
 #ifdef HAVE_SELECT
   if (select_fd (msock, opt.connect_timeout, 0) <= 0)
     return ACCEPTERR;
 #endif
-  if ((*sock = accept (msock, addr, &addrlen)) < 0)
+  if ((*sock = accept (msock, sa, &addrlen)) < 0)
     return ACCEPTERR;
   DEBUGP (("Created socket fd %d.\n", *sock));
   return ACCEPTOK;
@@ -419,24 +458,34 @@ closeport (int sock)
 int
 conaddr (int fd, ip_address *ip)
 {
-  wget_sockaddr mysrv;
-  socklen_t addrlen = sizeof (mysrv);  
-  if (getsockname (fd, &mysrv.sa, &addrlen) < 0)
+  struct sockaddr_storage ss;
+  struct sockaddr *sa = (struct sockaddr *)&ss;
+  socklen_t addrlen = sizeof (ss);     
+
+  if (getsockname (fd, sa, &addrlen) < 0)
     return 0;
 
-  switch (mysrv.sa.sa_family)
+  switch (sa->sa_family)
     {
 #ifdef ENABLE_IPV6
     case AF_INET6:
-      memcpy (ip, &mysrv.sin6.sin6_addr, 16);
+      ip->type = IPv6_ADDRESS;
+      ip->addr.ipv6.addr = ((struct sockaddr_in6 *)sa)->sin6_addr;
+#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
+      ip->addr.ipv6.scope_id = ((struct sockaddr_in6 *)sa)->sin6_scope_id;
+#endif
+      DEBUGP (("conaddr is: %s\n", pretty_print_address (ip)));
       return 1;
 #endif
     case AF_INET:
-      map_ipv4_to_ip ((ip4_address *)&mysrv.sin.sin_addr, ip);
+      ip->type = IPv4_ADDRESS;
+      ip->addr.ipv4.addr = ((struct sockaddr_in *)sa)->sin_addr;
+      DEBUGP (("conaddr is: %s\n", pretty_print_address (ip)));
       return 1;
     default:
       abort ();
     }
+
   return 0;
 }
 
index 75eb9caaa2f5ba8ff3aadbf4f345e6108c6782a1..f85fe6a61615575eda63b0bb5f9227abde49dec8 100644 (file)
@@ -32,6 +32,12 @@ so, delete this exception statement from your version.  */
 
 #include "host.h"
 
+/* bindport flags */
+#define BIND_ON_IPV4_ONLY LH_IPv4_ONLY
+#ifdef ENABLE_IPV6
+#define BIND_ON_IPV6_ONLY LH_IPv6_ONLY
+#endif /* ENABLE_IPV6 */
+
 /* Function declarations */
 
 int connect_to_one PARAMS ((ip_address *, unsigned short, int));
@@ -40,7 +46,7 @@ void set_connection_host_name PARAMS ((const char *));
 
 int test_socket_open PARAMS ((int));
 int select_fd PARAMS ((int, double, int));
-uerr_t bindport PARAMS ((unsigned short *, int));
+uerr_t bindport PARAMS ((const ip_address *, unsigned short *));
 uerr_t acceptport PARAMS ((int *));
 void closeport PARAMS ((int));
 int conaddr PARAMS ((int, ip_address *));
index 05f3f32ed9c93dab38d74c019ab4a31b968d5bc6..39d98fd19fe4c32f6cc0d98a6b811630b75fb7cc 100644 (file)
@@ -29,6 +29,7 @@ so, delete this exception statement from your version.  */
 
 #include <config.h>
 
+#include <assert.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -126,7 +127,7 @@ ftp_request (const char *command, const char *value)
       if (strncmp (res, "PASS", 4) != 0)
         logprintf (LOG_ALWAYS, "--> %s\n", res);
       else
-        logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n");
+        logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n\n");
     }
   else
     DEBUGP (("\n--> %s\n", res));
@@ -252,117 +253,246 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass)
   return FTPOK;
 }
 
-#ifdef ENABLE_IPV6
+static void
+ip_address_to_port_repr (const ip_address *addr, unsigned short port, char *buf, 
+                         size_t buflen)
+{
+  unsigned char *ptr;
+
+  assert (addr != NULL);
+  assert (addr->type == IPv4_ADDRESS);
+  assert (buf != NULL);
+  /* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
+  assert (buflen >= 6 * 4);
+
+  ptr = (unsigned char *)(&addr->addr.ipv4.addr.s_addr);
+  snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
+            ptr[2], ptr[3], (unsigned) (port & 0xff00) >> 8, port & 0xff);
+  buf[buflen - 1] = '\0';
+}
+
+/* Bind a port and send the appropriate PORT command to the FTP
+   server.  Use acceptport after RETR, to get the socket of data
+   connection.  */
 uerr_t
-ftp_eprt (struct rbuf *rbuf)
+ftp_port (struct rbuf *rbuf)
 {
   uerr_t err;
-
   char *request, *respline;
-  ip_address in_addr;
+  ip_address addr;
+  int nwritten;
   unsigned short port;
+  /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */
+  char bytes[6 * 4 + 1];
+
+  assert (rbuf != NULL);
+  assert (rbuf_initialized_p (rbuf));
+
+  /* Get the address of this side of the connection. */
+  if (!conaddr (RBUF_FD (rbuf), &addr))
+    return BINDERR;
 
-  char ipv6 [8 * (4 * 3 + 3) + 8];
-  char *bytes;
+  assert (addr.type == IPv4_ADDRESS);
 
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
-  err = bindport (&port, ip_default_family);
-  if (err != BINDOK)   /* Bind the port.  */
+
+  /* Bind the port.  */
+  err = bindport (&addr, &port);
+  if (err != BINDOK)
     return err;
 
-  /* Get the address of this side of the connection.  */
-  if (!conaddr (RBUF_FD (rbuf), &in_addr))
-    /* Huh?  This is not BINDERR! */
-    return BINDERR;
-  inet_ntop (AF_INET6, &in_addr, ipv6, sizeof (ipv6));
+  /* Construct the argument of PORT (of the form a,b,c,d,e,f). */
+  ip_address_to_port_repr (&addr, port, bytes, sizeof (bytes));
 
-  /* Construct the argument of EPRT (of the form |2|IPv6.ascii|PORT.ascii|). */
-  bytes = alloca (3 + strlen (ipv6) + 1 + numdigit (port) + 1 + 1);
-  sprintf (bytes, "|2|%s|%u|", ipv6, port);
   /* Send PORT request.  */
-  request = ftp_request ("EPRT", bytes);
-  if (0 > iwrite (RBUF_FD (rbuf), request, strlen (request)))
+  request = ftp_request ("PORT", bytes);
+  nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
+  if (nwritten < 0)
     {
-      closeport (port);
       xfree (request);
+      closeport (-1);
       return WRITEFAILED;
     }
   xfree (request);
+
   /* Get appropriate response.  */
   err = ftp_response (rbuf, &respline);
   if (err != FTPOK)
     {
-      closeport (port);
       xfree (respline);
+      closeport (-1);
       return err;
     }
   if (*respline != '2')
     {
-      closeport (port);
       xfree (respline);
+      closeport (-1);
       return FTPPORTERR;
     }
   xfree (respline);
   return FTPOK;
 }
-#endif
+
+#ifdef ENABLE_IPV6
+static void
+ip_address_to_lprt_repr (const ip_address *addr, unsigned short port, char *buf, 
+                         size_t buflen)
+{
+  unsigned char *ptr;
+
+  assert (addr != NULL);
+  assert (addr->type == IPv4_ADDRESS || addr->type == IPv6_ADDRESS);
+  assert (buf != NULL);
+  /* buf must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
+  assert (buflen >= 21 * 4);
+
+  /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
+  switch (addr->type) 
+    {
+      case IPv4_ADDRESS: 
+       ptr = (unsigned char *)(&addr->addr.ipv4.addr);
+        snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d", 4, 4, 
+                  ptr[0], ptr[1], ptr[2], ptr[3], 2,
+                  (unsigned) (port & 0xff00) >> 8, port & 0xff);
+        buf[buflen - 1] = '\0';
+        break;
+      case IPv6_ADDRESS: 
+       ptr = (unsigned char *)(&addr->addr.ipv6.addr);
+       snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+                 6, 16, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7], 
+                 ptr[8], ptr[9], ptr[10], ptr[11], ptr[12], ptr[13], ptr[14], ptr[15], 2,
+                 (unsigned) (port & 0xff00) >> 8, port & 0xff);
+       buf[buflen - 1] = '\0';
+       break;
+    }
+}
 
 /* Bind a port and send the appropriate PORT command to the FTP
    server.  Use acceptport after RETR, to get the socket of data
    connection.  */
 uerr_t
-ftp_port (struct rbuf *rbuf)
+ftp_lprt (struct rbuf *rbuf)
 {
   uerr_t err;
   char *request, *respline;
-  char bytes[6 * 4 +1];
-
-  ip_address in_addr;
-  ip4_address in_addr_4;
-  unsigned char *in_addr4_ptr = (unsigned char *)&in_addr_4;
-
+  ip_address addr;
   int nwritten;
   unsigned short port;
-#ifdef ENABLE_IPV6
-  /*
-    Only try the Extented Version if we actually use IPv6
-  */
-  if (ip_default_family == AF_INET6)
+  /* Must contain the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
+  char bytes[21 * 4 + 1];
+
+  assert (rbuf != NULL);
+  assert (rbuf_initialized_p (rbuf));
+
+  /* Get the address of this side of the connection. */
+  if (!conaddr (RBUF_FD (rbuf), &addr))
+    return BINDERR;
+
+  assert (addr.type == IPv4_ADDRESS || addr.type == IPv6_ADDRESS);
+
+  /* Setting port to 0 lets the system choose a free port.  */
+  port = 0;
+
+  /* Bind the port.  */
+  err = bindport (&addr, &port);
+  if (err != BINDOK)
+    return err;
+
+  /* Construct the argument of LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
+  ip_address_to_lprt_repr (&addr, port, bytes, sizeof (bytes));
+
+  /* Send PORT request.  */
+  request = ftp_request ("LPRT", bytes);
+  nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
+  if (nwritten < 0)
     {
-      err = ftp_eprt (rbuf);
-      if (err == FTPOK)
-       return err;
+      xfree (request);
+      closeport (-1);
+      return WRITEFAILED;
     }
-#endif
+  xfree (request);
+  /* Get appropriate response.  */
+  err = ftp_response (rbuf, &respline);
+  if (err != FTPOK)
+    {
+      xfree (respline);
+      closeport (-1);
+      return err;
+    }
+  if (*respline != '2')
+    {
+      xfree (respline);
+      closeport (-1);
+      return FTPPORTERR;
+    }
+  xfree (respline);
+  return FTPOK;
+}
+
+static void
+ip_address_to_eprt_repr (const ip_address *addr, unsigned short port, char *buf, 
+                         size_t buflen)
+{
+  int afnum;
+
+  assert (addr != NULL);
+  assert (addr->type == IPv4_ADDRESS || addr->type == IPv6_ADDRESS);
+  assert (buf != NULL);
+  /* buf must contain the argument of EPRT (of the form |af|addr|port|). 
+   * 4 chars for the | separators, INET6_ADDRSTRLEN chars for addr  
+   * 1 char for af (1-2) and 5 chars for port (0-65535) */
+  assert (buflen >= 4 + INET6_ADDRSTRLEN + 1 + 5); 
+
+  /* Construct the argument of EPRT (of the form |af|addr|port|). */
+  afnum = (addr->type == IPv4_ADDRESS ? 1 : 2);
+  snprintf (buf, buflen, "|%d|%s|%d|", afnum, pretty_print_address (addr), port);
+  buf[buflen - 1] = '\0';
+}
+
+/* Bind a port and send the appropriate PORT command to the FTP
+   server.  Use acceptport after RETR, to get the socket of data
+   connection.  */
+uerr_t
+ftp_eprt (struct rbuf *rbuf)
+{
+  uerr_t err;
+  char *request, *respline;
+  ip_address addr;
+  int nwritten;
+  unsigned short port;
+  /* Must contain the argument of EPRT (of the form |af|addr|port|). 
+   * 4 chars for the | separators, ENABLE_IPV6_ADDRSTRLEN chars for addr  
+   * 1 char for af (1-2) and 5 chars for port (0-65535) */
+  char bytes[4 + INET6_ADDRSTRLEN + 1 + 5 + 1];
+
+  assert (rbuf != NULL);
+  assert (rbuf_initialized_p(rbuf));
+
+  /* Get the address of this side of the connection. */
+  if (!conaddr (RBUF_FD (rbuf), &addr))
+    return BINDERR;
+
+  assert (addr.type == IPv4_ADDRESS || addr.type == IPv6_ADDRESS);
+
   /* Setting port to 0 lets the system choose a free port.  */
   port = 0;
 
-  err = bindport (&port, AF_INET);
+  /* Bind the port.  */
+  err = bindport (&addr, &port);
   if (err != BINDOK)
     return err;
 
-  /* Get the address of this side of the connection and convert it
-     (back) to IPv4.  */
-  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 LPRT (of the form af,n,h1,h2,...,hn,p1,p2). */
+  ip_address_to_eprt_repr (&addr, port, bytes, sizeof (bytes));
 
-  /* 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);
   /* Send PORT request.  */
-  request = ftp_request ("PORT", bytes);
+  request = ftp_request ("EPRT", bytes);
   nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
   if (nwritten < 0)
     {
       xfree (request);
+      closeport (-1);
       return WRITEFAILED;
     }
   xfree (request);
@@ -371,30 +501,48 @@ ftp_port (struct rbuf *rbuf)
   if (err != FTPOK)
     {
       xfree (respline);
+      closeport (-1);
       return err;
     }
   if (*respline != '2')
     {
       xfree (respline);
+      closeport (-1);
       return FTPPORTERR;
     }
   xfree (respline);
   return FTPOK;
 }
+#endif
 
-#ifdef ENABLE_IPV6
+/* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
+   transfer.  Reads the response from server and parses it.  Reads the
+   host and port addresses and returns them.  */
 uerr_t
-ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port, 
-         char *typ)
+ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
 {
-  int err;
-  char *s, *respline;
-  char *request = ftp_request ("EPSV", typ);
-  if (0 > iwrite (RBUF_FD (rbuf), request, strlen (request)))
+  char *request, *respline, *s;
+  int nwritten, i;
+  uerr_t err;
+  unsigned char tmp[6];
+
+  assert (rbuf != NULL);
+  assert (rbuf_initialized_p(rbuf));
+  assert (addr != NULL);
+  assert (port != NULL);
+
+  memset (addr, 0, sizeof (ip_address));
+
+  /* Form the request.  */
+  request = ftp_request ("PASV", NULL);
+  /* And send it.  */
+  nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
+  if (nwritten < 0)
     {
       xfree (request);
       return WRITEFAILED;
     }
+  xfree (request);
   /* Get the server response.  */
   err = ftp_response (rbuf, &respline);
   if (err != FTPOK)
@@ -409,63 +557,56 @@ ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port,
     }
   /* Parse the request.  */
   s = respline;
-  /* respline::=229 Entering Extended Passive Mode (|||6446|) */
   for (s += 4; *s && !ISDIGIT (*s); s++);
   if (!*s)
     return FTPINVPASV;
-  *port=0; 
-  for (; ISDIGIT (*s); s++) 
-    *port = (*s - '0') + 10 * (*port);
+  for (i = 0; i < 6; i++)
+    {
+      tmp[i] = 0;
+      for (; ISDIGIT (*s); s++)
+        tmp[i] = (*s - '0') + 10 * tmp[i];
+      if (*s == ',')
+        s++;
+      else if (i < 5)
+        {
+          /* When on the last number, anything can be a terminator.  */
+          xfree (respline);
+          return FTPINVPASV;
+        }
+    }
   xfree (respline);
-  /* Now we have the port but we need the IPv6 :-( */
-  {
-    wget_sockaddr remote;
-    socklen_t addrlen = sizeof (remote);
-    struct sockaddr_in *ipv4_sock = (struct sockaddr_in *)&remote;
-    getpeername (RBUF_FD (rbuf), (struct sockaddr *)&remote, &addrlen);
-    switch(remote.sa.sa_family)
-      {
-        case AF_INET6:
-          memcpy (addr, &remote.sin6.sin6_addr, 16);
-         break;
-       case AF_INET:  
-          map_ipv4_to_ip ((ip4_address *)&ipv4_sock->sin_addr, addr);
-         break;
-       default:
-         abort();
-         return FTPINVPASV;
-         /* realy bad */
-      }
-  }
+
+  addr->type = IPv4_ADDRESS;
+  /* Mauro Tortonesi: is this safe and/or elegant enough? */
+  memcpy (&addr->addr.ipv4.addr, tmp, 4);
+  *port = ((tmp[4] << 8) & 0xff00) + tmp[5];
+
   return FTPOK;
 }
-#endif
 
-
-/* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
+#ifdef ENABLE_IPV6
+/* Similar to ftp_lprt, but uses `LPSV' to initiate the passive FTP
    transfer.  Reads the response from server and parses it.  Reads the
    host and port addresses and returns them.  */
 uerr_t
-ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
+ftp_lpsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
 {
   char *request, *respline, *s;
-  int nwritten, i;
+  int nwritten, i, af, addrlen, portlen;
   uerr_t err;
-  unsigned char addr4[4];
+  unsigned char tmp[16];
+  unsigned char tmpprt[2];
+
+  assert (rbuf != NULL);
+  assert (rbuf_initialized_p(rbuf));
+  assert (addr != NULL);
+  assert (port != NULL);
+
+  memset (addr, 0, sizeof (ip_address));
 
-#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);
+  request = ftp_request ("LPSV", NULL);
+
   /* And send it.  */
   nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
   if (nwritten < 0)
@@ -474,6 +615,7 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
       return WRITEFAILED;
     }
   xfree (request);
+
   /* Get the server response.  */
   err = ftp_response (rbuf, &respline);
   if (err != FTPOK)
@@ -485,18 +627,61 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
     {
       xfree (respline);
       return FTPNOPASV;
-    }
-  /* Parse the request.  */
-  /* respline::=227 Entering Passive Mode (h1,h2,h3,h4,p1,p2).         */
+    }  
+
+  /* Parse the response.  */
   s = respline;
   for (s += 4; *s && !ISDIGIT (*s); s++);
   if (!*s)
     return FTPINVPASV;
-  for (i = 0; i < 4; i++)
+
+  /* First, get the address family */
+  af = 0;
+  for (; ISDIGIT (*s); s++)
+    af = (*s - '0') + 10 * af;
+
+  if (af != 4 && af != 6)
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }
+
+  if (!*s || *s++ != ',')
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }
+
+  /* Then, get the address length */
+  addrlen = 0;
+  for (; ISDIGIT (*s); s++)
+    addrlen = (*s - '0') + 10 * addrlen;
+
+  if (!*s || *s++ != ',')
     {
-      addr4[i] = 0;
+      xfree (respline);
+      return FTPINVPASV;
+    }
+
+  if (addrlen > 16)
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }
+
+  if ((af == 4 && addrlen != 4)
+      || (af == 6 && addrlen != 16))
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }
+
+  /* Now, we get the actual address */
+  for (i = 0; i < addrlen; i++)
+    {
+      tmp[i] = 0;
       for (; ISDIGIT (*s); s++)
-        addr4[i] = (*s - '0') + 10 * addr4[i];
+        tmp[i] = (*s - '0') + 10 * tmp[i];
       if (*s == ',')
         s++;
       else
@@ -506,29 +691,184 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
         }
     }
 
-  /* Eventually make an IPv4 in IPv6 adress if needed */
-  map_ipv4_to_ip ((ip4_address *)addr4, addr);
+  /* Now, get the port length */
+  portlen = 0;
+  for (; ISDIGIT (*s); s++)
+    portlen = (*s - '0') + 10 * portlen;
 
-  *port=0;
+  if (!*s || *s++ != ',')
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }
+
+  if (portlen > 2)
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }
+
+  /* Finally, we get the port number */
+  tmpprt[0] = 0;
   for (; ISDIGIT (*s); s++)
-    *port = (*s - '0') + 10 * (*port);
-  if (*s == ',') 
-    s++;
+    tmpprt[0] = (*s - '0') + 10 * tmpprt[0];
+
+  if (!*s || *s++ != ',')
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }
+
+  tmpprt[1] = 0;
+  for (; ISDIGIT (*s); s++)
+    tmpprt[1] = (*s - '0') + 10 * tmpprt[1];
+
+  assert (s != NULL);
+
+  if (af == 4)
+    {
+      addr->type = IPv4_ADDRESS;
+      memcpy (&addr->addr.ipv4.addr, tmp, 4);
+      *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
+      DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
+      DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
+      DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
+      DEBUGP (("*port is: %d\n", *port));
+    }
   else
+    {
+      assert (af == 6);
+      addr->type = IPv6_ADDRESS;
+      memcpy (&addr->addr.ipv6.addr, tmp, 16);
+      *port = ((tmpprt[0] << 8) & 0xff00) + tmpprt[1];
+      DEBUGP (("lpsv addr is: %s\n", pretty_print_address(addr)));
+      DEBUGP (("tmpprt[0] is: %d\n", tmpprt[0]));
+      DEBUGP (("tmpprt[1] is: %d\n", tmpprt[1]));
+      DEBUGP (("*port is: %d\n", *port));
+    }
+
+  xfree (respline);
+  return FTPOK;
+}
+
+/* Similar to ftp_eprt, but uses `EPSV' to initiate the passive FTP
+   transfer.  Reads the response from server and parses it.  Reads the
+   host and port addresses and returns them.  */
+uerr_t
+ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
+{
+  char *request, *respline, *start, delim, *s;
+  int nwritten, i;
+  uerr_t err;
+  unsigned short tport;
+  socklen_t addrlen;
+  struct sockaddr_storage ss;
+  struct sockaddr *sa = (struct sockaddr *)&ss;
+
+  assert (rbuf != NULL);
+  assert (rbuf_initialized_p(rbuf));
+  assert (addr != NULL);
+  assert (port != NULL);
+
+  addrlen = sizeof (ss);
+  if (getpeername (rbuf->fd, sa, &addrlen) < 0)
+    /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
+    return CONPORTERR;
+
+  assert (sa->sa_family == AF_INET || sa->sa_family == AF_INET6);
+
+  sockaddr_get_address (sa, NULL, addr);
+
+  /* Form the request.  */
+  /* EPSV 1 means that we ask for IPv4 and EPSV 2 means that we ask for IPv6. */
+  request = ftp_request ("EPSV", (sa->sa_family == AF_INET ? "1" : "2"));
+
+  /* And send it.  */
+  nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
+  if (nwritten < 0)
+    {
+      xfree (request);
+      return WRITEFAILED;
+    }
+  xfree (request);
+
+  /* Get the server response.  */
+  err = ftp_response (rbuf, &respline);
+  if (err != FTPOK)
+    {
+      xfree (respline);
+      return err;
+    }
+  if (*respline != '2')
+    {
+      xfree (respline);
+      return FTPNOPASV;
+    }  
+
+  assert (respline != NULL);
+
+  DEBUGP(("respline is %s\n", respline));
+
+  /* Parse the response.  */
+  s = respline;
+
+  /* Skip the useless stuff and get what's inside the parentheses */
+  start = strchr (respline, '(');
+  if (start == NULL)
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }  
+
+  /* Skip the first two void fields */
+  s = start + 1;
+  delim = *s++;
+  if (delim < 33 || delim > 126)
     {
       xfree (respline);
       return FTPINVPASV;
+    }  
+
+  for (i = 0; i < 2; i++)
+    {
+      if (*s++ != delim) 
+        {
+          xfree (respline);
+        return FTPINVPASV;
+        }  
     }
 
-  {
-    unsigned short port2 = 0; 
-    for (; ISDIGIT (*s); s++) 
-      port2 = (*s - '0') + 10 * port2;
-    *port = (*port) * 256 + port2;
-  }
+  /* Finally, get the port number */
+  tport = 0; 
+  for (i = 1; ISDIGIT (*s); s++) 
+    {
+      if (i > 5)
+        {
+          xfree (respline);
+          return FTPINVPASV;
+        }  
+      tport = (*s - '0') + 10 * tport;
+    }
+
+  /* Make sure that the response terminates correcty */
+  if (*s++ != delim)
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }  
+
+  if (*s++ != ')')
+    {
+      xfree (respline);
+      return FTPINVPASV;
+    }  
+
+  *port = tport;
+
   xfree (respline);
   return FTPOK;
 }
+#endif
 
 /* Sends the TYPE request to the server.  */
 uerr_t
@@ -755,7 +1095,7 @@ ftp_syst (struct rbuf *rbuf, enum stype *server_type)
 
   /* Skip the number (215, but 200 (!!!) in case of VMS) */
   strtok (respline, " ");
-  
+
   /* Which system type has been reported (we are interested just in the
      first word of the server response)?  */
   request = strtok (NULL, " ");
@@ -812,7 +1152,7 @@ ftp_pwd (struct rbuf *rbuf, char **pwd)
      and everything following it. */
   strtok (respline, "\"");
   request = strtok (NULL, "\"");
-  
+
   /* Has the `pwd' been already allocated?  Free! */
   FREE_MAYBE (*pwd);
 
index 7e997393204a1df915b215b4a11331eae333fbcc..7c0bee7b3e873fedcf809e42bd8e9758a7c9efce 100644 (file)
--- a/src/ftp.c
+++ b/src/ftp.c
@@ -121,6 +121,110 @@ ftp_expected_bytes (const char *s)
   return res;
 }
 
+#ifdef ENABLE_IPV6
+static int
+getfamily (int fd)
+{
+  struct sockaddr_storage ss;
+  struct sockaddr *sa = (struct sockaddr *)&ss;
+  socklen_t len = sizeof (ss);
+
+  assert (fd >= 0);
+
+  if (getpeername (fd, sa, &len) < 0)
+    /* Mauro Tortonesi: HOW DO WE HANDLE THIS ERROR? */
+    abort ();
+
+  return sa->sa_family;
+}
+
+/* 
+ * This function sets up a passive data connection with the FTP server.
+ * It is merely a wrapper around ftp_epsv, ftp_lpsv and ftp_pasv.
+ */
+static uerr_t
+ftp_do_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
+{
+  uerr_t err;
+  int family;
+
+  family = getfamily (rbuf->fd);
+  assert (family == AF_INET || family == AF_INET6);
+
+  /* If our control connection is over IPv6, then we first try EPSV and then 
+   * LPSV if the former is not supported. If the control connection is over 
+   * IPv4, we simply issue the good old PASV request. */
+  if (family == AF_INET6)
+    {
+      if (!opt.server_response)
+        logputs (LOG_VERBOSE, "==> EPSV ... ");
+      err = ftp_epsv (rbuf, addr, port);
+
+      /* If EPSV is not supported try LPSV */
+      if (err == FTPNOPASV)
+        {
+          if (!opt.server_response)
+            logputs (LOG_VERBOSE, "==> LPSV ... ");
+          err = ftp_lpsv (rbuf, addr, port);
+        }
+    }
+  else 
+    {
+      if (!opt.server_response)
+        logputs (LOG_VERBOSE, "==> PASV ... ");
+      err = ftp_pasv (rbuf, addr, port);
+    }
+
+  return err;
+}
+
+/* 
+ * This function sets up an active data connection with the FTP server.
+ * It is merely a wrapper around ftp_eprt, ftp_lprt and ftp_port.
+ */
+static uerr_t
+ftp_do_port (struct rbuf *rbuf)
+{
+  uerr_t err;
+  int family;
+
+  assert (rbuf != NULL);
+  assert (rbuf_initialized_p (rbuf));
+
+  family = getfamily (rbuf->fd);
+  assert (family == AF_INET || family == AF_INET6);
+
+  /* If our control connection is over IPv6, then we first try EPRT and then 
+   * LPRT if the former is not supported. If the control connection is over 
+   * IPv4, we simply issue the good old PORT request. */
+  if (family == AF_INET6)
+    {
+      if (!opt.server_response)
+        logputs (LOG_VERBOSE, "==> EPRT ... ");
+      err = ftp_eprt (rbuf);
+
+      /* If EPRT is not supported try LPRT */
+      if (err == FTPPORTERR)
+        {
+          if (!opt.server_response)
+            logputs (LOG_VERBOSE, "==> LPRT ... ");
+          err = ftp_lprt (rbuf);
+        }
+    }
+  else 
+    {
+      if (!opt.server_response)
+        logputs (LOG_VERBOSE, "==> PORT ... ");
+      err = ftp_port (rbuf);
+    }
+
+  return err;
+}
+#else
+#define ftp_do_pasv ftp_pasv
+#define ftp_do_port ftp_port
+#endif
+
 /* Retrieves a file with denoted parameters through opening an FTP
    connection to the server.  It always closes the data connection,
    and closes the control connection in case of error.  */
@@ -542,7 +646,7 @@ Error in server response, closing control connection.\n"));
          unsigned short passive_port;
          if (!opt.server_response)
            logputs (LOG_VERBOSE, "==> PASV ... ");
-         err = ftp_pasv (&con->rbuf, &passive_addr, &passive_port);
+         err = ftp_do_pasv (&con->rbuf, &passive_addr, &passive_port);
          /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
          switch (err)
            {
@@ -579,13 +683,16 @@ Error in server response, closing control connection.\n"));
            }   /* switch(err) */
          if (err==FTPOK)
            {
+             DEBUGP (("trying to connect to %s port %d\n", 
+                     pretty_print_address (&passive_addr),
+                     passive_port));
              dtsock = connect_to_one (&passive_addr, passive_port, 1);
              if (dtsock < 0)
                {
                  int save_errno = errno;
                  CLOSE (csock);
                  rbuf_uninitialize (&con->rbuf);
-                 logprintf (LOG_VERBOSE, _("couldn't connect to %s:%hu: %s\n"),
+                 logprintf (LOG_VERBOSE, _("couldn't connect to %s port %hu: %s\n"),
                             pretty_print_address (&passive_addr), passive_port,
                             strerror (save_errno));
                  return CONNECT_ERROR (save_errno);
@@ -601,7 +708,7 @@ Error in server response, closing control connection.\n"));
        {
          if (!opt.server_response)
            logputs (LOG_VERBOSE, "==> PORT ... ");
-         err = ftp_port (&con->rbuf);
+         err = ftp_do_port (&con->rbuf);
          /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR,
             LISTENERR), HOSTERR, FTPPORTERR */
          switch (err)
@@ -739,6 +846,7 @@ Error in server response, closing control connection.\n"));
              logprintf (LOG_VERBOSE, "==> RETR %s ... ", u->file);
            }
        }
+
       err = ftp_retr (&con->rbuf, u->file);
       /* FTPRERR, WRITEFAILED, FTPNSFOD */
       switch (err)
@@ -930,6 +1038,7 @@ Error in server response, closing control connection.\n"));
     if (flush_res == EOF)
       res = -2;
   }
+
   /* If get_contents couldn't write to fp, bail out.  */
   if (res == -2)
     {
@@ -1224,7 +1333,7 @@ ftp_loop_internal (struct url *u, struct fileinfo *f, ccon *con)
                logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
            }
        }
-      
+
       /* Restore the original leave-pendingness.  */
       if (orig_lp)
        con->cmd |= LEAVE_PENDING;
index a5e73927f1aac2f19f5af86770389e3732d0d33a..33c4c419210fb50d1bc2263f0725eb44adbd19db 100644 (file)
--- a/src/ftp.h
+++ b/src/ftp.h
@@ -51,8 +51,10 @@ uerr_t ftp_login PARAMS ((struct rbuf *, const char *, const char *));
 uerr_t ftp_port PARAMS ((struct rbuf *));
 uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_address *, unsigned short *));
 #ifdef ENABLE_IPV6
-uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_address *, unsigned short *,
-                        char *));
+uerr_t ftp_lprt PARAMS ((struct rbuf *));
+uerr_t ftp_lpsv PARAMS ((struct rbuf *, ip_address *, unsigned short *));
+uerr_t ftp_eprt PARAMS ((struct rbuf *));
+uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_address *, unsigned short *));
 #endif
 uerr_t ftp_type PARAMS ((struct rbuf *, int));
 uerr_t ftp_cwd PARAMS ((struct rbuf *, const char *));
index 5297d0f34347bc5b926d3d35192bf958f48e60c9..d0fd7e7c948e849c71dbfef4d3f6bcd57dc9f989 100644 (file)
@@ -45,7 +45,7 @@ so, delete this exception statement from your version.  */
 
 #ifdef WINDOWS
 # include <winsock.h>
-# define SET_H_ERRNO(err) WSASetLastError(err)
+# define SET_H_ERRNO(err) WSASetLastError (err)
 #else
 # include <sys/socket.h>
 # include <netinet/in.h>
@@ -82,9 +82,9 @@ extern int h_errno;
 #endif
 
 #ifdef ENABLE_IPV6
-int     ip_default_family = AF_INET6;
+int ip_default_family = AF_UNSPEC;
 #else
-int     ip_default_family = AF_INET;
+int ip_default_family = AF_INET;
 #endif
 
 /* Mapping between known hosts and to lists of their addresses. */
@@ -105,7 +105,7 @@ struct address_list {
 /* Get the bounds of the address list.  */
 
 void
-address_list_get_bounds (struct address_list *al, int *start, int *end)
+address_list_get_bounds (const struct address_list *al, int *start, int *end)
 {
   *start = al->faulty;
   *end   = al->count;
@@ -114,7 +114,7 @@ address_list_get_bounds (struct address_list *al, int *start, int *end)
 /* Copy address number INDEX to IP_STORE.  */
 
 void
-address_list_copy_one (struct address_list *al, int index, ip_address *ip_store)
+address_list_copy_one (const struct address_list *al, int index, ip_address *ip_store)
 {
   assert (index >= al->faulty && index < al->count);
   memcpy (ip_store, al->addresses + index, sizeof (ip_address));
@@ -123,14 +123,43 @@ address_list_copy_one (struct address_list *al, int index, ip_address *ip_store)
 /* Check whether two address lists have all their IPs in common.  */
 
 int
-address_list_match_all (struct address_list *al1, struct address_list *al2)
+address_list_match_all (const struct address_list *al1, const struct address_list *al2)
 {
+  int i;
   if (al1 == al2)
     return 1;
   if (al1->count != al2->count)
     return 0;
-  return 0 == memcmp (al1->addresses, al2->addresses,
-                     al1->count * sizeof (ip_address));
+  for (i = 0; i < al1->count; ++i) 
+    {
+#ifdef ENABLE_IPv6
+      if (al1->addresses[i].type != al2->addresses[i].type) 
+       return 0;
+      if (al1->addresses[i].type == IPv6_ADDRESS)
+       {
+         const struct in6_addr *addr1 = &al1->addresses[i].addr.ipv6.addr;
+         const struct in6_addr *addr2 = &al2->addresses[i].addr.ipv6.addr;
+
+#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
+         if ((al1->addresses[i].address.scope_id
+              != al2->addresses[i].address.scope_id)
+             || !IN6_ARE_ADDR_EQUAL (addr1, addr2))
+#else
+         if (!IN6_ARE_ADDR_EQUAL (addr1, addr2))
+#endif
+           return 0;
+       }
+      else
+#endif
+       {
+         const struct in_addr *addr1 = (const struct in_addr *)&al1->addresses[i].addr.ipv4.addr;
+         const struct in_addr *addr2 = (const struct in_addr *)&al2->addresses[i].addr.ipv4.addr;
+         
+         if (addr1->s_addr != addr2->s_addr)
+           return 0;
+       }
+    }
+  return 1;
 }
 
 /* Mark the INDEXth element of AL as faulty, so that the next time
@@ -153,7 +182,7 @@ address_list_set_faulty (struct address_list *al, int index)
     al->faulty = 0;
 }
 
-#ifdef HAVE_GETADDRINFO
+#ifdef ENABLE_IPV6
 /**
   * address_list_from_addrinfo
   *
@@ -166,15 +195,15 @@ address_list_set_faulty (struct address_list *al, int index)
   * address_list*      New allocated address_list
   */
 static struct address_list *
-address_list_from_addrinfo (struct addrinfo *ai)
+address_list_from_addrinfo (const struct addrinfo *ai)
 {
   struct address_list *al;
-  struct addrinfo *ai_head = ai;
+  const struct addrinfo *ptr;
   int cnt = 0;
   int i;
 
-  for (ai = ai_head; ai; ai = ai->ai_next)
-    if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6)
+  for (ptr = ai; ptr != NULL ; ptr = ptr->ai_next)
+    if (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)
       ++cnt;
   if (cnt == 0)
     return NULL;
@@ -185,17 +214,24 @@ address_list_from_addrinfo (struct addrinfo *ai)
   al->faulty    = 0;
   al->refcount  = 1;
 
-  for (i = 0, ai = ai_head; ai; ai = ai->ai_next)
-    if (ai->ai_family == AF_INET6) 
+  for (i = 0, ptr = ai; ptr != NULL; ptr = ptr->ai_next)
+    if (ptr->ai_family == AF_INET6) 
       {
-       struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr;
-       memcpy (al->addresses + i, &sin6->sin6_addr, 16);
+       const struct sockaddr_in6 *sin6 =
+         (const struct sockaddr_in6 *)ptr->ai_addr;
+       al->addresses[i].addr.ipv6.addr = sin6->sin6_addr;
+       al->addresses[i].type = IPv6_ADDRESS;
+#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
+       al->addresses[i].addr.ipv6.scope_id = sin6->sin6_scope_id;
+#endif
        ++i;
       } 
-    else if (ai->ai_family == AF_INET)
+    else if (ptr->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);
+       const struct sockaddr_in *sin =
+         (const struct sockaddr_in *)ptr->ai_addr;
+       al->addresses[i].addr.ipv4.addr = sin->sin_addr;
+       al->addresses[i].type = IPv4_ADDRESS;
        ++i;
       }
   assert (i == cnt);
@@ -219,18 +255,20 @@ address_list_from_vector (char **h_addr_list)
   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++) {
+    /* Mauro Tortonesi: is this safe? */
+    memcpy (&((al->addresses + i)->addr.ipv4.addr.s_addr), h_addr_list[i], 4);
+    (al->addresses + i)->type = IPv4_ADDRESS;
+  }
 
   return al;
 }
-#endif
 
 /* Like address_list_from_vector, but initialized with a single
    address. */
 
 static struct address_list *
-address_list_from_single (ip_address *addr)
+address_list_from_single (const ip_address *addr)
 {
   struct address_list *al = xmalloc (sizeof (struct address_list));
   al->count     = 1;
@@ -241,6 +279,7 @@ address_list_from_single (ip_address *addr)
 
   return al;
 }
+#endif
 
 static void
 address_list_delete (struct address_list *al)
@@ -262,58 +301,93 @@ address_list_release (struct address_list *al)
 }
 \f
 /**
-  * wget_sockaddr_set_address
+  * sockaddr_set_address
   *
-  * This function takes an wget_sockaddr and fill in the protocol type,
-  * the port number and the address, there NULL in address means wildcard.
-  * Unsuported adress family will abort the whole programm.
+  * This function takes a sockaddr struct and fills in the protocol type,
+  * the port number and the address. If ENABLE_IPV6 is defined, the sa
+  * parameter should point to a sockaddr_storage structure; if not, it 
+  * should point to a sockaddr_in structure.
+  * If the address parameter is NULL, the function will use the unspecified 
+  * address (0.0.0.0 for IPv4 and :: for IPv6). 
+  * Unsupported address family will abort the whole programm.
   *
   * Input:
-  * wget_sockaddr*     The space to be filled
-  * int                        The wished protocol
+  * struct sockaddr*   The space to be filled
   * unsigned short     The port
-  * const ip_address   The Binary IP adress
+  * const ip_address   The IP address
   *
   * Return:
-  * -                  Only modify 1. param
+  * -                  Only modifies 1st parameter.
   */
 void
-wget_sockaddr_set_address (wget_sockaddr *sa
-                          int ip_family, unsigned short port, ip_address *addr)
+sockaddr_set_address (struct sockaddr *sa, unsigned short port
+                     const ip_address *addr)
 {
-  if (ip_family == AF_INET) 
+  if (addr->type == IPv4_ADDRESS)
     {
-      sa->sin.sin_family = ip_family;
-      sa->sin.sin_port = htons (port);
+      struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+      sin->sin_family = AF_INET;
+      sin->sin_port = htons (port);
       if (addr == NULL) 
-       memset (&sa->sin.sin_addr, 0,      sizeof(ip4_address));
+       sin->sin_addr.s_addr = INADDR_ANY;
       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));
-       }
-      return;
+       sin->sin_addr = addr->addr.ipv4.addr;
     }
 #ifdef ENABLE_IPV6
-  if (ip_family == AF_INET6
+  else if (addr->type == IPv6_ADDRESS
     {
-      sa->sin6.sin6_family = ip_family;
-      sa->sin6.sin6_port = htons (port);
+      struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+      sin6->sin6_family = AF_INET6;
+      sin6->sin6_port = htons (port);
       if (addr == NULL) 
-       memset (&sa->sin6.sin6_addr, 0   , 16);
-      else          
-       memcpy (&sa->sin6.sin6_addr, addr, 16);
-      return;
+       sin6->sin6_addr = in6addr_any;
+      else
+       sin6->sin6_addr = addr->addr.ipv6.addr;
+#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
+      sin6->sin6_scope_id = addr->addr.ipv6.scope_id;
+#endif /* HAVE_SOCKADDR_IN6_SCOPE_ID */
+    }
+#endif /* ENABLE_IPV6 */
+  else
+    abort ();
+}
+
+void
+sockaddr_get_address (const struct sockaddr *sa, unsigned short *port, 
+                     ip_address *addr)
+{
+  if (sa->sa_family == AF_INET)
+    {
+      struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+
+      addr->type = IPv4_ADDRESS;
+      addr->addr.ipv4.addr = sin->sin_addr;
+      if (port != NULL) 
+       *port = ntohs (sin->sin_port);
+    }
+#ifdef ENABLE_IPV6
+  else if (sa->sa_family == AF_INET6) 
+    {
+      struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+
+      addr->type = IPv6_ADDRESS;
+      addr->addr.ipv6.addr = sin6->sin6_addr;
+#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
+      addr->addr.ipv6.scope_id = sin6->sin6_scope_id;
+#endif  
+      if (port != NULL) 
+       *port = ntohs (sin6->sin6_port);
     }
 #endif  
-  abort();
+  else
+    abort ();
 }
 
+#if 0                          /* currently unused */
 /**
-  * wget_sockaddr_set_port
+  * sockaddr_set_port
   *
   * This funtion only fill the port of the socket information.
   * If the protocol is not supported nothing is done.
@@ -330,54 +404,27 @@ wget_sockaddr_set_address (wget_sockaddr *sa,
   * -                  Only modify 1. param
   */
 void 
-wget_sockaddr_set_port (wget_sockaddr *sa, unsigned short port)
+sockaddr_set_port (struct sockaddr *sa, unsigned short port)
 {
-  if (sa->sa.sa_family == AF_INET)
+  if (sa->sa_family == AF_INET)
     {
-      sa->sin.sin_port = htons (port);
-      return;
+      struct sockaddr_in *sin = (struct sockaddr_in *)sa;
+      sin->sin_port = htons (port);
     }  
 #ifdef ENABLE_IPV6
-  if (sa->sa.sa_family == AF_INET6)
+  else if (sa->sa_family == AF_INET6)
     {
-      sa->sin6.sin6_port = htons (port);
-      return;
+      struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+      sin6->sin6_port = htons (port);
     }
 #endif
-  abort();
+  else
+    abort ();
 }
-
-/**
-  * wget_sockaddr_get_addr
-  *
-  * This function return the adress from an sockaddr as byte string.
-  * Unsuported adress family will abort the whole programm.
-  * 
-  * Require:
-  * that the IP-Protocol already is set.
-  *
-  * Input:
-  * wget_sockaddr*     Socket Information
-  *
-  * Output:
-  * unsigned char *    IP address as byte string.
-  */
-void *
-wget_sockaddr_get_addr (wget_sockaddr *sa)
-{ 
-  if (sa->sa.sa_family == AF_INET)
-    return &sa->sin.sin_addr;
-#ifdef ENABLE_IPV6
-  if (sa->sa.sa_family == AF_INET6)
-    return &sa->sin6.sin6_addr;
 #endif
-  abort();
-  /* unreached */
-  return NULL;
-}
 
 /**
-  * wget_sockaddr_get_port
+  * sockaddr_get_port
   *
   * This function only return the port from the input structure
   * Unsuported adress family will abort the whole programm.
@@ -392,15 +439,18 @@ wget_sockaddr_get_addr (wget_sockaddr *sa)
   * unsigned short     Port Number in host order.
   */
 unsigned short 
-wget_sockaddr_get_port (const wget_sockaddr *sa)
+sockaddr_get_port (const struct sockaddr *sa)
 {
-  if (sa->sa.sa_family == AF_INET)
-      return htons (sa->sin.sin_port);
+  if (sa->sa_family == AF_INET) {
+      const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
+      return htons (sin->sin_port);
 #ifdef ENABLE_IPV6
-  if (sa->sa.sa_family == AF_INET6)
-      return htons (sa->sin6.sin6_port);
+  } else if (sa->sa_family == AF_INET6) {
+      const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
+      return htons (sin6->sin6_port);
 #endif
-  abort();
+  } else
+    abort ();
   /* do not complain about return nothing */
   return -1;
 }
@@ -419,58 +469,26 @@ wget_sockaddr_get_port (const wget_sockaddr *sa)
   * -          Public IP-Family Information
   *
   * Output:
-  * socklen_t  structure length for socket options
+  * int                structure length for socket options
   */
 socklen_t
-sockaddr_len (
+sockaddr_len (const struct sockaddr *sa)
 {
-  if (ip_default_family == AF_INET) 
-    return sizeof (struct sockaddr_in);
+  if (sa->sa_family == AF_INET)
+    {
+      return sizeof (struct sockaddr_in);
+    }  
 #ifdef ENABLE_IPV6
-  if (ip_default_family == AF_INET6) 
-    return sizeof (struct sockaddr_in6);
+  else if (sa->sa_family == AF_INET6)
+    {
+      return sizeof (struct sockaddr_in6);
+    }
 #endif
-  abort();
+  else
+    abort ();
   /* do not complain about return nothing */
   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;
-}
 \f
 /* Versions of gethostbyname and getaddrinfo that support timeout. */
 
@@ -555,21 +573,33 @@ getaddrinfo_with_timeout (const char *node, const char *service,
    inet_ntoa.  With IPv6, it either prints an IPv6 address or an IPv4
    address.  */
 
-char *
-pretty_print_address (ip_address *addr)
+const char *
+pretty_print_address (const ip_address *addr)
 {
+  switch (addr->type) 
+    {
+    case IPv4_ADDRESS:
+      return inet_ntoa (addr->addr.ipv4.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;
+    case IPv6_ADDRESS:
+      {
+        int len;
+        static char buf[128];
+       inet_ntop (AF_INET6, &addr->addr.ipv6.addr, buf, sizeof (buf));
+#if 0
+#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
+        /* print also scope_id for all ?non-global? addresses */
+        snprintf (buf + len, sizeof (buf) - len, "%%%d", addr->addr.ipv6.scope_id);
+#endif
 #endif
-  return inet_ntoa (*(struct in_addr *)addr);
+        len = strlen (buf);
+        buf[sizeof (buf) - 1] = '\0';
+        return buf;
+      }
+#endif
+    }
+  abort ();
+  return NULL;
 }
 
 /* Add host name HOST with the address ADDR_TEXT to the cache.
@@ -598,28 +628,66 @@ cache_host_lookup (const char *host, struct address_list *al)
 }
 
 struct address_list *
-lookup_host (const char *host, int silent)
+lookup_host (const char *host, int flags)
 {
   struct address_list *al = NULL;
-  uint32_t addr_ipv4;
-  ip_address addr;
-
-  /* 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);
+  int err, family;
+  struct addrinfo hints, *res;
+
+  /* This ip_default_family+flags business looks like bad design to
+     me.  This function should rather accept a FAMILY argument.  */
+  if (flags & LH_IPv4_ONLY)
+    family = AF_INET;
+  else if (flags & LH_IPv6_ONLY)
+    family = AF_INET6;
+  else
+    family = ip_default_family;
 #endif
+         
+  /* First, try to check whether the address is already a numeric
+     address.  Where getaddrinfo is available, we do it using the
+     AI_NUMERICHOST flag.  Without IPv6, we check whether inet_addr
+     succeeds.  */
 
-  addr_ipv4 = (uint32_t)inet_addr (host);
-  if (addr_ipv4 != (uint32_t)-1)
+#ifdef ENABLE_IPV6
+  memset (&hints, 0, sizeof (hints));
+  hints.ai_family   = family;
+  hints.ai_socktype = SOCK_STREAM;
+  hints.ai_flags    = AI_NUMERICHOST;
+  if (flags & LH_PASSIVE)
+    hints.ai_flags = AI_PASSIVE;
+
+  /* no need to call getaddrinfo_with_timeout here, as we're not
+   * relying on the DNS, but we're only doing an address translation
+   * from presentation (ASCII) to network format */
+  err = getaddrinfo (host, NULL, &hints, &res);
+  if (err == 0 && res != NULL)
     {
-      /* 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);
+      al = address_list_from_addrinfo (res);
+      freeaddrinfo (res);
+      return al;
     }
+#else
+  {
+    uint32_t addr_ipv4 = (uint32_t)inet_addr (host);
+    if (addr_ipv4 != (uint32_t) -1)
+      {
+       /* The return value of inet_addr is in network byte order, so
+          we can just copy it to ADDR.  */
+       ip_address addr;
+       /* This has a huge number of dereferences because C doesn't
+          support anonymous unions and because struct in_addr adds a
+          cast.  */
+       addr.addr.ipv4.addr.s_addr = addr_ipv4;
+       addr.type = IPv4_ADDRESS;
+       return address_list_from_single (&addr);
+      }
+  }
+#endif
+
+  /* Then, try to find the host in the cache. */
 
   if (host_name_addresses_map)
     {
@@ -632,41 +700,37 @@ lookup_host (const char *host, int silent)
        }
     }
 
-  if (!silent)
+  if (!(flags & LH_SILENT))
     logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
 
   /* Host name lookup goes on below. */
 
-#ifdef HAVE_GETADDRINFO
+#ifdef ENABLE_IPV6
   {
-    struct addrinfo hints, *ai;
-    int err;
-
     memset (&hints, 0, sizeof (hints));
-    if (ip_default_family == AF_INET)
-      hints.ai_family   = AF_INET;
-    else
-      hints.ai_family   = PF_UNSPEC;
+    hints.ai_family   = family;
     hints.ai_socktype = SOCK_STREAM;
-    err = getaddrinfo_with_timeout (host, NULL, &hints, &ai, opt.dns_timeout);
+    if (flags & LH_PASSIVE) 
+      hints.ai_flags = AI_PASSIVE;
+
+    err = getaddrinfo_with_timeout (host, NULL, &hints, &res, opt.dns_timeout);
 
-    if (err != 0 || ai == NULL)
+    if (err != 0 || res == NULL)
       {
-        if (!silent)
+        if (!(flags & LH_SILENT))
          logprintf (LOG_VERBOSE, _("failed: %s.\n"),
                     err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
         return NULL;
       }
-    al = address_list_from_addrinfo (ai);
-    freeaddrinfo (ai);
+    al = address_list_from_addrinfo (res);
+    freeaddrinfo (res);
   }
 #else
   {
-    struct hostent *hptr;
-    hptr = gethostbyname_with_timeout (host, opt.dns_timeout);
+    struct hostent *hptr = gethostbyname_with_timeout (host, opt.dns_timeout);
     if (!hptr)
       {
-       if (!silent)
+       if (!(flags & LH_SILENT))
          {
            if (errno != ETIMEDOUT)
              logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
@@ -675,6 +739,7 @@ lookup_host (const char *host, int silent)
          }
        return NULL;
       }
+    assert (hptr->h_length == 4);
     /* Do all systems have h_addr_list, or is it a newer thing?  If
        the latter, use address_list_from_single.  */
     al = address_list_from_vector (hptr->h_addr_list);
@@ -683,7 +748,7 @@ lookup_host (const char *host, int silent)
 
   /* Print the addresses determined by DNS lookup, but no more than
      three.  */
-  if (!silent)
+  if (!(flags & LH_SILENT))
     {
       int i;
       int printmax = al->count <= 3 ? al->count : 3;
index 3b863aab66e18d0d997170128e240d5b6f19b764..46acacb18dbca748e321521829df962a0f67ff40 100644 (file)
@@ -6,7 +6,7 @@ This file is part of GNU Wget.
 GNU Wget is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
+ (at your option) any later version.
 
 GNU Wget is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -44,64 +44,71 @@ so, delete this exception statement from your version.  */
 struct url;
 struct address_list;
 
-/* wget_sockaddr is used instead of sockaddr where an IPV6 address
-   must fit.  */
-
-typedef union {
-       struct sockaddr     sa;   /* Generic but too small */
-       struct sockaddr_in  sin;  /* IPv4 socket address */
-#ifdef ENABLE_IPV6
-       struct sockaddr_in6 sin6; /* IPv6 socket address */
-#endif
-} wget_sockaddr;
+extern int ip_default_family;  /* defined in host.c */
 
 typedef struct {
-  unsigned char bytes[4];
-} ip4_address;
+  enum { 
+    IPv4_ADDRESS, 
+#ifdef ENABLE_IPV6
+    IPv6_ADDRESS 
+#endif /* ENABLE_IPV6 */
+  } type;
+  union {
+#ifdef ENABLE_IPV6
+    struct {
+      struct in6_addr addr;
+#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
+      unsigned int scope_id;
+#endif /* HAVE_SOCKADDR_IN6_SCOPE_ID */
+    } ipv6;
+#endif /* ENABLE_IPV6 */
+    struct {
+      struct in_addr addr;
+    } ipv4;
+  } addr;
+} ip_address;
 
-/* If compiled with IPv6 support, we internally represent all IP
-   addresses as IPv6 addresses.  IPv4 addresses are dynamically mapped
-   to IPv6, i.e. stored in the format ::ffff:<Ipv4>.  */
+#ifndef ENABLE_IPV6
 
-#ifdef ENABLE_IPV6
-# define MAX_IP_ADDRESS_SIZE 16
-#else
-# define MAX_IP_ADDRESS_SIZE 4
+#ifndef HAVE_SOCKADDR_STORAGE
+#define sockaddr_storage sockaddr_in
 #endif
 
-typedef struct {
-  unsigned char bytes[MAX_IP_ADDRESS_SIZE];
-} ip_address;
+#endif /* ENABLE_IPV6 */
+
+/* Flags for lookup_host */
+#define LH_SILENT    0x0001
+#define LH_PASSIVE   0x0002
+#define LH_IPv4_ONLY 0x0004
+#ifdef ENABLE_IPV6
+#define LH_IPv6_ONLY 0x0008
+#endif /* ENABLE_IPV6 */
 
 /* Function declarations */
 struct address_list *lookup_host PARAMS ((const char *, int));
 char *herrmsg PARAMS ((int));
 
-void address_list_get_bounds PARAMS ((struct address_list *, int *, int *));
-void address_list_copy_one PARAMS ((struct address_list *, int,
+void address_list_get_bounds PARAMS ((const struct address_list *,
+                                     int *, int *));
+void address_list_copy_one PARAMS ((const struct address_list *, int,
                                    ip_address *));
-int address_list_match_all PARAMS ((struct address_list *,
-                                   struct address_list *));
+int address_list_match_all PARAMS ((const struct address_list *,
+                                   const struct address_list *));
 void address_list_set_faulty PARAMS ((struct address_list *, int));
 void address_list_release PARAMS ((struct address_list *));
 
-char *pretty_print_address PARAMS ((ip_address *));
+const char *pretty_print_address PARAMS ((const ip_address *));
 
 int accept_domain PARAMS ((struct url *));
 int sufmatch PARAMS ((const char **, const char *));
 
-void host_cleanup PARAMS ((void));
-
-void wget_sockaddr_set_address PARAMS((wget_sockaddr *, int, 
-                                      unsigned short, ip_address *));
-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 *));
-extern int     ip_default_family;      /* defined in host.c */
+void sockaddr_set_address PARAMS ((struct sockaddr *, unsigned short,
+                                  const ip_address *));
+void sockaddr_get_address PARAMS ((const struct sockaddr *, unsigned short *,
+                                  ip_address *));
+unsigned short sockaddr_get_port PARAMS ((const struct sockaddr *));
+socklen_t sockaddr_len PARAMS ((const struct sockaddr *sa));
 
+void host_cleanup PARAMS ((void));
 
 #endif /* HOST_H */
index f683b628a6c1e401f7e5af338d03d37aecc7a2c5..d4ee74c063f871f3f6480408f0279447ad50e66b 100644 (file)
@@ -441,7 +441,7 @@ register_persistent (const char *host, unsigned short port, int fd)
 
   /* This lookup_host cannot fail, because it has the results in the
      cache.  */
-  pc_last_host_ip = lookup_host (host, 1);
+  pc_last_host_ip = lookup_host (host, LH_SILENT);
   assert (pc_last_host_ip != NULL);
 
   pc_last_port = port;
@@ -496,7 +496,7 @@ persistent_available_p (const char *host, unsigned short port)
     return 0;
 #endif /* HAVE_SSL */
 
-  this_host_ip = lookup_host (host, 1);
+  this_host_ip = lookup_host (host, LH_SILENT);
   if (!this_host_ip)
     return 0;