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