Saturday 20 February 2010

Remote Access using OpenVPN with DD-WRT

This is going to be a long post today...

DD-WRT is an awesome wireless router distribution.  I have had it installed on my Linksys WRT54Gv2 for quite some time (I have an ADSL modem that is bridged to the WAN port on the Linksys, so it provides the border function into my home LAN) but only in the last few days have I thought about using the VPN capability to remotely access my home lab when I have some free time at work or at a friends place and would like to access some of my files at home.

OpenVPN is an open source VPN SSL server and client that is available for Linux, Mac and Windows systems and can connect to Cisco routers too.  There is a firmware for DD-WRT that contains OpenVPN and has a pretty good interface to use assuming you don't want to do anything too hardcore.

What I wanted to do was something I thought relatively simple and the OpenVPN page has links and describes what to do, it just took a little bit of reading and checking to get things right in my situation, so I am documenting what I did - maybe it will be helpful to others in the future.

Firmware
Ensuring that you have the right firmware for your device is important, there are all sorts of warnings about doing firmware upgrades since you can "brick" your router if you do things wrongly.  All I will say here is that obviously you need  V2.4 SP1 or better with VPN capability, I'm pretty sure the standard image does not support OpenVPN - in my particular case I used dd-wrt.v24_vpn_generic.bin but please ensure you get the right firmware for your device.  The procedure to install the firmware is quite specific and nearly voodoo ritualistic but should be followed word for word to ensure that you don't break your device.

Dynamic DNS
I don't have a static IP address, and even if I did remembering it was not going to be something I really wanted to waste my memory on.  There are quite a number of Free DDNS providers and built in capability for DD-WRT to use them. The DDNS page on the DD-WRT site easily explains what to do there.

Creating Certificates
I used my ubuntu server to create the certificates used here, the process is most likely the same for other systems.  The ubuntu box isn't actually doing anything specific for the vpn, it's just handy for me to create certificates here.

I needed to install openvpn as it wasnt included in the standard server install
adam@labserver1:~$ sudo apt-get install openvpn
I am going to stick with the default 1024 bit keys as I am not sure how much space is available in the nvram on my WRT54G even though 2048 bit keys would be more secure.

