Monitoring Cisco ASA Cluster status

ASA-Cluster

 
 

There are multiple way’s of configuring High Availablity on a set of Cisco ASA firewalls.
One of them is clustering (Note that Active/Standby or Active/Active is not the same as a ASA Cluster)

As of now there is no way to monitor the cluster status using SNMP, the only way to check if your ASA cluster is up and running is by monitoring your interface status.
If the data interfaces of a single ASA change to a disconnected state you know something has gone wrong in your cluster.

However I wanted more, after contacting TAC they confirmed that there still is no way of monitoring the ASA cluster with SNMP so I had to find a different way.
Most I wanted is shown when you run the ‘show cluster info’ command from the system context (if you use contexts), so to monitor the ASA cluster status with Nagios all I needed was a output from this command.

For this I created two simple scripts (one in batch, the other in expect) to login with SSH and run the show cluster info command.
Now this is absolutely not the best way of monitoring, and as you need to provide the password somewhere in Nagios it is not the most secure way but it works and especially in a development environment it is a good way of knowing when something has gone wrong in the ASA cluster.

For this you need the two scripts and some modifications to your nagios setup (nagios core in my case), so download the following files:

1) Download both files and put then in your nagios libexec folder (/usr/local/nagios/libexec in my setup):

1
2
3
cd /usr/local/nagios/libexec/
wget https://raw.githubusercontent.com/darky83/Scripts/master/Nagios/ASA-Cluster-Status/check_asa_cluster.bash
wget https://raw.githubusercontent.com/darky83/Scripts/master/Nagios/ASA-Cluster-Status/check_asa_cluster.exp

2) Make the files executable:

1
chmod 755 check_asa_cluster.*

3) Edit nagios templates.cfg and add a new service, in my case I check only every 6 hours, no need to bash the ASA with ssh logins as long as we get a notification if something goes wrong once a day, so edit your templates.cfg and add the following section at the bottom.

1
2
3
4
5
6
7
	define service{
        	name                            asa-cluster-service
	        use                             generic-service
	        normal_check_interval           360
	        retry_check_interval            10
	        register                        0
        }

4) Add a new asa cluster test command in your commands.cfg file:

1
2
3
4
5
	# ASA Cluster test
	define command{
        	command_name    check_asa_cluster
	        command_line    $USER1$/check_asa_cluster.bash -H $HOSTADDRESS$ -U $ARG1$ -P $ARG2$ -M $ARG3$
	}

5) Add a new check somewhere in your host definition, note to change the hostname, ssh username, password and mode:

1
2
3
4
5
6
7
        # Cisco ASA Cluster status
	define service{
	        use                     asa-cluster-service
	        host_name               HOSTNAME_CHANGEME
	        service_description     Cisco ASA Cluster Status
	        check_command           check_asa_cluster!USERNAME_CHANGEME!PASSWORD_CHANGEME!MODE_CHANGEME
        }

The mode is a 0 if the monitored unit should be the cluster Master and a 1 if the unit should be a cluster slave, this way you can check if your cluster master status changes to another unit.

Hopefully Cisco will add support for ASA Clustering status monitoring in SNMP sometime soon so we won’t need workarounds anymore.

Status OK and the configured unit should be the master:
ASA-Cluster-master-ok

Status OK and the configured unit should be a slave:
ASA-Cluster-slave-ok

Status Critical when clustering is not enabled:ASA-Cluster-Critical

Category: linux | LEAVE A COMMENT

CentOS 7 and ZFS

zfs-linux
 
 
 
 
 

I have used ZFS before on FreeBSD but never on any Linux variant.
So it became time to play around with ZFS on Linux, but as you can read below, there still are some mayor issues.

As I just downloaded the latest CentOS 7 Minimal CD I used CentOS as my first try.
After the minimal install and updating all packages on my little VM we were ready to go.

ZFS is not part of CentOS so you will need to enable extra repository’s to install ZFS.

First we enable EPEL and add the zfs repo:

