
Use Linux (Debian/Ubuntu) as a VPN router
First step would be to make sure that the chosen hardware has a NIC which can easily be found and installed under linux. I had issues getting BM4312 (broadcom) lp-phy (low power) chip to work in my first trial hardware (Dell laptop). Next step is to choose if you wish to use Debian or Ubuntu. Installing server versions are better but remember no GUI by default so if you are GUI lover go with desktop versions and install the server bits you need later.
Once the NICs are operational you need to get the VPN working. This will be different for server and desktop versions. For server you need to install the plugin and create the dialup script (refer to documentation available for the linux flavour you chose). For desktop version the network manager provides easy and graphical way to create this. Once you have the VPN connection configured and tested to work you make the VPN (in our case, PPTP) auto dial after auto-login (Desktop version provides easy way for auto-login). You also need some changes to ip forwarding and firewall to let the traffic from your local network flow via the VPN connection.
For auto-connecting VPN in Desktop (using Network Manager and its VPN plugins) follow the guide below:
create a script file with the code below:
#!/bin/bash
#
#
############
# SETTINGS #
############
#
get_connections_paths()
{
dbus-send --system --print-reply --dest="$1" "/org/freedesktop/NetworkManagerSettings" "org.freedesktop.NetworkManagerSettings.ListConnections" \
| grep "object path" | cut -d '"' -f2
}
#
get_connection_settings()
{
dbus-send --system --print-reply --dest="$1" "$2" org.freedesktop.NetworkManagerSettings.Connection.GetSettings
}
#
get_connection_string_setting()
{
echo "$1" | grep -A 1 \""$2"\" | grep variant | cut -d '"' -f2
}
#
get_connection_id()
{
get_connection_string_setting "$1" "id"
}
#
get_connection_type()
{
get_connection_string_setting "$1" "type"
}
#
get_device_type_by_connection_type()
{
echo "$1" | grep -q "ethernet" && echo 1 && return
echo "$1" | grep -q "wireless" && echo 2 && return
echo 0
}
#
find_connection_path()
{
for connection_path in `get_connections_paths "$1"`
do
connection_settings=`get_connection_settings "$1" "$connection_path"`
connection_settings_id=`get_connection_id "$connection_settings"`
[ "$connection_settings_id" = "$2" ] && echo "$1" "$connection_path"
done
}
#
find_connection_path_everywhere()
{
find_connection_path "org.freedesktop.NetworkManagerSystemSettings" "$1"
find_connection_path "org.freedesktop.NetworkManagerUserSettings" "$1"
}
#
print_connections_ids()
{
for connection_path in `get_connections_paths "$1"`
do
connection_settings=`get_connection_settings "$1" "$connection_path"`
connection_settings_id=`get_connection_id "$connection_settings"`
echo "$connection_settings_id"
done
}
#
print_connections_ids_everywhere()
{
print_connections_ids "org.freedesktop.NetworkManagerSystemSettings"
print_connections_ids "org.freedesktop.NetworkManagerUserSettings"
}
#
#
###########
# DEVICES #
###########
#
get_devices_paths()
{
dbus-send --system --print-reply --dest="org.freedesktop.NetworkManager" "/org/freedesktop/NetworkManager" "org.freedesktop.NetworkManager.GetDevices" \
| grep "object path" | cut -d '"' -f2
}
#
get_device_property()
{
dbus-send --system --print-reply --dest="org.freedesktop.NetworkManager" "$1" "org.freedesktop.DBus.Properties.Get" string:"org.freedesktop.NetworkManager.Device" string:"$2" \
| grep variant | awk '{print $3}'
}
#
get_device_type()
{
get_device_property "$1" "DeviceType"
}
#
get_device_path_by_device_type()
{
device_path_by_device_type="/"
for device_path in `get_devices_paths`
do
device_type=`get_device_type "$device_path"`
[ "$device_type" = "$1" ] && device_path_by_device_type="$device_path"
done
echo "$device_path_by_device_type"
}
#
#
#######################
# ACTIVES CONNECTIONS #
#######################
#
get_actives_connections_paths()
{
dbus-send --system --print-reply --dest="org.freedesktop.NetworkManager" "/org/freedesktop/NetworkManager" "org.freedesktop.DBus.Properties.Get" string:"org.freedesktop.NetworkManager" string:"ActiveConnections" \
| grep "object path" | cut -d '"' -f2
}
#
get_last_active_connection_path()
{
get_actives_connections_paths | tail -n 1
}
#
get_parent_connection_path_by_device_type()
{
parent_connection_path="/"
[ "$1" = 0 ] && parent_connection_path=`get_last_active_connection_path`
echo "$parent_connection_path"
}
#
get_active_connection_property()
{
dbus-send --system --print-reply --dest="org.freedesktop.NetworkManager" "$1" "org.freedesktop.DBus.Properties.Get" string:"org.freedesktop.NetworkManager.Connection.Active" string:"$2" \
| grep variant | awk -F '"' '{print $2}'
}
#
get_active_connection_service()
{
get_active_connection_property "$1" "ServiceName"
}
#
get_active_connection_path()
{
get_active_connection_property "$1" "Connection"
}
#
get_active_connection_path_by_connection_path()
{
for active_connection_path in `get_actives_connections_paths`
do
service=`get_active_connection_service $active_connection_path`
path=`get_active_connection_path $active_connection_path`
[ "$service" = "$1" ] && [ "$path" = "$2" ] && echo "$active_connection_path"
done
}
#
print_actives_connections_ids()
{
for active_connection_path in `get_actives_connections_paths`
do
service=`get_active_connection_service $active_connection_path`
path=`get_active_connection_path $active_connection_path`
connection_settings=`get_connection_settings "$service" "$path"`
connection_settings_id=`get_connection_id "$connection_settings"`
echo "$connection_settings_id"
done
}
#
#
##############
# START/STOP #
##############
#
start_connection()
{
my_connection_complete_path=`find_connection_path_everywhere "$1"`
my_connection_settings=`get_connection_settings $my_connection_complete_path`
my_connection_type=`get_connection_type "$my_connection_settings"`
my_connection_device_type=`get_device_type_by_connection_type "$my_connection_type"`
#
my_connection_service=`echo $my_connection_complete_path | awk '{print $1}'`
my_connection_path=`echo $my_connection_complete_path | awk '{print $2}'`
my_connection_device_path=`get_device_path_by_device_type "$my_connection_device_type"`
my_parent_connection_path=`get_parent_connection_path_by_device_type "$my_connection_device_type"`
#
echo "connection_service=$my_connection_service"
echo "connection_path=$my_connection_path"
echo "connection_device_path=$my_connection_device_path"
echo "parent_connection_path=$my_parent_connection_path"
#
dbus-send --system --print-reply --dest="org.freedesktop.NetworkManager" /org/freedesktop/NetworkManager "org.freedesktop.NetworkManager.ActivateConnection" string:"$my_connection_service" objpath:"$my_connection_path" objpath:"$my_connection_device_path" objpath:"$my_parent_connection_path"
}
#
stop_connection()
{
my_connection_complete_path=`find_connection_path_everywhere "$1"`
my_active_connection_path=`get_active_connection_path_by_connection_path $my_connection_complete_path`
#
echo "active_connection_path=$my_active_connection_path"
#
dbus-send --system --print-reply --dest="org.freedesktop.NetworkManager" /org/freedesktop/NetworkManager "org.freedesktop.NetworkManager.DeactivateConnection" objpath:"$my_active_connection_path"
}
#
#
########
# MAIN #
########
#
invalid_arguments()
{
echo "Usage: `basename "$0"` connexion_name start|stop"
echo "---Available Connections:"
print_connections_ids_everywhere
echo "---Active Connections:"
print_actives_connections_ids
exit 0
}
#
[ "$#" != 2 ] && invalid_arguments
#
case "$2" in
"start")
start_connection "$1"
;;
"stop")
stop_connection "$1"
;;
*)
invalid_arguments
;;
esac
give it a name e.g. “vpn_connect”
copy it to /usr/local/bin
make it executable
sudo cp vpn_connect /usr/local/bin/
sudo chmod ugo+x /usr/local/bin/vpn_connect
now create another script in your home folder which will check if the VPN is connected and if not it will connect it. This script will monitor the VPN connection every 60 seconds and in case it finds it disconnected it will connect it again.
#!/bin/bash
for (( ; ; )); do
# creating ifinite loop
tested=$(vpn|grep -c USA)
# VPNNAME here is the name of desired vpn connection to monitor. The results can be:
# 0 - this connection does not exist
# 1 - connection exists, but not active
# 2 - connection exists, and is active
case $tested in
"0")
echo "something is wrong, cannot find desired connection in avaliable list"
;;
"1")
echo "VPN avaliable, but not connected"
vpn_connect USA start
;;
"2")
echo "VPN seems to work"
;;
esac
# enter desired time between checks here.
sleep 60
done
let’s call it startvpn
make this script executable
sudo chmod ugo+x startvpn
or
sudo chmod 777 startvpn
you can now put this in the startup applications (if using Desktop version of Ubuntu) or execute it on every reboot by having it in /etc/rc.local
The final part is to have the forwarding and enabled and the route defined. Assuming your VPN connection interface is ppp0.
create a script file with code below:
#!/bin/bash
sleep 120
echo 1 >; /proc/sys/net/ipv4/ip_forward
iptables -A POSTROUTING -t nat -s 192.168.100.0/24 -o ppp0 -j MASQUERADE
iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
this script enables forwarding, routing (from 192.168.100.0/24 network) and make sure that MTUis set correctly otherwise routing does not work fully.
let us call the script as vpn_route
you can now have it run on every boot by copying this code to /etc/rc.local or copy the script file in /etc/init.d/ and then the following command
sudo update-rc.d /etc/init.d/vpn_route defaults
This will add this script to all run level rc folders and will execute it on each boot.
Also make sure that the ‘/proc/sys/net/ipv4/ip_forward’ has value of 1 in it
Now the VPN should auto connect on every boot, will be monitored for disconnection and reconnected in case of disconnection and the forwarding, routing and MTU settings will be applied on every reboot as well.
Enjoy VPN router out of a linux box.
note: help on codes came from various places but will mention these posts specially:
Script for VPN connection
Further script for VPN connection
VPN Connection Sharing forwarding and routing
MTU setting command which bugged me for a while when browsing was half working