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