Road warrior setup: OpenVPN server and client

We’ll setup an OpenVPN server on a location where we can control the incoming network traffic, at home for instance.

Setting up the OpenVPN server

OpenVPN comes with a fully described server-configuration file, but I’ll just discuss the setup that has proven sufficient to me.

Below the full openvpn.conf.

# /etc/openvpn/openvpn.conf
port 1194
proto tcp-server
mode server
tls-server
dev tun0
ca cacert.pem
cert server.pem
key server.key
dh dh2048.pem

# These options are for a basic setup that 
# typically serves some mobile clients (single hosts) 
# that will have all their network traffic routed 
# through the VPN.
server 172.16.17.0 255.255.255.0
ifconfig-pool-persist /etc/openvpn/ipp.txt
push "route 192.168.2.0 255.255.255.0"
push "redirect-gateway"
push "dhcp-option DNS 192.168.2.1"
client-to-client

keepalive 5 15
tls-auth ta.key 0 
auth SHA1
comp-lzo
max-clients 20
user nobody
group nogroup
persist-key
persist-tun
status openvpn-status.log
log-append  /var/log/openvpn/openvpn.log
verb 3
mute 20

You might wanna run your VPN on port 443 (or use portforwarding from 443 on your router to the VPN port): many firewalls will allow traffic from your client inside a walled domain through port 443. Port 80 can also be used but traffic over that port might be subject to inspection, and blocked if not clearly determinable as regular webtraffic.

Use the certificates as created in the previous blog. Copy them over to /etc/openvpn or use the correct paths in the configuration file.

dev tun0 and server form a safe modus operandi together, with a private class network for your vpn net. tun specifies the tun device which operates on the network layer (OSI model layer 3, think IP packets). Really cool things can be done using the combination dev tap and server-bridge. tap specifies the tap device which operates on the link layer (OSI 2, ethernetframes). By using tap you can for instance bridge two IP subnets, or use IPX(SPX) on the ‘ LAN’  that is formed by all connecting clients. That means you can play games from back-in-the-days like Descent or Red Alert over OpenVPN with tap/server-bridge setup! Or connect to that old Windows-for-Workgroups box (‘do not power down!’) using Netbios.

Also, tun/tap are virtual devices that happily run in virtual machines. That means you can now can connect your remote vm to your LAN.

Protocol udp seems to perform best when using OpenVPN, but tcp is more accepted by firewalls. Tunneling is basically wrapping IP packets in IP packets, and this might cause some weird behaviour when using TCP: the wrapping of a TCP/IP packet might mess up the adaptive-timeout-setting of the wrapped packet, causing all kinds of unwanted network anomalies. However, never seen this happen.

 

Setting up the routing on the host

This might be the most difficult part of setting up OpenVPN, so it might help to take a look at what’s happening when an IP packet is travelling through the tunnel and LAN (A).

Let’s assume we did not set up OpenVPN on the router (192.168.2.1)  itself, but on a Raspberry Pi located somewhere on the LAN (192.168.2.3). For this, we have to setup port-forwarding on the router (B), from port 443 on the router to port 1194 on the Raspberry.

OpenVPN is listening on port 1194 on the Raspberry, and will decrypt incoming packets. It will deliver those decrypred packets to tun0, the virtual network adapter. Now here’s a funny thing: since OpenVPN is master of tun0, packets are only visible to the kernel when OpenVPN is done. That means that normal netfiltering does not apply to tun0 (C). If you set client-to-client in the server config of OpenVPN, netfiler INPUT rules to tun0 are not taken into consideration. If you leave client-to-client out of the server-config, you are in control on what to accept on tun0.

We need FORWARD rules (D) to transfer the packets from tun0 to eth0. This is where you can restrict/allow clients based on source- or destination address.

One more thing needs to be done: if the packets are not coming from a known destination, we must MASQUERADE them here before they enter the LAN, in order to be able to handle the response packets: those packets must be delivered back to the OpenVPN server. If we don’t masquerade, the response packet will be routed by the gateway to the internet and be dropped.

blog_routing

Once allowed to the LAN, the packet follows standard routing procedures (EF) to find its destination (192.168.2.x).

