Setting Up OpenWRT As An OpenVPN Client
I wanted to set up my wireless router so that all LAN (including wi-fi) connections to it would be tunnelled through OpenVPN to a remote OpenVPN server on the Internet. This turned out to be a lot more time consuming than I wanted it to be.
OpenVPN Client With OpenWRT Router
Above is a diagram of the set-up I wanted to establish.
Set Up OpenVPN
Packages you’re going to want to install:
ip. The ip package is very important because it has the
ip route command which sets the default route after a successful tunnel has been established.
Here is my OpenVPN client settings in file
/etc/config/openvpn on my OpenWRT router:
config openvpn sample_client
option enable 1 # Set to 1 to enable
option client 1
option pull 1
# choice of tap/tun must be the same as server
option dev tap
# option dev tun
# I started with TCP but moved to UDP
# option proto tcp
option proto udp
# UDP MUST be fragmented
option tun-mtu 1200
option fragment 1000
# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
list remote "184.108.40.206 1195" # myopenvpnserver.com
# Keep trying indefinitely to resolve the
# host name of the OpenVPN server.
option resolv_retry infinite
option nobind 1 # no need to bind to specific local port
# Try to preserve some state across restarts.
option persist_key 1
option persist_tun 1
# SSL/TLS parms.
option ca /etc/openvpn/ca.crt
option cert /etc/openvpn/client-homerouter.crt
option key /etc/openvpn/client-homerouter.key
# If a tls_auth key is used on the server
# then every client must also have the key.
option tls_auth "/etc/openvpn/ta.key 1"
option dh "/etc/openvpn/dh2048.pem"
# Enable compression on the VPN link.
# Don't enable this unless it is also
# enabled in the server config file.
option comp_lzo 0
option verb 3 # Set log file verbosity.
option status /tmp/openvpn-status.log
Your OpenVPN configuration may be somewhat different depending on what certificates you use, whether you use TA or DH, whether you use compression, or TCP/UDP (but I’ll discuss TCP/UDP a little later).
Now for OpenVPN to start automatically you need to run the following command on the server:
ln -s ../init.d/openvpn /etc/rc.d/S46openvpn
This will ensure OpenVPN is started upon reboot after the network has been configured.
Finally – if you use UDP then (as I describe further down) you need to establish a static route to your VPN server out the eth1 (WAN) port so that those packets can still go where they need to go after the VPN sets a default route to itself. You can run:
ip route add 220.127.116.11/32 via 192.168.0.1
… where 18.104.22.168 should be replaced with your OpenVPN server address, and 192.168.0.1 should be replaced with your upstream router IP address.
However if you want this to happen automatically on boot then add the following to your
option 'interface' 'wan'
option 'target' '22.214.171.124'
option 'netmask' '255.255.255.255'
option 'gateway' '192.168.0.1'
It becomes necessary to edit
/etc/config/network so that the following section is added:
config 'interface' 'vpn'
option 'ifname' 'tap0'
option '_orig_ifname' 'tap0'
option '_orig_bridge' 'false'
option 'proto' 'none'
Also you will have to add the following line to your
config 'interface' 'wan' block:
option 'metric' '20'
This is so that the WAN default route becomes lower in priority to the VPN default route when the VPN is established.
This is the trickiest bit. And for me didn’t actually work until I did a reboot!
In this example the file
/etc/config/firewall is being edited:
I added a zone:
option 'name' 'vpn'
option 'input' 'ACCEPT'
option 'output' 'ACCEPT'
option 'forward' 'ACCEPT'
option 'network' 'vpn'
option 'masq' '1'
Note the ‘masq’ option. It is important that this setting is present in both the ‘vpn’ and ‘wan’ zones but not the ‘lan’ zone.
Next I added two forwarding rules:
option 'src' 'vpn'
option 'dest' 'lan'
option 'src' 'lan'
option 'dest' 'vpn'
Okay time to reboot router!
At The OpenVPN Server Side
I was running my OpenVPN on an Ubuntu server. There were a few things I had to do before everything would go smoothly, however, mostly involving the firewall and iptables.
Firstly I needed a MASQUERADE rule. My OpenVPN server was configured to be 172.17.0.1/16 (that’s the IP address to which all clients would forward packets). So anything coming from that address destined for the Internet (eth0) needed to be MASQUERADE-d. In my
/var/lib/iptables/active file (which I restore using
iptables-restore on boot I added:
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 172.17.0.0/16 -o eth+ -j MASQUERADE
I also needed, in the
*filter tables, rules to permit forwarding to/from the TAP interface:
-A FORWARD -i tap+ -j ACCEPT
-A FORWARD -o tap+ -j ACCEPT
TCP vs UDP
I started with a TCP OpenVPN client connection – this would be established fine. But I had an infuriating problem. The connection kept dying after 1-4 minutes. I would get log entries in the server like this:
Sun Sep 2 17:34:07 2012 client-homerouter/126.96.36.199:35955 [client-homerouter] Inactivity timeout (--ping-restart), restarting
Sun Sep 2 17:34:07 2012 client-homerouter/188.8.131.52:35955 SIGUSR1[soft,ping-restart] received, client-instance restarting
Sun Sep 2 17:34:07 2012 TCP/UDP: Closing socket
I never resolved this. The closest I got was pulling out tshark on the server and tcpdump on the OpenWRT router and could see that TCP-retransmission packets were being sent back to the client but would never get a response from the router. No idea what the problem was.
This seems to have been resolved with switching to UDP – at least with UDP there are no retransmissions if a packet gets dropped. However UDP simply won’t work unless data is fragmented (see below).
FRAG_IN error flags=0xffffffff: FRAG_TEST not implemented
This was turning up in my OpenVPN server log after I switched from TCP to UDP. I’d set the
fragment options in my server.conf – but on my Android phone I had not set these values. By editing my OpenVPN connection on my Android phone, I then selected menu->Advanced and then at the bottom added the extra arguments:
--tun-mtu 1200 --fragment 1000
.. and this stopped the above errors in my server log.
read UDPv4 [EHOSTUNREACH]: No route to host (code=148)
On my OpenWRT router, which was acting as an OpenVPN client, I would be getting these errors – and this happened when I switched from TCP to UDP.
The problem was this: the connection would establish fine – I could see it established in my server log. But then something curious happened. The server would send UDP traffic to the client (my router) but my client (the router) would never send any more UDP packets after the connection was established.
Eventually I realised this: when an OpenVPN client establishes a connection I make it set the default route to be through that VPN tunnel. However the UDP packets the client was sending – which were being sent to the IP address of the server – were now being sucked into the new default route (in to itself) – hence they disappeared.
This didn’t happen with a TCP connection because a connection is established once: at the beginning of the connection. Hence it didn’t matter if the default route changed mid-way through the connection – because the connection had already been established. But UDP packets are independent entities – every single one of them. So the instant the default route changed the outgoing client packets were just going into the VPN tunnel instead of out the WAN link.
This was fixed by adding another specific route. E.g. if my VPN server was 184.108.40.206 then I should add the command:
ip route add 220.127.116.11/32 via 192.168.0.1
..(where 192.168.0.1 is my upstream router/WAN gateway).
read TCPv4_CLIENT : No route to host (code=148)
This is the error I’d receive when my TCP-based OpenVPN connection would stop working. Looking back I suspect this is identical to the UDPv4 problem above – just that it would take a few minutes before causing the problem rather than right away as in the case of UDP. The solution, of course, is to add a static route to the OpenVPN host through the WAN port.
Notes For Upgrading To Attitude Adjustment 12.09
After I upgraded the router to OpenWRT Attitude Adjustment 12.09 Beta I had to re-establish a few things:
opkg install openvpn
opkg install ip
ln -s ../init.d/openvpn /etc/rc.d/S46openvpn
While this will set up the tunnel I don’t seem to be getting the default route being set to point at the tunnel anymore. I can still manually force this by issuing the following command:
ip route add 0.0.0.0/0 via x.x.x.x
…where x.x.x.x is the next-hop address of the OpenVPN server.