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