Creating a VPN using ssh and ppp on FreeBSD

FreeBSD: Creating a VPN using ssh and ppp

Welcome to the 21st century, the time of fast computers, fan cooled graphics cards,
point and click packet sniffers, and “I didn’t know what that program did, i just ran it
script kiddies. The problem with the internet today is that it isn’t the nice place it
once was. You have no idea where your packets are going and who could be reading them.
Wouldn’t it be nice if we could encrypt all of our traffic from our home network to
our office. Obviously a VPN is the answer, but if you’ve ever looked at IPSEC, it’s
fairly complex. What makes IPSEC less appealing is the fact that most ISP’s hand you
out a dynamic IP address which makes it more complex to configure IPSEC, especially
when your using unix hosts. But with 2 boxes (one client, one server) we can
setup a pretty good VPN using ssh and ppp.

The concept behind this system is to use ssh to create a ppp connection between the 2 boxes.
We’ll ssh into the server and run ppp, have the local ppp client take control of the ssh
process using it’s stdin and stdout as a serial line. So all ppp traffic then goes thru the
encrypted (and possibly compressed) ssh stream. You could possible do this on other platforms,
but I know FreeBSD so FreeBSD it is.

The things we need are 2 FreeBSD boxes, and a subnet that our vpn clients can be allocated. We
could use a private network, and hand this out to vpn clients, but this means that we would have
to do Network Address Translation (see natd manpage) on the server machine. This is far more work to implement.
Lets just use a subnet that is routable within our office, and is setup to point to our vpn

For this example will be our office network, will be the network to
allocate to vpn clients. The vpn server will have the IP addresses of and
The fact that these IP addresses are private are just for demonstration. These could well be proper
subnets, the principle is still the same.

VPN Server

The first thing we want to do is alias the routing IP of the client subnet to the server.
To alias to an already configured network interface we use the following line
in the file /etc/rc.conf:

We now need to create some groups and users. If you are unsure on how
to add users and groups on FreeBSD read the pw manpage. It’s a
rather huge man page so to get basic help use: pw group add help
or pw user add help

We need to create a new group vpn. How we use this group will become clear later.
Now create a vpn user, the scripts provided here assume the format is vpn<username>. In this
example the username we will use is vpnsimon. When creating the user set the primary
group to vpn and put the account into the secondary group
of network. The reason we want it in the network group is
that /usr/sbin/ppp is only executable by the network group. The
shell of this user needs to be set to
/etc/ppp/ppp_start. This will start our ppp process when we
log into the account, it’s contents look something like this:

Now that we have a user that we can log in as, to start ppp. We need to setup ppp so we
can use it. The configuration of ppp is done in the file
/etc/ppp/ppp.conf. Create the file and add the
following lines to it:

When ppp is called with the name simon, the client
will be allocated the IP It also requires that the client authenticate itself
to the server. This can be disabled if you wish, by removing the enable pap. This
means that you will be relying on the RSA authentication of ssh only.

If you are going to use the ppp authentication, you’ll need to create the
/etc/ppp/ppp.secret. Each line of this file has the format of
username password something like this:

Make sure you chmod this file 600 and chown it to root. We only want root
seeing our passwords.

The most complex part of the whole vpn server is setting up ssh. Since we need to allow
access to the ssh daemon from alot of IP addresses, it’s safer to have a 2nd ssh daemon
running on a different port and only allowing RSA key authentication, we’ll reject passwords
if they are offered. Remember that vpn group we created before? We use it here,
in the configuration file for ssh, a line AllowGroups group tells ssh that only
people in the group specified are allowed to authenticate with the ssh server. Even if
they have the right RSA key they still won’t be allowed on unless they match the group.
Create a new sshd configuration file by copying /etc/ssh/sshd_config to
/etc/ssh/sshd_vpn_config and changing/adding the following options:

If your unsure what any of these options do, read the sshd manpage. But the basic
gist of the config is that we end up with a ssh server on port 1, using protocol 2 only,
listening on a specific ip address and not allowing password authentication from anyone,
and only RSA/Pubkey authentication from people in the vpn group.

Now that we have the new config, we also need a new name for the daemon. This helps us separate
it from our normal ssh server. Create a hard symlink from /usr/sbin/sshd to
/usr/sbin/ssh_vpnd (Hard links are done by leaving off
the -s on ln). Making this a hardlink means that the process runs as ssh_vpnd,
also that any tcp wrapper rules apply to this name too. The other advantage of
this is that since it’s a hardlink and not just a copy, if/when
you update to -stable or upgrade, when a new version of sshd is copied into place,
our ssh_vpnd will be updated to.

