1
0
mirror of https://github.com/moparisthebest/wget synced 2024-07-03 16:38:41 -04:00

[svn] Imported Mauro's IPv6 changes.

This commit is contained in:
hniksic 2003-10-29 10:23:56 -08:00
parent dd6e9914e6
commit 90cb3309da
8 changed files with 1027 additions and 449 deletions

View File

@ -67,32 +67,44 @@ extern int errno;
/* Variables shared by bindport and acceptport: */ /* Variables shared by bindport and acceptport: */
static int msock = -1; static int msock = -1;
static struct sockaddr *addr; /*static struct sockaddr *addr;*/
static ip_address bind_address; static int
static int bind_address_resolved; resolve_bind_address (int flags, ip_address *addr)
static void
resolve_bind_address (void)
{ {
struct address_list *al; struct address_list *al = NULL;
int bind_address_resolved = 0;
if (bind_address_resolved || opt.bind_address == NULL) if (opt.bind_address != NULL)
/* Nothing to do. */
return;
al = lookup_host (opt.bind_address, 1);
if (!al)
{ {
logprintf (LOG_NOTQUIET, al = lookup_host (opt.bind_address, flags | LH_SILENT | LH_PASSIVE);
_("Unable to convert `%s' to a bind address. Reverting to ANY.\n"),
opt.bind_address); if (al == NULL)
return; {
logprintf (LOG_NOTQUIET,
_("Unable to convert `%s' to a bind address. Reverting to ANY.\n"),
opt.bind_address);
}
else
bind_address_resolved = 1;
} }
address_list_copy_one (al, 0, &bind_address); if (al == NULL)
{
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);
}
assert (al != NULL);
address_list_copy_one (al, 0, addr);
address_list_release (al); address_list_release (al);
bind_address_resolved = 1;
return bind_address_resolved;
} }
struct cwt_context { struct cwt_context {
@ -151,15 +163,16 @@ set_connection_host_name (const char *host)
int int
connect_to_one (ip_address *addr, unsigned short port, int silent) 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; int sock, save_errno;
/* Set port and protocol */ /* Set port and protocol */
wget_sockaddr_set_address (&sa, ip_default_family, port, addr); sockaddr_set_address (sa, port, addr);
if (!silent) if (!silent)
{ {
char *pretty_addr = pretty_print_address (addr); const char *pretty_addr = pretty_print_address (addr);
if (connection_host_name if (connection_host_name
&& 0 != strcmp (connection_host_name, pretty_addr)) && 0 != strcmp (connection_host_name, pretty_addr))
logprintf (LOG_VERBOSE, _("Connecting to %s[%s]:%hu... "), 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. */ /* 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) if (sock < 0)
goto out; goto out;
@ -191,22 +204,26 @@ connect_to_one (ip_address *addr, unsigned short port, int silent)
`--post-file', also set SO_SNDBUF here. */ `--post-file', also set SO_SNDBUF here. */
} }
resolve_bind_address (); if (opt.bind_address)
if (bind_address_resolved)
{ {
/* Bind the client side to the requested address. */ /* Bind the client side to the requested address. */
wget_sockaddr bsa; ip_address bind_address;
wget_sockaddr_set_address (&bsa, ip_default_family, 0, &bind_address); if (resolve_bind_address (0, &bind_address))
if (bind (sock, &bsa.sa, sockaddr_len ())) {
{ struct sockaddr_storage bss;
CLOSE (sock); struct sockaddr *bsa = (struct sockaddr *)&bss;
sock = -1; sockaddr_set_address (bsa, 0, &bind_address);
goto out; if (bind (sock, bsa, sockaddr_len (bsa)))
{
CLOSE (sock);
sock = -1;
goto out;
}
} }
} }
/* Connect the socket to the remote host. */ /* 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) opt.connect_timeout) < 0)
{ {
CLOSE (sock); CLOSE (sock);
@ -297,28 +314,47 @@ test_socket_open (int sock)
chosen by the system, and its value is stored to *PORT. The chosen by the system, and its value is stored to *PORT. The
internal variable MPORT is set to the value of the ensuing master internal variable MPORT is set to the value of the ensuing master
socket. Call acceptport() to block for and accept a connection. */ socket. Call acceptport() to block for and accept a connection. */
uerr_t uerr_t
bindport (unsigned short *port, int family) bindport (const ip_address *bind_address, unsigned short *port)
{ {
int optval = 1; int family = AF_INET;
wget_sockaddr srv; int optval;
memset (&srv, 0, sizeof (wget_sockaddr)); struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *)&ss;
memset (&ss, 0, sizeof (ss));
msock = -1; msock = -1;
#ifdef ENABLE_IPV6
if (bind_address->type == IPv6_ADDRESS)
family = AF_INET6;
#endif
if ((msock = socket (family, SOCK_STREAM, 0)) < 0) if ((msock = socket (family, SOCK_STREAM, 0)) < 0)
return CONSOCKERR; return CONSOCKERR;
#ifdef SO_REUSEADDR #ifdef SO_REUSEADDR
optval = 1;
if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR, if (setsockopt (msock, SOL_SOCKET, SO_REUSEADDR,
(char *)&optval, sizeof (optval)) < 0) (char *)&optval, sizeof (optval)) < 0)
return CONSOCKERR; return CONSOCKERR;
#endif #endif
resolve_bind_address (); #ifdef ENABLE_IPV6
wget_sockaddr_set_address (&srv, ip_default_family, htons (*port), # ifdef HAVE_IPV6_V6ONLY
bind_address_resolved ? &bind_address : NULL); if (family == AF_INET6)
if (bind (msock, &srv.sa, sockaddr_len ()) < 0) {
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); CLOSE (msock);
msock = -1; msock = -1;
@ -327,15 +363,16 @@ bindport (unsigned short *port, int family)
DEBUGP (("Master socket fd %d bound.\n", msock)); DEBUGP (("Master socket fd %d bound.\n", msock));
if (!*port) if (!*port)
{ {
socklen_t sa_len = sockaddr_len (); socklen_t sa_len = sockaddr_len (sa);
if (getsockname (msock, &srv.sa, &sa_len) < 0) if (getsockname (msock, sa, &sa_len) < 0)
{ {
CLOSE (msock); CLOSE (msock);
msock = -1; msock = -1;
return CONPORTERR; return CONPORTERR;
} }
*port = wget_sockaddr_get_port (&srv); *port = sockaddr_get_port (sa);
DEBUGP (("using port %i.\n", *port)); DEBUGP (("binding to address %s using port %i.\n",
pretty_print_address (bind_address), *port));
} }
if (listen (msock, 1) < 0) if (listen (msock, 1) < 0)
{ {
@ -389,13 +426,15 @@ select_fd (int fd, double maxtime, int writep)
uerr_t uerr_t
acceptport (int *sock) 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 #ifdef HAVE_SELECT
if (select_fd (msock, opt.connect_timeout, 0) <= 0) if (select_fd (msock, opt.connect_timeout, 0) <= 0)
return ACCEPTERR; return ACCEPTERR;
#endif #endif
if ((*sock = accept (msock, addr, &addrlen)) < 0) if ((*sock = accept (msock, sa, &addrlen)) < 0)
return ACCEPTERR; return ACCEPTERR;
DEBUGP (("Created socket fd %d.\n", *sock)); DEBUGP (("Created socket fd %d.\n", *sock));
return ACCEPTOK; return ACCEPTOK;
@ -419,24 +458,34 @@ closeport (int sock)
int int
conaddr (int fd, ip_address *ip) conaddr (int fd, ip_address *ip)
{ {
wget_sockaddr mysrv; struct sockaddr_storage ss;
socklen_t addrlen = sizeof (mysrv); struct sockaddr *sa = (struct sockaddr *)&ss;
if (getsockname (fd, &mysrv.sa, &addrlen) < 0) socklen_t addrlen = sizeof (ss);
if (getsockname (fd, sa, &addrlen) < 0)
return 0; return 0;
switch (mysrv.sa.sa_family) switch (sa->sa_family)
{ {
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
case AF_INET6: 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; return 1;
#endif #endif
case AF_INET: 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; return 1;
default: default:
abort (); abort ();
} }
return 0; return 0;
} }

View File

@ -32,6 +32,12 @@ so, delete this exception statement from your version. */
#include "host.h" #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 */ /* Function declarations */
int connect_to_one PARAMS ((ip_address *, unsigned short, int)); 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 test_socket_open PARAMS ((int));
int select_fd PARAMS ((int, double, 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 *)); uerr_t acceptport PARAMS ((int *));
void closeport PARAMS ((int)); void closeport PARAMS ((int));
int conaddr PARAMS ((int, ip_address *)); int conaddr PARAMS ((int, ip_address *));

View File

@ -29,6 +29,7 @@ so, delete this exception statement from your version. */
#include <config.h> #include <config.h>
#include <assert.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <errno.h> #include <errno.h>
@ -126,7 +127,7 @@ ftp_request (const char *command, const char *value)
if (strncmp (res, "PASS", 4) != 0) if (strncmp (res, "PASS", 4) != 0)
logprintf (LOG_ALWAYS, "--> %s\n", res); logprintf (LOG_ALWAYS, "--> %s\n", res);
else else
logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n"); logputs (LOG_ALWAYS, "--> PASS Turtle Power!\n\n");
} }
else else
DEBUGP (("\n--> %s\n", res)); DEBUGP (("\n--> %s\n", res));
@ -252,61 +253,23 @@ ftp_login (struct rbuf *rbuf, const char *acc, const char *pass)
return FTPOK; return FTPOK;
} }
#ifdef ENABLE_IPV6 static void
uerr_t ip_address_to_port_repr (const ip_address *addr, unsigned short port, char *buf,
ftp_eprt (struct rbuf *rbuf) size_t buflen)
{ {
uerr_t err; unsigned char *ptr;
char *request, *respline; assert (addr != NULL);
ip_address in_addr; assert (addr->type == IPv4_ADDRESS);
unsigned short port; assert (buf != NULL);
/* buf must contain the argument of PORT (of the form a,b,c,d,e,f). */
assert (buflen >= 6 * 4);
char ipv6 [8 * (4 * 3 + 3) + 8]; ptr = (unsigned char *)(&addr->addr.ipv4.addr.s_addr);
char *bytes; snprintf (buf, buflen, "%d,%d,%d,%d,%d,%d", ptr[0], ptr[1],
ptr[2], ptr[3], (unsigned) (port & 0xff00) >> 8, port & 0xff);
/* Setting port to 0 lets the system choose a free port. */ buf[buflen - 1] = '\0';
port = 0;
err = bindport (&port, ip_default_family);
if (err != BINDOK) /* Bind the port. */
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 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)))
{
closeport (port);
xfree (request);
return WRITEFAILED;
}
xfree (request);
/* Get appropriate response. */
err = ftp_response (rbuf, &respline);
if (err != FTPOK)
{
closeport (port);
xfree (respline);
return err;
}
if (*respline != '2')
{
closeport (port);
xfree (respline);
return FTPPORTERR;
}
xfree (respline);
return FTPOK;
} }
#endif
/* Bind a port and send the appropriate PORT command to the FTP /* Bind a port and send the appropriate PORT command to the FTP
server. Use acceptport after RETR, to get the socket of data server. Use acceptport after RETR, to get the socket of data
@ -316,53 +279,136 @@ ftp_port (struct rbuf *rbuf)
{ {
uerr_t err; uerr_t err;
char *request, *respline; char *request, *respline;
char bytes[6 * 4 +1]; ip_address addr;
ip_address in_addr;
ip4_address in_addr_4;
unsigned char *in_addr4_ptr = (unsigned char *)&in_addr_4;
int nwritten; int nwritten;
unsigned short port; unsigned short port;
#ifdef ENABLE_IPV6 /* Must contain the argument of PORT (of the form a,b,c,d,e,f). */
/* char bytes[6 * 4 + 1];
Only try the Extented Version if we actually use IPv6
*/ assert (rbuf != NULL);
if (ip_default_family == AF_INET6) assert (rbuf_initialized_p (rbuf));
{
err = ftp_eprt (rbuf); /* Get the address of this side of the connection. */
if (err == FTPOK) if (!conaddr (RBUF_FD (rbuf), &addr))
return err; return BINDERR;
}
#endif assert (addr.type == IPv4_ADDRESS);
/* Setting port to 0 lets the system choose a free port. */ /* Setting port to 0 lets the system choose a free port. */
port = 0; port = 0;
err = bindport (&port, AF_INET); /* Bind the port. */
err = bindport (&addr, &port);
if (err != BINDOK) if (err != BINDOK)
return err; return err;
/* Get the address of this side of the connection and convert it /* Construct the argument of PORT (of the form a,b,c,d,e,f). */
(back) to IPv4. */ ip_address_to_port_repr (&addr, port, bytes, sizeof (bytes));
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);
/* Send PORT request. */ /* Send PORT request. */
request = ftp_request ("PORT", bytes); request = ftp_request ("PORT", bytes);
nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request)); nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
if (nwritten < 0) if (nwritten < 0)
{ {
xfree (request); xfree (request);
closeport (-1);
return WRITEFAILED;
}
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;
}
#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_lprt (struct rbuf *rbuf)
{
uerr_t err;
char *request, *respline;
ip_address addr;
int nwritten;
unsigned short port;
/* 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)
{
xfree (request);
closeport (-1);
return WRITEFAILED; return WRITEFAILED;
} }
xfree (request); xfree (request);
@ -371,77 +417,104 @@ ftp_port (struct rbuf *rbuf)
if (err != FTPOK) if (err != FTPOK)
{ {
xfree (respline); xfree (respline);
closeport (-1);
return err; return err;
} }
if (*respline != '2') if (*respline != '2')
{ {
xfree (respline); xfree (respline);
closeport (-1);
return FTPPORTERR; return FTPPORTERR;
} }
xfree (respline); xfree (respline);
return FTPOK; return FTPOK;
} }
#ifdef ENABLE_IPV6 static void
uerr_t ip_address_to_eprt_repr (const ip_address *addr, unsigned short port, char *buf,
ftp_epsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port, size_t buflen)
char *typ)
{ {
int err; int afnum;
char *s, *respline;
char *request = ftp_request ("EPSV", typ); assert (addr != NULL);
if (0 > iwrite (RBUF_FD (rbuf), request, strlen (request))) 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;
/* 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_eprt_repr (&addr, port, bytes, sizeof (bytes));
/* Send PORT request. */
request = ftp_request ("EPRT", bytes);
nwritten = iwrite (RBUF_FD (rbuf), request, strlen (request));
if (nwritten < 0)
{ {
xfree (request); xfree (request);
closeport (-1);
return WRITEFAILED; return WRITEFAILED;
} }
/* Get the server response. */ xfree (request);
/* Get appropriate response. */
err = ftp_response (rbuf, &respline); err = ftp_response (rbuf, &respline);
if (err != FTPOK) if (err != FTPOK)
{ {
xfree (respline); xfree (respline);
closeport (-1);
return err; return err;
} }
if (*respline != '2') if (*respline != '2')
{ {
xfree (respline); xfree (respline);
return FTPNOPASV; closeport (-1);
return FTPPORTERR;
} }
/* 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);
xfree (respline); 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 */
}
}
return FTPOK; return FTPOK;
} }
#endif #endif
/* Similar to ftp_port, but uses `PASV' to initiate the passive FTP /* Similar to ftp_port, but uses `PASV' to initiate the passive FTP
transfer. Reads the response from server and parses it. Reads the transfer. Reads the response from server and parses it. Reads the
host and port addresses and returns them. */ host and port addresses and returns them. */
@ -451,19 +524,15 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
char *request, *respline, *s; char *request, *respline, *s;
int nwritten, i; int nwritten, i;
uerr_t err; uerr_t err;
unsigned char addr4[4]; unsigned char tmp[6];
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. */ /* Form the request. */
request = ftp_request ("PASV", NULL); request = ftp_request ("PASV", NULL);
/* And send it. */ /* And send it. */
@ -487,16 +556,132 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
return FTPNOPASV; return FTPNOPASV;
} }
/* Parse the request. */ /* Parse the request. */
/* respline::=227 Entering Passive Mode (h1,h2,h3,h4,p1,p2). */
s = respline; s = respline;
for (s += 4; *s && !ISDIGIT (*s); s++); for (s += 4; *s && !ISDIGIT (*s); s++);
if (!*s) if (!*s)
return FTPINVPASV; return FTPINVPASV;
for (i = 0; i < 4; i++) for (i = 0; i < 6; i++)
{ {
addr4[i] = 0; tmp[i] = 0;
for (; ISDIGIT (*s); s++) for (; ISDIGIT (*s); s++)
addr4[i] = (*s - '0') + 10 * addr4[i]; 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);
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;
}
#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_lpsv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
{
char *request, *respline, *s;
int nwritten, i, af, addrlen, portlen;
uerr_t err;
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));
/* Form the request. */
request = ftp_request ("LPSV", 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)
{
xfree (respline);
return err;
}
if (*respline != '2')
{
xfree (respline);
return FTPNOPASV;
}
/* Parse the response. */
s = respline;
for (s += 4; *s && !ISDIGIT (*s); s++);
if (!*s)
return FTPINVPASV;
/* 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++ != ',')
{
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++)
tmp[i] = (*s - '0') + 10 * tmp[i];
if (*s == ',') if (*s == ',')
s++; s++;
else else
@ -506,30 +691,185 @@ ftp_pasv (struct rbuf *rbuf, ip_address *addr, unsigned short *port)
} }
} }
/* Eventually make an IPv4 in IPv6 adress if needed */ /* Now, get the port length */
map_ipv4_to_ip ((ip4_address *)addr4, addr); portlen = 0;
*port=0;
for (; ISDIGIT (*s); s++) for (; ISDIGIT (*s); s++)
*port = (*s - '0') + 10 * (*port); portlen = (*s - '0') + 10 * portlen;
if (*s == ',')
s++; if (!*s || *s++ != ',')
else
{ {
xfree (respline); xfree (respline);
return FTPINVPASV; return FTPINVPASV;
} }
{ if (portlen > 2)
unsigned short port2 = 0; {
for (; ISDIGIT (*s); s++) xfree (respline);
port2 = (*s - '0') + 10 * port2; return FTPINVPASV;
*port = (*port) * 256 + port2; }
}
/* Finally, we get the port number */
tmpprt[0] = 0;
for (; ISDIGIT (*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); xfree (respline);
return FTPOK; 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;
}
}
/* 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. */ /* Sends the TYPE request to the server. */
uerr_t uerr_t
ftp_type (struct rbuf *rbuf, int type) ftp_type (struct rbuf *rbuf, int type)
@ -755,7 +1095,7 @@ ftp_syst (struct rbuf *rbuf, enum stype *server_type)
/* Skip the number (215, but 200 (!!!) in case of VMS) */ /* Skip the number (215, but 200 (!!!) in case of VMS) */
strtok (respline, " "); strtok (respline, " ");
/* Which system type has been reported (we are interested just in the /* Which system type has been reported (we are interested just in the
first word of the server response)? */ first word of the server response)? */
request = strtok (NULL, " "); request = strtok (NULL, " ");
@ -812,7 +1152,7 @@ ftp_pwd (struct rbuf *rbuf, char **pwd)
and everything following it. */ and everything following it. */
strtok (respline, "\""); strtok (respline, "\"");
request = strtok (NULL, "\""); request = strtok (NULL, "\"");
/* Has the `pwd' been already allocated? Free! */ /* Has the `pwd' been already allocated? Free! */
FREE_MAYBE (*pwd); FREE_MAYBE (*pwd);

