Note rsyncd-over-ssh and documentation TODOs.
[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:
cb1bcc7e 301 case EINVAL:
b8771f96
MP
302 /* See if there's another address that will work... */
303 continue;
304 }
305 }
306
307 rprintf(FERROR, RSYNC_NAME ": open inbound socket"
308 "(dom=%d, type=%d, proto=%d) failed: %s\n",
309 resp->ai_family, resp->ai_socktype, resp->ai_protocol,
310 strerror(errno));
311 goto fail;
f0fca04e
AT
312 }
313
06963d0f 314 setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&one,sizeof(one));
f0fca04e
AT
315
316 /* now we've got a socket - we need to bind it */
06963d0f
MP
317 if (bind(s, res->ai_addr, res->ai_addrlen) < 0) {
318 rprintf(FERROR, RSYNC_NAME ": bind failed on port %d\n", port);
b8771f96
MP
319 close(s);
320 goto fail;
f0fca04e
AT
321 }
322
06963d0f 323 return s;
b8771f96
MP
324
325fail:
326 freeaddrinfo(res);
327 return -1;
f0fca04e
AT
328}
329
330
7c1b4daa
MP
331/*
332 * Determine if a file descriptor is in fact a socket
333 */
f0fca04e
AT
334int is_a_socket(int fd)
335{
ac2a1a44
MP
336 int v;
337 socklen_t l;
3eb38818 338 l = sizeof(int);
7c1b4daa
MP
339
340 /* Parameters to getsockopt, setsockopt etc are very
341 * unstandardized across platforms, so don't be surprised if
ac2a1a44
MP
342 * there are compiler warnings on e.g. SCO OpenSwerver or AIX.
343 * It seems they all eventually get the right idea.
7c1b4daa
MP
344 *
345 * Debian says: ``The fifth argument of getsockopt and
346 * setsockopt is in reality an int [*] (and this is what BSD
347 * 4.* and libc4 and libc5 have). Some POSIX confusion
348 * resulted in the present socklen_t. The draft standard has
349 * not been adopted yet, but glibc2 already follows it and
350 * also has socklen_t [*]. See also accept(2).''
351 *
352 * We now return to your regularly scheduled programming. */
3eb38818 353 return(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&v, &l) == 0);
f0fca04e
AT
354}
355
356
8ef4ffd6 357void start_accept_loop(int port, int (*fn)(int ))
f0fca04e
AT
358{
359 int s;
06963d0f 360 extern char *bind_address;
f0fca04e 361
f0fca04e 362 /* open an incoming socket */
d5d4b282
MP
363 s = open_socket_in(SOCK_STREAM, port, bind_address,
364 global_opts.af_hint);
f0fca04e 365 if (s == -1)
65417579 366 exit_cleanup(RERR_SOCKETIO);
f0fca04e
AT
367
368 /* ready to listen */
369 if (listen(s, 5) == -1) {
370 close(s);
65417579 371 exit_cleanup(RERR_SOCKETIO);
f0fca04e
AT
372 }
373
374
375 /* now accept incoming connections - forking a new process
376 for each incoming connection */
377 while (1) {
378 fd_set fds;
379 int fd;
2d6dbe29
MP
380 struct sockaddr_storage addr;
381 int addrlen = sizeof(addr);
f0fca04e 382
15b84e14
DD
383 /* close log file before the potentially very long select so
384 file can be trimmed by another process instead of growing
385 forever */
386 log_close();
45a83540 387
f0fca04e
AT
388 FD_ZERO(&fds);
389 FD_SET(s, &fds);
390
391 if (select(s+1, &fds, NULL, NULL, NULL) != 1) {
392 continue;
393 }
394
395 if(!FD_ISSET(s, &fds)) continue;
396
2d6dbe29 397 fd = accept(s,(struct sockaddr *)&addr,&addrlen);
f0fca04e
AT
398
399 if (fd == -1) continue;
400
31f440e6
AT
401 signal(SIGCHLD, SIG_IGN);
402
403 /* we shouldn't have any children left hanging around
404 but I have had reports that on Digital Unix zombies
405 are produced, so this ensures that they are reaped */
406#ifdef WNOHANG
0503f060 407 while (waitpid(-1, NULL, WNOHANG) > 0);
31f440e6
AT
408#endif
409
f0fca04e
AT
410 if (fork()==0) {
411 close(s);
15b84e14
DD
412 /* open log file in child before possibly giving
413 up privileges */
414 log_open();
f0fca04e
AT
415 _exit(fn(fd));
416 }
417
418 close(fd);
419 }
f0fca04e
AT
420}
421
422
423enum SOCK_OPT_TYPES {OPT_BOOL,OPT_INT,OPT_ON};
424
425struct
426{
427 char *name;
428 int level;
429 int option;
430 int value;
431 int opttype;
432} socket_options[] = {
433 {"SO_KEEPALIVE", SOL_SOCKET, SO_KEEPALIVE, 0, OPT_BOOL},
434 {"SO_REUSEADDR", SOL_SOCKET, SO_REUSEADDR, 0, OPT_BOOL},
435 {"SO_BROADCAST", SOL_SOCKET, SO_BROADCAST, 0, OPT_BOOL},
436#ifdef TCP_NODELAY
437 {"TCP_NODELAY", IPPROTO_TCP, TCP_NODELAY, 0, OPT_BOOL},
438#endif
439#ifdef IPTOS_LOWDELAY
440 {"IPTOS_LOWDELAY", IPPROTO_IP, IP_TOS, IPTOS_LOWDELAY, OPT_ON},
441#endif
442#ifdef IPTOS_THROUGHPUT
443 {"IPTOS_THROUGHPUT", IPPROTO_IP, IP_TOS, IPTOS_THROUGHPUT, OPT_ON},
444#endif
445#ifdef SO_SNDBUF
446 {"SO_SNDBUF", SOL_SOCKET, SO_SNDBUF, 0, OPT_INT},
447#endif
448#ifdef SO_RCVBUF
449 {"SO_RCVBUF", SOL_SOCKET, SO_RCVBUF, 0, OPT_INT},
450#endif
451#ifdef SO_SNDLOWAT
452 {"SO_SNDLOWAT", SOL_SOCKET, SO_SNDLOWAT, 0, OPT_INT},
453#endif
454#ifdef SO_RCVLOWAT
455 {"SO_RCVLOWAT", SOL_SOCKET, SO_RCVLOWAT, 0, OPT_INT},
456#endif
457#ifdef SO_SNDTIMEO
458 {"SO_SNDTIMEO", SOL_SOCKET, SO_SNDTIMEO, 0, OPT_INT},
459#endif
460#ifdef SO_RCVTIMEO
461 {"SO_RCVTIMEO", SOL_SOCKET, SO_RCVTIMEO, 0, OPT_INT},
462#endif
463 {NULL,0,0,0,0}};
464
465
466
467/****************************************************************************
468set user socket options
469****************************************************************************/
470void set_socket_options(int fd, char *options)
471{
472 char *tok;
a6801c39
AT
473 if (!options || !*options) return;
474
f0fca04e
AT
475 options = strdup(options);
476
477 if (!options) out_of_memory("set_socket_options");
478
479 for (tok=strtok(options, " \t,"); tok; tok=strtok(NULL," \t,")) {
480 int ret=0,i;
481 int value = 1;
482 char *p;
483 int got_value = 0;
484
485 if ((p = strchr(tok,'='))) {
486 *p = 0;
487 value = atoi(p+1);
488 got_value = 1;
489 }
490
491 for (i=0;socket_options[i].name;i++)
492 if (strcmp(socket_options[i].name,tok)==0)
493 break;
494
495 if (!socket_options[i].name) {
496 rprintf(FERROR,"Unknown socket option %s\n",tok);
497 continue;
498 }
499
500 switch (socket_options[i].opttype) {
501 case OPT_BOOL:
502 case OPT_INT:
503 ret = setsockopt(fd,socket_options[i].level,
504 socket_options[i].option,(char *)&value,sizeof(int));
505 break;
506
507 case OPT_ON:
508 if (got_value)
509 rprintf(FERROR,"syntax error - %s does not take a value\n",tok);
510
511 {
512 int on = socket_options[i].value;
513 ret = setsockopt(fd,socket_options[i].level,
514 socket_options[i].option,(char *)&on,sizeof(int));
515 }
516 break;
517 }
518
519 if (ret != 0)
660c6fbd
MP
520 rprintf(FERROR, "failed to set socket option %s: %s\n", tok,
521 strerror(errno));
f0fca04e
AT
522 }
523
524 free(options);
525}
526
527/****************************************************************************
528become a daemon, discarding the controlling terminal
529****************************************************************************/
530void become_daemon(void)
531{
b11ed3b1
AT
532 int i;
533
c46ded46 534 if (fork()) {
f0fca04e 535 _exit(0);
c46ded46 536 }
f0fca04e
AT
537
538 /* detach from the terminal */
539#ifdef HAVE_SETSID
540 setsid();
541#else
542#ifdef TIOCNOTTY
c46ded46
AT
543 i = open("/dev/tty", O_RDWR);
544 if (i >= 0) {
545 ioctl(i, (int) TIOCNOTTY, (char *)0);
546 close(i);
f0fca04e
AT
547 }
548#endif /* TIOCNOTTY */
549#endif
b11ed3b1
AT
550 /* make sure that stdin, stdout an stderr don't stuff things
551 up (library functions, for example) */
552 for (i=0;i<3;i++) {
553 close(i);
554 open("/dev/null", O_RDWR);
555 }
bc2e93eb 556}
ff8b29b8 557
1f0fa931
MP
558/**
559 * Return the IP addr of the client as a string
560 **/
ff8b29b8
AT
561char *client_addr(int fd)
562{
2d6dbe29 563 struct sockaddr_storage ss;
06963d0f 564 int length = sizeof(ss);
ff8b29b8 565 static char addr_buf[100];
11a5a3c7
AT
566 static int initialised;
567
568 if (initialised) return addr_buf;
569
570 initialised = 1;
ff8b29b8 571
2d6dbe29 572 if (getpeername(fd, (struct sockaddr *)&ss, &length)) {
65417579 573 exit_cleanup(RERR_SOCKETIO);
ff8b29b8 574 }
06963d0f 575
2d6dbe29 576 getnameinfo((struct sockaddr *)&ss, length,
06963d0f 577 addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
ff8b29b8
AT
578 return addr_buf;
579}
580
581
51f289d1 582static int get_sockaddr_family(const struct sockaddr_storage *ss)
d91c8c50
MP
583{
584 return ((struct sockaddr *) ss)->sa_family;
585}
586
587
1f0fa931
MP
588/**
589 * Return the DNS name of the client
590 **/
ff8b29b8
AT
591char *client_name(int fd)
592{
2d6dbe29 593 struct sockaddr_storage ss;
06963d0f 594 int length = sizeof(ss);
ff8b29b8 595 static char name_buf[100];
06963d0f 596 static char port_buf[100];
de5fb374 597 char *def = "UNKNOWN";
11a5a3c7 598 static int initialised;
06963d0f
MP
599 struct addrinfo hints, *res, *res0;
600 int error;
11a5a3c7
AT
601
602 if (initialised) return name_buf;
603
604 initialised = 1;
ff8b29b8 605
de5fb374 606 strcpy(name_buf,def);
ff8b29b8 607
06963d0f 608 if (getpeername(fd, (struct sockaddr *)&ss, &length)) {
d5d4b282
MP
609 /* FIXME: Can we really not continue? */
610 rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
c11b8806 611 fd, strerror(errno));
65417579 612 exit_cleanup(RERR_SOCKETIO);
ff8b29b8
AT
613 }
614
06963d0f 615#ifdef INET6
d91c8c50 616 if (get_sockaddr_family(&ss) == AF_INET6 &&
06963d0f
MP
617 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)&ss)->sin6_addr)) {
618 struct sockaddr_in6 sin6;
619 struct sockaddr_in *sin;
620
621 memcpy(&sin6, &ss, sizeof(sin6));
622 sin = (struct sockaddr_in *)&ss;
623 memset(sin, 0, sizeof(*sin));
624 sin->sin_family = AF_INET;
625 length = sizeof(struct sockaddr_in);
626#ifdef HAVE_SOCKADDR_LEN
627 sin->sin_len = length;
628#endif
629 sin->sin_port = sin6.sin6_port;
630 memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
631 sizeof(sin->sin_addr));
632 }
633#endif
634
635 /* reverse lookup */
636 if (getnameinfo((struct sockaddr *)&ss, length,
637 name_buf, sizeof(name_buf), port_buf, sizeof(port_buf),
638 NI_NAMEREQD | NI_NUMERICSERV) != 0) {
639 strcpy(name_buf, def);
640 rprintf(FERROR, "reverse name lookup failed\n");
ff8b29b8
AT
641 }
642
06963d0f
MP
643 /* forward lookup */
644 memset(&hints, 0, sizeof(hints));
645 hints.ai_family = PF_UNSPEC;
646 hints.ai_flags = AI_CANONNAME;
647 hints.ai_socktype = SOCK_STREAM;
648 error = getaddrinfo(name_buf, port_buf, &hints, &res0);
649 if (error) {
650 strcpy(name_buf, def);
7ef6aa64
MP
651 rprintf(FERROR,
652 RSYNC_NAME ": forward name lookup for %s failed: %s\n",
653 port_buf,
654 gai_strerror(error));
06963d0f
MP
655 return name_buf;
656 }
de5fb374 657
06963d0f
MP
658 /* XXX sin6_flowinfo and other fields */
659 for (res = res0; res; res = res->ai_next) {
d91c8c50 660 if (res->ai_family != get_sockaddr_family(&ss))
06963d0f
MP
661 continue;
662 if (res->ai_addrlen != length)
663 continue;
664 if (memcmp(res->ai_addr, &ss, res->ai_addrlen) == 0)
665 break;
666 }
667
61f543ca 668 /* TODO: Do a forward lookup as well to prevent spoofing */
06963d0f
MP
669
670 if (res == NULL) {
671 strcpy(name_buf, def);
d5d4b282
MP
672 rprintf(FERROR, RSYNC_NAME ": "
673 "reverse name lookup mismatch on fd%d - spoofed address?\n",
674 fd);
de5fb374
AT
675 }
676
06963d0f 677 freeaddrinfo(res0);
ff8b29b8
AT
678 return name_buf;
679}
5c9730a4 680
eecd22ff
MP
681
682/*******************************************************************
683this is like socketpair but uses tcp. It is used by the Samba
684regression test code
685The function guarantees that nobody else can attach to the socket,
686or if they do that this function fails and the socket gets closed
687returns 0 on success, -1 on failure
688the resulting file descriptors are symmetrical
689 ******************************************************************/
690static int socketpair_tcp(int fd[2])
691{
692 int listener;
693 struct sockaddr_in sock;
694 struct sockaddr_in sock2;
695 socklen_t socklen = sizeof(sock);
696 int connect_done = 0;
697
698 fd[0] = fd[1] = listener = -1;
699
700 memset(&sock, 0, sizeof(sock));
701
702 if ((listener = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
703
704 memset(&sock2, 0, sizeof(sock2));
705#ifdef HAVE_SOCK_SIN_LEN
706 sock2.sin_len = sizeof(sock2);
707#endif
708 sock2.sin_family = PF_INET;
709
710 bind(listener, (struct sockaddr *)&sock2, sizeof(sock2));
711
712 if (listen(listener, 1) != 0) goto failed;
713
714 if (getsockname(listener, (struct sockaddr *)&sock, &socklen) != 0) goto failed;
715
716 if ((fd[1] = socket(PF_INET, SOCK_STREAM, 0)) == -1) goto failed;
717
718 set_nonblocking(fd[1]);
719
720 sock.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
721
722 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) == -1) {
723 if (errno != EINPROGRESS) goto failed;
724 } else {
725 connect_done = 1;
726 }
727
728 if ((fd[0] = accept(listener, (struct sockaddr *)&sock, &socklen)) == -1) goto failed;
729
730 close(listener);
731 if (connect_done == 0) {
732 if (connect(fd[1],(struct sockaddr *)&sock,sizeof(sock)) != 0
733 && errno != EISCONN) goto failed;
734 }
735
736 set_blocking (fd[1]);
737
738 /* all OK! */
739 return 0;
740
741 failed:
742 if (fd[0] != -1) close(fd[0]);
743 if (fd[1] != -1) close(fd[1]);
744 if (listener != -1) close(listener);
745 return -1;
746}
747
748
749/*******************************************************************
750run a program on a local tcp socket, this is used to launch smbd
751when regression testing
752the return value is a socket which is attached to a subprocess
753running "prog". stdin and stdout are attached. stderr is left
754attached to the original stderr
755 ******************************************************************/
756int sock_exec(const char *prog)
757{
758 int fd[2];
759 if (socketpair_tcp(fd) != 0) {
760 rprintf (FERROR, RSYNC_NAME
761 ": socketpair_tcp failed (%s)\n",
762 strerror(errno));
763 return -1;
764 }
765 if (fork() == 0) {
766 close(fd[0]);
767 close(0);
768 close(1);
769 dup(fd[1]);
770 dup(fd[1]);
771 if (verbose > 3)
772 fprintf (stderr,
773 RSYNC_NAME ": execute socket program \"%s\"\n",
774 prog);
775 exit (system (prog));
776 }
777 close (fd[1]);
778 return fd[0];
779}
780
781
782