summaryrefslogtreecommitdiffstats
path: root/x11vnc
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc')
-rw-r--r--x11vnc/ChangeLog4
-rw-r--r--x11vnc/README19
-rw-r--r--x11vnc/enc.h628
-rw-r--r--x11vnc/help.c11
-rw-r--r--x11vnc/remote.c8
-rw-r--r--x11vnc/scan.c3
-rw-r--r--x11vnc/sslhelper.c15
-rw-r--r--x11vnc/x11vnc.113
-rw-r--r--x11vnc/x11vnc_defs.c2
9 files changed, 653 insertions, 50 deletions
diff --git a/x11vnc/ChangeLog b/x11vnc/ChangeLog
index 9c59c06..75505a8 100644
--- a/x11vnc/ChangeLog
+++ b/x11vnc/ChangeLog
@@ -1,3 +1,7 @@
+2010-04-25 Karl Runge <runge@karlrunge.com>
+ * x11vnc: incorporate new ultravnc_dsm_helper.c, add pointer_mask
+ remote control query. Cut openssl default -ping delay.
+
2010-04-18 Karl Runge <runge@karlrunge.com>
* x11vnc/misc: improvements to demo scripts
* x11vnc: Alias -coe for -connect_or_exit. more accurate
diff --git a/x11vnc/README b/x11vnc/README
index b822bc3..7456442 100644
--- a/x11vnc/README
+++ b/x11vnc/README
@@ -2,7 +2,7 @@
Copyright (C) 2002-2010 Karl J. Runge <runge@karlrunge.com>
All rights reserved.
-x11vnc README file Date: Sun Apr 18 17:09:43 EDT 2010
+x11vnc README file Date: Fri Apr 23 00:36:17 EDT 2010
The following information is taken from these URLs:
@@ -11183,6 +11183,8 @@ Enhanced TightVNC Viewer (SSVNC: SSL/SSH VNC viewer)
(-grab/-graball option).
* Fix for Popup menu positioning for old window managers (-popupfix
option).
+ * The VNC Viewer ssvncviewer supports IPv6 natively (no helpers
+ needed.)
The list of 3rd party software bundled in the archive files:
* TightVNC Viewer (windows, unix, macosx)
@@ -12076,7 +12078,7 @@ x11vnc: a VNC server for real X displays
Here are all of x11vnc command line options:
% x11vnc -opts (see below for -help long descriptions)
-x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-18
+x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-22
x11vnc options:
-display disp -auth file -N
@@ -12206,7 +12208,7 @@ libvncserver-tight-extension options:
% x11vnc -help
-x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-18
+x11vnc: allow VNC connections to real X11 displays. 0.9.10 lastmod: 2010-04-22
(type "x11vnc -opts" to just list the options.)
@@ -12299,7 +12301,7 @@ Options:
-6 IPv6 listening support. In addition to IPv4, the
IPv6 address is listened on for incoming connections.
- The same port as IPv4 is used.
+ The same port number as IPv4 is used.
NOTE: This x11vnc binary was compiled to have the
"-6" IPv6 listening mode ENABLED by default (CPPFLAGS
@@ -17258,6 +17260,7 @@ n
pointer_y print XQueryPointer y cursor position.
pointer_same print XQueryPointer ptr on same screen.
pointer_root print XQueryPointer curr ptr rootwin.
+ pointer_mask print XQueryPointer button and mods mask
mouse_x print x11vnc's idea of cursor position.
mouse_y print x11vnc's idea of cursor position.
noop do nothing.
@@ -17567,9 +17570,11 @@ n
ext_xrecord ext_xkb ext_xshm ext_xinerama ext_overlay
ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons
button_mask mouse_x mouse_y grab_state pointer_pos
- pointer_x pointer_y pointer_same pointer_root bpp depth
- indexed_color dpy_x dpy_y wdpy_x wdpy_y off_x off_y
- cdpy_x cdpy_y coff_x coff_y rfbauth passwd viewpasswd
+ pointer_x pointer_y pointer_same pointer_root
+ pointer_mask bpp depth indexed_color dpy_x dpy_y wdpy_x
+ wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y rfbauth
+ passwd viewpasswd
+
-QD variable Just like -query variable, but returns the default
value for that parameter (no running x11vnc server
is consulted)
diff --git a/x11vnc/enc.h b/x11vnc/enc.h
index 4dca954..55d49bb 100644
--- a/x11vnc/enc.h
+++ b/x11vnc/enc.h
@@ -42,11 +42,12 @@ so, delete this exception statement from your version.
/*
* ultravnc_dsm_helper.c unix/openssl UltraVNC encryption encoder/decoder.
* (also a generic symmetric encryption tunnel)
+ * (also a generic TCP relay and supports IPv6)
*
* compile via:
- cc -O -o ultravnc_dsm_helper ultravnc_dsm_helper.c -lcrypto
- cc -DDBG -O -o ultravnc_dsm_helper ultravnc_dsm_helper.c -lcrypto
+ cc -O -o ultravnc_dsm_helper ultravnc_dsm_helper.c -lssl -lcrypto
+ cc -DDBG -O -o ultravnc_dsm_helper ultravnc_dsm_helper.c -lssl -lcrypto
*
* See usage below for how to run it.
@@ -65,6 +66,10 @@ so, delete this exception statement from your version.
* e.g. to connect a non-ultra-dsm-vnc viewer to a non-ultra-dsm-vnc server
* without using SSH or SSL.
*
+ * It can also be used as a general TCP relay (no encryption.)
+ *
+ * It supports IPv6 and so can also be used as a IPv6 gateway.
+ *
* -----------------------------------------------------------------------
* Copyright (C) 2008-2010 Karl J. Runge <runge@karlrunge.com>
* All rights reserved.
@@ -98,13 +103,28 @@ so, delete this exception statement from your version.
static char *usage =
"\n"
- "usage: ultravnc_dsm_helper cipher keyfile listenport remotehost:port\n"
+ "ultravnc_dsm_helper: a symmetric encryption tunnel. version 0.2\n"
+ "\n"
+ " Created to enable encrypted VNC connections to UltraVNC, it can act as\n"
+ " a general encrypted tunnel between any two applications. It can also\n"
+ " be used as a general TCP relay (i.e. no encryption) or an IPv6 gateway.\n"
+ "\n"
+ "Usage: ultravnc_dsm_helper cipher keyfile listenport remotehost:port\n"
+ " ultravnc_dsm_helper relay listenport remotehost:port\n"
+ " ultravnc_dsm_helper showcert remotehost:port\n"
"\n"
"e.g.: ultravnc_dsm_helper arc4 ./arc4.key 5901 snoopy.net:5900\n"
"\n"
- " cipher: specify 'msrc4', 'msrc4_sc', 'arc4', 'aesv2',\n"
- " 'aes-cfb', 'aes256', 'blowfish', '3des',\n"
- " 'securevnc'.\n"
+ " IPv6 is supported: both IPv4 and IPv6 are attempted to listen on (port\n"
+ " 'listenport'.) For connections to remotehost, if IPv4 fails\n"
+ " then IPv6 is tried. Set the env. var ULTRAVNC_DSM_HELPER_NOIPV6\n"
+ " to completely disable the use of IPv6.\n"
+ "\n"
+ "\n"
+ " cipher: specify 'msrc4', 'msrc4_sc', 'arc4', 'aesv2', 'aes-cfb',\n"
+ " 'aes256', 'blowfish', '3des', 'securevnc'.\n"
+ "\n"
+ " Also 'none', 'relay', or 'showcert'. See below for details.\n"
"\n"
" 'msrc4_sc' enables a workaround for UVNC SC -plugin use.\n"
" (it might not be required in SC circa 2009 and later; try 'msrc4'.)\n"
@@ -127,19 +147,22 @@ static char *usage =
" use 'rev:arc4', etc. to reverse the roles of encrypter and decrypter.\n"
" (i.e. if you want to use it for a vnc server, not vnc viewer)\n"
"\n"
- " use 'noultra:...' to skip steps involving salt and IV to be compatible\n"
- " to be compatible with UltraVNC DSM, i.e. assume a normal symmetric\n"
- " cipher at the other end.\n"
+ " use 'noultra:...' to skip steps involving salt and IV to try to be\n"
+ " compatible with UltraVNC DSM, i.e. assume a normal symmetric cipher\n"
+ " at the other end.\n"
"\n"
" use 'noultra:rev:...' if both are to be supplied.\n"
"\n"
+ "\n"
" keyfile: file holding the key (16 bytes for arc4 and aesv2, 87 for msrc4)\n"
" E.g. dd if=/dev/random of=./my.key bs=16 count=1\n"
" keyfile can also be pw=<string> to use \"string\" for the key.\n"
" Or for 'securevnc' the RSA keystore and/or ClientAuth file.\n"
"\n"
+ "\n"
" listenport: port to listen for incoming connection on. (use 0 to connect\n"
- " to stdio, use a negative value to force localhost)\n"
+ " to stdio, use a negative value to force localhost listening)\n"
+ "\n"
"\n"
" remotehost:port: host and port to connect to. (e.g. ultravnc server)\n"
"\n"
@@ -150,6 +173,39 @@ static char *usage =
"\n"
" Use cipher@md+n,m to change the message digest. E.g. arc4@sha+8,16\n"
" Supported: 'md5', 'sha', 'sha1', 'ripemd160'.\n"
+ "\n"
+ "\n"
+ " TCP Relay mode: to connect without any encryption use a cipher type of\n"
+ " either 'relay' or 'none' (both are the equivalent):\n"
+ "\n"
+ " ultravnc_dsm_helper relay listenport remotehost:port\n"
+ " ultravnc_dsm_helper none listenport remotehost:port\n"
+ "\n"
+ " where 'relay' or 'none' is a literal string.\n"
+ " Note that for this mode no keyfile is suppled.\n"
+ " Note that this mode can act as an IPv4 to IPv6 gateway.\n"
+ "\n"
+ " ultravnc_dsm_helper relay 8080 ipv6.beijing2008.cn:80\n"
+ "\n"
+ "\n"
+ " SSL Show Certificate mode: Set the cipher to 'showcert' to fetch\n"
+ " the SSL certificate from remotehost:port and print it to the stdout.\n"
+ " No certificate authentication or verification is performed. E.g.\n"
+ "\n"
+ " ultravnc_dsm_helper showcert www.verisign.com:443\n"
+ "\n"
+ " (the output resembles that of 'openssl s_client ...') Set the env var\n"
+ " ULTRAVNC_DSM_HELPER_SHOWCERT_ADH=1 for Anonymous Diffie Hellman mode.\n"
+ "\n"
+ "\n"
+ " Looping Mode: Set the env. var. ULTRAVNC_DSM_HELPER_LOOP=1 to have it\n"
+ " restart itself after every disconnection in an endless loop. It pauses\n"
+ " 500 msec before restarting. Use ULTRAVNC_DSM_HELPER_LOOP=N to set the\n"
+ " pause to N msec.\n"
+ "\n"
+ " You can also set the env. var. ULTRAVNC_DSM_HELPER_BG to have the\n"
+ " program fork into the background for each connection, thereby acting\n"
+ " as a simple daemon.\n"
;
/*
@@ -200,6 +256,8 @@ static char *prog = "ultravnc_dsm_helper";
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/err.h>
+#include <openssl/ssl.h>
+#include <openssl/rsa.h>
static const EVP_CIPHER *Cipher;
static const EVP_MD *Digest;
#endif
@@ -291,7 +349,7 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
struct stat sb;
char *q, *p, *connect_host;
char tmp[16];
- int fd, len = 0, listen_port, connect_port, mbits;
+ int fd, len = 0, listen_port = 0, connect_port, mbits;
q = ciph;
@@ -337,6 +395,12 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
Cipher = EVP_aes_128_ofb(); cipher = "securevnc";
securevnc = 1;
+ } else if (strstr(q, "none") == q || strstr(q, "relay") == q) {
+ cipher = "none";
+
+ } else if (strstr(q, "showcert") == q) {
+ cipher = "showcert";
+
} else if (strstr(q, ".") == q) {
/* otherwise, try to guess cipher from key filename: */
if (strstr(keyfile, "arc4.key")) {
@@ -433,7 +497,9 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
}
/* port to listen on (0 => stdio, negative => localhost) */
- listen_port = atoi(lport);
+ if (lport != NULL) {
+ listen_port = atoi(lport);
+ }
/* extract remote hostname and port */
q = strrchr(rhp, ':');
@@ -449,6 +515,13 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
/* check for and read in the key file */
memset(keydata, 0, sizeof(keydata));
+ if (!strcmp(cipher, "none")) {
+ goto readed_in;
+ }
+ if (!strcmp(cipher, "showcert")) {
+ goto readed_in;
+ }
+
if (securevnc) {
/* note the keyfile for rsa verification later */
if (keyfile != NULL && strcasecmp(keyfile, "none")) {
@@ -536,6 +609,81 @@ extern void enc_do(char *ciph, char *keyfile, char *lport, char *rhp) {
}
#endif
+static void enc_raw_xfer(int sock_fr, int sock_to) {
+
+ unsigned char buf[BSIZE];
+ unsigned char *psrc = NULL;
+ int len, m, n = 0;
+
+ /* zero the buffers */
+ memset(buf, 0, BSIZE);
+
+ /* now loop forever processing the data stream */
+ while (1) {
+ errno = 0;
+
+ /* general case of loop, read some in: */
+ n = read(sock_fr, buf, BSIZE);
+
+ if (n == 0 || (n < 0 && errno != EINTR)) {
+ /* failure to read any data, it is EOF or fatal error */
+ int err = errno;
+
+ /* debug output: */
+ fprintf(stderr, "%s: input stream finished: n=%d, err=%d", prog, n, err);
+
+ /* EOF or fatal error */
+ break;
+
+ } else if (n > 0) {
+
+ /* write data to the other end: */
+ len = n;
+ psrc = buf;
+ while (len > 0) {
+ errno = 0;
+ m = write(sock_to, psrc, len);
+
+ if (m > 0) {
+ /* scoot them by how much was written: */
+ psrc += m;
+ len -= m;
+ }
+ if (m < 0 && (errno == EINTR || errno == EAGAIN)) {
+ /* interrupted or blocked */
+ continue;
+ }
+ /* EOF or fatal error */
+ break;
+ }
+ } else {
+ /* this is EINTR */
+ }
+ }
+
+ /* transfer done (viewer exited or some error) */
+
+ fprintf(stderr, "\n%s: close sock_to\n", prog);
+ close(sock_to);
+
+ fprintf(stderr, "%s: close sock_fr\n", prog);
+ close(sock_fr);
+
+ /* kill our partner after 1 secs. */
+ sleep(1);
+ if (child) {
+ if (kill(child, SIGTERM) == 0) {
+ fprintf(stderr, "%s[%d]: killed my partner: %d\n",
+ prog, (int) getpid(), (int) child);
+ }
+ } else {
+ if (kill(parent, SIGTERM) == 0) {
+ fprintf(stderr, "%s[%d]: killed my partner: %d\n",
+ prog, (int) getpid(), (int) parent);
+ }
+ }
+}
+
#if ENC_HAVE_OPENSSL
/*
* Initialize cipher context and then loop till EOF doing transfer &
@@ -1368,16 +1516,163 @@ static void securevnc_setup(int conn1, int conn2) {
write(viewer, to_viewer, to_viewer_len);
}
}
+
+#ifndef ENC_DISABLE_SHOW_CERT
+static void enc_sslerrexit(void) {
+ unsigned long err = ERR_get_error();
+
+ if (err) {
+ char str[256];
+ ERR_error_string(err, str);
+ fprintf(stdout, "ssl error: %s\n", str);
+ }
+ exit(1);
+}
+#endif
+
+static void show_cert(int sock) {
+#ifndef ENC_DISABLE_SHOW_CERT
+ SSL_CTX *ctx;
+ SSL *ssl = NULL;
+ STACK_OF(X509) *sk = NULL;
+ X509 *peer = NULL;
+ SSL_CIPHER *c;
+ BIO *bio;
+ unsigned char *sid = (unsigned char *) "ultravnc_dsm_helper SID";
+ long mode;
+ int i;
+
+ fprintf(stdout, "CONNECTED(%08X)\n",sock);
+
+ SSL_library_init();
+ SSL_load_error_strings();
+
+ if (!RAND_status()) {
+ RAND_poll();
+ }
+ /* this is not for a secured connection. */
+ for (i=0; i < 100; i++) {
+ if (!RAND_status()) {
+ char tmp[32];
+ sprintf(tmp, "%d", getpid() * (17 + i));
+ RAND_add(tmp, strlen(tmp), 5);
+ } else {
+ break;
+ }
+ }
+
+ ctx = SSL_CTX_new( SSLv23_client_method() );
+ if (ctx == NULL) {
+ fprintf(stdout, "show_cert: SSL_CTX_new failed.\n");
+ close(sock);
+ enc_sslerrexit();
+ }
+
+ mode = 0;
+ mode |= SSL_MODE_ENABLE_PARTIAL_WRITE;
+ mode |= SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER;
+ SSL_CTX_set_mode(ctx, mode);
+
+ if (getenv("ULTRAVNC_DSM_HELPER_SHOWCERT_ADH")) {
+ SSL_CTX_set_cipher_list(ctx, "ADH:@STRENGTH");
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ }
+
+ ssl = SSL_new(ctx);
+
+ if (ssl == NULL) {
+ fprintf(stdout, "show_cert: SSL_new failed.\n");
+ close(sock);
+ enc_sslerrexit();
+ }
+
+ SSL_set_session_id_context(ssl, sid, strlen((char *)sid));
+
+ if (! SSL_set_fd(ssl, sock)) {
+ fprintf(stdout, "show_cert: SSL_set_fd failed.\n");
+ close(sock);
+ enc_sslerrexit();
+ }
+
+ SSL_set_connect_state(ssl);
+
+ if (SSL_connect(ssl) <= 0) {
+ unsigned long err = ERR_get_error();
+ fprintf(stdout, "show_cert: SSL_connect failed.\n");
+ if (err) {
+ char str[256];
+ ERR_error_string(err, str);
+ fprintf(stdout, "ssl error: %s\n", str);
+ }
+ }
+
+ SSL_get_verify_result(ssl);
+
+ sk = SSL_get_peer_cert_chain(ssl);
+ if (sk != NULL) {
+ fprintf(stdout, "---\nCertificate chain\n");
+ for (i=0; i < sk_X509_num(sk); i++) {
+ char buf[2048];
+ X509_NAME_oneline(X509_get_subject_name(sk_X509_value(sk,i)), buf, sizeof buf);
+ fprintf(stdout, "%2d s:%s\n", i, buf);
+ X509_NAME_oneline(X509_get_issuer_name(sk_X509_value(sk,i)), buf, sizeof buf);
+ fprintf(stdout, " i:%s\n", buf);
+ }
+ } else {
+ fprintf(stdout, "show_cert: SSL_get_peer_cert_chain failed.\n");
+ }
+ fprintf(stdout, "---\n");
+ peer = SSL_get_peer_certificate(ssl);
+ bio = BIO_new_fp(stdout, BIO_NOCLOSE);
+ if (peer != NULL) {
+ char buf[2048];
+ BIO_printf(bio,"Server certificate\n");
+ PEM_write_bio_X509(bio, peer);
+
+ X509_NAME_oneline(X509_get_subject_name(peer), buf, sizeof buf);
+ BIO_printf(bio,"subject=%s\n",buf);
+ X509_NAME_oneline(X509_get_issuer_name(peer), buf, sizeof buf);
+ BIO_printf(bio,"issuer=%s\n",buf);
+ } else {
+ fprintf(stdout, "show_cert: SSL_get_peer_certificate failed.\n");
+ }
+
+ c = SSL_get_current_cipher(ssl);
+ BIO_printf(bio,"---\nNew, %s, Cipher is %s\n", SSL_CIPHER_get_version(c), SSL_CIPHER_get_name(c));
+
+ if (peer != NULL) {
+ EVP_PKEY *pktmp;
+ pktmp = X509_get_pubkey(peer);
+ BIO_printf(bio,"Server public key is %d bit\n", EVP_PKEY_bits(pktmp));
+ EVP_PKEY_free(pktmp);
+ }
+ BIO_printf(bio,"---\nDONE\n---\n");
+
+ fflush(stdout);
+
+#endif
+ close(sock);
+ exit(0);
+}
+
+#ifndef SOL_IPV6
+#ifdef IPPROTO_IPV6
+#define SOL_IPV6 IPPROTO_IPV6
+#endif
+#endif
+
/*
* Listens on incoming port for a client, then connects to remote server.
* Then forks into two processes one is the encrypter the other the
* decrypter.
*/
static void enc_connections(int listen_port, char *connect_host, int connect_port) {
- int listen_fd, conn1, conn2, ret, one = 1;
+ int listen_fd = -1, listen_fd6 = -1, conn1 = -1, conn2 = -1, ret, one = 1;
socklen_t clen;
struct hostent *hp;
struct sockaddr_in client, server;
+ fd_set fds;
+ int maxfd = -1;
/* zero means use stdio (preferably from socketpair()) */
if (listen_port == 0) {
@@ -1385,6 +1680,10 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por
goto use_stdio;
}
+ if (!strcmp(cipher, "showcert")) {
+ goto use_stdio;
+ }
+
/* fd=n,m means use the supplied already established sockets */
if (sscanf(connect_host, "fd=%d,%d", &conn1, &conn2) == 2) {
goto use_input_fds;
@@ -1405,25 +1704,95 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
if (listen_fd < 0) {
perror("socket");
- exit(1);
+ goto try6;
}
ret = setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR,
(char *)&one, sizeof(one));
if (ret < 0) {
perror("setsockopt");
- exit(1);
+ close(listen_fd);
+ listen_fd = -1;
+ goto try6;
}
ret = bind(listen_fd, (struct sockaddr *) &client, sizeof(client));
if (ret < 0) {
perror("bind");
- exit(1);
+ close(listen_fd);
+ listen_fd = -1;
+ goto try6;
}
ret = listen(listen_fd, 2);
if (ret < 0) {
perror("listen");
+ close(listen_fd);
+ listen_fd = -1;
+ goto try6;
+ }
+
+ try6:
+#ifdef AF_INET6
+ if (!getenv("ULTRAVNC_DSM_HELPER_NOIPV6")) {
+ struct sockaddr_in6 sin;
+ int one = 1, sock = -1;
+
+ sock = socket(AF_INET6, SOCK_STREAM, 0);
+ if (sock < 0) {
+ perror("socket6");
+ goto fail;
+ }
+
+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&one, sizeof(one)) < 0) {
+ perror("setsockopt6 SO_REUSEADDR");
+ close(sock);
+ sock = -1;
+ goto fail;
+ }
+
+#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
+ if (setsockopt(sock, SOL_IPV6, IPV6_V6ONLY, (char *)&one, sizeof(one)) < 0) {
+ perror("setsockopt6 IPV6_V6ONLY");
+ close(sock);
+ sock = -1;
+ goto fail;
+ }
+#endif
+
+ memset((char *)&sin, 0, sizeof(sin));
+ sin.sin6_family = AF_INET6;
+
+ if (listen_port < 0) {
+ sin.sin6_addr = in6addr_loopback;
+ sin.sin6_port = htons(-listen_port);
+ } else {
+ sin.sin6_addr = in6addr_any;
+ sin.sin6_port = htons(listen_port);
+ }
+
+ if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
+ perror("bind6");
+ close(sock);
+ sock = -1;
+ goto fail;
+ }
+
+ if (listen(sock, 2) < 0) {
+ perror("listen6");
+ close(sock);
+ sock = -1;
+ goto fail;
+ }
+
+ fail:
+ listen_fd6 = sock;
+ }
+#endif
+
+ if (listen_fd < 0 && listen_fd6 < 0) {
+ fprintf(stderr, "%s: could not listen on port: %d\n",
+ prog, listen_port);
exit(1);
}
@@ -1431,15 +1800,85 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por
prog, listen_port);
/* wait for a connection: */
- clen = sizeof(client);
- conn1 = accept(listen_fd, (struct sockaddr *) &client, &clen);
- if (conn1 < 0) {
- perror("accept");
+ FD_ZERO(&fds);
+ if (listen_fd >= 0) {
+ FD_SET(listen_fd, &fds);
+ if (listen_fd > maxfd) {
+ maxfd = listen_fd;
+ }
+ }
+ if (listen_fd6 >= 0) {
+ FD_SET(listen_fd6, &fds);
+ if (listen_fd6 > maxfd) {
+ maxfd = listen_fd6;
+ }
+ }
+ if (select(maxfd+1, &fds, NULL, NULL, NULL) <= 0) {
+ perror("select");
+ exit(1);
+ }
+
+ if (FD_ISSET(listen_fd, &fds)) {
+ clen = sizeof(client);
+ conn1 = accept(listen_fd, (struct sockaddr *) &client, &clen);
+ if (conn1 < 0) {
+ perror("accept");
+ exit(1);
+ }
+ } else if (FD_ISSET(listen_fd6, &fds)) {
+#ifdef AF_INET6
+ struct sockaddr_in6 addr;
+ socklen_t addrlen = sizeof(addr);
+
+ conn1 = accept(listen_fd6, (struct sockaddr *) &addr, &addrlen);
+ if (conn1 < 0) {
+ perror("accept6");
+ exit(1);
+ }
+#else
+ fprintf(stderr, "No IPv6 / AF_INET6 support.\n");
+ exit(1);
+#endif
+ }
+
+ if (setsockopt(conn1, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) {
+ perror("setsockopt TCP_NODELAY");
exit(1);
}
- /* done with the listening socket: */
- close(listen_fd);
+ /* done with the listening socket(s): */
+ if (listen_fd >= 0) {
+ close(listen_fd);
+ }
+ if (listen_fd6 >= 0) {
+ close(listen_fd6);
+ }
+
+ if (getenv("ULTRAVNC_DSM_HELPER_BG")) {
+ int p, n;
+ if ((p = fork()) > 0) {
+ fprintf(stderr, "%s: putting child %d in background.\n",
+ prog, p);
+ exit(0);
+ } else if (p == -1) {
+ fprintf(stderr, "%s: could not fork\n", prog);
+ perror("fork");
+ exit(1);
+ }
+ if (setsid() == -1) {
+ fprintf(stderr, "%s: setsid failed\n", prog);
+ perror("setsid");
+ exit(1);
+ }
+ /* adjust our stdio */
+ n = open("/dev/null", O_RDONLY);
+ dup2(n, 0);
+ dup2(n, 1);
+ dup2(n, 2);
+ if (n > 2) {
+ close(n);
+ }
+ }
use_stdio:
@@ -1453,8 +1892,7 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por
if ((server.sin_addr.s_addr = inet_addr(connect_host)) == htonl(INADDR_NONE)) {
if (!(hp = gethostbyname(connect_host))) {
perror("gethostbyname");
- close(conn1);
- exit(1);
+ goto tryconn6;
}
server.sin_addr.s_addr = *(unsigned long *)hp->h_addr;
}
@@ -1462,18 +1900,92 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por
conn2 = socket(AF_INET, SOCK_STREAM, 0);
if (conn2 < 0) {
perror("socket");
- close(conn1);
- exit(1);
+ goto tryconn6;
}
if (connect(conn2, (struct sockaddr *)&server, (sizeof(server))) < 0) {
perror("connect");
- close(conn1);
+ goto tryconn6;
+ }
+
+ tryconn6:
+#ifdef AF_INET6
+ if (conn2 < 0 && !getenv("ULTRAVNC_DSM_HELPER_NOIPV6")) {
+ int err;
+ struct addrinfo *ai;
+ struct addrinfo hints;
+ char service[32];
+
+ fprintf(stderr, "connect[ipv6]: trying to connect via IPv6 to %s\n", connect_host);
+ conn2 = -1;
+
+ memset(&hints, 0, sizeof(hints));
+ sprintf(service, "%d", connect_port);
+
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+#ifdef AI_ADDRCONFIG
+ hints.ai_flags |= AI_ADDRCONFIG;
+#endif
+#ifdef AI_NUMERICSERV
+ hints.ai_flags |= AI_NUMERICSERV;
+#endif
+
+ err = getaddrinfo(connect_host, service, &hints, &ai);
+ if (err != 0) {
+ fprintf(stderr, "getaddrinfo[%d]: %s\n", err, gai_strerror(err));
+ } else {
+ struct addrinfo *ap = ai;
+ while (ap != NULL) {
+ int fd = -1;
+ fd = socket(ap->ai_family, ap->ai_socktype, ap->ai_protocol);
+ if (fd == -1) {
+ perror("socket6");
+ } else {
+ int dmsg = 0;
+ int res = connect(fd, ap->ai_addr, ap->ai_addrlen);
+#if defined(SOL_IPV6) && defined(IPV6_V6ONLY)
+ if (res != 0) {
+ int zero = 0;
+ perror("connect6");
+ dmsg = 1;
+ if (setsockopt(fd, SOL_IPV6, IPV6_V6ONLY, (char *)&zero, sizeof(zero)) == 0) {
+ fprintf(stderr, "connect[ipv6]: trying again with IPV6_V6ONLY=0\n");
+ res = connect(fd, ap->ai_addr, ap->ai_addrlen);
+ dmsg = 0;
+ }
+ }
+#endif
+ if (res == 0) {
+ conn2 = fd;
+ break;
+ } else {
+ if (!dmsg) perror("connect6");
+ close(fd);
+ }
+ }
+ ap = ap->ai_next;
+ }
+ freeaddrinfo(ai);
+ }
+ }
+#endif
+ if (conn2 < 0) {
+ fprintf(stderr, "could not connect to %s\n", connect_host);
exit(1);
}
+ if (conn2 >= 0 && setsockopt(conn2, IPPROTO_TCP, TCP_NODELAY, (char *)&one, sizeof(one)) < 0) {
+ perror("setsockopt TCP_NODELAY");
+ }
use_input_fds:
+ if (!strcmp(cipher, "showcert")) {
+ show_cert(conn2);
+ close(conn2);
+ exit(0);
+ }
+
if (securevnc) {
securevnc_setup(conn1, conn2);
}
@@ -1495,18 +2007,74 @@ static void enc_connections(int listen_port, char *connect_host, int connect_por
if (child == 0) {
/* encrypter: local-viewer -> remote-server */
- enc_xfer(conn1, conn2, 1);
+ if (!strcmp(cipher, "none") || !strcmp(cipher, "relay")) {
+ enc_raw_xfer(conn1, conn2);
+ } else {
+ enc_xfer(conn1, conn2, 1);
+ }
} else {
/* decrypter: remote-server -> local-viewer */
- enc_xfer(conn2, conn1, 0);
+ if (!strcmp(cipher, "none") || !strcmp(cipher, "relay")) {
+ enc_raw_xfer(conn2, conn1);
+ } else {
+ enc_xfer(conn2, conn1, 0);
+ }
}
}
#endif /* ENC_HAVE_OPENSSL */
+static void doloop (int argc, char *argv[]) {
+ int ms = atoi(getenv("ULTRAVNC_DSM_HELPER_LOOP"));
+ if (ms > 0) {
+ char *cmd;
+ int i, len = 0;
+ for (i = 0; i < argc; i++) {
+ len += strlen(argv[i]) + 2;
+ }
+ cmd = (char *)malloc(len);
+ cmd[0] = '\0';
+ for (i = 0; i < argc; i++) {
+ strcat(cmd, argv[i]);
+ if (i < argc - 1) {
+ strcat(cmd, " ");
+ }
+ }
+
+ putenv("ULTRAVNC_DSM_HELPER_LOOP_SET=1");
+ if (ms == 1) {
+ ms = 500;
+ }
+ i = 0;
+ while (1) {
+ fprintf(stderr, "loop running[%d]: %s\n", ++i, cmd);
+ system(cmd);
+ usleep(1000 * ms);
+ }
+ }
+}
+
extern int main (int argc, char *argv[]) {
char *kf, *q;
- if (argc < 4) {
+ if (getenv("ULTRAVNC_DSM_HELPER_LOOP")) {
+ if (!getenv("ULTRAVNC_DSM_HELPER_LOOP_SET")) {
+ doloop(argc, argv);
+ }
+ }
+
+ if (argc == 3) {
+ if (!strcmp(argv[1], "showcert")) {
+ enc_do(argv[1], NULL, NULL, argv[2]);
+ return 0;
+ }
+ }
+ if (argc == 4) {
+ if (!strcmp(argv[1], "none") || !strcmp(argv[1], "relay")) {
+ enc_do(argv[1], NULL, argv[2], argv[3]);
+ return 0;
+ }
+ }
+ if (argc < 5) {
fprintf(stdout, "%s\n", usage);
exit(1);
}
diff --git a/x11vnc/help.c b/x11vnc/help.c
index c23112c..1289a42 100644
--- a/x11vnc/help.c
+++ b/x11vnc/help.c
@@ -144,7 +144,7 @@ void print_help(int mode) {
#if X11VNC_IPV6
"-6 IPv6 listening support. In addition to IPv4, the\n"
" IPv6 address is listened on for incoming connections.\n"
-" The same port as IPv4 is used.\n"
+" The same port number as IPv4 is used.\n"
"\n"
#if X11VNC_LISTEN6
" NOTE: This x11vnc binary was compiled to have the\n"
@@ -5131,6 +5131,7 @@ void print_help(int mode) {
" pointer_y print XQueryPointer y cursor position.\n"
" pointer_same print XQueryPointer ptr on same screen.\n"
" pointer_root print XQueryPointer curr ptr rootwin.\n"
+" pointer_mask print XQueryPointer button and mods mask\n"
" mouse_x print x11vnc's idea of cursor position.\n"
" mouse_y print x11vnc's idea of cursor position.\n"
" noop do nothing.\n"
@@ -5440,9 +5441,11 @@ void print_help(int mode) {
" ext_xrecord ext_xkb ext_xshm ext_xinerama ext_overlay\n"
" ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons\n"
" button_mask mouse_x mouse_y grab_state pointer_pos\n"
-" pointer_x pointer_y pointer_same pointer_root bpp depth\n"
-" indexed_color dpy_x dpy_y wdpy_x wdpy_y off_x off_y\n"
-" cdpy_x cdpy_y coff_x coff_y rfbauth passwd viewpasswd\n"
+" pointer_x pointer_y pointer_same pointer_root\n"
+" pointer_mask bpp depth indexed_color dpy_x dpy_y wdpy_x\n"
+" wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y rfbauth\n"
+" passwd viewpasswd\n"
+"\n"
"-QD variable Just like -query variable, but returns the default\n"
" value for that parameter (no running x11vnc server\n"
" is consulted)\n"
diff --git a/x11vnc/remote.c b/x11vnc/remote.c
index 2a45d8b..6b2903b 100644
--- a/x11vnc/remote.c
+++ b/x11vnc/remote.c
@@ -6126,10 +6126,10 @@ char *process_remote_cmd(char *cmd, int stringonly) {
}
goto qry;
}
- if (!strcmp(p, "pointer_pos") || !strcmp(p, "pointer_x") || !strcmp(p, "pointer_y") || !strcmp(p, "pointer_same") || !strcmp(p, "pointer_root")) {
+ if (!strcmp(p, "pointer_pos") || !strcmp(p, "pointer_x") || !strcmp(p, "pointer_y") || !strcmp(p, "pointer_same") || !strcmp(p, "pointer_root") || !strcmp(p, "pointer_mask")) {
int px = -1, py = -1;
int wx, wy;
- unsigned int m;
+ unsigned int m = 0;
Window r, c;
Bool same_screen = True;
@@ -6144,6 +6144,8 @@ char *process_remote_cmd(char *cmd, int stringonly) {
snprintf(buf, bufn, "aro=%s:%d", p, same_screen);
} else if (!strcmp(p, "pointer_root")) { /* skip-cmd-list */
snprintf(buf, bufn, "aro=%s:0x%x", p, (unsigned int) rootwin);
+ } else if (!strcmp(p, "pointer_mask")) { /* skip-cmd-list */
+ snprintf(buf, bufn, "aro=%s:0x%x", p, m);
}
if (!dpy) {
goto qry;
@@ -6166,6 +6168,8 @@ char *process_remote_cmd(char *cmd, int stringonly) {
snprintf(buf, bufn, "aro=%s:%d", p, same_screen);
} else if (!strcmp(p, "pointer_root")) { /* skip-cmd-list */
snprintf(buf, bufn, "aro=%s:0x%x", p, (unsigned int) r);
+ } else if (!strcmp(p, "pointer_mask")) { /* skip-cmd-list */
+ snprintf(buf, bufn, "aro=%s:0x%x", p, m);
}
if (rc_npieces < 10) {
rfbLog("remote_cmd: %s: %s\n", p, buf);
diff --git a/x11vnc/scan.c b/x11vnc/scan.c
index 03a37a0..7ef931c 100644
--- a/x11vnc/scan.c
+++ b/x11vnc/scan.c
@@ -3014,11 +3014,12 @@ static void ping_clients(int tile_cnt) {
if (tile_cnt > 0) {
last_send = now;
} else if (tile_cnt < 0) {
+ /* negative tile_cnt is -ping case */
if (now >= last_send - tile_cnt) {
mark_rect_as_modified(0, 0, 1, 1, 1);
last_send = now;
}
- } else if (now - last_send > 2) {
+ } else if (now - last_send > 5) {
/* Send small heartbeat to client */
mark_rect_as_modified(0, 0, 1, 1, 1);
last_send = now;
diff --git a/x11vnc/sslhelper.c b/x11vnc/sslhelper.c
index 3fc97b4..0cb120c 100644
--- a/x11vnc/sslhelper.c
+++ b/x11vnc/sslhelper.c
@@ -2717,6 +2717,19 @@ void openssl_port(int restart) {
return;
}
+ if (ipv6_listen && screen->port <= 0) {
+ if (got_rfbport) {
+ screen->port = got_rfbport_val;
+ } else {
+ int ap = 5900;
+ if (auto_port > 0) {
+ ap = auto_port;
+ }
+ screen->port = find_free_port6(ap, ap+200);
+ }
+ rfbLog("openssl_port: reset port from 0 => %d\n", screen->port);
+ }
+
if (restart) {
port = screen->port;
} else if (screen->listenSock > -1 && screen->port > 0) {
@@ -4279,6 +4292,8 @@ if (db) rfbLog("raw_xfer bad write: %d -> %d | %d/%d errno=%d\n", csock, s_out
#define ENC_HAVE_OPENSSL 0
#endif
+#define ENC_DISABLE_SHOW_CERT
+
#include "enc.h"
static void symmetric_encryption_xfer(int csock, int s_in, int s_out) {
diff --git a/x11vnc/x11vnc.1 b/x11vnc/x11vnc.1
index 66ce03b..05a5683 100644
--- a/x11vnc/x11vnc.1
+++ b/x11vnc/x11vnc.1
@@ -2,7 +2,7 @@
.TH X11VNC "1" "April 2010" "x11vnc " "User Commands"
.SH NAME
x11vnc - allow VNC connections to real X11 displays
- version: 0.9.10, lastmod: 2010-04-18
+ version: 0.9.10, lastmod: 2010-04-22
.SH SYNOPSIS
.B x11vnc
[OPTION]...
@@ -114,7 +114,7 @@ enter the port number.
.IP
IPv6 listening support. In addition to IPv4, the
IPv6 address is listened on for incoming connections.
-The same port as IPv4 is used.
+The same port number as IPv4 is used.
.IP
NOTE: This x11vnc binary was compiled to have the
"-6" IPv6 listening mode ENABLED by default (CPPFLAGS
@@ -6004,6 +6004,8 @@ pointer_same print XQueryPointer ptr on same screen.
.IP
pointer_root print XQueryPointer curr ptr rootwin.
.IP
+pointer_mask print XQueryPointer button and mods mask
+.IP
mouse_x print x11vnc's idea of cursor position.
.IP
mouse_y print x11vnc's idea of cursor position.
@@ -6411,9 +6413,10 @@ pipeinput clients client_count pid ext_xtest ext_xtrap
ext_xrecord ext_xkb ext_xshm ext_xinerama ext_overlay
ext_xfixes ext_xdamage ext_xrandr rootwin num_buttons
button_mask mouse_x mouse_y grab_state pointer_pos
-pointer_x pointer_y pointer_same pointer_root bpp depth
-indexed_color dpy_x dpy_y wdpy_x wdpy_y off_x off_y
-cdpy_x cdpy_y coff_x coff_y rfbauth passwd viewpasswd
+pointer_x pointer_y pointer_same pointer_root
+pointer_mask bpp depth indexed_color dpy_x dpy_y wdpy_x
+wdpy_y off_x off_y cdpy_x cdpy_y coff_x coff_y rfbauth
+passwd viewpasswd
.PP
\fB-QD\fR \fIvariable\fR
.IP
diff --git a/x11vnc/x11vnc_defs.c b/x11vnc/x11vnc_defs.c
index ac6dfc9..ee335cf 100644
--- a/x11vnc/x11vnc_defs.c
+++ b/x11vnc/x11vnc_defs.c
@@ -47,7 +47,7 @@ int xtrap_base_event_type = 0;
int xdamage_base_event_type = 0;
/* date +'lastmod: %Y-%m-%d' */
-char lastmod[] = "0.9.10 lastmod: 2010-04-18";
+char lastmod[] = "0.9.10 lastmod: 2010-04-22";
/* X display info */