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