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 |
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.
Steps to login without 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
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.
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
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.