Claudio Jeker([email protected]) on 2019.08.09 00:16:42 +0200:
> On Thu, Aug 08, 2019 at 11:06:30PM +0100, Stuart Henderson wrote:
> > On 2019/08/08 15:42, Claudio Jeker wrote:
> > > I need to be able to control the bind address for openrsync connections.
> > > This implements this but it only works for connections to an rsync daemon.
> > > For rsync over ssh you need to use -e 'ssh -b address' instead.
> >
> > Works as expected for IPv4. For IPv6 it only works if you use a hostname
> > that
> > only has a v6 address and not also a v4 address. In this situation GPL rsync
> > prints a warning (unless you also use -6), but then moves onto a v6
> > destination
> > address.
> >
> > (Maybe openrsync works if you use an IPv6 literal address as the
> > destination,
> > but I didn't see a way to do that).
> >
> > OK for now, but as rpki-client may well end up used in places with fiddly
> > addressing requirements (which is why you're adding it in the first place ;)
> > it would be good to improve v6 as a later step.
> >
>
> I think this has also to do with the way the host (aka destination) lookup
> happens. My assumption is that you first try to connect to a IPv4 address
> and so there is no binding to the IPv6 address happening.
> To be honest, the GPL rsync way of doing things is also not entierly clear to
> me. It may be necessary to add -4 and -6 support or maybe force the address
> family to match bind_address and destination (or error out if they
> mismatch) would be enough.
We definatly will need to add -4/6 options.
>
> I will commit this tomorrow morning so that improvements can happen in
> tree.
ok
> --
> :wq Claudio
>
> > > Index: extern.h
> > > ===================================================================
> > > RCS file: /cvs/src/usr.bin/rsync/extern.h,v
> > > retrieving revision 1.31
> > > diff -u -p -r1.31 extern.h
> > > --- extern.h 2 Jun 2019 17:36:48 -0000 1.31
> > > +++ extern.h 8 Aug 2019 13:41:02 -0000
> > > @@ -120,6 +120,7 @@ struct opts {
> > > char *rsync_path; /* --rsync-path */
> > > char *ssh_prog; /* --rsh or -e */
> > > char *port; /* --port */
> > > + char *address; /* --address */
> > > };
> > >
> > > /*
> > > Index: main.c
> > > ===================================================================
> > > RCS file: /cvs/src/usr.bin/rsync/main.c,v
> > > retrieving revision 1.47
> > > diff -u -p -r1.47 main.c
> > > --- main.c 3 Jun 2019 15:37:48 -0000 1.47
> > > +++ main.c 8 Aug 2019 13:41:02 -0000
> > > @@ -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);
> > > }
> > > Index: rsync.1
> > > ===================================================================
> > > RCS file: /cvs/src/usr.bin/rsync/rsync.1,v
> > > retrieving revision 1.18
> > > diff -u -p -r1.18 rsync.1
> > > --- rsync.1 6 May 2019 15:44:34 -0000 1.18
> > > +++ rsync.1 8 Aug 2019 13:41:02 -0000
> > > @@ -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
> > > Index: socket.c
> > > ===================================================================
> > > RCS file: /cvs/src/usr.bin/rsync/socket.c,v
> > > retrieving revision 1.25
> > > diff -u -p -r1.25 socket.c
> > > --- socket.c 3 Jun 2019 15:37:48 -0000 1.25
> > > +++ socket.c 8 Aug 2019 13:41:02 -0000
> > > @@ -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 sourc
> > > 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 sourc
> > > * 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 ch
> > > 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, i
> > >
> > > /* 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, i
> > >
> > > 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, i
> > > 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;
> > >
> >
>
> --
> :wq Claudio
>