#!/usr/bin/env bash
# ============================================================================
#  Consilium Belli — wg-backhaul.sh
#  Generates a WireGuard hub-and-spoke tunnel for the satellite / internet
#  backhaul (Layer 3). The tunnel carries only ALREADY-ENCRYPTED payloads —
#  it hides content and destination from the transit provider (Starlink,
#  Iridium, cellular), nothing more. The dish is still geolocatable and the
#  uplink still emits: this buys confidentiality, not invisibility.
#
#  Topology: one HUB (a node with a reachable endpoint) + N SPOKES (the boxes).
#  All spokes reach each other through the hub. 10.77.0.0/24 overlay by default.
#
#  Usage:   ./wg-backhaul.sh <spoke_count> [hub_endpoint_host] [udp_port]
#  Example: ./wg-backhaul.sh 3 toc-hub.example.net 51820
#
#  Requires: wireguard-tools (wg).  Output: ./wg-backhaul-<ts>/  (chmod 700)
# ============================================================================
set -euo pipefail

N="${1:-3}"
ENDPOINT="${2:-YOUR.HUB.ENDPOINT}"
PORT="${3:-51820}"
NET="10.77.0"
OUT="./wg-backhaul-$(date -u +%Y%m%dT%H%M%SZ)"

command -v wg >/dev/null 2>&1 || { echo "wireguard-tools ('wg') not installed."; exit 1; }
mkdir -p "$OUT"; chmod 700 "$OUT"

# Keys
hub_priv=$(wg genkey); hub_pub=$(printf '%s' "$hub_priv" | wg pubkey)
declare -a s_priv s_pub
for i in $(seq 1 "$N"); do s_priv[$i]=$(wg genkey); s_pub[$i]=$(printf '%s' "${s_priv[$i]}" | wg pubkey); done

# Hub config: listens, peers every spoke
{
  echo "[Interface]"
  echo "# HUB — reachable endpoint"
  echo "Address = ${NET}.1/24"
  echo "ListenPort = ${PORT}"
  echo "PrivateKey = ${hub_priv}"
  for i in $(seq 1 "$N"); do
    echo ""
    echo "[Peer]  # spoke ${i}"
    echo "PublicKey = ${s_pub[$i]}"
    echo "AllowedIPs = ${NET}.$((i+1))/32"
  done
} > "$OUT/hub.conf"; chmod 600 "$OUT/hub.conf"

# Spoke configs: each peers only the hub, keepalive so it works behind CGNAT/sat
for i in $(seq 1 "$N"); do
  {
    echo "[Interface]"
    echo "# SPOKE ${i} — a TOC box"
    echo "Address = ${NET}.$((i+1))/24"
    echo "PrivateKey = ${s_priv[$i]}"
    echo ""
    echo "[Peer]  # hub"
    echo "PublicKey = ${hub_pub}"
    echo "Endpoint = ${ENDPOINT}:${PORT}"
    echo "AllowedIPs = ${NET}.0/24"
    echo "PersistentKeepalive = 25"
  } > "$OUT/spoke${i}.conf"; chmod 600 "$OUT/spoke${i}.conf"
done

cat <<EOF

WireGuard backhaul generated in: $OUT
  hub.conf        -> the reachable node (set a real Endpoint host + open UDP/${PORT})
  spoke1..${N}.conf -> one per TOC box
Bring up:  sudo wg-quick up ./spokeN.conf     (or install to /etc/wireguard/)

Honest scope: hides content + destination from the transit provider. The dish
is still geolocated to your account; the uplink still emits. Confidentiality,
not concealment. Put your own end-to-end crypto ABOVE this, and only push
already-encrypted payloads through the tunnel.
EOF