Creating the Certificate Authority
The values for variables are specific to my case, feel free to modify the values to your own situation.
adam@labserver1:~$ sudo su
root@labserver1:~# cd /usr/share/doc/openvpn/examples/easy-rsa/2.0/
root@labserver1:/usr/share/doc/openvpn/examples/easy-rsa/2.0# source ./vars
NOTE: If you run ./clean-all, I will be doing a rm -rf on /usr/share/doc/openvpn/examples/easy-rsa/2.0/keys
root@labserver1:/usr/share/doc/openvpn/examples/easy-rsa/2.0# ./clean-all
root@labserver1:/usr/share/doc/openvpn/examples/easy-rsa/2.0# ./build-ca
Generating a 1024 bit RSA private key
........................++++++
...++++++
writing new private key to 'ca.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]:AU
State or Province Name (full name) [CA]:QLD
Locality Name (eg, city) [SanFrancisco]:Brisbane
Organization Name (eg, company) [Fort-Funston]:Family
Organizational Unit Name (eg, section) []:Home
Common Name (eg, your name or your server's hostname) [Fort-Funston CA]:server
Email Address [me@myhost.mydomain]:example@example.com
root@labserver1:/usr/share/doc/openvpn/examples/easy-rsa/2.0# ./build-key-server server
Generating a 1024 bit RSA private key
........................................................................++++++
.++++++
writing new private key to 'server.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]:AU
State or Province Name (full name) [CA]:QLD
Locality Name (eg, city) [SanFrancisco]:Brisbane
Organization Name (eg, company) [Fort-Funston]:Family
Organizational Unit Name (eg, section) []:Home
Common Name (eg, your name or your server's hostname) [server]:server
Email Address [me@myhost.mydomain]:example@example.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:secretpassword
An optional company name []:Family
Using configuration from /usr/share/doc/openvpn/examples/easy-rsa/2.0/openssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'AU'
stateOrProvinceName   :PRINTABLE:'QLD'
localityName          :PRINTABLE:'Brisbane'
organizationName      :PRINTABLE:'Family'
organizationalUnitName:PRINTABLE:'Home'
commonName            :PRINTABLE:'server'
emailAddress          :IA5STRING:'example@example.com'
Certificate is to be certified until Feb 20 07:43:23 2020 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Creating the DH file
root@labserver1:/usr/share/doc/openvpn/examples/easy-rsa/2.0# ./build-dh
Generating DH parameters, 1024 bit long safe prime, generator 2
This is going to take a long time
............................+.......................+.......+.+.....................+.....................................+.......................+............................................................................................................................+..........+..............+.+..............................+.....+...........................................................................................................+..........................................+.........................+................................+.......++*++*++*
Creating the User certificate
This is what will be used to identify the remote user
root@labserver1:/usr/share/doc/openvpn/examples/easy-rsa/2.0# ./build-key client1
Generating a 1024 bit RSA private key
..........++++++
...........................++++++
writing new private key to 'client1.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [US]:AU
State or Province Name (full name) [CA]:QLD
Locality Name (eg, city) [SanFrancisco]:Brisbane
Organization Name (eg, company) [Fort-Funston]:Family
Organizational Unit Name (eg, section) []:Home
Common Name (eg, your name or your server's hostname) [client1]:client1
Email Address [me@myhost.mydomain]:example@example.com

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:adifferentsecretpassword
An optional company name []:Home
Using configuration from /usr/share/doc/openvpn/examples/easy-rsa/2.0/openssl.cnf
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName           :PRINTABLE:'AU'
stateOrProvinceName   :PRINTABLE:'QLD'
localityName          :PRINTABLE:'Brisbane'
organizationName      :PRINTABLE:'Family'
organizationalUnitName:PRINTABLE:'Home'
commonName            :PRINTABLE:'client1'
emailAddress          :IA5STRING:'example@example.com'
Certificate is to be certified until Feb 20 07:45:17 2020 GMT (3650 days)
Sign the certificate? [y/n]:y


1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
Configuring OpenVPN on DD-WRT
The interface to set this up is pretty handy and can all be done through the web interface.  Navigate to the "Services Tab" and in the "OpenVPN Daemon" Box tick enable for Start OpenVPN.

I have the Start Type as "WAN Up"

In the text box titled "Public Server Certificate" I pasted in the entire output from the command below that I ran on the ubuntu box (make sure to include the BEGIN CERTIFICATE and END CERTIFICATE Lines)
root@labserver1:/usr/share/doc/openvpn/examples/easy-rsa/2.0# sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' keys/server.crt
-----BEGIN CERTIFICATE-----
Blah Blah Certificate
quite a few lines of what looks like random junk

-----END CERTIFICATE-----
In the text box titled "Public Client Cert" I pasted in the output from the command below.
root@labserver1:/usr/share/doc/openvpn/examples/easy-rsa/2.0# sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' keys/client1.crt
-----BEGIN CERTIFICATE-----
Blah Blah Certificate
quite a few lines of what looks like random junk similar but different to the server cert

-----END CERTIFICATE-----
In the text box titled "Private Client Key" the output below was pasted in.
root@labserver1:/usr/share/doc/openvpn/examples/easy-rsa/2.0# cat keys/server.key
-----BEGIN RSA PRIVATE KEY-----
Blah Blah Key
quite a few lines of what looks like random junk similar but different to the server cert

-----END RSA PRIVATE KEY-----
In the text box titled "DH PEM" The output below was pasted in.
root@labserver1:/usr/share/doc/openvpn/examples/easy-rsa/2.0# cat keys/dh1024.pem
-----BEGIN DH PARAMETERS-----
Blah blah DH
-----END DH PARAMETERS-----
The OpenVPN  Config box is very much installation specific, there are different methods available - this one is a routed (tunnel mode rather than bridging) case, to explain the details of my particular configuration:

192.168.1.0/24 is my internal LAN segment that I want to access via OpenVPN
192.168.99.0/24 is going to be the segment that remote users terminate on (basically a loopback - tun0 on the DD-WRT box - remote users will be allocated an IP on this segment)
Routing will occur on the DD-WRT box (devices on the 192.168.1.0/24 segment have the DD-WRT box as their default gateway) and remote users will have a route to 192.168.1.0/24 pushed out to them with the DD-WRT box as the next-hop (and 192.168.1.254 will be pushed as a DNS server for resolving LAN hostnames for the remote)
I'm using the default UDP Port 1154 configuration for the VPN termination and enabling compression.
The filenames and paths in the configuration match where DD-WRT stores the information we entered above

server 192.168.99.0 255.255.255.0
push "route 192.168.1.0 255.255.255.0"
push "dhcp-option DNS 192.168.1.254"


dev tun0
proto udp
keepalive 10 120
dh /tmp/openvpn/dh.pem
ca /tmp/openvpn/ca.crt
cert /tmp/openvpn/cert.pem
key /tmp/openvpn/key.pem

# Only use crl-verify if you are using the revoke list - otherwise leave it commented out
# crl-verify /tmp/openvpn/ca.crl

# management parameter allows DD-WRT's OpenVPN Status web page to access the server's management port
# port must be 5001 for scripts embedded in firmware to work
management localhost 5001
#verb is used for debug output - level 6 is quite detailed for troubleshooting problems
#telnet to the router and tail -f /var/log/messages to see a realtime trace

#verb 6
comp-lzo
Ok... Quite a lot of work on this tab - time to click Save and Click on "Administration" and select "Commands"

Now we have to allow the VPN traffic into the router for processing.  In the Command shell tab we enter these iptables rules (Remember to change these to match your particular situation)
iptables -I INPUT 1 -p udp --dport 1194 -j ACCEPT
iptables -I FORWARD 1 --source 192.168.99.0/24 -j ACCEPT
iptables -I FORWARD -i br0 -o tun0 -j ACCEPT
iptables -I FORWARD -i tun0 -o br0 -j ACCEPT
Now Click on the "Save Firewall" button and go and reboot the router.

Things to check once rebooted - the firewall is correct (telnet into the box and do "iptables --list" to see that the above settings are present and that the openvpn daemon is operational.
root@DD-WRT:~# ps | grep openvpn
  790 root      2276 S    openvpn --config /tmp/openvpn/openvpn.conf --route-up
 1340 root      1164 S    grep openvpn
Now it is time to set up the Remote Access box - in my case I have an XP laptop with a 3G Network connection that wants to connect.

The first thing to do is to install the OpenVPN Windows GUI version once this is done, we shall create a configuration in C:\Program Files\OpenVPN\Config - it is just a text file with a .ovpn extension.

# Simple OpenVPN client configuration
client
dev tun
proto udp
remote ddnsnameofdd-wrt.router 1194
resolv-retry infinite
nobind
mute-replay-warnings
ca c:\\certs\\ca.cert
cert c:\\certs\\client1.crt
key c:\\certs\\client1.key
comp-lzo
# Set the verbosity level when troubleshooting connections
#verb 6
Create a certs directory on C drive and copy across those files (ca.cert, client1.crt and client1.key) from the ubuntu box (using WinSCP on the local LAN or using a USB stick)

Now on the laptop I ensure that the LAN connection (wired and wireless is inactive) and connect to the internet

We can verify this by looking at the interface state and routing table

C:\>ipconfig /all
Windows IP Configuration

Ethernet adapter Local Area Connection:
        Media State . . . . . . . . . . . : Media disconnected

Ethernet adapter Wireless Network Connection:
        Media State . . . . . . . . . . . : Media disconnected

Ethernet adapter {0AD0400A-2C26-4AA0-B897-E97750F48671}:
        Media State . . . . . . . . . . . : Media disconnected

PPP adapter 3G:
        Connection-specific DNS Suffix  . :
        IP Address. . . . . . . . . . . . : 220.a.b.c
        Subnet Mask . . . . . . . . . . . : 255.255.255.255
        Default Gateway . . . . . . . . . : 220.a.b.c

C:\>netstat -rn
Active Routes:
Network Destination        Netmask          Gateway       Interface  Metric
          0.0.0.0          0.0.0.0        220.a.b.c  220.a.b.c      1
        127.0.0.0        255.0.0.0        127.0.0.1       127.0.0.1      1
        220.a.b.c  255.255.255.255        127.0.0.1       127.0.0.1      50
        220.a.b.d  255.255.255.255        220.a.b.c  220.a.b.c      50
        224.0.0.0        240.0.0.0        220.a.b.c  220.a.b.c      1
  255.255.255.255  255.255.255.255        220.a.b.c               3      1
  255.255.255.255  255.255.255.255        220.a.b.c               2      1
  255.255.255.255  255.255.255.255        220.a.b.c  220.a.b.c      1
  255.255.255.255  255.255.255.255        220.a.b.c               4      1
Default Gateway:         220.a.b.c
Now double click on the OpenVPN GUI icon and a connection should initiate and in a few seconds you should see an indication of a connection.

We can verify this by looking at the interface state and routing table since we should see an ip address on the 192.168.99.0/24 segment and a route to 192.168.1.0/24
C:\>ipconfig /all
Windows IP Configuration

Ethernet adapter Local Area Connection:
        Media State . . . . . . . . . . . : Media disconnected

Ethernet adapter Wireless Network Connection:
        Media State . . . . . . . . . . . : Media disconnected

Ethernet adapter {0AD0400A-2C26-4AA0-B897-E97750F48671}:
        Connection-specific DNS Suffix  . :
        Description . . . . . . . . . . . : TAP-Win32 Adapter V8 - Packet Scheduler Miniport
        Physical Address. . . . . . . . . : 00-FF-0A-D0-40-0A
        Dhcp Enabled. . . . . . . . . . . : Yes
        Autoconfiguration Enabled . . . . : Yes
        IP Address. . . . . . . . . . . . : 192.168.99.6
        Subnet Mask . . . . . . . . . . . : 255.255.255.252
        Default Gateway . . . . . . . . . :
        DHCP Server . . . . . . . . . . . : 192.168.99.5
        DNS Servers . . . . . . . . . . . : 192.168.1.254
        Lease Obtained. . . . . . . . . . : Saturday, 20 February 2010 2:42:47 PM
        Lease Expires . . . . . . . . . . : Sunday, 20 February 2011 2:42:47 PM

PPP adapter 3G:
        Connection-specific DNS Suffix  . :
        IP Address. . . . . . . . . . . . : 220.a.b.c
        Subnet Mask . . . . . . . . . . . : 255.255.255.255
        Default Gateway . . . . . . . . . : 220.a.b.c

C:\>netstat -rn
Active Routes:
Network Destination        Netmask          Gateway       Interface  Metric
          0.0.0.0          0.0.0.0        220.a.b.c  220.a.b.c      1
        127.0.0.0        255.0.0.0        127.0.0.1       127.0.0.1      1
      192.168.1.0    255.255.255.0     192.168.99.5    192.168.99.6      1
     192.168.99.1  255.255.255.255     192.168.99.5    192.168.99.6      1
     192.168.99.4  255.255.255.252     192.168.99.6    192.168.99.6      30
     192.168.99.6  255.255.255.255        127.0.0.1       127.0.0.1      30
   192.168.99.255  255.255.255.255     192.168.99.6    192.168.99.6      30
        220.a.b.c  255.255.255.255        127.0.0.1       127.0.0.1      50
        220.a.b.d  255.255.255.255        220.a.b.c  220.a.b.c      50
        224.0.0.0        240.0.0.0        220.a.b.c  220.a.b.c      1
  255.255.255.255  255.255.255.255        220.a.b.c               3      1
  255.255.255.255  255.255.255.255        220.a.b.c               2      1
  255.255.255.255  255.255.255.255        220.a.b.c  220.a.b.c      1
  255.255.255.255  255.255.255.255        220.a.b.c               4      1
Default Gateway:         220.a.b.c
Now to confirm that we can connect to a device on the LAN from the VPN Client
C:\>ping 192.168.1.250
Pinging 192.168.1.250 with 32 bytes of data:
Reply from 192.168.1.250: bytes=32 time=1722ms TTL=63
Reply from 192.168.1.250: bytes=32 time=856ms TTL=63
Reply from 192.168.1.250: bytes=32 time=983ms TTL=63
Reply from 192.168.1.250: bytes=32 time=669ms TTL=63

Ping statistics for 192.168.1.250:
    Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
    Minimum = 669ms, Maximum = 1722ms, Average = 1057ms
C:\>telnet 192.168.1.250
2610>exit

Connection to host lost.


Success! Please note that the high latency is mainly due to where I am doing the testing has poor mobile coverage and is using GPRS rather than a decent 3G connection.

If things do not appear to work:
  • Check OpenVPN is running (ps | grep openvpn)
  • Check that the firewall configuration is correct
  • Turning on the verbosity and checking the logs is very helpful
  • Verify that the DDNS config is working - if you do a nslookup on the DDNS hostname from the remote, does it actually match the WAN IP address of the server? The DD-WRT control panel displays the WAN IP.

No comments:

Post a Comment