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