Above we mentioned tcp wrappers. We need to make an entry in/create the file
/etc/hosts.allow. In this file we can tell sshd who is allowed
to connect to our new ssh daemon based on incoming IP address. If you
are unfamiliar with tcp wrapper rules read the hosts_access(5)
manpage. A sample /etc/hosts.allow looks like this:

This will restrict our vpn server to just the machines that are in the domain or are in the subnet. If you created this file,
other tcp wrapper enabled daemons will also stop accepting connections and will need
lines added. So if you are running services on the box your using as the server, double
check the services can still be accessed.

Now we better make a rc script to start this new server up at boot time.
The script is /usr/local/etc/rc.d/ and looks
like this:

That should be all we need to do on the server. We still have to copy in the public
key so our user can login. But that will come in the next section. For now give the
server a reboot and check that the ssh_vpnd process starts up. That would be a good
start to things.

Client Side Configuration

The client ppp side could be run as root, but we are going to make the ppp daemon run as a
non privileged user. Check to see if you have a ppp account created, if not create
this user using either pw or adduser commands. Make sure the ppp user is a
member of the network group either by primary group or secondary.

Now we need to generate our RSA key pairs. We run the command
su -m ppp -c ‘ssh-keygen -t rsa -b 1024’ and this will generate our RSA key
and save it into ppp’s home directory. Make sure you just press enter when it asks
for the pass-phrase, as we want a blank one.

Now you should have a file ~ppp/.ssh/ This file need to be copied to the
vpn server (the other box) and placed in ~vpnsimon/.ssh/authorized_keys2. Once this
is in place we can test to make sure the ssh connection is working as it should be by running the
command su -m ppp -c ‘ssh -p 1 -l vpnsimon’. We should see some garbage
characters, this means it’s working and ppp has started. If you don’t see things that look like
lots of braces ‘{‘ then look for error messages either when you run the ssh command
(can’t exec /usr/sbin/ppp on the server), or something else in the syslog. If the ssh
connection prompts you for a password, it means that for some reason sshd can’t find
the authorized_keys2 file, double check it’s permissions and ownership. Once this is
working we can go about making a shell script to call the ssh command, this file is called
/etc/ppp/ppp_secure and looks like this:

Now for the ppp.conf file. If you are already using the ppp.conf file to
dial in to your provider say for adsl/modem etc, then you might already have
a default: statement. If so it might pay to remove all the stuff from
default and put it into your ISP definition. Otherwise your VPN will get all
your default settings which may not be what we want as it’s not a modem. You
should end up with a /etc/ppp/ppp.conf that looks
like this:

Note the command add HISADDR in the adsl definition.
This tells ppp to add a static route for our vpn server to always go out the internet
link. This is *really* important, if we don’t add this to our normal
internet connection (either in ppp.conf or as a static route in the routing
table) there is no way our vpn will work. When the vpn comes up, all traffic for
will go via our VPN, which includes Our ssh packets need to go across the open
internet to get to otherwise we’ll be trying to run our vpn over our vpn.

Under vpn: are the options we need to establish our vpn connection. The ppp manpage
page will explain these options in greater detail, but we’ll quickly go thru them here.
set device !/etc/ppp/ppp_secure this tells ppp that instead of a serial port, it’s
going to be executing a program and using the stdin/stdout as the serial line. set mode ddial
indicates that we want direct dial mode, if the link drops at all, reconnect it straight away.
set ifddr lets us restrict what IP
addresses we’re expecting from the ppp server, in this case our ip address will be in the range and the server IP will be set authname simon and
set authkey vpnpass are our username and password we set in the servers ppp.secret file.
add HISADDR this will add a route to our office network via the IP address
of our server. And finally nat enable yes tells ppp that we want to to use
Network Address Translation.

Since we need that route for our vpn server to be added. Now is a good time reboot.
If you are using ipfw to restrict traffic into your network you will need to modify
your rules before we reboot so that the traffic is allowed to pass thru the new interface
that will be created. We’ll use the rules from the PPPoE article and add the new lines we
need so you can see what changes.

Once the machine has rebooted we should be able to establish our vpn. Start it with the command,
su -m ppp -c ‘ppp -unit1 -i vpn’, you should get something that looks like this:

You should see the ppp go from ppp -> Ppp -> PPp -> PPP. If you end up with PPP then you
you have an established PPP connection to the vpn server and you should be able
to ping/traceroute to the office network. Once you are happy that it’s working, type
quit to exit back to the prompt.

Now we need to make it start up each time we reboot. We make an rc script for this and
call it /usr/local/etc/rc.d/

There we go. We now have a working VPN to our office network. Any traffic that is for
our office will go via the encrypted ssh connection and anything that is for the
internet will go via our default connection.

Comments are closed.