What's new
  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

Update VPN client policy at runtime

Paul_1984

New Around Here
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:
  1. Router: Asus RT-AC5300 with Merlin RT-AC5300_380.65_2
  2. Only use OpenVPN (this is a requirement for AirVPN)
    • AirVPN only allows 3 concurrent connections, but I'll deal with that later
  3. Any device can select a different VPN client without logging into the router
  4. 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.
  5. A long-term solution should probably be a custom web form hosted on the router that does not require a login.
Here is my [potential] solution:
  1. Configure the router for several VPN profiles (client1, client2, ...).
    • Policy rules must be enabled and enforced.
  2. When the router detects a device attempting to browse to a specific IP/URL, then execute a custom script.
  3. 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
 
Why not simply configure a static IP on the client, and change the IP based on which tunnel you want to use? You can then define policy rules based on those different subnets.
 
Why not simply configure a static IP on the client, and change the IP based on which tunnel you want to use? You can then define policy rules based on those different subnets.
I considered that by way of various SSIDs, and then just changing my network as necessary, but I didn't like that because:
  1. It would flood my already congested neighborhood with many more SSIDs; they could be hidden, but they would still be there.
  2. It wouldn't work for my desktop; I could manually set the IP, but then my other computers that stream from my desktop would fail.
  3. It just seems like a clunky solution.
 
  • 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.

Is there a script that only executes because of a failed DNS lookup? Maybe this script can be injected there instead of every network request. That should not have much of an impact on performance like that.
 

Similar threads

Latest threads

Support SNBForums w/ Amazon

If you'd like to support SNBForums, just use this link and buy anything on Amazon. Thanks!

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Back
Top