1
2
sudo yum install epel-release
sudo yum localinstall --nogpgcheck http://archive.zfsonlinux.org/epel/zfs-release.el7.noarch.rpm

Then install ZFS:

1
sudo install kernel-devel zfs

This is where the first issue came up, ZFS did not seem to have installed correctly giving me not much more than an:

1
Failed to load ZFS module stack.

It seemed that ZFS was not build correctly because of the kernel update that was installed when I updated the system for the first time. After numerous attempts to fix ZFS I decided to just remove all the ZFS packages and old kernel and start over.

An tip online on gmane also mentioned to remove all modules, so sure lets go:

1
2
3
find /lib/modules/$(uname -r)/extra -name "splat.ko" -or -name "zcommon.ko" -or -name "zpios.ko" -or -name "spl.ko" -or -name "zavl.ko" -or -name "zfs.ko" -or -name "znvpair.ko" -or -name "zunicode.ko" | xargs rm -f
 
find /lib/modules/$(uname -r)/weak-updates/ -name "splat.ko" -or -name "zcommon.ko" -or -name "zpios.ko" -or -name "spl.ko" -or -name "zavl.ko" -or -name "zfs.ko" -or -name "znvpair.ko" -or -name "zunicode.ko" | xargs rm -f

Then I removed my old kernel, headers and all ZFS packages and finally an reboot:

1
2
3
4
sudo yum erase kernel-3.10.0-229.el7.x86_64
sudo yum erase kernel-headers kernel-devel kernel-tools
sudo yum erase zfs zfs-dkms libzfs2 spl spl-dkms dkmsc
reboot

After the reboot it was time to install everything again:

1
2
3
sudo yum localinstall --nogpgcheck https://download.fedoraproject.org/pub/epel/7/x86_64/e/epel-release-7-5.noarch.rpm
sudo yum localinstall --nogpgcheck http://archive.zfsonlinux.org/epel/zfs-release.el7.noarch.rpm
sudo yum install kernel-devel zfs

And finally ZFS worked like it should, no more error messages.

I have 4 small 5GB drives added to my VM to test with,
sdb, sdc, sdd and sde

So lets create an pool called data01 in raidz, as the drives are blank and unformatted you will need to force the creation of an new GPT.

1
zpool create data01 raidz sdb sdc sdd sde -f

See if all went well:

1
2
3
4
5
6
7
8
9
10
11
12
13
zpool status
  pool: data01
 state: ONLINE
  scan: none requested
config:
 
	NAME        STATE     READ WRITE CKSUM
	data01      ONLINE       0     0     0
	  raidz1-0  ONLINE       0     0     0
	    sdb     ONLINE       0     0     0
	    sdc     ONLINE       0     0     0
	    sdd     ONLINE       0     0     0
	  sde       ONLINE       0     0     0

That looks fine, now lets see what zdb says:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
zdb
data01:
    version: 5000
    name: 'data01'
    state: 0
    txg: 141
    pool_guid: 11371218379924896498
    errata: 0
    hostname: 'gluster01'
    vdev_children: 2
    vdev_tree:
        type: 'root'
        id: 0
        guid: 11371218379924896498
        create_txg: 4
        children[0]:
            type: 'raidz'
            id: 0
            guid: 832996839702454674
            nparity: 1
            metaslab_array: 34
            metaslab_shift: 27
            ashift: 9
            asize: 16060514304
            is_log: 0
            create_txg: 4
            children[0]:
                type: 'disk'
                id: 0
                guid: 2105630605786225987
                path: '/dev/sdb1'
                whole_disk: 1
                create_txg: 4
            children[1]:
                type: 'disk'
                id: 1
                guid: 6145009721102371365
                path: '/dev/sdc1'
                whole_disk: 1
                create_txg: 4
            children[2]:
                type: 'disk'
                id: 2
                guid: 14635352678309772165
                path: '/dev/sdd1'
                whole_disk: 1
                create_txg: 4
        children[1]:
            type: 'disk'
            id: 1
            guid: 1544288362510023523
            path: '/dev/sde1'
            whole_disk: 1
            metaslab_array: 112
            metaslab_shift: 25
            ashift: 9
            asize: 5353504768
            is_log: 0
            create_txg: 134
    features_for_read:
        com.delphix:hole_birth
        com.delphix:embedded_data

