Wednesday, October 1, 2014

OpenVPN - Windows Client with Raspberry Pi Server on Arch Linux


By the title, you should have gathered that this is a very specific case of using OpenVPN. This might be adaptable to variations on either end, but my intent is to lay out all the steps to get OpenVPN working for just this one scenario. If it weren't such a chore to sift through all the "generic" documentation that includes so much extra stuff that doesn't apply to any given scenario, this probably wouldn't even be worthwhile, but sometimes, it helps to just have all the info for a single example in one place... so here goes.

Server Setup

For more generic, more broad instructions on how to set up OpenVPN on ArchLinux, see this page:

For these instructions, the hardware and OS are...
  • Platform: Raspberry Pi B+
  • OS: ArchLinux 
    • More specifically, the output from uname -a is:
      • Linux alarmpi 3.12.26-2-ARCH #1 PREEMPT Sun Aug 31 22:36:40 MDT 2014 armv6l GNU/Linux

Installing Server Packages

  • OpenVPN
    • COMMAND: pacman -S openvpn
  • Easy RSA
    • COMMAND: pacman -S easy-rsa

Creating CA, Certificates, and Keys

 Create a CA certificate to sign other certificates, create a server certificate, and create at least one client certificate.  These instructions are already documented somewhat clearly and succinctly here:

The remainder of these instructions assume the various certificate and key files have been created with these names:
  • ca.crt  - The public certificate for the Certificate Authority
  • dh2048.pem - The diffie-hellman encryption key (which may also be a weaker/faster 1024 bit key)
  • raspiserver.crt - The public certificate signed by the CA for the OpenVPN server on Raspberry Pi
  • raspiserver.key - The private key signed by the CA for the OpenVPN server on Raspberry Pi
  • winclient.crt - The public certificate signed by the CA for the OpenVPN client on Windows
  • winclient.key - The private key signed by the CA for the OpenVPN client on Windows
  • ta.key - The tls (ssl) hash used by both client and server OpenVPN processes

Configuring OpenVPN on the Arch Linux  Server

When the package manager installs OpenVPN, it creates a new directory named /etc/openvpn which will contain a configuration file for each instance of OpenVPN.  This only describes the process for setting up one "server" instance, so there will just be one configuration file in /etc/openvpn named server.conf.  Create it by copying /usr/share/openvpn/examples/server.conf to /etc/openvpn/

Copy the server side certificate and key files to the /etc/openvpn directory (which is where OpenVPN will look for them, by default).  Alternatively, each of the certificate and key files can be kept in another location and referenced in /etc/openvpn/server.conf file using a fully specified file path like /root/openvpnkeys/ca.crt.  However, there may be some file permission issues to sort out if these files are not copied to /etc/openvpn/.

Next, edit /etc/openvpn/server.conf and modify the defaults.
  • REPLACE:  cert server.crt
    • WITH: cert raspiserver.crt
    • REASON: to match the filename specified above
  • REPLACE: key server.key
    • WITH: cert raspiserver.key
    • REASON: to match the filename specified above 
  • REPLACE: dh dh1024.pem
    • WITH: dh dh2048.pem
    • REASON: to match the filename specified above 
  • UNCOMMENT: ;tls-auth ta.key
    • REASON: to make OpenVPN use the ta.key file
 Also, here are a few brief notes on other modifications to /etc/openvpn/server.conf that may be useful.
  • port 1194 - Change this if you'd like to use OpenVPN via a different network port.
  • proto udp - Change this to "proto tcp" if reliability is more important than speed for the VPN.
  • push "route" - uncomment this line if the primary network on which the Raspberry Pi device / server is connected is the network.  Note: More on this later in the section on iptables rules.
  • user nobody - uncomment this to reduce the potential security risk when/if there are vulnerabilities discovered in the OpenVPN software
  • group nobody - also uncomment this to reduce security exposure

Adding OpenVPN to the System Startup, and Starting/Stopping the Service

OpenVPN isn't anything too different than a normal service using a systemctl based Linux system, except that the service name is qualified with a suffix reference to the config file.  This makes it possible to start more than one OpenVPN instance (e.g. an OpenVPN server and several OpenVPN clients, or several different OpenVPN servers with different access rules or routes).  The following example commands assume the configuration file is called server.conf
  • systemctl enable openvpn@server
  • systemctl start openvpn@server
  • systemctl stop openvpn@server
 Note: If there were another config file named specialaccess.conf, the systemctl commands would be systemctl {command} openvpn@specialaccess


Configuring Linux Packet Forwarding and iptables Masquerading Firewall

