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