I want to configure my router for various OpenVPN client profiles (US, EU, Asia, ...), but I want any network device to be able to select/change which profile to use ad-hoc without logging into the router each time.
I started down the path of creating SSID specific IP ranges and then assigning each range to the various VPN policies, but I don't think that's a very elegant solution. I'm a noob at router programming, and I have little shell scripting experience, but I think I have a pretty dynamic solution... if the performance is acceptable.
Here are my requirements and assumptions:
Here is my draft script:
I started down the path of creating SSID specific IP ranges and then assigning each range to the various VPN policies, but I don't think that's a very elegant solution. I'm a noob at router programming, and I have little shell scripting experience, but I think I have a pretty dynamic solution... if the performance is acceptable.
Here are my requirements and assumptions:
- Router: Asus RT-AC5300 with Merlin RT-AC5300_380.65_2
- Only use OpenVPN (this is a requirement for AirVPN)
- AirVPN only allows 3 concurrent connections, but I'll deal with that later
- Any device can select a different VPN client without logging into the router
- The whole process should aim to limit overhead
- This script probably requires every network packet/destination to be examined, but that is ok for this proof of concept... unless it truly kills network performance.
- A long-term solution should probably be a custom web form hosted on the router that does not require a login.
- Configure the router for several VPN profiles (client1, client2, ...).
- Policy rules must be enabled and enforced.
- When the router detects a device attempting to browse to a specific IP/URL, then execute a custom script.
- dynamic_vpn.sh
- Iterate through each client and remove any policy rules for that device.
- Add policy entry for the device under the chosen client (based on IP/URL)
Here is my draft script:
Code:
#!/bin/sh
########################################
## File Name: dynamic_vpn.sh
## Author: Paul_1984
## Created Date: 03/30/2017
## Update Date: 03/30/2017
## Purpose: Update VPN client policy at runtime.
## Notes: (1) This is based on the capabilities of Asus RT-AC5300 with Merlin RT-AC5300_380.65_2
## (2) Assumption: only using OpenVPN
## (3) Assumption: each VPN client may have a default CIDR range (192.168.1.144/28).
## (4) Assumption: every SOURCE is on LAN (low-risk).
## (5) Assumption: any SOURCE is allowed to update their VPN (even guests).
## Instructions: (1) File location: /jffs/scripts/dynamic_vpn.sh
## (2) Edit /jffs/scripts/???.sh; append the following commands at line ???:
## DESTINATION_IP="$TBD"
## VPN_COMMANDS_LIST="192.168.250.1 192.168.250.2 192.168.250.3 ..."
## if [ `expr index "$VPN_COMMANDS_LIST" "$DESTINATION_IP"` -gt 0 ]; then
## SOURCE_IP="$TBD"
## /jffs/scripts/dynamic_vpn.sh "$SOURCE_IP" "$DESTINATION_IP"
## fi
## (3) Have PC/iPhone/tablet browse to specific IP to update VPN policy; 404 is expected.
## Change History: (03/30/2017 by Paul_1984) Added option for no VPN.
## Known Issues: (1) Is this even possible?
## (2) Where to place this file?
## (3) What other scripts require update?
## (4) What parameters will it receive?
## (5) Confirm VPN Client names (tun11, tun22, ...).
## (6) Replace all "ToDo" placeholders.
########################################
main() {
SOURCE_IP=$1
DESTINATION_IP=$2
case "$DESTINATION_IP" in
"192.168.250.1") set_client_policy "tun11" ;; # Client1 = US
"192.168.250.2") set_client_policy "tun22" ;; # Client2 = EU
"192.168.250.3") set_client_policy "tun33" ;; # Client3 = Asia
"192.168.250.4") set_client_policy "tun44" ;; # Client4 = TBD
"192.168.250.5") set_client_policy "tun55" ;; # Client5 = TBD
"192.168.250.6") set_client_policy "tun66" ;; # Client6 = TBD
"192.168.250.9") set_client_policy "wan" ;; # Don't use any VPN
*) ;; # Do Nothing
esac
return 0
}
set_client_policy() {
NEW_CLIENT=$1
VPN_CLIENTS="tun11 tun22 tun33 tun44 tun55 tun66"
logger "dynamic_vpn.sh [Begin]: SOURCE_IP=["$SOURCE_IP"] NEW_CLIENT=["$NEW_CLIENT"];"
for CL_X in $VPN_CLIENTS # Loop each VPN Client
do
# Step 1: remove all specific SOURCE_IP policies
CL_X_POLICIES="ToDo: Get all policy records"
for POLICY in $CL_X_POLICIES # Loop each policy record
do
POLICY_SOURCE_IP="ToDo: Get the source IP for a specific policy record"
POLICY_DESTINATION_IP="ToDo: Get the destination IP for a specific policy record"
POLICY_TYPE="ToDo: Get the type for a specific policy record (VPN/WAN)"
if [ "$POLICY_SOURCE_IP" = "$SOURCE_IP" ]; then
#ToDo: delete policy record
logger "dynamic_vpn.sh: SOURCE_IP=["$SOURCE_IP"] removed from VPN_CLIENT=["$CL_X"] DESTINATION_IP=["$POLICY_DESTINATION_IP"] TYPE=["$POLICY_TYPE"];"
fi
done
# Step 2: Create new policy for SOURCE_IP; assume each Client has default a CIDR range
if [ "$NEW_CLIENT" = "$CL_X" ]; then
#ToDo: create policy record for $CL_X $SOURCE_IP destination="0.0.0.0" type="VPN"
logger "dynamic_vpn.sh: SOURCE_IP=["$SOURCE_IP"] added to VPN_CLIENT=["$CL_X"];"
elif [ "$NEW_CLIENT" = "wan" ]; then
#ToDo: create policy record for $CL_X $SOURCE_IP destination="0.0.0.0" type="WAN"
logger "dynamic_vpn.sh: SOURCE_IP=["$SOURCE_IP"] excluded from VPN_CLIENT=["$CL_X"];"
fi
done
logger "dynamic_vpn.sh [End];"
return 0
}
main "$@"
exit 0