After being handled by the service the response packet does not know where to go (G): the source of the incoming packet is now the destination-address, and this can be anything since the packet can have come from anywhere (however, we did masquerade them, remember). The gateway is consulted for unknown destination-addresses, and this is the reason why you need to setup static routes (H) from the gateway back to the OpenVPN server on the Raspberry: setup a route to the Raspberry for packets with the tunnel endpoint as masqueraded destination, and/or setup routes for all known non-local destinations (e.q. LAN’s that are on the other end of the OpenVPN tunnel) for which you did not do masquerading.

Now the response-packet is safely delivered to the Raspberry on eth0, simple FORWARD rules (I) will launch it into the tunnel. From here on there is no difference anymore between the encrypted reponse-packet and any other packet leaving the LAN through the router (J) into the interwebs (K).

So that leaves us with the simplest set of iptables rules. In following blogposts I will show a more complex example of routed LANs and controlling access for clients.

#!/bin/sh

# Interfaces
LAN_IF="eth0"
VPN_IF="tun0"

# Networks
LAN="192.168.2.0/24"
VPN="172.16.17.0/24" 

# Ports
VPN_PORT="1194"

# Clean old firewall
iptables -F
iptables -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X

# Load IPTABLES modules for NAT and IP conntrack support
modprobe ip_conntrack
modprobe ip_conntrack_ftp
echo 1 > /proc/sys/net/ipv4/ip_forward

# Setting default filter policy
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Unlimited access to loop back
iptables -A INPUT -i lo -j ACCEPT

# Open VPN port 
iptables -A INPUT -i $LAN_IF -m state --state NEW -p tcp --dport $VPN_PORT -j ACCEPT

# Not applicable when using 'client-to-client'
iptables -A INPUT -i $VPN_IF -j ACCEPT
# VPN clients can travel to LAN and vice versa
iptables -A FORWARD -i $VPN_IF -o $LAN_IF -j ACCEPT
iptables -A FORWARD -i $LAN_IF -o $VPN_IF -j ACCEPT

# Make sure the response packets can find their way back to the VPN
iptables -t nat -A POSTROUTING -s $VPN -o $LAN_IF -j MASQUERADE

Setting up the OpenVPN clients

Clients will need an .ovpn file together with cacert.pem, ta.key and their own client.pem and corresponding client.key, in this case named laptop.pem/key.

# /somewhere/laptop.ovpn
client
dev tun0
proto tcp
remote ip-or-vpn-server-address 443
resolv-retry infinite
nobind
persist-key
persist-tun
;http-proxy-retry
;http-proxy isa.proxy.intranet basic auth 
;http-proxy localhost 3128
mute-replay-warnings
ca cacert.pem
cert laptop.pem
key laptop.key
ns-cert-type server
tls-auth ta.key 1
auth SHA1
cipher BF-CBC
comp-lzo
verb 3
mute 20

When behind a proxy the easiest way to connect to the OpenVPN server is by configuring the proxy in the client.ovpn. It is however possible to setup a proxy-chain with cntlm as authenticating proxy, but this will make the routing, pushed from the OpenVPN server, more complex. So don’t go there. OpenVPN client is even capable of connecting through NTLM-authenticated proxies, so really there is no need for cntlm.

In the end, when all is setup, the log of the client should look something like:

...
Sat Feb 27 22:24:14 2016 TUN/TAP device tun0 opened
Sat Feb 27 22:24:14 2016 TUN/TAP TX queue length set to 100
Sat Feb 27 22:24:14 2016 do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
Sat Feb 27 22:24:14 2016 /sbin/ip link set dev tun0 up mtu 1500
Sat Feb 27 22:24:14 2016 /sbin/ip addr add dev tun0 local 172.16.17.10 peer 172.16.17.9
Sat Feb 27 22:24:14 2016 /sbin/ip route add 12.345.678.90/32 via 192.168.2.1
Sat Feb 27 22:24:14 2016 /sbin/ip route del 0.0.0.0/0
Sat Feb 27 22:24:14 2016 /sbin/ip route add 0.0.0.0/0 via 172.16.17.9
Sat Feb 27 22:24:14 2016 /sbin/ip route add 192.168.2.0/24 via 172.16.17.9
Sat Feb 27 22:24:14 2016 /sbin/ip route add 172.16.17.0/24 via 172.16.17.9
Sat Feb 27 22:24:14 2016 Initialization Sequence Completed

One thought on “Road warrior setup: OpenVPN server and client

Leave a comment