Tunnelling outside firewalls with HTTP

I like working at the library downtown, but for us UNIX geeks their wifi is frustratingly locked down. No outgoing connections on port 22 are allowed, meaning you can’t just SSH to whatever server you’d like to work on. Happily, there are ways to tunnel traffic over other ports as HTTP packets and thus get around these restrictions. While it’s also possible to tunnel SSH through DNS, which tends to work many places where this approach doesn’t, using HTTP is simpler, faster (lower latency and higher bitrate), and doesn’t require having root on a server someplace (the daemon which runs outside the firewall can use a non-priviledged port and run in userspace, meaning you can run it on a shared shell server).

To do this, you’ll first need the package httptunnel, which includes both the server (hts) and client (htc). You need to find an open outgoing port, set up an instance of hts someplace on the internet which tunnels that port to the port you actually want to use, run an instance of htc on your laptop within the firewall which redirects a local port to the outside hts instance, then start your local networked program and point it to this local port on localhost.

For example, the library allows outgoing connections on port 8080. So, to connect via SSH, I run this on my machine at home:

$ hts --strict-content-length --max-connection-age 20000 --forward-port myhomemachine.org:22 8080

I then run the following on my laptop from inside the library:

$ htc --forward-port 2222 --strict-content-length --max-connection-age 2000 myhomemachine.org:8080

Once that’s set up, I can invoke ssh to log into myhomemachine.org:

$ ssh localhost -p 2222

This raises two questions: first, how do I know which ports are open? Second, do I really have to leave hts running at all times in case I happen to stop by the library?

The answer to the first is this outgoing port tester run by Marc Maurice, who has clearly run across this kind of problem in the past. His server will respond to TCP requests on all IPv4 TCP ports from 1 to 65535. To see if you’re able to make outgoing connections on a given port, you can use netcat:

$ nc -v portquiz.org 22

More simply, you could also do this wholesale with nmap:

$ nmap -v -p1-65535 portquiz.org

Running the latter from my library using the network BAnQ-Public network shows me that the following ports are open:

  • 80/tcp : HTTP
  • 443/tcp : HTTPS
  • 1720/tcp : H.323 call signalling

There’s actually another public network available at the library (and many city buildings) called MTLWiFi, which has the following ports open (although they note that they reserve the right to block SMTP):

  • 21/tcp : FTP
  • 25/tcp : SMTP
  • 53/tcp : DNS
  • 80/tcp : HTTP
  • 110/tcp : POP3
  • 143/tcp : IMAP
  • 443/tcp : HTTPS
  • 587/tcp : submission (secure SMTP)
  • 993/tcp : IMAPS
  • 8080/tcp : HTTP (alternate port)

(Notes are from Wikipedia’s list of TCP and UDP port numbers.)

In order to not leave hts running at all times, I wrote a small script which I can use to turn it on or off. It also lets me choose between a number of possible ports, in case I need to use it elsewhere or the library’s firewall configuration changes. I access this via HTTPS and start or stop my tunnel as needed, and problem solved!

Updated: