Reading Your Email in Private on a Public Network


I have been using an ssh tunnel to access my home network over wireless for some time now. This is useful any time that I want to read my email on the road, and not potentially have everybody else in the room reading it, too. An ssh tunnel can also be used to access ports on remote machines that a firewall might normally restrict you from accessing. If that firewall allows traffic out port 22 (ssh), and most seem to, then you can tunnel the traffic to the restricted port through port 22. Or suppose for some reason you don't want anybody snooping on your web traffic. You can encrypt that traffic by tunneling it over ssh to a server that you control, or at least have an account on. There are lots of reasons to use an ssh tunnel, and I'm only mentioning these here as a quick overview.

The main reason for this page is to give a few hints on one particular method of setting up an ssh tunnel. There is more than one way to achieve tunneled traffic. The two that I have experience with are ssh port forwarding and ssh SOCKS proxy. Recently, I switched from using port forwarding to using a SOCKS proxy, and I managed to find a few pitfalls along the way. I'm making note here of how I got around those in case it might be of help to others who happen to enter the correct Google search terms.

I have been tunneling my traffic using ssh for a period of several years now. I was originally using the port forwarding method. In all examples from now on, my local machine is assumed to be a laptop running Linux, and the other end of the tunnel is my server at home, which runs OpenBSD. The traffic I want to send will go through the tunnel from the laptop to the OpenBSD server, and be resent by the ssh daemon running on the server. If I'm accessing a website, all traffic will appear to that web server to originate from the IP address of my OpenBSD server. The port forwarding required is accomplished by using the "-L" switch to the ssh program to set up a local port forward. In order to read email securely, I forwarded local port 5110 to port 110 on my mail server. I could then access localhost:5110 from my mail program in order to read my mail. The traffic would be encrypted between my mail server and laptop. In a similar fashion, I forwarded local port 8128 to port 3128 on my server. On the server, I ran a Squid web proxy on port 3128. The command I used to set this up was invoked on my laptop, and looked like this:

   "ssh -2 -q -N -f -L5110:localhost:110 -L8128:localhost:3128 servername &"

This left me with an ssh process running on each end of the tunnel that knew how to connect the ports I wanted together. For this to work, I had to set ssh up properly beforehand so that the login would be done using dsa keys rather than plain text passwords. This is a good idea anyway, you should consult the ssh man pages and/or the interet for the details. I used this method of ssh tunneling for several years.

The reason I stopped doing it this way was that I became aware that ssh could operate as a SOCKS proxy server. This has several advantages for me. One is that I don't need to forward N different ports in order to encrypt/tunnel N different protocols. If the application or protocol understands how to use a SOCKS proxy, the traffic can go through an existing SOCKS tunnel. The other advantage is that it allowed me to stop using the Squid web caching proxy, which had been aggravating me for some time. Both Firefox and Thunderbird understand how to work with a SOCKS proxy, and so I went ahead and changed my tunnelling methodology. In the process, I had a few issues with both the client setup (Thunderbird and Firefox) and some nuances of the packet filter and Postfix mail server setup on my OpenBSD server.

In order to use ssh as a SOCKS proxy, you need to use the "-P" switch. The command I use looks like this:

   "ssh -2 -q -ND 1080 servername &"

After this command is invoked, any traffic sent to port 1080 on the local machine will fall out the tunnel at the other end into the arms of the ssh daemon running there, which knows that it is serving as a SOCKS proxy. It will examine the traffic and figure out the right thing to do with it, like magic. It really works. Now all that is left to do is configure your client applications (email and web browser for this example) and then go over a few pitfalls.

To configure Firefox to use the new proxy, open the Edit/Preferences/Advanced/Network tab, then click the "Settings" button. Select "Manual Proxy Configuration". On the line that says "SOCKS Host:", type "localhost" (no quotes). For the "Port" setting, choose the port where you are running the proxy on your local machine, in the example given above, it was port 1080. Just below that line, select "SOCKSv5". On the line that says "No Proxy for:", put "localhost" at a minimum (no quotes). Depending on your situation, you might add more hosts on your local network. But any traffic to hosts listed on this line won't be encrypted, so be careful! This was my first pitfall. I originally was trying to set up to use port 1080 as an http proxy, and that didn't work at all. I don't know why I was blind and didn't see the SOCKS line just below it, but I didn't. So at this point you've encrypted your web data traffic, but anybody snooping could see your DNS requests, and know basically where you are going, if not what you are seeing. You can fix that by opening "about:config" in the Firefox URL bar, and setting "network.proxy.socks_remote_dns" to "true". This will send all of your DNS requests over the tunnel, and no one will have the faintest clue what you are browsing.

To configure Thunderbird, open the Edit/Preferences/Advanced/Network tab, and then click on the "Connection" button. You will see a proxy configuration dialog that should look very familiar to you by now, thanks to your experience with Firefox configuration. Set everything up the same way. You do not have to alter anything about your server settings if you started with a working setup. When the traffic comes out the other end of the tunnel, it is still looking for the same server and the same port that it was before. So everything you did before will work, if it was working before. I will explain the exception in the next paragraph.

The problem I had was caused by the fact that I run a properly-configured mail server on the machine at the other end of the tunnel. When I first tried to send mail to anybody on a different domain than my own with the SOCKS proxy setup, I'd get a "relay access denied" message from Postfix, which is the mail server I run. It took a while, but I eventually figured it out. I had set up my email client to access the external IP address of my mail server. This is because I was sending mail from outside my home network, to that IP address. When I first set up the proxy, I **assumed** that packets coming out the other end of the tunnel would be seen as originating from inside my internal network, since they had appeared on an internal interface. This is how it works if you do port forwarding, and I never had this "relay access denied" problem with that message. A mail message sent over the tunnel appears to the mail server as having originated on the server itself. A tunnel based on a SOCKS proxy works differently. When the mail message appears on the server, it has a source IP address that is outside any network that the server is aware of, and appears to be coming from the wild internet, despite the fact that it has appeared on an internal network interface (the loopback interface). When this traffic gets to the Postfix mail server, it thinks that it has mail from internet address 'A', addressed to internet address 'B', and it's own address is neither 'A' nor 'B'. This is the definition of a mail relay, and a good mail server setup will catch it and refuse. The way I got around this was fairly simple, in retrospect. Instead of using "mail" as the SMTP server host name in my Thunderbird configuration, with "mail" resolving to the external IP address of my server, I used "mail-internal", and created an entry in the /etc/hosts file so that "mail-internal" resolved to the IP address of an internal interface on the mail server. Voila!! Now, when the mail appears on the internal interface of the mail server, it has an internal IP address, and all is well.