diff options
author | Christiano F. Haesbaert <haesbaert@cvs.openbsd.org> | 2012-04-30 13:41:27 +0000 |
---|---|---|
committer | Christiano F. Haesbaert <haesbaert@cvs.openbsd.org> | 2012-04-30 13:41:27 +0000 |
commit | 0096e084a858467c2251be9590ec7ea3d12028dd (patch) | |
tree | ffbdebe1a05bf889580ee949110d3908c2090c5b /usr.bin/ftp | |
parent | 3226ff7a498795efde6d345c1f2258db3e98c1fe (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.c | 42 | ||||
-rw-r--r-- | usr.bin/ftp/ftp.1 | 16 | ||||
-rw-r--r-- | usr.bin/ftp/ftp.c | 74 | ||||
-rw-r--r-- | usr.bin/ftp/ftp_var.h | 3 | ||||
-rw-r--r-- | usr.bin/ftp/main.c | 28 |
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); |