That all looks fine so we should have an 15GB /data01 partition:

1
2
3
4
5
6
7
8
9
df -h
Filesystem               Size  Used Avail Use% Mounted on
/dev/mapper/centos-root  8.5G  1.1G  7.5G  13% /
devtmpfs                 481M     0  481M   0% /dev
tmpfs                    490M     0  490M   0% /dev/shm
tmpfs                    490M  6.7M  484M   2% /run
tmpfs                    490M     0  490M   0% /sys/fs/cgroup
/dev/sda1                497M  119M  378M  24% /boot
data01                    15G     0   15G   0% /data01

Perfect, that all works fine, lets see if duplication works:

I will create a 1GB file just filled with zero’s to see if this works.

1
2
3
4
5
6
7
8
9
10
11
dd if=/dev/zero of=/data01/zerofile1 bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 4.45455 s, 241 MB/s
 
ls -lh /data01/
total 1.0G
-rw-r--r--. 1 root root 1.0G Jul 28 22:42 zerofile1
 
df -h | grep data01
data01                    15G  1.0G   14G   7% /data01

Okay we have a single file on /data01 that uses 1GB of space, lets copy the file a few times and see what happens, if everything works like it should the usage of the drive should not increase:

1
2
3
4
5
6
7
8
9
10
11
12
i=2; while [ $i -lt 7 ]; do cp /data01/zerofile1 /data01/zerofile$i; i=$[i+1]; done
ls -lh /data01/
total 1.0G
-rw-r--r--. 1 root root 1.0G Jul 28 22:42 zerofile1
-rw-r--r--. 1 root root 1.0G Jul 28 22:53 zerofile2
-rw-r--r--. 1 root root 1.0G Jul 28 22:54 zerofile3
-rw-r--r--. 1 root root 1.0G Jul 28 22:54 zerofile4
-rw-r--r--. 1 root root 1.0G Jul 28 22:54 zerofile5
-rw-r--r--. 1 root root 1.0G Jul 28 22:54 zerofile6
 
df -h | grep data01
data01                    15G  1.0G   14G   7% /data01

Yep we have 6 of the same files that are each 1GB in size but still 1GB of total space used, looks good thus far, lets clean up and the drive should be empty again:

1
2
3
4
5
rm -rf zerofile*
ls -lh /data01/
total 0
df -h | grep data01
data01                    15G  1.0G   14G   7% /data01

Thats weird, I removed the files but still the drive has 1GB of space in use.
But if you unmount the drive and mount the drive again the disk space is free again:

1
2
3
4
5
cd /
umount /data01/
zfs mount data01
df -h | grep data
data01                    15G     0   15G   0% /data01

This seems to be an bug, creating an sub drive with xattr=sa and modify the drop_caches seems to ‘fix’ the issue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
zfs create -o xattr=sa data01/fs
echo 3 > /proc/sys/vm/drop_caches
 
dd if=/dev/zero of=/data01/fs/testfile bs=1M count=1024
1024+0 records in
1024+0 records out
1073741824 bytes (1.1 GB) copied, 1.98644 s, 541 MB/s
 
# df -h | grep data
data01/fs                 15G  1.0G   14G   7% /data01/fs
 
# rm /data01/fs/testfile
rm: remove regular file ‘/data01/fs/testfile’? y
 
#  df -h | grep data
data01/fs                 15G  128K   15G   1% /data01/fs

So it seems ZFS on CentOS 7 still has some issues, next up in test is Debian.

Category: linux | LEAVE A COMMENT

Howto setup openvpn in bridge mode on debian

Below is my setup for a OpenVPN server in bridged mode with local firewall.
In short we will create a VPN server with the following setup:

[one_half]

[/one_half]

