summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorClaudio Jeker <claudio@cvs.openbsd.org>2019-08-09 05:28:02 +0000
committerClaudio Jeker <claudio@cvs.openbsd.org>2019-08-09 05:28:02 +0000
commit3f4ae2496daeb2e51da42055ef7c980a1ab84261 (patch)
tree89bd8baa8c80fe4921a56cc895d7d8708f7ff608
parente756da33bd404fd890245d96a8217b2485e7c0bd (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.h3
-rw-r--r--usr.bin/rsync/main.c12
-rw-r--r--usr.bin/rsync/rsync.111
-rw-r--r--usr.bin/rsync/socket.c57
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;