summaryrefslogtreecommitdiffstats
path: root/x11vnc/inet.c
diff options
context:
space:
mode:
authorrunge <[email protected]>2010-04-09 20:09:15 -0400
committerrunge <[email protected]>2010-04-09 20:09:15 -0400
commit2a8ba97ec5b0f7fbfcfc8adab6732a95e95c7204 (patch)
tree7da693c36f06f4e16e8bc2b030c54b67f01d8671 /x11vnc/inet.c
parent5c53ccbbe99dbf098dbb396a65b487f08315d825 (diff)
downloadlibtdevnc-2a8ba97ec5b0f7fbfcfc8adab6732a95e95c7204.tar.gz
libtdevnc-2a8ba97ec5b0f7fbfcfc8adab6732a95e95c7204.zip
x11vnc: exit(1) for -connect_or_exit failure, quiet query mode for grab_state, pointer_pos, etc. ipv6 support. STUNNEL_LISTEN for particular interface. -input_eagerly in addition to -allinput. quiet Xinerama message.
Diffstat (limited to 'x11vnc/inet.c')
-rw-r--r--x11vnc/inet.c327
1 files changed, 324 insertions, 3 deletions
diff --git a/x11vnc/inet.c b/x11vnc/inet.c
index d63aef4..60e26f5 100644
--- a/x11vnc/inet.c
+++ b/x11vnc/inet.c
@@ -44,6 +44,7 @@ char *host2ip(char *host);
char *raw2host(char *raw, int len);
char *raw2ip(char *raw);
char *ip2host(char *ip);
+int ipv6_ip(char *host);
int dotted_ip(char *host);
int get_remote_port(int sock);
int get_local_port(int sock);
@@ -51,7 +52,13 @@ char *get_remote_host(int sock);
char *get_local_host(int sock);
char *ident_username(rfbClientPtr client);
int find_free_port(int start, int end);
+int find_free_port6(int start, int end);
int have_ssh_env(void);
+char *ipv6_getnameinfo(struct sockaddr *paddr, int addrlen);
+char *ipv6_getipaddr(struct sockaddr *paddr, int addrlen);
+int listen6(int port);
+int connect_tcp(char *host, int port);
+int listen_tcp(int port, in_addr_t iface, int try6);
static int get_port(int sock, int remote);
static char *get_host(int sock, int remote);
@@ -126,6 +133,43 @@ char *ip2host(char *ip) {
return str;
}
+int ipv6_ip(char *host_in) {
+ char *p, *host, a[2];
+ int ncol = 0, nhex = 0;
+
+ if (host_in[0] == '[') {
+ host = host_in + 1;
+ } else {
+ host = host_in;
+ }
+
+ if (strstr(host, "::ffff:") == host) {
+ return dotted_ip(host + strlen("::ffff:"));
+ }
+
+ a[1] = '\0';
+
+ p = host;
+ while (*p != '\0' && *p != '%' && *p != ']') {
+ if (*p == ':') {
+ ncol++;
+ } else {
+ nhex++;
+ }
+ a[0] = *p;
+ if (strpbrk(a, ":abcdef0123456789") == a) {
+ p++;
+ continue;
+ }
+ return 0;
+ }
+ if (ncol < 2 || ncol > 8 || nhex == 0) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
int dotted_ip(char *host) {
char *p = host;
while (*p != '\0') {
@@ -251,7 +295,7 @@ char *ident_username(rfbClientPtr client) {
signal(SIGQUIT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
- if ((sock = rfbConnectToTcpAddr(client->host, 113)) < 0) {
+ if ((sock = connect_tcp(client->host, 113)) < 0) {
exit(1);
} else {
close(sock);
@@ -262,7 +306,7 @@ char *ident_username(rfbClientPtr client) {
#endif
if (block || refused) {
;
- } else if ((sock = rfbConnectToTcpAddr(client->host, 113)) < 0) {
+ } else if ((sock = connect_tcp(client->host, 113)) < 0) {
rfbLog("ident_username: could not connect to ident: %s:%d\n",
client->host, 113);
} else {
@@ -356,7 +400,25 @@ int find_free_port(int start, int end) {
end = 65530;
}
for (port = start; port <= end; port++) {
- int sock = rfbListenOnTCPPort(port, htonl(INADDR_ANY));
+ int sock = listen_tcp(port, htonl(INADDR_ANY), 0);
+ if (sock >= 0) {
+ close(sock);
+ return port;
+ }
+ }
+ return 0;
+}
+
+int find_free_port6(int start, int end) {
+ int port;
+ if (start <= 0) {
+ start = 1024;
+ }
+ if (end <= 0) {
+ end = 65530;
+ }
+ for (port = start; port <= end; port++) {
+ int sock = listen6(port);
if (sock >= 0) {
close(sock);
return port;
@@ -428,3 +490,262 @@ if (0) fprintf(stderr, "%d/%d - '%s' '%s'\n", atoi(rport), atoi(lport), rhost, l
return 0;
}
+char *ipv6_getnameinfo(struct sockaddr *paddr, int addrlen) {
+#if X11VNC_IPV6
+ char name[200];
+ if (noipv6) {
+ return strdup("unknown");
+ }
+ if (getnameinfo(paddr, addrlen, name, sizeof(name), NULL, 0, 0) == 0) {
+ return strdup(name);
+ }
+#endif
+ return strdup("unknown");
+}
+
+char *ipv6_getipaddr(struct sockaddr *paddr, int addrlen) {
+#if X11VNC_IPV6
+ char name[200];
+ if (noipv6) {
+ return strdup("unknown");
+ }
+ if (getnameinfo(paddr, addrlen, name, sizeof(name), NULL, 0, NI_NUMERICHOST) == 0) {
+ return strdup(name);
+ }
+#endif
+ return strdup("unknown");
+}
+
+int listen6(int port) {
+#if X11VNC_IPV6
+ struct sockaddr_in6 sin;
+ int fd = -1, one = 1;
+
+ if (noipv6) {
+ return -1;
+ }
+
+ fd = socket(AF_INET6, SOCK_STREAM, 0);
+ if (fd < 0) {
+ rfbLogPerror("listen6: socket");
+ return -1;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) {
+ rfbLogPerror("listen6: setsockopt1");
+ close(fd);
+ return -1;
+ }
+
+#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
+ if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) {
+ rfbLogPerror("listen6: setsockopt2");
+ close(fd);
+ return -1;
+ }
+#endif
+
+ memset((char *)&sin, 0, sizeof(sin));
+ sin.sin6_family = AF_INET6;
+ sin.sin6_port = htons(port);
+ sin.sin6_addr = in6addr_any;
+
+ if (listen_str6) {
+ if (!strcmp(listen_str6, "localhost")) {
+ sin.sin6_addr = in6addr_loopback;
+ } else if (ipv6_ip(listen_str6)) {
+ int err = inet_pton(AF_INET6, listen_str6, &(sin.sin6_addr));
+ if (err <= 0) {
+ rfbLog("inet_pton[%d] failed -listen6 %s\n", err, listen_str6);
+ close(fd);
+ return -1;
+ }
+ } else {
+ rfbLog("Unsupported -listen6 string: %s\n", listen_str6);
+ close(fd);
+ return -1;
+ }
+ } else if (allow_list && !strcmp(allow_list, "127.0.0.1")) {
+ sin.sin6_addr = in6addr_loopback;
+ } else if (listen_str) {
+ if (!strcmp(listen_str, "localhost")) {
+ sin.sin6_addr = in6addr_loopback;
+ }
+ }
+
+ if (bind(fd, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ rfbLogPerror("listen6: bind");
+ close(fd);
+ return -1;
+ }
+ if (listen(fd, 32) < 0) {
+ rfbLogPerror("listen6: listen");
+ close(fd);
+ return -1;
+ }
+ return fd;
+#else
+ if (port) {}
+ return -1;
+#endif
+}
+
+int connect_tcp(char *host, int port) {
+ double t0 = dnow();
+ int fd = -1;
+ int fail4 = noipv4;
+ if (getenv("IPV4_FAILS")) {
+ fail4 = 2;
+ }
+
+ rfbLog("connect_tcp: trying: %s %d\n", host, port);
+
+ if (fail4) {
+ if (fail4 > 1) {
+ rfbLog("TESTING: IPV4_FAILS for connect_tcp.\n");
+ }
+ } else {
+ fd = rfbConnectToTcpAddr(host, port);
+ }
+
+ if (fd >= 0) {
+ return fd;
+ }
+ rfbLogPerror("connect_tcp: connection failed");
+
+ if (dnow() - t0 < 4.0) {
+ rfbLog("connect_tcp: re-trying %s %d\n", host, port);
+ usleep (100 * 1000);
+ if (!fail4) {
+ fd = rfbConnectToTcpAddr(host, port);
+ }
+ if (fd < 0) {
+ rfbLogPerror("connect_tcp: connection failed");
+ }
+ }
+
+ if (fd < 0 && !noipv6) {
+#if X11VNC_IPV6 && defined(AI_ADDRCONFIG)
+ int err;
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ char service[32], *host2, *q;
+
+ rfbLog("connect_tcp: trying IPv6 %s %d\n", host, port);
+
+ memset(&hints, 0, sizeof(hints));
+ sprintf(service, "%d", port);
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_ADDRCONFIG;
+ if(ipv6_ip(host)) {
+#ifdef AI_NUMERICHOST
+ rfbLog("connect_tcp[ipv6]: setting AI_NUMERICHOST for %s\n", host);
+ hints.ai_flags |= AI_NUMERICHOST;
+#else
+ rfbLog("connect_tcp[ipv6]: no AI_NUMERICHOST for %s\n", host);
+#endif
+ }
+#ifdef AI_NUMERICSERV
+ hints.ai_flags |= AI_NUMERICSERV;
+#endif
+
+ if (!strcmp(host, "127.0.0.1")) {
+ host2 = strdup("::1");
+ } else if (host[0] == '[') {
+ host2 = strdup(host+1);
+ } else {
+ host2 = strdup(host);
+ }
+ q = strrchr(host2, ']');
+ if (q) {
+ *q = '\0';
+ }
+
+
+ err = getaddrinfo(host2, service, &hints, &ai);
+ if (err != 0) {
+ rfbLog("connect_tcp[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err));
+ usleep(100 * 1000);
+ err = getaddrinfo(host2, service, &hints, &ai);
+ }
+ free(host2);
+
+ if (err != 0) {
+ rfbLog("connect_tcp[ipv6]: getaddrinfo[%d]: %s\n", err, gai_strerror(err));
+ } else {
+ struct addrinfo *ap = ai;
+ while (ap != NULL) {
+ int sock = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
+ if (sock == -1) {
+ rfbLogPerror("connect_tcp[ipv6]: socket");
+ } else {
+ char *s = ipv6_getipaddr(ap->ai_addr, ap->ai_addrlen);
+ if (!s) s = strdup("unknown");
+ rfbLog("connect_tcp[ipv6]: trying sock=%d using %s\n", sock, s);
+ if (connect(sock, ap->ai_addr, ap->ai_addrlen) == 0) {
+ rfbLog("connect_tcp[ipv6]: connect OK\n");
+ fd = sock;
+ if (!ipv6_client_ip_str) {
+ ipv6_client_ip_str = strdup(s);
+ }
+ free(s);
+ break;
+ } else {
+ close(sock);
+ rfbLogPerror("connect_tcp[ipv6]: connect");
+ }
+ free(s);
+ }
+ ap = ap->ai_next;
+ }
+ freeaddrinfo(ai);
+ }
+#endif
+ }
+ return fd;
+}
+
+int listen_tcp(int port, in_addr_t iface, int try6) {
+ int fd = -1;
+ int fail4 = noipv4;
+ if (getenv("IPV4_FAILS")) {
+ fail4 = 2;
+ }
+
+ if (fail4) {
+ if (fail4 > 1) {
+ rfbLog("TESTING: IPV4_FAILS for listen_tcp: port=%d try6=%d\n", port, try6);
+ }
+ } else {
+ fd = rfbListenOnTCPPort(port, iface);
+ }
+
+ if (fd >= 0) {
+ return fd;
+ }
+ if (fail4 > 1) {
+ rfbLogPerror("listen_tcp: listen failed");
+ }
+
+ if (fd < 0 && try6 && ipv6_listen && !noipv6) {
+#if X11VNC_IPV6
+ char *save = listen_str6;
+ if (iface == htonl(INADDR_LOOPBACK)) {
+ listen_str6 = "localhost";
+ rfbLog("listen_tcp: retrying on IPv6 in6addr_loopback ...\n");
+ fd = listen6(port);
+ } else if (iface == htonl(INADDR_ANY)) {
+ listen_str6 = NULL;
+ rfbLog("listen_tcp: retrying on IPv6 in6addr_any ...\n");
+ fd = listen6(port);
+ }
+ listen_str6 = save;
+#else
+ if (try6) {}
+#endif
+ }
+ return fd;
+}
+