In most cases, OpenVPN will "own" a virtual network with a range of address from which the it will issue (via DHCP) an ip address and routing information to a client upon connection.  It is not likely that the subnet used by the OpenVPN server and its virtual network device (TUN/TAP adapter) will be the same subnet configured on the wireless or wired hardware network adapter (wlan0, eth0, etc).  In order to transfer packets to and from other networks, the Linux kernel and firewall must be configured for packet forwarding.  This requires the following few steps:
  • Enable the kernel packet forwarding
    • TEMPORARY:  echo 1 > /proc/sys/net/ipv4/ip_forward
    • PERMANENT: edit  /etc/sysctl.d/99-sysctl.conf, add the following line, and reboot:
      • net.ipv4.ip_forward=1
  • Add masquerade packet forwarding rules to iptables
    Note: This example assumes the "real" network adapter on the Raspberry Pi device is wlan0, and the OpenVPN virtual network adapter is tun0. 
    Adjust the input and output adapters in these rules as necessary.
    For more details, see:
    • /sbin/iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
    • /sbin/iptables -A FORWARD -i wlan0 -o tun0 -m state --state RELATED,ESTABLISHED -j ACCEPT
    • /sbin/iptables -A FORWARD -i tun0 -o wlan0 -j ACCEPT
  • After testing that the forwarding/masquerading rules work, add them to /etc/iptables/openvpn.rules (or some other rules file of your choosing) so that they will be applied again whenever iptables is started.
    • If there isn't already an /etc/iptables/iptables.rules file, then
      • iptables-save > /etc/iptables/iptables.rules
    • If the iptables service is not already enabled to start at boot time...
      • systemctl enable iptables


Windows OpenVPN Client Setup

 Note: There is more information about this at: but the page covers both client and server installation of OpenVPN on Windows, so all of the instructions there do not necessarily apply to the Windows client side setup.
  • Download OpenVPN GUI and install
  • Create the following directory (because the installer apparently doesn't):  
    • c:\Program Files\OpenVPN\config
  • Copy the client side certificate and key files to the c:\Program Files\OpenVPN\config directory (or another directory if desired.  Config will refer to them by full path anyway.).
    Reminder: These files were generated on the Linux server, so use Filezilla, Putty pscp, or a similar tool to transfer them to the Windows machine.
    • ca.crt
    • dh2048.pem
    • winclient.crt
    • winclient.key
    • ta.key
  • Copy the example OpenVPN client.conf file from the Linux server /usr/share/openvpn/examples/client.conf to c:\Program Files\OpenVPN\config and rename it to client.ovpn
    • Reminder: Also use Filezilla, Putty pscp, or a similar tool for this server-to-Windows transfer.
    • Note: Config files for use by the Windows OpenVPN GUI tool must have an extension of .ovpn or OpenVPN GUI won't "see" them.
  • Modify the client.ovpn config file to use the correct server address.
    • e.g. remote my.raspberrypi.linuxbox 1194
  • Open the Windows Control Panel "Network and Sharing Center", click on "Change adapter settings", and rename the network adapter with device name "TAP-Windows Adapter v9" from "Local Area Connection (3)" (or whatever it was named) to a simpler name with no spaces, like "openvpntap"
  • Test the client configuration first from a command prompt before trying to connect via OpenVPN GUI because if the connection fails in OpenVPN GUI, there is no way to see the error messages.
  • ALERT: If the server is configured with any routes to "push" down to a connecting client, the OpenVPN GUI MUST BE RUN AS ADMINISTRATOR on Windows systems that require UAC (e.g. Vista, Windows-7).  A possible alternative is to set up OpenVPN GUI to run under a special account that is added to the local "Network Operators" group (The various ways to run programs as admin or using a special user will not be covered here since that would be a bit outside the scope of this post, and it's documented plenty of places already... for instance: HERE, or HERE).  
    • Note: The error message that occurs if OpenVPN GUI is _not_ run with admin rights, and the route-method exe / route-delay 2 directives are _not_ in the client configuration is similar to the following log excerpt:
      • MANAGEMENT: >STATE:1412177588,ADD_ROUTES,,,
        C:\Windows\system32\route.exe ADD MASK
        ROUTE: route addition failed using CreateIpForwardEntry: Access is denied.   [status=5 if_index=52]
        Route addition via IPAPI failed [adaptive]
        Route addition fallback to route.exe
    • Note: The error message that occurs if OpenVPN GUI is _not_ run with admin rights, and the route-method exe / route-delay 2 directives _are_ in the client configuration is similar to the following log excerpt:
      • MANAGEMENT: >STATE:1412177074,ADD_ROUTES,,,
        C:\Windows\system32\route.exe ADD MASK
        env_block: add PATH=C:\Windows\System32;C:\WINDOWS;C:\WINDOWS\System32\Wbem
        ERROR: Windows route add command failed: returned error code 1
    • See:
  • Connect/Disconnect using OpenVPN GUI.
  • OPTIONAL: Configure OpenVPN to pass SMB traffic to connect network shares, etc.
    • In order to allow SMB packets to pass through the OpenVPN adapter, it is necessary to add a gateway route, so add the following route in the server's OpenVPN configuration, (and don't forget to restart it and be sure the client re-connects after the change):
      • push "route vpn_gateway 999"
    • Verify the change by checking for the route on the client with weight 999, which should appear near the top of the output from the "route print" command.  Then check to see if SMB (Windows) shares are accessible via addresses that connect through OpenVPN.
    • See:
  • OPTIONAL: Configure the OpenVPN client to automatically retry a connection without ever giving up (might be desirable for a laptop that should reconnect whenever it is resumed from sleep/suspend state).

OpenVPN Clients for Other Operating Systems