rvnc: Simple VNC-Proxy across masquerading firewalls

Christian A. Lademann cal "at" zls.de
Tue, 30 Jun 1998 19:26:51 +0000


Hi, VNC people.

Thank you very much for this great tool. It will be a revolution for
helpdesks all over the world (at least for me :-).

I have had a problem with connections from my workstation to a PC connected
to a customers LAN, because my firewall as well as the customers firewall
does IP-masquerading. This means that my workstation can only connect
to the customers firewall and the customers PC can only connect to my
firewall. The reason for this is, of course, to hide the complete LAN
behind the firewall(s).

My Workstation <-> My Firewall <-> WAN <-> Customers Firewall <-> Customers UNIX
                                                              <-> Customers PC1
                                                              <-> Customers PC2
                                                                  ...
                                                              <-> Customers PCn

I think I found a nice solution for that problem. It consists of two parts:

1. a slightly patched vncviewer to accept the option '-stdio': this
   option tells vncviewer to not connect to a vncserver via TCP/IP, but
   to read data from stdin and to write data to stdout.

2. a shellscript, rvnc, that resides on a UNIX-machine in the remote LAN, that
   has the 'nc'-Command ('netcat', <http://c0re.l0pht.com/~weld/netcat/>)
   installed.

   A well-known port on that machine is configured to accept requests from
   outside, via inetd. Of course, THIS single portnumber has to be configured
   in the firewall to be accessible from outside the firewall.

Now, rvnc is started on the local (my) side. It connects to the rvnc-port on
the remote UNIX-machine. The name and the displaynumber of the specific 
remote PC are exchanged using a simple protocol. The remote names have to be
resolvable and the remote PCs have to be accessible for the remote UNIX-machine
ONLY, there does NOT have to be an IP-route between the local (my) workstation
(which is another UNIX-machine, of course) and the remote PC!

Next, the remote rvnc-script connects its stdin and stdout to the vncserver-
port of the specified machine and the local rvnc-script starts the patched
vncviewer to accept RFB on its stdin and -out. Voila.



The same technique could be used to remote-administer customers PCs using a
dialup modem-connection to the customers UNIX-machine:

1. cu to the customers machine
2. log in
3. start rvnc and answer the questions (server, display)
4. connect the modem to your local 'vncviewer -stdio'
   Taylor-UUCP has such a cu-command.


Tell me, what you think.

Christian.
----------------------------------------------------------------------
Christian A. Lademann                              EMail: <cal "at" zls.de>
--------------------- speaking from, not for: ------------------------
    ZLS Software GmbH                         Tel.:  (+49) 6195 900500
     D-65779 Kelkheim                         Fax:   (+49) 6195 900600
----------------------------------------------------------------------
---( cut here )-------------------------------------------------------
diff -ruN vnc-3.3.2/vncviewer/args.c vnc-3.3.2-p/vncviewer/args.c
--- vnc-3.3.2/vncviewer/args.c	Tue May 12 16:17:39 1998
+++ vnc-3.3.2-p/vncviewer/args.c	Wed Jun 24 17:44:35 1998
@@ -72,6 +72,8 @@
 
 Bool debug = False;
 
+Bool stdioSpecified = False;
+
 
 void
 usage()
@@ -90,7 +92,8 @@
 	    "              [-passwd <passwd-file>]\n"
 	    "              [-period <ms>]\n"
 	    "              [-region <x> <y> <width> <height>]\n"
-	    "              [-rawdelay <ms>] [-copyrectdelay <ms>] [-debug]\n\n"
+	    "              [-rawdelay <ms>] [-copyrectdelay <ms>] [-debug]\n"
+		"              [-stdio]\n\n"
 	    ,programName,programName);
     exit(1);
 }
@@ -232,6 +235,11 @@
 		listenPort = CLIENTPORT+atoi(argv[i]);
 		flashPort = FLASHPORT+atoi(argv[i]);
 	    }
