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