Annotation of src/usr.bin/rsync/socket.c, Revision 1.26
1.26 ! claudio 1: /* $Id: socket.c,v 1.25 2019/06/03 15:37:48 naddy Exp $ */
1.1 benno 2: /*
3: * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17: #include <sys/stat.h>
18: #include <sys/socket.h>
19: #include <arpa/inet.h>
20: #include <netinet/in.h>
21:
22: #include <assert.h>
23: #include <ctype.h>
24: #include <errno.h>
25: #include <fcntl.h>
26: #include <inttypes.h>
27: #include <netdb.h>
28: #include <poll.h>
29: #include <resolv.h>
30: #include <stdlib.h>
31: #include <string.h>
32: #include <unistd.h>
1.19 deraadt 33: #include <err.h>
1.1 benno 34:
35: #include "extern.h"
36:
37: /*
38: * Defines a resolved IP address for the host
39: * There can be many, IPV4 or IPV6.
40: */
41: struct source {
1.2 benno 42: int family; /* PF_INET or PF_INET6 */
43: char ip[INET6_ADDRSTRLEN]; /* formatted string */
1.1 benno 44: struct sockaddr_storage sa; /* socket */
45: socklen_t salen; /* length of socket buffer */
46: };
47:
48: /*
1.26 ! claudio 49: * Try to bind to a local IP address matching the addres family passed.
! 50: * Return -1 on failure to bind to any address, 0 on success.
! 51: */
! 52: static int
! 53: inet_bind(int s, sa_family_t af, const struct source *bsrc, size_t bsrcsz)
! 54: {
! 55: size_t i;
! 56:
! 57: if (bsrc == NULL)
! 58: return 0;
! 59: for (i = 0; i < bsrcsz; i++) {
! 60: if (bsrc[i].family != af)
! 61: continue;
! 62: if (bind(s, (const struct sockaddr *)&bsrc[i].sa,
! 63: bsrc[i].salen) == -1)
! 64: continue;
! 65: return 0;
! 66: }
! 67: return -1;
! 68: }
! 69:
! 70: /*
1.1 benno 71: * Connect to an IP address representing a host.
72: * Return <0 on failure, 0 on try another address, >0 on success.
73: */
74: static int
1.26 ! claudio 75: inet_connect(int *sd, const struct source *src, const char *host,
! 76: const struct source *bsrc, size_t bsrcsz)
1.1 benno 77: {
78: int c, flags;
79:
1.5 deraadt 80: if (*sd != -1)
1.1 benno 81: close(*sd);
82:
1.23 benno 83: LOG2("trying: %s, %s", src->ip, host);
1.1 benno 84:
1.5 deraadt 85: if ((*sd = socket(src->family, SOCK_STREAM, 0)) == -1) {
1.23 benno 86: ERR("socket");
1.1 benno 87: return -1;
88: }
89:
1.26 ! claudio 90: if (inet_bind(*sd, src->family, bsrc, bsrcsz) == -1) {
! 91: ERR("bind");
! 92: return -1;
! 93: }
! 94:
1.1 benno 95: /*
96: * Initiate blocking connection.
97: * We use the blocking connect() instead of passing NONBLOCK to
98: * the socket() function because we don't need to do anything
99: * while waiting for this to finish.
100: */
101:
1.7 deraadt 102: c = connect(*sd, (const struct sockaddr *)&src->sa, src->salen);
1.5 deraadt 103: if (c == -1) {
104: if (errno == ECONNREFUSED || errno == EHOSTUNREACH) {
1.23 benno 105: WARNX("connect refused: %s, %s",
1.7 deraadt 106: src->ip, host);
1.1 benno 107: return 0;
108: }
1.23 benno 109: ERR("connect");
1.1 benno 110: return -1;
111: }
112:
113: /* Set up non-blocking mode. */
114:
1.5 deraadt 115: if ((flags = fcntl(*sd, F_GETFL, 0)) == -1) {
1.23 benno 116: ERR("fcntl");
1.1 benno 117: return -1;
1.5 deraadt 118: } else if (fcntl(*sd, F_SETFL, flags|O_NONBLOCK) == -1) {
1.23 benno 119: ERR("fcntl");
1.1 benno 120: return -1;
121: }
122:
123: return 1;
124: }
125:
126: /*
127: * Resolve the socket addresses for host, both in IPV4 and IPV6.
128: * Once completed, the "dns" pledge may be dropped.
129: * Returns the addresses on success, NULL on failure (sz is always zero,
130: * in this case).
131: */
132: static struct source *
1.26 ! claudio 133: inet_resolve(struct sess *sess, const char *host, size_t *sz, int passive)
1.1 benno 134: {
135: struct addrinfo hints, *res0, *res;
136: struct sockaddr *sa;
137: struct source *src = NULL;
1.26 ! claudio 138: const char *port = sess->opts->port;
1.1 benno 139: size_t i, srcsz = 0;
140: int error;
141:
142: *sz = 0;
143:
144: memset(&hints, 0, sizeof(hints));
145: hints.ai_family = PF_UNSPEC;
1.12 deraadt 146: hints.ai_socktype = SOCK_STREAM;
1.26 ! claudio 147: if (passive) {
! 148: hints.ai_flags = SOCK_STREAM;
! 149: port = NULL;
! 150: }
1.1 benno 151:
1.26 ! claudio 152: error = getaddrinfo(host, port, &hints, &res0);
1.1 benno 153:
1.23 benno 154: LOG2("resolving: %s", host);
1.1 benno 155:
156: if (error == EAI_AGAIN || error == EAI_NONAME) {
1.23 benno 157: ERRX("could not resolve hostname %s: %s",
1.7 deraadt 158: host, gai_strerror(error));
1.1 benno 159: return NULL;
1.10 deraadt 160: } else if (error == EAI_SERVICE) {
1.23 benno 161: ERRX("could not resolve service rsync: %s",
1.18 benno 162: gai_strerror(error));
1.10 deraadt 163: return NULL;
1.1 benno 164: } else if (error) {
1.23 benno 165: ERRX("getaddrinfo: %s: %s", host, gai_strerror(error));
1.1 benno 166: return NULL;
167: }
168:
169: /* Allocate for all available addresses. */
170:
1.14 deraadt 171: for (res = res0; res != NULL; res = res->ai_next)
1.1 benno 172: if (res->ai_family == AF_INET ||
173: res->ai_family == AF_INET6)
174: srcsz++;
175:
1.5 deraadt 176: if (srcsz == 0) {
1.23 benno 177: ERRX("no addresses resolved: %s", host);
1.1 benno 178: freeaddrinfo(res0);
179: return NULL;
180: }
181:
182: src = calloc(srcsz, sizeof(struct source));
1.5 deraadt 183: if (src == NULL) {
1.23 benno 184: ERRX("calloc");
1.1 benno 185: freeaddrinfo(res0);
186: return NULL;
187: }
188:
1.14 deraadt 189: for (i = 0, res = res0; res != NULL; res = res->ai_next) {
1.1 benno 190: if (res->ai_family != AF_INET &&
191: res->ai_family != AF_INET6)
192: continue;
193:
194: assert(i < srcsz);
195:
196: /* Copy the socket address. */
197:
198: src[i].salen = res->ai_addrlen;
199: memcpy(&src[i].sa, res->ai_addr, src[i].salen);
200:
201: /* Format as a string, too. */
202:
203: sa = res->ai_addr;
1.5 deraadt 204: if (res->ai_family == AF_INET) {
1.1 benno 205: src[i].family = PF_INET;
206: inet_ntop(AF_INET,
1.7 deraadt 207: &(((struct sockaddr_in *)sa)->sin_addr),
208: src[i].ip, INET6_ADDRSTRLEN);
1.1 benno 209: } else {
210: src[i].family = PF_INET6;
211: inet_ntop(AF_INET6,
1.7 deraadt 212: &(((struct sockaddr_in6 *)sa)->sin6_addr),
213: src[i].ip, INET6_ADDRSTRLEN);
1.1 benno 214: }
1.2 benno 215:
1.23 benno 216: LOG2("hostname resolved: %s: %s", host, src[i].ip);
1.1 benno 217: i++;
218: }
219:
220: freeaddrinfo(res0);
221: *sz = srcsz;
222: return src;
223: }
224:
225: /*
226: * Process an rsyncd preamble line.
227: * This is either free-form text or @RSYNCD commands.
228: * Return <0 on failure, 0 on try more lines, >0 on finished.
229: */
230: static int
1.24 benno 231: protocol_line(struct sess *sess, __attribute__((unused)) const char *host,
232: const char *cp)
1.1 benno 233: {
234: int major, minor;
235:
236: if (strncmp(cp, "@RSYNCD: ", 9)) {
1.23 benno 237: LOG0("%s", cp);
1.1 benno 238: return 0;
239: }
240:
241: cp += 9;
242: while (isspace((unsigned char)*cp))
243: cp++;
244:
245: /* @RSYNCD: OK indicates that we're finished. */
246:
1.5 deraadt 247: if (strcmp(cp, "OK") == 0)
1.1 benno 248: return 1;
249:
250: /*
251: * Otherwise, all we have left is our version.
252: * There are two formats: x.y (w/submodule) and x.
253: */
254:
1.5 deraadt 255: if (sscanf(cp, "%d.%d", &major, &minor) == 2) {
1.1 benno 256: sess->rver = major;
257: return 0;
1.5 deraadt 258: } else if (sscanf(cp, "%d", &major) == 1) {
1.1 benno 259: sess->rver = major;
260: return 0;
261: }
262:
1.23 benno 263: ERRX("rsyncd protocol error: unknown command");
1.1 benno 264: return -1;
265: }
266:
267: /*
1.22 naddy 268: * Connect to a remote rsync://-enabled server sender.
269: * Returns exit code 0 on success, 1 on failure.
1.1 benno 270: */
271: int
1.22 naddy 272: rsync_connect(const struct opts *opts, int *sd, const struct fargs *f)
1.1 benno 273: {
274: struct sess sess;
1.26 ! claudio 275: struct source *src = NULL, *bsrc = NULL;
! 276: size_t i, srcsz = 0, bsrcsz = 0;
1.22 naddy 277: int c, rc = 1;
1.1 benno 278:
1.19 deraadt 279: if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw unveil",
280: NULL) == -1)
281: err(1, "pledge");
282:
1.1 benno 283: memset(&sess, 0, sizeof(struct sess));
284: sess.opts = opts;
285:
1.5 deraadt 286: assert(f->host != NULL);
1.1 benno 287:
288: /* Resolve all IP addresses from the host. */
289:
1.26 ! claudio 290: if ((src = inet_resolve(&sess, f->host, &srcsz, 0)) == NULL) {
1.23 benno 291: ERRX1("inet_resolve");
1.19 deraadt 292: exit(1);
1.1 benno 293: }
1.26 ! claudio 294: if (opts->address != NULL)
! 295: if ((bsrc = inet_resolve(&sess, opts->address, &bsrcsz, 1)) ==
! 296: NULL) {
! 297: ERRX1("inet_resolve bind");
! 298: exit(1);
! 299: }
1.1 benno 300:
301: /* Drop the DNS pledge. */
302:
1.19 deraadt 303: if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw inet unveil",
304: NULL) == -1) {
1.23 benno 305: ERR("pledge");
1.19 deraadt 306: exit(1);
1.1 benno 307: }
308:
309: /*
310: * Iterate over all addresses, trying to connect.
311: * When we succeed, then continue using the connected socket.
312: */
313:
314: assert(srcsz);
315: for (i = 0; i < srcsz; i++) {
1.26 ! claudio 316: c = inet_connect(sd, &src[i], f->host, bsrc, bsrcsz);
1.20 deraadt 317: if (c < 0) {
1.23 benno 318: ERRX1("inet_connect");
1.1 benno 319: goto out;
1.20 deraadt 320: } else if (c > 0)
1.1 benno 321: break;
322: }
323:
324: /* Drop the inet pledge. */
1.19 deraadt 325: if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil",
326: NULL) == -1) {
1.23 benno 327: ERR("pledge");
1.1 benno 328: goto out;
329: }
330:
331: if (i == srcsz) {
1.23 benno 332: ERRX("cannot connect to host: %s", f->host);
1.1 benno 333: goto out;
334: }
335:
1.23 benno 336: LOG2("connected: %s, %s", src[i].ip, f->host);
1.22 naddy 337:
338: free(src);
1.26 ! claudio 339: free(bsrc);
1.22 naddy 340: return 0;
341: out:
342: free(src);
1.26 ! claudio 343: free(bsrc);
1.22 naddy 344: if (*sd != -1)
345: close(*sd);
346: return rc;
347: }
348:
349: /*
350: * Talk to a remote rsync://-enabled server sender.
351: * Returns exit code 0 on success, 1 on failure, 2 on failure with
352: * incompatible protocols.
353: */
354: int
355: rsync_socket(const struct opts *opts, int sd, const struct fargs *f)
356: {
357: struct sess sess;
358: size_t i, skip;
359: int c, rc = 1;
360: char **args, buf[BUFSIZ];
361: uint8_t byte;
362:
363: if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil",
364: NULL) == -1)
365: err(1, "pledge");
366:
367: memset(&sess, 0, sizeof(struct sess));
368: sess.lver = RSYNC_PROTOCOL;
369: sess.opts = opts;
370:
371: assert(f->host != NULL);
372: assert(f->module != NULL);
373:
374: if ((args = fargs_cmdline(&sess, f, &skip)) == NULL) {
1.23 benno 375: ERRX1("fargs_cmdline");
1.22 naddy 376: exit(1);
377: }
378:
1.1 benno 379: /* Initiate with the rsyncd version and module request. */
380:
381: (void)snprintf(buf, sizeof(buf), "@RSYNCD: %d", sess.lver);
1.4 deraadt 382: if (!io_write_line(&sess, sd, buf)) {
1.23 benno 383: ERRX1("io_write_line");
1.1 benno 384: goto out;
385: }
386:
1.23 benno 387: LOG2("requesting module: %s, %s", f->module, f->host);
1.1 benno 388:
1.4 deraadt 389: if (!io_write_line(&sess, sd, f->module)) {
1.23 benno 390: ERRX1("io_write_line");
1.1 benno 391: goto out;
392: }
393:
394: /*
395: * Now we read the server's response, byte-by-byte, one newline
396: * terminated at a time, limited to BUFSIZ line length.
397: * For this protocol version, this consists of either @RSYNCD
398: * followed by some text (just "ok" and the remote version) or
399: * the message of the day.
400: */
401:
402: for (;;) {
403: for (i = 0; i < sizeof(buf); i++) {
1.4 deraadt 404: if (!io_read_byte(&sess, sd, &byte)) {
1.23 benno 405: ERRX1("io_read_byte");
1.1 benno 406: goto out;
407: }
1.5 deraadt 408: if ((buf[i] = byte) == '\n')
1.1 benno 409: break;
410: }
411: if (i == sizeof(buf)) {
1.23 benno 412: ERRX("line buffer overrun");
1.1 benno 413: goto out;
1.5 deraadt 414: } else if (i == 0)
1.1 benno 415: continue;
416:
417: /*
418: * The rsyncd protocol isn't very clear as to whether we
419: * get a CRLF or not: I don't actually see this being
420: * transmitted over the wire.
421: */
422:
423: assert(i > 0);
424: buf[i] = '\0';
1.5 deraadt 425: if (buf[i - 1] == '\r')
1.1 benno 426: buf[i - 1] = '\0';
427:
1.20 deraadt 428: if ((c = protocol_line(&sess, f->host, buf)) < 0) {
1.23 benno 429: ERRX1("protocol_line");
1.1 benno 430: goto out;
1.20 deraadt 431: } else if (c > 0)
1.1 benno 432: break;
433: }
434:
435: /*
436: * Now we've exchanged all of our protocol information.
437: * We want to send our command-line arguments over the wire,
438: * each with a newline termination.
439: * Use the same arguments when invoking the server, but leave
440: * off the binary name(s).
441: * Emit a standalone newline afterward.
442: */
443:
1.22 naddy 444: for (i = skip ; args[i] != NULL; i++)
1.4 deraadt 445: if (!io_write_line(&sess, sd, args[i])) {
1.23 benno 446: ERRX1("io_write_line");
1.1 benno 447: goto out;
448: }
1.4 deraadt 449: if (!io_write_byte(&sess, sd, '\n')) {
1.23 benno 450: ERRX1("io_write_line");
1.1 benno 451: goto out;
452: }
453:
454: /*
455: * All data after this point is going to be multiplexed, so turn
456: * on the multiplexer for our reads and writes.
457: */
458:
459: /* Protocol exchange: get the random seed. */
460:
1.4 deraadt 461: if (!io_read_int(&sess, sd, &sess.seed)) {
1.23 benno 462: ERRX1("io_read_int");
1.1 benno 463: goto out;
464: }
465:
466: /* Now we've completed the handshake. */
467:
468: if (sess.rver < sess.lver) {
1.23 benno 469: ERRX("remote protocol is older than our own (%d < %d): "
1.21 deraadt 470: "this is not supported",
471: sess.rver, sess.lver);
1.20 deraadt 472: rc = 2;
1.1 benno 473: goto out;
474: }
475:
476: sess.mplex_reads = 1;
1.23 benno 477: LOG2("read multiplexing enabled");
1.1 benno 478:
1.23 benno 479: LOG2("socket detected client version %d, server version %d, seed %d",
1.21 deraadt 480: sess.lver, sess.rver, sess.seed);
1.1 benno 481:
1.5 deraadt 482: assert(f->mode == FARGS_RECEIVER);
1.1 benno 483:
1.23 benno 484: LOG2("client starting receiver: %s", f->host);
1.4 deraadt 485: if (!rsync_receiver(&sess, sd, sd, f->sink)) {
1.23 benno 486: ERRX1("rsync_receiver");
1.1 benno 487: goto out;
488: }
489:
490: #if 0
491: /* Probably the EOF. */
492: if (io_read_check(&sess, sd))
1.23 benno 493: WARNX("data remains in read pipe");
1.1 benno 494: #endif
495:
1.20 deraadt 496: rc = 0;
1.1 benno 497: out:
498: free(args);
499: return rc;
500: }