Jump to content
Not connected, Your IP: 3.17.165.235
jabberwock

Auto-connect to AirVPN from a Raspberry Pi using only GSM

Recommended Posts

Posted ... (edited)

The following script took hours of trial and error due to having to "fly blind".
This script is to be executed by the pi user, which must be set to auto-login. This script will wait for the designated interface to 1) Be up and 2) Match an expected IP address before attempting to launch AirVPN.
I needed a way to launch AirVPN when and only when the above criteria is met.

My scenario is that I want my Pi 4b to only connect to AirVPN when the GSB interface (usb0) is up and has its DHCP-assigned IP from the GSM stick's router. 
The GSM stick itself has port forwarding disabled in the firmware. AT&T does not allow port forwarding through these devices either. I needed AirVPN for port forwarding, so I could reach this solar-powered pi from any network in the world.

Prerequisites: 
You must have tmux installed, or please modify the script to launch things in the background as you like.

Place this script where you please. Name it "airvpn.sh" and make sure to chmod +x airvpn.sh to make it executable.

Then in your .bashrc, zshrc, or whichever script will launch during auto-login - place:
sudo ./airvpn.sh

Here is the script:

#!/bin/bash
# Helper to start up AirVPN from auto-login

# Author's scenario that inspired this script:
# I have a raspberry pi with a GSM USB stick. No other interface can be used.
# The firmware on the GSM does not allow port forwarding.
# I need to be able to reach my pi over SSH after it connects to the mobile broadband network.
# AirVPN was the way to go as it allows port forwarding.
# The kludgy reverse tunnel back into a VPC was very slow and also a greater security risk as
# it exposes the VPC as well as the Pi should either be compromised.

function start_airvpn() {
    # set this to the interface you want to be available before connecting to AirVPN
    local interface="usb0"
    # first 3 octets you expect the interface to have as IPv4 address:
    local first_three="192.168.0"

    # Change these if you must
    local bluetit_lock_file="/etc/airvpn/bluetit.lock"  # location of bluetit.lock
    local tmux_session_name="airvpn"       # target name for tmux session
    local seconds_to_abort=10              # number of seconds a user has to ctrl+c to stop the script
    local log_prefix="[AirVPN-Extension]"  # prefix for dmesg log entries


    # --------------------------------------------------------------
    # !!! Only edit below if you are confident in your abilties. !!!
    # --------------------------------------------------------------
    #local PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/bin:$PATH
    #source /etc/profile
    local force_restart=0

    function dmsg() {  # log to dmesg (kernel messge buffer)
        echo "$log_prefix $1" | tee /dev/kmsg
        return 0
    }

    case $1 in
        -f)
            force_restart=1
            ;;
        *)
            force_restart=0
            ;;
    esac

    if [ $UID -ne 0 ]; then
        echo "Please run this script as root or via \`sudo\`"
        exit 1
    fi

    if [ $force_restart -eq 0 ]; then
        if [ -f $bluetit_lock_file ]; then
            echo "$log_prefix: Found bluetit lock file. Exiting. Use -f to override."
            exit 0
        fi
    fi

    function wait_seconds() {  # pass seconds integer to this function; default $seconds_to_abort
        if [ "$1" ]; then
            local re='^[0-9]+$'
            if ! [[ $1 =~ $re ]] ; then
                echo "$log_prefix: non-number passed to wait_seconds()"
                exit 1
            fi
            local wait=$1
        else
            local wait=$seconds_to_abort
        fi
        local count=1
        while :; do
            sleep 1
            (( count+=1 ))
            if [ "$count" -eq $wait ]; then
               break
           fi
        done
    }


    # ----------------------------------------
    # Wait for GSM and then connect to AirVPN.
    # ----------------------------------------
    local sys_class_path="/sys/class/net/$interface"

    echo "$log_prefix Ready to configure AirVPN connection. Interrupt within $seconds_to_abort second(s) to cancel."
    wait_seconds $seconds_to_abort

    dmsg "Stopping bluetit service until interface $interface comes up."
    service bluetit stop
    dmsg "Waiting 5 seconds."
    sleep 5

    dmsg "Waiting for $sys_class_path"
    while :; do
        if [ -d $sys_class_path ]; then
            dmsg "$interface appeared."
            if [ "$(cat $sys_class_path/operstate)" == "up" ]; then
                dmsg "$interface is up."
                dmsg "Waiting for an IP address that matches $first_three (Cycling every 2 seconds)"
                while :; do
                    current_first_three=$(ip a s $interface | awk '/inet.*brd/ {print $2}' | cut -d'.' -f1-3)
                    if [ "$current_first_three" == $first_three ]; then
                        dmsg "Found $current_first_three on $interface"
                        break
                    fi
                    sleep 2
                done
                dmsg "Restarting bluetit service."
                while :; do
                    if service bluetit start; then
                        tmux kill-session -t $tmux_session_name &> /dev/null
                        dmsg "Connecting to AirVPN via Goldcrest."
                        tmux new -d -s $tmux_session_name "goldcrest --air-connect"
                        # ensure the tmux session persists even if its command fails, so we can see:
                        tmux set-option -t $tmux_session_name remain-on-exit on
                        dmsg "tmux session '$tmux_session_name' is available for interacting."
                        dmsg "To interact, type \`sudo tmux attach -t $tmux_session_name\`"
                        exit 0
                    else
                        dmsg "bluetit returned $?. Trying again in 5 seconds..."
                        sleep 5
                        continue
                    fi
                done
            fi
        fi
        dmsg "Waiting 5 seconds."
        sleep 5
    done
}
start_airvpn "$1"
 

Edited ... by wabbajack
Made suggestions from shellcheck linter. Updated header comments. Implemented edits suggested by staff.

Share this post


Link to post

Thank you for your submission. Unsure I can test it myself in the near future, but anyways, if it works, cool :)
One remark:

 

18 hours ago, wabbajack said:

                    local ip_first_3=$(ifconfig usb0 | grep "inet " | tr -s ' ' | cut -d' ' -f3 | cut -d'.' -f1-3)


Since net-tools has been obsolete for years, consider using iproute2 here:
local ip_first_three=$(ip a s $interface | awk '/inet.*brd/ {print $2}' | cut -d'.' -f1-3)

NOT AN AIRVPN TEAM MEMBER. USE TICKETS FOR PROFESSIONAL SUPPORT.

LZ1's New User Guide to AirVPN « Plenty of stuff for advanced users, too!

Want to contact me directly? All relevant methods are on my About me page.

Share this post


Link to post

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Security Check
    Play CAPTCHA Audio
    Refresh Image

×
×
  • Create New...