DD-WRT OpenVPN 101

DEPRECATED

This document is a bit old. It still works. But I created a new setup on my Synology NAS. And it is a better setup. I now better understand openssl and how to configure it. There are a few things I would probably change in this document. Plus as nice as DD-WRT may be, it is open source and free. Those nice folks do not have the same resources as Synology. My DD-WRT OpenSSL package is a bit out of date and so is my OpenVPN package. Synology isn't the latest and greatest either. But it is more current. And it is more likely to be updated before DD-WRT.

Please use my Synology OpenVPN setup guide.

Read the Docs

The official DD-WRT documentation (and this doc) is very good.  And the official OpenVPN documentation covers a lot more detail.  Also refer to the Wikipedia article on X.509.  This document just covers the steps I needed to perform and does not add a lot of explanation.

Backup DD-WRT

Backup your DD-WRT configuration before you start changing anything.

Routing (tun) vs Bridging (tap)

Routing or tunneling encapsulates the data over OSI L3.  I am using this method.  One reason is that the iPhone does not support bridging.  With routing you need to create a new private subnet for the VPN server.

Bridging encapsulates the data over OSI L2.  You are extending your local LAN subnet across the VPN.  The default DD-WRT subnet is 192.168.1.0/24.  You create a TAP interface on the server and the client.  As stated above this is not supported on Apple IOS devices.  And from what I have read it can be rather difficult to setup on Windows as well.

File Formats

This is provided as a reminder to myself.  With OpenSSL you can convert from almost any format to another.  This information is from Wikipedia, ssl.com, openssl.org,  and a few other sources.

  • *.pem - (Privacy-enhanced Electronic Mail) Base64 encoded DER certificate, enclosed between "----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----".  Certificate container format that may include just the public certificate, or the entire certificate chain including the public key, private key, and root certificates.  
    • Base64 (ASCII) Encoding - Group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation.
    • DER Encoding (Binary) - DER is a restricted variant of BER for producing unequivocal transfer syntax for data structures described by ASN.1.
      • X.690 is an ITU-T standard specifying several ASN.1 encoding formats:
      • Basic Encoding Rules (BER)
      • Canonical Encoding Rules (CER)
      • Distinguished Encoding Rules (DER)
  • *.cer, *.crt - X.509 certificate (Base64 (ASCII) or DER (binary) encoded) - PEM formatted file with a different extension.  Recognized by Windows explorer as a certificate.
    • *.der - (DEPRECATED) - Binary DER encoded certificates.  These may also use the "*.cer" or "*.crt" extensions.
  • *.key - This is the PEM formatted file containing just the private key.
  • *.p7b *p7c, *.spc - PKCS#7 SignedData structure without data, just certificate(s) or CRL(s).  (Certificate Revocation List)
  • *.crl - Certificate Revocation List
  • *.csr - Certificate Signing Request - Submit this to the CA.  Contains some or all of the key details (subject, organization, state, OU, CN, etc) and the public key.
  • *.stl, *.ctl - Certificate Trust List (MS IIS)
  • *.sst - Microsoft Serialized Certificate Store
  • *.p12 - PKCS#12 - May contain certificate(s) public and private keys.  This is password protected.  
  • *.pfx - PFX, predecessor of PKCS#12.  Usually contains data in PKCS#12 formate with PFX files generated in IIS.)

The Environment

I am using a non-standard port.  My Aunt has a Xfinity wireless router.  The firewall on that isn't very good.  I have setup maximum security on it but it doesn't allow for exceptions or specific rules.  But it does allow 500/UDP GRE (Generic Routing Encapsulation) VPNs.  So I will use that port for my OpenVPN configuration.  My main laptop runs Windows.  I will be using the Windows setup steps.  I will be creating client files for my iPhone, Android tablet, Nexus tablet, and my Windows laptop.  At the time of this writing I installed version 2.3.11 (64 bit) for Windows Vista and later.  These directions assume you have already setup Dynamic DNS for your router's public IP address or you have a static IP address.