117
src/ftp.c
View File

@ -121,6 +121,110 @@ ftp_expected_bytes (const char *s)
return res; 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 /* Retrieves a file with denoted parameters through opening an FTP
connection to the server. It always closes the data connection, connection to the server. It always closes the data connection,
and closes the control connection in case of error. */ 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; unsigned short passive_port;
if (!opt.server_response) if (!opt.server_response)
logputs (LOG_VERBOSE, "==> PASV ... "); 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 */ /* FTPRERR, WRITEFAILED, FTPNOPASV, FTPINVPASV */
switch (err) switch (err)
{ {
@ -579,13 +683,16 @@ Error in server response, closing control connection.\n"));
} /* switch(err) */ } /* switch(err) */
if (err==FTPOK) 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); dtsock = connect_to_one (&passive_addr, passive_port, 1);
if (dtsock < 0) if (dtsock < 0)
{ {
int save_errno = errno; int save_errno = errno;
CLOSE (csock); CLOSE (csock);
rbuf_uninitialize (&con->rbuf); 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, pretty_print_address (&passive_addr), passive_port,
strerror (save_errno)); strerror (save_errno));
return CONNECT_ERROR (save_errno); return CONNECT_ERROR (save_errno);
@ -601,7 +708,7 @@ Error in server response, closing control connection.\n"));
{ {
if (!opt.server_response) if (!opt.server_response)
logputs (LOG_VERBOSE, "==> PORT ... "); logputs (LOG_VERBOSE, "==> PORT ... ");
err = ftp_port (&con->rbuf); err = ftp_do_port (&con->rbuf);
/* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR, /* FTPRERR, WRITEFAILED, bindport (CONSOCKERR, CONPORTERR, BINDERR,
LISTENERR), HOSTERR, FTPPORTERR */ LISTENERR), HOSTERR, FTPPORTERR */
switch (err) switch (err)
@ -739,6 +846,7 @@ Error in server response, closing control connection.\n"));
logprintf (LOG_VERBOSE, "==> RETR %s ... ", u->file); logprintf (LOG_VERBOSE, "==> RETR %s ... ", u->file);
} }
} }
err = ftp_retr (&con->rbuf, u->file); err = ftp_retr (&con->rbuf, u->file);
/* FTPRERR, WRITEFAILED, FTPNSFOD */ /* FTPRERR, WRITEFAILED, FTPNSFOD */
switch (err) switch (err)
@ -930,6 +1038,7 @@ Error in server response, closing control connection.\n"));
if (flush_res == EOF) if (flush_res == EOF)
res = -2; res = -2;
} }
/* If get_contents couldn't write to fp, bail out. */ /* If get_contents couldn't write to fp, bail out. */
if (res == -2) 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)); logprintf (LOG_NOTQUIET, "unlink: %s\n", strerror (errno));
} }
} }
/* Restore the original leave-pendingness. */ /* Restore the original leave-pendingness. */
if (orig_lp) if (orig_lp)
con->cmd |= LEAVE_PENDING; con->cmd |= LEAVE_PENDING;