[one_half_last]
[arrow_list]
[list_item]Debian 6 as VPN server.[/list_item]
[list_item]VPN Server on TCP port 443 (SSL)[/list_item]
[list_item]2048bit key size[/list_item]
[list_item]Local subnet of 192.168.255.0/24[/list_item]
[list_item]Max 10 VPN Clients[/list_item]
[list_item]All config files will be kept in /etc/openvpn[/list_item]
[list_item]Local firewall to control access for VPN users[/list_item]
[/arrow_list]
[/one_half_last]

If you are using ESXi follow this post first: OpenVPN bridge and vmware esxi.

Installation

First install the required packages:

apt-get install openssl bridge-utils openvpn zip

Copy over the example easy-rsa 2.0 data to /etc/openvpn

cp -a /usr/share/doc/openvpn/examples/easy-rsa/2.0/ /etc/openvpn/easy-rsa

Now we need to edit the vars file in the easy-rsa folder to match your organization information, so change EXAMPLE to your own info.

cd /etc/openvpn/easy-rsa
sed -i '/export EASY_RSA=/ c\export EASY_RSA=\"/etc/openvpn/easy-rsa\"' vars
sed -i '/export KEY_SIZE=/ c\export KEY_SIZE=2048' vars
sed -i '/export KEY_COUNTRY=/ c\export KEY_COUNTRY=\"EXAMPLE\"' vars
sed -i '/export KEY_PROVINCE=/ c\export KEY_PROVINCE=\"EXAMPLE\"' vars
sed -i '/export KEY_CITY=/ c\export KEY_CITY=\"EXAMPLE\"' vars
sed -i '/export KEY_ORG=/ c\export KEY_ORG=\"EXAMPLE\"' vars
sed -i '/export KEY_EMAIL=/ c\export KEY_EMAIL=\"user\@example.com\"' vars

Now build your CA and server key (you already have provided all the right info in the vars file so press enter all the way through).

source ./vars
./clean-all
./build-ca
./build-key-server server
./build-dh

Now we need to create a server.conf file in /etc/openvpn

cd /etc/openvpn && vi server.conf

server.conf
I will use TCP port 443 for the VPN server with a local subnet of 192.168.255.0/24
IP’s 192.168.255.200~192.168.255.210 will be used for client DHCP (max 10 clients), and 192.168.255.3 is the OpenVPN server himself.

port 443
proto tcp
dev tap0
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/server.crt
key /etc/openvpn/easy-rsa/keys/server.key
dh /etc/openvpn/easy-rsa/keys/dh2048.pem
ifconfig-pool-persist ipp.txt
server-bridge 192.168.255.3 255.255.255.0 192.168.255.200 192.168.255.210
keepalive 10 120
comp-lzo
persist-key
persist-tun
log /var/log/openvpn.log
log-append /var/log/openvpn.log
status /var/log/openvpn-status.log
verb 3

#===================================================#
# Client Settings
#===================================================#
# If you need to push routes you can do so here for example:
#push "route 192.168.0.0 255.255.255.0 192.168.255.1"

push "ping 10"
push "ping-restart 60"

push "dhcp-option DOMAIN example.local"
push "dhcp-option DNS 192.168.255.1"
push "dhcp-option DNS 192.168.255.2"
push "dhcp-option WINS 192.168.255.1"
push "route-delay 5"

push "echo "
push "echo Welcome to the EXAMPLE Network!"
push "echo "

Now we need to bridge the OpenVPN tap0 interface with your network interface (eth0 in this example).
Make sure to change the settings for your network (IP, subnet, gateway etc) as this will replace your current interface configuration don’t do this remotely.

vi /etc/init.d/bridge

/etc/init.d/bridge

#!/bin/bash  

### BEGIN INIT INFO
# Provides:             bridge
# Required-Start:       $remote_fs $syslog
# Required-Stop:        $remote_fs $syslog
# Default-Start:        2 3 4 5
# Default-Stop:
# Short-Description:    Bridge for OpenVPN
### END INIT INFO

