Tunnel Through a Firewall

Sometimes, it's handy to be able to connect to your home computer from work, or even possibly from an internet cafe; from a remote part of the world. In the old days, you might have set up your modem to answer after the 10th ring, and connect you at 300bps to your computer; nowadays, with DSL and broadband high-speed connections, you very likely have a firewall preventing any kind of inbound access. Sure, you could disable or "punch holes in" the firewall, but if you have access to a "server" already connected to the Internet, here's an alternative method that's more secure.

Steps

  1. On your GNU/Linux or Macintosh computer, add the following line to the end of your /etc/inittab file:
    • tunl:345:respawn:/usr/bin/ssh -n -N -T -R 6789:localhost:22 me@my.remote.server

      Replace 'me' with your username on the remote server, and 'my.remote.server' with the actual hostname or IP address of the server. If you have Windows, see Tips for suggestions.

      You have to have first established this connection "by hand", setting up shared-key authentication, in order for it to work unattended; if you can't type that same line starting with '/usr/bin/ssh' at the root command prompt and have it connect you to the remote server without any further input, this won't work.
  2. Restart the init process to activate the line you just added:

    # init q

  3. From work, or from any remote Internet location, try connecting to your computer via ssh.
    • It's a two-step process:

      $ ssh me@my.remote.server

    • Then, when connected:

      $ ssh -p 6789 home@localhost

      Replace 'home' in this example with your username on your home computer.

Tips

  • With Windows, you'll also need to install an SSH server in order to connect to it using this method. Cygwin, a free GNU layer for Windows, comes with sshd.
  • An alternate way of connecting in one step to the remote machine, without modifying the server setup:
    • ssh -t me@my.remote.server 'ssh -t -p 6789 home@localhost'
  • If your computer runs Windows rather than a Unix flavor, install an inexpensive router that can run OpenWRT, DD-WRT, or another similar free GNU/Linux variant, plugging it into your system between the DSL or cable modem and your computer(s). This method has an advantage even for Linux or Mac computers, as these routers are very energy-efficient: you can leave them on while you're gone, leaving the computer off; then start the computer on-demand using WOL (wake-on-lan). The inittab entry for OpenWRT will typically be

    ::respawn:/usr/bin/ssh -n -N -T -R 6789:localhost:22 me@my.remote.server

    (eliminating the first two fields of the entry)

    For this to work, you'll need to install openssh, replacing the dropbear package installed by default, and install wol. Once you've gained SSH access into the router, you then wake your computer with:

    # wol -v -p 9 00:11:22:33:44:55

    using, of course, your own PC's MAC address (which you've determined beforehand and encoded, with that command, into a script stored on the router).
  • Understanding the inittab entry:
    • init is the primary user-mode task on a Unix system, and inittab is the configuration file that tells it what to do.
    • tunl is simply a name, short for "tunnel", that indicates what this process is. It must be unique in the inittab file. If the tunnel isn't working, you might try shortening this to two letters, or, in the case of OpenWRT, getting rid of it altogether.
    • 345 the runlevels at which this process should be active; networking must be enabled in any case, so runlevel 3 (possibly 2) should be sufficient for the tunnel to be established. In the case of OpenWRT, this should probably be left out
    • respawn if the ssh tunnel breaks for whatever reason (routing problems, server down) you want it to reestablish itself automatically; "respawn" tells it to keep trying
  • Understanding the options given to the ssh tunnel process:
    • -n prevents reading from stdIn, used for background processes
    • -N tells ssh not to execute a remote command (primarily for port forwarding/tunneling)
    • -T disable pseudo-TTY allocation; may not be necessary but doesn't hurt
    • -R port:host:hostport port forwarding; 6789:localhost:22 means that, on the remote server, connecting to localhost:6789 actually connects you to port 22 (sshd) on the home computer.
  • If you want to be able to connect in one step to the internal machine, the inittab line should be slightly different:
    • tunl:345:respawn:/usr/bin/ssh -n -N -T -R 0:6789:localhost:22 me@my.remote.server
    • The "0:" before 6789 tells sshd to listen on all interfaces on the remote end, not just localhost
    • You will also need to change (or add) an option in the remote machine's sshd setup (/etc/ssh/sshd_config on Debian):
    • GatewayPorts clientspecified # is "no" by default
    • Then "hup" the server so it rereads the configuration:
    • kill -HUP $(</var/run/sshd.pid)
    • Then you connect in one step: ssh -p 6789 home@my.remote.server

Related Articles

Sources and Citations

  • This research was made possible, in part, by a land grant from the City of the Sun though the specifics of the research were not coordinated nor endorsed by COSF.