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