xref: /openbsd/usr.bin/rsync/socket.c (revision d415bd75)
1 /*	$OpenBSD: socket.c,v 1.33 2022/12/26 19:16:02 jmc Exp $ */
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>
33 #include <err.h>
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 {
42 	int		 family; /* PF_INET or PF_INET6 */
43 	char		 ip[INET6_ADDRSTRLEN]; /* formatted string */
44 	struct sockaddr_storage sa; /* socket */
45 	socklen_t	 salen; /* length of socket buffer */
46 };
47 
48 /*
49  * Try to bind to a local IP address matching the address 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 /*
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
75 inet_connect(int *sd, const struct source *src, const char *host,
76     const struct source *bsrc, size_t bsrcsz)
77 {
78 	struct pollfd	pfd;
79 	socklen_t	optlen;
80 	int		c;
81 	int		optval;
82 
83 	if (*sd != -1)
84 		close(*sd);
85 
86 	LOG2("trying: %s, %s", src->ip, host);
87 
88 	if ((*sd = socket(src->family, SOCK_STREAM | SOCK_NONBLOCK, 0))
89 	    == -1) {
90 		ERR("socket");
91 		return -1;
92 	}
93 
94 	if (inet_bind(*sd, src->family, bsrc, bsrcsz) == -1) {
95 		ERR("bind");
96 		return -1;
97 	}
98 
99 	/*
100 	 * Initiate blocking connection.
101 	 * We use non-blocking connect() so we can poll() for contimeout.
102 	 */
103 
104 	if ((c = connect(*sd, (const struct sockaddr *)&src->sa, src->salen))
105 	    != 0 && errno == EINPROGRESS) {
106 		pfd.fd = *sd;
107 		pfd.events = POLLOUT;
108 		switch (c = poll(&pfd, 1, poll_contimeout)) {
109 		case 1:
110 			optlen = sizeof(optval);
111 			if ((c = getsockopt(*sd, SOL_SOCKET, SO_ERROR, &optval,
112 			    &optlen)) == 0) {
113 				errno = optval;
114 				if (optval != 0)
115 					c = -1;
116 			}
117 			break;
118 		case 0:
119 			errno = ETIMEDOUT;
120 			WARNX("connect timeout: %s, %s", src->ip, host);
121 			return 0;
122 		default:
123 			ERR("poll failed");
124 			return -1;
125 		}
126 	}
127 	if (c == -1) {
128 		if (errno == EADDRNOTAVAIL)
129 			return 0;
130 		if (errno == ECONNREFUSED || errno == EHOSTUNREACH) {
131 			WARNX("connect refused: %s, %s", src->ip, host);
132 			return 0;
133 		}
134 		ERR("connect");
135 		return -1;
136 	}
137 
138 	return 1;
139 }
140 
141 /*
142  * Resolve the socket addresses for host, both in IPV4 and IPV6.
143  * Once completed, the "dns" pledge may be dropped.
144  * Returns the addresses on success, NULL on failure (sz is always zero,
145  * in this case).
146  */
147 static struct source *
148 inet_resolve(struct sess *sess, const char *host, size_t *sz, int passive)
149 {
150 	struct addrinfo	 hints, *res0, *res;
151 	struct sockaddr	*sa;
152 	struct source	*src = NULL;
153 	const char	*port = sess->opts->port;
154 	size_t		 i, srcsz = 0;
155 	int		 error;
156 
157 	*sz = 0;
158 
159 	memset(&hints, 0, sizeof(hints));
160 	hints.ai_family = PF_UNSPEC;
161 	hints.ai_socktype = SOCK_STREAM;
162 	if (passive) {
163 		hints.ai_flags = SOCK_STREAM;
164 		port = NULL;
165 	}
166 
167 	error = getaddrinfo(host, port, &hints, &res0);
168 
169 	LOG2("resolving: %s", host);
170 
171 	if (error == EAI_AGAIN || error == EAI_NONAME) {
172 		ERRX("could not resolve hostname %s: %s",
173 		    host, gai_strerror(error));
174 		return NULL;
175 	} else if (error == EAI_SERVICE) {
176 		ERRX("could not resolve service rsync: %s",
177 		    gai_strerror(error));
178 		return NULL;
179 	} else if (error) {
180 		ERRX("getaddrinfo: %s: %s", host, gai_strerror(error));
181 		return NULL;
182 	}
183 
184 	/* Allocate for all available addresses. */
185 
186 	for (res = res0; res != NULL; res = res->ai_next)
187 		if (res->ai_family == AF_INET ||
188 		    res->ai_family == AF_INET6)
189 			srcsz++;
190 
191 	if (srcsz == 0) {
192 		ERRX("no addresses resolved: %s", host);
193 		freeaddrinfo(res0);
194 		return NULL;
195 	}
196 
197 	src = calloc(srcsz, sizeof(struct source));
198 	if (src == NULL) {
199 		ERRX("calloc");
200 		freeaddrinfo(res0);
201 		return NULL;
202 	}
203 
204 	for (i = 0, res = res0; res != NULL; res = res->ai_next) {
205 		if (res->ai_family != AF_INET &&
206 		    res->ai_family != AF_INET6)
207 			continue;
208 
209 		assert(i < srcsz);
210 
211 		/* Copy the socket address. */
212 
213 		src[i].salen = res->ai_addrlen;
214 		memcpy(&src[i].sa, res->ai_addr, src[i].salen);
215 
216 		/* Format as a string, too. */
217 
218 		sa = res->ai_addr;
219 		if (res->ai_family == AF_INET) {
220 			src[i].family = PF_INET;
221 			inet_ntop(AF_INET,
222 			    &(((struct sockaddr_in *)sa)->sin_addr),
223 			    src[i].ip, INET6_ADDRSTRLEN);
224 		} else {
225 			src[i].family = PF_INET6;
226 			inet_ntop(AF_INET6,
227 			    &(((struct sockaddr_in6 *)sa)->sin6_addr),
228 			    src[i].ip, INET6_ADDRSTRLEN);
229 		}
230 
231 		LOG2("hostname resolved: %s: %s", host, src[i].ip);
232 		i++;
233 	}
234 
235 	freeaddrinfo(res0);
236 	*sz = srcsz;
237 	return src;
238 }
239 
240 /*
241  * Process an rsyncd preamble line.
242  * This is either free-form text or @RSYNCD commands.
243  * Return <0 on failure, 0 on try more lines, >0 on finished.
244  */
245 static int
246 protocol_line(struct sess *sess, __attribute__((unused)) const char *host,
247     const char *cp)
248 {
249 	int	major, minor;
250 
251 	if (strncmp(cp, "@RSYNCD: ", 9)) {
252 		if (sess->opts->no_motd == 0)
253 			LOG1("%s", cp);
254 		return 0;
255 	}
256 
257 	cp += 9;
258 	while (isspace((unsigned char)*cp))
259 		cp++;
260 
261 	/* @RSYNCD: OK indicates that we're finished. */
262 
263 	if (strcmp(cp, "OK") == 0)
264 		return 1;
265 
266 	/*
267 	 * Otherwise, all we have left is our version.
268 	 * There are two formats: x.y (w/submodule) and x.
269 	 */
270 
271 	if (sscanf(cp, "%d.%d", &major, &minor) == 2) {
272 		sess->rver = major;
273 		return 0;
274 	} else if (sscanf(cp, "%d", &major) == 1) {
275 		sess->rver = major;
276 		return 0;
277 	}
278 
279 	ERRX("rsyncd protocol error: unknown command");
280 	return -1;
281 }
282 
283 /*
284  * Connect to a remote rsync://-enabled server sender.
285  * Returns exit code 0 on success, 1 on failure.
286  */
287 int
288 rsync_connect(const struct opts *opts, int *sd, const struct fargs *f)
289 {
290 	struct sess	  sess;
291 	struct source	 *src = NULL, *bsrc = NULL;
292 	size_t		  i, srcsz = 0, bsrcsz = 0;
293 	int		  c, rc = 1;
294 
295 	if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw unveil",
296 	    NULL) == -1)
297 		err(ERR_IPC, "pledge");
298 
299 	memset(&sess, 0, sizeof(struct sess));
300 	sess.opts = opts;
301 
302 	assert(f->host != NULL);
303 
304 	/* Resolve all IP addresses from the host. */
305 
306 	if ((src = inet_resolve(&sess, f->host, &srcsz, 0)) == NULL) {
307 		ERRX1("inet_resolve");
308 		exit(1);
309 	}
310 	if (opts->address != NULL)
311 		if ((bsrc = inet_resolve(&sess, opts->address, &bsrcsz, 1)) ==
312 		    NULL) {
313 			ERRX1("inet_resolve bind");
314 			exit(1);
315 		}
316 
317 	/* Drop the DNS pledge. */
318 
319 	if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw inet unveil",
320 	    NULL) == -1) {
321 		ERR("pledge");
322 		exit(1);
323 	}
324 
325 	/*
326 	 * Iterate over all addresses, trying to connect.
327 	 * When we succeed, then continue using the connected socket.
328 	 */
329 
330 	assert(srcsz);
331 	for (i = 0; i < srcsz; i++) {
332 		c = inet_connect(sd, &src[i], f->host, bsrc, bsrcsz);
333 		if (c < 0) {
334 			ERRX1("inet_connect");
335 			goto out;
336 		} else if (c > 0)
337 			break;
338 	}
339 
340 	/* Drop the inet pledge. */
341 	if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil",
342 	    NULL) == -1) {
343 		ERR("pledge");
344 		goto out;
345 	}
346 
347 	if (i == srcsz) {
348 		ERRX("cannot connect to host: %s", f->host);
349 		goto out;
350 	}
351 
352 	LOG2("connected: %s, %s", src[i].ip, f->host);
353 
354 	free(src);
355 	free(bsrc);
356 	return 0;
357 out:
358 	free(src);
359 	free(bsrc);
360 	if (*sd != -1)
361 		close(*sd);
362 	return rc;
363 }
364 
365 /*
366  * Talk to a remote rsync://-enabled server sender.
367  * Returns exit code 0 on success, 1 on failure, 2 on failure with
368  * incompatible protocols.
369  */
370 int
371 rsync_socket(const struct opts *opts, int sd, const struct fargs *f)
372 {
373 	struct sess	  sess;
374 	size_t		  i, skip;
375 	int		  c, rc = 1;
376 	char		**args, buf[BUFSIZ];
377 	uint8_t		  byte;
378 
379 	if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil",
380 	    NULL) == -1)
381 		err(ERR_IPC, "pledge");
382 
383 	memset(&sess, 0, sizeof(struct sess));
384 	sess.lver = RSYNC_PROTOCOL;
385 	sess.opts = opts;
386 
387 	assert(f->host != NULL);
388 	assert(f->module != NULL);
389 
390 	args = fargs_cmdline(&sess, f, &skip);
391 
392 	/* Initiate with the rsyncd version and module request. */
393 
394 	(void)snprintf(buf, sizeof(buf), "@RSYNCD: %d", sess.lver);
395 	if (!io_write_line(&sess, sd, buf)) {
396 		ERRX1("io_write_line");
397 		goto out;
398 	}
399 
400 	LOG2("requesting module: %s, %s", f->module, f->host);
401 
402 	if (!io_write_line(&sess, sd, f->module)) {
403 		ERRX1("io_write_line");
404 		goto out;
405 	}
406 
407 	/*
408 	 * Now we read the server's response, byte-by-byte, one newline
409 	 * terminated at a time, limited to BUFSIZ line length.
410 	 * For this protocol version, this consists of either @RSYNCD
411 	 * followed by some text (just "ok" and the remote version) or
412 	 * the message of the day.
413 	 */
414 
415 	for (;;) {
416 		for (i = 0; i < sizeof(buf); i++) {
417 			if (!io_read_byte(&sess, sd, &byte)) {
418 				ERRX1("io_read_byte");
419 				goto out;
420 			}
421 			if ((buf[i] = byte) == '\n')
422 				break;
423 		}
424 		if (i == sizeof(buf)) {
425 			ERRX("line buffer overrun");
426 			goto out;
427 		} else if (i == 0)
428 			continue;
429 
430 		/*
431 		 * The rsyncd protocol isn't very clear as to whether we
432 		 * get a CRLF or not: I don't actually see this being
433 		 * transmitted over the wire.
434 		 */
435 
436 		assert(i > 0);
437 		buf[i] = '\0';
438 		if (buf[i - 1] == '\r')
439 			buf[i - 1] = '\0';
440 
441 		if ((c = protocol_line(&sess, f->host, buf)) < 0) {
442 			ERRX1("protocol_line");
443 			goto out;
444 		} else if (c > 0)
445 			break;
446 	}
447 
448 	/*
449 	 * Now we've exchanged all of our protocol information.
450 	 * We want to send our command-line arguments over the wire,
451 	 * each with a newline termination.
452 	 * Use the same arguments when invoking the server, but leave
453 	 * off the binary name(s).
454 	 * Emit a standalone newline afterward.
455 	 */
456 
457 	for (i = skip ; args[i] != NULL; i++)
458 		if (!io_write_line(&sess, sd, args[i])) {
459 			ERRX1("io_write_line");
460 			goto out;
461 		}
462 	if (!io_write_byte(&sess, sd, '\n')) {
463 		ERRX1("io_write_line");
464 		goto out;
465 	}
466 
467 	/*
468 	 * All data after this point is going to be multiplexed, so turn
469 	 * on the multiplexer for our reads and writes.
470 	 */
471 
472 	/* Protocol exchange: get the random seed. */
473 
474 	if (!io_read_int(&sess, sd, &sess.seed)) {
475 		ERRX1("io_read_int");
476 		goto out;
477 	}
478 
479 	/* Now we've completed the handshake. */
480 
481 	if (sess.rver < sess.lver) {
482 		ERRX("remote protocol is older than our own (%d < %d): "
483 		    "this is not supported",
484 		    sess.rver, sess.lver);
485 		rc = 2;
486 		goto out;
487 	}
488 
489 	sess.mplex_reads = 1;
490 	LOG2("read multiplexing enabled");
491 
492 	LOG2("socket detected client version %d, server version %d, seed %d",
493 	    sess.lver, sess.rver, sess.seed);
494 
495 	assert(f->mode == FARGS_RECEIVER);
496 
497 	LOG2("client starting receiver: %s", f->host);
498 	if (!rsync_receiver(&sess, sd, sd, f->sink)) {
499 		ERRX1("rsync_receiver");
500 		goto out;
501 	}
502 
503 #if 0
504 	/* Probably the EOF. */
505 	if (io_read_check(&sess, sd))
506 		WARNX("data remains in read pipe");
507 #endif
508 
509 	rc = 0;
510 out:
511 	free(args);
512 	return rc;
513 }
514