1 /* -*- c-file-style: "linux" -*-
3 Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
4 Copyright (C) 2001 by Martin Pool <mbp@samba.org>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 * Socket functions used in rsync.
29 #ifndef HAVE_GETADDRINFO
30 #include "lib/addrinfo.h"
33 // extern int af; /* NO MORE BLOODY GLOBALS! */
35 /* Establish a proxy connection on an open socket to a web roxy by
36 * using the CONNECT method. */
37 static int establish_proxy_connection(int fd, char *host, int port)
42 snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
43 if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) {
44 rprintf(FERROR, "failed to write to proxy: %s\n",
49 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; cp++) {
50 if (read(fd, cp, 1) != 1) {
51 rprintf(FERROR, "failed to read from proxy: %s\n",
64 if (strncmp(buffer, "HTTP/", 5) != 0) {
65 rprintf(FERROR, "bad response from proxy - %s\n",
69 for (cp = &buffer[5]; isdigit(*cp) || (*cp == '.'); cp++)
74 rprintf(FERROR, "bad response from proxy - %s\n",
78 /* throw away the rest of the HTTP header */
80 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1];
82 if (read(fd, cp, 1) != 1) {
83 rprintf(FERROR, "failed to read from proxy: %s\n",
90 if ((cp > buffer) && (*cp == '\n'))
92 if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r')))
101 * Open a socket to a tcp remote host with the specified port .
103 * Based on code from Warren. Proxy support by Stephen Rothwell.
104 * getaddrinfo() rewrite contributed by KAME.net.
106 * Now that we support IPv6 we need to look up the remote machine's
107 * address first, using @p af_hint to set a preference for the type
108 * of address. Then depending on whether it has v4 or v6 addresses we
109 * try to open a connection.
111 * The loop allows for machines with some addresses which may not be
112 * reachable, perhaps because we can't e.g. route ipv6 to that network
113 * but we can get ip4 packets through.
115 * @param bind_address Local address to use. Normally NULL to bind
116 * the wildcard address.
118 * @param af_hint Address family, e.g. AF_INET or AF_INET6.
120 int open_socket_out(char *host, int port, const char *bind_address,
123 int type = SOCK_STREAM;
127 struct addrinfo hints, *res0, *res;
134 /* if we have a RSYNC_PROXY env variable then redirect our
135 * connetcion via a web proxy at the given address. The format
136 * is hostname:port */
137 h = getenv("RSYNC_PROXY");
138 proxied = (h != NULL) && (*h != '\0');
141 strlcpy(buffer, h, sizeof(buffer));
142 cp = strchr(buffer, ':');
145 "invalid proxy specification: should be HOST:PORT\n");
152 snprintf(portbuf, sizeof(portbuf), "%d", port);
156 memset(&hints, 0, sizeof(hints));
157 hints.ai_family = af_hint;
158 hints.ai_socktype = type;
159 error = getaddrinfo(h, portbuf, &hints, &res0);
161 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: %s %s: %s\n",
162 h, portbuf, gai_strerror(error));
167 for (res = res0; res; res = res->ai_next) {
168 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
173 struct addrinfo bhints, *bres;
175 memset(&bhints, 0, sizeof(bhints));
176 bhints.ai_family = res->ai_family;
177 bhints.ai_socktype = type;
178 bhints.ai_flags = AI_PASSIVE;
179 error = getaddrinfo(bind_address, NULL, &bhints, &bres);
181 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s <noport>: %s\n",
182 bind_address, gai_strerror(error));
186 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s resolved to multiple hosts\n",
191 bind(s, bres->ai_addr, bres->ai_addrlen);
194 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
200 establish_proxy_connection(s, host, port) != 0) {
209 rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
218 * Open an outgoing socket, but allow for it to be intercepted by
219 * $RSYNC_CONNECT_PROG, which will execute a program across a TCP
220 * socketpair rather than really opening a socket.
222 * We use this primarily in testing to detect TCP flow bugs, but not
223 * cause security problems by really opening remote connections.
225 * This is based on the Samba LIBSMB_PROG feature.
227 * @param bind_address Local address to use. Normally NULL to get the stack default.
229 int open_socket_out_wrapped (char *host,
231 const char *bind_address,
236 if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
237 return sock_exec (prog);
239 return open_socket_out (host, port, bind_address,
246 * Open a socket of the specified type, port and address for incoming data
248 * @param bind_address Local address to bind, or NULL to allow it to
251 static int open_socket_in(int type, int port, const char *bind_address,
256 struct addrinfo hints, *res;
260 memset(&hints, 0, sizeof(hints));
261 hints.ai_family = af_hint;
262 hints.ai_socktype = type;
263 hints.ai_flags = AI_PASSIVE;
264 snprintf(portbuf, sizeof(portbuf), "%d", port);
265 error = getaddrinfo(bind_address, portbuf, &hints, &res);
267 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
268 bind_address, gai_strerror(error));
272 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: "
273 "resolved to multiple hosts\n",
279 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
281 rprintf(FERROR, RSYNC_NAME ": open socket in failed: %s\n",
287 setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
289 /* now we've got a socket - we need to bind it */
290 if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
291 rprintf(FERROR, RSYNC_NAME ": bind failed on port %d\n", port);
302 * Determine if a file descriptor is in fact a socket
304 int is_a_socket(int fd)
310 /* Parameters to getsockopt, setsockopt etc are very
311 * unstandardized across platforms, so don't be surprised if
312 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
313 * It seems they all eventually get the right idea.
315 * Debian says: ``The fifth argument of getsockopt and
316 * setsockopt is in reality an int [*] (and this is what BSD
317 * 4.* and libc4 and libc5 have). Some POSIX confusion
318 * resulted in the present socklen_t. The draft standard has
319 * not been adopted yet, but glibc2 already follows it and
320 * also has socklen_t [*]. See also accept(2).''
322 * We now return to your regularly scheduled programming. */
323 return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
327 void start_accept_loop(int port, int (*fn)(int ))
330 extern char *bind_address;
332 /* open an incoming socket */
333 s = open_socket_in(SOCK_STREAM, port, bind_address,
334 global_opts.af_hint);
336 exit_cleanup(RERR_SOCKETIO);
338 /* ready to listen */
339 if (listen(s, 5) == -1) {
341 exit_cleanup(RERR_SOCKETIO);
345 /* now accept incoming connections - forking a new process
346 for each incoming connection */
350 struct sockaddr addr;
351 int in_addrlen = sizeof(addr);
353 /* close log file before the potentially very long select so
354 file can be trimmed by another process instead of growing
361 if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
365 if(!FD_ISSET(s, &fds)) continue;
367 fd = accept(s,(struct sockaddr *)&addr,&in_addrlen);
369 if (fd == -1) continue;
371 signal(SIGCHLD, SIG_IGN);
373 /* we shouldn't have any children left hanging around
374 but I have had reports that on Digital Unix zombies
375 are produced, so this ensures that they are reaped */
377 while (waitpid(-1, NULL, WNOHANG) > 0);
382 /* open log file in child before possibly giving
393 enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
402 } socket_options[] = {
403 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
404 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
405 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
407 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
409 #ifdef IPTOS_LOWDELAY
410 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
412 #ifdef IPTOS_THROUGHPUT
413 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
416 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
419 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
422 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
425 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
428 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
431 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
437 /****************************************************************************
438 set user socket options
439 ****************************************************************************/
440 void set_socket_options(int fd, char *options)
443 if (!options || !*options) return;
445 options = strdup(options);
447 if (!options) out_of_memory("set_socket_options");
449 for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
455 if ((p = strchr(tok,'='))) {
461 for (i=0;socket_options[i].name;i++)
462 if (strcmp(socket_options[i].name,tok)==0)
465 if (!socket_options[i].name) {
466 rprintf(FERROR,"Unknown socket option %s\n",tok);
470 switch (socket_options[i].opttype) {
473 ret = setsockopt(fd,socket_options[i].level,
474 socket_options[i].option,(char *)&value,sizeof(int));
479 rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
482 int on = socket_options[i].value;
483 ret = setsockopt(fd,socket_options[i].level,
484 socket_options[i].option,(char *)&on,sizeof(int));
490 rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
497 /****************************************************************************
498 become a daemon, discarding the controlling terminal
499 ****************************************************************************/
500 void become_daemon(void)
508 /* detach from the terminal */
513 i = open("/dev/tty", O_RDWR);
515 ioctl(i, (int) TIOCNOTTY, (char *)0);
518 #endif /* TIOCNOTTY */
520 /* make sure that stdin, stdout an stderr don't stuff things
521 up (library functions, for example) */
524 open("/dev/null", O_RDWR);
529 * Return the IP addr of the client as a string
531 char *client_addr(int fd)
534 int length = sizeof(ss);
535 static char addr_buf[100];
536 static int initialised;
538 if (initialised) return addr_buf;
542 if (getpeername(fd, &ss, &length)) {
543 exit_cleanup(RERR_SOCKETIO);
546 getnameinfo(&ss, length,
547 addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
553 * Return the DNS name of the client
555 char *client_name(int fd)
558 int length = sizeof(ss);
559 static char name_buf[100];
560 static char port_buf[100];
561 char *def = "UNKNOWN";
562 static int initialised;
563 struct addrinfo hints, *res, *res0;
566 if (initialised) return name_buf;
570 strcpy(name_buf,def);
572 if (getpeername(fd, (struct sockaddr *)&ss, &length)) {
573 /* FIXME: Can we really not continue? */
574 rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
576 exit_cleanup(RERR_SOCKETIO);
580 if (ss.ss_family == AF_INET6 &&
581 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&ss)->sin6_addr)) {
582 struct sockaddr_in6 sin6;
583 struct sockaddr_in *sin;
585 memcpy(&sin6, &ss, sizeof(sin6));
586 sin = (struct sockaddr_in *)&ss;
587 memset(sin, 0, sizeof(*sin));
588 sin->sin_family = AF_INET;
589 length = sizeof(struct sockaddr_in);
590 #ifdef HAVE_SOCKADDR_LEN
591 sin->sin_len = length;
593 sin->sin_port = sin6.sin6_port;
594 memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
595 sizeof(sin->sin_addr));
600 if (getnameinfo((struct sockaddr *)&ss, length,
601 name_buf, sizeof(name_buf), port_buf, sizeof(port_buf),
602 NI_NAMEREQD | NI_NUMERICSERV) != 0) {
603 strcpy(name_buf, def);
604 rprintf(FERROR, "reverse name lookup failed\n");
608 memset(&hints, 0, sizeof(hints));
609 hints.ai_family = PF_UNSPEC;
610 hints.ai_flags = AI_CANONNAME;
611 hints.ai_socktype = SOCK_STREAM;
612 error = getaddrinfo(name_buf, port_buf, &hints, &res0);
614 strcpy(name_buf, def);
616 RSYNC_NAME ": forward name lookup for %s failed: %s\n",
618 gai_strerror(error));
622 /* XXX sin6_flowinfo and other fields */
623 for (res = res0; res; res = res->ai_next) {
624 if (res->ai_family != ss.sa_family)
626 if (res->ai_addrlen != length)
628 if (memcmp(res->ai_addr, &ss, res->ai_addrlen) == 0)
632 /* TODO: Do a forward lookup as well to prevent spoofing */
635 strcpy(name_buf, def);
636 rprintf(FERROR, RSYNC_NAME ": "
637 "reverse name lookup mismatch on fd%d - spoofed address?\n",
646 * Convert a string to an IP address. The string can be a name or
647 * dotted decimal number.
649 * Returns a pointer to a static in_addr struct -- if you call this
650 * more than once then you should copy it.
652 * TODO: Use getaddrinfo() instead, or make this function call getnameinfo
654 struct in_addr *ip_address(const char *str)
656 static struct in_addr ret;
660 rprintf (FERROR, "ip_address received NULL name\n");
664 /* try as an IP address */
665 if (inet_aton(str, &ret) != 0) {
669 /* otherwise assume it's a network name of some sort and use
671 if ((hp = gethostbyname (str)) == 0) {
672 rprintf(FERROR, "gethostbyname failed for \"%s\": unknown host?\n",str);
676 if (hp->h_addr == NULL) {
677 rprintf(FERROR, "gethostbyname: host address is invalid for host \"%s\"\n",str);
681 if (hp->h_length > sizeof ret) {
682 rprintf(FERROR, "gethostbyname: host address for \"%s\" is too large\n",
687 if (hp->h_addrtype != AF_INET) {
688 rprintf (FERROR, "gethostname: host address for \"%s\" is not IPv4\n",
693 /* This is kind of difficult. The only field in ret is
694 s_addr, which is the IP address as a 32-bit int. On
695 UNICOS, s_addr is in fact a *bitfield* for reasons best
696 know to Cray. This means we can't memcpy in to it. On the
697 other hand, h_addr is a char*, so we can't just assign.
699 Since there's meant to be only one field inside the in_addr
700 structure we will try just copying over the top and see how
702 memcpy (&ret, hp->h_addr, hp->h_length);
709 /*******************************************************************
710 this is like socketpair but uses tcp. It is used by the Samba
712 The function guarantees that nobody else can attach to the socket,
713 or if they do that this function fails and the socket gets closed
714 returns 0 on success, -1 on failure
715 the resulting file descriptors are symmetrical
716 ******************************************************************/
717 static int socketpair_tcp(int fd[2])
720 struct sockaddr_in sock;
721 struct sockaddr_in sock2;
722 socklen_t socklen = sizeof(sock);
723 int connect_done = 0;
725 fd[0] = fd[1] = listener = -1;
727 memset(&sock, 0, sizeof(sock));
729 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
731 memset(&sock2, 0, sizeof(sock2));
732 #ifdef HAVE_SOCK_SIN_LEN
733 sock2.sin_len = sizeof(sock2);
735 sock2.sin_family = PF_INET;
737 bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
739 if (listen(listener, 1) != 0) goto failed;
741 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
743 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
745 set_nonblocking(fd[1]);
747 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
749 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
750 if (errno != EINPROGRESS) goto failed;
755 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
758 if (connect_done == 0) {
759 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
760 && errno != EISCONN) goto failed;
763 set_blocking (fd[1]);
769 if (fd[0] != -1) close(fd[0]);
770 if (fd[1] != -1) close(fd[1]);
771 if (listener != -1) close(listener);
776 /*******************************************************************
777 run a program on a local tcp socket, this is used to launch smbd
778 when regression testing
779 the return value is a socket which is attached to a subprocess
780 running "prog". stdin and stdout are attached. stderr is left
781 attached to the original stderr
782 ******************************************************************/
783 int sock_exec(const char *prog)
786 if (socketpair_tcp(fd) != 0) {
787 rprintf (FERROR, RSYNC_NAME
788 ": socketpair_tcp failed (%s)\n",
800 RSYNC_NAME ": execute socket program \"%s\"\n",
802 exit (system (prog));