[links] add ipv6 patch

Ondrej Vasik ovasik at fedoraproject.org
Fri Jun 8 11:52:04 UTC 2012


commit 7b7a6fe9342f3a6c19f9f854f7c7e246a4ad4909
Author: Ondřej Vašík <ovasik at redhat.com>
Date:   Fri Jun 8 13:51:59 2012 +0200

    add ipv6 patch

 links-2.6-ipv6.patch |  954 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 954 insertions(+), 0 deletions(-)
---
diff --git a/links-2.6-ipv6.patch b/links-2.6-ipv6.patch
new file mode 100644
index 0000000..ffabdb4
--- /dev/null
+++ b/links-2.6-ipv6.patch
@@ -0,0 +1,954 @@
+diff -urNp links-2.6-orig/bfu.c links-2.6/bfu.c
+--- links-2.6-orig/bfu.c	2012-04-09 05:09:00.000000000 +0200
++++ links-2.6/bfu.c	2012-06-08 09:44:30.276915109 +0200
+@@ -1526,15 +1526,16 @@ int check_local_ip_address(struct dialog
+ {
+ 	int s;
+ 	int rs;
++	struct sockaddr_storage sockaddr;
+ 	unsigned char *p = di->cdata;
+ 	if (!*p) {
+ 		return 0;
+ 	}
+-	if (numeric_ip_address(p, NULL) == -1) {
++	if (numeric_ip_address(p, &sockaddr) == -1) {
+ 		msg_box(dlg->win->term, NULL, TEXT_(T_BAD_IP_ADDRESS), AL_CENTER, TEXT_(T_INVALID_IP_ADDRESS_SYNTAX), NULL, 1, TEXT_(T_CANCEL), NULL, B_ENTER | B_ESC);
+ 		return 1;
+ 	}
+-	s = socket_and_bind(p);
++	s = socket_and_bind(p, sockaddr.ss_family, SOCK_STREAM, 0);
+ 	if (s != -1) {
+ 		EINTRLOOP(rs, close(s));
+ 	} else {
+diff -urNp links-2.6-orig/configure.in links-2.6/configure.in
+--- links-2.6-orig/configure.in	2012-06-08 09:43:20.207817752 +0200
++++ links-2.6/configure.in	2012-06-08 09:44:30.279914737 +0200
+@@ -400,37 +400,12 @@ if test "$cf_result" = no; then
+ 	AC_CHECK_LIB(socket, setsockopt)
+ fi
+ 
+-#AC_MSG_CHECKING([for gethostbyname])
+-#AC_TRY_LINK([#include <netdb.h>], [gethostbyname("")], cf_result=yes, cf_result=no)
+-#AC_MSG_RESULT($cf_result)
+-AC_CHECK_FUNC(gethostbyname, cf_result=yes, cf_result=no)
+-if test "$cf_result" = no; then
+-	AC_CHECK_LIB(socket, gethostbyname)
+-	cf_result="$ac_cv_lib_socket_gethostbyname"
+-	if test "$ac_cv_lib_socket_gethostbyname" = no; then
+-		AC_CHECK_LIB(nsl, gethostbyname)
+-		cf_result="$ac_cv_lib_nsl_gethostbyname"
+-	fi
+-fi
+-test "$cf_result" = yes && AC_DEFINE(HAVE_GETHOSTBYNAME)
+-
+-if test "$cf_result" = yes && test "$ac_cv_have_watcom" = yes -o "`uname -s`" = SunOS; then
+-	AC_CACHE_CHECK([for flawed gethostbyname], ac_cv_gethostbyname_bug,
+-		AC_TRY_RUN([
+-		#include <netdb.h>
+-		int main()
+-		{
+-			return !gethostbyname("www.gnu.org");
+-		}
+-		], ac_cv_gethostbyname_bug=no, ac_cv_gethostbyname_bug=yes, ac_cv_gethostbyname_bug="$ac_cv_have_watcom")
+-	)
+-	test "$ac_cv_gethostbyname_bug" = yes && AC_DEFINE(HAVE_GETHOSTBYNAME_BUG)
+-fi
+-
+-AC_HAVE_FUNCS(gethostbyaddr)
++AC_CHECK_FUNCS(getaddrinfo getnameinfo freeaddrinfo, [],
++               AC_ERROR([RFC 3493 (getaddrinfo() etc.) not supported]))
+ AC_HAVE_FUNCS(dhcp_option)
+ 
+-AC_HAVE_FUNCS(herror)
++AC_CHECK_FUNC(gai_strerror, AC_DEFINE([HAVE_GAI_STRERROR], [1],
++              [Define if you have gai_strerror(3) function]))
+ AC_HAVE_FUNCS(cfmakeraw)
+ 
+ AC_HAVE_FUNCS(cygwin_conv_to_full_win32_path)
+diff -urNp links-2.6-orig/connect.c links-2.6/connect.c
+--- links-2.6-orig/connect.c	2012-06-08 09:43:20.200790122 +0200
++++ links-2.6/connect.c	2012-06-08 09:44:30.283915502 +0200
+@@ -43,24 +43,22 @@ static void exception(struct connection 
+ 	retry_connection(c);
+ }
+ 
+-int socket_and_bind(unsigned char *address)
++/* Create a socket of given family, type, and protocol. If @address is
++ * provided, bind it to the address.
++ * Return the socket, or -1 in case of error. */
++int socket_and_bind(unsigned char *address, int family, int type, int protocol)
+ {
+ 	int s;
+ 	int rs;
+-	EINTRLOOP(s, socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
++	EINTRLOOP(s, socket(family, type, protocol));
+ 	if (s == -1)
+ 		return -1;
+ 	if (address && *address) {
+-		struct sockaddr_in sa;
+-		ip__address addr;
+-		if (numeric_ip_address(address, &addr) == -1) {
++		struct sockaddr_storage sa;
++		if (numeric_ip_address(address, &sa) == -1) {
+ 			errno = EINVAL;
+ 			return -1;
+ 		}
+-		memset(&sa, 0, sizeof(struct sockaddr_in));
+-		sa.sin_family = AF_INET;
+-		sa.sin_addr.s_addr = addr;
+-		sa.sin_port = htons(0);
+ 		EINTRLOOP(rs, bind(s, (struct sockaddr *)(void *)&sa, sizeof sa));
+ 		if (rs) {
+ 			int sv_errno = errno;
+@@ -83,7 +81,7 @@ void close_socket(int *s)
+ 
+ struct conn_info {
+ 	void (*func)(struct connection *);
+-	ip__address addr;
++	char addr[NI_MAXHOST];
+ 	int port;
+ 	int *sock;
+ 	int real_port;
+@@ -106,6 +104,7 @@ void make_connection(struct connection *
+ 		host = stracpy(p);
+ 		real_port = port;
+ 		port = 1080;
++		/* TODO: Parse proxy specification as IPv6 */
+ 		if ((p = strchr(host, ':'))) {
+ 			*p++ = 0;
+ 			if (!*p) goto badu;
+@@ -137,18 +136,22 @@ void make_connection(struct connection *
+ 	log_data("\nCONNECTION: ", 13);
+ 	log_data(host, strlen(host));
+ 	log_data("\n", 1);
+-	if (c->no_cache >= NC_RELOAD) as = find_host_no_cache(host, &b->addr, &c->dnsquery, (void(*)(void *, int))dns_found, c);
+-	else as = find_host(host, &b->addr, &c->dnsquery, (void(*)(void *, int))dns_found, c);
++	if (c->no_cache >= NC_RELOAD) as = find_host_no_cache(host, b->addr, &c->dnsquery, (void(*)(void *, int))dns_found, c);
++	else as = find_host(host, b->addr, &c->dnsquery, (void(*)(void *, int))dns_found, c);
+ 	mem_free(host);
+ 	if (as) setcstate(c, S_DNS);
+ }
+ 
+-int get_pasv_socket(struct connection *c, int cc, int *sock, unsigned char *port)
++/* Create new listening socket bound to the same address as socket @cc.
++ * New socket is returned in @sock, address of new socket in @port. Both must
++ * be prellocated.
++ * Return 0, -1 in case of error. */
++int get_pasv_socket(struct connection *c, int cc, int *sock, struct sockaddr_storage *port)
+ {
+ 	int s;
+ 	int rs;
+-	struct sockaddr_in sa;
+-	struct sockaddr_in sb;
++	struct sockaddr_storage sa;
++	struct sockaddr_storage sb;
+ 	socklen_t len = sizeof(sa);
+ 	memset(&sa, 0, sizeof sa);
+ 	memset(&sb, 0, sizeof sb);
+@@ -159,12 +162,22 @@ int get_pasv_socket(struct connection *c
+ 		retry_connection(c);
+ 		return -1;
+ 	}
+-	EINTRLOOP(s, socket(PF_INET, SOCK_STREAM, IPPROTO_TCP));
++	EINTRLOOP(s, socket(sa.ss_family, SOCK_STREAM, 0));
+ 	if (s == -1) goto e;
+ 	EINTRLOOP(rs, fcntl(s, F_SETFL, O_NONBLOCK));
+ 	*sock = s;
+-	memcpy(&sb, &sa, sizeof(struct sockaddr_in));
+-	sb.sin_port = htons(0);
++	memcpy(&sb, &sa, sizeof(sa));
++	switch (sb.ss_family) {
++		case AF_INET:
++			((struct sockaddr_in *) &sb)->sin_port = 0;
++			break;
++		case AF_INET6:
++			((struct sockaddr_in6 *) &sb)->sin6_port = 0;
++			break;
++		default:
++			errno = EAFNOSUPPORT;
++			goto e;
++	}
+ 	EINTRLOOP(rs, bind(s, (struct sockaddr *)(void *)&sb, sizeof sb));
+ 	if (rs) goto e;
+ 	len = sizeof(sa);
+@@ -172,8 +185,7 @@ int get_pasv_socket(struct connection *c
+ 	if (rs) goto e;
+ 	EINTRLOOP(rs, listen(s, 1));
+ 	if (rs) goto e;
+-	memcpy(port, &sa.sin_addr.s_addr, 4);
+-	memcpy(port + 4, &sa.sin_port, 2);
++	memcpy(port, &sa, sizeof(*port));
+ 	return 0;
+ }
+ 
+@@ -306,38 +318,62 @@ static void dns_found(struct connection 
+ 	int s;
+ 	int rs;
+ 	struct conn_info *b = c->newconn;
+-	struct sockaddr_in sa;
++	struct addrinfo hints, *res, *res0;
++	char pbuf[NI_MAXSERV];
+ 	if (state) {
+ 		setcstate(c, S_NO_DNS);
+ 		abort_connection(c);
+ 		return;
+ 	}
+-	if ((s = socket_and_bind(bind_ip_address)) == -1) {
+-		setcstate(c, get_error_from_errno(errno));
++ 	sprintf(pbuf, "%d", b->port);
++ 	pbuf[sizeof(pbuf)-1] = '\0';
++ 	memset(&hints, 0, sizeof(hints));
++ 	hints.ai_family = AF_UNSPEC;
++ 	hints.ai_socktype = SOCK_STREAM;
++ 	if (getaddrinfo(b->addr, pbuf, &hints, &res0)) {
++ 		setcstate(c, get_error_from_errno(EADDRNOTAVAIL));
+ 		retry_connection(c);
+ 		return;
+ 	}
+-	EINTRLOOP(rs, fcntl(s, F_SETFL, O_NONBLOCK));
+-	*b->sock = s;
+-	memset(&sa, 0, sizeof(struct sockaddr_in));
+-	sa.sin_family = AF_INET;
+-	sa.sin_addr.s_addr = b->addr;
+-	sa.sin_port = htons(b->port);
+-	EINTRLOOP(rs, connect(s, (struct sockaddr *)(void *)&sa, sizeof sa));
+-	if (rs) {
+-		if (errno != EALREADY && errno != EINPROGRESS) {
++ 
++ 	for (res = res0; res != NULL; res = res->ai_next) {
++		s = socket_and_bind(bind_ip_address, res->ai_family, res->ai_socktype,
++				res->ai_protocol);
++		if (-1 == s) {
++			if (res->ai_next) {
++				continue;
++			} else {
++				setcstate(c, get_error_from_errno(errno));
++				retry_connection(c);
++				freeaddrinfo(res0);
++				return;
++			}
++		}
++		EINTRLOOP(rs, fcntl(s, F_SETFL, O_NONBLOCK));
++		*b->sock = s;
++		EINTRLOOP(rs, connect(s, res->ai_addr, res->ai_addrlen));
++		if (rs) {
++			if (res->ai_next) {
++				close(s);
++				continue;
++			} else if (errno != EALREADY && errno != EINPROGRESS) {
+ #ifdef BEOS
+-			if (errno == EWOULDBLOCK) errno = ETIMEDOUT;
++				if (errno == EWOULDBLOCK) errno = ETIMEDOUT;
+ #endif
+-			setcstate(c, get_error_from_errno(errno));
+-			retry_connection(c);
+-			return;
++				setcstate(c, get_error_from_errno(errno));
++				retry_connection(c);
++				freeaddrinfo(res0);
++				return;
++			}
++			set_handlers(s, NULL, (void(*)(void *))connected,
++					(void(*)(void *))exception, c);
++			setcstate(c, S_CONN);
++		} else {
++			connected(c);
+ 		}
+-		set_handlers(s, NULL, (void(*)(void *))connected, (void(*)(void *))exception, c);
+-		setcstate(c, S_CONN);
+-	} else {
+-		connected(c);
++		break;
+ 	}
++	freeaddrinfo(res0);
+ }
+ 
+ static void connected(struct connection *c)
+@@ -581,3 +617,7 @@ void kill_buffer_data(struct read_buffer
+ 	memmove(rb->data, rb->data + n, rb->len - n);
+ 	rb->len -= n;
+ }
++
++/*
++ * vim: noexpandtab
++ */
+diff -urNp links-2.6-orig/default.c links-2.6/default.c
+--- links-2.6-orig/default.c	2012-04-04 23:27:07.000000000 +0200
++++ links-2.6/default.c	2012-06-08 09:44:30.288941454 +0200
+@@ -1256,20 +1256,20 @@ static unsigned char *gen_cmd(struct opt
+ 
+ static unsigned char *lookup_cmd(struct option *o, unsigned char ***argv, int *argc)
+ {
+-	ip__address addr;
+-	unsigned char *p = (unsigned char *)&addr;
++	char addr[NI_MAXHOST];
++	int retval;
+ 	if (!*argc) return "Parameter expected";
+ 	if (*argc >= 2) return "Too many parameters";
+ 	(*argv)++; (*argc)--;
+-	if (do_real_lookup(*(*argv - 1), &addr)) {
+-#if defined(HAVE_GETHOSTBYNAME) && defined(HAVE_HERROR)
+-		herror("error");
++	if ((retval = do_real_lookup(*(*argv - 1), addr))) {
++#ifdef HAVE_GAI_STRERROR
++		fprintf(stderr, "error: host not found: %s\n", gai_strerror(retval));
+ #else
+ 		fprintf(stderr, "error: host not found\n");
+ #endif
+ 		return "";
+ 	}
+-	printf("%d.%d.%d.%d\n", (int)p[0], (int)p[1], (int)p[2], (int)p[3]);
+++	printf("%s\n", addr);
+ 	fflush(stdout);
+ 	return "";
+ }
+@@ -1505,7 +1505,7 @@ fprintf(stdout, "%s%s%s%s%s%s\n",
+ "  Password for anonymous ftp access.\n"
+ "\n"
+ " -ftp.use-passive <0>/<1>\n"
+-"  Use ftp PASV command to bypass firewalls.\n"
++"  Use ftp EPSV command to bypass firewalls.\n"
+ "\n"
+ " -ftp.fast <0>/<1>\n"
+ "  Send more ftp commands simultaneously. Faster response when\n"
+@@ -1767,7 +1767,7 @@ int max_connections_to_host = 8;
+ int max_tries = 3;
+ int receive_timeout = 120;
+ int unrestartable_receive_timeout = 600;
+-unsigned char bind_ip_address[16] = "";
++unsigned char bind_ip_address[NI_MAXHOST] = "";
+ int async_lookup = 1;
+ int download_utime = 0;
+ 
+@@ -1861,7 +1861,7 @@ static struct option links_options[] = {
+ 	{1, gen_cmd, num_rd, num_wr, 0, 16, &max_tries, "retries", "retries"},
+ 	{1, gen_cmd, num_rd, num_wr, 1, 9999, &receive_timeout, "receive_timeout", "receive-timeout"},
+ 	{1, gen_cmd, num_rd, num_wr, 1, 9999, &unrestartable_receive_timeout, "unrestartable_receive_timeout", "unrestartable-receive-timeout"},
+-	{1, gen_cmd, ip_rd, str_wr, 0, 16, bind_ip_address, "bind_address", "bind-address"},
++	{1, gen_cmd, ip_rd, str_wr, 0, NI_MAXHOST, bind_ip_address, "bind_address", "bind-address"},
+ 	{1, gen_cmd, num_rd, num_wr, 0, 1, &async_lookup, "async_dns", "async-dns"},
+ 	{1, gen_cmd, num_rd, num_wr, 0, 1, &download_utime, "download_utime", "download-utime"},
+ 	{1, gen_cmd, num_rd, num_wr, 0, 999, &max_format_cache_entries, "format_cache_size", "format-cache-size"},
+@@ -2067,3 +2067,6 @@ void save_url_history(void)
+ 	return;
+ }
+ 
++/*
++ * vim: noexpandtab
++ */
+diff -urNp links-2.6-orig/dns.c links-2.6/dns.c
+--- links-2.6-orig/dns.c	2012-03-30 06:26:00.000000000 +0200
++++ links-2.6/dns.c	2012-06-08 09:44:30.291914828 +0200
+@@ -5,15 +5,11 @@
+ 
+ #include "links.h"
+ 
+-#if defined(HAVE_GETHOSTBYNAME_BUG) || !defined(HAVE_GETHOSTBYNAME)
+-#define EXTERNAL_LOOKUP
+-#endif
+-
+ struct dnsentry {
+ 	struct dnsentry *next;
+ 	struct dnsentry *prev;
+ 	ttime get_time;
+-	ip__address addr;
++	char addr[NI_MAXHOST];
+ 	unsigned char name[1];
+ };
+ 
+@@ -30,138 +26,67 @@ struct dnsquery {
+ 	void (*xfn)(struct dnsquery *, int);
+ 	int h;
+ 	struct dnsquery **s;
+-	ip__address *addr;
++	char *addr;
+ 	unsigned char name[1];
+ };
+ 
+ static struct list_head dns_cache = {&dns_cache, &dns_cache};
+ 
+-static int get_addr_byte(unsigned char **ptr, unsigned char *res, unsigned char stp)
+-{
+-	unsigned u = 0;
+-	if (!(**ptr >= '0' && **ptr <= '9')) return -1;
+-	while (**ptr >= '0' && **ptr <= '9') {
+-		u = u * 10 + **ptr - '0';
+-		if (u >= 256) return -1;
+-		(*ptr)++;
++/* Convert numeric adress to socket address.
++ * @name is the ASCII represantion of the numeric address.
++ * @host is prealocated socket address. Pass NULL if you do not care.
++ * Return 0 if the address is valid, otherwise -1. */
++int numeric_ip_address(unsigned char *name, struct sockaddr_storage *host)
++{
++	struct addrinfo hints, *res;
++
++	memset(&hints, 0, sizeof(hints));
++	hints.ai_family = AF_UNSPEC;
++	hints.ai_socktype = SOCK_STREAM;
++	hints.ai_flags = AI_NUMERICHOST;
++
++	if (getaddrinfo(name, NULL, &hints, &res)) return -1;
++	if (host) {
++		memcpy(host, res->ai_addr, res->ai_addrlen);
+ 	}
+-	if (stp != 255 && **ptr != stp) return -1;
+-	(*ptr)++;
+-	*res = u;
+-	return 0;
+-}
+-
+-int numeric_ip_address(unsigned char *name, ip__address *host)
+-{
+-	ip__address dummy;
+-	if (!host) host = &dummy;
+-	if (get_addr_byte(&name, ((unsigned char *)host + 0), '.')) return -1;
+-	if (get_addr_byte(&name, ((unsigned char *)host + 1), '.')) return -1;
+-	if (get_addr_byte(&name, ((unsigned char *)host + 2), '.')) return -1;
+-	if (get_addr_byte(&name, ((unsigned char *)host + 3), 0)) return -1;
++	freeaddrinfo(res);
+ 	return 0;
+ }
+ 
+-#ifdef EXTERNAL_LOOKUP
+-
+-static int do_external_lookup(unsigned char *name, ip__address *host)
+-{
+-	unsigned char buffer[1024];
+-	unsigned char sink[16];
+-	int rd;
+-	int pi[2];
+-	pid_t f;
+-	unsigned char *n;
+-	int rs;
+-	if (c_pipe(pi) == -1)
+-		return -1;
+-	EINTRLOOP(f, fork());
+-	if (f == -1) {
+-		EINTRLOOP(rs, close(pi[0]));
+-		EINTRLOOP(rs, close(pi[1]));
+-		return -1;
+-	}
+-	if (!f) {
+-		EINTRLOOP(rs, close(pi[0]));
+-		EINTRLOOP(rs, dup2(pi[1], 1));
+-		if (rs == -1) _exit(1);
+-		EINTRLOOP(rs, dup2(pi[1], 2));
+-		if (rs == -1) _exit(1);
+-		EINTRLOOP(rs, close(pi[1]));
+-		EINTRLOOP(rs, execlp("host", "host", name, NULL));
+-		EINTRLOOP(rs, execl("/usr/sbin/host", "host", name, NULL));
+-		_exit(1);
+-	}
+-	EINTRLOOP(rs, close(pi[1]));
+-	rd = hard_read(pi[0], buffer, sizeof buffer - 1);
+-	if (rd >= 0) buffer[rd] = 0;
+-	if (rd > 0) {
+-		while (hard_read(pi[0], sink, sizeof sink) > 0);
+-	}
+-	EINTRLOOP(rs, close(pi[0]));
+-	/* Don't wait for the process, we already have sigchld handler that
+-	 * does cleanup.
+-	 * waitpid(f, NULL, 0); */
+-	if (rd < 0) return -1;
+-	/*fprintf(stderr, "query: '%s', result: %s\n", name, buffer);*/
+-	while ((n = strstr(buffer, name))) {
+-		memset(n, '-', strlen(name));
+-	}
+-	for (n = buffer; n < buffer + rd; n++) {
+-		if (*n >= '0' && *n <= '9') {
+-			if (get_addr_byte(&n, ((unsigned char *)host + 0), '.')) goto skip_addr;
+-			if (get_addr_byte(&n, ((unsigned char *)host + 1), '.')) goto skip_addr;
+-			if (get_addr_byte(&n, ((unsigned char *)host + 2), '.')) goto skip_addr;
+-			if (get_addr_byte(&n, ((unsigned char *)host + 3), 255)) goto skip_addr;
+-			return 0;
+-skip_addr:
+-			if (n >= buffer + rd) break;
+-		}
+-	}
+-	return -1;
+-}
+-
+-#endif
+-
+-int do_real_lookup(unsigned char *name, ip__address *host)
++/* Resolve @name and return its first IP address as ASCII representation in
++ * @host which must be pre-allocated to NI_MAXHOST bytes.
++ * Return getnameinfo(3) error code, or zero on success. */
++/* TODO: Support multi-homed domain names, link scope addresses. */
++int do_real_lookup(unsigned char *name, char *host)
+ {
+ 	unsigned char *n;
+-	struct hostent *hst;
+-	if (!*name) return -1;
+-	for (n = name; *n; n++) if (*n != '.' && (*n < '0' || *n > '9')) goto nogethostbyaddr;
+-	if (!numeric_ip_address(name, host)) return 0;
+-#ifdef HAVE_GETHOSTBYADDR
+-	if (!(hst = gethostbyaddr(name, strlen(name), AF_INET)))
+-#endif
+-	{
+-		nogethostbyaddr:
+-#ifdef HAVE_GETHOSTBYNAME
+-		if (!(hst = gethostbyname(name)))
+-#endif
+-		{
+-#ifdef EXTERNAL_LOOKUP
+-			return do_external_lookup(name, host);
+-#endif
+-			return -1;
+-		}
+-	}
+-	memcpy(host, hst->h_addr_list[0], sizeof(ip__address));
+-	return 0;
++	int retval;
++	struct addrinfo hints, *res;
++	char hbuf[NI_MAXHOST];
++	if (!*name) return EAI_NONAME;
++	memset(&hints, 0, sizeof(hints));
++	hints.ai_family = AF_UNSPEC;
++	hints.ai_socktype = SOCK_STREAM;
++	if ((retval = getaddrinfo(name, NULL, &hints, &res))) return retval;
++	retval = getnameinfo(res->ai_addr, res->ai_addrlen, host, NI_MAXHOST,
++	        NULL, 0, NI_NUMERICHOST);
++	freeaddrinfo(res);
++	return retval;
+ }
+ 
+ #ifndef NO_ASYNC_LOOKUP
+ static void lookup_fn(unsigned char *name, int h)
+ {
+-	ip__address host;
+-	if (do_real_lookup(name, &host)) return;
+-	hard_write(h, (unsigned char *)&host, sizeof(ip__address));
++	char host[NI_MAXHOST];
++	if (do_real_lookup(name, host)) return;
++	hard_write(h, (unsigned char *)host, NI_MAXHOST);
+ }
+ 
+ static void end_real_lookup(struct dnsquery *q)
+ {
+ 	int r = 1;
+ 	int rs;
+-	if (!q->addr || hard_read(q->h, (unsigned char *)q->addr, sizeof(ip__address)) != sizeof(ip__address)) goto end;
++	if (!q->addr || hard_read(q->h, (unsigned char *)q->addr, NI_MAXHOST) != NI_MAXHOST) goto end;
+ 	r = 0;
+ 
+ 	end:
+@@ -189,7 +114,7 @@ static int do_lookup(struct dnsquery *q,
+ #ifndef NO_ASYNC_LOOKUP
+ 		sync_lookup:
+ #endif
+-		r = do_real_lookup(q->name, q->addr);
++		r = -!!do_real_lookup(q->name, q->addr);
+ 		q->xfn(q, r);
+ 		return 0;
+ #ifndef NO_ASYNC_LOOKUP
+@@ -252,7 +177,7 @@ static void end_dns_lookup(struct dnsque
+ 	}
+ 	if (!find_in_dns_cache(q->name, &dnsentry)) {
+ 		if (a) {
+-			memcpy(q->addr, &dnsentry->addr, sizeof(ip__address));
++			memcpy(q->addr, dnsentry->addr, NI_MAXHOST);
+ 			a = 0;
+ 			goto e;
+ 		}
+@@ -262,7 +187,7 @@ static void end_dns_lookup(struct dnsque
+ 	if (a) goto e;
+ 	dnsentry = mem_alloc(sizeof(struct dnsentry) + strlen(q->name) + 1);
+ 	strcpy(dnsentry->name, q->name);
+-	memcpy(&dnsentry->addr, q->addr, sizeof(ip__address));
++	memcpy(dnsentry->addr, q->addr, NI_MAXHOST);
+ 	dnsentry->get_time = get_time();
+ 	add_to_list(dns_cache, dnsentry);
+ 	e:
+@@ -273,7 +198,7 @@ static void end_dns_lookup(struct dnsque
+ 	fn(data, a);
+ }
+ 
+-int find_host_no_cache(unsigned char *name, ip__address *addr, void **qp, void (*fn)(void *, int), void *data)
++int find_host_no_cache(unsigned char *name, char *addr, void **qp, void (*fn)(void *, int), void *data)
+ {
+ 	struct dnsquery *q;
+ 	retry:
+@@ -293,13 +218,13 @@ int find_host_no_cache(unsigned char *na
+ 	return do_queued_lookup(q);
+ }
+ 
+-int find_host(unsigned char *name, ip__address *addr, void **qp, void (*fn)(void *, int), void *data)
++int find_host(unsigned char *name, char *addr, void **qp, void (*fn)(void *, int), void *data)
+ {
+ 	struct dnsentry *dnsentry;
+ 	if (qp) *qp = NULL;
+ 	if (!find_in_dns_cache(name, &dnsentry)) {
+ 		if ((uttime)get_time() - (uttime)dnsentry->get_time > DNS_TIMEOUT) goto timeout;
+-		memcpy(addr, &dnsentry->addr, sizeof(ip__address));
++		memcpy(addr, dnsentry->addr, NI_MAXHOST);
+ 		fn(data, 0);
+ 		return 0;
+ 	}
+@@ -353,3 +278,7 @@ void init_dns(void)
+ {
+ 	register_cache_upcall(shrink_dns_cache, "dns");
+ }
++
++/*
++ * vim: noexpandtab
++ */
+diff -urNp links-2.6-orig/ftp.c links-2.6/ftp.c
+--- links-2.6-orig/ftp.c	2012-03-30 06:26:00.000000000 +0200
++++ links-2.6/ftp.c	2012-06-08 09:44:30.294914833 +0200
+@@ -212,12 +212,45 @@ static void ftp_pass_info(struct connect
+ 	else ftp_send_retr_req(c, S_GETH);
+ }
+ 
++/* Add EPRT FTP command (RFC 2428) to @string with @length parametrized by
++ * @port. Return 0, -1 in case of error (unknown protocol family or similar). */
++static int ftp_add_eprt(unsigned char **string, int *length, const struct sockaddr_storage *port){
++	unsigned char host_string[NI_MAXHOST];
++	unsigned char port_string[NI_MAXSERV];
++	unsigned char *protocol_string;
++	if (getnameinfo((const struct sockaddr *)port, (socklen_t) sizeof(*port),
++			(char *)host_string, NI_MAXHOST, (char *)port_string, NI_MAXSERV,
++			NI_NUMERICHOST|NI_NUMERICSERV)) return -1;
++	switch (port->ss_family) {
++		/* Numbers assigned by RFC 1070. */
++		case AF_INET:
++			protocol_string = "1";
++			break;
++		case AF_INET6:
++			protocol_string = "2";
++			/* If link-local address, do not send local interface name. */
++			char *interface = strchr(host_string, '%');
++			if (interface) *interface = '\0';
++			break;
++		default:
++			return -1;
++	}
++	add_to_str(string, length, "EPRT |");
++	add_to_str(string, length, protocol_string);
++	add_chr_to_str(string, length, '|');
++	add_to_str(string, length, host_string);
++	add_chr_to_str(string, length, '|');
++	add_to_str(string, length, port_string);
++	add_to_str(string, length, "|\r\n");
++	return 0;
++}
++
+ static struct ftp_connection_info *add_file_cmd_to_str(struct connection *c)
+ {
+ 	unsigned char *d = get_url_data(c->url);
+ 	unsigned char *de;
+ 	int del;
+-	unsigned char pc[6];
++	struct sockaddr_storage pc;
+ 	int ps;
+ 	struct ftp_connection_info *inf, *inf2;
+ 	unsigned char *s;
+@@ -238,7 +271,7 @@ static struct ftp_connection_info *add_f
+ 	inf->pasv = ftp_options.passive_ftp;
+ 	if (*c->socks_proxy) inf->pasv = 1;
+ 	c->info = inf;
+-	if (!inf->pasv) if ((ps = get_pasv_socket(c, c->sock1, &c->sock2, pc))) {
++	if (!inf->pasv) if ((ps = get_pasv_socket(c, c->sock1, &c->sock2, &pc))) {
+ 		mem_free(d);
+ 		return NULL;
+ 	}
+@@ -255,21 +288,13 @@ static struct ftp_connection_info *add_f
+ 		inf->pending_commands = 4;
+ 		add_to_str(&s, &l, "TYPE A\r\n");
+ 		if (!inf->pasv) {
+-			add_to_str(&s, &l, "PORT ");
+-			add_num_to_str(&s, &l, pc[0]);
+-			add_chr_to_str(&s, &l, ',');
+-			add_num_to_str(&s, &l, pc[1]);
+-			add_chr_to_str(&s, &l, ',');
+-			add_num_to_str(&s, &l, pc[2]);
+-			add_chr_to_str(&s, &l, ',');
+-			add_num_to_str(&s, &l, pc[3]);
+-			add_chr_to_str(&s, &l, ',');
+-			add_num_to_str(&s, &l, pc[4]);
+-			add_chr_to_str(&s, &l, ',');
+-			add_num_to_str(&s, &l, pc[5]);
+-			add_to_str(&s, &l, "\r\n");
++			if (ftp_add_eprt(&s, &l, &pc)) {
++				mem_free(d);
++				mem_free(s);
++				return NULL;
++			}
+ 		} else {
+-			add_to_str(&s, &l, "PASV\r\n");
++			add_to_str(&s, &l, "EPSV\r\n");
+ 		}
+ 		add_to_str(&s, &l, "CWD /");
+ 		add_bytes_to_str(&s, &l, d, de - d);
+@@ -280,21 +305,13 @@ static struct ftp_connection_info *add_f
+ 		inf->pending_commands = 3;
+ 		add_to_str(&s, &l, "TYPE I\r\n");
+ 		if (!inf->pasv) {
+-			add_to_str(&s, &l, "PORT ");
+-			add_num_to_str(&s, &l, pc[0]);
+-			add_chr_to_str(&s, &l, ',');
+-			add_num_to_str(&s, &l, pc[1]);
+-			add_chr_to_str(&s, &l, ',');
+-			add_num_to_str(&s, &l, pc[2]);
+-			add_chr_to_str(&s, &l, ',');
+-			add_num_to_str(&s, &l, pc[3]);
+-			add_chr_to_str(&s, &l, ',');
+-			add_num_to_str(&s, &l, pc[4]);
+-			add_chr_to_str(&s, &l, ',');
+-			add_num_to_str(&s, &l, pc[5]);
+-			add_to_str(&s, &l, "\r\n");
++			if (ftp_add_eprt(&s, &l, &pc)) {
++				mem_free(d);
++				mem_free(s);
++				return NULL;
++			}
+ 		} else {
+-			add_to_str(&s, &l, "PASV\r\n");
++			add_to_str(&s, &l, "EPSV\r\n");
+ 		}
+ 		if (c->from && c->no_cache < NC_IF_MOD) {
+ 			add_to_str(&s, &l, "REST ");
+@@ -361,38 +378,37 @@ static void ftp_retr_file(struct connect
+ 		}
+ 	}
+ 	if (inf->pending_commands > 1) {
+-		unsigned char pc[6];
++		int port = 0;
+ 		if (inf->pasv && inf->opc - (inf->pending_commands - 1) == 2) {
+ 			int i = 3, j;
+-			while (i < rb->len) {
+-				if (rb->data[i] >= '0' && rb->data[i] <= '9') {
+-					for (j = 0; j < 6; j++) {
+-						int n = 0;
+-						while (rb->data[i] >= '0' && rb->data[i] <= '9') {
+-							n = n * 10 + rb->data[i] - '0';
+-							if (n >= 256) goto no_pasv;
+-							if (++i >= rb->len) goto no_pasv;
+-						}
+-						pc[j] = n;
+-						if (j != 5) {
+-							if (rb->data[i] != ',') goto xa;
+-							if (++i >= rb->len) goto xa;
+-							if (rb->data[i] < '0' || rb->data[i] > '9') {
+-								xa:
+-								if (j != 1) goto no_pasv;
+-								pc[4] = pc[0];
+-								pc[5] = pc[1];
+-								pc[0] = pc[1] = pc[2] = pc[3] = 0;
+-								goto pasv_ok;
+-							}
+-						}
+-					}
+-					goto pasv_ok;
+-				}
++			/* RFC 2428 defines message: <text> (<d><d><d><tcp_port><d>)
++			 * where <d> is one-character delimiter and only port can be
++			 * returned by server. */
++			/* Search from the end (<text> could contain paranthesis) of first
++			 * line in rb->data. */
++			/* Find end of line */
++			while (i < rb->len && rb->data[i] != '\r' && rb->data[i] != '\n')
++				i++;
++			if (i >= rb->len) goto no_pasv;
++			/* Find preceding closing parenthesis */
++			while (i >= 3 && rb->data[i] != ')') i--;
++			if (i < 3) goto no_pasv;
++			/* Delimit port number */
++			j = --i;
++			i--;
++			while (i >= 3 && rb->data[i] != rb->data[j]) i--;
++			if (i < 3) goto no_pasv;
++			i++;
++			/* The port number string is rb->data[i..j-1] */
++			while (i < j) {
++				if (rb->data[i] < '0' || rb->data[i] > '9') goto no_pasv;
++				port = port * 10 + rb->data[i] - '0';
++				if (port < 0) goto no_pasv; /* Integer overflow */
+ 				i++;
+ 			}
++			goto pasv_ok;
+ 			no_pasv:
+-			memset(pc, 0, sizeof pc);
++				port = 0;
+ 			pasv_ok:;
+ 		}
+ 		g = get_ftp_response(c, rb, 0);
+@@ -405,12 +421,12 @@ static void ftp_retr_file(struct connect
+ 			case 2:		/* PORT */
+ 				if (g >= 400) { setcstate(c, S_FTP_PORT); abort_connection(c); return; }
+ 				if (inf->pasv) {
+-					if (!pc[4] && !pc[5]) {
++					if (port == 0) {
+ 						setcstate(c, S_FTP_ERROR);
+ 						retry_connection(c);
+ 						return;
+ 					}
+-					make_connection(c, (pc[4] << 8) + pc[5], &c->sock2, created_data_connection);
++					make_connection(c, port, &c->sock2, created_data_connection);
+ 				}
+ 				goto rep;
+ 			case 3:		/* REST / CWD */
+@@ -790,3 +806,6 @@ static void ftp_end_request(struct conne
+ 	add_keepalive_socket(c, FTP_KEEPALIVE_TIMEOUT);
+ }
+ 
++/*
++ * vim: noexpandtab
++ */
+diff -urNp links-2.6-orig/http.c links-2.6/http.c
+--- links-2.6-orig/http.c	2012-04-04 23:27:07.000000000 +0200
++++ links-2.6/http.c	2012-06-08 09:44:30.297914934 +0200
+@@ -259,7 +259,17 @@ static void http_send_header(struct conn
+ 	else add_to_str(&hdr, &l, " HTTP/1.0\r\n");
+ 	if ((h = get_host_name(host))) {
+ 		add_to_str(&hdr, &l, "Host: ");
+-		add_to_str(&hdr, &l, h);
++		if (strchr(h, ':')) {
++			/* Do not send local interface name.
++			 * TODO: Do it, only if we know this is IPv6 address. */ 
++			char *interface = strchr(h, '%');
++			if (interface) *interface = '\0';
++			add_to_str(&hdr, &l, "[");
++			add_to_str(&hdr, &l, h);
++			add_to_str(&hdr, &l, "]");
++		} else
++			add_to_str(&hdr, &l, h);
++
+ 		mem_free(h);
+ 		if ((h = get_port_str(host))) {
+ 			add_to_str(&hdr, &l, ":");
+@@ -1040,3 +1050,7 @@ static void http_get_header(struct conne
+ 	rb->close = 1;
+ 	read_from_socket(c, c->sock1, rb, http_got_header);
+ }
++
++/*
++ * vim: noexpandtab
++ */
+diff -urNp links-2.6-orig/intl/english.lng links-2.6/intl/english.lng
+--- links-2.6-orig/intl/english.lng	2012-04-09 05:09:02.000000000 +0200
++++ links-2.6/intl/english.lng	2012-06-08 09:46:13.159917776 +0200
+@@ -216,7 +216,7 @@ T_ERROR_OPENING_FILE, "Error opening fil
+ T_BAD_FTP_RESPONSE, "Bad FTP response",
+ T_FTP_SERVICE_UNAVAILABLE, "FTP service unavailable",
+ T_BAD_FTP_LOGIN, "Bad FTP login",
+-T_FTP_PORT_COMMAND_FAILED, "FTP PORT command failed",
++T_FTP_PORT_COMMAND_FAILED, "FTP EPRT command failed",
+ T_FILE_NOT_FOUND, "File not found",
+ T_FTP_FILE_ERROR, "FTP file error",
+ T_UNKNOWN_ERROR, "Unknown error",
+diff -urNp links-2.6-orig/language.inc links-2.6/language.inc
+--- links-2.6-orig/language.inc	2012-04-09 05:09:00.000000000 +0200
++++ links-2.6/language.inc	2012-06-08 09:44:30.312940885 +0200
+@@ -220,7 +220,7 @@ static struct translation translation_en
+   {T_BAD_FTP_RESPONSE, "Bad FTP response" },
+   {T_FTP_SERVICE_UNAVAILABLE, "FTP service unavailable" },
+   {T_BAD_FTP_LOGIN, "Bad FTP login" },
+-  {T_FTP_PORT_COMMAND_FAILED, "FTP PORT command failed" },
++  {T_FTP_PORT_COMMAND_FAILED, "FTP EPRT command failed" },
+   {T_FILE_NOT_FOUND, "File not found" },
+   {T_FTP_FILE_ERROR, "FTP file error" },
+   {T_UNKNOWN_ERROR, "Unknown error" },
+diff -urNp links-2.6-orig/links.1 links-2.6/links.1
+--- links-2.6-orig/links.1	2012-01-24 17:14:37.000000000 +0100
++++ links-2.6/links.1	2012-06-08 09:44:30.316939443 +0200
+@@ -247,7 +247,7 @@ Password for anonymous ftp access.
+ 
+ .TP
+ \f3-ftp.use-passive \f2<0>/<1>\f1
+-Use ftp PASV command to bypass firewalls.
++Use ftp EPSV command to bypass firewalls.
+ 
+ .TP
+ \f3-ftp.fast \f2<0>/<1>\f1
+diff -urNp links-2.6-orig/links.h links-2.6/links.h
+--- links-2.6-orig/links.h	2012-04-09 05:09:00.000000000 +0200
++++ links-2.6/links.h	2012-06-08 09:44:30.320942363 +0200
+@@ -727,12 +727,10 @@ void set_sigcld(void);
+ 
+ /* dns.c */
+ 
+-typedef unsigned ip__address;
+-
+-int numeric_ip_address(unsigned char *name, ip__address *host);
+-int do_real_lookup(unsigned char *, ip__address *);
+-int find_host(unsigned char *, ip__address *, void **, void (*)(void *, int), void *);
+-int find_host_no_cache(unsigned char *, ip__address *, void **, void (*)(void *, int), void *);
++int numeric_ip_address(unsigned char *name, struct sockaddr_storage *host);
++int do_real_lookup(unsigned char *, char *);
++int find_host(unsigned char *, char *, void **, void (*)(void *, int), void *);
++int find_host_no_cache(unsigned char *, char *, void **, void (*)(void *, int), void *);
+ void kill_dns_request(void **);
+ unsigned long dns_info(int type);
+ void init_dns(void);
+@@ -1026,10 +1024,10 @@ struct read_buffer {
+ 	unsigned char data[1];
+ };
+ 
+-int socket_and_bind(unsigned char *address);
++int socket_and_bind(unsigned char *address, int family, int type, int protocol);
+ void close_socket(int *);
+ void make_connection(struct connection *, int, int *, void (*)(struct connection *));
+-int get_pasv_socket(struct connection *, int, int *, unsigned char *);
++int get_pasv_socket(struct connection *, int, int *, struct sockaddr_storage *);
+ void write_to_socket(struct connection *, int, unsigned char *, int, void (*)(struct connection *));
+ struct read_buffer *alloc_read_buffer(struct connection *c);
+ void read_from_socket(struct connection *, int, struct read_buffer *, void (*)(struct connection *, struct read_buffer *));
+@@ -4133,7 +4131,7 @@ extern int max_connections_to_host;
+ extern int max_tries;
+ extern int receive_timeout;
+ extern int unrestartable_receive_timeout;
+-extern unsigned char bind_ip_address[16];
++extern unsigned char bind_ip_address[NI_MAXHOST];
+ extern int async_lookup;
+ extern int download_utime;
+ 
+diff -urNp links-2.6-orig/url.c links-2.6/url.c
+--- links-2.6-orig/url.c	2012-01-24 17:14:38.000000000 +0100
++++ links-2.6/url.c	2012-06-08 09:44:30.323940116 +0200
+@@ -110,11 +110,22 @@ int parse_url(unsigned char *url, int *p
+ 			if (palen) *palen = q - pp - 1;
+ 		}
+ 		p = q + 1;
+-	} 
+-	q = p + strcspn(p, ":/?");
+-	if (!*q && protocols[a].need_slash_after_host) return -1;
++	}
++	if (*p == '[') {
++		q = strchr(++p, ']');
++		if (!q++ || (*q != ':' && *q != '/' && *q != '?' && *q != '\0')){
++			/* Missing closing bracket or garbage after that */
++			return -1;
++		}
++		if (holen) *holen = q - p - 1;
++	} else {
++	    q = p + strcspn(p, ":/?");
++		if (holen) *holen = q - p;
++	}
+ 	if (host) *host = p;
+-	if (holen) *holen = q - p;
++	/* XXX: the q needs to point after host including ']' here.
++	 * Thus *holen computation is specific to every upper if-branche */
++	if (!*q && protocols[a].need_slash_after_host) return -1;
+ 	if (*q == ':') {
+ 		unsigned char *pp = q + strcspn(q, "/");
+ 		int cc;
+@@ -148,6 +159,10 @@ unsigned char *get_host_and_pass(unsigne
+ 	int hl, pl;
+ 	if (parse_url(url, NULL, &u, NULL, NULL, NULL, &h, &hl, &p, &pl, NULL, NULL, NULL)) return NULL;
+ 	z = u ? u : h;
++	/* XXX: This will omit opening bracket in case of IPv6 numeric hostname
++	 * Now, the output string is used only as a key into a list, so it
++	 * doesn't matter. When usage changes, we need to build properly balanced
++	 * substring. */
+ 	k = p ? p + pl : h + hl;
+ 	return memacpy(z, k - z);
+ }
+@@ -573,3 +588,6 @@ void add_conv_str(unsigned char **s, int
+ 	}
+ }
+ 
++/* 
++ * vim: noexpandtab
++ */


More information about the scm-commits mailing list