check_name: Print out name *before* clobbering it.
[rsync/rsync.git] / socket.c
... / ...
CommitLineData
1/* -*- c-file-style: "linux" -*-
2
3 rsync -- fast file replication program
4
5 Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
6 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23/**
24 * @file socket.c
25 *
26 * Socket functions used in rsync.
27 *
28 * This file is now converted to use the new-style getaddrinfo()
29 * interface, which supports IPv6 but is also supported on recent
30 * IPv4-only machines. On systems that don't have that interface, we
31 * emulate it using the KAME implementation.
32 **/
33
34#include "rsync.h"
35
36static const char default_name[] = "UNKNOWN";
37
38
39/* Establish a proxy connection on an open socket to a web roxy by
40 * using the CONNECT method. */
41static int establish_proxy_connection(int fd, char *host, int port)
42{
43 char buffer[1024];
44 char *cp;
45
46 snprintf(buffer, sizeof(buffer), "CONNECT %s:%d HTTP/1.0\r\n\r\n", host, port);
47 if (write(fd, buffer, strlen(buffer)) != strlen(buffer)) {
48 rprintf(FERROR, "failed to write to proxy: %s\n",
49 strerror(errno));
50 return -1;
51 }
52
53 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1]; cp++) {
54 if (read(fd, cp, 1) != 1) {
55 rprintf(FERROR, "failed to read from proxy: %s\n",
56 strerror(errno));
57 return -1;
58 }
59 if (*cp == '\n')
60 break;
61 }
62
63 if (*cp != '\n')
64 cp++;
65 *cp-- = '\0';
66 if (*cp == '\r')
67 *cp = '\0';
68 if (strncmp(buffer, "HTTP/", 5) != 0) {
69 rprintf(FERROR, "bad response from proxy - %s\n",
70 buffer);
71 return -1;
72 }
73 for (cp = &buffer[5]; isdigit(*cp) || (*cp == '.'); cp++)
74 ;
75 while (*cp == ' ')
76 cp++;
77 if (*cp != '2') {
78 rprintf(FERROR, "bad response from proxy - %s\n",
79 buffer);
80 return -1;
81 }
82 /* throw away the rest of the HTTP header */
83 while (1) {
84 for (cp = buffer; cp < &buffer[sizeof(buffer) - 1];
85 cp++) {
86 if (read(fd, cp, 1) != 1) {
87 rprintf(FERROR, "failed to read from proxy: %s\n",
88 strerror(errno));
89 return -1;
90 }
91 if (*cp == '\n')
92 break;
93 }
94 if ((cp > buffer) && (*cp == '\n'))
95 cp--;
96 if ((cp == buffer) && ((*cp == '\n') || (*cp == '\r')))
97 break;
98 }
99 return 0;
100}
101
102
103/**
104 * Try to set the local address for a newly-created socket. Return -1
105 * if this fails.
106 **/
107int try_bind_local(int s,
108 int ai_family, int ai_socktype,
109 const char *bind_address)
110{
111 int error;
112 struct addrinfo bhints, *bres_all, *r;
113
114 memset(&bhints, 0, sizeof(bhints));
115 bhints.ai_family = ai_family;
116 bhints.ai_socktype = ai_socktype;
117 bhints.ai_flags = AI_PASSIVE;
118 if ((error = getaddrinfo(bind_address, NULL, &bhints, &bres_all))) {
119 rprintf(FERROR, RSYNC_NAME ": getaddrinfo %s: %s\n",
120 bind_address, gai_strerror(error));
121 return -1;
122 }
123
124 for (r = bres_all; r; r = r->ai_next) {
125 if (bind(s, r->ai_addr, r->ai_addrlen) == -1)
126 continue;
127 return s;
128 }
129
130 /* no error message; there might be some problem that allows
131 * creation of the socket but not binding, perhaps if the
132 * machine has no ipv6 address of this name. */
133 return -1;
134}
135
136
137/**
138 * Open a socket to a tcp remote host with the specified port .
139 *
140 * Based on code from Warren. Proxy support by Stephen Rothwell.
141 * getaddrinfo() rewrite contributed by KAME.net.
142 *
143 * Now that we support IPv6 we need to look up the remote machine's
144 * address first, using @p af_hint to set a preference for the type
145 * of address. Then depending on whether it has v4 or v6 addresses we
146 * try to open a connection.
147 *
148 * The loop allows for machines with some addresses which may not be
149 * reachable, perhaps because we can't e.g. route ipv6 to that network
150 * but we can get ip4 packets through.
151 *
152 * @param bind_address Local address to use. Normally NULL to bind
153 * the wildcard address.
154 *
155 * @param af_hint Address family, e.g. AF_INET or AF_INET6.
156 **/
157int open_socket_out(char *host, int port, const char *bind_address,
158 int af_hint)
159{
160 int type = SOCK_STREAM;
161 int error;
162 int s;
163 struct addrinfo hints, *res0, *res;
164 char portbuf[10];
165 char *h;
166 int proxied = 0;
167 char buffer[1024];
168 char *cp;
169
170 /* if we have a RSYNC_PROXY env variable then redirect our
171 * connetcion via a web proxy at the given address. The format
172 * is hostname:port */
173 h = getenv("RSYNC_PROXY");
174 proxied = (h != NULL) && (*h != '\0');
175
176 if (proxied) {
177 strlcpy(buffer, h, sizeof(buffer));
178 cp = strchr(buffer, ':');
179 if (cp == NULL) {
180 rprintf(FERROR,
181 "invalid proxy specification: should be HOST:PORT\n");
182 return -1;
183 }
184 *cp++ = '\0';
185 strcpy(portbuf, cp);
186 h = buffer;
187 } else {
188 snprintf(portbuf, sizeof(portbuf), "%d", port);
189 h = host;
190 }
191
192 memset(&hints, 0, sizeof(hints));
193 hints.ai_family = af_hint;
194 hints.ai_socktype = type;
195 error = getaddrinfo(h, portbuf, &hints, &res0);
196 if (error) {
197 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: %s %s: %s\n",
198 h, portbuf, gai_strerror(error));
199 return -1;
200 }
201
202 s = -1;
203 /* Try to connect to all addresses for this machine until we get
204 * through. It might e.g. be multi-homed, or have both IPv4 and IPv6
205 * addresses. We need to create a socket for each record, since the
206 * address record tells us what protocol to use to try to connect. */
207 for (res = res0; res; res = res->ai_next) {
208 s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
209 if (s < 0)
210 continue;
211
212 if (bind_address)
213 if (try_bind_local(s, res->ai_family, type,
214 bind_address) == -1) {
215 close(s);
216 s = -1;
217 continue;
218 }
219
220 if (connect(s, res->ai_addr, res->ai_addrlen) < 0) {
221 close(s);
222 s = -1;
223 continue;
224 }
225 if (proxied &&
226 establish_proxy_connection(s, host, port) != 0) {
227 close(s);
228 s = -1;
229 continue;
230 } else
231 break;
232 }
233 freeaddrinfo(res0);
234 if (s < 0) {
235 rprintf(FERROR, RSYNC_NAME ": failed to connect to %s: %s\n",
236 h, strerror(errno));
237 return -1;
238 }
239 return s;
240}
241
242
243/**
244 * Open an outgoing socket, but allow for it to be intercepted by
245 * $RSYNC_CONNECT_PROG, which will execute a program across a TCP
246 * socketpair rather than really opening a socket.
247 *
248 * We use this primarily in testing to detect TCP flow bugs, but not
249 * cause security problems by really opening remote connections.
250 *
251 * This is based on the Samba LIBSMB_PROG feature.
252 *
253 * @param bind_address Local address to use. Normally NULL to get the stack default.
254 **/
255int open_socket_out_wrapped (char *host,
256 int port,
257 const char *bind_address,
258 int af_hint)
259{
260 char *prog;
261
262 if ((prog = getenv ("RSYNC_CONNECT_PROG")) != NULL)
263 return sock_exec (prog);
264 else
265 return open_socket_out (host, port, bind_address,
266 af_hint);
267}
268
269
270
271/**
272 * Open a socket of the specified type, port and address for incoming data
273 *
274 * Try to be better about handling the results of getaddrinfo(): when
275 * opening an inbound socket, we might get several address results,
276 * e.g. for the machine's ipv4 and ipv6 name.
277 *
278 * If binding a wildcard, then any one of them should do. If an address
279 * was specified but it's insufficiently specific then that's not our
280 * fault.
281 *
282 * However, some of the advertized addresses may not work because e.g. we
283 * don't have IPv6 support in the kernel. In that case go on and try all
284 * addresses until one succeeds.
285 *
286 * @param bind_address Local address to bind, or NULL to allow it to
287 * default.
288 **/
289static int open_socket_in(int type, int port, const char *bind_address,
290 int af_hint)
291{
292 int one=1;
293 int s;
294 struct addrinfo hints, *all_ai, *resp;
295 char portbuf[10];
296 int error;
297
298 memset(&hints, 0, sizeof(hints));
299 hints.ai_family = af_hint;
300 hints.ai_socktype = type;
301 hints.ai_flags = AI_PASSIVE;
302 snprintf(portbuf, sizeof(portbuf), "%d", port);
303 error = getaddrinfo(bind_address, portbuf, &hints, &all_ai);
304 if (error) {
305 rprintf(FERROR, RSYNC_NAME ": getaddrinfo: bind address %s: %s\n",
306 bind_address, gai_strerror(error));
307 return -1;
308 }
309
310 /* We may not be able to create the socket, if for example the
311 * machine knows about IPv6 in the C library, but not in the
312 * kernel. */
313 for (resp = all_ai; resp; resp = resp->ai_next) {
314 s = socket(resp->ai_family, resp->ai_socktype,
315 resp->ai_protocol);
316
317 if (s == -1)
318 /* See if there's another address that will work... */
319 continue;
320
321 setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
322 (char *)&one, sizeof one);
323
324 /* now we've got a socket - we need to bind it */
325 if (bind(s, all_ai->ai_addr, all_ai->ai_addrlen) < 0) {
326 /* Nope, try another */
327 close(s);
328 continue;
329 }
330
331 return s;
332 }
333
334 rprintf(FERROR, RSYNC_NAME ": open inbound socket on port %d failed: "
335 "%s\n",
336 port,
337 strerror(errno));
338
339 freeaddrinfo(all_ai);
340 return -1;
341}
342
343
344/*
345 * Determine if a file descriptor is in fact a socket
346 */
347int is_a_socket(int fd)
348{
349 int v;
350 socklen_t l;
351 l = sizeof(int);
352
353 /* Parameters to getsockopt, setsockopt etc are very
354 * unstandardized across platforms, so don't be surprised if
355 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
356 * It seems they all eventually get the right idea.
357 *
358 * Debian says: ``The fifth argument of getsockopt and
359 * setsockopt is in reality an int [*] (and this is what BSD
360 * 4.* and libc4 and libc5 have). Some POSIX confusion
361 * resulted in the present socklen_t. The draft standard has
362 * not been adopted yet, but glibc2 already follows it and
363 * also has socklen_t [*]. See also accept(2).''
364 *
365 * We now return to your regularly scheduled programming. */
366 return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
367}
368
369
370void start_accept_loop(int port, int (*fn)(int ))
371{
372 int s;
373 extern char *bind_address;
374 extern int default_af_hint;
375
376 /* open an incoming socket */
377 s = open_socket_in(SOCK_STREAM, port, bind_address, default_af_hint);
378 if (s == -1)
379 exit_cleanup(RERR_SOCKETIO);
380
381 /* ready to listen */
382 if (listen(s, 5) == -1) {
383 close(s);
384 exit_cleanup(RERR_SOCKETIO);
385 }
386
387
388 /* now accept incoming connections - forking a new process
389 for each incoming connection */
390 while (1) {
391 fd_set fds;
392 int fd;
393 struct sockaddr_storage addr;
394 socklen_t addrlen = sizeof addr;
395
396 /* close log file before the potentially very long select so
397 file can be trimmed by another process instead of growing
398 forever */
399 log_close();
400
401 FD_ZERO(&fds);
402 FD_SET(s, &fds);
403
404 if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
405 continue;
406 }
407
408 if(!FD_ISSET(s, &fds)) continue;
409
410 fd = accept(s,(struct sockaddr *)&addr,&addrlen);
411
412 if (fd == -1) continue;
413
414 signal(SIGCHLD, SIG_IGN);
415
416 /* we shouldn't have any children left hanging around
417 but I have had reports that on Digital Unix zombies
418 are produced, so this ensures that they are reaped */
419#ifdef WNOHANG
420 while (waitpid(-1, NULL, WNOHANG) > 0);
421#endif
422
423 if (fork()==0) {
424 close(s);
425 /* open log file in child before possibly giving
426 up privileges */
427 log_open();
428 _exit(fn(fd));
429 }
430
431 close(fd);
432 }
433}
434
435
436enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
437
438struct
439{
440 char *name;
441 int level;
442 int option;
443 int value;
444 int opttype;
445} socket_options[] = {
446 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
447 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
448 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
449#ifdef TCP_NODELAY
450 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
451#endif
452#ifdef IPTOS_LOWDELAY
453 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
454#endif
455#ifdef IPTOS_THROUGHPUT
456 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
457#endif
458#ifdef SO_SNDBUF
459 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
460#endif
461#ifdef SO_RCVBUF
462 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
463#endif
464#ifdef SO_SNDLOWAT
465 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
466#endif
467#ifdef SO_RCVLOWAT
468 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
469#endif
470#ifdef SO_SNDTIMEO
471 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
472#endif
473#ifdef SO_RCVTIMEO
474 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
475#endif
476 {NULL,0,0,0,0}};
477
478
479
480/****************************************************************************
481set user socket options
482****************************************************************************/
483void set_socket_options(int fd, char *options)
484{
485 char *tok;
486 if (!options || !*options) return;
487
488 options = strdup(options);
489
490 if (!options) out_of_memory("set_socket_options");
491
492 for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
493 int ret=0,i;
494 int value = 1;
495 char *p;
496 int got_value = 0;
497
498 if ((p = strchr(tok,'='))) {
499 *p = 0;
500 value = atoi(p+1);
501 got_value = 1;
502 }
503
504 for (i=0;socket_options[i].name;i++)
505 if (strcmp(socket_options[i].name,tok)==0)
506 break;
507
508 if (!socket_options[i].name) {
509 rprintf(FERROR,"Unknown socket option %s\n",tok);
510 continue;
511 }
512
513 switch (socket_options[i].opttype) {
514 case OPT_BOOL:
515 case OPT_INT:
516 ret = setsockopt(fd,socket_options[i].level,
517 socket_options[i].option,(char *)&value,sizeof(int));
518 break;
519
520 case OPT_ON:
521 if (got_value)
522 rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
523
524 {
525 int on = socket_options[i].value;
526 ret = setsockopt(fd,socket_options[i].level,
527 socket_options[i].option,(char *)&on,sizeof(int));
528 }
529 break;
530 }
531
532 if (ret != 0)
533 rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
534 strerror(errno));
535 }
536
537 free(options);
538}
539
540/****************************************************************************
541become a daemon, discarding the controlling terminal
542****************************************************************************/
543void become_daemon(void)
544{
545 int i;
546
547 if (fork()) {
548 _exit(0);
549 }
550
551 /* detach from the terminal */
552#ifdef HAVE_SETSID
553 setsid();
554#else
555#ifdef TIOCNOTTY
556 i = open("/dev/tty", O_RDWR);
557 if (i >= 0) {
558 ioctl(i, (int) TIOCNOTTY, (char *)0);
559 close(i);
560 }
561#endif /* TIOCNOTTY */
562#endif
563 /* make sure that stdin, stdout an stderr don't stuff things
564 up (library functions, for example) */
565 for (i=0;i<3;i++) {
566 close(i);
567 open("/dev/null", O_RDWR);
568 }
569}
570
571/**
572 * Return the IP addr of the client as a string
573 **/
574char *client_addr(int fd)
575{
576 struct sockaddr_storage ss;
577 socklen_t length = sizeof ss;
578 static char addr_buf[100];
579 static int initialised;
580
581 if (initialised) return addr_buf;
582
583 initialised = 1;
584
585 if (getpeername(fd, (struct sockaddr *)&ss, &length)) {
586 exit_cleanup(RERR_SOCKETIO);
587 }
588
589 getnameinfo((struct sockaddr *)&ss, length,
590 addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
591 return addr_buf;
592}
593
594
595static int get_sockaddr_family(const struct sockaddr_storage *ss)
596{
597 return ((struct sockaddr *) ss)->sa_family;
598}
599
600
601/**
602 * Return the DNS name of the client.
603 *
604 * The name is statically cached so that repeated lookups are quick,
605 * so there is a limit of one lookup per customer.
606 *
607 * If anything goes wrong, including the name->addr->name check, then
608 * we just use "UNKNOWN", so you can use that value in hosts allow
609 * lines.
610 **/
611char *client_name(int fd)
612{
613 struct sockaddr_storage ss;
614 socklen_t ss_len = sizeof ss;
615 static char name_buf[100];
616 static char port_buf[100];
617 static int initialised;
618
619 if (initialised) return name_buf;
620
621 strcpy(name_buf, default_name);
622 initialised = 1;
623
624 if (getpeername(fd, (struct sockaddr *)&ss, &ss_len)) {
625 /* FIXME: Can we really not continue? */
626 rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
627 fd, strerror(errno));
628 exit_cleanup(RERR_SOCKETIO);
629 }
630
631 if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf, port_buf, sizeof port_buf))
632 check_name(fd, &ss, ss_len, name_buf, port_buf);
633
634 return name_buf;
635}
636
637
638/**
639 * Look up a name from @p ss into @p name_buf.
640 **/
641int lookup_name(int fd, const struct sockaddr_storage *ss,
642 socklen_t ss_len,
643 char *name_buf, size_t name_buf_len,
644 char *port_buf, size_t port_buf_len)
645{
646 int name_err;
647
648#ifdef INET6
649 if (get_sockaddr_family(ss) == AF_INET6 &&
650 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
651 /* OK, so ss is in the IPv6 family, but it is really
652 * an IPv4 address: something like
653 * "::ffff:10.130.1.2". If we use it as-is, then the
654 * reverse lookup might fail or perhaps something else
655 * bad might happen. So instead we convert it to an
656 * equivalent address in the IPv4 address family. */
657 struct sockaddr_in6 sin6;
658 struct sockaddr_in *sin;
659
660 memcpy(&sin6, ss, sizeof(sin6));
661 sin = (struct sockaddr_in *)ss;
662 memset(sin, 0, sizeof(*sin));
663 sin->sin_family = AF_INET;
664 ss_len = sizeof(struct sockaddr_in);
665#ifdef HAVE_SOCKADDR_LEN
666 sin->sin_len = ss_len;
667#endif
668 sin->sin_port = sin6.sin6_port;
669 /* FIXME: Isn't there a macro we can use here rather
670 * than grovelling through the struct? It might be
671 * wrong on some systems. */
672 memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
673 sizeof(sin->sin_addr));
674 }
675#endif
676
677 /* reverse lookup */
678 name_err = getnameinfo((struct sockaddr *) ss, ss_len,
679 name_buf, name_buf_len,
680 port_buf, port_buf_len,
681 NI_NAMEREQD | NI_NUMERICSERV);
682 if (name_err != 0) {
683 strcpy(name_buf, default_name);
684 rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
685 client_addr(fd),
686 gai_strerror(name_err));
687 return name_err;
688 }
689
690 return 0;
691}
692
693
694
695/* Do a forward lookup on name_buf and make sure it corresponds to ss
696 * -- otherwise we may be being spoofed. If we suspect we are, then
697 * we don't abort the connection but just emit a warning. */
698int check_name(int fd,
699 const struct sockaddr_storage *ss,
700 socklen_t ss_len,
701 char *name_buf,
702 const char *port_buf)
703{
704 struct addrinfo hints, *res, *res0;
705 int error;
706
707 memset(&hints, 0, sizeof(hints));
708 hints.ai_family = PF_UNSPEC;
709 hints.ai_flags = AI_CANONNAME;
710 hints.ai_socktype = SOCK_STREAM;
711 error = getaddrinfo(name_buf, port_buf, &hints, &res0);
712 if (error) {
713 rprintf(FERROR,
714 RSYNC_NAME ": forward name lookup for %s:%s failed: %s\n",
715 name_buf, port_buf,
716 gai_strerror(error));
717 strcpy(name_buf, default_name);
718 return error;
719 }
720
721
722 /* We expect that one of the results will be the same as ss. */
723 for (res = res0; res; res = res->ai_next) {
724 if (res->ai_family != get_sockaddr_family(ss))
725 continue;
726 if (res->ai_addrlen != ss_len)
727 continue;
728 if (memcmp(res->ai_addr, ss, res->ai_addrlen) == 0)
729 break;
730 }
731
732 if (res == NULL) {
733 /* We hit the end of the list without finding an
734 * address that was the same as ss. */
735 rprintf(FERROR, RSYNC_NAME
736 ": %s is not a known address for \"%s\": "
737 "spoofed address?\n",
738 client_addr(fd),
739 name_buf);
740 strcpy(name_buf, default_name);
741 }
742
743 freeaddrinfo(res0);
744 return 0;
745}
746
747
748/*******************************************************************
749this is like socketpair but uses tcp. It is used by the Samba
750regression test code
751The function guarantees that nobody else can attach to the socket,
752or if they do that this function fails and the socket gets closed
753returns 0 on success, -1 on failure
754the resulting file descriptors are symmetrical
755 ******************************************************************/
756static int socketpair_tcp(int fd[2])
757{
758 int listener;
759 struct sockaddr_in sock;
760 struct sockaddr_in sock2;
761 socklen_t socklen = sizeof(sock);
762 int connect_done = 0;
763
764 fd[0] = fd[1] = listener = -1;
765
766 memset(&sock, 0, sizeof(sock));
767
768 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
769
770 memset(&sock2, 0, sizeof(sock2));
771#ifdef HAVE_SOCK_SIN_LEN
772 sock2.sin_len = sizeof(sock2);
773#endif
774 sock2.sin_family = PF_INET;
775
776 bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
777
778 if (listen(listener, 1) != 0) goto failed;
779
780 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
781
782 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
783
784 set_nonblocking(fd[1]);
785
786 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
787
788 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
789 if (errno != EINPROGRESS) goto failed;
790 } else {
791 connect_done = 1;
792 }
793
794 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
795
796 close(listener);
797 if (connect_done == 0) {
798 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
799 && errno != EISCONN) goto failed;
800 }
801
802 set_blocking (fd[1]);
803
804 /* all OK! */
805 return 0;
806
807 failed:
808 if (fd[0] != -1) close(fd[0]);
809 if (fd[1] != -1) close(fd[1]);
810 if (listener != -1) close(listener);
811 return -1;
812}
813
814
815
816/**
817 * Run a program on a local tcp socket, so that we can talk to it's
818 * stdin and stdout. This is used to fake a connection to a daemon
819 * for testing -- not for the normal case of running SSH.
820 *
821 * @return a socket which is attached to a subprocess running
822 * "prog". stdin and stdout are attached. stderr is left attached to
823 * the original stderr
824 **/
825int sock_exec(const char *prog)
826{
827 int fd[2];
828
829 if (socketpair_tcp(fd) != 0) {
830 rprintf (FERROR, RSYNC_NAME
831 ": socketpair_tcp failed (%s)\n",
832 strerror(errno));
833 return -1;
834 }
835 if (fork() == 0) {
836 close(fd[0]);
837 close(0);
838 close(1);
839 dup(fd[1]);
840 dup(fd[1]);
841 if (verbose > 3) {
842 /* Can't use rprintf because we've forked. */
843 fprintf (stderr,
844 RSYNC_NAME ": execute socket program \"%s\"\n",
845 prog);
846 }
847 exit (system (prog));
848 }
849 close (fd[1]);
850 return fd[0];
851}
852
853
854