Last active
April 25, 2024 10:17
-
-
Save skipperTux/5bbc3d261c82c21bfee530d518a4bc38 to your computer and use it in GitHub Desktop.
Bash script for managing WireGuard connections using NetworkManager CLI
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -o nounset | |
set -o pipefail | |
#set -o xtrace | |
# http://www.tldp.org/LDP/abs/html/exitcodes.html | |
# user-defined exit codes range 64 - 113 (in addition to 0, for success) | |
readonly SUCCESS=0 | |
readonly E_NO_CONNECTION_PROFILE=64 | |
readonly E_UNKNOWN_CONNECTION_PROFILE=65 | |
readonly E_INVALID_CONNECTION_STATUS=66 | |
readonly E_CONNECTION_NAME_TOO_LONG=67 | |
# constant variables | |
YELLOW=$(tput setaf 226) | |
readonly YELLOW | |
ORANGE=$(tput setaf 208) | |
readonly ORANGE | |
RED=$(tput setaf 196) | |
readonly RED | |
RESET=$(tput sgr0) | |
readonly RESET | |
readonly INFO="${YELLOW}INFO:${RESET} " | |
readonly WARNING="${ORANGE}WARNING:${RESET} " | |
readonly ERROR="${RED}ERROR:${RESET} " | |
readonly DQT='"' | |
readonly WIREGUARD_TYPE='wireguard' | |
readonly WIREGUARD_CONFIGS='/etc/wireguard' | |
readonly CONNECTION_NAME_MAX_LENGTH=15 | |
# variables | |
connection='up' | |
autoconnect=false | |
# https://stackoverflow.com/questions/192249/how-do-i-parse-command-line-arguments-in-bash/39398359#39398359 | |
# As long as there is at least one more argument, keep looping | |
while [[ $# -gt 0 ]]; do | |
key="$1" | |
case "$key" in | |
# Also a flag type option. Will catch either -i or --import | |
-i|--import) | |
connection='import' | |
;; | |
# Also a flag type option. Will catch either -rm or --remove | |
-rm|--remove) | |
connection='remove' | |
;; | |
# Also a flag type option. Will catch either -r or --reload | |
-r|--reload) | |
connection='reload' | |
;; | |
# This is a flag type option. Will catch either -u or --up | |
-u|--up) | |
connection='up' | |
;; | |
# Also a flag type option. Will catch either -d or --down | |
-d|--down) | |
connection='down' | |
;; | |
# This is a flag type option. Will catch either -h or --help | |
-h|--help) | |
connection='help' | |
;; | |
# Also a flag type option. Will catch either -a or --auto-connect | |
-a|--auto-connect) | |
autoconnect=true | |
;; | |
# This is an arg value type option. Will catch -ds value or --dns-search value | |
-ds|--dns-search) | |
shift # past the key and to the value | |
dns_search="$1" | |
;; | |
# This is an arg=value type option. Will catch -ds=value or --dns-search=value | |
-ds=*|--dns-search=*) | |
# No need to shift here since the value is part of the same string | |
dns_search="${key#*=}" | |
;; | |
# This is an arg value type option. Will catch -cn value or --connection-name value | |
-cn|--connection-name) | |
shift # past the key and to the value | |
connection_name="$1" | |
;; | |
# This is an arg=value type option. Will catch -cn=value or --connection-name=value | |
-cn=*|--connection-name=*) | |
# No need to shift here since the value is part of the same string | |
connection_name="${key#*=}" | |
;; | |
*) | |
# Do whatever you want with extra argument | |
echo "Unknown argument '$key'" | |
connection='help' | |
;; | |
esac | |
# Shift after checking all the cases to get the next option | |
shift | |
done | |
# functions | |
show_help() { | |
# display help | |
echo "Usage: wg-nmcli [COMMAND] [IMPORT-OPTIONS] { CONNECTION-NAME | help }" | |
echo "Manage WireGuard connections using NetworkManager CLI." | |
echo | |
echo "COMMAND" | |
echo " -i, --import import an external WireGuard configuration as a NetworkManager connection profile" | |
echo "-rm, --remove delete a WireGuard connection profile" | |
echo " -r, --reload re-import (remove and import) an external WireGuard configuration" | |
echo " -u, --up activate a WireGuard connection (default)" | |
echo " -d, --down deactivate a WireGuard connection" | |
echo " -h, --help print this help" | |
echo | |
echo "IMPORT-OPTIONS" | |
echo " -a, --auto-connect enable auto-connect for WireGuard connection profile" | |
echo "-ds, --dns-search[=]ARG Modify 'DNS domain' property of the WireGuard connection profile" | |
echo " ARG := ${DQT}comma separated list of domains${DQT} (see https://blogs.gnome.org/mcatanzaro/2020/12/17/understanding-systemd-resolved-split-dns-and-vpn-configuration/)" | |
echo | |
echo "CONNECTION-NAME" | |
echo "-cn, --connection-name[=]ARG name of the WireGuard connection profile (mandatory)" | |
echo " ARG := ${DQT}WireGuard connection profile name${DQT}" | |
echo | |
} | |
connection_status() { | |
if [ "${connection_name:-}" = "" ]; then | |
echo "${ERROR}Please provide a WireGuard connection profile name." | |
exit ${E_NO_CONNECTION_PROFILE} | |
fi | |
if [ "${#connection_name}" -gt ${CONNECTION_NAME_MAX_LENGTH} ]; then | |
echo "${ERROR}WireGuard connection name too long, must not exceed ${CONNECTION_NAME_MAX_LENGTH}." | |
exit ${E_CONNECTION_NAME_TOO_LONG} | |
fi | |
conn_exists=$(nmcli connection show | grep -icP "(${connection_name})(.*)(${WIREGUARD_TYPE})") | |
conn_up=$(nmcli connection show | grep -icP "(${connection_name})(.*)(${WIREGUARD_TYPE})(\s*)(${connection_name})") | |
if [ "${conn_exists}" -eq 0 ]; then | |
if [ "${connection:-}" != "import" ]; then | |
echo "${ERROR}WireGuard connection profile '${connection_name}' does not exist." | |
exit ${E_UNKNOWN_CONNECTION_PROFILE} | |
fi | |
else | |
if [ "${connection:-}" = "import" ]; then | |
connection='reload' | |
echo "${INFO}WireGuard connection profile '${connection_name}' already exists, reloading." | |
fi | |
fi | |
} | |
connection_up() { | |
if [ "${conn_up}" -eq 1 ]; then | |
echo "${WARNING}WireGuard connection '${connection_name}' already active." | |
exit ${E_INVALID_CONNECTION_STATUS} | |
fi | |
nmcli connection up "${connection_name}" | |
} | |
connection_down() { | |
if [ "${conn_up}" -eq 0 ]; then | |
echo "${WARNING}WireGuard connection '${connection_name}' not active." | |
exit ${E_INVALID_CONNECTION_STATUS} | |
fi | |
nmcli connection down "${connection_name}" | |
} | |
connection_import() { | |
sudo nmcli connection import type ${WIREGUARD_TYPE} file "${WIREGUARD_CONFIGS}/${connection_name}.conf" | |
if [ "${autoconnect:-}" != "true" ]; then | |
nmcli connection modify "${connection_name}" autoconnect no | |
fi | |
nmcli connection modify "${connection_name}" ipv4.never-default true | |
if [ "${dns_search:-}" != "" ]; then | |
nmcli connection modify "${connection_name}" ipv4.dns-search "${dns_search}" | |
fi | |
nmcli connection modify "${connection_name}" connection.permissions "user:$(id -nu)" | |
} | |
connection_remove() { | |
sudo nmcli connection delete "${connection_name}" | |
} | |
connection_reload() { | |
connection_remove | |
connection_import | |
} | |
# script main | |
if [ "${connection:-}" = "help" ]; then | |
show_help | |
exit ${SUCCESS} | |
fi | |
connection_status | |
case "${connection:-}" in | |
up) | |
connection_up | |
;; | |
down) | |
connection_down | |
;; | |
import) | |
connection_import | |
;; | |
remove) | |
connection_remove | |
;; | |
reload) | |
connection_reload | |
;; | |
*) | |
show_help | |
;; | |
esac |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment