00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "rsync.h"
00035
00036
00037
00038
00039
00040
00041 static int establish_proxy_connection(int fd, char *host, int port)
00042 {
00043 char buffer[1024];
00044 char *cp;
00045
00046 snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
00047 if (write(fd, buffer, strlen(buffer)) != (int) strlen(buffer)) {
00048 rprintf(FERROR, "failed to write to proxy: %s\n",
00049 strerror(errno));
00050 return -1;
00051 }
00052
00053 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; cp++) {
00054 if (read(fd, cp, 1) != 1) {
00055 rprintf(FERROR, "failed to read from proxy: %s\n",
00056 strerror(errno));
00057 return -1;
00058 }
00059 if (*cp == '\n')
00060 break;
00061 }
00062
00063 if (*cp != '\n')
00064 cp++;
00065 *cp-- = '\0';
00066 if (*cp == '\r')
00067 *cp = '\0';
00068 if (strncmp(buffer, "HTTP/", 5) != 0) {
00069 rprintf(FERROR, "bad response from proxy - %s\n",
00070 buffer);
00071 return -1;
00072 }
00073 for (cp = &buffer[5]; isdigit(* (unsigned char *) cp) || (*cp == '.'); cp++)
00074 ;
00075 while (*cp == ' ')
00076 cp++;
00077 if (*cp != '2') {
00078 rprintf(FERROR, "bad response from proxy - %s\n",
00079 buffer);
00080 return -1;
00081 }
00082
00083 while (1) {
00084 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1];
00085 cp++) {
00086 if (read(fd, cp, 1) != 1) {
00087 rprintf(FERROR, "failed to read from proxy: %s\n",
00088 strerror(errno));
00089 return -1;
00090 }
00091 if (*cp == '\n')
00092 break;
00093 }
00094 if ((cp > buffer) && (*cp == '\n'))
00095 cp--;
00096 if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r')))
00097 break;
00098 }
00099 return 0;
00100 }
00101
00102
00103
00104
00105
00106
00107 int try_bind_local(int s,
00108 int ai_family, int ai_socktype,
00109 const char *bind_address)
00110 {
00111 int error;
00112 struct addrinfo bhints, *bres_all, *r;
00113
00114 memset(&bhints, 0, sizeof(bhints));
00115 bhints.ai_family = ai_family;
00116 bhints.ai_socktype = ai_socktype;
00117 bhints.ai_flags = AI_PASSIVE;
00118 if ((error = getaddrinfo(bind_address, NULL, &bhints, &bres_all))) {
00119 rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n",
00120 bind_address, gai_strerror(error));
00121 return -1;
00122 }
00123
00124 for (r = bres_all; r; r = r->ai_next) {
00125 if (bind(s, r->ai_addr, r->ai_addrlen) == -1)
00126 continue;
00127 freeaddrinfo(bres_all);
00128 return s;
00129 }
00130
00131
00132
00133
00134 freeaddrinfo(bres_all);
00135 return -1;
00136 }
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 int open_socket_out(char *host, int port, const char *bind_address,
00160 int af_hint)
00161 {
00162 int type = SOCK_STREAM;
00163 int error;
00164 int s;
00165 struct addrinfo hints, *res0, *res;
00166 char portbuf[10];
00167 char *h;
00168 int proxied = 0;
00169 char buffer[1024];
00170 char *cp;
00171
00172
00173
00174
00175 h = getenv("RSYNC_PROXY");
00176 proxied = (h != NULL) && (*h != '\0');
00177
00178 if (proxied) {
00179 strlcpy(buffer, h, sizeof(buffer));
00180 cp = strchr(buffer, ':');
00181 if (cp == NULL) {
00182 rprintf(FERROR,
00183 "invalid proxy specification: should be HOST:PORT\n");
00184 return -1;
00185 }
00186 *cp++ = '\0';
00187 strcpy(portbuf, cp);
00188 h = buffer;
00189 if (verbose >= 2) {
00190 rprintf(FINFO, "connection via http proxy %s port %s\n",
00191 h, portbuf);
00192 }
00193 } else {
00194 snprintf(portbuf, sizeof(portbuf), "%d", port);
00195 h = host;
00196 }
00197
00198 memset(&hints, 0, sizeof(hints));
00199 hints.ai_family = af_hint;
00200 hints.ai_socktype = type;
00201 error = getaddrinfo(h, portbuf, &hints, &res0);
00202 if (error) {
00203 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: %s %s: %s\n",
00204 h, portbuf, gai_strerror(error));
00205 return -1;
00206 }
00207
00208 s = -1;
00209
00210
00211
00212
00213 for (res = res0; res; res = res->ai_next) {
00214 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
00215 if (s < 0)
00216 continue;
00217
00218 if (bind_address)
00219 if (try_bind_local(s, res->ai_family, type,
00220 bind_address) == -1) {
00221 close(s);
00222 s = -1;
00223 continue;
00224 }
00225
00226 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
00227 close(s);
00228 s = -1;
00229 continue;
00230 }
00231 if (proxied &&
00232 establish_proxy_connection(s, host, port) != 0) {
00233 close(s);
00234 s = -1;
00235 continue;
00236 } else
00237 break;
00238 }
00239 freeaddrinfo(res0);
00240 if (s < 0) {
00241 rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
00242 h, strerror(errno));
00243 return -1;
00244 }
00245 return s;
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261 int open_socket_out_wrapped (char *host,
00262 int port,
00263 const char *bind_address,
00264 int af_hint)
00265 {
00266 char *prog;
00267
00268 if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
00269 return sock_exec (prog);
00270 else
00271 return open_socket_out (host, port, bind_address,
00272 af_hint);
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291
00292
00293
00294
00295 static int open_socket_in(int type, int port, const char *bind_address,
00296 int af_hint)
00297 {
00298 int one=1;
00299 int s;
00300 struct addrinfo hints, *all_ai, *resp;
00301 char portbuf[10];
00302 int error;
00303
00304 memset(&hints, 0, sizeof(hints));
00305 hints.ai_family = af_hint;
00306 hints.ai_socktype = type;
00307 hints.ai_flags = AI_PASSIVE;
00308 snprintf(portbuf, sizeof(portbuf), "%d", port);
00309 error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
00310 if (error) {
00311 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
00312 bind_address, gai_strerror(error));
00313 return -1;
00314 }
00315
00316
00317
00318
00319 for (resp = all_ai; resp; resp = resp->ai_next) {
00320 s = socket(resp->ai_family, resp->ai_socktype,
00321 resp->ai_protocol);
00322
00323 if (s == -1)
00324
00325 continue;
00326
00327 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
00328 (char *)&one, sizeof one);
00329
00330
00331 if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) {
00332
00333 close(s);
00334 continue;
00335 }
00336
00337 freeaddrinfo(all_ai);
00338 return s;
00339 }
00340
00341 rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
00342 "%s\n",
00343 port,
00344 strerror(errno));
00345
00346 freeaddrinfo(all_ai);
00347 return -1;
00348 }
00349
00350
00351
00352
00353
00354 int is_a_socket(int fd)
00355 {
00356 int v;
00357 socklen_t l;
00358 l = sizeof(int);
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373 return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
00374 }
00375
00376
00377 void start_accept_loop(int port, int (*fn)(int ))
00378 {
00379 int s;
00380 extern char *bind_address;
00381 extern int default_af_hint;
00382
00383
00384 s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
00385 if (s == -1)
00386 exit_cleanup(RERR_SOCKETIO);
00387
00388
00389 if (listen(s, 5) == -1) {
00390 close(s);
00391 exit_cleanup(RERR_SOCKETIO);
00392 }
00393
00394
00395
00396
00397 while (1) {
00398 fd_set fds;
00399 pid_t pid;
00400 int fd;
00401 struct sockaddr_storage addr;
00402 socklen_t addrlen = sizeof addr;
00403
00404
00405
00406
00407 log_close();
00408
00409 FD_ZERO(&fds);
00410 FD_SET(s, &fds);
00411
00412 if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
00413 continue;
00414 }
00415
00416 if(!FD_ISSET(s, &fds)) continue;
00417
00418 fd = accept(s,(struct sockaddr *)&addr,&addrlen);
00419
00420 if (fd == -1) continue;
00421
00422 signal(SIGCHLD, SIG_IGN);
00423
00424
00425
00426
00427 #ifdef WNOHANG
00428 while (waitpid(-1, NULL, WNOHANG) > 0);
00429 #endif
00430
00431 if ((pid = fork()) == 0) {
00432 close(s);
00433
00434
00435 log_open();
00436 _exit(fn(fd));
00437 } else if (pid < 0) {
00438 rprintf(FERROR,
00439 RSYNC_NAME
00440 ": could not create child server process: %s\n",
00441 strerror(errno));
00442 close(fd);
00443
00444
00445
00446 sleep(2);
00447 } else {
00448
00449 close(fd);
00450 }
00451 }
00452 }
00453
00454
00455 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
00456
00457 struct
00458 {
00459 char *name;
00460 int level;
00461 int option;
00462 int value;
00463 int opttype;
00464 } socket_options[] = {
00465 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
00466 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
00467 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
00468 #ifdef TCP_NODELAY
00469 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
00470 #endif
00471 #ifdef IPTOS_LOWDELAY
00472 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
00473 #endif
00474 #ifdef IPTOS_THROUGHPUT
00475 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
00476 #endif
00477 #ifdef SO_SNDBUF
00478 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
00479 #endif
00480 #ifdef SO_RCVBUF
00481 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
00482 #endif
00483 #ifdef SO_SNDLOWAT
00484 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
00485 #endif
00486 #ifdef SO_RCVLOWAT
00487 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
00488 #endif
00489 #ifdef SO_SNDTIMEO
00490 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
00491 #endif
00492 #ifdef SO_RCVTIMEO
00493 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
00494 #endif
00495 {NULL,0,0,0,0}};
00496
00497
00498
00499
00500
00501
00502 void set_socket_options(int fd, char *options)
00503 {
00504 char *tok;
00505 if (!options || !*options) return;
00506
00507 options = strdup(options);
00508
00509 if (!options) out_of_memory("set_socket_options");
00510
00511 for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
00512 int ret=0,i;
00513 int value = 1;
00514 char *p;
00515 int got_value = 0;
00516
00517 if ((p = strchr(tok,'='))) {
00518 *p = 0;
00519 value = atoi(p+1);
00520 got_value = 1;
00521 }
00522
00523 for (i=0;socket_options[i].name;i++)
00524 if (strcmp(socket_options[i].name,tok)==0)
00525 break;
00526
00527 if (!socket_options[i].name) {
00528 rprintf(FERROR,"Unknown socket option %s\n",tok);
00529 continue;
00530 }
00531
00532 switch (socket_options[i].opttype) {
00533 case OPT_BOOL:
00534 case OPT_INT:
00535 ret = setsockopt(fd,socket_options[i].level,
00536 socket_options[i].option,(char *)&value,sizeof(int));
00537 break;
00538
00539 case OPT_ON:
00540 if (got_value)
00541 rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
00542
00543 {
00544 int on = socket_options[i].value;
00545 ret = setsockopt(fd,socket_options[i].level,
00546 socket_options[i].option,(char *)&on,sizeof(int));
00547 }
00548 break;
00549 }
00550
00551 if (ret != 0)
00552 rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
00553 strerror(errno));
00554 }
00555
00556 free(options);
00557 }
00558
00559
00560
00561
00562 void become_daemon(void)
00563 {
00564 int i;
00565
00566 if (fork()) {
00567 _exit(0);
00568 }
00569
00570
00571 #ifdef HAVE_SETSID
00572 setsid();
00573 #else
00574 #ifdef TIOCNOTTY
00575 i = open("/dev/tty", O_RDWR);
00576 if (i >= 0) {
00577 ioctl(i, (int) TIOCNOTTY, (char *)0);
00578 close(i);
00579 }
00580 #endif
00581 #endif
00582
00583
00584 for (i=0;i<3;i++) {
00585 close(i);
00586 open("/dev/null", O_RDWR);
00587 }
00588 }
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600 static int socketpair_tcp(int fd[2])
00601 {
00602 int listener;
00603 struct sockaddr_in sock;
00604 struct sockaddr_in sock2;
00605 socklen_t socklen = sizeof(sock);
00606 int connect_done = 0;
00607
00608 fd[0] = fd[1] = listener = -1;
00609
00610 memset(&sock, 0, sizeof(sock));
00611
00612 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
00613
00614 memset(&sock2, 0, sizeof(sock2));
00615 #ifdef HAVE_SOCKADDR_LEN
00616 sock2.sin_len = sizeof(sock2);
00617 #endif
00618 sock2.sin_family = PF_INET;
00619
00620 bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
00621
00622 if (listen(listener, 1) != 0) goto failed;
00623
00624 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
00625
00626 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
00627
00628 set_nonblocking(fd[1]);
00629
00630 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
00631
00632 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
00633 if (errno != EINPROGRESS) goto failed;
00634 } else {
00635 connect_done = 1;
00636 }
00637
00638 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
00639
00640 close(listener);
00641 if (connect_done == 0) {
00642 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
00643 && errno != EISCONN) goto failed;
00644 }
00645
00646 set_blocking (fd[1]);
00647
00648
00649 return 0;
00650
00651 failed:
00652 if (fd[0] != -1) close(fd[0]);
00653 if (fd[1] != -1) close(fd[1]);
00654 if (listener != -1) close(listener);
00655 return -1;
00656 }
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669 int sock_exec(const char *prog)
00670 {
00671 int fd[2];
00672
00673 if (socketpair_tcp(fd) != 0) {
00674 rprintf (FERROR, RSYNC_NAME
00675 ": socketpair_tcp failed (%s)\n",
00676 strerror(errno));
00677 return -1;
00678 }
00679 if (fork() == 0) {
00680 close(fd[0]);
00681 close(0);
00682 close(1);
00683 dup(fd[1]);
00684 dup(fd[1]);
00685 if (verbose > 3) {
00686
00687 fprintf (stderr,
00688 RSYNC_NAME ": execute socket program \"%s\"\n",
00689 prog);
00690 }
00691 exit (system (prog));
00692 }
00693 close (fd[1]);
00694 return fd[0];
00695 }
00696
00697
00698