OpenVPN is a full-featured SSL VPN solution which can accomodate a wide range of configurations, including remote access, site-to-site VPNs, WiFi security, and enterprise-scale remote access solutions with load balancing, failover, and fine-grained access-controls.
Okay this was stolen from the OpenVPN website but it explains what OpenVPN is. I use it mainly because it is easy to set up (if you compare it with IPSec) and as it is SSL/UPD based it has no problems with NAT. Newer versions of isakpmd (IKE key management daemon) support NAT-Traversal but I wanted to give OpenVPN a chance to build a secure wireless access point with my wrap.
Note: I use OpenVPN 2.0 which is not available for the 3.7 ports collection. You need to use current or compile it from the sources.
OpenVPN can operate in two modes, Routing or Ethernet Bridging. In Routing mode a new virtual network is created that is used for the clear-text traffic between the VPN endpoints. That means that you need routing set up right if you want to access other networks (i.e. servers that are not part of the VPN). In Ethernet Bridging mode, as the name suggests, the VPN server functions as an ethernet bridge and forward all ethernet traffic to a network behind the VPN. That means that e.g. broadcasts will work between clients in a VPN and clients in a network behind the VPN server as also non-IP traffic can pass the VPN server. See this page for a comparison.
OpenVPN works by using a virtual interface (a tun interface for Routing mode and a tap interface for Ethernet Bridging mode) while the encripted traffic passes the physical interface.
The above picture describes my setting. I have local network (192.168.0.0/24) that is connected to the Internet through NAT. The wrap (the small box on the lower right) is dual homed and has a WLAN NIC (ath0 – 192.168.1.1) that uses the network 192.168.1.0/24. My PowerBook uses it’s WLAN card to connect to the wrap. OpenVPN will communicate over this wireless network (192.168.1.1/24).
The encrypted traffic will use port 1194/UDP and this is the only traffic that will be allowed to access ath0.
wlan_if=”ath0”
pass in on $wlan_if inet proto udp from $wlan_if:network to ($wlan_if) port 1194 keep state
The first step is to make sure that the client (PowerBook) will connect to the WLAN and use the right settings. On the wrap I use:
# cat /etc/hostname.ath0
inet 192.168.1.1 255.255.255.0 NONE media autoselect
mode 11b mediaopt hostap nwid wrap chan 11
and for DHCP:
# cat /etc/dhcpd.conf
shared-network LOCAL-NET {
option domain-name “nodomain”;
option domain-name-servers 192.168.0.1;
subnet 192.168.1.0 netmask 255.255.255.0 {
range 192.168.1.200 192.168.1.250;
}
}
# cat /etc/dhcpd.interfaces
ath0
# cat /etc/rc.conf.local
dhcpd_flags=””
This will make sure that the client will use my internal DNS server after it uses the VPN.
After we can connect normally to the access point we need to set up OpenVPN. Again, I use 2.0 which is not available for 3.7. Use current or compile it from the sources.
Installation is pretty straight forwarded. With the ports collection of current:
# cd /usr/ports/net/openvpn
# make install clean
or
# pkg_add ftp://ftp.openbsd.org/pub/OpenBSD/ snapshots/packages/i386/openvpn-2.0.tgz
Then create /etc/openvpn and copy /usr/local/share/examples/ openvpn/easy-rsa and /usr/local/share/examples/ openvpn/sample-config/files/server.conf into it.
Then use the scripts in /etc/openvpn/easy-rsa to create the PKI and the sever/client certificates. Each client will use a SSL/TSL certificate to authenticate itself to the server and the server will use its certificate to authenticate to the clients. The official HOWTO is very clear on how to do this. The following will create the Certificate Authority, one server certificate and two client certificates:
# cd /etc/openvpn/easy-rsa
# init-config
# . ./vars
# ./clean-all
# ./build-ca
# ./build-key-server server
# ./build-key client1
# ./build-key client2
# ./build-dh
All keys are now the the /etc/openvpn/easy-rsa/keys directory. Distribute the ca.crt file to all machines in the VPN. Further each machine needs its .key and .crt files. E.g. the first client needs client1.key and client1.crt and the server needs server.key and server.crt.
So /etc/openvpn on the VPN server should look like this:
# ls /etc/openvpn
ca.crt easy-rsa server.conf server.crt server.key
dh1024.pem sample-config-files server.csr
Now were are ready for configuration and have to choose between Routing mode and Ethernet Bridging mode.
Routing mode
In Routing mode we need a tun interface. So let’s create it:
# echo “up” > /etc/hostname.tun0
# sh /etc/netstart
Verify it’s creation with ifconfig tun0. Now we edit server.conf to create a VPN. The configuration file is well commented so I will cover only the most important entries.
# more server.conf | egrep -v ‘(#|;)’ | grep ‘[a-z]’
local 192.168.1.1
port 1194
proto udp
dev tun0
ca ca.crt
cert server.crt
dh dh1024.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist /tmp/ipp.txt
push “redirect-gateway local def1”
keepalive 10 120
comp-lzo
user nobody
group nobody
persist-key
persist-tun
status /var/log/openvpn-status.log
verb 3
`dev tun0` tells OpenVPN to use the tun0 interface and Routing mode. `server 10.8.0.0 255.255.255.0` will tell it to use the 10.8.0.0/24 network as the virtual network and `push “redirect-gateway local def1”` will set up the VPN server as the default gateway for the clients. This is useful if you want to redirect all traffic through your VPN as with a wireless access point.
In my case I used /var/log for the status file and /tmp for the persistence-pool as my root filesystem is mounted read-only. Also make sure to use `dev tun0` and not `dev tun` on OpenBSD.
Now we can test the setup. Start OpenVPN on the server:
# cd /etc/openvpn
# openvpn server.conf
Mon Jul 4 22:27:11 2005 OpenVPN 2.0 i386-unknown-openbsd3.7 SSL built on Jun 29 2005
Mon Jul 4 22:27:11 2005 Diffie-Hellman initialized with 1024 bit key
Mon Jul 4 22:27:11 2005 TLS-Auth MTU parms [ L:1542 D:138 EF:38 EB:0 ET:0 EL:0 ]
Mon Jul 4 22:27:11 2005 gw 192.168.0.1
Mon Jul 4 22:27:11 2005 /sbin/ifconfig tun0 destroy
Mon Jul 4 22:27:11 2005 /sbin/ifconfig tun0 create
Mon Jul 4 22:27:11 2005 NOTE: Tried to delete pre-existing tun/tap instance—No Problem if failure
Mon Jul 4 22:27:11 2005 /sbin/ifconfig tun0 10.8.0.1 10.8.0.2 mtu 1500 netmask 255.255.255.255 up
Mon Jul 4 22:27:11 2005 TUN/TAP device /dev/tun0 opened
Mon Jul 4 22:27:11 2005 /sbin/route add -net 10.8.0.0 10.8.0.2 -netmask 255.255.255.0
add net 10.8.0.0: gateway 10.8.0.2
Mon Jul 4 22:27:12 2005 Data Channel MTU parms [ L:1542 D:1450 EF:42 EB:23 ET:0 EL:0 AF:3/1 ]
Mon Jul 4 22:27:12 2005 GID set to nobody
Mon Jul 4 22:27:12 2005 UID set to nobody
Mon Jul 4 22:27:12 2005 UDPv4 link local (bound): 192.168.1.1:1194
Mon Jul 4 22:27:12 2005 UDPv4 link remote: [undef]
Mon Jul 4 22:27:12 2005 MULTI: multi_init called, r=256 v=256
Mon Jul 4 22:27:12 2005 IFCONFIG POOL: base=10.8.0.4 size=62
Mon Jul 4 22:27:12 2005 IFCONFIG POOL LIST
Mon Jul 4 22:27:12 2005 Initialization Sequence Completed
And now the client. On the Mac I used Tunnelblick, a GUI for OpenVPN that includes OpenVPN and the tun/tap driver. I used the default openvpn.conf with these entries:
client
dev tun
remote 192.168.1.1 1194
After a successful connection you should be able to ping 10.8.0.1 (the remote end of the VPN connection) from the client. Verify that only encrypted traffic passes the VPN:
# tcpdump -i ath0 -vv
tcpdump: listening on ath0, link-type EN10MB
22:47:53.385760 192.168.1.200.49187 > 192.168.1.1.1194: udp 125 (ttl 64, id 2584, len 153)
22:47:53.386681 192.168.1.200.49187 > 192.168.1.1.1194: udp 125 (ttl 64, id 2585, len 153)
22:47:53.436540 192.168.1.1.1194 > 192.168.1.200.49187: udp 197 (ttl 64, id 23444, len 225)
22:47:53.437604 192.168.1.1.1194 > 192.168.1.200.49187: udp 197 (ttl 64, id 17819, len 225)
# tcpdump -i tun0 -vv
tcpdump: listening on tun0, link-type EN10MB
22:48:52.785529 10.8.0.6 > 10.8.0.5: icmp: echo request (id:015c seq:78) (ttl 64, id 2707, len 84)
22:48:52.785928 10.8.0.5 > 10.8.0.6: icmp: echo reply (id:015c seq:78) (ttl 64, id 45169, len 84)
22:48:53.756184 10.8.0.6 > 10.8.0.5: icmp: echo request (id:015c seq:79) (ttl 64, id 2709, len 84)
22:48:53.756548 10.8.0.5 > 10.8.0.6: icmp: echo reply (id:015c seq:79) (ttl 64, id 36423, len 84)
So the physical interface ath0 only sees UPD packets for port 1194 and does not recognize the content, the virtual interface tun0 sees ICMP echo requests and replies on the 10.8.0.0/24 network.
In order to speak to the 192.168.0.0/24 network or the internet you need to set up routes or NAT on the VPN server. You can for example tell all machines in the 192.168.0.0/24 network that they can reach the 10.8.0.0/24 network over the VPN server (192.168.0.3 in my case):
# route add -net 10.8.0.0 192.168.0.3
You can also only tell this your gateway (192.168.0.1 in my case) if you do not want to set up this route on every client. As the gateway is your default route, the clients on the 192.168.0.0/24 network will forward their packets meant to the 10.8.0.0/24 network to the gateway and the gateway will forward it to 192.168.0.3/VPN server. This will cause some extra traffic but shouldn’t matter on home networks.
You should now have a working Routing VPN.
Ethernet Bridging mode
Ethernet Bridging mode is useful if you need non-IP or broadcast traffic to pass the VPN like for IPX, network gaming or CUPS auto negotiation/detection. In Ethernet Bridging mode we need to virtually combine an ethernet interface with the virtual VPN interface to a single interface.
The official Bridging HOWTO is not very clear and very Linux and Windows centered. I had to search mailing lists and play with the settings for some hours in order to get it working on OpenBSD. So I hope that this will help any OpenBSD folks with the same problems.
At first we need to create a bridge between the virtual tun0 interface and the ethernet interface to the 192.168.0.0/24 local network (sis0). Yes, on OpenBSD it is tun0 again and not tap as it should be if you follow the HOWTO. On OpenBSD bridges are created with ifconfig and brconfig. See also bridge(4).
# more /etc/bridgename.bridge0
add sis0
add tun0
up
This will create the virtual interface bridge0 that is composed of sis0 and tun0. The style of bridgename.if(5) if comparable to hostname.if(5).
Normally you get test this with `sh /etc/netstart` but I always got some errors about tun0. The solution is to include the link0 statement in /etc/hostname.tun0:
# cat /etc/hostname.tun0
link0 up
Now bridge0 should work. Edit server.conf in order to tell OpenVPN that we want an bridge config but that we use tun0 instead of tap.
# more server.conf | egrep -v ‘(#|;)’ | grep ‘[a-z]’
local 192.168.1.1
port 1194
proto udp
dev-type tap
dev tun0
ca ca.crt
cert server.crt
dh dh1024.pem
ifconfig-pool-persist /tmp/ipp.txt
server-bridge 192.168.0.1 255.255.255.0 192.168.0.210 192.168.0.220
push “redirect-gateway local def1”
keepalive 10 120
comp-lzo
user nobody
group nobody
persist-key
persist-tun
status /var/log/openvpn-status.log
verb 3
The `dev-type tap` and `dev tun0` will do that for us. The only other difference to the Routing mode configuration is `server-bridge 192.168.0.1 255.255.255.0 192.168.0.210 192.168.0.220`. This will tell OpenVPN to act as an DHCP server for the 192.168.0.210-192.168.0.220 range on the local 192.168.0.0/24 network for the VPN clients and to use 192.168.0.1 as their default gateway (together with the `push “redirect-gateway local def1”` entry). This way, the clients will just look like “normal”,local clients on the 192.168.0.0/24 network.
The client needs only to change the `dev tun` to `dev tap` and that will do:
client
dev tap
remote 192.168.1.1 1194
Note that this is an OS X client and that OpenBSD clients will need `dev tun0` and `dev-type tap` (I guess, I have to test it with OpenBSD clients). Now connect to the VPN server and verify that all traffic is encrypted.
You now should have a bridging VPN.
Startup
In order to start OpenVPN on every boot, add the following to /etc/rc.local.
openvpn—cd /etc/openvpn—daemon—config server.conf
UPDATE:
There is now a follow-up article on improving the security settings of OpenVPN.