+
+	} else if (strcmp(argv[i],"-stdio") == 0) {
+
+	    stdioSpecified = True;
+	    argumentSpecified = True;
 
 	} else if (argv[i][0] != '-') {
 
diff -ruN vnc-3.3.2/vncviewer/sockets.c vnc-3.3.2-p/vncviewer/sockets.c
--- vnc-3.3.2/vncviewer/sockets.c	Thu Jan 15 19:21:00 1998
+++ vnc-3.3.2-p/vncviewer/sockets.c	Wed Jun 24 14:25:15 1998
@@ -44,6 +44,9 @@
     int i = 0;
     int j;
 
+	if(stdioSpecified)
+		sock = 0;
+
     while (i < n) {
 	j = read(sock, buf + i, (n - i));
 	if (j <= 0) {
@@ -74,6 +77,9 @@
 {
     int i = 0;
     int j;
+
+	if(stdioSpecified)
+		sock = 1;
 
     while (i < n) {
 	j = write(sock, buf + i, (n - i));
diff -ruN vnc-3.3.2/vncviewer/vncviewer.c vnc-3.3.2-p/vncviewer/vncviewer.c
--- vnc-3.3.2/vncviewer/vncviewer.c	Tue Mar 17 13:28:21 1998
+++ vnc-3.3.2-p/vncviewer/vncviewer.c	Wed Jun 24 14:24:16 1998
@@ -37,7 +37,7 @@
 	listenForIncomingConnections();
 	/* returns only with a succesful connection */
 
-    } else {
+    } else if (!stdioSpecified) {
 	if (!ConnectToRFBServer(hostname, port)) exit(1);
     }
 
diff -ruN vnc-3.3.2/vncviewer/vncviewer.h vnc-3.3.2-p/vncviewer/vncviewer.h
--- vnc-3.3.2/vncviewer/vncviewer.h	Tue May 12 14:51:04 1998
+++ vnc-3.3.2-p/vncviewer/vncviewer.h	Wed Jun 24 14:24:54 1998
@@ -77,6 +77,8 @@
 extern int copyRectDelay;
 extern Bool debug;
 
+extern Bool stdioSpecified;
+
 extern void processArgs(int argc, char **argv);
 extern void usage();
 
diff -ruN vnc-3.3.2/vncviewer/rvnc vnc-3.3.2-p/vncviewer/rvnc
--- vnc-3.3.2/vncviewer/rvnc	Thu Jan  1 01:00:00 1970
+++ vnc-3.3.2-p/vncviewer/rvnc	Wed Jun 24 18:24:52 1998
@@ -0,0 +1,162 @@
+#!/bin/sh
+
+#
+#  Copyright (C) 1998 Christian Lademann, ZLS Software GmbH <cal "at" zls.de>
+#
+#  This 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.
+#
+#  This software 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 this software; if not, write to the Free Software
+#  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
+#  USA.
+#
+
+VERSION="1.0.001"
+RVNC=${RVNC:-""}
+RVNCPORT=${RVNCPORT:-rvnc}
+NETCAT=${NETCAT:-/usr/bin/nc}
+VNCVIEWER=${VNCVIEWER:-/opt/vnc/vncviewer}
+VNCSERVERPORT=${VNCSERVERPORT:-5900}
+
+IFS=`echo -n " \r\n\t"`
+OFS=" "
+
+usage () {
+	echo "usage: rvnc [options] host [port] establish connection to remote VNC proxyserver"
+    echo "       options: -s server         name of VNC server"
+    echo "                -d display        display number"
+    echo "                -v options        vncviewer options"
+    echo "                -V                show version of rvnc"
+    echo "                -h                this help"
+    echo
+    echo "   or: rvnc -server               remote VNC proxyserver to be started by inetd"
+	exit 1
+}
+
+
+if [ "$1" = "-server" ]; then
+	echo "MESSAGE Welcome to the Remote VNC Proxyserver on `hostname`"
+	echo "MESSAGE"
+	echo "QUESTION SERVER Enter Servername:"
+	read Server
+
+	Display=""
+
+	case "$Server" in
+	*:* )
+		set -- `echo $Server | tr ":" " "`
+
+		Server=$1
+		Display=$2
+	;;
+	esac
+
+	if [ ! "$Display" ]; then
+		echo "QUESTION DISPLAY Enter Displaynumber:"
+		read Display
+	fi
+
+	Port=`expr $VNCSERVERPORT + $Display`
+
+	echo "START VNCVIEWER"
+
+	eval "exec $NETCAT -w 4 $Server $Port"
+elif [ "$1" = "-h" ]; then
+	usage;
+elif [ "$RVNC" = "RVNC" ]; then
+	while true; do
+		read Line
+
+		case "$Line" in
+		START* )
+			break
+		;;
+
+		QUIT* )
+			exit 1
+		;;
+
+		MESSAGE* )
+			set -- $Line
+			shift
+			echo "$*" > /dev/tty
+		;;
+
+		QUESTION* )
+			set -- $Line
+
+			Question=$2
+
+			shift
+			shift
+
+			Answer=""
+			case "$Question" in
+			SERVER )	
+				if [ "$RVNCSERVER" ]; then
+					Answer=$RVNCSERVER
+				fi
+			;;
+
+			DISPLAY )	
+				if [ "$RVNCDISPLAY" ]; then
+					Answer=$RVNCDISPLAY
+				fi
+			;;
+			esac
+
+			if [ ! "$Answer" ]; then
+				echo -n "$* " > /dev/tty
+				read Answer < /dev/tty
+			fi
+
+			echo "$Answer"
+		;;
+		esac
+	done
+
+	eval "exec $VNCVIEWER $RVNCOPTIONS -stdio 2>/dev/tty"
+else
+	if [ $# -lt 1 ]; then
+		usage;
+	fi
+
+	RVNCSERVER=""
+	RVNCDISPLAY=""
+	RVNCOPTIONS=""
+
+	while true; do
+		case "$1" in
+		-s )	RVNCSERVER=$2; shift; shift;;
+		-d )	RVNCDISPLAY=$2; shift; shift;;
+		-v )	RVNCOPTIONS="$RVNCOPTIONS $2"; shift; shift;;
+		-V* )	echo "rvnc version $VERSION"; exit 0;;
+        -h* )	usage;;
+		-- )	break;;
+		-* )	usage;;
+		* )		break;;
+		esac
+	done
+
+	host=$1
+
+	if [ $# -gt 1 ]; then
+		port=$2
+	else
+		port=$RVNCPORT
+	fi
+
+	export RVNCSERVER
+	export RVNCDISPLAY
+	export RVNCOPTIONS
+	RVNC="RVNC"; export RVNC
+	eval "exec $NETCAT -e $0 $host $port"
+fi
---( cut here )-------------------------------------------------------

---------------------------------------------------------------------
The VNC mailing list     -   see http://www.orl.co.uk/vnc/intouch.html
---------------------------------------------------------------------