PPP Over SSH - a simple vpn solution for unix
Posted Sat, 25 Mar 2006
Table of Contents
PPP over SSH is a quick and dirty vpn solution. You can run a PPP connection over an SSH connection to make for an easy, encrypted vpn. Sure, there are lots of existing, prepackaged vpn solutions out there, but how difficult are they to setup? What do you need to install on *both* points of the vpn connection? Why is the sky blue?
If you run any flavor of *nix (Free/Open/NetBSD, Linux, etc), chances are you have two things installed: ppp and ssh. With these two tools you can create your own encrypted vpn in only a few minutes. In this article, I will explain how to set it up under FreeBSD, though it should be similar in other OS's.
Before I get into the details, I'm first going to explain the situation I'm using ppp over ssh in. You need two machines for this, your client (say, my laptop) and the endpoint (one of my freebsd servers). Here's a picture, so you can get a general idea of what is going on and what the final result will be:
The gist of it is as follows. My laptop is on an insecure, wireless, untrusted network. I want my traffic to be secure, so people can't gather anything useful out of my packets they sniff. My server is on a more trusted network, so that's where I'll be wanting to tunnel all of my traffic. From there, my traffic will hit the Internet or whatever it's intended destination may be.
Special mentions should be made: If I refer to client, I'm talking about my laptop. If I refer to gateway, I'm referring to my endpoint server on the trusted network.
Before you can actually run ppp(8), you must have root on both the client and gateway machines. Make sure you do.
First, you're going to need a passphraseless ssh key so we can login to your vpn gateway without a password. You do this by using the
ssh-keygen -N "" -t rsa -f ~/.ssh/ppp.key
This should create two files, a public and private key:
first one is your private key, you'll need to keep that on your client
machine. The public key needs to go on your gateway (vpn endpoint).
Assuming your end point is running OpenSSH, you need to copy
the contents of your public key into
~/.ssh/authorized_keys on the gateway server.
That's all you need to do for ssh keys right now , I'll come back to the key later.
The next file you want to look at is
/etc/ppp/ppp.conf. This is where FreeBSD's
ppp(8) looks for it's configuration. You need to add a new
entry, I called mine
vpn. Here i what I used:
vpn: set ifaddr 192.168.10.2 192.168.10.1 255.255.255.255 set dial set device "!env SSH_AUTH_SOCK= ssh -C -c blowfish -i /home/psionic/.ssh/ppp.key [email protected]"
Remeber, this configuration is for the client only. The first line tells ppp to create a tunnel between 192.168.10.2 and 192.168.10.1. The first IP on this line is the desired IP of the client on your new private network. The second address is the target IP of the tunnel, which is the gateway.
These two IPs can be different, as long as they are on the same subnet and are in the nonroutable range. It'd work cleaner aswell if you didn't pick a subnet already in use in either end of your network, if any are in use at all.
The only special note here, is the
in this ppp session. It is not a device, but ppp is told to
execute ssh(1) and use it as a transport medium. It will ssh
to 220.127.116.11 with the private key we created in the last
ppp.conf configuration for the
gateway is much simpler. Again, I called the new
vpn: set ifaddr 192.168.10.1 192.168.10.2 255.255.255.255
Again, the first ip in that line is the desired private ip of this machine, which is the gateway this time. Remember above when we set the client's ip to 192.168.10.2 and the tunnel endpoint ip to 192.168.10.1?
I said we'd come back to the ssh key, right? You should now
have your private key on the client as
~/.ssh/ppp.key and have put the contents of the
public key (
~/.ssh/ppp.key.pub) into the
You can verify that this key is working by doing:
ssh -i ~/.ssh/ppp.key yourgatewayserver
If it lets you login without prompting for a password, then you've done it right. If it doesn't work, then you probably didn't copy the public key properly or at all.
Assuming all goes well, we'll need to tell the gateway to
execute a specific command for the key we are using. Your
authorized_keys file should have
something looking vaguely like this:
ssh-rsa AAAAB....lotsofcharacters...= [email protected]
We need to add a command section now. Add this:
command="op pppvpn" ssh-rsa AAAAB...etc...
All you add is a
command="op pppvpn" to the
beginning of the line. That command is just what it looks
like: when you login with the key you created, it will run
"op pppvpn" regardless of what command you try to run, or
even if you try to get a login shell. This secures your
gateway by greatly limiting what can be done should
your private key become compromised. Granted, with a ppp
connection they'll be able to pretend they are coming from
your gateway server, but they won't get access to the
You don't have to do this. I use op to run things as root.
It's similar to
sudo, but I think it's easier
to configure. Anyway, I have an entry in my
pppvpn /usr/sbin/ppp -direct vpn; users=psionic environment
This means that when I (psionic) type "
pppvpn", then op will run "
-direct vpn" as root for me.
You can alternatively use sudo or put your public key in
your root user's .ssh/authorized_keys and ssh to the server
as root. Either way, you need to be able to ssh to your
gateway from your client and attain root
privileges so you can run
ppp(8) on the
Everything should be setup now:
- ppp.conf on the client
- ppp.conf on the gateway
- ssh key with public/private parts put in the right places
- root access attainable through ssh login on the gateway with the ssh key
ppp -auto vpn
Now try pinging the gateway ip, which if you remember should be 192.168.10.1 (unless you set it differently).
nightfall(~)  % sudo ppp -auto vpn Password: Working in auto mode Using interface: tun0 nightfall(~)  % ping 192.168.10.1 PING 192.168.10.1 (192.168.10.1): 56 data bytes 64 bytes from 192.168.10.1: icmp_seq=0 ttl=64 time=2.672 ms ^C
Works! Now, how do you get traffic to go through this tunnel? Use routes. An example would be if I wanted all my google.com traffic to go through the tunnel:
nightfall(~)  % sudo route add 18.104.22.168 192.168.10.1 add host 22.214.171.124: gateway 192.168.10.1 nightfall(~)  % sudo route add 126.96.36.199 192.168.10.1 add host 188.8.131.52: gateway 192.168.10.1 nightfall(~)  % sudo route add 184.108.40.206 192.168.10.1 add host 220.127.116.11: gateway 192.168.10.1 nightfall(~)  % traceroute google.com traceroute: Warning: google.com has multiple addresses; using 18.104.22.168 traceroute to google.com (22.214.171.124), 64 hops max, 40 byte packets 1 192.168.10.1 (192.168.10.1) 2.589 ms 1.707 ms 1.728 ms 2 rit-core1-vlan60.rit.edu (126.96.36.199) 2.673 ms 2.197 ms 1.966 ms 3 rit-rit1-pp-core1-vlan807.rit.edu (188.8.131.52) 2.724 ms 2.607 ms 2.203 ms ...
And we're all done! You can see that the first route goes to 192.168.10.1.