Sunday, February 8, 2009

Create Open VPN with FreeBSD

OpenVPN - getting it running

Installing

Installing OpenVPN on FreeBSD is pretty simple:

cd /usr/ports/security/openvpn
make install clean/usr/ports/security/openvpn

You will find sample configuration files at /usr/local/share/doc/openvpn/sample-config-files but I will share my configuration files with you.


TAP interfaces

I have chosen a particular OpenVPN solution that makes use of a virtual ethernet device. This device must be loaded before running OpenVPN. You can do this on the command line with this:

kldload if_tap

To ensure this module is loaded at boot time, add the following line to /boot/loader.conf:

if_tap_load="YES"

If you see an error like this one, then you have forgotten to load this particular kernel module:

openvpn[1264]: Cannot allocate TUN/TAP dev dynamically
kldload if_tap

Server configuration

This section shows you the setup of my OpenVPN server. The main configuration file is /usr/local/etc/openvpn/openvpn.conf. This is mine:

#
# Sample OpenVPN configuration file for
# office using SSL/TLS mode and RSA certificates/keys.
#
# '#' or ';' may be used to delimit comments.

# Use a dynamic tun device.
# For Linux 2.2 or non-Linux OSes,
# you may want to use an explicit
# unit number such as "tun1".
# OpenVPN also supports virtual
# ethernet "tap" devices.
dev tap

# 192.168.100.2 is our local VPN endpoint (home).
# 192.168.100.3 is our remote VPN endpoint (office).
ifconfig 192.168.100.3 255.255.255.0

# In SSL/TLS key exchange, Office will
# assume server role and Home
# will assume client role.
tls-server

# Diffie-Hellman Parameters (tls-server only)
dh /usr/local/etc/openvpn/keys/dh1024.pem

# Certificate Authority file
ca /usr/local/etc/openvpn/keys/ca.crt

# Our certificate/public key
cert /usr/local/etc/openvpn/keys/myserver.example.com.crt

# Our private key
key /usr/local/etc/openvpn/keys/myserver.example.com.key

# OpenVPN 2.0 uses UDP port 1194 by default
# (official port assignment by iana.org 11/04).
# OpenVPN 1.x uses UDP port 5000 by default.
# Each OpenVPN tunnel must use
# a different port number.
# lport or rport can be used
# to denote different ports
# for local and remote.
port 1194

# Downgrade UID and GID to
# "nobody" after initialization
# for extra security.
; user nobody
; group nobody

# Verbosity level.
# 0 -- quiet except for fatal errors.
# 1 -- mostly quiet, but display non-fatal network errors.
# 3 -- medium output, good for normal operation.
# 9 -- verbose, good for troubleshooting
verb 3

status openvpn-status.log

From the above configuration, you will need to get the certificate public key, the certificate private key, the CA public key, and the Diffie-Hellman Parameters file (see the items in bold above). Each of these files were created when you followed the instructions in the CA reference article.

You must copy the .key files over a secure channel. Do not email it.

To start OpenVPN at boot time, you need to add the following items to /etc/rc.conf:

openvpn_enable="YES"
openvpn_if="tap"

The second line defines the interface to use, in this case, tap(4).
Starting the server

To start the server, issue this command:

# /usr/local/etc/rc.d/openvpn start
Starting openvpn.

If you look at /var/log/messages, you should see something like this:

openvpn[52594]: OpenVPN 2.0.6 i386-portbld-freebsd6.3 [SSL] [LZO] built on Jun 1 2008
openvpn[52594]: Diffie-Hellman initialized with 1024 bit key
openvpn[52594]: Control Channel MTU parms [ L:1573 D:138 EF:38 EB:0 ET:0 EL:0 ]
openvpn[52594]: TUN/TAP device /dev/tap0 opened
openvpn[52594]: /sbin/ifconfig tap0 192.168.100.3 netmask 255.255.255.0 mtu 1500 up
openvpn[52594]: Data Channel MTU parms [ L:1573 D:1450 EF:41 EB:4 ET:32 EL:0 ]
openvpn[52594]: Local Options hash (VER=V4): '6ab3b73a'
openvpn[52594]: Expected Remote Options hash (VER=V4): 'ea8adc0d'
openvpn[52597]: UDPv4 link local (bound): [undef]:1194
openvpn[52597]: UDPv4 link remote: [undef]

You should also see a tap device such as this:

tap0: flags=8843 mtu 1500
inet6 fe80::2bd:a4ff:fe65:0%tap0 prefixlen 64 scopeid 0x8
inet 192.168.100.3 netmask 0xffffff00 broadcast 192.168.100.255
ether 00:bd:a4:65:00:00
Opened by PID 52594

