diff options
| author | Robert Günzler <r@gnzler.io> | 2026-04-08 13:18:14 +0900 |
|---|---|---|
| committer | Robert Günzler <r@gnzler.io> | 2026-04-08 13:18:14 +0900 |
| commit | b61b58ce2c1371d6f904f108fa7feed3abfbe5c7 (patch) | |
| tree | 008a5cf54ecbfffb97ddac30e44c8ab224395ab0 /bin/vpnm | |
| parent | d4620f3ac119263fee90bd819eadaf84fc8d50b7 (diff) | |
*
Automated-commit-by: dots Signed-off-by: Robert Günzler <r@gnzler.io>
Diffstat (limited to 'bin/vpnm')
| -rwxr-xr-x | bin/vpnm | 124 |
1 files changed, 124 insertions, 0 deletions
diff --git a/bin/vpnm b/bin/vpnm new file mode 100755 index 0000000..f09b41a --- /dev/null +++ b/bin/vpnm @@ -0,0 +1,124 @@ +#!/bin/bash +set -eu + +# shellcheck disable=2034 +description="vpn manager" + +FUZL_PROMPT=vpnm +FUZL_ICON= +. libfuzl.sh + +main() { + local conn + + conn=$(get_current_connection) + [ -n "$conn" ] && fuzl_action_add "down" "" "Connected to $conn" + fuzl_action_add "networks" "" "Available networks" + fuzl_action_add "profile" "" "Switch profile" + + fuzl_action_menu || return +} + +# +# helpers +# + +get_emoji_flag() { + code= + # TODO: calc flag + # U\1F1E6 A + # U\200D zero-w joiner + case "$*" in + au-*) code=$'🦘' ;; + be-*) code=$'🇧🇪' ;; + br-*) code=$'🇧🇷' ;; + ca-*) code=$'🇨🇦' ;; + de-*) code=$'🇩🇪' ;; + fr-*) code=$'🇫🇷' ;; + gb-*) code=$'🇬🇧' ;; + jp-*) code=$'🇯🇵' ;; + no-*) code=$'🇳🇴' ;; + se-*) code=$'🇸🇪' ;; + us-*) code=$'🇺🇸' ;; + *tail2d6ce*) code=$'' ;; + *) code=$'🌐' ;; + esac + echo -n $code +} + +get_vpn_connections() { + ( + tailscale exit-node list | + awk '/.tail2d6ce.ts.net/{print $2, $1}' + tailscale exit-node list | + awk -F '[ ]{2,}' '/.mullvad.ts.net/{print $2, $1, ($3 "/" $4)}' | + sort -u + ) | while read -r conn ip location; do + printf '%s\t' "$ip" + printf '%s\t' "$(get_emoji_flag "$conn")" + if grep -q 'mullvad.ts.net' <<<"$conn"; then + printf '%s\t' "$location" + else + printf '%s\t' "$conn" + fi + printf '\n' + done +} + +get_current_connection() { + tailscale exit-node list | + grep -e selected | + grep -v -e Any | ( + awk '/.tail2d6ce.ts.net/{print $2, $1}' + awk -F '[ ]{2,}' '/.mullvad.ts.net/{print $2, $1, ($3 "/" $4)}' + ) | while read -r conn ip location; do + printf '%s' "$(get_emoji_flag "$conn")" + printf ' ' + if grep -q 'mullvad.ts.net' <<<"$conn"; then + printf '%s' "$location" + else + printf '%s' "$conn" + fi + done +} + +vpnup() { + fuzl_try -- tailscale set --exit-node=${1:?} + fuzl_try -- pkill -RTMIN+2 -x waybar +} + +vpndown() { + fuzl_try -- tailscale set --exit-node= + fuzl_try -- pkill -RTMIN+2 -x waybar +} + +# +# actions +# + +vpnm_down() { + fuzl_try -- vpndown +} + +vpnm_networks() { + ip=$(get_vpn_connections | + fuzl_menu $FUZL_MENU_FILTER --with-nth='{2} {3}' --accept-nth=1) + + [ -n "$ip" ] || main + fuzl_try -- vpnup "$ip" + +} + +vpnm_profile() { + profile=$(tailscale switch --list 2>/dev/null | + tail -n+2 | + awk '{printf "%s\t%s\n", $3, $2}' | + fuzl_menu $FUZL_MENU_FILTER --accept-nth=1) + + [ -n "$profile" ] || main + fuzl_try -- tailscale switch "$profile" + sleep 2 + fuzl_try -- pkill -SIGRTMIN+2 waybar +} + +main |