# Define Bridge Interface
br="br0"
# Define list of TAP interfaces to be bridged,
# for example tap="tap0 tap1".
tap="tap0"
# Define physical ethernet interface to be bridged
# with TAP interface(s) above.
eth="eth0"
eth_ip="192.168.255.3"
eth_netmask="255.255.255.0"
eth_broadcast="192.168.255.255"
gw="192.168.255.254"   

#################################
# Set up Ethernet bridge on Linux
# Requires: bridge-utils
#################################
start_bridge () {
        for t in $tap; do
                openvpn --mktun --dev $t
        done   

        brctl addbr $br
        brctl addif $br $eth

        for t in $tap; do
                brctl addif $br $t
        done

        for t in $tap; do
                ifconfig $t 0.0.0.0 promisc up
        done
        ifconfig $eth 0.0.0.0 promisc up
        ifconfig $br $eth_ip netmask $eth_netmask broadcast $eth_broadcast up
        route add default gw $gw $br
} 

####################################
# Tear Down Ethernet bridge on Linux
####################################
stop_bridge () {
        ifconfig $br down
        brctl delbr $br
        for t in $tap; do
                openvpn --rmtun --dev $t
        done
        ifconfig $eth $eth_ip netmask $eth_netmask broadcast $eth_broadcast up
        route add default gw $gw $eth
}  

####################################
# OPTIONS
####################################
case "$1" in
        start)
          echo -n "Starting Bridge"
          start_bridge
          ;;
        stop)
          echo -n "Stopping Bridge"
          stop_bridge
          ;;
        restart)
          stop_bridge
          sleep 2
          start_bridge
          ;;
        *)
          echo "Usage: $0 {start|stop|restart}" >&2
          exit 1
          ;;
esac

Now make the script executable and set it as a default startup script:

chmod 755 /etc/init.d/bridge
update-rc.d bridge defaults

User creation script

For easy management I create a template config file and a script to create the certificate and zip the certificates and config file so you can send it to a user.

First we will create a template config file for openvpn, make sure to edit the VPNSERVERHOSTNAME to your hostname/ip for the VPN Server.
Create a configs directory, here we will keep the user configuration zip files later on.

cd /etc/openvpn
mkdir configs
cd /etc/openvpn/configs
vi template-config.ovpn
client
dev tap
proto tcp
remote VPNSERVERHOSTNAME 443
resolv-retry infinite
nobind
pkcs12 <>.p12
ns-cert-type server
comp-lzo
verb 3
#redirect-gateway

Then create the new-user script.

cd /etc/openvpn
vi new-user
#!/bin/bash
action="$1"
option="$2"
base="/etc/openvpn"
#
#if [ -n $base/configs/$username ]

#----------------------------------------------------------------#
# new user
#----------------------------------------------------------------#
function new_user()
{
 echo "Creating the new user $username"

 # source the easy-rsa variables:
 source $base/easy-rsa/vars

 echo "Checking if user already exists"
 if [ -x $base/configs/$username ]
  then
   echo "ERROR: user already exists"
   echo ""
   exit 0
 else
  echo "Please check the already filled in answers and press"
  echo "enter for all the options finaly press 'Y' twice."
  echo ""
  sleep 5
  $base/easy-rsa/build-key-pkcs12 $username

  echo "Creating the config directory"
  userdir=$base/configs/$username
  mkdir $userdir
  cp $base/easy-rsa/keys/$username.p12 $userdir
  cp $base/configs/template-config.ovpn $userdir/$username.ovpn
  sed -i "s/<>/$username/g" $userdir/$username.ovpn
  cd $userdir
  /usr/bin/zip $userdir/$username.zip $username.*

  echo ""
  echo "User created"
  echo ""
 fi
}

#----------------------------------------------------------------#
# show the usage
#----------------------------------------------------------------#
function show_usage()
{
  echo ""
  echo "Usage: $0 [option] [arg]"
  echo "Where [option] is:"
  echo ""
  echo "-new"
  echo "   Create a new user"
  echo "   [arg] = "
  echo ""
  echo ""
}
#----------------------------------------------------------------#

