diff options
author | Claudio Jeker <claudio@cvs.openbsd.org> | 2019-08-09 05:28:02 +0000 |
---|---|---|
committer | Claudio Jeker <claudio@cvs.openbsd.org> | 2019-08-09 05:28:02 +0000 |
commit | 3f4ae2496daeb2e51da42055ef7c980a1ab84261 (patch) | |
tree | 89bd8baa8c80fe4921a56cc895d7d8708f7ff608 | |
parent | e756da33bd404fd890245d96a8217b2485e7c0bd (diff) |
Add --address argument to openrsync to bind to the specified address
when connecting to a rsync daemon.
OK deraadt@ benno@ naddy@ sthen@
-rw-r--r-- | usr.bin/rsync/extern.h | 3 | ||||
-rw-r--r-- | usr.bin/rsync/main.c | 12 | ||||
-rw-r--r-- | usr.bin/rsync/rsync.1 | 11 | ||||
-rw-r--r-- | usr.bin/rsync/socket.c | 57 |
4 files changed, 68 insertions, 15 deletions
diff --git a/usr.bin/rsync/extern.h b/usr.bin/rsync/extern.h index 07c0e0e5111..15de8cd9b5c 100644 --- a/usr.bin/rsync/extern.h +++ b/usr.bin/rsync/extern.h @@ -1,4 +1,4 @@ -/* $Id: extern.h,v 1.31 2019/06/02 17:36:48 florian Exp $ */ +/* $Id: extern.h,v 1.32 2019/08/09 05:28:01 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -120,6 +120,7 @@ struct opts { char *rsync_path; /* --rsync-path */ char *ssh_prog; /* --rsh or -e */ char *port; /* --port */ + char *address; /* --address */ }; /* diff --git a/usr.bin/rsync/main.c b/usr.bin/rsync/main.c index 5e39f012c37..d348c5ffaec 100644 --- a/usr.bin/rsync/main.c +++ b/usr.bin/rsync/main.c @@ -1,4 +1,4 @@ -/* $Id: main.c,v 1.47 2019/06/03 15:37:48 naddy Exp $ */ +/* $Id: main.c,v 1.48 2019/08/09 05:28:01 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -307,6 +307,7 @@ main(int argc, char *argv[]) { "no-times", no_argument, &opts.preserve_times, 0 }, { "verbose", no_argument, &verbose, 1 }, { "no-verbose", no_argument, &verbose, 0 }, + { "address", required_argument, NULL, 4 }, { NULL, 0, NULL, 0 }}; /* Global pledge. */ @@ -380,6 +381,9 @@ main(int argc, char *argv[]) case 3: opts.port = optarg; break; + case 4: + opts.address = optarg; + break; case 'h': default: goto usage; @@ -505,9 +509,9 @@ main(int argc, char *argv[]) exit(rc); usage: fprintf(stderr, "usage: %s" - " [-aDglnoprtvx] [-e program] [--del] [--numeric-ids]\n" - "\t[--port=portnumber] [--rsync-path=program] [--version]\n" - "\tsource ... directory\n", + " [-aDglnoprtvx] [-e program] [--address=bind_address] [--del]\n" + "\t[--numeric-ids] [--port=portnumber] [--rsync-path=program]\n" + "\t[--version] source ... directory\n", getprogname()); exit(1); } diff --git a/usr.bin/rsync/rsync.1 b/usr.bin/rsync/rsync.1 index 3e84a8e0581..80c09d5fe2d 100644 --- a/usr.bin/rsync/rsync.1 +++ b/usr.bin/rsync/rsync.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: rsync.1,v 1.18 2019/05/06 15:44:34 schwarze Exp $ +.\" $OpenBSD: rsync.1,v 1.19 2019/08/09 05:28:01 claudio Exp $ .\" .\" Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> .\" @@ -14,7 +14,7 @@ .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. .\" -.Dd $Mdocdate: May 6 2019 $ +.Dd $Mdocdate: August 9 2019 $ .Dt OPENRSYNC 1 .Os .Sh NAME @@ -24,6 +24,7 @@ .Nm openrsync .Op Fl aDglnoprtvx .Op Fl e Ar program +.Op Fl -address Ns = Ns Ar bind_address .Op Fl -del .Op Fl -numeric-ids .Op Fl -port Ns = Ns Ar service @@ -50,6 +51,12 @@ The arguments are as follows: .It Fl a , -archive Shorthand for .Fl Dgloprt . +.It Fl -address Ns = Ns Ar bind_address +Use +.Ar bind_address +on the local machine as the source address of the connection. +Only useful when connecting to an rsync daemon and on systems with more than +one address. .It Fl D Also transfer device and special files. Shorthand for diff --git a/usr.bin/rsync/socket.c b/usr.bin/rsync/socket.c index 740a19918f9..7329aba13e5 100644 --- a/usr.bin/rsync/socket.c +++ b/usr.bin/rsync/socket.c @@ -1,4 +1,4 @@ -/* $Id: socket.c,v 1.25 2019/06/03 15:37:48 naddy Exp $ */ +/* $Id: socket.c,v 1.26 2019/08/09 05:28:01 claudio Exp $ */ /* * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv> * @@ -46,11 +46,34 @@ struct source { }; /* + * Try to bind to a local IP address matching the addres family passed. + * Return -1 on failure to bind to any address, 0 on success. + */ +static int +inet_bind(int s, sa_family_t af, const struct source *bsrc, size_t bsrcsz) +{ + size_t i; + + if (bsrc == NULL) + return 0; + for (i = 0; i < bsrcsz; i++) { + if (bsrc[i].family != af) + continue; + if (bind(s, (const struct sockaddr *)&bsrc[i].sa, + bsrc[i].salen) == -1) + continue; + return 0; + } + return -1; +} + +/* * Connect to an IP address representing a host. * Return <0 on failure, 0 on try another address, >0 on success. */ static int -inet_connect(int *sd, const struct source *src, const char *host) +inet_connect(int *sd, const struct source *src, const char *host, + const struct source *bsrc, size_t bsrcsz) { int c, flags; @@ -64,6 +87,11 @@ inet_connect(int *sd, const struct source *src, const char *host) return -1; } + if (inet_bind(*sd, src->family, bsrc, bsrcsz) == -1) { + ERR("bind"); + return -1; + } + /* * Initiate blocking connection. * We use the blocking connect() instead of passing NONBLOCK to @@ -102,11 +130,12 @@ inet_connect(int *sd, const struct source *src, const char *host) * in this case). */ static struct source * -inet_resolve(struct sess *sess, const char *host, size_t *sz) +inet_resolve(struct sess *sess, const char *host, size_t *sz, int passive) { struct addrinfo hints, *res0, *res; struct sockaddr *sa; struct source *src = NULL; + const char *port = sess->opts->port; size_t i, srcsz = 0; int error; @@ -115,8 +144,12 @@ inet_resolve(struct sess *sess, const char *host, size_t *sz) memset(&hints, 0, sizeof(hints)); hints.ai_family = PF_UNSPEC; hints.ai_socktype = SOCK_STREAM; + if (passive) { + hints.ai_flags = SOCK_STREAM; + port = NULL; + } - error = getaddrinfo(host, sess->opts->port, &hints, &res0); + error = getaddrinfo(host, port, &hints, &res0); LOG2("resolving: %s", host); @@ -239,8 +272,8 @@ int rsync_connect(const struct opts *opts, int *sd, const struct fargs *f) { struct sess sess; - struct source *src = NULL; - size_t i, srcsz = 0; + struct source *src = NULL, *bsrc = NULL; + size_t i, srcsz = 0, bsrcsz = 0; int c, rc = 1; if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw unveil", @@ -254,10 +287,16 @@ rsync_connect(const struct opts *opts, int *sd, const struct fargs *f) /* Resolve all IP addresses from the host. */ - if ((src = inet_resolve(&sess, f->host, &srcsz)) == NULL) { + if ((src = inet_resolve(&sess, f->host, &srcsz, 0)) == NULL) { ERRX1("inet_resolve"); exit(1); } + if (opts->address != NULL) + if ((bsrc = inet_resolve(&sess, opts->address, &bsrcsz, 1)) == + NULL) { + ERRX1("inet_resolve bind"); + exit(1); + } /* Drop the DNS pledge. */ @@ -274,7 +313,7 @@ rsync_connect(const struct opts *opts, int *sd, const struct fargs *f) assert(srcsz); for (i = 0; i < srcsz; i++) { - c = inet_connect(sd, &src[i], f->host); + c = inet_connect(sd, &src[i], f->host, bsrc, bsrcsz); if (c < 0) { ERRX1("inet_connect"); goto out; @@ -297,9 +336,11 @@ rsync_connect(const struct opts *opts, int *sd, const struct fargs *f) LOG2("connected: %s, %s", src[i].ip, f->host); free(src); + free(bsrc); return 0; out: free(src); + free(bsrc); if (*sd != -1) close(*sd); return rc; |