version 1.1, 2012/02/17 15:09:30
|
version 1.1.1.4, 2021/03/17 00:32:36
|
Line 3
|
Line 3
|
* |
* |
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org> |
* Copyright (C) 1992-2001 Andrew Tridgell <tridge@samba.org> |
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org> |
* Copyright (C) 2001, 2002 Martin Pool <mbp@samba.org> |
* Copyright (C) 2003-2009 Wayne Davison | * Copyright (C) 2003-2020 Wayne Davison |
* |
* |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
Line 25
|
Line 25
|
* emulate it using the KAME implementation. */ |
* emulate it using the KAME implementation. */ |
|
|
#include "rsync.h" |
#include "rsync.h" |
|
#include "itypes.h" |
#include "ifuncs.h" |
#include "ifuncs.h" |
#ifdef HAVE_NETINET_IN_SYSTM_H |
#ifdef HAVE_NETINET_IN_SYSTM_H |
#include <netinet/in_systm.h> |
#include <netinet/in_systm.h> |
Line 38 extern char *bind_address;
|
Line 39 extern char *bind_address;
|
extern char *sockopts; |
extern char *sockopts; |
extern int default_af_hint; |
extern int default_af_hint; |
extern int connect_timeout; |
extern int connect_timeout; |
|
extern int pid_file_fd; |
|
extern int diffserv; |
|
extern char *congestion_alg; |
|
|
#ifdef HAVE_SIGACTION |
#ifdef HAVE_SIGACTION |
static struct sigaction sigact; |
static struct sigaction sigact; |
Line 48 static int sock_exec(const char *prog);
|
Line 52 static int sock_exec(const char *prog);
|
/* Establish a proxy connection on an open socket to a web proxy by using the |
/* Establish a proxy connection on an open socket to a web proxy by using the |
* CONNECT method. If proxy_user and proxy_pass are not NULL, they are used to |
* CONNECT method. If proxy_user and proxy_pass are not NULL, they are used to |
* authenticate to the proxy using the "Basic" proxy-authorization protocol. */ |
* authenticate to the proxy using the "Basic" proxy-authorization protocol. */ |
static int establish_proxy_connection(int fd, char *host, int port, | static int establish_proxy_connection(int fd, char *host, int port, char *proxy_user, char *proxy_pass) |
char *proxy_user, char *proxy_pass) | |
{ |
{ |
char *cp, buffer[1024]; |
char *cp, buffer[1024]; |
char *authhdr, authbuf[1024]; |
char *authhdr, authbuf[1024]; |
Line 73 static int establish_proxy_connection(int fd, char *ho
|
Line 76 static int establish_proxy_connection(int fd, char *ho
|
authhdr = ""; |
authhdr = ""; |
} |
} |
|
|
snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n", | len = snprintf(buffer, sizeof buffer, "CONNECT %s:%d HTTP/1.0%s%s\r\n\r\n", host, port, authhdr, authbuf); |
host, port, authhdr, authbuf); | assert(len > 0 && len < (int)sizeof buffer); |
len = strlen(buffer); | |
if (write(fd, buffer, len) != len) { |
if (write(fd, buffer, len) != len) { |
rsyserr(FERROR, errno, "failed to write to proxy"); |
rsyserr(FERROR, errno, "failed to write to proxy"); |
return -1; |
return -1; |
Line 161 int try_bind_local(int s, int ai_family, int ai_sockty
|
Line 163 int try_bind_local(int s, int ai_family, int ai_sockty
|
} |
} |
|
|
/* connect() timeout handler based on alarm() */ |
/* connect() timeout handler based on alarm() */ |
static RETSIGTYPE contimeout_handler(UNUSED(int val)) | static void contimeout_handler(UNUSED(int val)) |
{ |
{ |
connect_timeout = -1; |
connect_timeout = -1; |
} |
} |
|
|
|
/* Set special socket options |
|
* |
|
* Diffserv is a value in the range of 0-63, and needs to be shifted left |
|
* 2 places AND treated differently for ipv4 and ipv6. |
|
* Setting TCP congestion control is rather Linux specific (at the moment) |
|
* and sends a varying length string to setsockopt rather than an integer |
|
* or character. |
|
*/ |
|
|
|
void set_special_sockopts(int s) |
|
{ |
|
#if defined(TCP_CONGESTION) |
|
if (congestion_alg) { |
|
if (setsockopt(s, SOL_TCP, TCP_CONGESTION, congestion_alg, strlen(congestion_alg)) == -1) |
|
rprintf(FINFO, "Couldn't set %s congestion algorithm\n", congestion_alg); |
|
} |
|
#endif |
|
|
|
/* setting the diffserv/tos bits is different on ipv6 and |
|
* ipv4, so we just hammer down on both and ignore the result |
|
* And ipv6 demands an int for v. I didn't write the spec. |
|
*/ |
|
if (diffserv) { |
|
int v = (diffserv & 63) <<2; |
|
setsockopt(s,IPPROTO_IP, IP_TOS, &v, sizeof(v)); |
|
#if defined(IPV6_TCLASS) |
|
setsockopt(s,IPPROTO_IPV6, IPV6_TCLASS, &v, sizeof(v)); |
|
#endif |
|
} |
|
} |
|
|
/* Open a socket to a tcp remote host with the specified port. |
/* Open a socket to a tcp remote host with the specified port. |
* |
* |
* Based on code from Warren. Proxy support by Stephen Rothwell. |
* Based on code from Warren. Proxy support by Stephen Rothwell. |
Line 182 static RETSIGTYPE contimeout_handler(UNUSED(int val))
|
Line 215 static RETSIGTYPE contimeout_handler(UNUSED(int val))
|
* bind_addr: local address to use. Normally NULL to bind the wildcard address. |
* bind_addr: local address to use. Normally NULL to bind the wildcard address. |
* |
* |
* af_hint: address family, e.g. AF_INET or AF_INET6. */ |
* af_hint: address family, e.g. AF_INET or AF_INET6. */ |
int open_socket_out(char *host, int port, const char *bind_addr, | int open_socket_out(char *host, int port, const char *bind_addr, int af_hint) |
int af_hint) | |
{ |
{ |
int type = SOCK_STREAM; |
int type = SOCK_STREAM; |
int error, s, j, addr_cnt, *errnos; |
int error, s, j, addr_cnt, *errnos; |
Line 195 int open_socket_out(char *host, int port, const char *
|
Line 227 int open_socket_out(char *host, int port, const char *
|
char *proxy_user = NULL, *proxy_pass = NULL; |
char *proxy_user = NULL, *proxy_pass = NULL; |
|
|
/* if we have a RSYNC_PROXY env variable then redirect our |
/* if we have a RSYNC_PROXY env variable then redirect our |
* connetcion via a web proxy at the given address. */ | * connection via a web proxy at the given address. */ |
h = getenv("RSYNC_PROXY"); |
h = getenv("RSYNC_PROXY"); |
proxied = h != NULL && *h != '\0'; |
proxied = h != NULL && *h != '\0'; |
|
|
Line 229 int open_socket_out(char *host, int port, const char *
|
Line 261 int open_socket_out(char *host, int port, const char *
|
} |
} |
*cp++ = '\0'; |
*cp++ = '\0'; |
strlcpy(portbuf, cp, sizeof portbuf); |
strlcpy(portbuf, cp, sizeof portbuf); |
if (verbose >= 2) { | if (DEBUG_GTE(CONNECT, 1)) { |
rprintf(FINFO, "connection via http proxy %s port %s\n", |
rprintf(FINFO, "connection via http proxy %s port %s\n", |
h, portbuf); |
h, portbuf); |
} |
} |
Line 250 int open_socket_out(char *host, int port, const char *
|
Line 282 int open_socket_out(char *host, int port, const char *
|
|
|
for (res = res0, addr_cnt = 0; res; res = res->ai_next, addr_cnt++) {} |
for (res = res0, addr_cnt = 0; res; res = res->ai_next, addr_cnt++) {} |
errnos = new_array0(int, addr_cnt); |
errnos = new_array0(int, addr_cnt); |
if (!errnos) |
|
out_of_memory("open_socket_out"); |
|
|
|
s = -1; |
s = -1; |
/* Try to connect to all addresses for this machine until we get |
/* Try to connect to all addresses for this machine until we get |
Line 275 int open_socket_out(char *host, int port, const char *
|
Line 305 int open_socket_out(char *host, int port, const char *
|
alarm(connect_timeout); |
alarm(connect_timeout); |
} |
} |
|
|
|
set_special_sockopts(s); |
set_socket_options(s, sockopts); |
set_socket_options(s, sockopts); |
while (connect(s, res->ai_addr, res->ai_addrlen) < 0) { |
while (connect(s, res->ai_addr, res->ai_addrlen) < 0) { |
if (connect_timeout < 0) |
if (connect_timeout < 0) |
Line 294 int open_socket_out(char *host, int port, const char *
|
Line 325 int open_socket_out(char *host, int port, const char *
|
continue; |
continue; |
} |
} |
|
|
if (proxied | if (proxied && establish_proxy_connection(s, host, port, proxy_user, proxy_pass) != 0) { |
&& establish_proxy_connection(s, host, port, | |
proxy_user, proxy_pass) != 0) { | |
close(s); |
close(s); |
s = -1; |
s = -1; |
continue; |
continue; |
} |
} |
if (verbose >= 3) { | if (DEBUG_GTE(CONNECT, 2)) { |
char buf[2048]; |
char buf[2048]; |
if ((error = getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof buf, NULL, 0, NI_NUMERICHOST)) != 0) |
if ((error = getnameinfo(res->ai_addr, res->ai_addrlen, buf, sizeof buf, NULL, 0, NI_NUMERICHOST)) != 0) |
snprintf(buf, sizeof buf, "*getnameinfo failure: %s*", gai_strerror(error)); |
snprintf(buf, sizeof buf, "*getnameinfo failure: %s*", gai_strerror(error)); |
Line 310 int open_socket_out(char *host, int port, const char *
|
Line 339 int open_socket_out(char *host, int port, const char *
|
break; |
break; |
} |
} |
|
|
if (s < 0 || verbose >= 3) { | if (s < 0 || DEBUG_GTE(CONNECT, 2)) { |
char buf[2048]; |
char buf[2048]; |
for (res = res0, j = 0; res; res = res->ai_next, j++) { |
for (res = res0, j = 0; res; res = res->ai_next, j++) { |
if (errnos[j] == 0) |
if (errnos[j] == 0) |
Line 340 int open_socket_out(char *host, int port, const char *
|
Line 369 int open_socket_out(char *host, int port, const char *
|
* This is based on the Samba LIBSMB_PROG feature. |
* This is based on the Samba LIBSMB_PROG feature. |
* |
* |
* bind_addr: local address to use. Normally NULL to get the stack default. */ |
* bind_addr: local address to use. Normally NULL to get the stack default. */ |
int open_socket_out_wrapped(char *host, int port, const char *bind_addr, | int open_socket_out_wrapped(char *host, int port, const char *bind_addr, int af_hint) |
int af_hint) | |
{ |
{ |
char *prog = getenv("RSYNC_CONNECT_PROG"); |
char *prog = getenv("RSYNC_CONNECT_PROG"); |
|
|
Line 359 int open_socket_out_wrapped(char *host, int port, cons
|
Line 387 int open_socket_out_wrapped(char *host, int port, cons
|
len += hlen; |
len += hlen; |
} |
} |
f = prog; |
f = prog; |
if (!(prog = new_array(char, len))) | prog = new_array(char, len); |
out_of_memory("open_socket_out_wrapped"); | |
for (t = prog; *f; f++) { |
for (t = prog; *f; f++) { |
if (*f == '%') { |
if (*f == '%') { |
switch (*++f) { |
switch (*++f) { |
Line 381 int open_socket_out_wrapped(char *host, int port, cons
|
Line 408 int open_socket_out_wrapped(char *host, int port, cons
|
*t = '\0'; |
*t = '\0'; |
} |
} |
|
|
if (verbose >= 2) { | if (DEBUG_GTE(CONNECT, 1)) { |
rprintf(FINFO, "%sopening tcp connection to %s port %d\n", |
rprintf(FINFO, "%sopening tcp connection to %s port %d\n", |
prog ? "Using RSYNC_CONNECT_PROG instead of " : "", |
prog ? "Using RSYNC_CONNECT_PROG instead of " : "", |
host, port); |
host, port); |
Line 428 static int *open_socket_in(int type, int port, const c
|
Line 455 static int *open_socket_in(int type, int port, const c
|
|
|
socks = new_array(int, maxs + 1); |
socks = new_array(int, maxs + 1); |
errmsgs = new_array(char *, maxs); |
errmsgs = new_array(char *, maxs); |
if (!socks || !errmsgs) |
|
out_of_memory("open_socket_in"); |
|
|
|
/* We may not be able to create the socket, if for example the |
/* We may not be able to create the socket, if for example the |
* machine knows about IPv6 in the C library, but not in the |
* machine knows about IPv6 in the C library, but not in the |
Line 449 static int *open_socket_in(int type, int port, const c
|
Line 474 static int *open_socket_in(int type, int port, const c
|
continue; |
continue; |
} |
} |
|
|
|
set_special_sockopts(s); |
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, |
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, |
(char *)&one, sizeof one); |
(char *)&one, sizeof one); |
if (sockopts) |
if (sockopts) |
Line 458 static int *open_socket_in(int type, int port, const c
|
Line 484 static int *open_socket_in(int type, int port, const c
|
|
|
#ifdef IPV6_V6ONLY |
#ifdef IPV6_V6ONLY |
if (resp->ai_family == AF_INET6) { |
if (resp->ai_family == AF_INET6) { |
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, | if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&one, sizeof one) < 0 |
(char *)&one, sizeof one) < 0 | && default_af_hint != AF_INET6) { |
&& default_af_hint != AF_INET6) { | |
close(s); |
close(s); |
continue; |
continue; |
} |
} |
Line 489 static int *open_socket_in(int type, int port, const c
|
Line 514 static int *open_socket_in(int type, int port, const c
|
/* Only output the socket()/bind() messages if we were totally |
/* Only output the socket()/bind() messages if we were totally |
* unsuccessful, or if the daemon is being run with -vv. */ |
* unsuccessful, or if the daemon is being run with -vv. */ |
for (s = 0; s < ecnt; s++) { |
for (s = 0; s < ecnt; s++) { |
if (!i || verbose > 1) | if (!i || DEBUG_GTE(BIND, 1)) |
rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]), 0); |
rwrite(FLOG, errmsgs[s], strlen(errmsgs[s]), 0); |
free(errmsgs[s]); |
free(errmsgs[s]); |
} |
} |
Line 529 int is_a_socket(int fd)
|
Line 554 int is_a_socket(int fd)
|
} |
} |
|
|
|
|
static RETSIGTYPE sigchld_handler(UNUSED(int val)) | static void sigchld_handler(UNUSED(int val)) |
{ |
{ |
#ifdef WNOHANG |
#ifdef WNOHANG |
while (waitpid(-1, NULL, WNOHANG) > 0) {} | int status; |
| while (waitpid(-1, &status, WNOHANG) > 0) { |
| if (WIFSIGNALED(status)) { |
| rprintf(FLOG, |
| "rsync error: (3) Child proccess has unexpectedly died with signal %d\n", |
| WTERMSIG(status)); |
| } else if (WIFEXITED(status) && WEXITSTATUS(status) == RERR_WECRASHED) { |
| rprintf(FLOG, |
| "rsync error: (3) Child proccess has CRASHED.\n"); |
| } |
| } |
#endif |
#endif |
#ifndef HAVE_SIGACTION |
#ifndef HAVE_SIGACTION |
signal(SIGCHLD, sigchld_handler); |
signal(SIGCHLD, sigchld_handler); |
Line 544 void start_accept_loop(int port, int (*fn)(int, int))
|
Line 579 void start_accept_loop(int port, int (*fn)(int, int))
|
{ |
{ |
fd_set deffds; |
fd_set deffds; |
int *sp, maxfd, i; |
int *sp, maxfd, i; |
|
#ifdef HAVE_LIBSLP |
|
time_t next_slp_refresh; |
|
short slp_timeout = lp_use_slp() ? lp_slp_refresh() : 0; |
|
if (slp_timeout) { |
|
if (slp_timeout < SLP_MIN_TIMEOUT) |
|
slp_timeout = SLP_MIN_TIMEOUT; |
|
/* re-register before slp times out */ |
|
slp_timeout -= 15; |
|
} |
|
#endif |
|
|
#ifdef HAVE_SIGACTION |
#ifdef HAVE_SIGACTION |
sigact.sa_flags = SA_NOCLDSTOP; |
sigact.sa_flags = SA_NOCLDSTOP; |
Line 557 void start_accept_loop(int port, int (*fn)(int, int))
|
Line 602 void start_accept_loop(int port, int (*fn)(int, int))
|
/* ready to listen */ |
/* ready to listen */ |
FD_ZERO(&deffds); |
FD_ZERO(&deffds); |
for (i = 0, maxfd = -1; sp[i] >= 0; i++) { |
for (i = 0, maxfd = -1; sp[i] >= 0; i++) { |
if (listen(sp[i], 5) < 0) { | if (listen(sp[i], lp_listen_backlog()) < 0) { |
rsyserr(FERROR, errno, "listen() on socket failed"); |
rsyserr(FERROR, errno, "listen() on socket failed"); |
#ifdef INET6 |
#ifdef INET6 |
if (errno == EADDRINUSE && i > 0) { |
if (errno == EADDRINUSE && i > 0) { |
rprintf(FINFO, | rprintf(FINFO, "Try using --ipv4 or --ipv6 to avoid this listen() error.\n"); |
"Try using --ipv4 or --ipv6 to avoid this listen() error.\n"); | |
} |
} |
#endif |
#endif |
exit_cleanup(RERR_SOCKETIO); |
exit_cleanup(RERR_SOCKETIO); |
Line 572 void start_accept_loop(int port, int (*fn)(int, int))
|
Line 616 void start_accept_loop(int port, int (*fn)(int, int))
|
maxfd = sp[i]; |
maxfd = sp[i]; |
} |
} |
|
|
|
#ifdef HAVE_LIBSLP |
|
next_slp_refresh = time(NULL) + slp_timeout; |
|
#endif |
|
|
/* now accept incoming connections - forking a new process |
/* now accept incoming connections - forking a new process |
* for each incoming connection */ |
* for each incoming connection */ |
while (1) { |
while (1) { |
fd_set fds; |
fd_set fds; |
pid_t pid; |
pid_t pid; |
int fd; |
int fd; |
|
int sel_ret; |
struct sockaddr_storage addr; |
struct sockaddr_storage addr; |
socklen_t addrlen = sizeof addr; |
socklen_t addrlen = sizeof addr; |
|
#ifdef HAVE_LIBSLP |
|
struct timeval slp_tv; |
|
|
|
slp_tv.tv_sec = 10; |
|
slp_tv.tv_usec = 0; |
|
#endif |
|
|
/* close log file before the potentially very long select so |
/* close log file before the potentially very long select so |
* file can be trimmed by another process instead of growing |
* file can be trimmed by another process instead of growing |
* forever */ |
* forever */ |
Line 592 void start_accept_loop(int port, int (*fn)(int, int))
|
Line 647 void start_accept_loop(int port, int (*fn)(int, int))
|
fds = deffds; |
fds = deffds; |
#endif |
#endif |
|
|
if (select(maxfd + 1, &fds, NULL, NULL, NULL) < 1) | #ifdef HAVE_LIBSLP |
| sel_ret = select(maxfd + 1, &fds, NULL, NULL, |
| slp_timeout ? &slp_tv : NULL); |
| if (sel_ret == 0 && slp_timeout && time(NULL) > next_slp_refresh) { |
| rprintf(FINFO, "Service registration expired, refreshing it\n"); |
| register_services(); |
| next_slp_refresh = time(NULL) + slp_timeout; |
| } |
| #else |
| sel_ret = select(maxfd + 1, &fds, NULL, NULL, NULL); |
| #endif |
| if (sel_ret < 1) |
continue; |
continue; |
|
|
for (i = 0, fd = -1; sp[i] >= 0; i++) { |
for (i = 0, fd = -1; sp[i] >= 0; i++) { |
if (FD_ISSET(sp[i], &fds)) { |
if (FD_ISSET(sp[i], &fds)) { |
fd = accept(sp[i], (struct sockaddr *)&addr, | fd = accept(sp[i], (struct sockaddr *)&addr, &addrlen); |
&addrlen); | |
break; |
break; |
} |
} |
} |
} |
Line 610 void start_accept_loop(int port, int (*fn)(int, int))
|
Line 675 void start_accept_loop(int port, int (*fn)(int, int))
|
|
|
if ((pid = fork()) == 0) { |
if ((pid = fork()) == 0) { |
int ret; |
int ret; |
|
if (pid_file_fd >= 0) |
|
close(pid_file_fd); |
for (i = 0; sp[i] >= 0; i++) |
for (i = 0; sp[i] >= 0; i++) |
close(sp[i]); |
close(sp[i]); |
/* Re-open log file in child before possibly giving |
/* Re-open log file in child before possibly giving |
Line 690 void set_socket_options(int fd, char *options)
|
Line 757 void set_socket_options(int fd, char *options)
|
|
|
options = strdup(options); |
options = strdup(options); |
|
|
if (!options) |
|
out_of_memory("set_socket_options"); |
|
|
|
for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) { |
for (tok = strtok(options, " \t,"); tok; tok = strtok(NULL," \t,")) { |
int ret=0,i; |
int ret=0,i; |
int value = 1; |
int value = 1; |
Line 797 static int socketpair_tcp(int fd[2])
|
Line 861 static int socketpair_tcp(int fd[2])
|
set_blocking(fd[1]); |
set_blocking(fd[1]); |
|
|
if (connect_done == 0) { |
if (connect_done == 0) { |
if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0 | if (connect(fd[1], (struct sockaddr *)&sock, sizeof sock) != 0 && errno != EISCONN) |
&& errno != EISCONN) | |
goto failed; |
goto failed; |
} |
} |
|
|
Line 820 static int socketpair_tcp(int fd[2])
|
Line 883 static int socketpair_tcp(int fd[2])
|
* stdout. This is used to fake a connection to a daemon for testing -- not |
* stdout. This is used to fake a connection to a daemon for testing -- not |
* for the normal case of running SSH. |
* for the normal case of running SSH. |
* |
* |
* Retruns a socket which is attached to a subprocess running "prog". stdin and | * Returns a socket which is attached to a subprocess running "prog". stdin and |
* stdout are attached. stderr is left attached to the original stderr. */ |
* stdout are attached. stderr is left attached to the original stderr. */ |
static int sock_exec(const char *prog) |
static int sock_exec(const char *prog) |
{ |
{ |
Line 831 static int sock_exec(const char *prog)
|
Line 894 static int sock_exec(const char *prog)
|
rsyserr(FERROR, errno, "socketpair_tcp failed"); |
rsyserr(FERROR, errno, "socketpair_tcp failed"); |
return -1; |
return -1; |
} |
} |
if (verbose >= 2) | if (DEBUG_GTE(CMD, 1)) |
rprintf(FINFO, "Running socket program: \"%s\"\n", prog); |
rprintf(FINFO, "Running socket program: \"%s\"\n", prog); |
|
|
pid = fork(); |
pid = fork(); |
Line 847 static int sock_exec(const char *prog)
|
Line 910 static int sock_exec(const char *prog)
|
fprintf(stderr, "Failed to run \"%s\"\n", prog); |
fprintf(stderr, "Failed to run \"%s\"\n", prog); |
exit(1); |
exit(1); |
} |
} |
exit(system(prog)); | exit(shell_exec(prog)); |
} |
} |
|
|
close(fd[1]); |
close(fd[1]); |