Updating the `vpn-profile-switcher.sh` to Include WireGuard Support
In a recent update to the vpn-profile-switcher.sh
script, I have added support for WireGuard, expanding its functionality beyond the initial OpenVPN compatibility. This update allows users to choose between OpenVPN and WireGuard for their VPN configurations on OpenWRT. Below, I will walk you through the changes and explain the new options and functionalities added to the script.
Overview of the Script
The vpn-profile-switcher.sh
script automates the process of retrieving the recommended NordVPN server, downloading its configuration file, setting the credentials, and configuring OpenWRT to use this server. Initially designed for OpenVPN, the script now includes support for WireGuard, a faster and more efficient VPN protocol.
Key Updates for WireGuard Support
New Options in the Usage Function
To accommodate WireGuard, new command-line options have been added:
printf " -t | --type < openvpn | wireguard >,\t\tSelect either OpenVPN or WireGuard. Default is OpenVPN.\n"
printf " -i | --interface < interface >,\t\tSpecify interface to use for WireGuard. Default is 'nordlynx'. Applicable only for WireGuard.\n"
The --type
option allows the user to select the VPN type, either openvpn
or wireguard
. The --interface
option specifies the interface to use for WireGuard, with nordlynx
as the default.
Verification Functions
Two new functions ensure that valid values are provided for the --type
and --interface
options:
function verify_vpn_type() {
if [ ! "$1" == "openvpn" ] && [ ! "$1" == "wireguard" ]; then
logger -s "($0) VPN type must be either openvpn or wireguard, your input was: $1."
exit 1
else
echo $1
fi
}
function verify_protocol() {
if [ ! "$1" == "tcp" ] && [ ! "$1" == "udp" ]; then
logger -s "($0) Protocol must be either udp or tcp, your input was: $1."
exit 1
else
echo $1
fi
}
Fetching Recommendations
The get_recommended
function fetches the recommended server configuration. If WireGuard is selected, it also retrieves the server’s public key:
function get_recommended() {
_url="https://api.nordvpn.com/v1/servers/recommendations?"
if [ ! -z "$group_identifier" ]; then
_url=${_url}"filters[servers_groups][identifier]="${group_identifier}"&"
fi
if [ ! -z "$country_id" ]; then
_url=${_url}"filters[country_id]="${country_id}"&"
fi
_url=${_url}"filters[servers_technologies][identifier]="${vpn_type}"_"${protocol}"&limit="${recommendations_n}
logger -s "($0) Fetching VPN recommendations from: $_url"
_json=$(wget -q -O - "$_url") || true
recommended=$(jsonfilter -s "$_json" -e '$[0].hostname') || true
recommendations=$(jsonfilter -s "$_json" -e '$[*].hostname') || true
loads=$(jsonfilter -s "$_json" -e '$[*].load') || true
if [ "$vpn_type" == "wireguard" ]; then
public_key=$(jsonfilter -s "$_json" -e '$[0].technologies[*].metadata[*].value') || true
fi
}
Configuration Handling
The script includes functions for checking existing configurations and enabling or disabling them as needed:
function check_in_configs() {
if [ "$vpn_type" == "openvpn" ]; then
server_name=$(uci show openvpn | grep $recommended.$protocol | awk -F '\.' '/config/{print $2}')
elif [ "$vpn_type" == "wireguard" ]; then
server_name=$(uci show network | grep "${wg_iface}.*endpoint_host.*${recommended}" | sed -E 's/.*_([a-z]{0,2}[0-9]{1,3}).*='\''(.*)'\''$/\1/')
fi
}
function check_enabled() {
if [ "$vpn_type" == "openvpn" ]; then
enabled_server=$(uci show openvpn | grep "enabled='1'" | awk -F '\.' '/.*/{print $2}')
elif [ "$vpn_type" == "wireguard" ]; then
enabled_server=$(uci show network | grep "${wg_iface}.*disabled='0'" | sed -E 's/.*_([a-z]{0,2}[0-9]{1,3}).*='\''.*'\''$/\1/')
fi
}
Creating and Enabling Entries
For WireGuard, the script creates a new entry and configures it with the appropriate parameters:
function create_new_entry() {
if [ "$vpn_type" == "openvpn" ] then
new_server=$(echo "$recommended" | sed 's/[\.\ -]/_/g' | sed "s/com/$protocol/g")
uci set openvpn.$new_server=openvpn
uci set openvpn.$new_server.config="/etc/openvpn/$recommended.$protocol.ovpn"
elif [ "$vpn_type" == "wireguard" ] then
new_server=$(echo "$recommended" | sed -E 's/([a-z]{2}[0-9]{1,3}).*''$/\1/')
uci set network.${wg_iface}_peer_${new_server}="wireguard_$wg_iface"
uci set network.${wg_iface}_peer_${new_server}.public_key="$public_key"
uci set network.${wg_iface}_peer_${new_server}.endpoint_host="$recommended"
uci set network.${wg_iface}_peer_${new_server}.endpoint_port="51820"
uci set network.${wg_iface}_peer_${new_server}.persistent_keepalive="25"
uci set network.${wg_iface}_peer_${new_server}.route_allowed_ips="1"
uci add_list network.${wg_iface}_peer_${new_server}.allowed_ips="0.0.0.0/0"
uci add_list network.${wg_iface}_peer_${new_server}.allowed_ips="::/0"
uci set network.${wg_iface}_peer_${new_server}.description="$recommended"
fi
}
Restarting Services
Depending on the VPN type selected, the script restarts the appropriate service:
function restart_openvpn() {
uci commit openvpn
/etc/init.d/openvpn restart
}
function restart_wireguard() {
uci commit network
/etc/init.d/network restart
}
Execution
Finally, the script’s main execution block processes the provided command-line arguments and invokes the necessary functions to configure the VPN:
check_required
while [ ! -z "$1" ]; do
case "$1" in
-h | --help)
show_usage
;;
-t | --type)
shift
vpn_type=$(verify_vpn_type $1)
;;
-p | --protocol)
shift
protocol=$(verify_protocol $1)
;;
-c | --country)
shift
country_id=$(country_code $1)
;;
-g | --group)
shift
group_identifier=$(server_groups $1)
;;
-r | --recommendations)
shift
recommendations_n=$(check_is_num $1)
;;
-d | --distance)
shift
load_distance=$(check_is_num $1)
;;
-l | --login-info)
shift
secret="$1"
;;
-i | --interface)
shift
wg_iface="$1"
;;
-b | --db-location)
shift
db_location=$(verify_db_location $1)
;;
*)
show_usage
;;
esac
shift
done
# Fetch the recommended server
get_recommended
# Check if the recommended server is already configured
check_in_configs
# Disable the current server configuration if it exists
if [ ! -z "$server_name" ]; then
disable_current_entry $server_name
fi
# Create a new entry for the recommended server if it doesn't already exist
if [ -z "$server_name" ]; then
create_new_entry
else
enable_existing_entry $server_name
fi
# Restart the appropriate VPN service
if [ "$vpn_type" == "openvpn" ]; then
restart_openvpn
elif [ "$vpn_type" == "wireguard" ]; then
restart_wireguard
fi
# Clean up and exit
unset_variables
Conclusion
The vpn-profile-switcher.sh
script now offers robust support for both OpenVPN and WireGuard, providing flexibility and efficiency for users. This update simplifies the process of configuring VPN profiles on OpenWRT, ensuring a seamless experience regardless of the chosen VPN protocol. For more details, refer to the dev
branch on the repository on GitHub.
In the next post, I will cover adding some nice to have features as separate scripts, and perhaps add some test results. Stay tuned for more updates and enhancements to the VPN Profile Switcher script.
This post is a continuation of my previous post on parsinng NordVPN’s WireGuard info. Check it out, and check tthe
dev
branch of the repo for more info.