#!/bin/bash
################################################################################
# Copyright (c) 2026 ModalAI, Inc. All rights reserved.
#
# voxl-wg-up - Bring up the VOXL WireGuard tunnel.
#
# Works around two platform quirks:
#   1. The VOXL kernel has no in-kernel wireguard module, so we start
#      wireguard-go directly rather than via `wg-quick up` (which would
#      try to `ip link add ... type wireguard` and fail).
#   2. `wg setconf` on this kernel hangs on return; it applies the
#      config successfully but the syscall does not exit. We background
#      it and kill it after a short delay.
#
# Usage: voxl-wg-up [interface]    (default: wg0)
################################################################################

set -e

INTERFACE="${1:-wg0}"
CONFIG="/etc/wireguard/${INTERFACE}.conf"
STRIPPED="/run/voxl-wireguard/${INTERFACE}-stripped.conf"
SETCONF_TIMEOUT="${VOXL_WG_SETCONF_TIMEOUT:-2}"

log() { echo "[voxl-wg-up] $*"; }
die() { echo "[voxl-wg-up] ERROR: $*" >&2; exit 1; }

[ "$(id -u)" -eq 0 ] || die "must run as root"
[ -r "$CONFIG" ] || die "config not found: $CONFIG"
command -v wireguard-go >/dev/null || die "wireguard-go not on PATH"
command -v wg >/dev/null || die "wg not on PATH (install wireguard-tools)"

# Parse [Interface] section for Address and MTU.
ADDRESS=$(awk -F'=' '
  /^\[/{section=$0}
  section=="[Interface]" && /^[ \t]*Address[ \t]*=/ {
    gsub(/[ \t]/,"",$2); print $2; exit
  }' "$CONFIG")

MTU=$(awk -F'=' '
  /^\[/{section=$0}
  section=="[Interface]" && /^[ \t]*MTU[ \t]*=/ {
    gsub(/[ \t]/,"",$2); print $2; exit
  }' "$CONFIG")
MTU="${MTU:-1380}"

[ -n "$ADDRESS" ] || die "no Address= line in [Interface] section of $CONFIG"

# Clean up any prior state. Idempotent.
log "tearing down any prior $INTERFACE state"
pkill -9 -f "wireguard-go $INTERFACE" 2>/dev/null || true
ip link delete "$INTERFACE" 2>/dev/null || true
sleep 1

# Build the stripped config. `wg setconf` only understands a subset of
# the wg-quick schema: [Interface] PrivateKey + ListenPort, plus all
# [Peer] blocks. Strip everything else.
mkdir -p /run/voxl-wireguard
touch "$STRIPPED"
chmod 600 "$STRIPPED"

awk '
  BEGIN { keep=0 }
  /^\[Interface\]/ { section="Interface"; print; keep=1; next }
  /^\[Peer\]/      { section="Peer";      print; keep=1; next }
  /^\[/            { section="Other";     keep=0; next }
  keep && section=="Interface" && /^[ \t]*(PrivateKey|ListenPort)[ \t]*=/ { print; next }
  keep && section=="Peer"      && /^[ \t]*(PublicKey|PresharedKey|AllowedIPs|Endpoint|PersistentKeepalive)[ \t]*=/ { print; next }
' "$CONFIG" > "$STRIPPED"

# Start the userspace daemon
log "starting wireguard-go $INTERFACE"
wireguard-go "$INTERFACE"

# Wait for the UAPI socket
for i in $(seq 1 40); do
  [ -S "/var/run/wireguard/${INTERFACE}.sock" ] && break
  sleep 0.1
done
[ -S "/var/run/wireguard/${INTERFACE}.sock" ] || die "wireguard-go socket never appeared"

# Apply the config. It will hang on return on this kernel even though
# the config is applied successfully. Background and kill.
log "applying config (wg setconf will be killed after ${SETCONF_TIMEOUT}s; this is expected)"
wg setconf "$INTERFACE" "$STRIPPED" &
SETCONF_PID=$!
sleep "$SETCONF_TIMEOUT"
kill -9 "$SETCONF_PID" 2>/dev/null || true
wait "$SETCONF_PID" 2>/dev/null || true

# Sanity check
if ! wg show "$INTERFACE" | grep -q '^peer:'; then
  die "no peers configured after setconf; check $CONFIG"
fi

# Bring up the interface
log "configuring address $ADDRESS and bringing $INTERFACE up (mtu $MTU)"
ip address add "$ADDRESS" dev "$INTERFACE"
ip link set mtu "$MTU" up dev "$INTERFACE"

log "$INTERFACE is up"
exit 0
