Setting up OpenVPN for Android phone (NAT & ZBFW on Cisco 1801)
I've been looking to get a decent "native" VPN setup on my android phone for a while. There doesn't seem to be native support for IPSEC VPNs terminating on Cisco routers. Long request topic for it [here] although ASA8.4(1) supposedly has support I haven't had a chance to test it yet.
For the following I used:
- Rooted HTC Desire
- CyanogenMod 7.0 (built in OpenVPN support :D ) http://www.cyanogenmod.com/
- Ubuntu 10.10
- OpenVPN 2.1.0
- Cisco 1801 running 15.0(1)M using zone based firewall
Setup the OpenVPN server
Since I was new to OpenVPN I followed the Ubuntu wiki found [here]. One really cool feature of OpenVPN is tls-auth you can read a bit more about it [here]. Basically if the OpenVPN server receives a packet that doesn't have a HMAC generated by the ta.key it will just drop the packet. Makes it pretty difficult to port scan for :)
For the most part it worked perfectly but I added a couple of extra lines to the server config below. I found it useful to run the server via
sudo openvpn --config server.conf --script-security 2 when I was doing the initial testing.
My server.conf file:
mode server tls-server local 10.1.1.10 ## ip/hostname of server port 12345 ## My Custom port proto udp #bridging directive dev tap0 ## If you need multiple tap devices, add them here up "/etc/openvpn/up.sh br0" down "/etc/openvpn/down.sh br0" persist-key persist-tun #certificates and encryption ca ca.crt cert server.crt key server.key # This file should be kept secret dh dh1024.pem tls-auth ta.key 0 # This file is secret cipher BF-CBC # Blowfish (default) comp-lzo #DHCP Information ifconfig-pool-persist ipp.txt server-bridge 10.1.1.10 255.255.255.0 10.1.1.240 10.1.1.250 push "dhcp-option DNS 184.108.40.206" push "dhcp-option DOMAIN m00nie.com" max-clients 10 ## set this to the max number of clients that should be connected at a time #log and security user nobody group nogroup keepalive 10 120 status openvpn-status.log script-security 2 ## This needed added verb 4 ##Changed the logging level
Setup the OpenVPN client on the phone
Create the client cert
cd /etc/openvpn/easy-rsa/ ## move to the easy-rsa directory source ./vars ## execute the vars file ./pkitool client ## create a cert and key named "client"
Android only seems to accept .p12 filetype certificates. You can either generate .p12 certs using this command below then copy them to your sdcard and then use the Location & Security settings > Install from SD card option to install them or just put the .crt files on a webserver and browse to them (the browser seems to accept .crt files) and it will add them to the secure store for you.
To make .p12 cert
openssl pkcs12 -export -in client.crt -inkey client.key -certfile ca.crt -out client.p12
When you copy the files to your sdcard be sure to copy the ta.key file too and note is location. If its on the sdcard its final location will be
Now we can configure the VPN as follows. (Click for larger images)
The main config:
At the moment there is no gui setting to configure tls-auth but they did give us the Extra arguments option :D In here I added
--tls-auth /mnt/sdcard/VPN/ta.key 1 --explicit-exit-notify 2
When testing I had this error logged on the OpenVPN server:
read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
I had to use the tap device rather than the tun to make the VPN connect and stop this error
Port forward & ZBFW on the router
Since at the moment we still have NAT we have to forward ports.
ip nat inside source static udp <ubuntu server IP> <server port> interface <outside address> <some port>
so mine was
ip nat inside source static udp 10.1.1.10 12345 interface dialer 0 12345
Now we can see the static translation:
Moons-Router#show ip nat translations Pro Inside global Inside local Outside local Outside global udp 192.168.1.1:12345 10.1.1.10:12345 --- ---
Now the port is forwarding to the OpenVPN server but my zone based firewall config is dropping the packets.
Apr 13 18:14:04.136: %FW-6-DROP_PKT: Dropping udp session 172.16.1.1 10.1.1.10:12345 on zone-pair out-in class class-default due to DROP action found in policy-map with ip ident 0
At the moment there is no explicit zone-pair for outside to inside so the default is deny all. Lets define one
m00nies_router#conf t Enter configuration commands, one per line. End with CNTL/Z. m00nies_router(config)#access-list 199 permit udp any any eq 12345 m00nies_router(config)#class-map type inspect match-all OPENVPN m00nies_router(config-cmap)# match access-group 199 m00nies_router(config-cmap)# exit m00nies_router(config)#policy-map type inspect OPENVPN_POLICY m00nies_router(config-pmap)#class type inspect OPENVPN m00nies_router(config-pmap-c)#pass log m00nies_router(config-pmap-c)#exit m00nies_router(config-pmap)#exit m00nies_router(config)#zone-pair security out-in source out-zone destination in-zone m00nies_router(config-sec-zone-pair)# service-policy type inspect OPENVPN_POLICY m00nies_router(config-sec-zone-pair)#^Z m00nies_router#
First off we classify the traffic we want the allow it to pass but log it. Next we apply that policy to a zone pair. Theres more info about configuring ZBFW [here]. Below we can see the default that catches all other traffic is still drop.
m00nies_router#show policy-map type inspect OPENVPN_POLICY Policy Map type inspect OPENVPN_POLICY Class OPENVPN Pass log Class class-default Drop
Now we can try our VPN access.
It passes the router ok
Apr 13 18:31:00.085: %FW-6-PASS_PKT: (target:class)-(out-in:OPENVPN) Passing udp pkt 172.16.1.1:52585 => 10.1.1.10:12345 with ip ident 0
And the OpenVPN server logs confirm it works ok too. Its been very stable on both 2 and 3G.