summaryrefslogtreecommitdiffstats
path: root/x11vnc/misc
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/misc')
-rw-r--r--x11vnc/misc/Makefile.am2
-rw-r--r--x11vnc/misc/README11
-rwxr-xr-xx11vnc/misc/connect_switch276
-rwxr-xr-xx11vnc/misc/desktop.cgi1134
-rwxr-xr-xx11vnc/misc/inet6to4400
-rwxr-xr-xx11vnc/misc/panner.pl117
-rwxr-xr-xx11vnc/misc/ultravnc_repeater.pl131
7 files changed, 2038 insertions, 33 deletions
diff --git a/x11vnc/misc/Makefile.am b/x11vnc/misc/Makefile.am
index f814315..98a7511 100644
--- a/x11vnc/misc/Makefile.am
+++ b/x11vnc/misc/Makefile.am
@@ -1,3 +1,3 @@
SUBDIRS = turbovnc
DIST_SUBDIRS = turbovnc
-EXTRA_DIST=README blockdpy.c dtVncPopup rx11vnc rx11vnc.pl shm_clear ranfb.pl slide.pl vcinject.pl x11vnc_loop Xdummy ultravnc_repeater.pl connect_switch
+EXTRA_DIST=README blockdpy.c dtVncPopup rx11vnc rx11vnc.pl shm_clear ranfb.pl slide.pl vcinject.pl x11vnc_loop Xdummy ultravnc_repeater.pl connect_switch panner.pl desktop.cgi inet6to4
diff --git a/x11vnc/misc/README b/x11vnc/misc/README
index abb60f6..f38616e 100644
--- a/x11vnc/misc/README
+++ b/x11vnc/misc/README
@@ -33,3 +33,14 @@ Misc. scripts:
use Xsetup mechanism.
Xdummy An LD_PRELOAD kludge to run the Xorg "dummy" device driver
like Xvfb.
+
+ ultravnc_repeater.pl: Unix script to act as UltraVNC repeater proxy.
+
+ connect_switch: Share HTTPS, VNC, SSH, etc. through a single port (e.g. 443)
+
+ panner.pl Allows a small rectangle to pan around a desktop more or less.
+
+ desktop.cgi CGI script for creating multi-user virtual desktops on a
+ server. Also can do port-redirection to internal machines.
+
+ inet6to4 ipv6 to ipv4 relay (i.e. until libvncserver supports ipv6)
diff --git a/x11vnc/misc/connect_switch b/x11vnc/misc/connect_switch
index ad6d138..212157f 100755
--- a/x11vnc/misc/connect_switch
+++ b/x11vnc/misc/connect_switch
@@ -1,6 +1,6 @@
#!/usr/bin/perl
#
-# Copyright (c) 2006-2009 by Karl J. Runge <runge@karlrunge.com>
+# Copyright (c) 2006-2010 by Karl J. Runge <runge@karlrunge.com>
#
# connect_switch is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -35,10 +35,14 @@
# because the CONNECT request appears to be forwarded encrypted to
# the remote host and so the SSL dies immediately.
#
+# It can also be used to redirect ANY protocol, e.g. SSH, not just VNC.
+# See CONNECT_SWITCH_APPLY_VNC_OFFSET=0 to disable VNC 5900 shift.
+#
# Note: There is no need to use this script for a non-ssl apache webserver
# port because mod_proxy works fine for doing the switching all inside
# apache (see ProxyRequests and AllowCONNECT parameters).
#
+#
# Apache configuration:
#
# The mod_ssl configuration is often in a file named ssl.conf. In the
@@ -68,6 +72,126 @@
# It is probably a good idea to set $listen_host below to the known
# IP address you want the service to listen on (to avoid localhost where
# apache is listening).
+#
+
+####################################################################
+# NOTE: For more info on configuration settings, read below for
+# all of the CONNECT_SWITCH_* env. var. parameters.
+####################################################################
+
+
+####################################################################
+# Allow env vars to also be specified on cmdline:
+#
+foreach my $arg (@ARGV) {
+ if ($arg =~ /^(CONNECT_SWITCH.*?)=(.*)$/) {
+ $ENV{$1} = $2;
+ }
+}
+
+# Set up logging:
+#
+if (exists $ENV{CONNECT_SWITCH_LOGFILE}) {
+ close STDOUT;
+ if (!open(STDOUT, ">>$ENV{CONNECT_SWITCH_LOGFILE}")) {
+ die "connect_switch: $ENV{CONNECT_SWITCH_LOGFILE} $!\n";
+ }
+ close STDERR;
+ open(STDERR, ">&STDOUT");
+}
+select(STDERR); $| = 1;
+select(STDOUT); $| = 1;
+
+# interrupt handler:
+#
+my $looppid = '';
+my $pidfile = '';
+my $listen_sock = ''; # declared here for get_out()
+#
+sub get_out {
+ print STDERR "$_[0]:\t$$ looppid=$looppid\n";
+ close $listen_sock if $listen_sock;
+ if ($looppid) {
+ kill 'TERM', $looppid;
+ fsleep(0.2);
+ }
+ unlink $pidfile if $pidfile;
+ exit 0;
+}
+$SIG{INT} = \&get_out;
+$SIG{TERM} = \&get_out;
+
+# pidfile:
+#
+sub open_pidfile {
+ if (exists $ENV{CONNECT_SWITCH_PIDFILE}) {
+ my $pf = $ENV{CONNECT_SWITCH_PIDFILE};
+ if (open(PID, ">$pf")) {
+ print PID "$$\n";
+ close PID;
+ $pidfile = $pf;
+ } else {
+ print STDERR "could not open pidfile: $pf - $! - continuing...\n";
+ }
+ delete $ENV{CONNECT_SWITCH_PIDFILE};
+ }
+}
+
+####################################################################
+# Set CONNECT_SWITCH_LOOP=1 to have this script create an outer loop
+# restarting itself if it ever exits. Set CONNECT_SWITCH_LOOP=BG to
+# do this in the background as a daemon.
+
+if (exists $ENV{CONNECT_SWITCH_LOOP}) {
+ my $csl = $ENV{CONNECT_SWITCH_LOOP};
+ if ($csl ne 'BG' && $csl ne '1') {
+ die "connect_switch: invalid CONNECT_SWITCH_LOOP.\n";
+ }
+ if ($csl eq 'BG') {
+ # go into bg as "daemon":
+ setpgrp(0, 0);
+ my $pid = fork();
+ if (! defined $pid) {
+ die "connect_switch: $!\n";
+ } elsif ($pid) {
+ wait;
+ exit 0;
+ }
+ if (fork) {
+ exit 0;
+ }
+ setpgrp(0, 0);
+ close STDIN;
+ if (! $ENV{CONNECT_SWITCH_LOGFILE}) {
+ close STDOUT;
+ close STDERR;
+ }
+ }
+ delete $ENV{CONNECT_SWITCH_LOOP};
+
+ if (exists $ENV{CONNECT_SWITCH_PIDFILE}) {
+ open_pidfile();
+ }
+
+ print STDERR "connect_switch: starting service at ", scalar(localtime), " master-pid=$$\n";
+ while (1) {
+ $looppid = fork;
+ if (! defined $looppid) {
+ sleep 10;
+ } elsif ($looppid) {
+ wait;
+ } else {
+ exec $0;
+ exit 1;
+ }
+ print STDERR "connect_switch: re-starting service at ", scalar(localtime), " master-pid=$$\n";
+ sleep 1;
+ }
+ exit 0;
+}
+if (exists $ENV{CONNECT_SWITCH_PIDFILE}) {
+ open_pidfile();
+}
############################################################################
@@ -83,15 +207,29 @@
# CONNECT_SWITCH_VERBOSE
# CONNECT_SWITCH_APPLY_VNC_OFFSET
# CONNECT_SWITCH_VNC_OFFSET
+# CONNECT_SWITCH_LISTEN_IPV6
+# CONNECT_SWITCH_BUFSIZE
+# CONNECT_SWITCH_LOGFILE
+# CONNECT_SWITCH_PIDFILE
+#
+# You can also set these on the cmdline:
+# connect_switch CONNECT_SWITCH_LISTEN=X CONNECT_SWITCH_ALLOW_FILE=Y ...
+#
+# By default we will use hostname and assume it resolves:
+#
my $hostname = `hostname`;
chomp $hostname;
my $listen_host = $hostname;
my $listen_port = 443;
+# Let user override listening situation, e.g. multihomed:
+#
if (exists $ENV{CONNECT_SWITCH_LISTEN}) {
+ #
# E.g. CONNECT_SWITCH_LISTEN=192.168.0.32:443
+ #
($listen_host, $listen_port) = split(/:/, $ENV{CONNECT_SWITCH_LISTEN});
}
@@ -99,10 +237,21 @@ my $httpd_host = 'localhost';
my $httpd_port = 443;
if (exists $ENV{CONNECT_SWITCH_HTTPD}) {
+ #
# E.g. CONNECT_SWITCH_HTTPD=127.0.0.1:443
+ #
($httpd_host, $httpd_port) = split(/:/, $ENV{CONNECT_SWITCH_HTTPD});
}
+my $bufsize = 8192;
+if (exists $ENV{CONNECT_SWITCH_BUFSIZE}) {
+ #
+ # E.g. CONNECT_SWITCH_BUFSIZE=32768
+ #
+ $bufsize = $ENV{CONNECT_SWITCH_BUFSIZE};
+}
+
+
############################################################################
# You can/should override the host/port settings here:
#
@@ -113,6 +262,9 @@ if (exists $ENV{CONNECT_SWITCH_HTTPD}) {
# You must set the allowed host:port CONNECT redirection list.
# Only these host:port pairs will be redirected to.
+# Port ranges are allowed too: host:5900-5930.
+# If there is one entry named ALL all connections are allow.
+# You must supply something, default is deny.
#
my @allowed = qw(
machine1:5915
@@ -141,6 +293,8 @@ if (exists $ENV{CONNECT_SWITCH_ALLOWED}) {
# fredsbox 15
# rupert 1
+# For examply, mine is:
+#
my $allow_file = '/dist/apache/2.0/conf/vnc.hosts';
$allow_file = '';
@@ -158,25 +312,34 @@ my $apply_vnc_offset = 1;
my $vnc_offset = 5900;
if (exists $ENV{CONNECT_SWITCH_APPLY_VNC_OFFSET}) {
+ #
# E.g. CONNECT_SWITCH_APPLY_VNC_OFFSET=0
+ #
$apply_vnc_offset = $ENV{CONNECT_SWITCH_APPLY_VNC_OFFSET};
}
if (exists $ENV{CONNECT_SWITCH_VNC_OFFSET}) {
+ #
# E.g. CONNECT_SWITCH_VNC_OFFSET=6000
+ #
$vnc_offset = $ENV{CONNECT_SWITCH_VNC_OFFSET};
}
-# Set to 1 for more debugging output:
+# Set to 1 or higher for more info output:
#
my $verbose = 0;
if (exists $ENV{CONNECT_SWITCH_VERBOSE}) {
+ #
# E.g. CONNECT_SWITCH_VERBOSE=1
+ #
$verbose = $ENV{CONNECT_SWITCH_VERBOSE};
}
-############################################################################
+
+
+#===========================================================================
# No need for any changes below here.
+#===========================================================================
use IO::Socket::INET;
use strict;
@@ -186,12 +349,29 @@ my $killpid = 1;
setpgrp(0, 0);
-my $listen_sock = IO::Socket::INET->new(
- Listen => 10,
- LocalAddr => $listen_host,
- LocalPort => $listen_port,
- Proto => "tcp"
-);
+if (exists $ENV{CONNECT_SWITCH_LISTEN_IPV6}) {
+ # note we leave out LocalAddr.
+ my $cmd = '
+ use IO::Socket::INET6;
+ $listen_sock = IO::Socket::INET6->new(
+ Listen => 10,
+ LocalPort => $listen_port,
+ ReuseAddr => 1,
+ Domain => AF_INET6,
+ Proto => "tcp"
+ );
+ ';
+ eval $cmd;
+ die "$@\n" if $@;
+} else {
+ $listen_sock = IO::Socket::INET->new(
+ Listen => 10,
+ LocalAddr => $listen_host,
+ LocalPort => $listen_port,
+ ReuseAddr => 1,
+ Proto => "tcp"
+ );
+}
if (! $listen_sock) {
die "connect_switch: $!\n";
@@ -210,7 +390,7 @@ while (1) {
fsleep(0.5);
next;
}
- print STDERR "conn: $conn -- ", $client->peerhost(), "\n" if $verbose;
+ print STDERR "conn: $conn -- ", $client->peerhost(), " at ", scalar(localtime), "\n" if $verbose;
my $pid = fork();
if (! defined $pid) {
@@ -237,6 +417,10 @@ sub handle_conn {
my @allow = @allowed;
+ # read allow file. Note we read it for every connection
+ # to allow the admin to modify it w/o restarting us.
+ # better way would be to read in parent and check mtime.
+ #
if ($allow_file && -f $allow_file) {
if (open(ALLOW, "<$allow_file")) {
while (<ALLOW>) {
@@ -259,6 +443,8 @@ sub handle_conn {
}
}
+ # Read the first 7 bytes of connection, see if it is 'CONNECT'
+ #
my $str = '';
my $N = 0;
my $isconn = 1;
@@ -267,7 +453,7 @@ sub handle_conn {
sysread($client, $b, 1);
$str .= $b;
$N++;
- print STDERR "read: '$str'\n" if $verbose;
+ print STDERR "read: '$str'\n" if $verbose > 1;
my $cstr = substr('CONNECT', 0, $i+1);
if ($str ne $cstr) {
$isconn = 0;
@@ -276,28 +462,60 @@ sub handle_conn {
}
my $sock = '';
+
if ($isconn) {
+ # it is CONNECT, read rest of HTTP header:
+ #
while ($str !~ /\r\n\r\n/) {
my $b;
sysread($client, $b, 1);
$str .= $b;
}
- print STDERR "read: $str\n" if $verbose;
+ print STDERR "read: $str\n" if $verbose > 1;
+ # get http version and host:port
+ #
my $ok = 0;
my $hostport = '';
my $http_vers = '1.0';
if ($str =~ /^CONNECT\s+(\S+)\s+HTTP\/(\S+)/) {
$hostport = $1;
$http_vers = $2;
- foreach my $hp (@allow) {
- if ($hp eq $hostport) {
- $ok = 1;
- last;
+
+ my ($h, $p) = split(/:/, $hostport);
+ if ($p =~ /^\d+$/) {
+ # check allowed host list:
+ foreach my $hp (@allow) {
+ if ($hp eq 'ALL') {
+ $ok = 1;
+ }
+ if ($hp eq $hostport) {
+ $ok = 1;
+ }
+ if ($hp =~ /^(.*):(\d+)-(\d+)$/) {
+ my $ahost = $1;
+ my $pmin = $2;
+ my $pmax = $3;
+ if ($h eq $ahost) {
+ if ($p >= $pmin && $p <= $pmax) {
+ $ok = 1;
+ }
+ }
+ }
+ last if $ok;
}
}
}
+
+ my $msg_1 = "HTTP/$http_vers 200 Connection Established\r\n"
+ . "Proxy-agent: connect_switch v0.2\r\n\r\n";
+ my $msg_2 = "HTTP/$http_vers 502 Bad Gateway\r\n"
+ . "Connection: close\r\n\r\n";
+
if (! $ok) {
+ # disallowed. drop with message.
+ #
+ syswrite($client, $msg_2, length($msg_2));
close $client;
exit 0;
}
@@ -312,18 +530,20 @@ sub handle_conn {
Proto => "tcp"
);
my $msg;
+
+ # send the connect proxy reply:
+ #
if ($sock) {
- $msg = "HTTP/$http_vers 200 Connection Established\r\n"
- . "Proxy-agent: connect_switch v0.2\r\n\r\n";
+ $msg = $msg_1;
} else {
- $msg = "HTTP/$http_vers 502 Bad Gateway\r\n"
- . "Connection: close\r\n\r\n";
+ $msg = $msg_2;
}
syswrite($client, $msg, length($msg));
$str = '';
} else {
- print STDERR "connecting to: $httpd_host:$httpd_port\n"
- if $verbose;
+ # otherwise, redirect to apache for normal https:
+ #
+ print STDERR "connecting to: $httpd_host:$httpd_port\n" if $verbose;
$sock = IO::Socket::INET->new(
PeerAddr => $httpd_host,
PeerPort => $httpd_port,
@@ -336,6 +556,8 @@ sub handle_conn {
die "connect_switch: $!\n";
}
+ # get ready for xfer phase:
+ #
$current_fh1 = $client;
$current_fh2 = $sock;
@@ -349,6 +571,8 @@ sub handle_conn {
kill 'TERM', $child;
}
} else {
+ # write those first bytes if not CONNECT:
+ #
if ($str ne '' && $N > 0) {
syswrite($sock, $str, $N);
}
@@ -358,9 +582,9 @@ sub handle_conn {
kill 'TERM', $parent;
}
}
- if ($verbose) {
+ if ($verbose > 1) {
my $dt = time() - $start;
- print STDERR "dt\[$$]: $dt\n";
+ print STDERR "duration\[$$]: $dt seconds. ", scalar(localtime), "\n";
}
exit 0;
}
@@ -380,7 +604,7 @@ sub xfer {
while (! $nf) {
$nf = select($ROUT=$RIN, undef, undef, undef);
}
- my $len = sysread($in, $buf, 8192);
+ my $len = sysread($in, $buf, $bufsize);
if (! defined($len)) {
next if $! =~ /^Interrupted/;
print STDERR "connect_switch\[$lab/$conn/$$]: $!\n";
@@ -392,7 +616,7 @@ sub xfer {
}
if (0) {
- # verbose debugging of data:
+ # very verbose debugging of data:
syswrite(STDERR , "\n$lab: ", 6);
syswrite(STDERR , $buf, $len);
}
diff --git a/x11vnc/misc/desktop.cgi b/x11vnc/misc/desktop.cgi
new file mode 100755
index 0000000..c2f9cc9
--- /dev/null
+++ b/x11vnc/misc/desktop.cgi
@@ -0,0 +1,1134 @@
+#!/usr/bin/perl
+#
+# desktop.cgi
+#
+# An example cgi script to provide multi-user web access to x11vnc
+# desktops. This script should/must be served by an HTTPS webserver,
+# otherwise the unix and vnc passwords are sent over the network
+# unencrypted (see below to disable)
+#
+# Note that the x11vnc -create virtual desktop service used below requires
+# that you install the 'Xvfb' program.
+#
+# You should put this script in, say, a cgi-bin directory.
+#
+# You will *also* need to copy the x11vnc classes/ssl/UltraViewerSSL.jar
+# file to the document root: /UltraViewerSSL.jar (or change the html
+# at bottom.)
+#
+# Each x11vnc server created for a login will listen on its own port (see
+# below for port selection schemes.) Your firewall must let in these ports.
+# It is difficult and not as reliable to do all of this through a single port;
+# however, see the fixed port scheme find_free_port = 'fixed:5900' below.
+#
+# Note there are two SSL certificates involved that the user may be
+# asked to inspect: apache's SSL cert and x11vnc's SSL cert. This may
+# confuse the user.
+#
+# This script provides one example on how to provide the service. You can
+# customize to meet your needs, e.g. switch to php, newer modules,
+# different authentication, SQL database, etc. If you plan to use it
+# in production, please examine all security aspects of it carefully;
+# read the comments in the script for more info.
+#
+# More information and background:
+#
+# http://www.karlrunge.com/x11vnc/faq.html#faq-xvfb
+# http://www.karlrunge.com/x11vnc/faq.html#faq-ssl-tunnel-viewers
+# http://www.karlrunge.com/x11vnc/faq.html#faq-ssl-java-viewer-proxy
+# http://www.karlrunge.com/x11vnc/faq.html#faq-ssl-portal
+# http://www.karlrunge.com/x11vnc/faq.html#faq-unix-passwords
+# http://www.karlrunge.com/x11vnc/faq.html#faq-userlogin
+
+
+#-------------------------------------------------------------------------
+# Copyright (c) 2010 by Karl J. Runge <runge@karlrunge.com>
+#
+# desktop.cgi is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or (at
+# your option) any later version.
+#
+# desktop.cgi is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with desktop.cgi; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
+# or see <http://www.gnu.org/licenses/>.
+#-------------------------------------------------------------------------
+
+use strict;
+use IO::Socket::INET;
+
+
+# TCP Ports:
+#
+# Set find_free_port to 1 (or the other modes described below) to
+# autoselect a free port to use. The default is to use a fixed port
+# based on the userid.
+#
+my $find_free_port = 0;
+#
+# Or specify a port range:
+#
+#$find_free_port = '7000-8000';
+#
+# Or indicate to use a kludge to try to do everything through a SINGLE
+# port. To try to avoid contention on the port, simultaneous instances
+# of this script attempt to 'take turns' using it.
+#
+#$find_free_port = 'fixed:5900';
+
+
+# Port redirection mode:
+#
+# This is to allow port redirection mode: username@host:port If username
+# is valid, there will be a port redirection to internal machine
+# host:port. Presumably there is already an SSL enabled and password
+# protected VNC server running there. We don't start that server.
+# See the next setting for an allowed hosts file. The default for port
+# redirection is off.
+#
+my $enable_port_redirection = 0;
+
+# A file with allowed port redirections. The empty string '' (the
+# default) means all host:port redirections would be allowed.
+#
+# Format of the file: A list of 'user@host:port' or 'host:port'
+# entries, one per line. Port ranges, e.g. host:n-m are also accepted.
+#
+# Leading and trailing whitespace is trimmed off each line. Blank lines
+# and comment lines starting with '#' are skipped. A line consisting of
+# 'ALL' matches everything. If no match can be found or the file cannot
+# be opened the connection is dropped.
+#
+my $port_redirection_allowed_hosts = '';
+
+
+# Set to 0 to have the java applet html set the parameter
+# trustUrlVncCert=no, i.e. the applet will not automatically accept an
+# SSL cert already accepted by an HTTPS URL. See print_applet_html()
+# below for more info.
+#
+my $trustUrlVncCert = 1;
+
+
+# Comment this out if you don't want PATH modified:
+#
+$ENV{PATH} = "/usr/bin:bin:$ENV{PATH}";
+
+
+# For the next two settings, note that most users will be confused that
+# geometry and session are ignored when they are returning to their
+# existing desktop session (x11vnc FINDDISPLAY action.)
+
+# Used below if user did not specify preferred geometry and color depth:
+#
+my $default_geometry = '1024x768x24';
+
+
+# Set this to the list of x11vnc -create sessions types to show a session
+# dropdown for the user to select from.
+#
+my $session_types = '';
+#
+# example:
+#$session_types = 'gnome kde xfce lxde wmaker enlightenment mwm twm failsafe';
+
+
+# Set this to 1 to enable user setting a unique tag for each one
+# of his desktops and so can have multiple ones simultaneously and
+# select which one he wants. For now we just hack this onto geometry
+# 1024x768x24:my_2nd_desktop but ultimately there should be a form entry
+# for it. Search for enable_unique_tags for more info:
+#
+my $enable_unique_tags = 0;
+my $unique_tag = '';
+
+# You can set some extra x11vnc cmdline options here:
+#
+my $x11vnc_extra_opts = '';
+
+
+# Path to x11vnc program:
+#
+my $x11vnc = '/usr/bin/x11vnc';
+
+if (`uname -n` =~ /haystack/) {
+ # for my testing:
+ if (-f "/home/runge/dtcgi.test") {
+ eval `cat /home/runge/dtcgi.test`;
+ }
+}
+
+
+# http header:
+#
+print STDOUT "Content-Type: text/html\r\n\r\n";
+
+
+# Require HTTPS so that unix and vnc passwords are not sent in clear text
+# (perhaps it is too late...) Disable HTTPS at your own risk.
+#
+if ($ENV{HTTPS} !~ /^on$/i) {
+ bye("HTTPS must be used (to encrypt passwords)");
+}
+
+
+# Read request:
+#
+my $request;
+if ($ENV{'REQUEST_METHOD'} eq "POST") {
+ read(STDIN, $request, $ENV{'CONTENT_LENGTH'});
+} elsif ($ENV{'REQUEST_METHOD'} eq "GET" ) {
+ $request = $ENV{'QUERY_STRING'};
+} else {
+ $request = $ARGV[0];
+}
+
+my %request = url_decode(split(/[&=]/, $request));
+
+
+# Experiment for FD_TAG x11vnc feature for multiple desktops:
+#
+# we hide it in geometry:tag for now:
+#
+if ($enable_unique_tags && $request{geometry} =~ /^(.*):(\w+)$/) {
+ $request{geometry} = $1;
+ $unique_tag = $2;
+}
+
+# Check/set geometry and session:
+#
+if (!exists $request{geometry} || $request{geometry} !~ /^[x\d]+$/) {
+ # default geometry and depth:
+ $request{geometry} = $default_geometry;
+}
+if (!exists $request{session} || $request{session} =~ /^\s*$/) {
+ $request{session} = '';
+}
+
+
+# String for the login form:
+#
+my $login_str = <<"END";
+<title>x11vnc web access</title>
+<h3>x11vnc web access</h3>
+<form action="$ENV{REQUEST_URI}" method="post">
+ <table border="0">
+ <tr><td colspan=2><h2>Login</h2></td></tr>
+ <tr><td>Username:</td><td>
+ <input type="text" name="username" maxlength="40" value="$request{username}">
+ </td></tr>
+ <tr><td>Password:</td><td>
+ <input type="password" name="password" maxlength="50">
+ </td></tr>
+ <tr><td>Geometry:</td><td>
+ <input type="text" name="geometry" maxlength="40" value="$request{geometry}">
+ </td></tr>
+ <!-- session -->
+ <tr><td colspan="2" align="right">
+ <input type="submit" name="submit" value="Login">
+ </td></tr>
+ </table>
+</form>
+END
+
+
+# Set up user selected desktop session list, if enabled:
+#
+my %sessions;
+
+if ($session_types ne '') {
+ my $str = "<tr><td>Session:</td><td>\n<select name=session>";
+ $str .= "<option value=none>select</option>";
+
+ foreach my $sess (split(' ', $session_types)) {
+ next if $sess =~ /^\s*$/;
+ next if $sess !~ /^\w+$/; # alphanumeric
+ $sessions{$sess} = 1;
+ $str .= "<option value=$sess>$sess</option>";
+ }
+ $str .= "</select>\n</td></tr>";
+
+ # This forces $request{session} to be a valid one:
+ #
+ if (! exists $sessions{$request{session}}) {
+ $request{session} = 'none';
+ }
+
+ # Insert into login_str:
+ #
+ my $r = $request{session};
+ $str =~ s/option value=\Q$r\E/option selected value=$r/;
+ $login_str =~ s/<!-- session -->/$str/;
+}
+
+
+# If no username or password, show login form:
+#
+if (!$request{username} && !$request{password}) {
+ bye($login_str);
+} elsif (!$request{username}) {
+ bye("No Username.<p>$login_str");
+} elsif (!$request{password}) {
+ bye("No Password.<p>$login_str");
+}
+
+
+# Some shorthand names:
+#
+my $username = $request{username};
+my $password = $request{password};
+my $geometry = $request{geometry};
+my $session = $request{session};
+
+
+# If port redirection is enabled, split username@host:port
+#
+my $redirect_host = '';
+my $current_fh1 = '';
+my $current_fh2 = '';
+
+if ($enable_port_redirection) {
+ ($username, $redirect_host) = split(/@/, $username, 2);
+ if ($redirect_host ne '') {
+ # will exit if the redirection is not allowed:
+ check_redirect_host();
+ }
+}
+
+
+# Require username to be alphanumeric + '-' + '_':
+# (one may want to add '.' as well)
+#
+if ($username !~ /^\w[-\w]*$/) {
+ bye("Invalid Username.<p>$login_str");
+}
+
+
+# Get the userid number, we may use it as his VNC display port; this
+# also checks if the username exists:
+#
+my $uid = `/usr/bin/id -u '$username'`;
+chomp $uid;
+if ($? != 0 || $uid !~ /^\d+$/) {
+ bye("Invalid Username.<p>$login_str");
+}
+
+
+# Use x11vnc trick to check if the unix password is valid:
+#
+if (!open(X11VNC, "| $x11vnc -unixpw \%stdin > /dev/null")) {
+ bye("Internal Error #1");
+}
+print X11VNC "$username:$password\n";
+
+if (!close X11VNC) {
+ # x11vnc returns non-zero for invalid username+password:
+ bye("Invalid Password.<p>$login_str");
+}
+
+
+# Initialize random number generator for use below:
+#
+initialize_random();
+
+
+# Set vnc port:
+#
+my $vnc_port = 0;
+my $fixed_port = 0;
+
+if (! $find_free_port) {
+ # Fixed port based on userid (we assume it is free):
+ #
+ $vnc_port = 7000 + $uid;
+
+} elsif ($find_free_port =~ /^fixed:(\d+)$/) {
+ #
+ # Enable the -loopbg method that tries to share a single port:
+ #
+ $vnc_port = $1;
+ $fixed_port = 1;
+} else {
+ # Autoselect a port, either default range (7000-8000) or a user
+ # supplied range. (note that $find_free_port will now contain
+ # a socket listening on the found port so that it is held.)
+ #
+ $vnc_port = auto_select_port();
+}
+
+# Check for crazy port value:
+#
+if ($vnc_port > 64000 || $vnc_port < 1) {
+ bye("Internal Error #2 $vnc_port");
+}
+
+
+# If port redirection is enabled and the user selected it via
+# username@host:port, we do that right now and then exit.
+#
+if ($enable_port_redirection && $redirect_host ne '') {
+ port_redir();
+ exit 0;
+}
+
+
+# Make a random, onetime vnc password:
+#
+my $pass = '';
+my $chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
+my @abc = split(//, $chars);
+
+for (my $i = 0; $i < 8; $i++) {
+ $pass .= $abc[ rand(scalar(@abc)) ];
+}
+
+# Use x11vnc trick to switch to user and store vnc pass in the passwdfile.
+# Result is $pass is placed in user's $HOME/x11vnc.pw
+#
+# (This is actually difficult to do without untrusted local users being
+# able to see the pass as well, see copy_password_to_user() for details
+# on how we try to avoid this.)
+#
+copy_password_to_user($pass);
+
+
+# Make a tmp file for x11vnc launcher script:
+#
+my $tmpfile = `/bin/mktemp /tmp/desktop.cgi.XXXXXX`;
+chomp $tmpfile;
+
+# Check if the tmpfile is valid:
+#
+if (! -e $tmpfile || ! -o $tmpfile || -l $tmpfile) {
+ unlink $tmpfile;
+ bye("Internal Error #3");
+}
+if (!chmod 0644, $tmpfile) {
+ unlink $tmpfile;
+ bye("Internal Error #4");
+}
+if (!open(TMP, ">$tmpfile")) {
+ unlink $tmpfile;
+ bye("Internal Error #5");
+}
+
+
+# The x11vnc command. You adjust it to suit your needs.
+#
+# some ideas: -env FD_PROG=/usr/bin/gnome-session
+# -env FD_SESS=kde
+# -env FD_TAG=my_2nd_desktop
+# -ultrafilexfer
+#
+# Note that -timeout will cause it to exit if client does not connect
+# and -sslonly disables VeNCrypt SSL connections.
+
+# Some settings:
+#
+my $timeout = 75;
+my $extra = '';
+if ($fixed_port) {
+ # settings for fixed port case:
+ $timeout = 45;
+ $extra .= " -loopbg100,1";
+}
+if ($session_types ne '') {
+ # settings for session selection case:
+ if (exists $sessions{$session}) {
+ $extra .= " -env FD_SESS='$session'";
+ }
+}
+if ($enable_unique_tags && $unique_tag ne '' && $unique_tag =~ /^\w+$/) {
+ $extra .= " -env FD_TAG='$unique_tag'";
+}
+
+# This md5sum check of the vnc passwd is for extra safety (see
+# copy_password_to_user for details.)
+#
+my $md5sum = '';
+system("type md5sum > /dev/null");
+if ($? == 0) {
+ my $md5 = `/bin/mktemp /tmp/desktop.cgi.XXXXXX`;
+ chomp $md5;
+ # compute md5sum of password:
+ if (-o $md5 && open(MD5, "| md5sum > $md5")) {
+ print MD5 "$pass\n";
+ close MD5;
+ if (open(MD5, "<$md5")) {
+ # read it:
+ my $line = <MD5>;
+ close MD5;
+ my ($s, $t) = split(' ', $line);
+ if (length($s) >= 32 && $s =~ /^\w+$/) {
+ # shell code for user to check he has correct passwd:
+ $md5sum = "if md5sum \$HOME/x11vnc.pw | grep '$s' > /dev/null; then true; else exit 1; fi";
+ }
+ }
+ }
+ unlink $md5;
+}
+
+# write x11vnc command to the tmp file:
+#
+print TMP <<"END";
+#!/bin/sh
+export PATH=/usr/bin:/bin:\$PATH
+$md5sum
+$x11vnc -sigpipe ignore:HUP -nopw -rfbport $vnc_port \\
+ -passwdfile \$HOME/x11vnc.pw -oa \$HOME/x11vnc.log \\
+ -create -ssl SAVE -sslonly -env FD_GEOM=$geometry \\
+ -timeout $timeout $extra $x11vnc_extra_opts \\
+ >/dev/null 2>/dev/null </dev/null &
+sleep 2
+exit 0
+END
+
+close TMP;
+
+# Now launch x11vnc to switch to user and run the wrapper script:
+# (this requires x11vnc 0.9.10 or later.)
+#
+$ENV{UNIXPW_CMD} = "/bin/sh $tmpfile";
+
+# For the fixed port scheme we try to cooperate via lock file:
+#
+my $rmlock = '';
+#
+if ($fixed_port) {
+ # try to grab the fixed port for the next 90 secs removing stale
+ # locks older than 60 secs:
+ #
+ $rmlock = lock_fixed_port(90, 60);
+}
+
+# Start the x11vnc cmd:
+#
+if (!open(X11VNC, "| $x11vnc -unixpw \%stdin > /dev/null")) {
+ unlink $tmpfile;
+ unlink $rmlock if $rmlock;
+ bye("Internal Error #6");
+}
+
+select(X11VNC); $| = 1; select(STDOUT);
+
+# Close any port we held. There is still a gap of time between now
+# and when when x11vnc in $tmpfile reopens the port after the password
+# authentication. So another instance of this script could accidentally
+# think it is free...
+#
+sleep 1;
+close $find_free_port if $find_free_port;
+
+print X11VNC "$username:$password\n";
+close X11VNC; # note we ignore return value.
+unlink $tmpfile;
+
+if ($rmlock) {
+ # let our x11vnc proceed a bit before removing lock.
+ sleep 2;
+ unlink $rmlock;
+}
+
+# Return html for the java applet to connect to x11vnc.
+#
+print_applet_html();
+
+exit 0;
+
+#################################################################
+# Subroutines:
+
+# print the message to client and exit with success.
+#
+sub bye {
+ my $msg = shift;
+ print STDOUT "<html>$msg</html>\n";
+ exit 0;
+}
+
+# decode %xx to character:
+#
+sub url_decode {
+ foreach (@_) {
+ tr/+/ /;
+ s/%(..)/pack("c",hex($1))/ge;
+ }
+ @_;
+}
+
+# seed random
+#
+sub initialize_random {
+ my $rbytes = '';
+ if (open(RAN, "</dev/urandom")) {
+ read(RAN, $rbytes, 8);
+ } elsif (open(RAN, "</dev/random")) {
+ read(RAN, $rbytes, 8);
+ } else {
+ $rbytes = sprintf("%08d", $$);
+ }
+ close RAN;
+
+ # set seed:
+ #
+ my $seed = join('', unpack("C8", $rbytes));
+ $seed = substr($seed, -9);
+ srand($seed);
+
+ for (my $i = 0; $i < ($$ % 4096); $i++) {
+ # Mix it up even a little bit more. There should be
+ # over 1 billion possible vnc passwords now.
+ rand();
+ }
+}
+
+# Autoselect a port for vnc. Note that a socket for the found port
+# is kept open (and stored in $find_free_port) until we call x11vnc at
+# the end.
+#
+sub auto_select_port {
+ my $pmin = 7000; # default range.
+ my $pmax = 8000;
+
+ if ($find_free_port =~ /^(\d+)-(\d+)$/) {
+ # user supplied a range:
+ $pmin = $1;
+ $pmax = $2;
+ if ($pmin > $pmax) {
+ ($pmin, $pmax) = ($pmax, $pmin);
+ }
+ } elsif ($find_free_port > 1024) {
+ # user supplied a starting port:
+ $pmin = $find_free_port;
+ $pmax = $pmin + 1000;
+ }
+
+ # Try to add a bit of randomness to the starting port so
+ # simultaneous instances of this script won't be fooled by the gap
+ # of time before x11vnc reopens the port (see near the bottom.)
+ #
+ my $dp = int(rand(1.0) * 0.25 * ($pmax - $pmin));
+ if ($pmin + $dp < $pmax - 20) {
+ $pmin = $pmin + $dp;
+ }
+
+ my $port = 0;
+
+ # Now try to find a free one:
+ #
+ for (my $p = $pmin; $p <= $pmax; $p++) {
+ my $sock = IO::Socket::INET->new(
+ Listen => 1,
+ LocalPort => $p,
+ ReuseAddr => 1,
+ Proto => "tcp"
+ );
+ if ($sock) {
+ # we will keep this open until we call x11vnc:
+ $find_free_port = $sock;
+ $port = $p;
+ last;
+ }
+ }
+ return $port;
+}
+
+# Since apache typically runs as user 'apache', 'nobody', etc, and not
+# as root it is tricky for us to copy the pass string to a file owned by
+# the user without some other untrusted local user being able to learn
+# the password (e.g. via reading a file or watching ps.) Note that with
+# the x11vnc -unixpw trick we unfortunately can't use a pipe because
+# the user command is run in its own tty.
+#
+# The best way would be a sudo action or a special setuid program for
+# copying. So consider using that and thereby simplify this function.
+#
+# Short of a special program doing this, we use a fifo so ONLY ONE
+# process can read the password. If the untrusted local user reads it,
+# then the logging-in user's x11vnc won't get it. The login and x11vnc
+# will fail, but the untrusted user won't gain access to the logging-in
+# user's desktop.
+#
+# So here we start long, tedious work carefully managing the fifo.
+#
+sub copy_password_to_user {
+
+ my $pass = shift;
+
+ my $use_fifo = '';
+
+ # Find a command to make a fifo:
+ #
+ system("type mkfifo > /dev/null");
+ if ($? == 0) {
+ $use_fifo = 'mkfifo %s';
+ } else {
+ system("type mknod > /dev/null");
+ if ($? == 0) {
+ $use_fifo = 'mknod %s p';
+ }
+ }
+
+ # Create the filename for our fifo:
+ #
+ my $fifo = `/bin/mktemp /tmp/desktop.cgi.XXXXXX`;
+ chomp $fifo;
+
+ if (! -e $fifo || ! -o $fifo || -l $fifo) {
+ unlink $fifo;
+ bye("Internal Error #7");
+ }
+
+ # Make the fifo:
+ #
+ if ($use_fifo) {
+ $use_fifo = sprintf($use_fifo, $fifo);
+
+ # there is a small race here:
+ system("umask 077; rm -f $fifo; $use_fifo; chmod 600 $fifo");
+
+ if (!chmod 0600, $fifo) {
+ # we chmod once more..
+ unlink $fifo;
+ bye("Internal Error #8");
+ }
+
+ if (! -o $fifo || ! -p $fifo || -l $fifo) {
+ # but we get out if not owned by us anymore:
+ unlink $fifo;
+ bye("Internal Error #9");
+ }
+ }
+
+ # Build cmd for user to read our fifo:
+ #
+ my $upw = '$HOME/x11vnc.pw';
+ $ENV{UNIXPW_CMD} = "touch $upw; chmod 600 $upw; cat $fifo > $upw";
+
+ # Start it:
+ #
+ if (!open(X11VNC, "| $x11vnc -unixpw \%stdin > /dev/null")) {
+ unlink $fifo;
+ bye("Internal Error #10");
+ }
+ select(X11VNC); $| = 1; select(STDOUT);
+
+ if (! $use_fifo) {
+ # regular file, we need to write it now.
+ if (!open(FIFO, ">$fifo")) {
+ close X11VNC;
+ unlink $fifo;
+ bye("Internal Error #11");
+ }
+ print FIFO "$pass\n";
+ close FIFO;
+ }
+
+ # open fifo up for reading.
+ # (this means the bad guy can read it too.)
+ #
+ if (!chmod 0644, $fifo) {
+ unlink $fifo;
+ bye("Internal Error #12");
+ }
+
+ # send the user's passwd now:
+ #
+ print X11VNC "$username:$password\n";
+
+ if ($use_fifo) {
+ # wait a bit for the cat $fifo to start, reader will block.
+ sleep 1;
+ if (!open(FIFO, ">$fifo")) {
+ close X11VNC;
+ unlink $fifo;
+ bye("Internal Error #13");
+ }
+ # here it goes:
+ print FIFO "$pass\n";
+ close FIFO;
+ }
+ close X11VNC; # note we ignore return value.
+ fsleep(0.5);
+ #print STDERR `ls -l $fifo ~$username/x11vnc.pw`;
+ unlink $fifo;
+
+ # Done!
+}
+
+# For fixed, single port mode. Try to open and lock the port before
+# proceeding.
+#
+sub lock_fixed_port {
+ my ($t_max, $t_age) = @_;
+
+ # lock file name:
+ #
+ my $lock = '/tmp/desktop.cgi.lock';
+ my $remove = '';
+
+ my $t = 0;
+ my $sock = '';
+
+ while ($t < $t_max) {
+ if (-e $lock) {
+ # clean out stale locks if possible:
+ if (! -l $lock) {
+ unlink $lock;
+ } else {
+ my ($pid, $time) = split(/:/, readlink($lock));
+ if (! -d "/proc/$pid") {
+ unlink $lock;
+ }
+ if (time() > $time + $t_age) {
+ unlink $lock;
+ }
+ }
+ }
+
+ my $reason = '';
+
+ if (-l $lock) {
+ # someone has locked it.
+ $reason = 'locked';
+ } else {
+ # unlocked, try to listen on port:
+ $sock = IO::Socket::INET->new(
+ Listen => 1,
+ LocalPort => $vnc_port,
+ ReuseAddr => 1,
+ Proto => "tcp"
+ );
+ if ($sock) {
+ # we got it, now try to lock:
+ my $str = "$$:" . time();
+ if (symlink($str, $lock)) {
+ $remove = $lock;
+ $find_free_port = $sock;
+ last;
+ }
+ # wow, we didn't lock it...
+ $reason = "symlink failed: $!";
+ close $sock;
+ } else {
+ $reason = "listen failed: $!";
+ }
+ }
+ # sleep a bit and then try again:
+ #
+ print STDERR "$$ failed to get fixed port $vnc_port for $username at $t ($reason)\n";
+ $sock = '';
+ $t += 5;
+ sleep 5;
+ }
+ if (! $sock) {
+ bye("Failed to lock fixed TCP port. Try again a bit later.<p>$login_str");
+ }
+ print STDERR "$$ got fixed port $vnc_port for $username at $t\n";
+
+ # Return the file to remove, if any:
+ #
+ return $remove;
+}
+
+
+# Return html for the java applet to connect to x11vnc.
+#
+# N.B. Please examine the applet params, e.g. trustUrlVncCert=yes to
+# see if you agree with them. See x11vnc classes/ssl/README for all
+# parameters.
+#
+# Note how we do not take extreme care to authenticate the server to
+# the client applet (but note that trustUrlVncCert=yes is better than
+# trustAllVncCerts=yes) One can tighten all of this up at the expense
+# of extra certificate dialogs (assuming the user bothers to check...)
+#
+# This assumes /UltraViewerSSL.jar is at document root; you need to put
+# it there.
+#
+sub print_applet_html {
+ my ($W, $H, $D) = split(/x/, $geometry);
+ $W = 640; # make it smaller since we 'Open New Window' below anyway.
+ $H = 480;
+ my $tUVC = ($trustUrlVncCert ? 'yes' : 'no');
+ my $str = <<"END";
+<html>
+<TITLE>
+x11vnc desktop ($uid/$vnc_port)
+</TITLE>
+<APPLET CODE=VncViewer.class ARCHIVE=/UltraViewerSSL.jar WIDTH=$W HEIGHT=$H>
+<param name=PORT value=$vnc_port>
+<param name=VNCSERVERPORT value=$vnc_port>
+<param name=PASSWORD value=$pass>
+<param name=trustUrlVncCert value=$tUVC>
+<param name="Open New Window" value=yes>
+<param name="Offer Relogin" value=no>
+<param name="ignoreMSLogonCheck" value=yes>
+<param name="delayAuthPanel" value=yes>
+<!-- extra -->
+</APPLET>
+<br>
+<a href="$ENV{REQUEST_URI}">Login page</a><br>
+<a href=http://www.karlrunge.com/x11vnc>x11vnc website</a>
+</html>
+END
+
+ if ($enable_port_redirection && $redirect_host ne '') {
+ $str =~ s/name=PASSWORD value=.*>/name=NOT_USED value=yes>/;
+ #$str =~ s/<!-- extra -->/<!-- extra -->\n<param name="ignoreProxy" value=yes>/;
+ }
+
+ print $str;
+}
+
+##########################################################################
+# The following subroutines are for port redirection only, which is
+# disabled by default ($enable_port_redirection == 0)
+#
+sub port_redir {
+ # To aid in avoiding zombies:
+ #
+ setpgrp(0, 0);
+
+ # For the fixed port scheme we try to cooperate via lock file:
+ #
+ my $rmlock = '';
+ #
+ if ($fixed_port) {
+ # try to grab the fixed port for the next 90 secs removing
+ # stale locks older than 60 secs:
+ #
+ $rmlock = lock_fixed_port(90, 60);
+
+ } elsif ($find_free_port eq '0') {
+ $find_free_port = IO::Socket::INET->new(
+ Listen => 1,
+ LocalPort => $vnc_port,
+ ReuseAddr => 1,
+ Proto => "tcp"
+ );
+ }
+ # In all cases, at this point $find_free_port is the listening
+ # socket.
+
+ # fork a helper process to do the port redir:
+ #
+ # Actually we need to spawn 4(!) of them in case the proxy check
+ # /check.https.proxy.connection (it is by default) and the other
+ # test connections. Spawn one for each expected connection, for
+ # whatever applet parameter usage mode you set up.
+ #
+ for (my $n = 1; $n <= 4; $n++) {
+ my $pid = fork();
+ if (! defined $pid) {
+ bye("Internal Error #14");
+ } elsif ($pid) {
+ wait;
+ } else {
+ if (fork) {
+ exit 0;
+ }
+ setpgrp(0, 0);
+ handle_conn();
+ exit 0;
+ }
+ }
+
+ # We now close the listening socket:
+ #
+ close $find_free_port;
+
+ if ($rmlock) {
+ # let our process proceed a bit before removing lock.
+ sleep 1;
+ unlink $rmlock;
+ }
+
+ # Now send html to the browser so it can connect:
+ #
+ print_applet_html();
+
+ exit 0;
+}
+
+# This checks the validity of a username@host:port for the port
+# redirection mode. Finishes and exits if it is invalid.
+#
+sub check_redirect_host {
+ # First check that the host:port string is valid:
+ #
+ if ($redirect_host !~ /^\w[-\w\.]*:\d+$/) {
+ bye("Invalid Redirect Host:Port.<p>$login_str");
+ }
+ # Second, check if the allowed host file permits it:
+ #
+ if ($port_redirection_allowed_hosts ne '') {
+ if (! open(ALLOWED, "<$port_redirection_allowed_hosts")) {
+ bye("Internal Error #15");
+ }
+ my $ok = 0;
+ while (my $line = <ALLOWED>) {
+ chomp $line;
+ # skip blank lines and '#' comments:
+ next if $line =~ /^\s*$/;
+ next if $line =~ /^\s*#/;
+
+ # trim spaces from ends:
+ $line =~ s/^\s*//;
+ $line =~ s/\s*$//;
+
+ # collect host:ports in case port range given:
+ my @items;
+ if ($line =~ /^(.*):(\d+)-(\d+)$/) {
+ # port range:
+ my $host = $1;
+ my $pmin = $2;
+ my $pmax = $3;
+ for (my $p = $pmin; $p <= $pmax; $p++) {
+ push @items, "$host:$p";
+ }
+ } else {
+ push @items, $line;
+ }
+
+ # now check each item for a match:
+ foreach my $item (@items) {
+ if ($item eq 'ALL') {
+ $ok = 1;
+ last;
+ } elsif ($item =~ /@/) {
+ if ("$username\@$redirect_host" eq $item) {
+ $ok = 1;
+ last;
+ }
+ } elsif ($redirect_host eq $item) {
+ $ok = 1;
+ last;
+ }
+ }
+ # got a match:
+ last if $ok;
+ }
+ close ALLOWED;
+
+ if (! $ok) {
+ bye("Disallowed Redirect Host:Port.<p>$login_str");
+ }
+ }
+}
+
+# Much of this code is borrowed from 'connect_switch':
+#
+sub handle_conn {
+ close STDIN;
+ close STDOUT;
+ close STDERR;
+
+ $SIG{ALRM} = sub {close $find_free_port; exit 0};
+
+ # We only wait 30 secs for the redir case, esp. since
+ # we need to spawn so many helpers...
+ #
+ alarm(30);
+
+ my ($client, $ip) = $find_free_port->accept();
+
+ alarm(0);
+
+ close $find_free_port;
+
+ if (!$client) {
+ exit 1;
+ }
+
+ my ($host, $port) = split(/:/, $redirect_host);
+
+ my $sock = IO::Socket::INET->new(
+ PeerAddr => $host,
+ PeerPort => $port,
+ Proto => "tcp"
+ );
+
+ if (! $sock) {
+ close $client;
+ exit 1;
+ }
+
+ $current_fh1 = $client;
+ $current_fh2 = $sock;
+
+ $SIG{TERM} = sub {close $current_fh1; close $current_fh2; exit 0};
+
+ my $killpid = 1;
+
+ my $parent = $$;
+ if (my $child = fork()) {
+ xfer($sock, $client, 'S->C');
+ if ($killpid) {
+ fsleep(0.5);
+ kill 'TERM', $child;
+ }
+ } else {
+ xfer($client, $sock, 'C->S');
+ if ($killpid) {
+ fsleep(0.75);
+ kill 'TERM', $parent;
+ }
+ }
+ exit 0;
+}
+
+# This does socket data transfer in one direction.
+#
+sub xfer {
+ my($in, $out, $lab) = @_;
+ my ($RIN, $WIN, $EIN, $ROUT);
+ $RIN = $WIN = $EIN = "";
+ $ROUT = "";
+ vec($RIN, fileno($in), 1) = 1;
+ vec($WIN, fileno($in), 1) = 1;
+ $EIN = $RIN | $WIN;
+ my $buf;
+
+ while (1) {
+ my $nf = 0;
+ while (! $nf) {
+ $nf = select($ROUT=$RIN, undef, undef, undef);
+ }
+ my $len = sysread($in, $buf, 8192);
+ if (! defined($len)) {
+ next if $! =~ /^Interrupted/;
+ last;
+ } elsif ($len == 0) {
+ last;
+ }
+
+ my $offset = 0;
+ my $quit = 0;
+ while ($len) {
+ my $written = syswrite($out, $buf, $len, $offset);
+ if (! defined $written) {
+ $quit = 1;
+ last;
+ }
+ $len -= $written;
+ $offset += $written;
+ }
+ last if $quit;
+ }
+ close($in);
+ close($out);
+}
+
+# Sleep a small amount of time (float)
+#
+sub fsleep {
+ my ($time) = @_;
+ select(undef, undef, undef, $time) if $time;
+}
diff --git a/x11vnc/misc/inet6to4 b/x11vnc/misc/inet6to4
new file mode 100755
index 0000000..b5c2fd1
--- /dev/null
+++ b/x11vnc/misc/inet6to4
@@ -0,0 +1,400 @@
+#!/usr/bin/perl
+#
+# inet6to4: Act as an ipv6-to-ipv4 relay for tcp applications that
+# do not support ipv6.
+#
+# Usage: inet6to4 <ipv6-listen-port> <ipv4-host:port>
+# inet6to4 -r <ipv4-listen-port> <ipv6-host:port>
+#
+# Examples: inet6to4 5900 localhost:5900
+# inet6to4 8080 web1:80
+# inet6to4 -r 5900 fe80::217:f2ff:fee6:6f5a%eth0:5900
+#
+# The -r option reverses the direction of translation (e.g. for ipv4
+# clients that need to connect to ipv6 servers.) Reversing is the default
+# if this script is named 'inet4to6' (e.g. by a symlink.)
+#
+# Use Ctrl-C to stop this program.
+#
+# You can also set env. vars INET6TO4_LOOP=1 or INET6TO4_LOOP=BG
+# to have an outer loop restarting this program (BG means do that
+# in the background), and INET6TO4_LOGFILE for a log file.
+# Also set INET6TO4_VERBOSE to verbosity level and INET6TO4_WAITTIME
+# and INET6TO4_PIDFILE (see below.)
+#
+
+#-------------------------------------------------------------------------
+# Copyright (c) 2010 by Karl J. Runge <runge@karlrunge.com>
+#
+# inet6to4 is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or (at
+# your option) any later version.
+#
+# inet6to4 is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with inet6to4; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
+# or see <http://www.gnu.org/licenses/>.
+#-------------------------------------------------------------------------
+
+# Set up logging:
+#
+if (exists $ENV{INET6TO4_LOGFILE}) {
+ close STDOUT;
+ if (!open(STDOUT, ">>$ENV{INET6TO4_LOGFILE}")) {
+ die "inet6to4: $ENV{INET6TO4_LOGFILE} $!\n";
+ }
+ close STDERR;
+ open(STDERR, ">&STDOUT");
+}
+select(STDERR); $| = 1;
+select(STDOUT); $| = 1;
+
+# interrupt handler:
+#
+my $looppid = '';
+my $pidfile = '';
+my $listen_sock = ''; # declared here for get_out()
+#
+sub get_out {
+ print STDERR "$_[0]:\t$$ looppid=$looppid\n";
+ close $listen_sock if $listen_sock;
+ if ($looppid) {
+ kill 'TERM', $looppid;
+ fsleep(0.2);
+ }
+ unlink $pidfile if $pidfile;
+ exit 0;
+}
+$SIG{INT} = \&get_out;
+$SIG{TERM} = \&get_out;
+
+# pidfile:
+#
+sub open_pidfile {
+ if (exists $ENV{INET6TO4_PIDFILE}) {
+ my $pf = $ENV{INET6TO4_PIDFILE};
+ if (open(PID, ">$pf")) {
+ print PID "$$\n";
+ close PID;
+ $pidfile = $pf;
+ } else {
+ print STDERR "could not open pidfile: $pf - $! - continuing...\n";
+ }
+ delete $ENV{INET6TO4_PIDFILE};
+ }
+}
+
+####################################################################
+# Set INET6TO4_LOOP=1 to have this script create an outer loop
+# restarting itself if it ever exits. Set INET6TO4_LOOP=BG to
+# do this in the background as a daemon.
+
+if (exists $ENV{INET6TO4_LOOP}) {
+ my $csl = $ENV{INET6TO4_LOOP};
+ if ($csl ne 'BG' && $csl ne '1') {
+ die "inet6to4: invalid INET6TO4_LOOP.\n";
+ }
+ if ($csl eq 'BG') {
+ # go into bg as "daemon":
+ setpgrp(0, 0);
+ my $pid = fork();
+ if (! defined $pid) {
+ die "inet6to4: $!\n";
+ } elsif ($pid) {
+ wait;
+ exit 0;
+ }
+ if (fork) {
+ exit 0;
+ }
+ setpgrp(0, 0);
+ close STDIN;
+ if (! $ENV{INET6TO4_LOGFILE}) {
+ close STDOUT;
+ close STDERR;
+ }
+ }
+ delete $ENV{INET6TO4_LOOP};
+
+ if (exists $ENV{INET6TO4_PIDFILE}) {
+ open_pidfile();
+ }
+
+ print STDERR "inet6to4: starting service at ", scalar(localtime), " master-pid=$$\n";
+ while (1) {
+ $looppid = fork;
+ if (! defined $looppid) {
+ sleep 10;
+ } elsif ($looppid) {
+ wait;
+ } else {
+ exec $0, @ARGV;
+ exit 1;
+ }
+ print STDERR "inet6to4: re-starting service at ", scalar(localtime), " master-pid=$$\n";
+ sleep 1;
+ }
+ exit 0;
+}
+if (exists $ENV{INET6TO4_PIDFILE}) {
+ open_pidfile();
+}
+
+use IO::Socket::INET6;
+use strict;
+use warnings;
+
+# some settings:
+#
+my $verbose = 1; # set to 0 for no messages, 2 for more.
+my $killpid = 1; # does kill(2) at end of connection.
+my $waittime = 0.25; # time to wait between connections.
+my $reverse = 0; # -r switch (or file named inet4to6)
+
+if (exists $ENV{INET6TO4_VERBOSE}) {
+ $verbose = $ENV{INET6TO4_VERBOSE};
+}
+if (exists $ENV{INET6TO4_WAITTIME}) {
+ $waittime = $ENV{INET6TO4_WAITTIME};
+}
+
+# process command line args:
+
+if (! @ARGV || $ARGV[0] =~ '^-+h') { # -help
+ open(ME, "<$0");
+ while (<ME>) {
+ last unless /^#/;
+ next if /usr.bin.perl/;
+ $_ =~ s/# ?//;
+ print;
+ }
+ exit;
+}
+
+if ($ARGV[0] eq '-r') { # -r
+ shift;
+ $reverse = 1;
+} elsif ($0 =~ /inet4to6$/) {
+ $reverse = 1;
+}
+
+my $listen_port = shift; # ipv6-listen-port
+my $connect_to = shift; # ipv4-host:port
+
+die "no listen port or connect-to-host:port\n" if ! $listen_port || ! $connect_to;
+
+# connect to host:
+#
+my $host = '';
+my $port = '';
+if ($connect_to =~ /^(.*):(\d+)$/) {
+ $host = $1;
+ $port = $2;
+}
+die "invalid connect-to-host:port\n" if ! $host || ! $port;
+
+setpgrp(0, 0);
+
+# create listening socket:
+#
+if (!$reverse) {
+ $listen_sock = IO::Socket::INET6->new(
+ Listen => 10,
+ LocalPort => $listen_port,
+ Domain => AF_INET6,
+ ReuseAddr => 1,
+ Proto => "tcp"
+ );
+} else {
+ $listen_sock = IO::Socket::INET->new(
+ Listen => 10,
+ LocalPort => $listen_port,
+ ReuseAddr => 1,
+ Proto => "tcp"
+ );
+}
+if (! $listen_sock) {
+ die "inet6to4: $!\n";
+}
+
+# for use by the xfer helper processes' interrupt handlers:
+#
+my $current_fh1 = '';
+my $current_fh2 = '';
+
+# connection counter:
+#
+my $conn = 0;
+
+# loop forever waiting for connections:
+#
+while (1) {
+ $conn++;
+ print STDERR "listening for connection: $conn\n" if $verbose;
+ my ($client, $ip) = $listen_sock->accept();
+
+ if ($client && !$reverse && $port == $listen_port) {
+ # This happens on Darwin 'tcp46'
+ if ($client->peerhost() =~ /^::ffff:/) {
+ print STDERR "closing client we think is actually us: ",
+ $client->peerhost(), "\n";
+ close $client;
+ $client = undef;
+ }
+ }
+ if (! $client) {
+ # to throttle runaways
+ fsleep(2 * $waittime);
+ next;
+ }
+ print STDERR "conn: $conn -- ", $client->peerhost(), " at ", scalar(localtime), "\n" if $verbose;
+
+ # spawn helper:
+ #
+ my $pid = fork();
+ if (! defined $pid) {
+ die "inet6to4: $!\n";
+ } elsif ($pid) {
+ wait;
+ # to throttle runaways
+ fsleep($waittime);
+ next;
+ } else {
+ # this is to avoid zombies:
+ close $listen_sock;
+ if (fork) {
+ exit 0;
+ }
+ setpgrp(0, 0);
+ handle_conn($client);
+ }
+}
+
+exit 0;
+
+sub handle_conn {
+ my $client = shift;
+
+ my $start = time();
+
+ print STDERR "connecting to: $host:$port\n" if $verbose;
+
+ my $sock = '';
+ if (!$reverse) {
+ $sock = IO::Socket::INET->new(
+ PeerAddr => $host,
+ PeerPort => $port,
+ Proto => "tcp"
+ );
+ } else {
+ $sock = IO::Socket::INET6->new(
+ PeerAddr => $host,
+ PeerPort => $port,
+ Domain => AF_INET6,
+ Proto => "tcp"
+ );
+ }
+
+ if (! $sock) {
+ close $client;
+ die "inet6to4: $!\n";
+ }
+
+ $current_fh1 = $client;
+ $current_fh2 = $sock;
+
+ # interrupt handler:
+ #
+ $SIG{TERM} = sub {print STDERR "got sigterm\[$$]\n" if $verbose; close $current_fh1; close $current_fh2; exit 0};
+
+ # spawn another helper and transfer the data:
+ #
+ my $parent = $$;
+ if (my $child = fork()) {
+ xfer($sock, $client, 'S->C');
+ if ($killpid) {
+ fsleep(0.5);
+ kill 'TERM', $child;
+ }
+ } else {
+ xfer($client, $sock, 'C->S');
+ if ($killpid) {
+ fsleep(0.75);
+ kill 'TERM', $parent;
+ }
+ }
+
+ # done.
+ #
+ if ($verbose > 1) {
+ my $dt = time() - $start;
+ print STDERR "dt\[$$]: $dt\n";
+ }
+ exit 0;
+}
+
+# transfers data in one direction:
+#
+sub xfer {
+ my($in, $out, $lab) = @_;
+ my ($RIN, $WIN, $EIN, $ROUT);
+ $RIN = $WIN = $EIN = "";
+ $ROUT = "";
+ vec($RIN, fileno($in), 1) = 1;
+ vec($WIN, fileno($in), 1) = 1;
+ $EIN = $RIN | $WIN;
+ my $buf;
+
+ while (1) {
+ my $nf = 0;
+ while (! $nf) {
+ $nf = select($ROUT=$RIN, undef, undef, undef);
+ }
+ my $len = sysread($in, $buf, 8192);
+ if (! defined($len)) {
+ next if $! =~ /^Interrupted/;
+ print STDERR "inet6to4\[$lab/$conn/$$]: $!\n";
+ last;
+ } elsif ($len == 0) {
+ print STDERR "inet6to4\[$lab/$conn/$$]: "
+ . "Input is EOF.\n";
+ last;
+ }
+
+ if ($verbose > 4) {
+ # verbose debugging of data:
+ syswrite(STDERR , "\n$lab: ", 6);
+ syswrite(STDERR , $buf, $len);
+ }
+
+ my $offset = 0;
+ my $quit = 0;
+ while ($len) {
+ my $written = syswrite($out, $buf, $len, $offset);
+ if (! defined $written) {
+ print STDERR "inet6to4\[$lab/$conn/$$]: "
+ . "Output is EOF. $!\n";
+ $quit = 1;
+ last;
+ }
+ $len -= $written;
+ $offset += $written;
+ }
+ last if $quit;
+ }
+ close($in);
+ close($out);
+}
+
+# sleep a fraction of a second:
+#
+sub fsleep {
+ my ($time) = @_;
+ select(undef, undef, undef, $time) if $time;
+}
diff --git a/x11vnc/misc/panner.pl b/x11vnc/misc/panner.pl
new file mode 100755
index 0000000..344beee
--- /dev/null
+++ b/x11vnc/misc/panner.pl
@@ -0,0 +1,117 @@
+#!/usr/bin/perl
+#
+# panner.pl: start up x11vnc in '-clip' mode viewing a small (WxH)
+# rectangular region of the screen. Allow the viewer user
+# to 'pan' around the display region by moving the mouse.
+#
+# Remote interaction with applications, e.g. clicking a
+# button though the VNC viewer, will be very difficult.
+# This may be useful in a 'demo' mode where the user sitting
+# at the physical display is the only one moving the mouse.
+# Depending on your usage the following x11vnc options may
+# be useful: -nonap
+#
+# Usage: panner.pl WxH <x11vnc-args> (e.g. -display ...)
+# or panner.pl WxH:0.05 <x11vnc-args> (e.g. 0.05 is polling time in secs.)
+
+use strict;
+
+my $WxH = shift;
+my $poll_time;
+
+# split off poll time:
+#
+($WxH, $poll_time) = split(/:/, $WxH);
+my ($W, $H) = split(/x/, $WxH);
+
+$poll_time = 0.1 unless $poll_time ne '';
+
+# set to x11vnc command (e.g. full PATH)
+#
+my $x11vnc = "x11vnc";
+
+# check if display was given:
+#
+my $query_args = "";
+for (my $i=0; $i < @ARGV; $i++) {
+ if ($ARGV[$i] eq '-display') {
+ $query_args = "-display $ARGV[$i+1]";
+ }
+}
+
+# find the size of display and the current mouse position:
+my %v;
+vset("DIRECT:wdpy_x,wdpy_y,pointer_x,pointer_y,pointer_same");
+
+# set a -clip argument based on the above:
+#
+my $clip = '';
+clip_set();
+$clip = "${W}x${H}+0+0" unless $v{pointer_same};
+
+# launch x11vnc with -clip in the background:
+#
+my $cmd = "$x11vnc -clip $clip -bg " . join(" ", @ARGV);
+print STDERR "running: $cmd\n";
+system $cmd;
+
+# user can hit Ctrl-C or kill this script to quit (and stop x11vnc)
+#
+sub quit {
+ system("$x11vnc $query_args -R stop");
+ exit 0;
+}
+
+$SIG{INT} = \&quit;
+$SIG{TERM} = \&quit;
+
+# loop forever waiting for mouse position to change, then shift -clip:
+#
+my $clip_old = $clip;
+while (1) {
+ fsleep($poll_time);
+ vset("pointer_x,pointer_y,pointer_same");
+ next unless $v{pointer_same};
+ clip_set();
+ if ($clip ne $clip_old) {
+ system("$x11vnc $query_args -R clip:$clip");
+ $clip_old = $clip
+ }
+}
+
+exit 0;
+
+# short sleep:
+#
+sub fsleep {
+ my ($time) = @_;
+ select(undef, undef, undef, $time) if $time;
+}
+
+# set the -clip string, making sure view doesn't go off edges of display:
+#
+sub clip_set {
+ my $x = int($v{pointer_x} - $W/2);
+ my $y = int($v{pointer_y} - $H/2);
+ $x = 0 if $x < 0;
+ $y = 0 if $y < 0;
+ $x = $v{wdpy_x} - $W if $x + $W > $v{wdpy_x};
+ $y = $v{wdpy_y} - $H if $y + $H > $v{wdpy_y};
+ $clip = "${W}x${H}+$x+$y";
+}
+
+# query x11vnc for values, put results in the %v hash:
+#
+sub vset {
+ my $str = shift;
+ my $out = `$x11vnc $query_args -Q $str 2>/dev/null`;
+ chomp $out;
+ foreach my $pair (split(/,/, $out)) {
+ $pair =~ s/^a..=//;
+ my ($k, $v) = split(/:/, $pair, 2);
+ if ($k ne '' && $v ne '') {
+ print STDERR "k=$k v=$v\n" if $ENV{DEBUG};
+ $v{$k} = $v;
+ }
+ }
+}
diff --git a/x11vnc/misc/ultravnc_repeater.pl b/x11vnc/misc/ultravnc_repeater.pl
index 40af575..a305ebe 100755
--- a/x11vnc/misc/ultravnc_repeater.pl
+++ b/x11vnc/misc/ultravnc_repeater.pl
@@ -1,6 +1,6 @@
#!/usr/bin/env perl
#
-# Copyright (c) 2009 by Karl J. Runge <runge@karlrunge.com>
+# Copyright (c) 2009-2010 by Karl J. Runge <runge@karlrunge.com>
#
# ultravnc_repeater.pl is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -41,17 +41,137 @@ usage: ultravnc_repeater.pl [-r] [client_port [server_port]]
Use -r to refuse new server/client connections with an existing
server/client ID. The default is to close the previous one.
+To write to a log file set the env. var ULTRAVNC_REPEATER_LOGFILE.
+
+To run in a loop restarting the server if it exits set the env. var.
+ULTRAVNC_REPEATER_LOOP=1 or ULTRAVNC_REPEATER_LOOP=BG, the latter
+forks into the background. Set ULTRAVNC_REPEATER_PIDFILE to a file
+to store the master pid in.
+
+
Examples:
+ ultravnc_repeater.pl
ultravnc_repeater.pl -r
ultravnc_repeater.pl 5901
ultravnc_repeater.pl 5901 5501
+ env ULTRAVNC_REPEATER_LOOP=BG ULTRAVNC_REPEATER_LOGFILE=/tmp/u.log ultravnc_repeater.pl ...
+
';
-use warnings;
use strict;
+# Set up logging:
+#
+if (exists $ENV{ULTRAVNC_REPEATER_LOGFILE}) {
+ close STDOUT;
+ if (!open(STDOUT, ">>$ENV{ULTRAVNC_REPEATER_LOGFILE}")) {
+ die "ultravnc_repeater.pl: $ENV{ULTRAVNC_REPEATER_LOGFILE} $!\n";
+ }
+ close STDERR;
+ open(STDERR, ">&STDOUT");
+}
+select(STDERR); $| = 1;
+select(STDOUT); $| = 1;
+
+# interrupt handler:
+#
+my $looppid = '';
+my $pidfile = '';
+#
+sub get_out {
+ print STDERR "$_[0]:\t$$ looppid=$looppid\n";
+ if ($looppid) {
+ kill 'TERM', $looppid;
+ fsleep(0.2);
+ }
+ unlink $pidfile if $pidfile;
+ cleanup();
+ exit 0;
+}
+
+# These are overridden in actual server thread:
+#
+$SIG{INT} = \&get_out;
+$SIG{TERM} = \&get_out;
+
+# pidfile:
+#
+sub open_pidfile {
+ if (exists $ENV{ULTRAVNC_REPEATER_PIDFILE}) {
+ my $pf = $ENV{ULTRAVNC_REPEATER_PIDFILE};
+ if (open(PID, ">$pf")) {
+ print PID "$$\n";
+ close PID;
+ $pidfile = $pf;
+ } else {
+ print STDERR "could not open pidfile: $pf - $! - continuing...\n";
+ }
+ delete $ENV{ULTRAVNC_REPEATER_PIDFILE};
+ }
+}
+
+####################################################################
+# Set ULTRAVNC_REPEATER_LOOP=1 to have this script create an outer loop
+# restarting itself if it ever exits. Set ULTRAVNC_REPEATER_LOOP=BG to
+# do this in the background as a daemon.
+
+if (exists $ENV{ULTRAVNC_REPEATER_LOOP}) {
+ my $csl = $ENV{ULTRAVNC_REPEATER_LOOP};
+ if ($csl ne 'BG' && $csl ne '1') {
+ die "ultravnc_repeater.pl: invalid ULTRAVNC_REPEATER_LOOP.\n";
+ }
+ if ($csl eq 'BG') {
+ # go into bg as "daemon":
+ setpgrp(0, 0);
+ my $pid = fork();
+ if (! defined $pid) {
+ die "ultravnc_repeater.pl: $!\n";
+ } elsif ($pid) {
+ wait;
+ exit 0;
+ }
+ if (fork) {
+ exit 0;
+ }
+ setpgrp(0, 0);
+ close STDIN;
+ if (! $ENV{ULTRAVNC_REPEATER_LOGFILE}) {
+ close STDOUT;
+ close STDERR;
+ }
+ }
+ delete $ENV{ULTRAVNC_REPEATER_LOOP};
+
+ if (exists $ENV{ULTRAVNC_REPEATER_PIDFILE}) {
+ open_pidfile();
+ }
+
+ print STDERR "ultravnc_repeater.pl: starting service at ", scalar(localtime), " master-pid=$$\n";
+ while (1) {
+ $looppid = fork;
+ if (! defined $looppid) {
+ sleep 10;
+ } elsif ($looppid) {
+ wait;
+ } else {
+ exec $0, @ARGV;
+ exit 1;
+ }
+ print STDERR "ultravnc_repeater.pl: re-starting service at ", scalar(localtime), " master-pid=$$\n";
+ sleep 1;
+ }
+ exit 0;
+}
+if (exists $ENV{ULTRAVNC_REPEATER_PIDFILE}) {
+ open_pidfile();
+}
+
+# End of background/daemon stuff.
+####################################################################
+
+use warnings;
use IO::Socket::INET;
use IO::Select;
@@ -85,6 +205,7 @@ my ($RIN, $WIN, $EIN, $ROUT);
my $client_listen = IO::Socket::INET->new(
Listen => 10,
LocalPort => $client_port,
+ ReuseAddr => 1,
Proto => "tcp"
);
if (! $client_listen) {
@@ -95,6 +216,7 @@ if (! $client_listen) {
my $server_listen = IO::Socket::INET->new(
Listen => 10,
LocalPort => $server_port,
+ ReuseAddr => 1,
Proto => "tcp"
);
if (! $server_listen) {
@@ -103,7 +225,7 @@ if (! $server_listen) {
}
my $select = new IO::Select();
-if (! select) {
+if (! $select) {
cleanup();
die "$prog: select $!\n";
}
@@ -120,9 +242,6 @@ my $CURR = '';
print "watching for connections on ports $server_port/server and $client_port/client\n";
-select(STDERR); $| = 1;
-select(STDOUT); $| = 1;
-
my $alarm_sock = '';
my $got_alarm = 0;
sub alarm_handler {