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 to the server side VPN endpoint while the client side VPN endpoint is assigned the IP address 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" 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

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’ 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.

Missing wpa_passphrase in FreeBSD

A couple of days ago I wrote a patch for connecting the wpa_passphrase utility from wpa_supplicant to the FreeBSD src build, but judging from the lack of interest on the freebsd-mobile mailing list, I thought I’d better explain the usefulness of this utility on my blog as well ;-)

I often use wpa_passphrase when assigning new WPA keys to users on my FreeBSD (and hostapd) based access points.

Instead of having to generate all the 256-bit pre-shared WPA keys from ASCII passphrases at runtime (cpu intensive operation when you have many keys configured), I just call wpa_passphrase with the given SSID, enter the ASCII passphrase and it gives me a static 256-bit key in return.

This furthermore allows me to give both the ASCII passphrase and the 256-bit pre-shared WPA key to any given user along with proper instructions.

The last part is especially helpful since quite a few vendor specific WPA configuration utilities for that “other” operating system accepts either an ASCII passphrase _or_ a WPA pre-shared key, meaning I would have to guess which vendor specific piece of software a given user has, and hand him/her either an ASCII passphrase or a WPA pre-shared key based on my guess.

Hopefully someone with src commit bit will eventually pick up the patch and get it included in FreeBSD proper.