1 /*
2    Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
3    All rights reserved.
4 
5 This file is part of x11vnc.
6 
7 x11vnc is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or (at
10 your option) any later version.
11 
12 x11vnc is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with x11vnc; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
20 or see <http://www.gnu.org/licenses/>.
21 
22 In addition, as a special exception, Karl J. Runge
23 gives permission to link the code of its release of x11vnc with the
24 OpenSSL project's "OpenSSL" library (or with modified versions of it
25 that use the same license as the "OpenSSL" library), and distribute
26 the linked executables.  You must obey the GNU General Public License
27 in all respects for all of the code used other than "OpenSSL".  If you
28 modify this file, you may extend this exception to your version of the
29 file, but you are not obligated to do so.  If you do not wish to do
30 so, 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  */
43 char *host2ip(char *host);
44 char *raw2host(char *raw, int len);
45 char *raw2ip(char *raw);
46 char *ip2host(char *ip);
47 int ipv6_ip(char *host);
48 int dotted_ip(char *host, int partial);
49 int get_remote_port(int sock);
50 int get_local_port(int sock);
51 char *get_remote_host(int sock);
52 char *get_local_host(int sock);
53 char *ident_username(rfbClientPtr client);
54 int find_free_port(int start, int end);
55 int find_free_port6(int start, int end);
56 int have_ssh_env(void);
57 char *ipv6_getnameinfo(struct sockaddr *paddr, int addrlen);
58 char *ipv6_getipaddr(struct sockaddr *paddr, int addrlen);
59 int listen6(int port);
60 int listen_unix(char *file);
61 int accept_unix(int s);
62 int connect_tcp(char *host, int port);
63 int listen_tcp(int port, in_addr_t iface, int try6);
64 
65 static int get_port(int sock, int remote);
66 static char *get_host(int sock, int remote);
67 
host2ip(char * host)68 char *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 
raw2host(char * raw,int len)88 char *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 
raw2ip(char * raw)108 char *raw2ip(char *raw) {
109 	return strdup(inet_ntoa(*((struct in_addr *)raw)));
110 }
111 
ip2host(char * ip)112 char *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 
ipv6_ip(char * host_in)138 int 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 
dotted_ip(char * host,int partial)175 int 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 
get_port(int sock,int remote)206 static 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 
get_remote_port(int sock)226 int get_remote_port(int sock) {
227 	return get_port(sock, 1);
228 }
229 
get_local_port(int sock)230 int get_local_port(int sock) {
231 	return get_port(sock, 0);
232 }
233 
get_host(int sock,int remote)234 static 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 
get_remote_host(int sock)260 char *get_remote_host(int sock) {
261 	return get_host(sock, 1);
262 }
263 
get_local_host(int sock)264 char *get_local_host(int sock) {
265 	return get_host(sock, 0);
266 }
267 
ident_username(rfbClientPtr client)268 char *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 
find_free_port(int start,int end)415 int 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 
find_free_port6(int start,int end)433 int 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 
have_ssh_env(void)451 int 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 
490 if (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 
ipv6_getnameinfo(struct sockaddr * paddr,int addrlen)514 char *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 
ipv6_getipaddr(struct sockaddr * paddr,int addrlen)527 char *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 
listen6(int port)540 int 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 
listen_unix(char * file)661 int 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 
accept_unix(int s)696 int 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 
connect_tcp(char * host,int port)713 int 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 
listen_tcp(int port,in_addr_t iface,int try6)892 int 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 
937