summaryrefslogtreecommitdiffstats
path: root/x11vnc/misc/connect_switch
diff options
context:
space:
mode:
Diffstat (limited to 'x11vnc/misc/connect_switch')
-rwxr-xr-xx11vnc/misc/connect_switch696
1 files changed, 0 insertions, 696 deletions
diff --git a/x11vnc/misc/connect_switch b/x11vnc/misc/connect_switch
deleted file mode 100755
index 08376c6..0000000
--- a/x11vnc/misc/connect_switch
+++ /dev/null
@@ -1,696 +0,0 @@
-#!/usr/bin/perl
-#
-# 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
-# the Free Software Foundation; either version 2 of the License, or (at
-# your option) any later version.
-#
-# connect_switch 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 connect_switch; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA
-# or see <http://www.gnu.org/licenses/>.
-#
-#
-# connect_switch:
-#
-# A kludge script that sits between web clients and a mod_ssl (https)
-# enabled apache webserver.
-#
-# If an incoming web client connection makes a proxy CONNECT request
-# it is handled directly by this script (apache is not involved).
-# Otherwise, all other connections are forwarded to the apache webserver.
-#
-# This can be useful for VNC redirection using an existing https (port
-# 443) webserver, thereby not requiring a 2nd (non-https) port open on
-# the firewall for the CONNECT requests.
-#
-# It does not seem possible (to me) to achieve this entirely within apache
-# 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
-# simplest case you change something like this:
-#
-# From:
-#
-# Listen 443
-#
-# <VirtualHost _default_:443>
-# ...
-# </VirtualHost>
-#
-# To:
-#
-# Listen 127.0.0.1:443
-#
-# <VirtualHost _default_:443>
-# ...
-# </VirtualHost>
-#
-# (i.e. just change the Listen directive).
-#
-# If you have mod_ssl listening on a different internal port, you do
-# not need to specify the localhost Listen address.
-#
-# 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();
-}
-
-
-############################################################################
-# The defaults for hosts and ports (you can override them below if needed):
-#
-# Look below for these environment variables that let you set the various
-# parameters without needing to edit this script:
-#
-# CONNECT_SWITCH_LISTEN
-# CONNECT_SWITCH_HTTPD
-# CONNECT_SWITCH_ALLOWED
-# CONNECT_SWITCH_ALLOW_FILE
-# 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
-# CONNECT_SWITCH_MAX_CONNECTIONS
-#
-# 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 = '';
- if ($ENV{CONNECT_SWITCH_LISTEN} =~ /^(.*):(\d+)$/) {
- ($listen_host, $listen_port) = ($1, $2);
- }
-}
-
-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 = '';
- if ($ENV{CONNECT_SWITCH_HTTPD} =~ /^(.*):(\d+)$/) {
- ($httpd_host, $httpd_port) = ($1, $2);
- }
-}
-
-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:
-#
-#$listen_host = '23.45.67.89'; # set to your interface IP number.
-#$listen_port = 555; # and/or nonstandard port.
-#$httpd_host = 'somehost'; # maybe you redir https to another machine.
-#$httpd_port = 666; # and/or nonstandard port.
-
-# 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
- machine2:5900
-);
-
-if (exists $ENV{CONNECT_SWITCH_ALLOWED}) {
- #
- # E.g. CONNECT_SWITCH_ALLOWED=machine1:5915,machine2:5900
- #
- @allowed = split(/,/, $ENV{CONNECT_SWITCH_ALLOWED});
-}
-
-# Or you could also use an external "allow file".
-# They get added to the @allowed list.
-# The file is re-read for each new connection.
-#
-# Format of $allow_file:
-#
-# host1 vncdisp
-# host2 vncdisp
-#
-# where, e.g. vncdisp = 15 => port 5915, say
-#
-# joesbox 15
-# fredsbox 15
-# rupert 1
-
-# For examply, mine is:
-#
-my $allow_file = '/dist/apache/2.0/conf/vnc.hosts';
-$allow_file = '';
-
-if (exists $ENV{CONNECT_SWITCH_ALLOW_FILE}) {
- # E.g. CONNECT_SWITCH_ALLOW_FILE=/usr/local/etc/allow.txt
- $allow_file = $ENV{CONNECT_SWITCH_ALLOW_FILE};
-}
-
-# Set to 1 to re-map to vnc port, e.g. 'hostname 15' to 'hostname 5915'
-# i.e. assume a port 0 <= port < 200 is actually a VNC display
-# and add 5900 to it. Set to 0 to not do the mapping.
-# Note that negative ports, e.g. 'joesbox -22' go directly to -port.
-#
-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 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};
-}
-
-# zero means loop forever, positive value means exit after handling that
-# many connections.
-#
-my $cmax = 0;
-if (exists $ENV{CONNECT_SWITCH_MAX_CONNECTIONS}) {
- $cmax = $ENV{CONNECT_SWITCH_MAX_CONNECTIONS};
-}
-
-
-#===========================================================================
-# No need for any changes below here.
-#===========================================================================
-
-use IO::Socket::INET;
-use strict;
-use warnings;
-
-# Test for INET6 support:
-#
-my $have_inet6 = 0;
-eval "use IO::Socket::INET6;";
-$have_inet6 = 1 if $@ eq "";
-
-my $killpid = 1;
-
-setpgrp(0, 0);
-
-if (exists $ENV{CONNECT_SWITCH_LISTEN_IPV6}) {
- # note we leave out LocalAddr.
- my $cmd = '
- $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";
-}
-
-my $current_fh1 = '';
-my $current_fh2 = '';
-
-my $conn = 0;
-
-while (1) {
- $conn++;
- if ($cmax > 0 && $conn > $cmax) {
- print STDERR "last connection ($cmax)\n" if $verbose;
- last;
- }
- print STDERR "listening for connection: $conn\n" if $verbose;
- my ($client, $ip) = $listen_sock->accept();
- if (! $client) {
- fsleep(0.5);
- next;
- }
- print STDERR "conn: $conn -- ", $client->peerhost(), " at ", scalar(localtime), "\n" if $verbose;
-
- my $pid = fork();
- if (! defined $pid) {
- die "connect_switch: $!\n";
- } elsif ($pid) {
- wait;
- next;
- } else {
- close $listen_sock;
- if (fork) {
- exit 0;
- }
- setpgrp(0, 0);
- handle_conn($client);
- }
-}
-
-exit 0;
-
-sub handle_conn {
- my $client = shift;
-
- my $start = time();
-
- 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>) {
- next if /^\s*#/;
- next if /^\s*$/;
- chomp;
- my ($host, $dpy) = split(' ', $_);
- next if ! defined $host;
- next if ! defined $dpy;
- if ($dpy < 0) {
- $dpy = -$dpy;
- } elsif ($apply_vnc_offset) {
- $dpy += $vnc_offset if $dpy < 200;
- }
- push @allow, "$host:$dpy";
- }
- close(ALLOW);
- } else {
- warn "$allow_file: $!\n";
- }
- }
-
- # Read the first 7 bytes of connection, see if it is 'CONNECT'
- #
- my $str = '';
- my $N = 0;
- my $isconn = 1;
- for (my $i = 0; $i < 7; $i++) {
- my $b;
- sysread($client, $b, 1);
- $str .= $b;
- $N++;
- print STDERR "read: '$str'\n" if $verbose > 1;
- my $cstr = substr('CONNECT', 0, $i+1);
- if ($str ne $cstr) {
- $isconn = 0;
- last;
- }
- }
-
- 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 > 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;
- my $h = '';
- my $p = '';
-
- if ($hostport =~ /^(.*):(\d+)$/) {
- ($h, $p) = ($1, $2);
- }
- 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;
- }
-
- my $host = '';
- my $port = '';
-
- if ($hostport =~ /^(.*):(\d+)$/) {
- ($host, $port) = ($1, $2);
- }
-
- print STDERR "connecting to: $host:$port\n" if $verbose;
-
- $sock = IO::Socket::INET->new(
- PeerAddr => $host,
- PeerPort => $port,
- Proto => "tcp"
- );
- print STDERR "connect to host='$host' port='$port' failed: $!\n" if !$sock;
- if (! $sock && $have_inet6) {
- eval {$sock = IO::Socket::INET6->new(
- PeerAddr => $host,
- PeerPort => $port,
- Proto => "tcp"
- );};
- print STDERR "connect to host='$host' port='$port' failed: $! (ipv6)\n" if !$sock;
- }
- my $msg;
-
- # send the connect proxy reply:
- #
- if ($sock) {
- $msg = $msg_1;
- } else {
- $msg = $msg_2;
- }
- syswrite($client, $msg, length($msg));
- $str = '';
- } else {
- # 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,
- Proto => "tcp"
- );
- if (! $sock && $have_inet6) {
- eval {$sock = IO::Socket::INET6->new(
- PeerAddr => $httpd_host,
- PeerPort => $httpd_port,
- Proto => "tcp"
- );};
- }
- }
-
- if (! $sock) {
- close $client;
- die "connect_switch: $!\n";
- }
-
- # get ready for xfer phase:
- #
- $current_fh1 = $client;
- $current_fh2 = $sock;
-
- $SIG{TERM} = sub {print STDERR "got sigterm\[$$]\n" if $verbose; close $current_fh1; close $current_fh2; exit 0};
-
- my $parent = $$;
- if (my $child = fork()) {
- xfer($sock, $client, 'S->C');
- if ($killpid) {
- fsleep(0.5);
- kill 'TERM', $child;
- }
- } else {
- # write those first bytes if not CONNECT:
- #
- if ($str ne '' && $N > 0) {
- syswrite($sock, $str, $N);
- }
- xfer($client, $sock, 'C->S');
- if ($killpid) {
- fsleep(0.75);
- kill 'TERM', $parent;
- }
- }
- if ($verbose > 1) {
- my $dt = time() - $start;
- print STDERR "duration\[$$]: $dt seconds. ", scalar(localtime), "\n";
- }
- exit 0;
-}
-
-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, $bufsize);
- if (! defined($len)) {
- next if $! =~ /^Interrupted/;
- print STDERR "connect_switch\[$lab/$conn/$$]: $!\n";
- last;
- } elsif ($len == 0) {
- print STDERR "connect_switch\[$lab/$conn/$$]: "
- . "Input is EOF.\n";
- last;
- }
-
- if (0) {
- # very 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 "connect_switch\[$lab/$conn/$$]: "
- . "Output is EOF. $!\n";
- $quit = 1;
- last;
- }
- $len -= $written;
- $offset += $written;
- }
- last if $quit;
- }
- close($in);
- close($out);
-}
-
-sub fsleep {
- my ($time) = @_;
- select(undef, undef, undef, $time) if $time;
-}
OpenPOWER on IntegriCloud