View File

@ -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_port PARAMS ((struct rbuf *));
uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_address *, unsigned short *)); uerr_t ftp_pasv PARAMS ((struct rbuf *, ip_address *, unsigned short *));
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
uerr_t ftp_epsv PARAMS ((struct rbuf *, ip_address *, unsigned short *, uerr_t ftp_lprt PARAMS ((struct rbuf *));
char *)); 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 #endif
uerr_t ftp_type PARAMS ((struct rbuf *, int)); uerr_t ftp_type PARAMS ((struct rbuf *, int));
uerr_t ftp_cwd PARAMS ((struct rbuf *, const char *)); uerr_t ftp_cwd PARAMS ((struct rbuf *, const char *));

View File

@ -45,7 +45,7 @@ so, delete this exception statement from your version. */
#ifdef WINDOWS #ifdef WINDOWS
# include <winsock.h> # include <winsock.h>
# define SET_H_ERRNO(err) WSASetLastError(err) # define SET_H_ERRNO(err) WSASetLastError (err)
#else #else
# include <sys/socket.h> # include <sys/socket.h>
# include <netinet/in.h> # include <netinet/in.h>
@ -82,9 +82,9 @@ extern int h_errno;
#endif #endif
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
int ip_default_family = AF_INET6; int ip_default_family = AF_UNSPEC;
#else #else
int ip_default_family = AF_INET; int ip_default_family = AF_INET;
#endif #endif
/* Mapping between known hosts and to lists of their addresses. */ /* Mapping between known hosts and to lists of their addresses. */
@ -105,7 +105,7 @@ struct address_list {
/* Get the bounds of the address list. */ /* Get the bounds of the address list. */
void 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; *start = al->faulty;
*end = al->count; *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. */ /* Copy address number INDEX to IP_STORE. */
void 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); assert (index >= al->faulty && index < al->count);
memcpy (ip_store, al->addresses + index, sizeof (ip_address)); 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. */ /* Check whether two address lists have all their IPs in common. */
int 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) if (al1 == al2)
return 1; return 1;
if (al1->count != al2->count) if (al1->count != al2->count)
return 0; return 0;
return 0 == memcmp (al1->addresses, al2->addresses, for (i = 0; i < al1->count; ++i)
al1->count * sizeof (ip_address)); {
#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 /* 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; al->faulty = 0;
} }
#ifdef HAVE_GETADDRINFO #ifdef ENABLE_IPV6
/** /**
* address_list_from_addrinfo * address_list_from_addrinfo
* *
@ -166,15 +195,15 @@ address_list_set_faulty (struct address_list *al, int index)
* address_list* New allocated address_list * address_list* New allocated address_list
*/ */
static struct 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 address_list *al;
struct addrinfo *ai_head = ai; const struct addrinfo *ptr;
int cnt = 0; int cnt = 0;
int i; int i;
for (ai = ai_head; ai; ai = ai->ai_next) for (ptr = ai; ptr != NULL ; ptr = ptr->ai_next)
if (ai->ai_family == AF_INET || ai->ai_family == AF_INET6) if (ptr->ai_family == AF_INET || ptr->ai_family == AF_INET6)
++cnt; ++cnt;
if (cnt == 0) if (cnt == 0)
return NULL; return NULL;
@ -185,17 +214,24 @@ address_list_from_addrinfo (struct addrinfo *ai)
al->faulty = 0; al->faulty = 0;
al->refcount = 1; al->refcount = 1;
for (i = 0, ai = ai_head; ai; ai = ai->ai_next) for (i = 0, ptr = ai; ptr != NULL; ptr = ptr->ai_next)
if (ai->ai_family == AF_INET6) if (ptr->ai_family == AF_INET6)
{ {
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr; const struct sockaddr_in6 *sin6 =
memcpy (al->addresses + i, &sin6->sin6_addr, 16); (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; ++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; const struct sockaddr_in *sin =
map_ipv4_to_ip ((ip4_address *)&sin->sin_addr, al->addresses + i); (const struct sockaddr_in *)ptr->ai_addr;
al->addresses[i].addr.ipv4.addr = sin->sin_addr;
al->addresses[i].type = IPv4_ADDRESS;
++i; ++i;
} }
assert (i == cnt); assert (i == cnt);
@ -219,18 +255,20 @@ address_list_from_vector (char **h_addr_list)
al->addresses = xmalloc (count * sizeof (ip_address)); al->addresses = xmalloc (count * sizeof (ip_address));
al->refcount = 1; al->refcount = 1;
for (i = 0; i < count; i++) for (i = 0; i < count; i++) {
map_ipv4_to_ip ((ip4_address *)h_addr_list[i], al->addresses + 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; return al;
} }
#endif
/* Like address_list_from_vector, but initialized with a single /* Like address_list_from_vector, but initialized with a single
address. */ address. */
static struct address_list * 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)); struct address_list *al = xmalloc (sizeof (struct address_list));
al->count = 1; al->count = 1;
@ -241,6 +279,7 @@ address_list_from_single (ip_address *addr)
return al; return al;
} }
#endif
static void static void
address_list_delete (struct address_list *al) address_list_delete (struct address_list *al)
@ -262,58 +301,93 @@ address_list_release (struct address_list *al)
} }
/** /**
* wget_sockaddr_set_address * sockaddr_set_address
* *
* This function takes an wget_sockaddr and fill in the protocol type, * This function takes a sockaddr struct and fills in the protocol type,
* the port number and the address, there NULL in address means wildcard. * the port number and the address. If ENABLE_IPV6 is defined, the sa
* Unsuported adress family will abort the whole programm. * 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: * Input:
* wget_sockaddr* The space to be filled * struct sockaddr* The space to be filled
* int The wished protocol
* unsigned short The port * unsigned short The port
* const ip_address The Binary IP adress * const ip_address The IP address
* *
* Return: * Return:
* - Only modify 1. param * - Only modifies 1st parameter.
*/ */
void void
wget_sockaddr_set_address (wget_sockaddr *sa, sockaddr_set_address (struct sockaddr *sa, unsigned short port,
int ip_family, unsigned short port, ip_address *addr) const ip_address *addr)
{ {
if (ip_family == AF_INET) if (addr->type == IPv4_ADDRESS)
{ {
sa->sin.sin_family = ip_family; struct sockaddr_in *sin = (struct sockaddr_in *)sa;
sa->sin.sin_port = htons (port);
sin->sin_family = AF_INET;
sin->sin_port = htons (port);
if (addr == NULL) if (addr == NULL)
memset (&sa->sin.sin_addr, 0, sizeof(ip4_address)); sin->sin_addr.s_addr = INADDR_ANY;
else else
{ sin->sin_addr = addr->addr.ipv4.addr;
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;
} }
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
if (ip_family == AF_INET6) else if (addr->type == IPv6_ADDRESS)
{ {
sa->sin6.sin6_family = ip_family; struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
sa->sin6.sin6_port = htons (port);
sin6->sin6_family = AF_INET6;
sin6->sin6_port = htons (port);
if (addr == NULL) if (addr == NULL)
memset (&sa->sin6.sin6_addr, 0 , 16); sin6->sin6_addr = in6addr_any;
else else
memcpy (&sa->sin6.sin6_addr, addr, 16); sin6->sin6_addr = addr->addr.ipv6.addr;
return; #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
sin6->sin6_scope_id = addr->addr.ipv6.scope_id;
#endif /* HAVE_SOCKADDR_IN6_SCOPE_ID */
} }
#endif #endif /* ENABLE_IPV6 */
abort(); 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
else
abort ();
}
#if 0 /* currently unused */
/** /**
* wget_sockaddr_set_port * sockaddr_set_port
* *
* This funtion only fill the port of the socket information. * This funtion only fill the port of the socket information.
* If the protocol is not supported nothing is done. * If the protocol is not supported nothing is done.
@ -330,54 +404,27 @@ wget_sockaddr_set_address (wget_sockaddr *sa,
* - Only modify 1. param * - Only modify 1. param
*/ */
void 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); struct sockaddr_in *sin = (struct sockaddr_in *)sa;
return; sin->sin_port = htons (port);
} }
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
if (sa->sa.sa_family == AF_INET6) else if (sa->sa_family == AF_INET6)
{ {
sa->sin6.sin6_port = htons (port); struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
return; sin6->sin6_port = htons (port);
} }
#endif #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 #endif
abort();
/* unreached */
return NULL;
}
/** /**
* wget_sockaddr_get_port * sockaddr_get_port
* *
* This function only return the port from the input structure * This function only return the port from the input structure
* Unsuported adress family will abort the whole programm. * 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 Port Number in host order.
*/ */
unsigned short unsigned short
wget_sockaddr_get_port (const wget_sockaddr *sa) sockaddr_get_port (const struct sockaddr *sa)
{ {
if (sa->sa.sa_family == AF_INET) if (sa->sa_family == AF_INET) {
return htons (sa->sin.sin_port); const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
return htons (sin->sin_port);
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
if (sa->sa.sa_family == AF_INET6) } else if (sa->sa_family == AF_INET6) {
return htons (sa->sin6.sin6_port); const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
return htons (sin6->sin6_port);
#endif #endif
abort(); } else
abort ();
/* do not complain about return nothing */ /* do not complain about return nothing */
return -1; return -1;
} }
@ -419,58 +469,26 @@ wget_sockaddr_get_port (const wget_sockaddr *sa)
* - Public IP-Family Information * - Public IP-Family Information
* *
* Output: * Output:
* socklen_t structure length for socket options * int structure length for socket options
*/ */
socklen_t socklen_t
sockaddr_len () sockaddr_len (const struct sockaddr *sa)
{ {
if (ip_default_family == AF_INET) if (sa->sa_family == AF_INET)
return sizeof (struct sockaddr_in); {
return sizeof (struct sockaddr_in);
}
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
if (ip_default_family == AF_INET6) else if (sa->sa_family == AF_INET6)
return sizeof (struct sockaddr_in6); {
return sizeof (struct sockaddr_in6);
}
#endif #endif
abort(); else
abort ();
/* do not complain about return nothing */ /* do not complain about return nothing */
return 0; 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. */ /* 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 inet_ntoa. With IPv6, it either prints an IPv6 address or an IPv4
address. */ address. */
char * const char *
pretty_print_address (ip_address *addr) pretty_print_address (const ip_address *addr)
{ {
switch (addr->type)
{
case IPv4_ADDRESS:
return inet_ntoa (addr->addr.ipv4.addr);
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
ip4_address addr4; case IPv6_ADDRESS:
static char buf[128]; {
int len;
if (map_ip_to_ipv4 (addr, &addr4)) static char buf[128];
return inet_ntoa (*(struct in_addr *)&addr4); inet_ntop (AF_INET6, &addr->addr.ipv6.addr, buf, sizeof (buf));
#if 0
if (!inet_ntop (AF_INET6, addr, buf, sizeof (buf))) #ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
return "<unknown>"; /* print also scope_id for all ?non-global? addresses */
return buf; snprintf (buf + len, sizeof (buf) - len, "%%%d", addr->addr.ipv6.scope_id);
#endif #endif
return inet_ntoa (*(struct in_addr *)addr); #endif
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. /* 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 * struct address_list *
lookup_host (const char *host, int silent) lookup_host (const char *host, int flags)
{ {
struct address_list *al = NULL; 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 #ifdef ENABLE_IPV6
if (inet_pton (AF_INET6, host, &addr) > 0) int err, family;
return address_list_from_single (&addr); 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. */
#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)
{
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 #endif
addr_ipv4 = (uint32_t)inet_addr (host); /* Then, try to find the host in the cache. */
if (addr_ipv4 != (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);
}
if (host_name_addresses_map) 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); logprintf (LOG_VERBOSE, _("Resolving %s... "), host);
/* Host name lookup goes on below. */ /* Host name lookup goes on below. */
#ifdef HAVE_GETADDRINFO #ifdef ENABLE_IPV6
{ {
struct addrinfo hints, *ai;
int err;
memset (&hints, 0, sizeof (hints)); memset (&hints, 0, sizeof (hints));
if (ip_default_family == AF_INET) hints.ai_family = family;
hints.ai_family = AF_INET;
else
hints.ai_family = PF_UNSPEC;
hints.ai_socktype = SOCK_STREAM; 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;
if (err != 0 || ai == NULL) err = getaddrinfo_with_timeout (host, NULL, &hints, &res, opt.dns_timeout);
if (err != 0 || res == NULL)
{ {
if (!silent) if (!(flags & LH_SILENT))
logprintf (LOG_VERBOSE, _("failed: %s.\n"), logprintf (LOG_VERBOSE, _("failed: %s.\n"),
err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno)); err != EAI_SYSTEM ? gai_strerror (err) : strerror (errno));
return NULL; return NULL;
} }
al = address_list_from_addrinfo (ai); al = address_list_from_addrinfo (res);
freeaddrinfo (ai); freeaddrinfo (res);
} }
#else #else
{ {
struct hostent *hptr; struct hostent *hptr = gethostbyname_with_timeout (host, opt.dns_timeout);
hptr = gethostbyname_with_timeout (host, opt.dns_timeout);
if (!hptr) if (!hptr)
{ {
if (!silent) if (!(flags & LH_SILENT))
{ {
if (errno != ETIMEDOUT) if (errno != ETIMEDOUT)
logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno)); logprintf (LOG_VERBOSE, _("failed: %s.\n"), herrmsg (h_errno));
@ -675,6 +739,7 @@ lookup_host (const char *host, int silent)
} }
return NULL; return NULL;
} }
assert (hptr->h_length == 4);
/* Do all systems have h_addr_list, or is it a newer thing? If /* Do all systems have h_addr_list, or is it a newer thing? If
the latter, use address_list_from_single. */ the latter, use address_list_from_single. */
al = address_list_from_vector (hptr->h_addr_list); 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 /* Print the addresses determined by DNS lookup, but no more than
three. */ three. */
if (!silent) if (!(flags & LH_SILENT))
{ {
int i; int i;
int printmax = al->count <= 3 ? al->count : 3; int printmax = al->count <= 3 ? al->count : 3;

View File

@ -6,7 +6,7 @@ This file is part of GNU Wget.
GNU Wget is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or 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, GNU Wget is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of 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 url;
struct address_list; struct address_list;
/* wget_sockaddr is used instead of sockaddr where an IPV6 address extern int ip_default_family; /* defined in host.c */
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;
typedef struct { typedef struct {
unsigned char bytes[4]; enum {
} ip4_address; IPv4_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>. */
#ifdef ENABLE_IPV6 #ifdef ENABLE_IPV6
# define MAX_IP_ADDRESS_SIZE 16 IPv6_ADDRESS
#else #endif /* ENABLE_IPV6 */
# define MAX_IP_ADDRESS_SIZE 4 } type;
#endif union {
#ifdef ENABLE_IPV6
typedef struct { struct {
unsigned char bytes[MAX_IP_ADDRESS_SIZE]; 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; } ip_address;
#ifndef ENABLE_IPV6
#ifndef HAVE_SOCKADDR_STORAGE
#define sockaddr_storage sockaddr_in
#endif
#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 */ /* Function declarations */
struct address_list *lookup_host PARAMS ((const char *, int)); struct address_list *lookup_host PARAMS ((const char *, int));
char *herrmsg PARAMS ((int)); char *herrmsg PARAMS ((int));
void address_list_get_bounds PARAMS ((struct address_list *, int *, int *)); void address_list_get_bounds PARAMS ((const struct address_list *,
void address_list_copy_one PARAMS ((struct address_list *, int, int *, int *));
void address_list_copy_one PARAMS ((const struct address_list *, int,
ip_address *)); ip_address *));
int address_list_match_all PARAMS ((struct address_list *, int address_list_match_all PARAMS ((const struct address_list *,
struct address_list *)); const struct address_list *));
void address_list_set_faulty PARAMS ((struct address_list *, int)); void address_list_set_faulty PARAMS ((struct address_list *, int));
void address_list_release PARAMS ((struct address_list *)); 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 accept_domain PARAMS ((struct url *));
int sufmatch PARAMS ((const char **, const char *)); int sufmatch PARAMS ((const char **, const char *));
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)); 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 */
#endif /* HOST_H */ #endif /* HOST_H */

View 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 /* This lookup_host cannot fail, because it has the results in the
cache. */ cache. */
pc_last_host_ip = lookup_host (host, 1); pc_last_host_ip = lookup_host (host, LH_SILENT);
assert (pc_last_host_ip != NULL); assert (pc_last_host_ip != NULL);
pc_last_port = port; pc_last_port = port;
@ -496,7 +496,7 @@ persistent_available_p (const char *host, unsigned short port)
return 0; return 0;
#endif /* HAVE_SSL */ #endif /* HAVE_SSL */
this_host_ip = lookup_host (host, 1); this_host_ip = lookup_host (host, LH_SILENT);
if (!this_host_ip) if (!this_host_ip)
return 0; return 0;