xref: /openbsd-src/usr.bin/rsync/socket.c (revision 99fd087599a8791921855f21bd7e36130f39aadc)
1 /*	$Id: socket.c,v 1.27 2019/08/09 13:11:26 claudio 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 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 /*
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 	int	 c, flags;
79 
80 	if (*sd != -1)
81 		close(*sd);
82 
83 	LOG2("trying: %s, %s", src->ip, host);
84 
85 	if ((*sd = socket(src->family, SOCK_STREAM, 0)) == -1) {
86 		ERR("socket");
87 		return -1;
88 	}
89 
90 	if (inet_bind(*sd, src->family, bsrc, bsrcsz) == -1) {
91 		ERR("bind");
92 		return -1;
93 	}
94 
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 
102 	c = connect(*sd, (const struct sockaddr *)&src->sa, src->salen);
103 	if (c == -1) {
104 		if (errno == ECONNREFUSED || errno == EHOSTUNREACH) {
105 			WARNX("connect refused: %s, %s",
106 			    src->ip, host);
107 			return 0;
108 		}
109 		ERR("connect");
110 		return -1;
111 	}
112 
113 	/* Set up non-blocking mode. */
114 
115 	if ((flags = fcntl(*sd, F_GETFL, 0)) == -1) {
116 		ERR("fcntl");
117 		return -1;
118 	} else if (fcntl(*sd, F_SETFL, flags|O_NONBLOCK) == -1) {
119 		ERR("fcntl");
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 *
133 inet_resolve(struct sess *sess, const char *host, size_t *sz, int passive)
134 {
135 	struct addrinfo	 hints, *res0, *res;
136 	struct sockaddr	*sa;
137 	struct source	*src = NULL;
138 	const char	*port = sess->opts->port;
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;
146 	hints.ai_socktype = SOCK_STREAM;
147 	if (passive) {
148 		hints.ai_flags = SOCK_STREAM;
149 		port = NULL;
150 	}
151 
152 	error = getaddrinfo(host, port, &hints, &res0);
153 
154 	LOG2("resolving: %s", host);
155 
156 	if (error == EAI_AGAIN || error == EAI_NONAME) {
157 		ERRX("could not resolve hostname %s: %s",
158 		    host, gai_strerror(error));
159 		return NULL;
160 	} else if (error == EAI_SERVICE) {
161 		ERRX("could not resolve service rsync: %s",
162 		    gai_strerror(error));
163 		return NULL;
164 	} else if (error) {
165 		ERRX("getaddrinfo: %s: %s", host, gai_strerror(error));
166 		return NULL;
167 	}
168 
169 	/* Allocate for all available addresses. */
170 
171 	for (res = res0; res != NULL; res = res->ai_next)
172 		if (res->ai_family == AF_INET ||
173 		    res->ai_family == AF_INET6)
174 			srcsz++;
175 
176 	if (srcsz == 0) {
177 		ERRX("no addresses resolved: %s", host);
178 		freeaddrinfo(res0);
179 		return NULL;
180 	}
181 
182 	src = calloc(srcsz, sizeof(struct source));
183 	if (src == NULL) {
184 		ERRX("calloc");
185 		freeaddrinfo(res0);
186 		return NULL;
187 	}
188 
189 	for (i = 0, res = res0; res != NULL; res = res->ai_next) {
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;
204 		if (res->ai_family == AF_INET) {
205 			src[i].family = PF_INET;
206 			inet_ntop(AF_INET,
207 			    &(((struct sockaddr_in *)sa)->sin_addr),
208 			    src[i].ip, INET6_ADDRSTRLEN);
209 		} else {
210 			src[i].family = PF_INET6;
211 			inet_ntop(AF_INET6,
212 			    &(((struct sockaddr_in6 *)sa)->sin6_addr),
213 			    src[i].ip, INET6_ADDRSTRLEN);
214 		}
215 
216 		LOG2("hostname resolved: %s: %s", host, src[i].ip);
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
231 protocol_line(struct sess *sess, __attribute__((unused)) const char *host,
232     const char *cp)
233 {
234 	int	major, minor;
235 
236 	if (strncmp(cp, "@RSYNCD: ", 9)) {
237 		LOG1("%s", cp);
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 
247 	if (strcmp(cp, "OK") == 0)
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 
255 	if (sscanf(cp, "%d.%d", &major, &minor) == 2) {
256 		sess->rver = major;
257 		return 0;
258 	} else if (sscanf(cp, "%d", &major) == 1) {
259 		sess->rver = major;
260 		return 0;
261 	}
262 
263 	ERRX("rsyncd protocol error: unknown command");
264 	return -1;
265 }
266 
267 /*
268  * Connect to a remote rsync://-enabled server sender.
269  * Returns exit code 0 on success, 1 on failure.
270  */
271 int
272 rsync_connect(const struct opts *opts, int *sd, const struct fargs *f)
273 {
274 	struct sess	  sess;
275 	struct source	 *src = NULL, *bsrc = NULL;
276 	size_t		  i, srcsz = 0, bsrcsz = 0;
277 	int		  c, rc = 1;
278 
279 	if (pledge("stdio unix rpath wpath cpath dpath inet fattr chown dns getpw unveil",
280 	    NULL) == -1)
281 		err(1, "pledge");
282 
283 	memset(&sess, 0, sizeof(struct sess));
284 	sess.opts = opts;
285 
286 	assert(f->host != NULL);
287 
288 	/* Resolve all IP addresses from the host. */
289 
290 	if ((src = inet_resolve(&sess, f->host, &srcsz, 0)) == NULL) {
291 		ERRX1("inet_resolve");
292 		exit(1);
293 	}
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 		}
300 
301 	/* Drop the DNS pledge. */
302 
303 	if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw inet unveil",
304 	    NULL) == -1) {
305 		ERR("pledge");
306 		exit(1);
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++) {
316 		c = inet_connect(sd, &src[i], f->host, bsrc, bsrcsz);
317 		if (c < 0) {
318 			ERRX1("inet_connect");
319 			goto out;
320 		} else if (c > 0)
321 			break;
322 	}
323 
324 	/* Drop the inet pledge. */
325 	if (pledge("stdio unix rpath wpath cpath dpath fattr chown getpw unveil",
326 	    NULL) == -1) {
327 		ERR("pledge");
328 		goto out;
329 	}
330 
331 	if (i == srcsz) {
332 		ERRX("cannot connect to host: %s", f->host);
333 		goto out;
334 	}
335 
336 	LOG2("connected: %s, %s", src[i].ip, f->host);
337 
338 	free(src);
339 	free(bsrc);
340 	return 0;
341 out:
342 	free(src);
343 	free(bsrc);
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) {
375 		ERRX1("fargs_cmdline");
376 		exit(1);
377 	}
378 
379 	/* Initiate with the rsyncd version and module request. */
380 
381 	(void)snprintf(buf, sizeof(buf), "@RSYNCD: %d", sess.lver);
382 	if (!io_write_line(&sess, sd, buf)) {
383 		ERRX1("io_write_line");
384 		goto out;
385 	}
386 
387 	LOG2("requesting module: %s, %s", f->module, f->host);
388 
389 	if (!io_write_line(&sess, sd, f->module)) {
390 		ERRX1("io_write_line");
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++) {
404 			if (!io_read_byte(&sess, sd, &byte)) {
405 				ERRX1("io_read_byte");
406 				goto out;
407 			}
408 			if ((buf[i] = byte) == '\n')
409 				break;
410 		}
411 		if (i == sizeof(buf)) {
412 			ERRX("line buffer overrun");
413 			goto out;
414 		} else if (i == 0)
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';
425 		if (buf[i - 1] == '\r')
426 			buf[i - 1] = '\0';
427 
428 		if ((c = protocol_line(&sess, f->host, buf)) < 0) {
429 			ERRX1("protocol_line");
430 			goto out;
431 		} else if (c > 0)
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 
444 	for (i = skip ; args[i] != NULL; i++)
445 		if (!io_write_line(&sess, sd, args[i])) {
446 			ERRX1("io_write_line");
447 			goto out;
448 		}
449 	if (!io_write_byte(&sess, sd, '\n')) {
450 		ERRX1("io_write_line");
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 
461 	if (!io_read_int(&sess, sd, &sess.seed)) {
462 		ERRX1("io_read_int");
463 		goto out;
464 	}
465 
466 	/* Now we've completed the handshake. */
467 
468 	if (sess.rver < sess.lver) {
469 		ERRX("remote protocol is older than our own (%d < %d): "
470 		    "this is not supported",
471 		    sess.rver, sess.lver);
472 		rc = 2;
473 		goto out;
474 	}
475 
476 	sess.mplex_reads = 1;
477 	LOG2("read multiplexing enabled");
478 
479 	LOG2("socket detected client version %d, server version %d, seed %d",
480 	    sess.lver, sess.rver, sess.seed);
481 
482 	assert(f->mode == FARGS_RECEIVER);
483 
484 	LOG2("client starting receiver: %s", f->host);
485 	if (!rsync_receiver(&sess, sd, sd, f->sink)) {
486 		ERRX1("rsync_receiver");
487 		goto out;
488 	}
489 
490 #if 0
491 	/* Probably the EOF. */
492 	if (io_read_check(&sess, sd))
493 		WARNX("data remains in read pipe");
494 #endif
495 
496 	rc = 0;
497 out:
498 	free(args);
499 	return rc;
500 }
501