OpenVPN server on Fedora 16 connecting Cyanogenmod (7.1) Android phone [bridged]

I have already posted about openVPN on Ubuntu  but the config for Fedora is a little different so here's a updated post. I did the following setup using

I've used this quite a lot and its been very stable :D Have to say OpenVPN is pretty awesome. Seems very stable even when transitioning between 2G & 3G.

Server Setup

First of all we need to make sure we have bridge-utils and the OpenVPN package installed.
yum install -y openvpn bridge-utils

Network interfaces

For this to work we need to create a logical bridge interface and then add physical interfaces to the bridge. So first we create a file /etc/sysconfig/network-scripts/ifcfg-br0 and add the following:

DEVICE=br0
TYPE=Bridge
ONBOOT=yes
BOOTPROTO=static
IPADDR=10.10.10.21
NETMASK=255.255.255.0
GATEWAY=10.10.10.21
DELAY=0
STP=off

Save the file and open the file /etc/sysconfig/network-scripts/ifcfg-Wired_connection_1 (file names may vary depending on the setup of your machine). Basically we want to remove IP addressing and add it to the bridge group. Change this file accordingly (there's no need to change the HWADDR info that's already there)

HWADDR=BE:EF:BE:EF:BE:EF
TYPE=Ethernet
BOOTPROTO=none
ONBOOT=yes
BRIDGE=br0

Now we should be able to restart the network service and have full connectivity to/from the server.
service network restart
If you still can browse to/from the server as usual dont carry on any further something is b0rked. Check /etc/resolve.conf has valid DNS servers etc.

Server Certificates

Now we need to generate certificates for our server to use. OpenVPN comes with some scripts to take most of the pain out of this. To keep things where I can find them I like to move these to /etc/openvpn/easy-rsa. First off we make a new directory and copy the scripts into it.

mkdir /etc/openvpn/easy-rsa
cd /etc/openvpn
cp -R /usr/share/openvpn/easy-rsa/2.0/* easy-rsa/
cd easy-rsa

Edit the following in the vars file of this directory

export KEY_COUNTRY="UK"
export KEY_PROVINCE="M0"
export KEY_CITY="m00nieTown"
export KEY_ORG="m00nie.co"
export KEY_EMAIL="spam@weeeeeimaspamer.com"

Now just run the following commands

source ./vars ## execute your new vars file
./clean-all  ## Setup the easy-rsa directory (Deletes all keys)
./build-dh  ## takes a while consider backgrounding
./pkitool --initca ## creates ca cert and key
./pkitool --server server ## creates a server cert and key
cd keys
openvpn --genkey --secret ta.key  ## Build a TLS key
sudo cp server.crt server.key ca.crt dh1024.pem ta.key ../../
cd ../..

Server Config

Create a directory and two files. One called ifup.sh and one called ifdown.sh. These will be used to control bringing the interfaces up/down and should contain the following.

mkdir /etc/openvpn/ifupdown
touch /etc/openvpn/ifupdown/ifup.sh
touch /etc/openvpn/ifupdown/ifdown.sh
sudo chmod +x /etc/openvpn/ifupdown/ifup.sh /etc/openvpn/ifupdown/ifdown.sh

ifup.sh

#!/bin/sh

BR=$1
DEV=$2
MTU=$3
/sbin/ip link set "$DEV" up promisc on mtu "$MTU"
/usr/sbin/brctl addif $BR $DEV

ifdown.sh

#!/bin/sh

BR=$1
DEV=$2

/usr/sbin/brctl delif $BR $DEV
/sbin/ip link set "$DEV" down

Now to edit the /etc/openvpn/server.conf file. Mine looks like the following

mode server
tls-server
local 10.10.10.21 ## 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/ifupdown/ifup.sh br0"
down “/etc/openvpn/ifupdown/ifdown.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.10.10.21 255.255.255.0 10.10.10.240 10.10.10.250
push “dhcp-option DNS 8.8.8.8″
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

You should be able to run the server with the following command and recieve no errors. If you do fix them first
openvpn --config server.conf --script-security 2
If it all looks good lets make OpenVPN run as a service and start when the server boots
systemctl start openvpn.service systemctl enable openvpn.service

Client Setup

We need to create some certificates for our client (the phone)

cd /etc/openvpn/easy-rsa
source ./vars             ## execute the vars file
./pkitool phone          ## create a cert and key named "phone"

Now to make it easy to import to my phone I made a p12 file

cd keys
openssl pkcs12 -export -in phone.crt -inkey phone.key -certfile ca.crt -out phone.p12
mv phone.p12 /var/www/html

Now browse to the file on your phone E.g http://10.10.10.21/phone.p12. Your phone will then store the certificates into is credential store :) Finally we configure the VPN under Settings > Wireless & networks > VPN settings > Add VPN like so

The main config:

Menu > Advanced OpenVPN Settings:

At the moment there is no gui setting to configure tls-auth but they did give us the Extra arguments option. In here I added (I used FTP to copy the ta.key file to the phone in a directory called VPN.
--tls-auth /mnt/sdcard/VPN/ta.key 1 --explicit-exit-notify 2

Router Setup

Time for some evil NAT. The basic syntax is
ip nat inside source static udp >fedora server IP> >server port> interface >outside address>  >some port>
so mine was
ip nat inside source static udp 10.10.10.21 12345 interface dialer 0 12345
Now we can see the static translation:

m00nies_router#show ip nat translations
Pro Inside global Inside local Outside local Outside global
udp 192.168.1.1:12345 10.10.10.21: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.10.10.21:12345 with ip ident 0

And the OpenVPN server logs confirm it works ok too. Its been very stable on both 2 and 3G.

moonie :)