That looks good. Now let us start the client.
Client configuration

On the client, as on the server, I have this in /etc/rc.conf:

openvpn_enable="YES"
openvpn_if="tap"

The configuration file, /usr/local/etc/openvpn/openvpn.conf, contains this:

#
# Sample OpenVPN configuration file for
# home using SSL/TLS mode and RSA certificates/keys.
#
# '#' or ';' may be used to delimit comments.

# Use a dynamic tun device.
# For Linux 2.2 or non-Linux OSes,
# you may want to use an explicit
# unit number such as "tun1".
# OpenVPN also supports virtual
# ethernet "tap" devices.
dev tap

# Our OpenVPN peer is the office gateway.
float
remote myserver.example.com

# 192.168.100.2 is our local VPN endpoint (home).
# 192.168.100.3 is our remote VPN endpoint (office).
ifconfig 192.168.100.2 255.255.255.0
route 10.55.0.0 255.255.255.0 192.168.100.3

# In SSL/TLS key exchange, Office will
# assume server role and Home
# will assume client role.
tls-client

ns-cert-type server

# Certificate Authority file
ca /usr/local/etc/openvpn/keys/ca.crt

# Our certificate/public key
cert /usr/local/etc/openvpn/keys/client.example.com.crt

# Our private key
key /usr/local/etc/openvpn/keys/client.example.com.key

# OpenVPN 2.0 uses UDP port 1194 by default
# (official port assignment by iana.org 11/04).
# OpenVPN 1.x uses UDP port 5000 by default.
# Each OpenVPN tunnel must use
# a different port number.
# lport or rport can be used
# to denote different ports
# for local and remote.
port 1194

# Downgrade UID and GID to
# "nobody" after initialization
# for extra security.
user nobody
group nobody

persist-key
persist-tun

# Send a UDP ping to remote once
# every 15 seconds to keep
# stateful firewall connection
# alive. Uncomment this
# out if you are using a stateful
# firewall.
ping 15
#keepalive 10 60

# Verbosity level.
# 0 -- quiet except for fatal errors.
# 1 -- mostly quiet, but display non-fatal network errors.
# 3 -- medium output, good for normal operation.
# 9 -- verbose, good for troubleshooting
verb 3

To start the client, issue this command:

# /usr/local/etc/rc.d/openvpn start
Starting openvpn.
add net 10.55.0.0: gateway 192.168.100.3

This is similar to what you should now see in /var/log/messages:

openvpn[62722]: OpenVPN 2.0.6 i386-portbld-freebsd6.3 [SSL] [LZO] built on Nov 26 2008
openvpn[62722]: WARNING: --ping should normally be used with --ping-restart or --ping-exit
openvpn[62722]: Control Channel MTU parms [ L:1573 D:138 EF:38 EB:0 ET:0 EL:0 ]
openvpn[62722]: gw 64.147.113.41
openvpn[62722]: TUN/TAP device /dev/tap0 opened
openvpn[62722]: /sbin/ifconfig tap0 192.168.100.2 netmask 255.255.255.0 mtu 1500 up
openvpn[62722]: /sbin/route add -net 10.55.0.0 192.168.100.3 255.255.255.0
openvpn[62722]: Data Channel MTU parms [ L:1573 D:1450 EF:41 EB:4 ET:32 EL:0 ]
openvpn[62722]: Local Options hash (VER=V4): 'ea8adc0d'
openvpn[62722]: Expected Remote Options hash (VER=V4): '6ab3b73a'
openvpn[62727]: GID set to nobody
openvpn[62727]: UID set to nobody
openvpn[62727]: UDPv4 link local (bound): [undef]:1194
openvpn[62727]: UDPv4 link remote: 172.28.123.191:1194
openvpn[62727]: TLS: Initial packet from 172.28.123.191:1194, sid=9a791e73 6db7b2f9
openvpn[62727]: VERIFY OK: depth=1, /C=US/ST=PA/L=Warrington/O=The_FreeBSD_Diary
/emailAddress=dan@example.com
openvpn[62727]: VERIFY OK: nsCertType=SERVER
openvpn[62727]: VERIFY OK: depth=0, /C=US/ST=PA/O=The_FreeBSD_Diary/CN=myserver.example.com
/emailAddress=dan@example.com
openvpn[62727]: Data Channel Encrypt: Cipher 'BF-CBC' initialized with 128 bit key
openvpn[62727]: Data Channel Encrypt: Using 160 bit message hash 'SHA1' for
HMAC authentication
openvpn[62727]: Data Channel Decrypt: Cipher 'BF-CBC' initialized with 128 bit key
openvpn[62727]: Data Channel Decrypt: Using 160 bit message hash 'SHA1' for
HMAC authentication
openvpn[62727]: Control Channel: TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 1024 bit RSA
openvpn[62727]: [myserver.example.com] Peer Connection Initiated with 172.28.123.191:1194
openvpn[62727]: Initialization Sequence Completed

