SSH

Create a VNC tunnel to work

Suppose your home and organization's network looks like this:

                               +-----Organization-Network----------+
                               |           |                       |
                   outside     |           |     inside            |
                   firewall -> |           | <- firewall           |
                               |           |                       |
 +------+                      |    +---------+   +---------+      |
 | home |-------Internet-------|    | SSH     |---| work    |      |
 | DSL  |                      |    | gateway |   | station |      |
 +------+                      |    +---------+   +---------+      |
                               |           |                       |
                               |           |                       |
                               |           | Internal              |
                               | DMZ       | network               |
                               +-----------+-----------------------+

The gateway runs SSH and is used as a hop to your workstation. I.e. you
login on the gateway machine and from there, you ssh to your workstation.

The command line enables many things but sometimes just ssh is not enough. You probably also want to connect to a port on your workstation for example to use VNC. The trick is to run a tunnel from your home machine through the login box to your workstation.

This is done with the -L option. The following example drops you into a shell on the gateway and tunnels all FTP traffic from localhost port 8021 to your workstation port 21:

  $ ssh username@gateway -L 8021:workstation:21

You can now test this by FTP'ing to localhost, port 8021

  $ ftp localhost 8021

Note that it's possible to start several tunnels at once with multiple -L options. To tunnel all FTP, POP3 and HTTP traffic, type:

  $ ssh username@gateway -L 8021:workstation:21 \
    -L 8023:workstation:23 \
    -L 8080:workstation:80

Two command-line options are useful in this context:

-N Tells the ssh client that this is a non-interactive shell
-f Tells the ssh client to fork itself into the background

Reverse throught the firewall

Suppose you are at work where outbound ssh traffic is allowed, but no facilities exist to connect from outside (say, home) to the inside.

One solution is to start a connection from the inside to home and tell ssh to start listening for connections back:

  work$ ssh -N -f -R 2222:localhost:22 home

When you come home, enter the following command to connect over the existing connection to work:

  home$ ssh -p 2222 localhost

If you don't want to leave the connection open indefinitely and use the bash shell, put the following lines in the .bashrc at home:

  WORK_IP="192.168.0.100"
  FROM=`echo $SSH_CLIENT | cut -f1 -d" "`
  case $FROM in
    *$WORK_IP)
       export TMOUT=600
       ;;
  esac

The variable TMOUT is important here; after 600 seconds, the bash shell detects inactivity and logs you out. However, the variable only gets set when logged in from work.

Login without a password

Steps to login without a password:

  1. Log into your account at box1.company.com
  2. Do cd .ssh
  3. Do files id_dsa and id_dsa.pub exist? (Can also be
    id_rsa and id_rsa.pub)
  1. Copy the public key to the other box, box2.company.com:
    scp id_dsa.pub user@box2:
  2. Log in on that machine:
    ssh user@box2
  3. Put the key in the list of keys that are authorized to log in here:
    cat id_dsa.pub >> .ssh/authorized_keys
    rm id_dsa.pub
  4. Log out and try again:
    ssh user@box2
    If everything went right, a prompt is presented without a request for a
    password.

If a password still is requested, check the permissions of the directory .ssh and the file authorized_keys. Both should have all bits for group and others turned off:

  box2$ chmod go-rwx .ssh
  box2$ chmod go-rwx .ssh/authorized_keys

Another problem could be that the sshd daemon was not configured for public/private key authentication. Check for the following line in /etc/ssh/sshd_config:

  PubkeyAuthentication yes

Automated logins

Sometimes it happens that you want to automate SSH logins to other machines for a user which doesn't have a (writeable) homedirectory. This can happen when using SSH from a script (Perl, PHP) which is run through Apache or some other web server.

One solution is to:

  /usr/bin/ssh -o UserKnownHostsFile=/var/www/private/known_hosts \
               -i /var/www/private/id_rsa user@remotemachine mycommand

Note: you could consider using /etc/ssh/ssh_known_hosts to store the public key of the remote machine. You can then omit the UserKnownHosts file.

To add to security, you can limit the commands executed on the remote machine. Log in to the remote machine and open up the .ssh/authorized_keys file (which you created in the above steps).

Then, before the created line, add the option

  command="mycommand"

but don't add a newline; just leave everything on one line. It'll look like something as follows:

  command="mycommand" ssh-rsa AAABBBBCCCDDDEEFFF....

There are lots of other options to be added, check the manual for this.

Using environment variables

SSH sets some environment variables when you use it to log in. The variable SSH_CONNECTION has the form "FROM_IP FROM_PORT TO_IP TO_PORT"

This can be used in scripts, for instance in .bashrc.

  # If we're logging in through SSH, write this down
  if [ -n "$SSH_CLIENT" ]; then
    LOGFILE=".ssh/.mylog"
  if [ -e $LOGFILE ]; then
    echo "`date`: SSH_CONNECTION $SSH_CONNECTION" >> $LOGFILE
  else
    echo "`date`: SSH_CONNECTION $SSH_CONNECTION" > $LOGFILE
  fi

We can also use this to determine where we're coming from, and based on that set alternative settings:

   # Alternative settings
   SRON0311="172.16.140.14"
   FROM=`echo $SSH_CLIENT | cut -f1 -d" "`
   case $FROM in
     *$SRON0311)
       export TMOUT=180 #Logout after 3 minutes
     ;;
   esac

Proxying

Besides tunneling each and every application, there's another way to pass traffic through a firewall or insecure network: SOCKS proxying. Note that the application in question has to support SOCKS, otherwise you're back to plain old tunneling.

To start a SOCKS proxy, start ssh as follows:

  $ ssh -D 1080 example.net

Now configure applications to use the SOCKS proxy on 127.0.0.1, port 1080. Firefox, Gaim, XChat and lots of other applications can use this type of proxy.

The SOCKS proxy in Firefox is configured through Preferences -> Advanced -> Network. Then select "manual proxy configuration", leave all fields empty except the SOCKS hostname and port number. If you fill in the other fields like HTTP proxy, the result will be a blank page (not even an error message) when you request a site. To tunnel DNS requests as well in Firefox, go to about:config and search for the option network.proxy.socks_remote_dns. Set this option to true.