Easy-RSA Certification Creation

From an Administrator command prompt switch to the easy-rsa directory.

  • C:\Program Files\OpenVPN\easy-rsa

Perform the following steps.  I have VIM and GOW installed on my Windows box.

  • init-config <ENTER>  (This will copy the vars.bat.sample to vars.bat.)
  • vim vars.bat  (Edit the following lines as appropriate.)

set KEY_COUNTRY=US
set KEY_PROVINCE=IL
set KEY_CITY=Chicago
set KEY_ORG=OpenVPN
set KEY_EMAIL=zaphod@example.com
set KEY_CN=OpenVPN-CA
set KEY_NAME=Zaphods Widgits
set KEY_OU=Zaphods
set PKCS11_MODULE_PATH=changeme (Ignore)
set PKCS11_PIN=1234  (Ignore)

  • vars <ENTER>  (This will source the environmental variables.)
  • clean-all <ENTER>  (Deletes anything in .\keys\* and recreates the index.txt and serial files in .\keys.)
  • build-ca <ENTER>  (Builds the Certificate Authority (CA) certificate (.\keys\ca.crt) and key (.\keys\ca.key).  This allows us to sign our certificates.)

WARNING: can't open config file: /etc/ssl/openssl.cnf
Loading 'screen' into random state - done
Generating a 1024 bit RSA private key
..............++++++
...++++++
writing new private key to 'keys\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]:
State or Province Name (full name) [IL]:
Locality Name (eg, city) [Chicago]:
Organization Name (eg, company) [OpenVPN]:
Organizational Unit Name (eg, section) [Zaphods]:
Common Name (eg, your name or your server's hostname) [OpenVPN-CA]:
Name [Zaphods Widgits]:
Email Address [zaphod@example.com]:

  • vars <ENTER> (re-source variables)
  • build-key-server server <ENTER>  (You can use any name, but using 'server' is easier.  This creates the server crt and key and csr.  You MUST USE 'server' as the CN in the example below.  Edited to highlight the important bits.)

Country Name (2 letter code) [US]:
State or Province Name (full name) [IL]:
Locality Name (eg, city) [Chicago]:
Organization Name (eg, company) [OpenVPN]:
Organizational Unit Name (eg, section) [Zaphods]:
Common Name (eg, your name or your server's hostname) [OpenVPN-CA]:server
Name [Zaphods Widgits]:
Email Address [zaphod@example.com]:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:******* (Optional - used by revocation)
An optional company name []:
WARNING: can't open config file: /etc/ssl/openssl.cnf
Using configuration from openssl-1.0.0.cnf
Loading 'screen' into random state - done
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'US'
stateOrProvinceName :PRINTABLE:'IL'
localityName :PRINTABLE:'Chicago'
organizationName :PRINTABLE:'OpenVPN'
organizationalUnitName:PRINTABLE:'Zaphods'
commonName :PRINTABLE:'server'
name :PRINTABLE:'Zaphods Widgits'
emailAddress :IA5STRING:'zaphod@example.com'
Certificate is to be certified until Jul 8 21:06:12 2026 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

C:\Program Files\OpenVPN\easy-rsa>

Create the Client Keys

You can use the same client key and crt files on every client.  But it is more secure to use unique keys.  This allows for client revocation.  You should use unique identifiable names for each client.  You MUST use the client name for the CN name during the file creation process.  You can come back to this section and create more client keys at any time.  This will create three files in the keys directory.  (*.crt, *.key, *.csr)

  • vars <ENTER>
  • build-key iphone <ENTER>  (Replace iphone with a unique name for each client.  Use the same name in commands below for the CN.)

Country Name (2 letter code) [US]:
State or Province Name (full name) [IL]:
Locality Name (eg, city) [Chicago]:
Organization Name (eg, company) [OpenVPN]:
Organizational Unit Name (eg, section) [Zaphods]:
Common Name (eg, your name or your server's hostname) [OpenVPN-CA]:iphone
Name [Zaphods Widgits]:
Email Address [zaphod@example.com]:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:******* (Optional)
An optional company name []:
WARNING: can't open config file: /etc/ssl/openssl.cnf
Using configuration from openssl-1.0.0.cnf
Loading 'screen' into random state - done
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
countryName :PRINTABLE:'US'
stateOrProvinceName :PRINTABLE:'IL'
localityName :PRINTABLE:'Chicago'
organizationName :PRINTABLE:'OpenVPN'
organizationalUnitName:PRINTABLE:'Zaphods'
commonName :PRINTABLE:'iphone'
name :PRINTABLE:'Zaphods Widgits'
emailAddress :IA5STRING:'zaphod@pahoehoe.net'
Certificate is to be certified until Jul 8 22:36:47 2026 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

C:\Program Files\OpenVPN\easy-rsa>

Repeat as necessary for each client.

Create the Diffie Hellman Parameters

If this was a Linux server I would use a 2048 bit key.  This step will create the 'dh1024.pem' file.  To change this to 2048 bits edit 'vars.bat' and change the 'KEY_SIZE' variable from 1024 to 2048.  This will also change the output file from 'dh1024.pem' to 'dh2048.pem'.

  • vars <ENTER>
  • build-dh <ENTER>

Create the TLS Authentication File

This isn't part of the easy-rsa setup.  But while we are creating all of our files on our Windows box we may as well create this file as well.  I am copying this to the keys directory just to keep all of the files together.

  • cd ..\bin
  • openvpn.exe --genkey --secret ta.key
    • --genkey:  Generate a random key to be used as a shared secret, for use with the --secret option.
    • --secret file:  Write the key to a file.
  • move ta.key ..\easy-rsa\keys\ta.key
    • server config = tls-auth ta.key 0
    • client config = tls-auth ta.key 1
    • iphone = key-directive 1 (comment out tls-auth)

List of Files

All of these files are in the keys directory.  This is just the relevant files.  The "*.csr" files are not required anymore.

Filename Needed By Purpose Secret
ca.crt server & all clients Root CA Certificate No
ca.key Key Signing Machine Only Root CA Key Yes
dh{n}.pem server only DH Parameters No
server.crt server only Server Certificate No
server.key server only Server Key Yes
iphone.crt client 1 only (iphone) Client 1 Certificate No
iphone.key client 1 only (iphone) Client 1 Key Yes
ta.key server & all clients OpenVPN TLS Auth Yes

Setup the DD-WRT Gateway

Log into the DD-WRT web GUI.  Go to 'Services // VPN' and enable the 'OpenVPN Server/Daemon'.  I am using the WAN UP start type and configuring this as a daemon.  Copy the files we created via easy-rsa to the server.  Simply copy and paste the Base64 encoded sections of each file.  See the example below.  Most of the file has been replaced by '........'.

-----BEGIN CERTIFICATE-----  (Start Copy & Paste Here)
MIID1DCCAz2gAwIBAgIJAKs5r3xYQISKMA0GCSqGSIb3DQEBBQUAMIGjMQswCQYD
........
G0t7SngHbrooGimTgkuAALqvwTIO3mLOk52f10rQC5OoG6s5pClP1eNsWnr+Kxs3
mLvuSsTEx7Kts0R9ed8rBje4EB0PRhpT
-----END CERTIFICATE-----  (End Copy & Paste Here)

Box Name File to Insert
CA Cert ca.crt
Public Server Cert server.crt
Private Server Key server.key
DH PEM dh1024.pem
Additional Config See Server Config Below
TLS Auth Key ta.key
Certificate Revoke List crl.pem (If exists to revoke client X)

At this time the 'clr.pem' file does not exist.  If we revoke a client in the future we can add the 'crl.pem' file.

  • vars <ENTER>
  • revoke-full clientX <ENTER>  (Where clientX is the name of one of the clients.)

Server Config

OpenVPN includes a fully annotated sample configuration file.  I am configuring the server using the 'additional config' box.  This replicates how an OpenVPN server would be setup on a Linux box.  The results are the same using the web GUI or the command line.  See the config by running 'nvram get openvpn_config' from the DD-WRT command line.

Many sites recommend using 'push "dhcp-options DNS x.x.x.x"'.  I am not using that setting.  If I use that option I cannot get DNS working.  I suspect I have some strange setting in my DHCP setup.

I am using the 'push "redirect-gateway def1"' on the server.  This forces all traffic over the VPN.  You can use this option on the client side by removing the 'push' part.  Feel free to test this option using 'tcpdump -nl -i tun0' on your DD-WRT router.  Or by simply heading to 'ipchicken.com' or 'whatismyip.com'.

  • C:\Program Files\OpenVPN\sample-config\server.ovpn

There are two networks that connect over the internet (WAN).

  • Local LAN = 192.168.1.0/24 (DD-WRT Default - Update with your subnet)
  • OpenVPN Private Routing = 10.2.192.0/24 (Use whatever you like)

# Push route to clients for local LAN subnet
push "route 192.168.1.0 255.255.255.0"
# Set subnet mode (net30, p2p, subnet)
topology subnet

# VPN Server Subnet - OpenVPN uses x.x.x.1
# Clients use the remaining IPs
server 10.2.192.0 255.255.255.0

# Listen on non-standard port (default 1194)
port 500
# Set protocol tcp or udp
proto udp
# Set device (tunX|tapX|null) server/client identical
# tun - L3 // tap - L2
dev tun0
# keepalive n m = ping n ping-restart x
# ping every 10 sec // restart after no ping in 120 sec
keepalive 10 120
# path to certs and keys - hard coded dd-wrt paths
dh /tmp/openvpn/dh.pem
ca /tmp/openvpn/ca.crt
cert /tmp/openvpn/cert.pem
key /tmp/openvpn/key.pem
# Additional layer HMAC auth on top of TLS control

# channel to protect against DoS attacks
# server must be  0 // client 1
tls-auth /tmp/openvpn/ta.key 0
# Compression mode (yes|no|adaptive (default) )
comp-lzo adaptive
# Allow multiple clients with same CN to connect concurrently
# duplicate-cn
# Route all traffic over VPN - NOT split tunnel
# 1. create static route for remote address which forwards
#    to pre-existing default gateway
# 2. delete the default gateway route
# 3. Set new def gateway to be the VPN endpoint address
# local - both openvpn servers connected via common subnet (wireless)
#         causes step 1 to be omitted
# def1 - override def gateway (0.0.0.0/1,128.0.0.0/1) does not wipe
#        out original def gateway
push "redirect-gateway def1"

# Encrypt data channel packets
# cipher alg - server/client must match
# defaults to BF-CBC 128 bit
# openvpn --show-ciphers (to list ciphers)
cipher AES-256-CBC
# Authenticate packets with HMAC (message digest algorithm)
# auth alg - server/client must match
# defaults to sha1
# openvpn --show-digests (to list digests)
auth sha1

# Logging verbosity (services/services/syslogd)
# 0 silent except fatal
# 4 reasonable for general usage
# 5, 6 - debug
# 9 - extremely verbose
verb 0

# Only use crl-verify if you have revoke list
# crl-verify /tmp/openvpn/ca.crl

# Management parameter - DD-WRT can 
# access server's management port
management localhost 5001

Copy and paste the above into the 'additional config' box.  Edit as desired.  Now save and apply the settings.

DD-WRT Firewall Settings

Now we must allow the VPN traffic through the DD-WRT firewall.  Go to "Administrative // Commands".  Edit the rules below as required for your environment.  To help identify the correct interface run 'netstat -rn' from the DD-WRT command line or from the web GUI.  An edited example is shown below.  The public interface uses vlan2.  DD-WRT creates br0 for the internal networks.  And OpenVPN created tun0.

# netstat -rn (Removed Flags MSS Window and irtt)
Kernel IP routing table
Destination     Gateway       Genmask       Iface
0.0.0.0         001.002.003.1 0.0.0.0       vlan2  (Public Gateway)
10.2.192.0      0.0.0.0       255.255.255.0 tun0  (OpenVPN)
001.002.003.0   0.0.0.0       255.255.254.0 vlan2
127.0.0.0       0.0.0.0       255.0.0.0     lo
169.254.0.0     0.0.0.0       255.255.0.0   br0
192.168.1.0     0.0.0.0       255.255.255.0 br0 (DD-WRT Internal Bridged Networks)

Edit the lines below before adding them to the web GUI.  Cut and paste them into the 'Commands' box.  Then click 'Save Firewall'.  You will lose connectivity as the firewall rules are processed.  Edit the bold blue items as required.

  • udp - Change to tcp if required
  • 500 - Default port is 1194.  Edit as required
  • 10.2.192.0/24 - This is the VPN server subnet previously created.  Edit as appropriate.
  • br0 - Default DD-WRT internal bridge
  • tun0 - The newly created OpenVPN tunnel interface
  • vlan2 - The public interface for the DD-WRT router (netstat -rn)
  • # Accept incoming connections on port 500/UDP
    iptables -I INPUT 1 -p udp --dport 500 -j ACCEPT
    # Forward packets from VPN subnet 10.2.192.0/24

    iptables -I FORWARD 1 --source 10.2.192.0/24 -j ACCEPT
    # Forward packets inbound bridge outbound via tunnel

    iptables -I FORWARD -i br0 -o tun0 -j ACCEPT
    # Forward packets inbound tunnel outbound via bridge

    iptables -I FORWARD -i tun0 -o br0 -j ACCEPT
    # SNAT 10.2.192.0/24 outbound packets as VLAN2 IP (public ip)

    iptables -t nat -A POSTROUTING -s 10.2.192.0/24 -o vlan2 -j MASQUERADE

To see the rules run 'iptables -nvL' and 'iptables -t nat -nvL'.

Client Config

You can edit the sample configuration file.  It is nicely annotated.

  • C:\Program Files\OpenVPN\sample-config\client.ovpn

# Specify that we are a client and that we
# will be pulling certain config file directives
# from the server.
client

# Specify virtual network device tunX|tapX|null
# X may be omitted for dynamic device
# Both ends must match settings
# tun - encapsulate IPv4-6 OSI L3
# tap - encapsulate IPv4-6 Ethernet 802.3 OSI L2
dev tun0

# Are we connecting to a TCP or
# UDP server? Use the same setting as
# on the server.
proto udp

# The hostname/IP and port of the server.
# You can have multiple remote entries
# to load balance between the servers.
remote DD-WRT-PUBLIC.dyndns.com 500

# Keep trying indefinitely to resolve the
# host name of the OpenVPN server. Very useful
# on machines which are not permanently connected
# to the internet such as laptops.
resolv-retry infinite

# Most clients don't need to bind to
# a specific local port number.
nobind

# Downgrade privileges after initialization (non-Windows only)
user nobody
group nobody

# Try to preserve some state across restarts.
persist-key
persist-tun

# Offers policy-level control over usage of external
# programs and scripts
# 0 -- strictly no calling of external programs
# 1 -- DEFAULT - Only call built-in exec - ifconfig, ip, route
# 2 -- All calling of built-in exec and user-defined scripts
# 3 -- Allow passwords to be passed to scripts via env variables
# script-security <level>

# SSL/TLS parms.
# See the server config file for more
# description.
# Using inline files - comment out here

# ca ca.crt
# cert client.crt
# key client.key
# tls-auth ta.key 1

# Verify server certificate by checking that the
# certicate has the correct key usage set.
# This is an important precaution to protect against
# a potential attack discussed here:
# http://openvpn.net/howto.html#mitm
#
# To use this feature, you will need to generate
# your server certificates with the keyUsage set to
# digitalSignature, keyEncipherment
# and the extendedKeyUsage to
# serverAuth
# EasyRSA can do this for you.
remote-cert-tls server

# If a tls-auth key is used on the server
# then every client must also have the key.
# tls-auth ta.key 1
# For inline files use key-direction not tls-auth
key-direction 1

# Allow remote peer to change IP (DHCP)
# Accept authenticated packets from any address
# not just address specified by 'remote' option
float

# Select a cryptographic cipher.
# If the cipher option is used on the server
# then you must also specify it here.
cipher AES-256-CBC

# Select HMAC Authentication
# server/client must match - default sha1
auth sha1

# Enable compression on the VPN link.
# Don't enable this unless it is also
# enabled in the server config file.
comp-lzo adaptive

# Set log file verbosity.
verb 0

# Redirect all traffic over vpn
# Optional - I am setting on server side via push

# redirect-gateway def1

Read the next section to add all of the TLS files to the OVPN configuration file.  This makes management of the files much easier.

Concatenate Key Files into OVPN

Instead of providing the clients with the "*.ovpn" file and the key files you can combine everything into the OVPN file.  At the bottom of the OVPN file add the following.

Here is a list of the files you will need to add.

File Description File to Insert Enclosed By
Root CA Certificate ca.crt (The same file on all clients) <ca> </ca>
Client Certificate iphone.crt (Replace iphone as required) Unique per client <crt> </crt>
Client Private Key iphone.key (Replace iphone as required) Unique per client <key> </key>
TLS Auth Key ta.key (The same file on all clients) <tls-auth> </tls-auth>

# Root Certificate Authority ca.crt
<ca>
-----BEGIN CERTIFICATE-----
MIID1DCCAz2gAwIBAgIJAKs5r3xYQISK
................
mLvuSsTEx7Kts0R9ed8rBje4EB0PRhpT
-----END CERTIFICATE-----
</ca>
# client cert iphone.crt
<cert>
-----BEGIN CERTIFICATE-----
MIIEFjCCA3+gAwIBAgIBAjANBgkqhkiG9
................
6PSxUlAeZkPnVpj8BZ3HpERWZvy7Ljw79Z36
-----END CERTIFICATE-----
</cert>

# client private key iphone.key
<key>
-----BEGIN PRIVATE KEY-----
MIICdgIBADANBgkqhkiG9w0BAQEF
...................................
FDAQQyE4WV4GJ113Dtfagw==
-----END PRIVATE KEY-----
</key>
# tls auth ta.key
<tls-auth>
-----BEGIN OpenVPN Static key V1-----
64b7b9b8b1b25825fa006aabe829b379
...............................
d200a5f90563facf2f5a374564904e15
-----END OpenVPN Static key V1-----
</tls-auth>

Verify Your Connection

Before you use this in the wild you need to verify that your VPN tunnel is operating correctly.  Here are a few commands to verify that all traffic is routing over the VPN.

From the DD-WRT command line run a few tcpdump commands.

  • tcpdump -nl -i tun0
  • tcpdump -nl -i tun0 port 53
  • To verify ipchicken.com
    • tcpdump -nl -i tun0 host 104.25.63.114 && host 104.25.64.114
  • To verify whatismyip.com
    • tcpdump -nl -i tun0 host 104.27.201.91 && host 104.27.202.91

Obviously use your browser and go to 'whatismyip.com' and 'ipchicken.com' before and after you establish your VPN tunnel.  Make sure your IP is now your ISP public IP address.

A Note on Windows

You must run the OpenVPN client as an Administrator.  And you must comment out the 'user nobody' and 'group nobody' lines in the client OVPN file.

One thought on “DD-WRT OpenVPN 101”

Comments are closed.