On the server, you should see something like this:

bast openvpn[52597]: TLS: new session incoming connection from 172.10.10.101:1194
bast openvpn[52597]: VERIFY OK: depth=1, /C=US/ST=PA/L=Warrington/O=The_FreeBSD_Diary
/emailAddress=dan@example.com
bast openvpn[52597]: VERIFY OK: depth=0, /C=US/ST=PA/O=The_FreeBSD_Diary
/CN=client.example.com
/emailAddress=dan@example.com
bast openvpn[52597]: Data Channel Encrypt: Cipher 'BF-CBC' initialized with 128 bit key
bast openvpn[52597]: Data Channel Encrypt: Using 160 bit message hash 'SHA1' for
HMAC authentication
bast openvpn[52597]: Data Channel Decrypt: Cipher 'BF-CBC' initialized with 128 bit key
bast openvpn[52597]: Data Channel Decrypt: Using 160 bit message hash 'SHA1' for
HMAC authentication
bast openvpn[52597]: TLS: move_session: dest=TM_ACTIVE src=TM_UNTRUSTED reinit_src=1
bast openvpn[52597]: TLS: tls_multi_process: untrusted session promoted to trusted
bast openvpn[52597]: Control Channel: TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA,
1024 bit RSA

You should see see a tap device like this on the client:

# ifconfig tap0
tap0: flags=8843 mtu 1500
inet 192.168.100.2 netmask 0xffffff00 broadcast 192.168.100.255
ether 00:bd:10:e7:72:00
Opened by PID 62722

Testing the comms

These tests are done on the client.

Test that you can ping the local end of the VPN:

# ping -c 5 192.168.100.2
PING 192.168.100.2 (192.168.100.2): 56 data bytes
64 bytes from 192.168.100.2: icmp_seq=0 ttl=64 time=0.043 ms
64 bytes from 192.168.100.2: icmp_seq=1 ttl=64 time=0.042 ms
64 bytes from 192.168.100.2: icmp_seq=2 ttl=64 time=0.038 ms
64 bytes from 192.168.100.2: icmp_seq=3 ttl=64 time=0.035 ms
64 bytes from 192.168.100.2: icmp_seq=4 ttl=64 time=0.028 ms

--- 192.168.100.2 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max/stddev = 0.028/0.037/0.043/0.005 ms

Can we ping the far end of the VPN?

# ping -c 5 192.168.100.3
PING 192.168.100.3 (192.168.100.3): 56 data bytes
64 bytes from 192.168.100.3: icmp_seq=0 ttl=64 time=30.379 ms
64 bytes from 192.168.100.3: icmp_seq=1 ttl=64 time=39.191 ms
64 bytes from 192.168.100.3: icmp_seq=2 ttl=64 time=15.725 ms
64 bytes from 192.168.100.3: icmp_seq=3 ttl=64 time=17.148 ms
64 bytes from 192.168.100.3: icmp_seq=4 ttl=64 time=21.225 ms

--- 192.168.100.3 ping statistics ---
5 packets transmitted, 5 packets received, 0% packet loss
round-trip min/avg/max/stddev = 15.725/24.734/39.191/8.853 ms

If you cannot ping the far end of the VPN, check your routing tables, firewall rules etc. Any problems you encounter here are outside the scope of this tutorial.

If these pings work, then traffic from the client to the server should just work.
Unroutable control packet

If you see errors on the server such as this, don't Google them. Look farther up in /var/log/messages for the real error.

openvpn[29610]: TLS Error: Unroutable control packet received from 172.10.10.101:1194
(si=3 op=P_CONTROL_V1)
last message repeated 10 times
openvpn[29610]: TLS Error: Unroutable control packet received from 172.10.10.101:1194
(si=3 op=P_ACK_V1)

Look above that for other errors. In my case:

openvpn[29610]: VERIFY ERROR: depth=0, error=unable to get local issuer certificate:
/CN=client.example.com
openvpn[29610]: TLS_ERROR: BIO read tls_read_plaintext error: error:14090086:SSL
routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
openvpn[29610]: TLS Error: TLS object -> incoming plaintext read error
openvpn[29610]: TLS Error: TLS handshake failed

In this case, there was clearly something wrong with my setup. I had the wrong certificates or wrong ca.crt file, something like that. Be cautious and careful.
It should just work

The hard part is getting the certificates and configuration correct. The primary goal of this article is to simplify that process. It Should Just Work(tm).

Best wishes. Enjoy.

No comments: