Friday, February 15, 2013

Using Pogoplug as a OpenVPN server - with FreeBSD and VLAN

Recently, I needed to establish a VPN between my office, a colocated server and my home office. I generally prefer building networks on my own rather than buying cheap customer grade appliances, so here is what I've used.

Router

As router, I use a Pogoplug E02. It is marketed as a "private cloud device" and basically is a Linux based NAS with Internet sharing built in. Hardware wise, it is an ARM box with 256 MB RAM, four USB ports and one Gigabit Ethernet port in a funny looking plastic enclosure, with a built-in power supply. Kind of an industrialized Raspberry Pi, if you will. The E02 is from a previous generation and no longer marketed by Pogoplug, but it is available from a number of sources for prices below $50 - Mine cost 35 Euro a piece. I spent another 11 Euros for a high-speed USB Flash stick with 4GB and 10 Euros for a Nokia CA-42 cable that I installed to access the serial console port (which I actually did not need yet, but just in case).

Switch

In order to provide me with Ethernet ports which are part of the VPN, I use the Netgear GS108E 8-port managed Gigabit Ethernet switch. At some earlier point in my life, I swore that I will never buy a Netgear device again, but at a price tag of €37, I was willing to take a chance. Sure enough, the experience with this device is not totally pleasant. Configuration requires a Windows computer (or an obscure Linux utility that I could not get to run), the Windows configuration program uses Adobe AIR (wth?), and it never just works. But, with some patience, it does.

FreeBSD

The first step to transform the Pogoplug into a useable computer is to replace the Busybox based Linux with a real operating system. This requires replacing the boot loader with a new u-boot version which can boot from USB media, a procedure that is very well documented on the platform support page for running Arch Linux on the Pogoplug E02.

As a long-time FreeBSD user, I was very happy to discover that my favorite OS would run on the device, too. Detailed and very accurate installation instructions, together with quite some pre-built packages, are available on the excellent FreeBSD for Kirkwood page. I followed these instructions and got going very quickly. I had to build a new kernel in order to add the tun device driver and make some minor adjustments for the Pogoplug hardware, but again, the instructions on Nicole's page were accurate. I tried building a newer FreeBSD release with the same patches, but I did not succeed with that and thus sticked with FreeBSD-8.1.

Router configuration

In addition to the FreeBSD base installation, the openvpn and isc-dhcp41-server packages are required. I built them on the Pogoplug myself.

The Pogoplug only has one Ethernet port, so in order to talk to two separate Ethernet segments, I use a tagged VLAN. On the untagged VLAN, the router is connected to my "normal" home network. The VPN is in a VLAN with tag 1, and the Ethernet switch is used to make some ports into members of the VPN and some members of my home network.

The relevant configuration section from my /etc/rc.conf looks like this:

ifconfig_mge0="Home-LAN-IP/24"
static_routes="vpn_router"
route_vpn_router="VPN-GW-Public-IP Home-Router-IP"
defaultrouter="VPN-GW-VPN-IP"
cloned_interfaces="vlan0"
ifconfig_vlan0="vlan 1 vlandev mge0 Home-VPN-IP"
gateway_enable="YES"

Some explanation is in order: Home-LAN-IP is the (static) IP address of the router in my home LAN. DHCP can be used as well, but I prefer having my infrastructure devices on fixed addresses. A static route named "vpn_router" is established so that packets to the VPN router, on IP address VPN-GW-Public-IP, are always routed through my home LAN gateway with IP address Home-Router-IP. For all other packets, a default route to the VPN gateway with the address VPN-GW-VPN-IP is established. A VLAN interface named "vlan0" is created and the address Home-VPN-IP is assigned to that virtual interface. Finally, IP packet forwarding is enabled.

The OpenVPN router is started from /etc/rc.conf:

openvpn_enable="YES"
openvpn_configfile="/usr/local/etc/openvpn/client.conf"

On the VLAN segment, a DHCP server is run by the way of these lines in /etc/rc.conf:

dhcpd_enable="YES"
dhcpd_flags="-q"
dhcpd_conf="/usr/local/etc/dhcpd.conf"
dhcpd_ifaces="vlan0"
dhcpd_withumask="022"

DHCP server configuration

The DHCP server configuration for the vlan0 segment is placed in /usr/local/etc/dhcpd.conf and reproduced for completeness:

option domain-name-servers VPN-GW-VPN-IP;

default-lease-time 600;
max-lease-time 7200;

log-facility local7;

subnet Home-VPN-LAN netmask 255.255.255.0 {
  range 192.168.21.100 192.168.21.120;
  option routers VPN-GW-VPN-IP;
}

Obviously, the range needs to be adapted to the network in use.

OpenVPN configuration

OpenVPN uses SSL certificates to authenticate clients and servers. Creating and maintaining a certificate authority using the standard OpenSSL command line tools is too cumbersome for me. I am using the excellent and free XCA tool which makes managing a private certficate authority (CA) rather easy. I used XCA to create a CA, a server certificate for my central VPN router as well as a client certificate for my Pogoplug. Certificates and keys must be exported to PEM files for OpenVPN to use them.

I use a fairly standard LAN-to-LAN configuration for OpenVPN which is based on the server.conf and client.conf example configuration files which are located in /usr/local/share/examples/openvpn/sample-config-files. The client configuration used on the Pogoplug looks like this:

client
dev tun
proto udp
remote VPN-GW-Public-IP 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert client.crt
key client.key
ns-cert-type server
comp-lzo
verb 3

Again, VPN-GW-Public-IP is the public IP address of the central VPN router. The client certificate and key need to be placed in the client.crt and client.key files in /usr/local/etc/openvpn/ on the Pogoplug. The root CA certificate that you've created needs to be placed in the ca.crt file in the same directory.

On the server, the OpenVPN configuration is slightly more complex. Here is the server.conf file:

port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh1024.pem
server VPN-GW-VPN-IP 255.255.255.0
ifconfig-pool-persist ipp.txt

client-to-client

push "route 0.0.0.0 0.0.0.0"
push "route Home-VPN-LAN 255.255.255.0"

client-config-dir ccd
route Home-VPN-IP 255.255.255.0

keepalive 10 120
comp-lzo
persist-key
persist-tun
status openvpn-status.log
verb 3

Again, Home-VPN-IP is the IP address of the vlan0 interface on the Pogoplug. The Home-VPN-LAN is the network address of that interface, and the "push" directive is there to push a route to that network to other clients connecting, which may choose to ignore the default route. On the server, a ccd subdirectory needs to be created in /usr/local/etc/openvpn/ to contain client-specific configuration options. Each file needs to have the name that is put into the "Common Name" attribute of the certificate used by the client. For example, I have a file named strelitzer in that directory which is the Common Name of the certificate of my Pogoplug. That file contains this:

iroute 192.168.21.0 255.255.255.0

This directive announces my VPN LAN at home to the OpenVPN router.

Switch configuration

The GS108E switch must be configured for 802.1Q VLANs in "Advanced" mode. In that mode, it is possible to individually set up the VLAN membership for each port. The default VLAN for untagged packets can also be configured on a per-port fashion.

Here is how I configured my switch so that ports 1-4 are members of VLAN 1 (VPN) and ports 4-8 are member of VLAN 2 (Home Network):

Ports 1-3 use VLAN 1 for untagged packets. Port 4 uses VLAN 1 with tagged packets and VLAN 2 with untagged packets. Ports 5-8 use VLAN 2 with untagged packets:


Finally, I configured the PVIDs for each port like so:

Done

That is basically all that is to it. I'm sure I've left out some information that might be useful. Send me email if you have trouble with any of this. It should be possible to adapt this setup to FreeBSD running on other hardware, like the Raspberry Pi. Let me know if you get something like that to run, too!