feat(@scripts): ✨ add sudo-less wg-bounce restart tool
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
30da76d909
commit
bf36c94464
2 changed files with 107 additions and 0 deletions
95
bin/wg-bounce
Executable file
95
bin/wg-bounce
Executable file
|
|
@ -0,0 +1,95 @@
|
||||||
|
#!/bin/sh
|
||||||
|
# wg-bounce — restart the wg1 tunnel without an interactive sudo password.
|
||||||
|
#
|
||||||
|
# macOS WireGuard (wg-quick) needs root to create the utun interface and
|
||||||
|
# install routes. This script invokes it via `sudo -n`. If the sudoers entry
|
||||||
|
# is missing, the script offers to install it from the bundled template
|
||||||
|
# (a single password prompt that won't be needed again).
|
||||||
|
#
|
||||||
|
# Usage:
|
||||||
|
# wg-bounce # down + up the default config
|
||||||
|
# wg-bounce <conf-path> # down + up a specific .conf file
|
||||||
|
#
|
||||||
|
# Exit codes:
|
||||||
|
# 0 success
|
||||||
|
# 1 setup needed and the install prompt failed
|
||||||
|
# 2 wg-quick down or up failed
|
||||||
|
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
conf=${1:-"$HOME/.wireguard/wg1.conf"}
|
||||||
|
|
||||||
|
if [ ! -r "$conf" ]; then
|
||||||
|
echo "wg-bounce: missing config $conf" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Resolve symlinks so $script_dir points at the real bin/ inside session-tools,
|
||||||
|
# letting us find ../share/. macOS /bin/sh lacks `readlink -f`, so walk it
|
||||||
|
# manually until we hit a non-symlink.
|
||||||
|
resolve_link() {
|
||||||
|
target=$1
|
||||||
|
while [ -L "$target" ]; do
|
||||||
|
link=$(readlink "$target")
|
||||||
|
case $link in
|
||||||
|
/*) target=$link ;;
|
||||||
|
*) target=$(dirname "$target")/$link ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
printf %s "$target"
|
||||||
|
}
|
||||||
|
script_path=$(resolve_link "$0")
|
||||||
|
script_dir=$(cd "$(dirname "$script_path")" && pwd)
|
||||||
|
sudoers_src="$script_dir/../share/wg-quick.sudoers"
|
||||||
|
sudoers_dst=/etc/sudoers.d/wg-quick
|
||||||
|
|
||||||
|
if ! sudo -n /opt/homebrew/bin/wg-quick --help >/dev/null 2>&1; then
|
||||||
|
# Sudoers entry missing or doesn't apply yet. Try to install it from the
|
||||||
|
# bundled template — this is the ONE prompt for a password we accept; all
|
||||||
|
# subsequent wg-bounce runs are passwordless.
|
||||||
|
if [ ! -r "$sudoers_src" ]; then
|
||||||
|
echo "wg-bounce: sudoers template missing at $sudoers_src" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "wg-bounce: first run — installing $sudoers_dst (one-time sudo prompt)"
|
||||||
|
# Validate the template before installing so a typo never lands in
|
||||||
|
# /etc/sudoers.d (visudo -c -f checks parseability).
|
||||||
|
if ! sudo visudo -c -f "$sudoers_src" >/dev/null; then
|
||||||
|
echo "wg-bounce: $sudoers_src failed visudo syntax check" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! sudo install -m 0440 -o root -g wheel "$sudoers_src" "$sudoers_dst"; then
|
||||||
|
echo "wg-bounce: failed to install $sudoers_dst" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Re-check; should now succeed without prompting.
|
||||||
|
if ! sudo -n /opt/homebrew/bin/wg-quick --help >/dev/null 2>&1; then
|
||||||
|
echo "wg-bounce: sudoers installed but sudo still prompts — check $sudoers_dst" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "wg-bounce: setup complete; future runs won't prompt"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "wg-bounce: down $conf"
|
||||||
|
# down may fail if the tunnel is already down — that's fine, we proceed to up.
|
||||||
|
sudo -n /opt/homebrew/bin/wg-quick down "$conf" 2>/dev/null || true
|
||||||
|
|
||||||
|
echo "wg-bounce: up $conf"
|
||||||
|
if ! sudo -n /opt/homebrew/bin/wg-quick up "$conf"; then
|
||||||
|
echo "wg-bounce: wg-quick up failed" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Brief reach test against the hub so the caller knows immediately whether
|
||||||
|
# the new endpoint is actually carrying packets.
|
||||||
|
echo "wg-bounce: waiting for handshake..."
|
||||||
|
for i in 1 2 3 4 5 6 7 8 9 10; do
|
||||||
|
if ping -c 1 -W 1500 10.9.0.1 >/dev/null 2>&1; then
|
||||||
|
echo "wg-bounce: hub reachable after ${i}s"
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "wg-bounce: hub (10.9.0.1) still unreachable after 10s — tunnel is up but no packets are flowing (check hotel wifi / NAT)." >&2
|
||||||
|
exit 2
|
||||||
12
share/wg-quick.sudoers
Normal file
12
share/wg-quick.sudoers
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
# Allow Natalie to run wg-quick without a password. Required by
|
||||||
|
# session-tools/bin/wg-bounce so the WG tunnel can be re-established
|
||||||
|
# from CLI without prompting (useful on hotel wifi where NAT mappings
|
||||||
|
# shift and the existing tunnel goes dead).
|
||||||
|
#
|
||||||
|
# Install with:
|
||||||
|
# sudo install -m 0440 -o root -g wheel \
|
||||||
|
# ~/Code/@scripts/session-tools/share/wg-quick.sudoers \
|
||||||
|
# /etc/sudoers.d/wg-quick
|
||||||
|
#
|
||||||
|
# Validate before activating: sudo visudo -c -f .../wg-quick.sudoers
|
||||||
|
natalie ALL=(root) NOPASSWD: /opt/homebrew/bin/wg-quick
|
||||||
Loading…
Add table
Reference in a new issue