blob: 23a911e891e551bca35411678d1e75c89c0ad57a [file] [log] [blame]
San Mehata430b2b2014-09-23 08:30:51 -07001/*
2 Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3 All rights reserved.
4
5This file is part of x11vnc.
6
7x11vnc is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License as published by
9the Free Software Foundation; either version 2 of the License, or (at
10your option) any later version.
11
12x11vnc is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
18along with x11vnc; if not, write to the Free Software
19Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20or see <http://www.gnu.org/licenses/>.
21
22In addition, as a special exception, Karl J. Runge
23gives permission to link the code of its release of x11vnc with the
24OpenSSL project's "OpenSSL" library (or with modified versions of it
25that use the same license as the "OpenSSL" library), and distribute
26the linked executables. You must obey the GNU General Public License
27in all respects for all of the code used other than "OpenSSL". If you
28modify this file, you may extend this exception to your version of the
29file, but you are not obligated to do so. If you do not wish to do
30so, delete this exception statement from your version.
31*/
32
33/* -- inet.c -- */
34
35#include "x11vnc.h"
36#include "unixpw.h"
37#include "sslhelper.h"
38
39/*
40 * Simple utility to map host name to dotted IP address. Ignores aliases.
41 * Up to caller to free returned string.
42 */
43char *host2ip(char *host);
44char *raw2host(char *raw, int len);
45char *raw2ip(char *raw);
46char *ip2host(char *ip);
47int ipv6_ip(char *host);
48int dotted_ip(char *host, int partial);
49int get_remote_port(int sock);
50int get_local_port(int sock);
51char *get_remote_host(int sock);
52char *get_local_host(int sock);
53char *ident_username(rfbClientPtr client);
54int find_free_port(int start, int end);
55int find_free_port6(int start, int end);
56int have_ssh_env(void);
57char *ipv6_getnameinfo(struct sockaddr *paddr, int addrlen);
58char *ipv6_getipaddr(struct sockaddr *paddr, int addrlen);
59int listen6(int port);
60int listen_unix(char *file);
61int accept_unix(int s);
62int connect_tcp(char *host, int port);
63int listen_tcp(int port, in_addr_t iface, int try6);
64
65static int get_port(int sock, int remote);
66static char *get_host(int sock, int remote);
67
68char *host2ip(char *host) {
69 struct hostent *hp;
70 struct sockaddr_in addr;
71 char *str;
72
73 if (! host_lookup) {
74 return NULL;
75 }
76
77 hp = gethostbyname(host);
78 if (!hp) {
79 return NULL;
80 }
81 memset(&addr, 0, sizeof(addr));
82 addr.sin_family = AF_INET;
83 addr.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
84 str = strdup(inet_ntoa(addr.sin_addr));
85 return str;
86}
87
88char *raw2host(char *raw, int len) {
89 char *str;
90#if LIBVNCSERVER_HAVE_NETDB_H && LIBVNCSERVER_HAVE_NETINET_IN_H
91 struct hostent *hp;
92
93 if (! host_lookup) {
94 return strdup("unknown");
95 }
96
97 hp = gethostbyaddr(raw, len, AF_INET);
98 if (!hp) {
99 return strdup(inet_ntoa(*((struct in_addr *)raw)));
100 }
101 str = strdup(hp->h_name);
102#else
103 str = strdup("unknown");
104#endif
105 return str;
106}
107
108char *raw2ip(char *raw) {
109 return strdup(inet_ntoa(*((struct in_addr *)raw)));
110}
111
112char *ip2host(char *ip) {
113 char *str;
114#if LIBVNCSERVER_HAVE_NETDB_H && LIBVNCSERVER_HAVE_NETINET_IN_H
115 struct hostent *hp;
116 in_addr_t iaddr;
117
118 if (! host_lookup) {
119 return strdup("unknown");
120 }
121
122 iaddr = inet_addr(ip);
123 if (iaddr == htonl(INADDR_NONE)) {
124 return strdup("unknown");
125 }
126
127 hp = gethostbyaddr((char *)&iaddr, sizeof(in_addr_t), AF_INET);
128 if (!hp) {
129 return strdup("unknown");
130 }
131 str = strdup(hp->h_name);
132#else
133 str = strdup("unknown");
134#endif
135 return str;
136}
137
138int ipv6_ip(char *host_in) {
139 char *p, *host, a[2];
140 int ncol = 0, nhex = 0;
141
142 if (host_in[0] == '[') {
143 host = host_in + 1;
144 } else {
145 host = host_in;
146 }
147
148 if (strstr(host, "::ffff:") == host || strstr(host, "::FFFF:") == host) {
149 return dotted_ip(host + strlen("::ffff:"), 0);
150 }
151
152 a[1] = '\0';
153
154 p = host;
155 while (*p != '\0' && *p != '%' && *p != ']') {
156 if (*p == ':') {
157 ncol++;
158 } else {
159 nhex++;
160 }
161 a[0] = *p;
162 if (strpbrk(a, ":abcdef0123456789") == a) {
163 p++;
164 continue;
165 }
166 return 0;
167 }
168 if (ncol < 2 || ncol > 8 || nhex == 0) {
169 return 0;
170 } else {
171 return 1;
172 }
173}
174
175int dotted_ip(char *host, int partial) {
176 int len, dots = 0;
177 char *p = host;
178
179 if (!host) {
180 return 0;
181 }
182
183 if (!isdigit((unsigned char) host[0])) {
184 return 0;
185 }
186
187 len = strlen(host);
188 if (!partial && !isdigit((unsigned char) host[len-1])) {
189 return 0;
190 }
191
192 while (*p != '\0') {
193 if (*p == '.') dots++;
194 if (*p == '.' || isdigit((unsigned char) (*p))) {
195 p++;
196 continue;
197 }
198 return 0;
199 }
200 if (!partial && dots != 3) {
201 return 0;
202 }
203 return 1;
204}
205
206static int get_port(int sock, int remote) {
207 struct sockaddr_in saddr;
208 unsigned int saddr_len;
209 int saddr_port;
210
211 saddr_len = sizeof(saddr);
212 memset(&saddr, 0, sizeof(saddr));
213 saddr_port = -1;
214 if (remote) {
215 if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
216 saddr_port = ntohs(saddr.sin_port);
217 }
218 } else {
219 if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
220 saddr_port = ntohs(saddr.sin_port);
221 }
222 }
223 return saddr_port;
224}
225
226int get_remote_port(int sock) {
227 return get_port(sock, 1);
228}
229
230int get_local_port(int sock) {
231 return get_port(sock, 0);
232}
233
234static char *get_host(int sock, int remote) {
235 struct sockaddr_in saddr;
236 unsigned int saddr_len;
237 int saddr_port;
238 char *saddr_ip_str = NULL;
239
240 saddr_len = sizeof(saddr);
241 memset(&saddr, 0, sizeof(saddr));
242 saddr_port = -1;
243#if LIBVNCSERVER_HAVE_NETINET_IN_H
244 if (remote) {
245 if (!getpeername(sock, (struct sockaddr *)&saddr, &saddr_len)) {
246 saddr_ip_str = inet_ntoa(saddr.sin_addr);
247 }
248 } else {
249 if (!getsockname(sock, (struct sockaddr *)&saddr, &saddr_len)) {
250 saddr_ip_str = inet_ntoa(saddr.sin_addr);
251 }
252 }
253#endif
254 if (! saddr_ip_str) {
255 saddr_ip_str = "unknown";
256 }
257 return strdup(saddr_ip_str);
258}
259
260char *get_remote_host(int sock) {
261 return get_host(sock, 1);
262}
263
264char *get_local_host(int sock) {
265 return get_host(sock, 0);
266}
267
268char *ident_username(rfbClientPtr client) {
269 ClientData *cd = (ClientData *) client->clientData;
270 char *str, *newhost, *user = NULL, *newuser = NULL;
271 int len;
272
273 if (cd) {
274 user = cd->username;
275 }
276 if (!user || *user == '\0') {
277 int n, sock, ok = 0;
278 int block = 0;
279 int refused = 0;
280
281 /*
282 * need to check to see if the operation will block for
283 * a long time: a firewall may just ignore our packets.
284 */
285#if LIBVNCSERVER_HAVE_FORK
286 { pid_t pid, pidw;
287 int rc;
288 if ((pid = fork()) > 0) {
289 usleep(100 * 1000); /* 0.1 sec for quick success or refusal */
290 pidw = waitpid(pid, &rc, WNOHANG);
291 if (pidw <= 0) {
292 usleep(1500 * 1000); /* 1.5 sec */
293 pidw = waitpid(pid, &rc, WNOHANG);
294 if (pidw <= 0) {
295 int rc2;
296 rfbLog("ident_username: set block=1 (hung)\n");
297 block = 1;
298 kill(pid, SIGTERM);
299 usleep(100 * 1000);
300 waitpid(pid, &rc2, WNOHANG);
301 }
302 }
303 if (pidw > 0 && !block) {
304 if (WIFEXITED(rc) && WEXITSTATUS(rc) == 1) {
305 rfbLog("ident_username: set refused=1 (exit)\n");
306 refused = 1;
307 }
308 }
309 } else if (pid == -1) {
310 ;
311 } else {
312 /* child */
313 signal(SIGHUP, SIG_DFL);
314 signal(SIGINT, SIG_DFL);
315 signal(SIGQUIT, SIG_DFL);
316 signal(SIGTERM, SIG_DFL);
317
318 if ((sock = connect_tcp(client->host, 113)) < 0) {
319 exit(1);
320 } else {
321 close(sock);
322 exit(0);
323 }
324 }
325 }
326#endif
327 if (block || refused) {
328 ;
329 } else if ((sock = connect_tcp(client->host, 113)) < 0) {
330 rfbLog("ident_username: could not connect to ident: %s:%d\n",
331 client->host, 113);
332 } else {
333 char msg[128];
334 int ret;
335 fd_set rfds;
336 struct timeval tv;
337 int rport = get_remote_port(client->sock);
338 int lport = get_local_port(client->sock);
339
340 sprintf(msg, "%d, %d\r\n", rport, lport);
341 n = write(sock, msg, strlen(msg));
342
343 FD_ZERO(&rfds);
344 FD_SET(sock, &rfds);
345 tv.tv_sec = 3;
346 tv.tv_usec = 0;
347 ret = select(sock+1, &rfds, NULL, NULL, &tv);
348
349 if (ret > 0) {
350 int i;
351 char *q, *p;
352 for (i=0; i < (int) sizeof(msg); i++) {
353 msg[i] = '\0';
354 }
355 usleep(250*1000);
356 n = read(sock, msg, 127);
357 close(sock);
358 if (n <= 0) goto badreply;
359
360 /* 32782 , 6000 : USERID : UNIX :runge */
361 q = strstr(msg, "USERID");
362 if (!q) goto badreply;
363 q = strstr(q, ":");
364 if (!q) goto badreply;
365 q++;
366 q = strstr(q, ":");
367 if (!q) goto badreply;
368 q++;
369 q = lblanks(q);
370 p = q;
371 while (*p) {
372 if (*p == '\r' || *p == '\n') {
373 *p = '\0';
374 }
375 p++;
376 }
377 ok = 1;
378 if (strlen(q) > 24) {
379 *(q+24) = '\0';
380 }
381 newuser = strdup(q);
382
383 badreply:
384 n = 0; /* avoid syntax error */
385 } else {
386 close(sock);
387 }
388 }
389 if (! ok || !newuser) {
390 newuser = strdup("unknown-user");
391 }
392 if (cd) {
393 if (cd->username) {
394 free(cd->username);
395 }
396 cd->username = newuser;
397 }
398 user = newuser;
399 }
400 if (!strcmp(user, "unknown-user") && cd && cd->unixname[0] != '\0') {
401 user = cd->unixname;
402 }
403 if (unixpw && openssl_last_ip && strstr("UNIX:", user) != user) {
404 newhost = ip2host(openssl_last_ip);
405 } else {
406 newhost = ip2host(client->host);
407 }
408 len = strlen(user) + 1 + strlen(newhost) + 1;
409 str = (char *) malloc(len);
410 sprintf(str, "%s@%s", user, newhost);
411 free(newhost);
412 return str;
413}
414
415int find_free_port(int start, int end) {
416 int port;
417 if (start <= 0) {
418 start = 1024;
419 }
420 if (end <= 0) {
421 end = 65530;
422 }
423 for (port = start; port <= end; port++) {
424 int sock = listen_tcp(port, htonl(INADDR_ANY), 0);
425 if (sock >= 0) {
426 close(sock);
427 return port;
428 }
429 }
430 return 0;
431}
432
433int find_free_port6(int start, int end) {
434 int port;
435 if (start <= 0) {
436 start = 1024;
437 }
438 if (end <= 0) {
439 end = 65530;
440 }
441 for (port = start; port <= end; port++) {
442 int sock = listen6(port);
443 if (sock >= 0) {
444 close(sock);
445 return port;
446 }
447 }
448 return 0;
449}
450
451int have_ssh_env(void) {
452 char *str, *p = getenv("SSH_CONNECTION");
453 char *rhost, *rport, *lhost, *lport;
454
455 if (! p) {
456 char *q = getenv("SSH_CLIENT");
457 if (! q) {
458 return 0;
459 }
460 if (strstr(q, "127.0.0.1") != NULL) {
461 return 0;
462 }
463 return 1;
464 }
465
466 if (strstr(p, "127.0.0.1") != NULL) {
467 return 0;
468 }
469
470 str = strdup(p);
471
472 p = strtok(str, " ");
473 rhost = p;
474
475 p = strtok(NULL, " ");
476 if (! p) goto fail;
477
478 rport = p;
479
480 p = strtok(NULL, " ");
481 if (! p) goto fail;
482
483 lhost = p;
484
485 p = strtok(NULL, " ");
486 if (! p) goto fail;
487
488 lport = p;
489
490if (0) fprintf(stderr, "%d/%d - '%s' '%s'\n", atoi(rport), atoi(lport), rhost, lhost);
491
492 if (atoi(rport) <= 16 || atoi(rport) > 65535) {
493 goto fail;
494 }
495 if (atoi(lport) <= 16 || atoi(lport) > 65535) {
496 goto fail;
497 }
498
499 if (!strcmp(rhost, lhost)) {
500 goto fail;
501 }
502
503 free(str);
504
505 return 1;
506
507 fail:
508
509 free(str);
510
511 return 0;
512}
513
514char *ipv6_getnameinfo(struct sockaddr *paddr, int addrlen) {
515#if X11VNC_IPV6
516 char name[200];
517 if (noipv6) {
518 return strdup("unknown");
519 }
520 if (getnameinfo(paddr, addrlen, name, sizeof(name), NULL, 0, 0) == 0) {
521 return strdup(name);
522 }
523#endif
524 return strdup("unknown");
525}
526
527char *ipv6_getipaddr(struct sockaddr *paddr, int addrlen) {
528#if X11VNC_IPV6 && defined(NI_NUMERICHOST)
529 char name[200];
530 if (noipv6) {
531 return strdup("unknown");
532 }
533 if (getnameinfo(paddr, addrlen, name, sizeof(name), NULL, 0, NI_NUMERICHOST) == 0) {
534 return strdup(name);
535 }
536#endif
537 return strdup("unknown");
538}
539
540int listen6(int port) {
541#if X11VNC_IPV6
542 struct sockaddr_in6 sin;
543 int fd = -1, one = 1;
544
545 if (noipv6) {
546 return -1;
547 }
548 if (port <= 0 || 65535 < port) {
549 /* for us, invalid port means do not listen. */
550 return -1;
551 }
552
553 fd = socket(AF_INET6, SOCK_STREAM, 0);
554 if (fd < 0) {
555 rfbLogPerror("listen6: socket");
556 rfbLog("(Ignore the above error if this system is IPv4-only.)\n");
557 return -1;
558 }
559
560 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) {
561 rfbLogPerror("listen6: setsockopt SO_REUSEADDR");
562 close(fd);
563 return -1;
564 }
565
566#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
567 if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) {
568 rfbLogPerror("listen6: setsockopt IPV6_V6ONLY");
569 close(fd);
570 return -1;
571 }
572#endif
573
574 memset((char *)&sin, 0, sizeof(sin));
575 sin.sin6_family = AF_INET6;
576 sin.sin6_port = htons(port);
577 sin.sin6_addr = in6addr_any;
578
579 if (listen_str6) {
580 if (!strcmp(listen_str6, "localhost") || !strcmp(listen_str6, "::1")) {
581 sin.sin6_addr = in6addr_loopback;
582 } else {
583 int err;
584 struct addrinfo *ai;
585 struct addrinfo hints;
586 char service[32];
587
588 memset(&hints, 0, sizeof(hints));
589 sprintf(service, "%d", port);
590
591 hints.ai_family = AF_INET6;
592 hints.ai_socktype = SOCK_STREAM;
593#ifdef AI_ADDRCONFIG
594 hints.ai_flags |= AI_ADDRCONFIG;
595#endif
596#ifdef AI_NUMERICHOST
597 if(ipv6_ip(listen_str6)) {
598 hints.ai_flags |= AI_NUMERICHOST;
599 }
600#endif
601#ifdef AI_NUMERICSERV
602 hints.ai_flags |= AI_NUMERICSERV;
603#endif
604 err = getaddrinfo(listen_str6, service, &hints, &ai);
605 if (err == 0) {
606 struct addrinfo *ap = ai;
607 err = 1;
608 while (ap != NULL) {
609 char *s = ipv6_getipaddr(ap->ai_addr, ap->ai_addrlen);
610 if (!s) s = strdup("unknown");
611
612 rfbLog("listen6: checking: %s family: %d\n", s, ap->ai_family);
613 if (ap->ai_family == AF_INET6) {
614 memcpy((char *)&sin, ap->ai_addr, sizeof(sin));
615 rfbLog("listen6: using: %s scope_id: %d\n", s, sin.sin6_scope_id);
616 err = 0;
617 free(s);
618 break;
619 }
620 free(s);
621 ap = ap->ai_next;
622 }
623 freeaddrinfo(ai);
624 }
625
626 if (err != 0) {
627 rfbLog("Invalid or Unsupported -listen6 string: %s\n", listen_str6);
628 close(fd);
629 return -1;
630 }
631 }
632 } else if (allow_list && !strcmp(allow_list, "127.0.0.1")) {
633 sin.sin6_addr = in6addr_loopback;
634 } else if (listen_str) {
635 if (!strcmp(listen_str, "localhost")) {
636 sin.sin6_addr = in6addr_loopback;
637 }
638 }
639
640 if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
641 rfbLogPerror("listen6: bind");
642 close(fd);
643 return -1;
644 }
645 if (listen(fd, 32) < 0) {
646 rfbLogPerror("listen6: listen");
647 close(fd);
648 return -1;
649 }
650 return fd;
651#else
652 if (port) {}
653 return -1;
654#endif
655}
656
657#ifdef LIBVNCSERVER_HAVE_SYS_SOCKET_H
658#include <sys/un.h>
659#endif
660
661int listen_unix(char *file) {
662#if !defined(AF_UNIX) || !defined(LIBVNCSERVER_HAVE_SYS_SOCKET_H)
663 if (sock) {}
664 return -1;
665#else
666 int s, len;
667 struct sockaddr_un saun;
668
669 s = socket(AF_UNIX, SOCK_STREAM, 0);
670 if (s < 0) {
671 rfbLogPerror("listen_unix: socket");
672 return -1;
673 }
674 saun.sun_family = AF_UNIX;
675 strcpy(saun.sun_path, file);
676 unlink(file);
677
678 len = sizeof(saun.sun_family) + strlen(saun.sun_path);
679
680 if (bind(s, (struct sockaddr *)&saun, len) < 0) {
681 rfbLogPerror("listen_unix: bind");
682 close(s);
683 return -1;
684 }
685
686 if (listen(s, 32) < 0) {
687 rfbLogPerror("listen_unix: listen");
688 close(s);
689 return -1;
690 }
691 rfbLog("listening on unix socket: %s fd=%d\n", file, s);
692 return s;
693#endif
694}
695
696int accept_unix(int s) {
697#if !defined(AF_UNIX) || !defined(LIBVNCSERVER_HAVE_SYS_SOCKET_H)
698 if (s) {}
699 return -1;
700#else
701 int fd, fromlen;
702 struct sockaddr_un fsaun;
703
704 fd = accept(s, (struct sockaddr *)&fsaun, &fromlen);
705 if (fd < 0) {
706 rfbLogPerror("accept_unix: accept");
707 return -1;
708 }
709 return fd;
710#endif
711}
712
713int connect_tcp(char *host, int port) {
714 double t0 = dnow();
715 int fd = -1;
716 int fail4 = noipv4;
717 if (getenv("IPV4_FAILS")) {
718 fail4 = 2;
719 }
720
721 rfbLog("connect_tcp: trying: %s %d\n", host, port);
722
723 if (fail4) {
724 if (fail4 > 1) {
725 rfbLog("TESTING: IPV4_FAILS for connect_tcp.\n");
726 }
727 } else {
728 fd = rfbConnectToTcpAddr(host, port);
729 }
730
731 if (fd >= 0) {
732 return fd;
733 }
734 rfbLogPerror("connect_tcp: connection failed");
735
736 if (dnow() - t0 < 4.0) {
737 rfbLog("connect_tcp: re-trying %s %d\n", host, port);
738 usleep (100 * 1000);
739 if (!fail4) {
740 fd = rfbConnectToTcpAddr(host, port);
741 }
742 if (fd < 0) {
743 rfbLogPerror("connect_tcp: connection failed");
744 }
745 }
746
747 if (fd < 0 && !noipv6) {
748#if X11VNC_IPV6
749 int err;
750 struct addrinfo *ai;
751 struct addrinfo hints;
752 char service[32], *host2, *q;
753
754 rfbLog("connect_tcp: trying IPv6 %s %d\n", host, port);
755
756 memset(&hints, 0, sizeof(hints));
757 sprintf(service, "%d", port);
758
759 hints.ai_family = AF_UNSPEC;
760 hints.ai_socktype = SOCK_STREAM;
761#ifdef AI_ADDRCONFIG
762 hints.ai_flags |= AI_ADDRCONFIG;
763#endif
764 if(ipv6_ip(host)) {
765#ifdef AI_NUMERICHOST
766 rfbLog("connect_tcp[ipv6]: setting AI_NUMERICHOST for %s\n", host);
767 hints.ai_flags |= AI_NUMERICHOST;
768#endif
769 }
770#ifdef AI_NUMERICSERV
771 hints.ai_flags |= AI_NUMERICSERV;
772#endif
773
774 if (!strcmp(host, "127.0.0.1")) {
775 host2 = strdup("::1");
776 } else if (host[0] == '[') {
777 host2 = strdup(host+1);
778 } else {
779 host2 = strdup(host);
780 }
781 q = strrchr(host2, ']');
782 if (q) {
783 *q = '\0';
784 }
785
786 err = getaddrinfo(host2, service, &hints, &ai);
787 if (err != 0) {
788 rfbLog("connect_tcp[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err));
789 usleep(100 * 1000);
790 err = getaddrinfo(host2, service, &hints, &ai);
791 }
792 free(host2);
793
794 if (err != 0) {
795 rfbLog("connect_tcp[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err));
796 } else {
797 struct addrinfo *ap = ai;
798 while (ap != NULL) {
799 int sock;
800
801 if (fail4) {
802 struct sockaddr_in6 *s6ptr;
803 if (ap->ai_family != AF_INET6) {
804 rfbLog("connect_tcp[ipv6]: skipping AF_INET address under -noipv4\n");
805 ap = ap->ai_next;
806 continue;
807 }
808#ifdef IN6_IS_ADDR_V4MAPPED
809 s6ptr = (struct sockaddr_in6 *) ap->ai_addr;
810 if (IN6_IS_ADDR_V4MAPPED(&(s6ptr->sin6_addr))) {
811 rfbLog("connect_tcp[ipv6]: skipping V4MAPPED address under -noipv4\n");
812 ap = ap->ai_next;
813 continue;
814 }
815#endif
816 }
817
818 sock = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
819
820 if (sock == -1) {
821 rfbLogPerror("connect_tcp[ipv6]: socket");
822 if (0) rfbLog("(Ignore the above error if this system is IPv4-only.)\n");
823 } else {
824 int res = -1, dmsg = 0;
825 char *s = ipv6_getipaddr(ap->ai_addr, ap->ai_addrlen);
826 if (!s) s = strdup("unknown");
827
828 rfbLog("connect_tcp[ipv6]: trying sock=%d fam=%d proto=%d using %s\n",
829 sock, ap->ai_family, ap->ai_protocol, s);
830 res = connect(sock, ap->ai_addr, ap->ai_addrlen);
831#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
832 if (res != 0) {
833 int zero = 0;
834 rfbLogPerror("connect_tcp[ipv6]: connect");
835 dmsg = 1;
836 if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY, (char *)&zero, sizeof(zero)) == 0) {
837 rfbLog("connect_tcp[ipv6]: trying again with IPV6_V6ONLY=0\n");
838 res = connect(sock, ap->ai_addr, ap->ai_addrlen);
839 dmsg = 0;
840 } else {
841 rfbLogPerror("connect_tcp[ipv6]: setsockopt IPV6_V6ONLY");
842 }
843 }
844#endif
845 if (res == 0) {
846 rfbLog("connect_tcp[ipv6]: connect OK\n");
847 fd = sock;
848 if (!ipv6_client_ip_str) {
849 ipv6_client_ip_str = strdup(s);
850 }
851 free(s);
852 break;
853 } else {
854 if (!dmsg) rfbLogPerror("connect_tcp[ipv6]: connect");
855 close(sock);
856 }
857 free(s);
858 }
859 ap = ap->ai_next;
860 }
861 freeaddrinfo(ai);
862 }
863#endif
864 }
865 if (fd < 0 && !fail4) {
866 /* this is a kludge for IPv4-only machines getting v4mapped string. */
867 char *q, *host2;
868 if (host[0] == '[') {
869 host2 = strdup(host+1);
870 } else {
871 host2 = strdup(host);
872 }
873 q = strrchr(host2, ']');
874 if (q) {
875 *q = '\0';
876 }
877 if (strstr(host2, "::ffff:") == host2 || strstr(host2, "::FFFF:") == host2) {
878 char *host3 = host2 + strlen("::ffff:");
879 if (dotted_ip(host3, 0)) {
880 rfbLog("connect_tcp[ipv4]: trying fallback to IPv4 for %s\n", host2);
881 fd = rfbConnectToTcpAddr(host3, port);
882 if (fd < 0) {
883 rfbLogPerror("connect_tcp[ipv4]: connection failed");
884 }
885 }
886 }
887 free(host2);
888 }
889 return fd;
890}
891
892int listen_tcp(int port, in_addr_t iface, int try6) {
893 int fd = -1;
894 int fail4 = noipv4;
895 if (getenv("IPV4_FAILS")) {
896 fail4 = 2;
897 }
898
899 if (port <= 0 || 65535 < port) {
900 /* for us, invalid port means do not listen. */
901 return -1;
902 }
903
904 if (fail4) {
905 if (fail4 > 1) {
906 rfbLog("TESTING: IPV4_FAILS for listen_tcp: port=%d try6=%d\n", port, try6);
907 }
908 } else {
909 fd = rfbListenOnTCPPort(port, iface);
910 }
911
912 if (fd >= 0) {
913 return fd;
914 }
915 if (fail4 > 1) {
916 rfbLogPerror("listen_tcp: listen failed");
917 }
918
919 if (fd < 0 && try6 && ipv6_listen && !noipv6) {
920#if X11VNC_IPV6
921 char *save = listen_str6;
922 if (iface == htonl(INADDR_LOOPBACK)) {
923 listen_str6 = "localhost";
924 rfbLog("listen_tcp: retrying on IPv6 in6addr_loopback ...\n");
925 fd = listen6(port);
926 } else if (iface == htonl(INADDR_ANY)) {
927 listen_str6 = NULL;
928 rfbLog("listen_tcp: retrying on IPv6 in6addr_any ...\n");
929 fd = listen6(port);
930 }
931 listen_str6 = save;
932#endif
933 }
934 return fd;
935}
936