VPN using OpenSSH and tun(4) under FreeBSD

Since the recent import of OpenSSH 4.4p1 into FreeBSD RELENG_6 I have been meaning to test the (in OpenSSH 4.3p1) new VPN over tun(4) feature. As I was unable to find any FreeBSD specific instructions – and as the instructions supplied with OpenSSH are specific to OpenBSD – I decided to document my setup here.

To use the VPN over tun(4) feature you need two endpoints with OpenSSH 4.3p1 or later, one running sshd(8). You need root access and kernel support for tun(4) on both ends.

The examples below assign the IP address 10.0.3.1 to the server side VPN endpoint while the client side VPN endpoint is assigned the IP address 10.0.3.2. Don’t forget to update the firewall configuration on both ends to allow traffic to/from these IPs.

Server side

On the server side you need to add the following lines to /etc/ssh/sshd_config:

PermitRootLogin yes
PermitTunnel yes

You also need to add the following line to /root/.ssh/authorized_keys (replacing ‘ssh-dss …’ with the actual SSH public key, of course):

tunnel="0",command="/sbin/ifconfig tun0 10.0.3.1/30 10.0.3.2" ssh-dss ...

You can append ‘; /bin/echo VPN established’ or similar to the above command to receive visual feedback on the client once the VPN connection is established.

Client side

On the client you need to add the following entry to /root/.ssh/config (Replacing ‘vpn.example.com’ with the hostname of the server side VPN endpoint):

Host vpn
  HostName vpn.example.com
  User root
  IdentityFile ~/.ssh/id_dsa_vpn
  Tunnel yes
  TunnelDevice 0:any
  PermitLocalCommand yes
  LocalCommand /bin/echo > /dev/tun0; /sbin/ifconfig tun0 10.0.3.2/30 10.0.3.1

I recommend using a dedicated SSH key (here ~/.ssh/id_dsa_vpn) for authenticating the tunnel, but this is of course optional. The ‘/bin/echo > /dev/tun0′ command is needed to avoid a race condition where ifconfig(8) is called before the tun0 interface is created.

Once the above configuration has been made you can establish the VPN connection simply by executing:

# ssh vpn

Hit Ctrl+C to close the VPN connection again. Please note that the tun0 interface is not destroyed upon closing the tunnel. The interface is merely brought down and the routing table entry is deleted. See the tun(4) manual page for more information.

Update: Following this commit to the FreeBSD src tree, the tun0 interface is correctly destroyed upon closing the tunnel.

If you wish to route more nets through the VPN connection it is as simple as appending an ‘/sbin/route add -net 10.0.0.0/16 10.0.3.1′ or similar command to the authorized_keys entry.

To increase security you can add a dedicated user account with privileges to create and configure the tun0 interface (e.g. via security/sudo) and instead use that account for establishing the VPN connection. This is left as an exercise for the reader.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>