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