summaryrefslogtreecommitdiffstats
path: root/usr.bin/ftp
diff options
context:
space:
mode:
authorshin <shin@FreeBSD.org>2000-01-27 09:28:38 +0000
committershin <shin@FreeBSD.org>2000-01-27 09:28:38 +0000
commitce15efb7c04858f00b57c16093d4a3043809048e (patch)
tree8b3d00f78a4a5a34cc3b17e29c28b4472d93a35c /usr.bin/ftp
parentdcbae417f8f4365a5eea807290162acd308b720d (diff)
downloadFreeBSD-src-ce15efb7c04858f00b57c16093d4a3043809048e.zip
FreeBSD-src-ce15efb7c04858f00b57c16093d4a3043809048e.tar.gz
another tcp apps IPv6 updates.(should be make world safe)
ftp, telnet, ftpd, faithd also telnet related sync with crypto, secure, kerberosIV Obtained from: KAME project
Diffstat (limited to 'usr.bin/ftp')
-rw-r--r--usr.bin/ftp/Makefile1
-rw-r--r--usr.bin/ftp/extern.h2
-rw-r--r--usr.bin/ftp/fetch.c107
-rw-r--r--usr.bin/ftp/ftp.122
-rw-r--r--usr.bin/ftp/ftp.c416
-rw-r--r--usr.bin/ftp/ftp_var.h11
-rw-r--r--usr.bin/ftp/main.c69
-rw-r--r--usr.bin/ftp/util.c17
8 files changed, 463 insertions, 182 deletions
diff --git a/usr.bin/ftp/Makefile b/usr.bin/ftp/Makefile
index bbd82e2..b5a59cc 100644
--- a/usr.bin/ftp/Makefile
+++ b/usr.bin/ftp/Makefile
@@ -10,6 +10,7 @@ PROG= ftp
SRCS= cmds.c cmdtab.c complete.c domacro.c fetch.c ftp.c main.c ruserpass.c \
util.c
+CFLAGS+=-DINET6 -g
LDADD+= -ledit -ltermcap
DPADD+= ${LIBEDIT} ${LIBTERMCAP}
diff --git a/usr.bin/ftp/extern.h b/usr.bin/ftp/extern.h
index a8ac97b..7841f7b 100644
--- a/usr.bin/ftp/extern.h
+++ b/usr.bin/ftp/extern.h
@@ -73,7 +73,7 @@ int getreply __P((int));
int globulize __P((char **));
char *gunique __P((const char *));
void help __P((int, char **));
-char *hookup __P((const char *, int));
+char *hookup __P((const char *, char *));
void idle __P((int, char **));
int initconn __P((void));
void intr __P((void));
diff --git a/usr.bin/ftp/fetch.c b/usr.bin/ftp/fetch.c
index 1d73c0f..62b64e9 100644
--- a/usr.bin/ftp/fetch.c
+++ b/usr.bin/ftp/fetch.c
@@ -57,6 +57,7 @@ __RCSID_SOURCE("$NetBSD: fetch.c,v 1.16.2.1 1997/11/18 01:00:22 mellon Exp $");
#include <ctype.h>
#include <err.h>
+#include <errno.h>
#include <netdb.h>
#include <fcntl.h>
#include <signal.h>
@@ -67,6 +68,11 @@ __RCSID_SOURCE("$NetBSD: fetch.c,v 1.16.2.1 1997/11/18 01:00:22 mellon Exp $");
#include "ftp_var.h"
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
static int url_get __P((const char *, const char *));
void aborthttp __P((int));
@@ -91,9 +97,11 @@ url_get(origline, proxyenv)
const char *origline;
const char *proxyenv;
{
- struct sockaddr_in sin;
+ struct addrinfo hints;
+ struct addrinfo *res;
+ char nameinfo[2 * INET6_ADDRSTRLEN + 1];
int i, out, isftpurl;
- u_int16_t port;
+ char *port;
volatile int s;
size_t len;
char c, *cp, *ep, *portnum, *path, buf[4096];
@@ -101,6 +109,7 @@ url_get(origline, proxyenv)
char *line, *proxy, *host;
volatile sig_t oldintr;
off_t hashbytes;
+ int error;
s = -1;
proxy = NULL;
@@ -172,68 +181,69 @@ url_get(origline, proxyenv)
path = line;
}
- portnum = strchr(host, ':'); /* find portnum */
- if (portnum != NULL)
+ if (*host == '[' && (portnum = strrchr(host, ']'))) { /* IPv6 URL */
*portnum++ = '\0';
-
+ host++;
+ if (*portnum == ':')
+ portnum++;
+ else
+ portnum = NULL;
+ } else {
+ portnum = strrchr(host, ':'); /* find portnum */
+ if (portnum != NULL)
+ *portnum++ = '\0';
+ }
+
if (debug)
printf("host %s, port %s, path %s, save as %s.\n",
host, portnum, path, savefile);
- memset(&sin, 0, sizeof(sin));
- sin.sin_family = AF_INET;
-
- if (isdigit((unsigned char)host[0])) {
- if (inet_aton(host, &sin.sin_addr) == 0) {
- warnx("Invalid IP address: %s", host);
- goto cleanup_url_get;
- }
- } else {
- struct hostent *hp;
-
- hp = gethostbyname(host);
- if (hp == NULL) {
- warnx("%s: %s", host, hstrerror(h_errno));
- goto cleanup_url_get;
- }
- if (hp->h_addrtype != AF_INET) {
- warnx("%s: not an Internet address?", host);
- goto cleanup_url_get;
- }
- memcpy(&sin.sin_addr, hp->h_addr, hp->h_length);
- }
-
if (! EMPTYSTRING(portnum)) {
- char *ep;
- long nport;
-
- nport = strtol(portnum, &ep, 10);
- if (nport < 1 || nport > 0xffff || *ep != '\0') {
- warnx("Invalid port: %s", portnum);
- goto cleanup_url_get;
- }
- port = htons(nport);
+ port = portnum;
} else
port = httpport;
- sin.sin_port = port;
- s = socket(AF_INET, SOCK_STREAM, 0);
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(host, port, &hints, &res);
+ if (error) {
+ warnx("%s: %s", host, gai_strerror(error));
+ if (error = EAI_SYSTEM)
+ warnx("%s: %s", host, strerror(errno));
+ goto cleanup_url_get;
+ }
+
+ while (1)
+ {
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (s == -1) {
warn("Can't create socket");
goto cleanup_url_get;
}
if (dobind && bind(s, (struct sockaddr *)&bindto,
- sizeof(bindto)) == -1) {
- warn("Can't bind to %s", inet_ntoa(bindto.sin_addr));
+ ((struct sockaddr *)&bindto)->sa_len) == -1) {
+ getnameinfo((struct sockaddr *)&bindto,
+ ((struct sockaddr *)&bindto)->sa_len,
+ nameinfo, sizeof(nameinfo), NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ /* XXX check error? */
+ warn("Can't bind to %s", nameinfo);
goto cleanup_url_get;
}
- if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
- warn("Can't connect to %s", host);
+ if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
+ close(s);
+ res = res->ai_next;
+ if (res)
+ continue;
goto cleanup_url_get;
}
+ break;
+ }
+
/*
* Construct and send the request. We're expecting a return
* status of "200". Proxy requests don't want leading /.
@@ -645,3 +655,14 @@ parsed_url:
disconnect(0, NULL);
return (rval);
}
+
+int
+isurl(p)
+ const char *p;
+{
+ if (strncasecmp(p, FTP_URL, sizeof(FTP_URL) - 1) == 0
+ || strncasecmp(p, HTTP_URL, sizeof(HTTP_URL) - 1) == 0) {
+ return 1;
+ }
+ return 0;
+}
diff --git a/usr.bin/ftp/ftp.1 b/usr.bin/ftp/ftp.1
index 59b371f..a112709 100644
--- a/usr.bin/ftp/ftp.1
+++ b/usr.bin/ftp/ftp.1
@@ -34,7 +34,7 @@
.\"
.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94
.\"
-.Dd August 18, 1997
+.Dd January 27, 2000
.Dt FTP 1
.Os BSD 4.2
.Sh NAME
@@ -61,6 +61,7 @@ is the user interface to the
standard File Transfer Protocol.
The program allows a user to transfer files to and from a
remote network site.
+The version supports IPv6 (Internet protocol version 6), as well as IPv4.
.Pp
The latter three usage formats will fetch a file using either the
HTTP or FTP protocols into the current directory.
@@ -682,7 +683,18 @@ through a gateway router or host that controls the directionality of
traffic.
(Note that though ftp servers are required to support the
.Dv PASV
-command by RFC 1123, some do not.)
+command by RFC 1123, some do not.
+Please note that if you are connecting to IPv6 ftp server,
+the program will use
+.Dv EPSV/EPRT
+pair and
+.Dv LPSV/LPRT
+pair,
+instead of
+.Dv PASV
+and
+.Dv PORT .
+The meaning is the same.)
.It Ic preserve
Toggle preservation of modification times on retrieved files.
.It Ic progress
@@ -1402,6 +1414,8 @@ fetching of files, ftp and http URLs, and modification time
preservation were implemented in
.Nx 1.3
by Luke Mewburn, with assistance from Jason Thorpe.
+.Pp
+IPv6 support was added by WIDE/KAME Project.
.Sh BUGS
Correct execution of many commands depends upon proper behavior
by the remote server.
@@ -1416,3 +1430,7 @@ to and from
.Bx 4.2
servers using the ascii type.
Avoid this problem by using the binary image type.
+.Pp
+Proxying functionalities, such as
+.Ev ftp_proxy ,
+may not work for IPv6 connection.
diff --git a/usr.bin/ftp/ftp.c b/usr.bin/ftp/ftp.c
index d2edd01..3c7da3f 100644
--- a/usr.bin/ftp/ftp.c
+++ b/usr.bin/ftp/ftp.c
@@ -71,68 +71,93 @@ __RCSID_SOURCE("$NetBSD: ftp.c,v 1.29.2.1 1997/11/18 01:01:04 mellon Exp $");
#include "ftp_var.h"
-struct sockaddr_in hisctladdr;
-struct sockaddr_in data_addr;
+/* wrapper for KAME-special getnameinfo() */
+#ifndef NI_WITHSCOPEID
+#define NI_WITHSCOPEID 0
+#endif
+
+extern int h_errno;
+
int data = -1;
int abrtflag = 0;
jmp_buf ptabort;
int ptabflg;
int ptflag = 0;
-struct sockaddr_in myctladdr;
-
FILE *cin, *cout;
+union sockunion {
+ struct sockinet {
+ u_char si_len;
+ u_char si_family;
+ u_short si_port;
+ } su_si;
+ struct sockaddr_in su_sin;
+ struct sockaddr_in6 su_sin6;
+};
+#define su_len su_si.si_len
+#define su_family su_si.si_family
+#define su_port su_si.si_port
+
+union sockunion myctladdr, hisctladdr, data_addr;
+
char *
hookup(host, port)
const char *host;
- int port;
+ char *port;
{
- struct hostent *hp = NULL;
- int s, len, tos;
+ int s, len, tos, error;
+ struct addrinfo hints, *res, *res0;
static char hostnamebuf[MAXHOSTNAMELEN];
- memset((void *)&hisctladdr, 0, sizeof(hisctladdr));
- if (inet_aton(host, &hisctladdr.sin_addr) != 0) {
- hisctladdr.sin_family = AF_INET;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_CANONNAME;
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 0;
+ error = getaddrinfo(host, port, &hints, &res0);
+ if (error) {
+ warnx("%s: %s", host, gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ warnx("%s: %s", host, strerror(errno));
+ code = -1;
+ return (0);
+ }
+
+ res = res0;
+ if (res->ai_canonname)
+ hostname = res->ai_canonname;
+ else {
(void) strncpy(hostnamebuf, host, sizeof(hostnamebuf));
- } else {
- hp = gethostbyname(host);
- if (hp == NULL) {
- warnx("%s: %s", host, hstrerror(h_errno));
- code = -1;
- return ((char *) 0);
- }
- hisctladdr.sin_family = hp->h_addrtype;
- memcpy(&hisctladdr.sin_addr, hp->h_addr_list[0],
- MIN(hp->h_length,sizeof(hisctladdr.sin_addr)));
- (void) strncpy(hostnamebuf, hp->h_name, sizeof(hostnamebuf));
+ hostname = hostnamebuf;
}
- hostnamebuf[sizeof(hostnamebuf) - 1] = '\0';
- hostname = hostnamebuf;
- hisctladdr.sin_port = port;
while (1) {
- if ((s = socket(hisctladdr.sin_family, SOCK_STREAM, 0)) == -1) {
+ s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (s < 0) {
warn("socket");
code = -1;
return (0);
}
- if (dobind && bind(s, (struct sockaddr *)&bindto,
- sizeof(bindto)) == -1) {
+ if (dobind &&
+ bind(s, (struct sockaddr *)&bindto,
+ ((struct sockaddr *)&bindto)->sa_len) == -1) {
warn("bind");
- code = -1;
- goto bad;
+ goto next;
}
- if (connect(s, (struct sockaddr *)&hisctladdr,
- sizeof(hisctladdr)) == 0)
+ if (connect(s, res->ai_addr, res->ai_addrlen) == 0)
break;
- if (hp && *++hp->h_addr_list) {
- warnc(errno, "connect to address %s",
- inet_ntoa(hisctladdr.sin_addr));
- memcpy(&hisctladdr.sin_addr, hp->h_addr_list[0],
- MIN(hp->h_length,sizeof(hisctladdr.sin_addr)));
- printf("Trying %s...\n",
- inet_ntoa(hisctladdr.sin_addr));
+ next:
+ if (res->ai_next) {
+ char hname[INET6_ADDRSTRLEN];
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ hname, sizeof(hname) - 1, NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ warn("connect to address %s", hname);
+ res = res->ai_next;
+ getnameinfo(res->ai_addr, res->ai_addrlen,
+ hname, sizeof(hname) - 1, NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID);
+ printf("Trying %s...\n", hname);
(void)close(s);
continue;
}
@@ -140,6 +165,7 @@ hookup(host, port)
code = -1;
goto bad;
}
+ memcpy(&hisctladdr, res->ai_addr, res->ai_addrlen);
len = sizeof(myctladdr);
if (getsockname(s, (struct sockaddr *)&myctladdr, &len) < 0) {
warn("getsockname");
@@ -147,9 +173,12 @@ hookup(host, port)
goto bad;
}
#ifdef IP_TOS
- tos = IPTOS_LOWDELAY;
+ if (myctladdr.su_family == AF_INET)
+ {
+ tos = IPTOS_LOWDELAY;
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
+ }
#endif
cin = fdopen(s, "r");
cout = fdopen(s, "w");
@@ -324,11 +353,25 @@ getreply(expecteof)
}
if (dig < 4 && isdigit((unsigned char)c))
code = code * 10 + (c - '0');
- if (!pflag && code == 227)
- pflag = 1;
- if (dig > 4 && pflag == 1 && isdigit((unsigned char)c))
+ switch (pflag) {
+ case 0:
+ if (code == 227 || code == 228) {
+ /* result for PASV/LPSV */
+ pflag = 1;
+ /* fall through */
+ } else if (code == 229) {
+ /* result for EPSV */
+ pflag = 1;
+ pflag = 100;
+ break;
+ } else
+ break;
+ case 1:
+ if (!(dig > 4 && isdigit((unsigned char)c)))
+ break;
pflag = 2;
- if (pflag == 2) {
+ /* fall through */
+ case 2:
if (c != '\r' && c != ')' &&
pt < &pasv[sizeof(pasv)-1])
*pt++ = c;
@@ -336,6 +379,11 @@ getreply(expecteof)
*pt = '\0';
pflag = 3;
}
+ break;
+ case 100:
+ if (dig > 4 && c == '(')
+ pflag = 2;
+ break;
}
if (dig == 4 && c == '-') {
if (continuation)
@@ -1080,17 +1128,29 @@ initconn()
char *p, *a;
int result, len, tmpno = 0;
int on = 1;
- int a0, a1, a2, a3, p0, p1;
- int ports;
+ int error, ports;
+ u_int af;
+ u_int hal, h[16];
+ u_int pal, prt[2];
+ char *pasvcmd;
+
+#ifdef INET6
+ if (myctladdr.su_family == AF_INET6
+ && (IN6_IS_ADDR_LINKLOCAL(&myctladdr.su_sin6.sin6_addr)
+ || IN6_IS_ADDR_SITELOCAL(&myctladdr.su_sin6.sin6_addr))) {
+ warnx("use of scoped address can be troublesome");
+ }
+#endif
if (passivemode) {
- data = socket(AF_INET, SOCK_STREAM, 0);
+ data_addr = myctladdr;
+ data = socket(data_addr.su_family, SOCK_STREAM, 0);
if (data < 0) {
warn("socket");
return (1);
}
if (dobind && bind(data, (struct sockaddr *)&bindto,
- sizeof(bindto)) == -1) {
+ ((struct sockaddr *)&bindto)->sa_len) == -1) {
warn("bind");
goto bad;
}
@@ -1098,47 +1158,166 @@ initconn()
setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
sizeof(on)) < 0)
warn("setsockopt (ignored)");
- if (command("PASV") != COMPLETE) {
+ switch (data_addr.su_family) {
+ case AF_INET:
+ result = command(pasvcmd = "EPSV");
+ if (code / 10 == 22 && code != 229) {
+ puts("wrong server: return code must be 229");
+ result = COMPLETE + 1;
+ }
+ if (result != COMPLETE)
+ result = command(pasvcmd = "PASV");
+ break;
+#ifdef INET6
+ case AF_INET6:
+ result = command(pasvcmd = "EPSV");
+ if (code / 10 == 22 && code != 229) {
+ puts("wrong server: return code must be 229");
+ result = COMPLETE + 1;
+ }
+ if (result != COMPLETE)
+ result = command(pasvcmd = "LPSV");
+ break;
+#endif
+ default:
+ result = COMPLETE + 1;
+ }
+ if (result != COMPLETE) {
puts("Passive mode refused.");
goto bad;
}
+#define pack2(var, offset) \
+ (((var[(offset) + 0] & 0xff) << 8) | ((var[(offset) + 1] & 0xff) << 0))
+#define pack4(var, offset) \
+ (((var[(offset) + 0] & 0xff) << 24) | ((var[(offset) + 1] & 0xff) << 16) \
+ | ((var[(offset) + 2] & 0xff) << 8) | ((var[(offset) + 3] & 0xff) << 0))
/*
* What we've got at this point is a string of comma
* separated one-byte unsigned integer values.
+ * In PASV case,
* The first four are the an IP address. The fifth is
* the MSB of the port number, the sixth is the LSB.
* From that we'll prepare a sockaddr_in.
+ * In other case, the format is more complicated.
*/
+ if (strcmp(pasvcmd, "PASV") == 0) {
+ if (code / 10 == 22 && code != 227) {
+ puts("wrong server: return code must be 227");
+ error = 1;
+ goto bad;
+ }
+ error = sscanf(pasv, "%d,%d,%d,%d,%d,%d",
+ &h[0], &h[1], &h[2], &h[3],
+ &prt[0], &prt[1]);
+ if (error == 6) {
+ error = 0;
+ data_addr.su_sin.sin_addr.s_addr =
+ htonl(pack4(h, 0));
+ } else
+ error = 1;
+ } else if (strcmp(pasvcmd, "LPSV") == 0) {
+ if (code / 10 == 22 && code != 228) {
+ puts("wrong server: return code must be 228");
+ error = 1;
+ goto bad;
+ }
+ switch (data_addr.su_family) {
+ case AF_INET:
+ error = sscanf(pasv,
+"%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ &af, &hal,
+ &h[0], &h[1], &h[2], &h[3],
+ &pal, &prt[0], &prt[1]);
+ if (error == 9 && af == 4 && hal == 4 && pal == 2) {
+ error = 0;
+ data_addr.su_sin.sin_addr.s_addr =
+ htonl(pack4(h, 0));
+ } else
+ error = 1;
+ break;
+#ifdef INET6
+ case AF_INET6:
+ error = sscanf(pasv,
+"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ &af, &hal,
+ &h[0], &h[1], &h[2], &h[3],
+ &h[4], &h[5], &h[6], &h[7],
+ &h[8], &h[9], &h[10], &h[11],
+ &h[12], &h[13], &h[14], &h[15],
+ &pal, &prt[0], &prt[1]);
+ if (error != 21 || af != 6 || hal != 16 || pal != 2) {
+ error = 1;
+ break;
+ }
- if (sscanf(pasv, "%d,%d,%d,%d,%d,%d",
- &a0, &a1, &a2, &a3, &p0, &p1) != 6) {
+ error = 0;
+ {
+ u_int32_t *p32;
+ p32 = (u_int32_t *)&data_addr.su_sin6.sin6_addr;
+ p32[0] = htonl(pack4(h, 0));
+ p32[1] = htonl(pack4(h, 4));
+ p32[2] = htonl(pack4(h, 8));
+ p32[3] = htonl(pack4(h, 12));
+ }
+ break;
+#endif
+ default:
+ error = 1;
+ }
+ } else if (strcmp(pasvcmd, "EPSV") == 0) {
+ char delim[4];
+ char *tcpport;
+
+ prt[0] = 0;
+ if (code / 10 == 22 && code != 229) {
+ puts("wrong server: return code must be 229");
+ error = 1;
+ goto bad;
+ }
+ error = sscanf(pasv, "%c%c%c%d%c",
+ &delim[0], &delim[1], &delim[2],
+ &prt[1], &delim[3]);
+ if (error != 5) {
+ error = 1;
+ goto epsv_done;
+ }
+ if (delim[0] != delim[1] || delim[0] != delim[2]
+ || delim[0] != delim[3]) {
+ error = 1;
+ goto epsv_done;
+ }
+
+ data_addr = hisctladdr;
+ /* quickhack */
+ prt[0] = (prt[1] & 0xff00) >> 8;
+ prt[1] &= 0xff;
+ error = 0;
+epsv_done:
+ } else
+ error = 1;
+
+ if (error) {
puts(
"Passive mode address scan failure. Shouldn't happen!");
goto bad;
- }
+ };
- memset(&data_addr, 0, sizeof(data_addr));
- data_addr.sin_family = AF_INET;
- a = (char *)&data_addr.sin_addr.s_addr;
- a[0] = a0 & 0xff;
- a[1] = a1 & 0xff;
- a[2] = a2 & 0xff;
- a[3] = a3 & 0xff;
- p = (char *)&data_addr.sin_port;
- p[0] = p0 & 0xff;
- p[1] = p1 & 0xff;
+ data_addr.su_port = htons(pack2(prt, 0));
if (connect(data, (struct sockaddr *)&data_addr,
- sizeof(data_addr)) < 0) {
+ data_addr.su_len) < 0) {
warn("connect");
goto bad;
}
#ifdef IP_TOS
+ if (data_addr.su_family == AF_INET)
+ {
on = IPTOS_THROUGHPUT;
if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on,
sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
+ }
#endif
return (0);
}
@@ -1146,10 +1325,10 @@ initconn()
noport:
data_addr = myctladdr;
if (sendport)
- data_addr.sin_port = 0; /* let system pick one */
+ data_addr.su_port = 0; /* let system pick one */
if (data != -1)
(void)close(data);
- data = socket(AF_INET, SOCK_STREAM, 0);
+ data = socket(data_addr.su_family, SOCK_STREAM, 0);
if (data < 0) {
warn("socket");
if (tmpno)
@@ -1163,12 +1342,27 @@ noport:
goto bad;
}
#ifdef IP_PORTRANGE
+ if (data_addr.su_family == AF_INET)
+ {
+
ports = restricted_data_ports ? IP_PORTRANGE_HIGH : IP_PORTRANGE_DEFAULT;
if (setsockopt(data, IPPROTO_IP, IP_PORTRANGE, (char *)&ports,
sizeof(ports)) < 0)
warn("setsockopt PORTRANGE (ignored)");
+ }
+#endif
+#ifdef INET6
+#ifdef IPV6_PORTRANGE
+ if (data_addr.su_family == AF_INET6) {
+ ports = restricted_data_ports ? IPV6_PORTRANGE_HIGH
+ : IPV6_PORTRANGE_DEFAULT;
+ if (setsockopt(data, IPPROTO_IPV6, IPV6_PORTRANGE,
+ (char *)&ports, sizeof(ports)) < 0)
+ warn("setsockopt PORTRANGE (ignored)");
+ }
+#endif
#endif
- if (bind(data, (struct sockaddr *)&data_addr, sizeof(data_addr)) < 0) {
+ if (bind(data, (struct sockaddr *)&data_addr, data_addr.su_len) < 0) {
warn("bind");
goto bad;
}
@@ -1184,13 +1378,79 @@ noport:
if (listen(data, 1) < 0)
warn("listen");
if (sendport) {
- a = (char *)&data_addr.sin_addr;
- p = (char *)&data_addr.sin_port;
+ char hname[INET6_ADDRSTRLEN];
+ int af;
+ struct sockaddr_in data_addr4;
+ union sockunion *daddr;
+
+#ifdef INET6
+ if (data_addr.su_family == AF_INET6 &&
+ IN6_IS_ADDR_V4MAPPED(&data_addr.su_sin6.sin6_addr)) {
+ memset(&data_addr4, 0, sizeof(data_addr4));
+ data_addr4.sin_len = sizeof(struct sockaddr_in);
+ data_addr4.sin_family = AF_INET;
+ data_addr4.sin_port = data_addr.su_port;
+ memcpy((caddr_t)&data_addr4.sin_addr,
+ (caddr_t)&data_addr.su_sin6.sin6_addr.s6_addr[12],
+ sizeof(struct in_addr));
+ daddr = (union sockunion *)&data_addr4;
+ } else
+#endif
+ daddr = &data_addr;
+
+
+
#define UC(b) (((int)b)&0xff)
- result =
- command("PORT %d,%d,%d,%d,%d,%d",
- UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3]),
- UC(p[0]), UC(p[1]));
+
+ switch (daddr->su_family) {
+ case AF_INET:
+#ifdef INET6
+ case AF_INET6:
+#endif
+ af = (daddr->su_family == AF_INET) ? 1 : 2;
+ if (getnameinfo((struct sockaddr *)daddr,
+ daddr->su_len, hname,
+ sizeof(hname) - 1, NULL, 0,
+ NI_NUMERICHOST|NI_WITHSCOPEID)) {
+ result = ERROR;
+ } else {
+ result = command("EPRT |%d|%s|%d|",
+ af, hname, ntohs(daddr->su_port));
+ }
+ break;
+ default:
+ result = COMPLETE + 1;
+ break;
+ }
+ if (result == COMPLETE)
+ goto skip_port;
+
+ p = (char *)&daddr->su_port;
+ switch (daddr->su_family) {
+ case AF_INET:
+ a = (char *)&daddr->su_sin.sin_addr;
+ result = command("PORT %d,%d,%d,%d,%d,%d",
+ UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
+ UC(p[0]), UC(p[1]));
+ break;
+#ifdef INET6
+ case AF_INET6:
+ a = (char *)&daddr->su_sin6.sin6_addr;
+ result = command(
+"LPRT %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d",
+ 6, 16,
+ UC(a[0]),UC(a[1]),UC(a[2]),UC(a[3]),
+ UC(a[4]),UC(a[5]),UC(a[6]),UC(a[7]),
+ UC(a[8]),UC(a[9]),UC(a[10]),UC(a[11]),
+ UC(a[12]),UC(a[13]),UC(a[14]),UC(a[15]),
+ 2, UC(p[0]), UC(p[1]));
+ break;
+#endif
+ default:
+ result = COMPLETE + 1; /* xxx */
+ }
+ skip_port:
+
if (result == ERROR && sendport == -1) {
sendport = 0;
tmpno = 1;
@@ -1201,9 +1461,12 @@ noport:
if (tmpno)
sendport = 1;
#ifdef IP_TOS
+ if (data_addr.su_family == AF_INET)
+ {
on = IPTOS_THROUGHPUT;
if (setsockopt(data, IPPROTO_IP, IP_TOS, (char *)&on, sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
+ }
#endif
return (0);
bad:
@@ -1217,10 +1480,10 @@ FILE *
dataconn(lmode)
const char *lmode;
{
- struct sockaddr_in from;
+ union sockunion from;
int s, fromlen, tos;
- fromlen = sizeof(from);
+ fromlen = myctladdr.su_len;
if (passivemode)
return (fdopen(data, lmode));
@@ -1234,9 +1497,12 @@ dataconn(lmode)
(void)close(data);
data = s;
#ifdef IP_TOS
+ if (data_addr.su_family == AF_INET)
+ {
tos = IPTOS_THROUGHPUT;
if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *)&tos, sizeof(int)) < 0)
warn("setsockopt TOS (ignored)");
+ }
#endif
return (fdopen(data, lmode));
}
@@ -1267,8 +1533,8 @@ pswitch(flag)
static struct comvars {
int connect;
char name[MAXHOSTNAMELEN];
- struct sockaddr_in mctl;
- struct sockaddr_in hctl;
+ union sockunion mctl;
+ union sockunion hctl;
FILE *in;
FILE *out;
int tpe;
diff --git a/usr.bin/ftp/ftp_var.h b/usr.bin/ftp/ftp_var.h
index d26d22d..cd9b0bd 100644
--- a/usr.bin/ftp/ftp_var.h
+++ b/usr.bin/ftp/ftp_var.h
@@ -41,6 +41,7 @@
*/
#include <sys/param.h>
+#include <sys/socket.h>
#include <setjmp.h>
#include <stringlist.h>
#include <netinet/in.h>
@@ -96,7 +97,7 @@ int preserve; /* preserve modification time on files */
int progress; /* display transfer progress bar */
int code; /* return/reply code for ftp command */
int crflag; /* if 1, strip car. rets. on ascii gets */
-char pasv[64]; /* passive port for proxy data connection */
+char pasv[BUFSIZ]; /* passive port for proxy data connection */
int passivemode; /* passive mode enabled */
int restricted_data_ports; /* enable quarantine FTP area */
char *altarg; /* argv[1] with no shell-like preprocessing */
@@ -138,12 +139,12 @@ char *hostname; /* name of host connected to */
int unix_server; /* server is unix, can use binary for ascii */
int unix_proxy; /* proxy is unix, can use binary for ascii */
-u_int16_t ftpport; /* port number to use for ftp connections */
-u_int16_t httpport; /* port number to use for http connections */
-u_int16_t gateport; /* port number to use for gateftp connections */
+char *ftpport; /* port number to use for ftp connections */
+char *httpport; /* port number to use for http connections */
+char *gateport; /* port number to use for gateftp connections */
int dobind; /* bind to specific address */
-struct sockaddr_in bindto; /* address to bind to */
+struct sockaddr_storage bindto; /* address to bind to */
jmp_buf toplevel; /* non-local goto stuff for cmd scanner */
diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c
index 3717308..aeb7487 100644
--- a/usr.bin/ftp/main.c
+++ b/usr.bin/ftp/main.c
@@ -58,6 +58,7 @@ __RCSID_SOURCE("$NetBSD: main.c,v 1.26 1997/10/14 16:31:22 christos Exp $");
#include <arpa/inet.h>
#include <err.h>
+#include <errno.h>
#include <locale.h>
#include <netdb.h>
#include <pwd.h>
@@ -86,33 +87,14 @@ main(argc, argv)
(void) setlocale(LC_ALL, "");
- sp = getservbyname("ftp", "tcp");
- if (sp == 0)
- ftpport = htons(FTP_PORT); /* good fallback */
- else
- ftpport = sp->s_port;
- sp = getservbyname("http", "tcp");
- if (sp == 0)
- httpport = htons(HTTP_PORT); /* good fallback */
- else
- httpport = sp->s_port;
- gateport = 0;
+ ftpport = "ftp";
+ httpport = "http";
+ gateport = NULL;
cp = getenv("FTPSERVERPORT");
- if (cp != NULL) {
- port = strtol(cp, &ep, 10);
- if (port < 1 || port > 0xffff || *ep != '\0')
- warnx("bad FTPSERVERPORT port number: %s (ignored)",
- cp);
- else
- gateport = htons(port);
- }
- if (gateport == 0) {
- sp = getservbyname("ftpgate", "tcp");
- if (sp == 0)
- gateport = htons(GATE_PORT);
- else
- gateport = sp->s_port;
- }
+ if (cp != NULL)
+ gateport = cp;
+ if (!gateport)
+ gateport = "ftpgate";
doglob = 1;
interactive = 1;
autologin = 1;
@@ -203,11 +185,7 @@ main(argc, argv)
break;
case 'P':
- port = strtol(optarg, &ep, 10);
- if (port < 1 || port > 0xffff || *ep != '\0')
- warnx("bad port number: %s (ignored)", optarg);
- else
- ftpport = htons(port);
+ ftpport = optarg;
break;
case 's':
@@ -244,17 +222,24 @@ main(argc, argv)
sendport = -1; /* not using ports */
if (dobind) {
- memset((void *)&bindto, 0, sizeof(bindto));
- if (inet_aton(src_addr, &bindto.sin_addr) == 1)
- bindto.sin_family = AF_INET;
- else {
- struct hostent *hp = gethostbyname(src_addr);
- if (hp == NULL)
- errx(1, "%s: %s", src_addr, hstrerror(h_errno));
- bindto.sin_family = hp->h_addrtype;
- memcpy(&bindto.sin_addr, hp->h_addr_list[0],
- MIN(hp->h_length,sizeof(bindto.sin_addr)));
+ struct addrinfo hints;
+ struct addrinfo *res;
+ char *ftpdataport = "ftp-data";
+ int error;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ error = getaddrinfo(src_addr, NULL, &hints, &res);
+ if (error) {
+ fprintf(stderr, "%s: %s", src_addr,
+ gai_strerror(error));
+ if (error == EAI_SYSTEM)
+ errx(1, "%s", strerror(errno));
+ exit(1);
}
+ memcpy(&bindto, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
}
/*
@@ -280,7 +265,7 @@ main(argc, argv)
#endif
if (argc > 0) {
- if (strchr(argv[0], ':') != NULL) {
+ if (isurl(argv[0])) {
anonftp = 1; /* Handle "automatic" transfers. */
rval = auto_fetch(argc, argv);
if (rval >= 0) /* -1 == connected and cd-ed */
diff --git a/usr.bin/ftp/util.c b/usr.bin/ftp/util.c
index a34ca34..a62565c 100644
--- a/usr.bin/ftp/util.c
+++ b/usr.bin/ftp/util.c
@@ -76,7 +76,7 @@ setpeer(argc, argv)
char *argv[];
{
char *host;
- u_int16_t port;
+ char *port;
if (connected) {
printf("Already connected to %s, use close first.\n",
@@ -95,19 +95,8 @@ setpeer(argc, argv)
port = gateport;
else
port = ftpport;
- if (argc > 2) {
- char *ep;
- long nport;
-
- nport = strtol(argv[2], &ep, 10);
- if (nport < 1 || nport > 0xffff || *ep != '\0') {
- printf("%s: bad port number '%s'.\n", argv[0], argv[2]);
- printf("usage: %s host-name [port]\n", argv[0]);
- code = -1;
- return;
- }
- port = htons(nport);
- }
+ if (argc > 2)
+ port = strdup(argv[2]);
if (gatemode) {
if (gateserver == NULL || *gateserver == '\0')
OpenPOWER on IntegriCloud