1 /* 2 Copyright (C) 2002-2010 Karl J. Runge <runge (at) 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 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 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 108 char *raw2ip(char *raw) { 109 return strdup(inet_ntoa(*((struct in_addr *)raw))); 110 } 111 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 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 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 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 226 int get_remote_port(int sock) { 227 return get_port(sock, 1); 228 } 229 230 int get_local_port(int sock) { 231 return get_port(sock, 0); 232 } 233 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 260 char *get_remote_host(int sock) { 261 return get_host(sock, 1); 262 } 263 264 char *get_local_host(int sock) { 265 return get_host(sock, 0); 266 } 267 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 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 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 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 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 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 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 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 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 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 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