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