summaryrefslogtreecommitdiff
path: root/usr.bin/ftp
diff options
context:
space:
mode:
authorChristiano F. Haesbaert <haesbaert@cvs.openbsd.org>2012-04-30 13:41:27 +0000
committerChristiano F. Haesbaert <haesbaert@cvs.openbsd.org>2012-04-30 13:41:27 +0000
commit0096e084a858467c2251be9590ec7ea3d12028dd (patch)
treeffbdebe1a05bf889580ee949110d3908c2090c5b /usr.bin/ftp
parent3226ff7a498795efde6d345c1f2258db3e98c1fe (diff)
Add a -s flag to ftp(1) to let the user specify the source IP address
of the connection. This is useful for testing ftp(1) over VPN tunnels. This -s flag is present in the other BSDs, including OS X. All work was done by Lawrence Teo, thanks (-:. ok myself mikeb
Diffstat (limited to 'usr.bin/ftp')
-rw-r--r--usr.bin/ftp/fetch.c42
-rw-r--r--usr.bin/ftp/ftp.116
-rw-r--r--usr.bin/ftp/ftp.c74
-rw-r--r--usr.bin/ftp/ftp_var.h3
-rw-r--r--usr.bin/ftp/main.c28
5 files changed, 150 insertions, 13 deletions
diff --git a/usr.bin/ftp/fetch.c b/usr.bin/ftp/fetch.c
index bfa1b822a7c..a9cb49db78c 100644
--- a/usr.bin/ftp/fetch.c
+++ b/usr.bin/ftp/fetch.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: fetch.c,v 1.104 2012/04/23 21:22:02 sthen Exp $ */
+/* $OpenBSD: fetch.c,v 1.105 2012/04/30 13:41:26 haesbaert Exp $ */
/* $NetBSD: fetch.c,v 1.14 1997/08/18 10:20:20 lukem Exp $ */
/*-
@@ -179,7 +179,7 @@ url_get(const char *origline, const char *proxyenv, const char *outfile)
char *hosttail, *cause = "unknown", *newline, *host, *port, *buf = NULL;
char *epath, *redirurl, *loctail;
int error, i, isftpurl = 0, isfileurl = 0, isredirect = 0, rval = -1;
- struct addrinfo hints, *res0, *res;
+ struct addrinfo hints, *res0, *res, *ares = NULL;
const char * volatile savefile;
char * volatile proxyurl = NULL;
char *cookie = NULL;
@@ -198,6 +198,7 @@ url_get(const char *origline, const char *proxyenv, const char *outfile)
#endif /* !SMALL */
SSL *ssl = NULL;
int status;
+ int save_errno;
direction = "received";
@@ -490,6 +491,17 @@ noslash:
goto cleanup_url_get;
}
+#ifndef SMALL
+ if (srcaddr) {
+ hints.ai_flags |= AI_NUMERICHOST;
+ error = getaddrinfo(srcaddr, NULL, &hints, &ares);
+ if (error) {
+ warnx("%s: %s", gai_strerror(error), srcaddr);
+ goto cleanup_url_get;
+ }
+ }
+#endif /* !SMALL */
+
s = -1;
for (res = res0; res; res = res->ai_next) {
if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf,
@@ -504,10 +516,28 @@ noslash:
continue;
}
+#ifndef SMALL
+ if (srcaddr) {
+ if (ares->ai_family != res->ai_family) {
+ close(s);
+ s = -1;
+ errno = EINVAL;
+ cause = "bind";
+ continue;
+ }
+ if (bind(s, ares->ai_addr, ares->ai_addrlen) < 0) {
+ save_errno = errno;
+ close(s);
+ errno = save_errno;
+ s = -1;
+ cause = "bind";
+ continue;
+ }
+ }
+#endif /* !SMALL */
+
again:
if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
- int save_errno;
-
if (errno == EINTR)
goto again;
save_errno = errno;
@@ -532,6 +562,10 @@ again:
break;
}
freeaddrinfo(res0);
+#ifndef SMALL
+ if (srcaddr)
+ freeaddrinfo(ares);
+#endif /* !SMALL */
if (s < 0) {
warn("%s", cause);
goto cleanup_url_get;
diff --git a/usr.bin/ftp/ftp.1 b/usr.bin/ftp/ftp.1
index 41e8e0b7377..1c2e56e2a94 100644
--- a/usr.bin/ftp/ftp.1
+++ b/usr.bin/ftp/ftp.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: ftp.1,v 1.81 2010/07/26 21:31:34 jmc Exp $
+.\" $OpenBSD: ftp.1,v 1.82 2012/04/30 13:41:26 haesbaert Exp $
.\" $NetBSD: ftp.1,v 1.22 1997/08/18 10:20:22 lukem Exp $
.\"
.\" Copyright (c) 1985, 1989, 1990, 1993
@@ -30,7 +30,7 @@
.\"
.\" @(#)ftp.1 8.3 (Berkeley) 10/9/94
.\"
-.Dd $Mdocdate: July 26 2010 $
+.Dd $Mdocdate: April 30 2012 $
.Dt FTP 1
.Os
.Sh NAME
@@ -42,10 +42,12 @@
.Op Fl k Ar seconds
.Op Fl P Ar port
.Op Fl r Ar seconds
+.Op Fl s Ar srcaddr
.Op Ar host Op Ar port
.Nm ftp
.Op Fl C
.Op Fl o Ar output
+.Op Fl s Ar srcaddr
.Sm off
.No ftp:// Oo Ar user : password No @
.Oc Ar host Oo : Ar port
@@ -57,6 +59,7 @@
.Op Fl C
.Op Fl c Ar cookie
.Op Fl o Ar output
+.Op Fl s Ar srcaddr
.Sm off
.No http:// Ar host Oo : Ar port
.Oc No / Ar file
@@ -66,6 +69,7 @@
.Op Fl C
.Op Fl c Ar cookie
.Op Fl o Ar output
+.Op Fl s Ar srcaddr
.Sm off
.No https:// Ar host Oo : Ar port
.Oc No / Ar file
@@ -74,6 +78,7 @@
.Nm ftp
.Op Fl C
.Op Fl o Ar output
+.Op Fl s Ar srcaddr
.Sm off
.No file: Ar file
.Sm on
@@ -81,6 +86,7 @@
.Nm ftp
.Op Fl C
.Op Fl o Ar output
+.Op Fl s Ar srcaddr
.Sm off
.Ar host : No / Ar file Oo /
.Oc
@@ -220,6 +226,12 @@ if the server does not support passive connections.
.It Fl r Ar seconds
Retry to connect if failed, pausing for number of
.Ar seconds .
+.It Fl s Ar srcaddr
+Use
+.Ar srcaddr
+on the local machine as the source address
+of the connection.
+Only useful on systems with more than one address.
.It Fl t
Enables packet tracing.
.It Fl V
diff --git a/usr.bin/ftp/ftp.c b/usr.bin/ftp/ftp.c
index 84cc905977c..9e895a02f59 100644
--- a/usr.bin/ftp/ftp.c
+++ b/usr.bin/ftp/ftp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ftp.c,v 1.81 2010/09/03 03:49:37 lum Exp $ */
+/* $OpenBSD: ftp.c,v 1.82 2012/04/30 13:41:26 haesbaert Exp $ */
/* $NetBSD: ftp.c,v 1.27 1997/08/18 10:20:23 lukem Exp $ */
/*
@@ -114,7 +114,7 @@ hookup(char *host, char *port)
{
int s, tos, error;
static char hostnamebuf[MAXHOSTNAMELEN];
- struct addrinfo hints, *res, *res0;
+ struct addrinfo hints, *res, *res0, *ares;
char hbuf[NI_MAXHOST];
char *cause = "unknown";
socklen_t namelen;
@@ -163,6 +163,25 @@ hookup(char *host, char *port)
else
strlcpy(hostnamebuf, host, sizeof(hostnamebuf));
hostname = hostnamebuf;
+
+#ifndef SMALL
+ if (srcaddr) {
+ struct addrinfo ahints;
+
+ memset(&ahints, 0, sizeof(ahints));
+ ahints.ai_family = family;
+ ahints.ai_socktype = SOCK_STREAM;
+ ahints.ai_flags |= AI_NUMERICHOST;
+ ahints.ai_protocol = 0;
+
+ error = getaddrinfo(srcaddr, NULL, &ahints, &ares);
+ if (error) {
+ warnx("%s: %s", gai_strerror(error), srcaddr);
+ code = -1;
+ return (0);
+ }
+ }
+#endif /* !SMALL */
s = -1;
for (res = res0; res; res = res->ai_next) {
@@ -183,6 +202,25 @@ hookup(char *host, char *port)
cause = "socket";
continue;
}
+#ifndef SMALL
+ if (srcaddr) {
+ if (ares->ai_family != res->ai_family) {
+ close(s);
+ s = -1;
+ errno = EINVAL;
+ cause = "bind";
+ continue;
+ }
+ if (bind(s, ares->ai_addr, ares->ai_addrlen) < 0) {
+ cause = "bind";
+ error = errno;
+ close(s);
+ errno = error;
+ s = -1;
+ continue;
+ }
+ }
+#endif /* !SMALL */
while ((error = connect(s, res->ai_addr, res->ai_addrlen)) < 0
&& errno == EINTR) {
;
@@ -218,6 +256,12 @@ hookup(char *host, char *port)
namelen = res->ai_addrlen;
freeaddrinfo(res0);
res0 = res = NULL;
+#ifndef SMALL
+ if (srcaddr) {
+ freeaddrinfo(ares);
+ ares = NULL;
+ }
+#endif /* !SMALL */
if (getsockname(s, (struct sockaddr *)&myctladdr, &namelen) < 0) {
warn("getsockname");
code = -1;
@@ -1240,12 +1284,31 @@ initconn(void)
u_int af, hal, pal;
char *pasvcmd = NULL;
socklen_t namelen;
+ struct addrinfo *ares;
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");
}
+#ifndef SMALL
+ if (srcaddr) {
+ struct addrinfo ahints;
+
+ memset(&ahints, 0, sizeof(ahints));
+ ahints.ai_family = family;
+ ahints.ai_socktype = SOCK_STREAM;
+ ahints.ai_flags |= AI_NUMERICHOST;
+ ahints.ai_protocol = 0;
+
+ error = getaddrinfo(srcaddr, NULL, &ahints, &ares);
+ if (error) {
+ warnx("%s: %s", gai_strerror(error), srcaddr);
+ code = -1;
+ return (0);
+ }
+ }
+#endif /* !SMALL */
reinit:
if (passivemode) {
data_addr = myctladdr;
@@ -1255,6 +1318,13 @@ reinit:
return (1);
}
#ifndef SMALL
+ if (srcaddr) {
+ if (bind(data, ares->ai_addr, ares->ai_addrlen) < 0) {
+ warn("bind");
+ close(data);
+ return (1);
+ }
+ }
if ((options & SO_DEBUG) &&
setsockopt(data, SOL_SOCKET, SO_DEBUG, (char *)&on,
sizeof(on)) < 0)
diff --git a/usr.bin/ftp/ftp_var.h b/usr.bin/ftp/ftp_var.h
index 180153fc74c..3ec69627b67 100644
--- a/usr.bin/ftp/ftp_var.h
+++ b/usr.bin/ftp/ftp_var.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: ftp_var.h,v 1.31 2010/07/02 22:01:10 deraadt Exp $ */
+/* $OpenBSD: ftp_var.h,v 1.32 2012/04/30 13:41:26 haesbaert Exp $ */
/* $NetBSD: ftp_var.h,v 1.18 1997/08/18 10:20:25 lukem Exp $ */
/*
@@ -165,6 +165,7 @@ size_t cursor_argc; /* location of cursor in margv */
size_t cursor_argo; /* offset of cursor in margv[cursor_argc] */
char *cookiefile; /* cookie jar to use */
int resume; /* continue transfer */
+char *srcaddr; /* source address to bind to */
#endif /* !SMALL */
off_t bytes; /* current # of bytes read */
diff --git a/usr.bin/ftp/main.c b/usr.bin/ftp/main.c
index e4ba176635a..40eb7bd3352 100644
--- a/usr.bin/ftp/main.c
+++ b/usr.bin/ftp/main.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: main.c,v 1.81 2010/06/29 23:12:33 halex Exp $ */
+/* $OpenBSD: main.c,v 1.82 2012/04/30 13:41:26 haesbaert Exp $ */
/* $NetBSD: main.c,v 1.24 1997/08/18 10:20:26 lukem Exp $ */
/*
@@ -114,6 +114,7 @@ main(volatile int argc, char *argv[])
hist = NULL;
cookiefile = NULL;
resume = 0;
+ srcaddr = NULL;
marg_sl = sl_init();
#endif /* !SMALL */
mark = HASHBYTES;
@@ -174,7 +175,7 @@ main(volatile int argc, char *argv[])
cookiefile = getenv("http_cookies");
#endif /* !SMALL */
- while ((ch = getopt(argc, argv, "46AaCc:dEegik:mno:pP:r:tvV")) != -1) {
+ while ((ch = getopt(argc, argv, "46AaCc:dEegik:mno:pP:r:s:tvV")) != -1) {
switch (ch) {
case '4':
family = PF_INET;
@@ -275,6 +276,12 @@ main(volatile int argc, char *argv[])
}
break;
+ case 's':
+#ifndef SMALL
+ srcaddr = optarg;
+#endif /* !SMALL */
+ break;
+
case 't':
trace = 1;
break;
@@ -756,15 +763,21 @@ usage(void)
" %s [-C] "
#endif /* !SMALL */
"[-o output] "
+#ifndef SMALL
+ "[-s srcaddr] "
+#endif /* !SMALL */
"ftp://[user:password@]host[:port]/file[/] ...\n"
" %s "
#ifndef SMALL
"[-C] [-c cookie] "
#endif /* !SMALL */
"[-o output] "
+#ifndef SMALL
+ "[-s srcaddr] "
+#endif /* !SMALL */
"http://host[:port]/file ...\n"
#ifndef SMALL
- " %s [-C] [-c cookie] [-o output] "
+ " %s [-C] [-c cookie] [-o output] [-s srcaddr] "
"https://host[:port]/file ...\n"
#endif /* !SMALL */
" %s "
@@ -772,12 +785,19 @@ usage(void)
"[-C] "
#endif /* !SMALL */
"[-o output] "
+#ifndef SMALL
+ "[-s srcaddr] "
+#endif /* !SMALL */
"file:file ...\n"
" %s "
#ifndef SMALL
"[-C] "
#endif /* !SMALL */
- "[-o output] host:/file[/] ...\n",
+ "[-o output] "
+#ifndef SMALL
+ "[-s srcaddr] "
+#endif /* !SMALL */
+ "host:/file[/] ...\n",
#ifndef SMALL
__progname, __progname, __progname, __progname, __progname,
__progname);