#----------------------------------------------------------------#
# Parse action
#----------------------------------------------------------------#
function parse_action()
{
   case $action in
      -new)
        username="$option"
        new_user
        ;;
      *)
        show_usage
        ;;
   esac
exit 0
}
#----------------------------------------------------------------#

#----------------------------------------------------------------#
# Main function
#----------------------------------------------------------------#
function main()
{
  if [ "X${action}" == "X" ]
   then
    show_usage
    exit 0
   else
    parse_action
  fi

}
#----------------------------------------------------------------#

#----------------------------------------------------------------#
# run the Main script
#----------------------------------------------------------------#
main
#----------------------------------------------------------------#

Now make the script executable and run it with “-new johndoe” to create a new vpn certificate for user John Doe.

cd /etc/openvpn
chmod 700 new-user
./new-user -new johndoe

And finally we start the openvpn service:

/etc/init.d/openvpn start

Firewall

Now we add a IPtables firewall script to protect the network from the VPN clients.

mkdir /opt/firewall
vi /opt/firewall/localfw
#!/bin/bash
#----------------------------------------------------#
#   Firewall for bridged openvpn
#   ver 0.1 20111021
#----------------------------------------------------#

echo "--------------------------------"
echo "IPTABLES FIREWALL SCRIPT LOADING"
echo "--------------------------------"

modprobe ip_tables

#--------------IP Variables -------------------------#
DNS1=192.168.255.1                      # dns server 1
DNS2=192.168.255.2                      # dns server 2
DNSSERVERS="$DNS1 $DNS2"

WAN_IF="br0"                            # WAN Interface
WAN_IP="192.168.255.3"                  # WAN IP

LANRANGE="192.168.255.0/24"               # LAN Range
#-----------------------------------------------------#
IPTABLES="/sbin/iptables"       # path to iptables

#-----------------------------------------------------#
# Check how we are started
CMD=$1
echo "Checking how we are started"
if ( [ -z $CMD ] ); then CMD="start"; fi
#-----------------------------------------------------#

#-----------------------------------------------------#
if ( [ $CMD = "start" ] ); then
#-----------------------------------------------------#

 echo "checking if we need to enable IP forwarding"
 IPFWDCHK="`cat /proc/sys/net/ipv4/ip_forward`"
 if ( [ "$IPFWDCHK" != "1" ] ); then
   echo "IP forwarding not enabled yet enabling forwarding now"
   echo 1 > /proc/sys/net/ipv4/ip_forward
 fi

#--------------- Firewall default --------------------#

 # Default policy: ACCEPT
 $IPTABLES -P FORWARD ACCEPT
 $IPTABLES -P INPUT ACCEPT
 $IPTABLES -P OUTPUT ACCEPT

 # Flush
 echo "Flushing all rules"
 $IPTABLES -F
 $IPTABLES -t mangle -F
 $IPTABLES -t nat -F
 $IPTABLES -F FORWARD
 $IPTABLES -F INPUT
 $IPTABLES -F OUTPUT

 # Default policy: ACCEPT
 $IPTABLES -P FORWARD ACCEPT
 $IPTABLES -P INPUT ACCEPT
 $IPTABLES -P OUTPUT ACCEPT
#-----------------------------------------------------#

 # high-volumes
 $IPTABLES -N Aforward

 #allow fragmentation-needed
 $IPTABLES -A Aforward -p icmp --icmp-type fragmentation-needed -j ACCEPT

fi

echo "Start setting VPN Client rules"

#-----------------------------------------------------#
#       VPN CLIENT RULES FROM HERE                    #
#-----------------------------------------------------#

