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