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
> 

Reply via email to