if ( [ $CMD = "VPN" -o $CMD = "start" ] ); then
        ####################################################
        # VPN Clients
        #########################
        echo " - Setting rules for VPN Clients"
        $IPTABLES -F vpn-clients
        $IPTABLES -X vpn-clients
        $IPTABLES -N vpn-clients
        if ( [ $CMD = "start" ] ); then
                for ip in 192.168.255.200 192.168.255.201 192.168.255.202 192.168.255.203 192.168.255.204 192.168.255.205 192.168.255.206 192.168.255.207 192.168.255.208 192.168.255.209 192.168.255.210
                    do
                        $IPTABLES -A FORWARD -s $ip -j vpn-clients
                        $IPTABLES -A FORWARD -d $ip -j vpn-clients
                done
        fi

        # YOUR RULES GO HERE

        # HTTP to a local webserver (for example)
        $IPTABLES -A vpn-clients -p tcp -d 192.168.255.10 --dport 80 -j ACCEPT
        $IPTABLES -A vpn-clients -p tcp -s 192.168.255.10 --sport 80 ! --syn -j ACCEPT

        # ALLOW Ping
        $IPTABLES -A vpn-clients -p icmp -j ACCEPT

        # DROP ALL Other
        $IPTABLES -A vpn-clients -j LOG --log-prefix "[DROP-vpn-clients ]"
        $IPTABLES -A vpn-clients -j DROP
        #########################
        # VPN range
        ####################################################
fi

#-----------------------------------------------------#
echo "Done setting VPN Client Rules"
#-----------------------------------------------------#
#       VPN CLIENT RULES UNTIL HERE                   #
#-----------------------------------------------------#

#-----------------------------------------------------#
if ( [ $CMD = "start" ] ); then
        #********************************************************
        # VPNServer local rules
        #********************
        echo "Setting local rules"
        # ssh in
        $IPTABLES -A INPUT -p tcp -d $WAN_IP --dport 22 -j ACCEPT
        $IPTABLES -A OUTPUT -p tcp -s $WAN_IP --sport 22 ! --syn -j ACCEPT

        # VPN in
        $IPTABLES -A INPUT -p tcp -d $WAN_IP --dport 443 -j ACCEPT
        $IPTABLES -A OUTPUT -p tcp -s $WAN_IP --sport 443 -j ACCEPT

        # DNS lookups naar DNS
        for i in $DNSSERVERS
        do
          $IPTABLES -A OUTPUT -p udp --sport 53 -d $i -j ACCEPT
          $IPTABLES -A INPUT  -p udp -s $i --sport 53 -j ACCEPT
          $IPTABLES -A OUTPUT -p udp -d $i --dport 53 -j ACCEPT
          $IPTABLES -A INPUT  -p udp -s $i --dport 53 -j ACCEPT
          $IPTABLES -A OUTPUT -p tcp -d $i --dport 53 -j ACCEPT
          $IPTABLES -A INPUT  -p tcp -s $i --dport 53 -j ACCEPT
          $IPTABLES -A OUTPUT -p tcp --sport 53 -d $i ! --syn -j ACCEPT
          $IPTABLES -A OUTPUT -p udp --dport 123 -j ACCEPT
          $IPTABLES -A INPUT -p udp --sport 123 -j ACCEPT
        done

        # local everything
        $IPTABLES -A OUTPUT -p tcp -d 127.0.0.1 -s 127.0.0.1 -j ACCEPT
        $IPTABLES -A INPUT -p tcp -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT
        $IPTABLES -A INPUT -p tcp -d 127.0.0.1 -s 127.0.0.1 -j ACCEPT
        $IPTABLES -A OUTPUT -p tcp -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT

        $IPTABLES -A OUTPUT -p udp -d 127.0.0.1 -s 127.0.0.1 -j ACCEPT
        $IPTABLES -A INPUT -p udp -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT
        $IPTABLES -A INPUT -p udp -d 127.0.0.1 -s 127.0.0.1 -j ACCEPT
        $IPTABLES -A OUTPUT -p udp -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT

        $IPTABLES -A OUTPUT -p icmp -d 127.0.0.1 -s 127.0.0.1 -j ACCEPT
        $IPTABLES -A INPUT -p icmp -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT
        $IPTABLES -A INPUT -p icmp -d 127.0.0.1 -s 127.0.0.1 -j ACCEPT
        $IPTABLES -A OUTPUT -p icmp -s 127.0.0.1 -d 127.0.0.1 -j ACCEPT

        # browse (apt, etc..)
        $IPTABLES -A OUTPUT -p tcp -s $WAN_IP --dport 80 -j ACCEPT
        $IPTABLES -A INPUT -p tcp -d $WAN_IP --sport 80 ! --syn -j ACCEPT
        $IPTABLES -A OUTPUT -p tcp -s $WAN_IP --dport 443 -j ACCEPT
        $IPTABLES -A INPUT -p tcp -d $WAN_IP --sport 443 ! --syn -j ACCEPT

        # ALLOW ICMP
        $IPTABLES -A INPUT -p icmp -j ACCEPT
        $IPTABLES -A OUTPUT -p icmp -j ACCEPT

        # deny rest
        $IPTABLES -A INPUT -j LOG --log-prefix "[DROP-INPUT-WAN] "
        $IPTABLES -A INPUT -j DROP
        $IPTABLES -A OUTPUT -j LOG --log-prefix "[DROP-OUTPUT-WAN] "
        $IPTABLES -A OUTPUT -j DROP
        #$IPTABLES -A FORWARD -j LOG --log-prefix "[DROP-FORWARD-WAN] "
        $IPTABLES -A FORWARD -j DROP

        # Reset default policy: DROP
        $IPTABLES -P FORWARD DROP
        $IPTABLES -P INPUT DROP
        $IPTABLES -P OUTPUT DROP
