#!/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 # 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