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.


> -- 
> :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;
> 

Reply via email to