I've searched around for this and haven't really been able to figure it out. Can anyone point me in the right direction for creating an easy way to selectively NOT use VPN on demand?
The original selective routing or RPDB techniques both simply create a decision rule that determines if the Client VPN should be used for a particular source.
i.e. if the appropriate '
iptables -t mangle PREROUTING fwmark' chain rule or the RPDB '
ip rule' entry exists (depending on the technique used).
If you have a script on the router (say
VPN_select_ON_OFF.sh) that can be invoked with the appropriate arguments, then you need to have method of invoking that script remotely
e.g. from a Windows PC (as has been described in an earlier post) you can use PLINK.EXE or encapsulate the remote SSH/TELNET request in say an Autoit script to be able to retrieve the outcome of the script execution.
(Obviously you could also have a cron entry to schedule the script locally on the router.)
So the script simply adds/deletes the 'decision' rule
I wrote the following script originally to selectively route either a specific device or a group of devices using the iptables 'fwmark' technique but you can see from the comments that it now currently uses the RPDB policy 'ip rules' method.
NOTE: The script should be used as an example, and appears overly complicated but essentially it simply adds/deletes the routing decision rule so is really only 2 commands!
EDIT: Hmm perhaps I should have
actually replied to this thread ....
http://www.snbforums.com/threads/ho...-from-open-vpn-client-using-batch-file.27678/
Code:
#!/bin/sh
# Usage: VPN_select_ON_OFF {1 | 2 | 3} [host.dnsmasq | ip_address | KEY_tag] {ON | OFF} {FORCE | NOFORCE}
#
#
# where 1 | 2 VPN Client to be used
# 3 PPTP or L2TP Client to be used
# Host.dnsmasq will be matched against /etc/hosts.dnsmasq contents
# Key_tag will be matched against /mnt/$MYROUTER/VPN_MASKS.txt
#
# ON | OFF VPN routing (if omitted then the audit file will be used to flip)
#
# FORCE | NOFORCE Enforce or remove WAN blocking
# e.g.
#
# VPN_select_ON_OFF 1 u200-115 on force
# VPN_select_ON_OFF 1 u200-115 off noforce
# VPN_select_ON_OFF 1 u200-115 off
# VPN_select_ON_OFF 2 192.168.10.8/29
# VPN_select_ON_OFF 2 192.168.10.200-192.168.10.203 on force
# VPN_select_ON_OFF 1 192.168.10.8/29 force
# VPN_select_ON_OFF 1 192.168.10.8/29 noforce
#
# VPN_select_ON_OFF 1 All_Phones off
#
MYROUTER=$(nvram get computer_name)
USEPATH="/tmp/mnt/$MYROUTER"
if [ "$1" != "1" ] && [ "$1" != "2" ] && [ "$1" != "3" ];then
logger -s -t "($(basename $0))" $$ **ERROR First arg $1 must be 1,2 or 3...... [$@]
exit 1
else
if [ "$1" != "3" ];then
logger -s -t "($(basename $0))" $$ VPN$1 Selective routing for [$@]
else
logger -s -t "($(basename $0))" $$ PPTP/L2TP Selective routing for [$@]
fi
fi
# Translate input args into UPPERCASE
ACTION=`echo $3 | tr '[a-z]' '[A-Z]'`
FORCE=`echo $4 | tr '[a-z]' '[A-Z]'`
# Check if WAN access id to be blocked $3=FORCE requested
if [ "$ACTION" = "FORCE" ];then
ACTION="NULL"
FORCE="FORCE"
fi
# Check if WAN access id to be unblocked $3=NOFORCE requested
if [ "$ACTION" = "NOFORCE" ];then
ACTION="NULL"
FORCE="NOFORCE"
fi
# Perform a lookup if a hostname (or I/P address) is supplied and is not known to PING
# NOTE: etc/host.dnsmasq is in format
#
# I/P address hostname
#
if [ "$1" != "" ];then
IP_NAME=`echo $2 | tr '[a-z]' '[A-Z]'`
IP_RANGE=`ping -c1 -t1 -w1 $IP_NAME 2>&1 | tr -d '():' | awk '/^PING/{print $3}'`
if [ -z $IP_RANGE ];then # Not PINGable so lookup static
IP_RANGE=`grep -i "$IP_NAME" /etc/hosts.dnsmasq | awk '{print $1}'`
logger -s -t "($(basename $0))" $$ "Lookup '$IP_NAME' in DNSMASQ returned:>$IP_RANGE<"
# If entry not matched in /etc/hosts.dnsmasq see if it exists in our VPN_MASKS.txt lookup file
#
# KEY I/P address
#
if [ "$IP_RANGE" = "" ];then
IP_RANGE=`grep -i "^$2" $USEPATH/VPN_MASKS.txt | awk '{print $2}'`
logger -s -t "($(basename $0))" $$ "Lookup '$IP_NAME' in $USEPATH/VPN_MASKS.txt returned:>$IP_RANGE<"
fi
fi
else
#IP_NAME="U200-115"
IP_NAME="HP-SPECTRE"
IP_RANGE=`grep -i $IP_NAME /etc/hosts.dnsmasq | awk '{print $1}'`
logger -s -t "($(basename $0))" $$ "DEFAULT '$IP_NAME' lookup returned:>$IP_RANGE<"
fi
echo "Processing options: $IP_NAME - $ACTION - $FORCE"
# Validate the I/P address
REGEX="\b(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b"
CHECK=$(echo $IP_RANGE | egrep $REGEX)
if [[ "$?" -eq 0 ]];then
echo "Valid IP address " $IP_RANGE
else
logger -s -t "($(basename $0))" $$ **ERROR Invalid IP address $IP_RANGE
exit 1
fi
if [ "$IP_RANGE" = "" ];then
logger -s -t "($(basename $0))" $$ "**ERROR Missing arg: DNSMASQ hostname or IP address"
exit 1
fi
# Is the actual VPN client UP....well is there a route to the VPN?
VPNROUTE=`ip route show | grep -a "dev tun1"$1`
if [ "x$VPNROUTE" = "x" ];then
logger -s -t "($(basename $0))" $$ "**Warning VPN Client$1 is not UP?"
#exit 1
fi
# Flip the VPN selective routing if the tracking file exists and no explicit directive supplied
if [ -e $USEPATH/VPN_$IP_RANGE.txt ] && [ "$ACTION" = "" ] ;then
# Retrieve the previous known status (Reboot should definitely delete these files? - see post-mount or ip_down event?)
ON_OFF=`cat $USEPATH/VPN_$IP_RANGE.txt`
if [ "$ON_OFF" = `grep -i "VPN"$1 /jffs/configs/VPNSelect | awk '{print $3}'` ];then
ACTION="OFF"
logger -s -t "($(basename $0))" $$ "Current '$IP_NAME' tracking file is MARK=$ON_OFF (ON)"
else
ACTION="ON"
logger -s -t "($(basename $0))" $$ "Current '$IP_NAME' tracking file is MARK=$ON_OFF (OFF)"
fi
fi
MY_VPNTAB=`grep -i "VPN$1" /jffs/configs/VPNSelect | awk '{print $2}'`
# Turn selective routing OFF
if [ "$ACTION" = "OFF" ];then
ON_OFF=0
#logger -s -t "($(basename $0))" $$ VPN$1 Selective routing for $IP_RANGE set MARK=$ON_OFF "(OFF)"
logger -s -t "($(basename $0))" $$ VPN$1 Selective routing for $IP_RANGE RPDB $MY_VPNTAB "(OFF)"
# Remove the selective rerouting....why ADD a new line with the mark set OFF?
#iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range $IP_RANGE -j MARK --set-mark $ON_OFF
# .... why not simply delete the entire entry..but have to try all MARK entries!!!!
#iptables -t mangle -D PREROUTING -i br0 -m iprange --src-range $IP_RANGE -j MARK --set-mark 1 2> /dev/null > /dev/null
#iptables -t mangle -D PREROUTING -i br0 -m iprange --src-range $IP_RANGE -j MARK --set-mark 2
ip rule del from $IP_RANGE lookup $MY_VPNTAB 2> /dev/null > /dev/null
fi
# Turn selective routing ON
if [ "$ACTION" = "ON" ];then
#ON_OFF=2
ON_OFF=`grep -i "VPN"$1 /jffs/configs/VPNSelect | awk '{print $3}'`
#logger -s -t "($(basename $0))" $$ VPN$1 Selective routing for $IP_RANGE set MARK=$ON_OFF "(ON)"
# Enable the selective rerouting
# Prevent duplicate selective routing rule entries
# If the $IP_RANGE is xxx.xxx.xxx.xxx-xxx.xxx.xxx.xxx or xxx.xxx.xxx.xxx,xxx.xxx.xxx.xxx then use -t mangle syntax
#iptables -t mangle -D PREROUTING -i br0 -m iprange --src-range $IP_RANGE -j MARK --set-mark $ON_OFF 2> /dev/null > /dev/null
#iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range $IP_RANGE -j MARK --set-mark $ON_OFF
# Example for routing a specific port via VPN
# iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range $IP_RANGE -p tcp --dport ppppp -j MARK --set-mark $ON_OFF
#Apr 2015: Policy routing is more reliable for devices and or a subnet mask;
# i.e if the -t mangle table gets flushed by the DPI engine? then selective routing via ip rule will STILL work!
# iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range xxx.xxx.xxx.xxx -j MARK --set-mark $TAG_MARK
# or
logger -s -t "($(basename $0))" $$ VPN$1 Selective routing for $IP_RANGE RPDB $MY_VPNTAB "(ON)"
ip rule del from $IP_RANGE lookup $MY_VPNTAB 2> /dev/null > /dev/null
ip rule add from $IP_RANGE lookup $MY_VPNTAB
# The two statements above are the same... and we can route ALL devices via the VPN...
# iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range xxx.xxx.xxx.0/24 -j MARK --set-mark $TAG_MARK
# or
# ip rule add from xxx.xxx.xxx.0/24 lookup $MY_VPNTAB
fi
# Optionally FORCE the use of the VPN tunnel, so if the VPN tunnel drops, the device will not use the unencrypted default WAN
if [ "$FORCE" = "FORCE" ];then
logger -s -t "($(basename $0))" $$ VPN$1 Selective routing for $IP_RANGE WAN access blocked
# Prevent duplicate blocking rule entries
iptables -D FORWARD -i br0 -s $IP_RANGE -o eth0 -j DROP 2> /dev/null > /dev/null
iptables -I FORWARD -i br0 -s $IP_RANGE -o eth0 -j DROP
#ip route add unreachable default table $VPN_TBL
fi
# Allow removing of the WAN blocking if it was previously set
if [ "$FORCE" = "NOFORCE" ];then
logger -s -t "($(basename $0))" $$ VPN$1 Selective routing for $IP_RANGE WAN access allowed
iptables -D FORWARD -i br0 -s $IP_RANGE -o eth0 -j DROP 2> /dev/null > /dev/null
#ip route del unreachable default table $VPN_TBL
fi
# Track known status of VPN selective routing.....
echo $ON_OFF > $USEPATH/VPN_$IP_RANGE.txt
# Debug the routing tables
/jffs/scripts/IPTablesDump.sh "VPN$1_Client_$IP_RANGE-$ACTION"
exit 0