VNC port forwarding with ssh: HOWTO

2/4/2003

This HOWTO addresses using VNC with port forwarding. It is a working example of how I've done it.


Introduction

This diagram shows my setup. It should be general enough to allow any setup to be created with this as a guide.

Once this setup is clear, then do see VNC ssh HOWTO to get an idea of some of the very many options, including MSwindoze options, that may be used.

Background:

VNC is an appealing solution to a few problems.

  • It is a cheap and good MSwindoze X server
  • It allows one to export a MSwindoze desktop to another machine
  • It provides remote X session capability with acceptable performance over modem/adsl links.

    I want to run a vncviewer on MyBox under linux, to a linux vncserver on lin.perth and to a MSwindoze vncserver on win.perth.

    I show the trivial case of win.perth displaying the desktop of lin.perth

    I show the trivial case of lin.perth displaying the desktop of win.perth

    Setup of lin.perth

    Install VNC server

    This machine is setup in run level 5, running a DisplayManager (but a local X display or login is optional. I use gdm and the gdmsetup is a nice graphical tool to setup the local DisplayManager. XDMCP must be allowed and enabled.

    Add this line(s) to /etc/services. Multiple ports may be allocated for different resolutions, eg my two ports.

    vnc		5950/tcp			# 1010x740 vnc
    vncs		5951/tcp			# 800x600  vnc
    

    This is the corresponding /etc/xinetd.d entry for service vnc

    service vnc
    {
    	disable	= no
    	socket_type     = stream
    	wait            = no
    	user            = nobody
    	server          = /usr/bin/Xvnc
    	server_args     = -inetd -broadcast -once -geometry 1010x740 -depth 16
    	log_on_failure  += USERID
    }
    

    The broadcast flag will find any vncserver, you may want to -query localhost instead.

    Setup of win.perth

    Install the VNC MSwindoze server and viewer. I added a desktop icon for the viewer, and ran the server as a start-time-program.

    Setup of svr.com

    Run a firewall with masquerading. I found an iptables howto with this stronger iptables configuration. Sorry I can't acknowledge it, I don't know where I got it from. iptables.conf

    Redhat users: service iptables save
    will setup the tables firewall so it can be restarted each boot.
    This script firewalls the server to allow incoming http, mail and ssh.

    Setup of MyServer

    Run a firewall with masquerading. iptables.conf

    Setup of MyBox

    Install the VNC viewer.

    win.perth's desktop viewed on lin.perth

    On an X-desktop on lin: vncviewer win.perth:0

    lin.perth's desktop viewed on win.perth

    Click to VNCviewer icon (or run the viewer)
    connect to lin.perth:50
    I chose to have a login session, and this is what lin.perth's setup is all about. You can chose to run vncserver on lin.perth using any port, connect and retain a persistent desktop, from any connection.

    lin.perth's desktop viewed on MyBox

    At last the interesting bit.

    On MyBox ssh to svr.perth with port forwarding.

        ssh -C -g -L 5910:lin.perth:5950 svr.com
    

    This forwards an arbitrary unused port, 5910, to the remote 1024x768 display login on port 5950.

    Now connect

        vncviewer localhost:5910
    

    which runs the viewer on the local machine, tunneled to the remote machine.
    See the VNC docs for details on this option for slow links

        -encodings "copyrect hextile"
    

    win.perth's desktop viewed on MyBox

    On MyBox ssh to svr.perth with port forwarding.

        ssh -C -g -L 5910:win.perth:5900 svr.com
    

    This forwards an arbitrary unused port, 5910, to the remote normal desktop on port 5900.

    Now connect

        vncviewer localhost:5910
    

    which runs the viewer on the local machine, tunneled to the remote machine.
    Again the VNC howto shows many options, including the case where MyBox is a MSwindoze machine.

    other options

    Do the port forwarding on MyServer and then linux and MSwindoze viewers can connect to MyServer:port without any further ado.

        On MyServer
        ssh -C -g -L 5910:win.perth:5900 svr.com
    
        On MyLinux
        vncviewer MyServer:10
    
        On MyMSwindoze
        vncviewer MyServer:10
    

    A sample iptables setup

    
    #!/bin/sh
    #
    FWVER=0.73s
    
    echo -e "\nLoading STRONGER rc.firewall - version $FWVER..\n"
    
    # The location of various iptables and other shell programs
    #
    IPTABLES=/sbin/iptables
    LSMOD=/sbin/lsmod
    DEPMOD=/sbin/depmod
    INSMOD=/sbin/insmod
    GREP=/bin/grep
    AWK=/bin/awk
    SED=/bin/sed
    IFCONFIG=/sbin/ifconfig
    
    
    #Setting the EXTERNAL and INTERNAL interfaces for the network
    EXTIF="eth1"
    INTIF="eth0"
    echo "  External Interface:  $EXTIF"
    echo "  Internal Interface:  $INTIF"
    echo "  ---"
    
    # Specify your Static IP address here or let the script take care of it 
    # for you.
    #EXTIP="`$IFCONFIG $EXTIF | $GREP 'inet addr' | $AWK '{print $2}' | \
    #$SED -e 's/.*://'`"
    
    # For users who wish to use STATIC IP addresses:
    EXTIP="202.71.175.58"
    echo "  External IP: $EXTIP"
    echo "  ---"
    
    
    # Assign the internal TCP/IP network and IP address
    INTNET="192.168.1.0/24"
    INTIP="192.168.1.254/24"
    echo "  Internal Network: $INTNET"
    echo "  Internal IP:      $INTIP"
    echo "  ---"
    
    # Setting a few other local variables
    UNIVERSE="0.0.0.0/0"
    
    #======================================================================
    # Need to verify that all modules have all required dependencies
    echo "  - Verifying that all kernel modules are ok"
    $DEPMOD -a
    echo -en "    Loading kernel modules: "
    
    echo -en "ip_tables, "
    if [ -z "` $LSMOD | $GREP ip_tables | $AWK {'print $1'} `" ]; then
       $INSMOD ip_tables
    fi
    echo -en "ip_conntrack, "
    if [ -z "` $LSMOD | $GREP ip_conntrack | $AWK {'print $1'} `" ]; then
       $INSMOD ip_conntrack
    fi
    echo -e "ip_conntrack_ftp, "
    if [ -z "` $LSMOD | $GREP ip_conntrack_ftp | $AWK {'print $1'} `" ]; then
       $INSMOD ip_conntrack_ftp
    fi
    echo -en "                             ip_conntrack_irc, "
    if [ -z "` $LSMOD | $GREP ip_conntrack_irc | $AWK {'print $1'} `" ]; then
       $INSMOD ip_conntrack_irc
    fi
    echo -en "iptable_nat, "
    #
    if [ -z "` $LSMOD | $GREP iptable_nat | $AWK {'print $1'} `" ]; then
       $INSMOD iptable_nat
    fi
    echo -e "ip_nat_ftp"
    if [ -z "` $LSMOD | $GREP ip_nat_ftp | $AWK {'print $1'} `" ]; then
       $INSMOD ip_nat_ftp
    fi
    
    echo "  ---"
    
    #CRITICAL:  Enable IP forwarding since it is disabled by default since
    echo "  Enabling forwarding.."
    echo "1" > /proc/sys/net/ipv4/ip_forward
    
    #Clearing any previous configuration
    echo "  Clearing any existing rules and setting default policy to DROP.."
    $IPTABLES -P INPUT DROP  
    $IPTABLES -F INPUT 
    $IPTABLES -P OUTPUT DROP  
    $IPTABLES -F OUTPUT 
    $IPTABLES -P FORWARD DROP  
    $IPTABLES -F FORWARD 
    $IPTABLES -F -t nat
    
    # Flush the user chain.. if it exists
    if [ -n "`$IPTABLES -L | $GREP drop-and-log-it`" ]; then
       $IPTABLES -F drop-and-log-it
    fi
    # Delete all User-specified chains
    $IPTABLES -X
    # Reset all IPTABLES counters
    $IPTABLES -Z
    
    
    #echo "  Creating a DROP chain.."
    #$IPTABLES -N drop-and-log-it
    #$IPTABLES -A drop-and-log-it -j LOG --log-level info 
    #$IPTABLES -A drop-and-log-it -j DROP
    
    echo -e "\n   - Loading INPUT rulesets"
    
    
    #######################################################################
    # loopback interfaces are valid.
    $IPTABLES -A INPUT -i lo -s $UNIVERSE -d $UNIVERSE -j ACCEPT
    
    # local interface, local machines, going anywhere is valid
    $IPTABLES -A INPUT -i $INTIF -s $INTNET -d $UNIVERSE -j ACCEPT
    
    # remote interface, claiming to be local machines, IP spoofing, get lost
    $IPTABLES -A INPUT -i $EXTIF -s $INTNET -d $UNIVERSE -j DROP
    
    # external interface, from any source, for ICMP traffic is valid
    $IPTABLES -A INPUT -i $EXTIF -p ICMP -s $UNIVERSE -d $EXTIP -j ACCEPT
    
    # Allow any related traffic coming back to the MASQ server in
    $IPTABLES -A INPUT -i $EXTIF -s $UNIVERSE -d $EXTIP -m state --state \
    ESTABLISHED,RELATED -j ACCEPT
    
    # ----- Begin OPTIONAL Section -----
    
    echo -e "      - Allowing EXTERNAL access to the WWW server"
    $IPTABLES -A INPUT --protocol tcp --dport 80 -j ACCEPT
    $IPTABLES -A INPUT --protocol tcp --dport 443 -j ACCEPT
    
    echo -e "      - Allowing EXTERNAL access to the Mail server"
    $IPTABLES -A INPUT --protocol tcp --dport 25 -j ACCEPT
    
    echo -e "      - Allowing EXTERNAL access to the SSH server"
    $IPTABLES -A INPUT --protocol tcp --dport 22 -j ACCEPT
    
    # ----- End OPTIONAL Section -----
    
    # Catch all rule, all other incoming is denied and logged. 
    $IPTABLES -A INPUT -s $UNIVERSE -d $UNIVERSE -j DROP
    
    
    #######################################################################
    echo -e "   - Loading OUTPUT rulesets"
    # loopback interface is valid.
    $IPTABLES -A OUTPUT -o lo -s $UNIVERSE -d $UNIVERSE -j ACCEPT
    
    # local interfaces, any source going to local net is valid
    $IPTABLES -A OUTPUT -o $INTIF -s $EXTIP -d $INTNET -j ACCEPT
    
    # local interface, any source going to local net is valid
    $IPTABLES -A OUTPUT -o $INTIF -s $INTIP -d $INTNET -j ACCEPT
    
    # outgoing to local net on remote interface, stuffed routing, deny
    $IPTABLES -A OUTPUT -o $EXTIF -s $UNIVERSE -d $INTNET -j DROP
    
    # anything else outgoing on remote interface is valid
    $IPTABLES -A OUTPUT -o $EXTIF -s $EXTIP -d $UNIVERSE -j ACCEPT
    
    
    # Catch all rule, all other outgoing is denied and logged. 
    $IPTABLES -A OUTPUT -s $UNIVERSE -d $UNIVERSE -j DROP
    
    
    #######################################################################
    echo -e "   - Loading FORWARD rulesets"
    echo "     - FWD: Allow all connections OUT and only existing/related IN"
    $IPTABLES -A FORWARD -i $EXTIF -o $INTIF -m state --state ESTABLISHED,RELATED \
    -j ACCEPT
    $IPTABLES -A FORWARD -i $INTIF -o $EXTIF -j ACCEPT
    
    # Catch all rule, all other forwarding is denied and logged. 
    $IPTABLES -A FORWARD -j DROP
    
    echo "     - NAT: Enabling SNAT (MASQUERADE) functionality on $EXTIF"
    #More liberal form
    #$IPTABLES -t nat -A POSTROUTING -o $EXTIF -j MASQUERADE
    #Stricter form
    $IPTABLES -t nat -A POSTROUTING -o $EXTIF -j SNAT --to $EXTIP
    
    #######################################################################
    echo -e "\nDone.\n"