Thursday, December 27, 2012

Raspberry Pi as an SSH Tunnel Gateway

The Raspberry Pi is a neat little Linux box that costs $25 and is the size of a credit card. I've been tinkering with mine for about a month now. I know a few people who bought them and are wondering what they can do with it, so I'm going to do a series called "10 slices of Pi"

In this first post, I'm going to show you how to set up your Raspberry Pi to tunnel SSH traffic through your home network. This will help you browse privately and securely from behind firewalls and public wireless hotspot.


Why tunnel SSH traffic?

There are a few good reasons you may want to tunnel your web traffic through your home.

By tunneling your traffic through SSH, it is encrypted to any prying eyes that may be hoping to sniff passwords and sensitive information on a public wireless hotspot. 

Encrypting your traffic defeats website-blocking firewalls at your school, work, or oppressive country.


Requirements

  1. An "always-on" SSH server on a trusted network (like your home). This is what the raspberry pi will become.
  2. An SSH client on the computer or laptop you wish to do the tunneling (mac has a native ssh application, and for windows you can use PuTTY.
  3. Firewall rules that allow you to access your open-ssh server from the outside.
  4. A browser that supports SOCKS proxies.


Setting up the Raspberry Pi

Fortunately, there's very little setup we'll actually do on the RPI. Most of what will take place will happen on your router or laptop. The first thing we'll need to do is make sure that your openssh-server is running and accepting connections.

If you're logged into your RPI, simply check if openssh is listening on port 22



$ nc localhost 22
SSH-2.0-OpenSSH_6.0p1 Debian-3

Looks like it is! If it wasn't listening, netcat would simply hang up on you. 
If openssh isn't listening, you can run the config again to enable the server.
 sudo dpkg-reconfigure


Give the Raspberry Pi a static IP

Before you go on to the port forwarding step, you'll want to take a moment to give your RPI a static IP on the network. Since it's a regular linux computer the steps are the same. 

$ sudo vi /etc/network/interfaces
    auto eth0
    iface eth0 inet static
        address 192.168.1.3
        netmask 255.255.255.0
        gateway 192.168.1.1
$ ifdown eth0$ ifup eth0


Granting Access To Port 22

The next step is to make sure you can access your raspberry pi from the outside world. This is where it gets tricky. Most everyone has their computers protected from the outside world via the firewall on their router, but we need a way to snake our way through the firewall and onto our RPI. For purposes like this, routers come with a feature called "port forwarding" which allows you to route specific traffic to a particular host.


Settings on your router

To log into your router, typically you type in 192.168.1.1 or 192.168.0.1 into your browser window. You'll find port forwarding usually around access control. 

Since port 22 is a privileged port and is frequently scanned. I'm going to pick a random and unprivileged port (those above port number 1024).


In this example, we're forward external port 7000 from the outside to internal port 22 on the RPI server. 


This means when you connect to your router on port 7000, it will send that traffic to your rpi on port 22. You'll need to forward it to your raspberry pi internal network address. 

Here's what my home network settings look like:




Put in your appropriate settings and restart your router. Now it's time to test if it's listening properly to the outside world. You can use the port forwarding tester over at yougetsignal.com


Setting up your SOCKS proxy

Now you need to connect to your RPI using your SSH client to establish a SOCKS proxy. 

Directions for doing that in Windows using PuTTY can be found here.

If you're on a mac you can look at my previous post here: How to SSH Tunnel on a Mac.


Setting up your browser

Our last step is to set up our browser to use the new SOCKS proxy for all web traffic. I usually keep a copy of portable firefox just for this. You can even stash firefox and portable PuTTY on a flash drive and carry it around with you.

In Firefox, you can adjust the settings by doing the following:
  1. Go to preferences, and select the "Advanced" tab.
  2. Select "Network" button and choose "Settings"
  3. Select "Manual proxy configuration" and under "SOCKS Host", you're going to put your local loopback address (127.0.0.1) and the port you selected when you opened up the proxy 
You are now relaying your internet traffic through your raspberry pi as a proxy. 


Caveats

This will forward your web traffic (port 80, 443), but will not forward DNS queries (port 53). Your DNS server could be keeping a log, so your browsing isn't completely private. 

18 comments:

  1. Hi Stephen, nice post. Instead of port forwarding you might also use Yaler, our simple relay infrastructure. The YalerTunnel command line tool offers generic protocol tunnelling via HTTP. Please see http://yaler.net/ for info and contact.

    Kind regards,
    Thomas

    ReplyDelete
  2. I've had great results doing something similar to this with SOCKS5 proxies via ProxySwitchSharp for chrome, and host-based ssh configs to pipe data through bastions hosts that exist across multiple production environments! ^_^

    A few tips that might be useful if you wanted to access another server via ssh after your home/ssh server is by utilizing ssh-agent-forwarding as well as ControlPath in the ssh config.

    http://www.unixwiz.net/techtips/ssh-agent-forwarding.html

    agent-forwarding when combined with key-based auth will allow you to only unlock the private key ONCE. so, after the initial connection, you wont be prompted for a key password. this makes things alot more secure for automation as an alternative to assigning a blank password or something.

    http://protempore.net/~calvins/howto/ssh-connection-sharing/#section-02

    ControlPath is a way to pipe all your traffic for a given host over one pipe by utilizing a socket file that is created. This will help speed up subsequent connections and transfers!

    ReplyDelete
  3. Which Linux distro are you running on your Pi?

    ReplyDelete
    Replies
    1. I run the standard debian system provided by the Raspberry Pi website. I think it's squeeze?

      Delete
  4. Hello, thanks for your tutorial...really useful!

    as for the caveat in firefox->about:config just edit network.proxy.socks_remote_dns to "true" and even DNS requests will go through the tunnel. Ah, just in case your DNS requests take forever also edit network.dns.disableIPv6 to "true".

    hope this helps :)

    ReplyDelete
    Replies
    1. Appreciate your tip. I can't find this in FF version 22.0 on the Mac. Could you explain a little more? Thx,

      Delete
    2. In your firefox address bar, type in "about:config" and hit enter. Click on "I'll be careful, I promise" to open up the configuration.

      Once it opens you'll see a long list of options. Find "network.proxy.socks_remote_dns" and toggle it to "true". This should use your SOCKS proxy to also tunnel in DNS requests.

      Generally speaking you'll want to disable these settings once you're done or you'll have to enable your SOCKS proxy every time you use the net. That's why I use firefox entirely for SSH tunnel traffic and chome for everything else. It's just handier to leave the settings intact :)

      Good luck!

      Delete
    3. Thx, that worked a treat. I dont generally use FF. Thanks for the tip... FF for SSH tunnelling and Chrome for everything else... up to now I'd been using Chrome and Safari.

      Delete
  5. I'll preface this by saying that the Pi is my first Linux machine.

    For some reason, the ssh -D XXXX user@host -vv line, which is mentioned in the "SSH Tunneling on Mac in 5 Minutes" post, wasn't working for me. After fiddling around, I found that ssh -D XXXX user@host -p XXXX -vv did work.

    ReplyDelete
    Replies
    1. Thanks for the tip Tyler, I had the same problem using my Mac OS 10.8.4 to log in using Terminal.

      Delete
  6. A couple reasons could explain that. What client are you using to connect? By default, openssh-server listens on port 22 and most clients attempt to connect on port 22. If that port is different, you'll need to use the -p flag to specify the port.

    ReplyDelete
  7. Hi Stephen,

    Many thanks for this tutorial. I'm planning on doing something similar soon.

    I have a question though. Is it possible to modify this configuration so that after ssh tunneling into the Pi from a remote location, you could have the pi then forward all traffic to another remote vpn server? I've been searching all over to see if this is possible, but I have a suspicion I may be overthinking it. Is it as simple as setting up an openvpn client on the pi, alongside setting up the ssh server?

    It would look as follows:

    Remote Laptop ---[SSH Tunnel]---> Raspberry Pi w/ SSH server & OpenVPN Client ---[OpenVPN]---> OpenVPN Server ---> Internet

    ReplyDelete
    Replies
    1. It's very possible depending on the type of traffic you want to forward. The easiest solution I can think of is to create another persistent SOCKS5 connection from your RPI to your remote server. Then you would just need a simple iptables rule to forward all incoming traffic on X (the SOCKS port you created) to local port Y (the SOCKS port to your remote machine).

      Of course, if you're fine with your traffic going over the public inet you could just run something like squid on your remote server and have it proxy at of your rpi web traffic.

      Delete
    2. Of course, if you already have a VPN set up remotely there's no reason you can't just make your RPI a persistent client. Depending on the VPN software you use, the OS might transparently forward all of the ports you care about anyway (port 80 and 443 are typical ones that come to mind).

      I've never set that up personally but the setup should be no different than any other debian machine.

      Delete
  8. settings for Chrome can be done with this app
    https://chrome.google.com/webstore/detail/proxy-switchy/caehdcpeofiiigpdhbabniblemipncjj

    ReplyDelete
    Replies
    1. That's a nice Chrome extension! Thanks for the tip.

      Delete
  9. Hello, I have my Pi acting as a router in my private network 192.168.0.0/24 and I open an ssh connection to use it as a socks server (with ssh -N -l root -D *:1080 other.domain.com).
    Now I want to force one host of my private network, for example 192.168.0.101, to use the socks proxy on port 1080. The host should NOT know that for its connections it is using the socks proxy. No configuration in no application in the host Any idea? Thank you very much.
    Luca Di Gregorio

    ReplyDelete
    Replies
    1. Resolved with redsocks for Debian Wheezy. Woderful.

      Delete