OpenVPN – Adding Iptables Route on Connect

bashiptablesopenvpnscripting

I have my openvpn server up and running and I push certain routes to my clients via the ccd directive, I would like to know how I can update the iptables based on the ccd files when the client connects.

So lets say my ccd for client1 is :

ifconfig-push 10.8.0.45 255.255.255.0
push 'route 10.10.0.45'

and I want to add this to the iptables.

iptables -A FORWARD -s 10.8.0.45 -d 10.10.0.45 -j ACCEPT

and then

iptables -A FORWARD -s 10.8.0.0/24 -d 10.10.0.0/16 -j DROP

If someone can point me in the right direction would be much appreciated, im fairly newb with bash scripts

Best Answer

You can hook into an OpenVPN configuration many scripts, which receive many parameters from the server as environment variables: cf. Reference Manual.

You are mostly interested in the up, down scripts to insert the DROP rule at server startup and shutdown and the client-connect and client-disconnect script for per client rules. You need to modify your server config to contain:

# Allow user scripts
script-security 2
# up/down script
up /etc/openvpn/updown.sh
down /etc/openvpn/updown.sh
# Client connect/disconnect
client-connect /etc/openvpn/client.sh
client-disconnect /etc/openvpn/client.sh
  1. Your /etc/openvpn/updown.sh script will create a OPENVPN and link it from the FORWARD chain:
#!/bin/bash
IPT=/usr/sbin/iptables
# 'script_type' contains the type of the script
if [ "$script_type" = "up" ]; then
  $IPT -N OPENVPN
  $IPT -A FORWARD -j OPENVPN
  $IPT -A OPENVPN -s 10.8.0.0/24 -d 10.10.0.0/16 -j DROP
else
  $IPT -F OPENVPN
  $IPT -D FORWARD -j OPENVPN
  $IPT -X OPENVPN
fi
  1. You client script /etc/openvpn/client.sh will be more complicated: while the public and private IP addresses of the remote client are contained in the ifconfig_remote and ifconfig_pool_remote_ip, you will need to parse the ccd file to find out which routes did you send to the client:
#!/bin/bash
IPT=/usr/sbin/iptables
# We need to split the line into words as bash would, by
# interpreting the double quotes, hence the 'eval'.
function parse_ccd_line() {
  eval "local line=($1)"
  # If the first word is 'push' return the second one.
  if [ "${line[0]}" = "push" ]; then
    echo "${line[1]}"
  fi
}

# Your ccd_dir so we don't need to parse the OpenVPN
# server config file too.
ccd_dir=/etc/openvpn/ccd

if [ -f "$ccd_dir/$common_name" ]; then
  # We read the "$ccd_dir/$common_name" file line by line:
  while read line; do
    # We split the argument of every 'push' directive into 'cmd' and 'arg1'
    # If you need more arguments, the array 'push_opt' contains them.
    push_opt=($(parse_ccd_line "$line"))
    cmd=${push_opt[0]}
    arg1=${push_opt[1]}
    # We use just the 'route' commands
    if [ "$cmd" = "route" ]; then
      if [ "$script_type" = "client-connect" ]; then
        $IPT -I OPENVPN -s "$ifconfig_pool_remote_ip" -d "$arg1" -j ACCEPT
      else
        $IPT -D OPENVPN -s "$ifconfig_pool_remote_ip" -d "$arg1" -j ACCEPT
      fi
    fi
  done < "$ccd_dir/$common_name"
fi
Related Topic