fi
#-----------------------------------------------------#

echo "--------------------------------"
echo "IPTABLES FIREWALL SCRIPT LOADED "
echo "--------------------------------"
#-----------------------------------------------------#
#eof
#-----------------------------------------------------#

Then make the script executable and add the firewall to run at startup

chmod 700 /opt/firwall/localfw
vi /etc/rc.local (add <strong>/opt/firewall/localfw</strong> just before exit 0)

VPN status

This script will show you some statistics on the VPN server.

vi /usr/local/bin/openvpn-status
#!/usr/bin/env python
# -*- coding: utf-8 -*-

STATUS = "/var/log/openvpn-status.log"

status_file = open(STATUS, 'r')
stats = status_file.readlines()
status_file.close()

hosts = []

headers = {
    'cn':    'Common Name',
    'virt':  'Virtual Address',
    'real':  'Real Address',
    'sent':  'Sent',
    'recv':  'Received',
    'since': 'Connected Since'
}

sizes = [
    (1<<50L, 'PB'),
    (1<<40L, 'TB'),
    (1<<30L, 'GB'),
    (1<<20L, 'MB'),
    (1<<10L, 'KB'), (1, 'B') ] def byte2str(size): for f, suf in sizes: if size >= f:
            break

    return "%.2f %s" % (size / float(f), suf)

for line in stats:
    cols = line.split(',')

    if len(cols) == 5 and not line.startswith('Common Name'):
        host  = {}
        host['cn']    = cols[0]
        host['real']  = cols[1].split(':')[0]
        host['recv']  = byte2str(int(cols[2]))
        host['sent']  = byte2str(int(cols[3]))
        host['since'] = cols[4].strip()
        hosts.append(host)

    if len(cols) == 4 and not line.startswith('Virtual Address'):
        for h in hosts:
            if h['cn'] == cols[1]:
                h['virt'] = cols[0]

fmt = "%(cn)-25s %(virt)-18s %(real)-15s %(sent)13s %(recv)13s %(since)25s"
print fmt % headers
print "\n".join([fmt % h for h in hosts])

Now make the script executable.

chmod 700 /usr/local/bin/openvpn-status

If you run it and a client is connected you will see something like this:

# /usr/local/bin/openvpn-status
Common Name               Virtual Address    Real Address             Sent      Received           Connected Since
johndoe                   00:00:00:00:00:00  1.2.3.4          1.11 MB     489.49 KB  Wed Dec 11 13:26:42 2011

References