2
Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
5
This file is part of x11vnc.
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.
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.
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/>.
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.
512
char *ipv6_getnameinfo(struct sockaddr *paddr, int addrlen) {
516
return strdup("unknown");
518
if (getnameinfo(paddr, addrlen, name, sizeof(name), NULL, 0, 0) == 0) {
522
return strdup("unknown");
525
char *ipv6_getipaddr(struct sockaddr *paddr, int addrlen) {
526
#if X11VNC_IPV6 && defined(NI_NUMERICHOST)
529
return strdup("unknown");
531
if (getnameinfo(paddr, addrlen, name, sizeof(name), NULL, 0, NI_NUMERICHOST) == 0) {
535
return strdup("unknown");
538
int listen6(int port) {
540
struct sockaddr_in6 sin;
541
int fd = -1, one = 1;
546
if (port <= 0 || 65535 < port) {
547
/* for us, invalid port means do not listen. */
551
fd = socket(AF_INET6, SOCK_STREAM, 0);
553
rfbLogPerror("listen6: socket");
554
rfbLog("(Ignore the above error if this system is IPv4-only.)\n");
558
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) {
559
rfbLogPerror("listen6: setsockopt SO_REUSEADDR");
564
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
565
if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) {
566
rfbLogPerror("listen6: setsockopt IPV6_V6ONLY");
572
memset((char *)&sin, 0, sizeof(sin));
573
sin.sin6_family = AF_INET6;
574
sin.sin6_port = htons(port);
575
sin.sin6_addr = in6addr_any;
578
if (!strcmp(listen_str6, "localhost") || !strcmp(listen_str6, "::1")) {
579
sin.sin6_addr = in6addr_loopback;
583
struct addrinfo hints;
586
memset(&hints, 0, sizeof(hints));
587
sprintf(service, "%d", port);
589
hints.ai_family = AF_INET6;
590
hints.ai_socktype = SOCK_STREAM;
592
hints.ai_flags |= AI_ADDRCONFIG;
594
#ifdef AI_NUMERICHOST
595
if(ipv6_ip(listen_str6)) {
596
hints.ai_flags |= AI_NUMERICHOST;
599
#ifdef AI_NUMERICSERV
600
hints.ai_flags |= AI_NUMERICSERV;
602
err = getaddrinfo(listen_str6, service, &hints, &ai);
604
struct addrinfo *ap = ai;
607
char *s = ipv6_getipaddr(ap->ai_addr, ap->ai_addrlen);
608
if (!s) s = strdup("unknown");
610
rfbLog("listen6: checking: %s family: %d\n", s, ap->ai_family);
611
if (ap->ai_family == AF_INET6) {
612
memcpy((char *)&sin, ap->ai_addr, sizeof(sin));
613
rfbLog("listen6: using: %s scope_id: %d\n", s, sin.sin6_scope_id);
625
rfbLog("Invalid or Unsupported -listen6 string: %s\n", listen_str6);
630
} else if (allow_list && !strcmp(allow_list, "127.0.0.1")) {
631
sin.sin6_addr = in6addr_loopback;
632
} else if (listen_str) {
633
if (!strcmp(listen_str, "localhost")) {
634
sin.sin6_addr = in6addr_loopback;
638
if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
639
rfbLogPerror("listen6: bind");
643
if (listen(fd, 32) < 0) {
644
rfbLogPerror("listen6: listen");
655
int connect_tcp(char *host, int port) {
659
if (getenv("IPV4_FAILS")) {
663
rfbLog("connect_tcp: trying: %s %d\n", host, port);
667
rfbLog("TESTING: IPV4_FAILS for connect_tcp.\n");
670
fd = rfbConnectToTcpAddr(host, port);
676
rfbLogPerror("connect_tcp: connection failed");
678
if (dnow() - t0 < 4.0) {
679
rfbLog("connect_tcp: re-trying %s %d\n", host, port);
682
fd = rfbConnectToTcpAddr(host, port);
685
rfbLogPerror("connect_tcp: connection failed");
689
if (fd < 0 && !noipv6) {
693
struct addrinfo hints;
694
char service[32], *host2, *q;
696
rfbLog("connect_tcp: trying IPv6 %s %d\n", host, port);
698
memset(&hints, 0, sizeof(hints));
699
sprintf(service, "%d", port);
701
hints.ai_family = AF_UNSPEC;
702
hints.ai_socktype = SOCK_STREAM;
704
hints.ai_flags |= AI_ADDRCONFIG;
707
#ifdef AI_NUMERICHOST
708
rfbLog("connect_tcp[ipv6]: setting AI_NUMERICHOST for %s\n", host);
709
hints.ai_flags |= AI_NUMERICHOST;
712
#ifdef AI_NUMERICSERV
713
hints.ai_flags |= AI_NUMERICSERV;
716
if (!strcmp(host, "127.0.0.1")) {
717
host2 = strdup("::1");
718
} else if (host[0] == '[') {
719
host2 = strdup(host+1);
721
host2 = strdup(host);
723
q = strrchr(host2, ']');
728
err = getaddrinfo(host2, service, &hints, &ai);
730
rfbLog("connect_tcp[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err));
732
err = getaddrinfo(host2, service, &hints, &ai);
737
rfbLog("connect_tcp[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err));
739
struct addrinfo *ap = ai;
744
struct sockaddr_in6 *s6ptr;
745
if (ap->ai_family != AF_INET6) {
746
rfbLog("connect_tcp[ipv6]: skipping AF_INET address under -noipv4\n");
750
#ifdef IN6_IS_ADDR_V4MAPPED
751
s6ptr = (struct sockaddr_in6 *) ap->ai_addr;
752
if (IN6_IS_ADDR_V4MAPPED(&(s6ptr->sin6_addr))) {
753
rfbLog("connect_tcp[ipv6]: skipping V4MAPPED address under -noipv4\n");
760
sock = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
763
rfbLogPerror("connect_tcp[ipv6]: socket");
764
if (0) rfbLog("(Ignore the above error if this system is IPv4-only.)\n");
766
int res = -1, dmsg = 0;
767
char *s = ipv6_getipaddr(ap->ai_addr, ap->ai_addrlen);
768
if (!s) s = strdup("unknown");
770
rfbLog("connect_tcp[ipv6]: trying sock=%d fam=%d proto=%d using %s\n",
771
sock, ap->ai_family, ap->ai_protocol, s);
772
res = connect(sock, ap->ai_addr, ap->ai_addrlen);
773
#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
776
rfbLogPerror("connect_tcp[ipv6]: connect");
778
if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY, (char *)&zero, sizeof(zero)) == 0) {
779
rfbLog("connect_tcp[ipv6]: trying again with IPV6_V6ONLY=0\n");
780
res = connect(sock, ap->ai_addr, ap->ai_addrlen);
783
rfbLogPerror("connect_tcp[ipv6]: setsockopt IPV6_V6ONLY");
788
rfbLog("connect_tcp[ipv6]: connect OK\n");
790
if (!ipv6_client_ip_str) {
791
ipv6_client_ip_str = strdup(s);
796
if (!dmsg) rfbLogPerror("connect_tcp[ipv6]: connect");
807
if (fd < 0 && !fail4) {
808
/* this is a kludge for IPv4-only machines getting v4mapped string. */
810
if (host[0] == '[') {
811
host2 = strdup(host+1);
813
host2 = strdup(host);
815
q = strrchr(host2, ']');
819
if (strstr(host2, "::ffff:") == host2 || strstr(host2, "::FFFF:") == host2) {
820
char *host3 = host2 + strlen("::ffff:");
821
if (dotted_ip(host3, 0)) {
822
rfbLog("connect_tcp[ipv4]: trying fallback to IPv4 for %s\n", host2);
823
fd = rfbConnectToTcpAddr(host3, port);
825
rfbLogPerror("connect_tcp[ipv4]: connection failed");
834
int listen_tcp(int port, in_addr_t iface, int try6) {
837
if (getenv("IPV4_FAILS")) {
841
if (port <= 0 || 65535 < port) {
842
/* for us, invalid port means do not listen. */
848
rfbLog("TESTING: IPV4_FAILS for listen_tcp: port=%d try6=%d\n", port, try6);
851
fd = rfbListenOnTCPPort(port, iface);
858
rfbLogPerror("listen_tcp: listen failed");
861
if (fd < 0 && try6 && ipv6_listen && !noipv6) {
863
char *save = listen_str6;
864
if (iface == htonl(INADDR_LOOPBACK)) {
865
listen_str6 = "localhost";
866
rfbLog("listen_tcp: retrying on IPv6 in6addr_loopback ...\n");
868
} else if (iface == htonl(INADDR_ANY)) {
870
rfbLog("listen_tcp: retrying on IPv6 in6addr_any ...\n");