refactor: Remove GRE tunnels, add Mullvad gateway health check

Radical simplification — no more VPS data plane:
- Delete parahub-vpn-tunnel init script (GRE6 no longer used)
- Revert heartbeat to clean version (no tunnel_ip parsing)
- Add parahub-gw-check: monitors WireGuard handshake, switches
  batman-adv gw_mode between server/client (cron every 2 min)
- Update uci-defaults: remove vpn_tunnel zone/interface, start
  bumblebee as gw_mode=client (health check promotes to server)

Guest internet now requires Mullvad — kill switch by design.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-11 12:50:31 +00:00
parent f96a455dc8
commit e31f626c7c
4 changed files with 56 additions and 158 deletions

View File

@@ -4,7 +4,7 @@
# It configures: batman-adv mesh, dual-band WiFi (private+public), firewall zones, SQM shaping.
#
# Roles:
# bumblebee (L3 Gateway) — full stack: yggdrasil, GRE6, VPN, guest isolation, SQM, DoH
# bumblebee (L3 Gateway) — full stack: yggdrasil, Mullvad VPN, guest isolation, speed control, DoH
# bee (L2 Transport) — minimal: batman-adv mesh relay, heartbeat
# Read firmware role (written by build.sh)
@@ -175,7 +175,7 @@ NET_EOF
done
else
# --- Bumblebee: full network (gw_mode=server, GRE6, guest, policy routing) ---
# --- Bumblebee: full network (gw_mode starts as client, promoted to server by gw-check when Mullvad is up) ---
uci batch <<-NET_EOF
# --- loopback ---
set network.loopback=interface
@@ -184,14 +184,14 @@ set network.loopback.proto='static'
set network.loopback.ipaddr='127.0.0.1'
set network.loopback.netmask='255.0.0.0'
# --- bat0 (batman-adv, server mode — acts as gateway for Bee nodes) ---
# --- bat0 (batman-adv, starts as client — gw-check promotes to server when Mullvad is active) ---
set network.bat0=interface
set network.bat0.proto='batadv'
set network.bat0.routing_algo='BATMAN_V'
set network.bat0.aggregated_ogms='1'
set network.bat0.bridge_loop_avoidance='1'
set network.bat0.distributed_arp_table='1'
set network.bat0.gw_mode='server'
set network.bat0.gw_mode='client'
set network.bat0.hop_penalty='15'
set network.bat0.orig_interval='1000'
@@ -229,12 +229,7 @@ set network.wan=interface
set network.wan.device='${WAN_DEV}'
set network.wan.proto='dhcp'
# --- VPN tunnel interface (device created by parahub-vpn-tunnel init script) ---
set network.vpn_tunnel=interface
set network.vpn_tunnel.device='gre6-vpn'
set network.vpn_tunnel.proto='none'
# --- Policy routing: guest traffic → VPN table 100 ---
# --- Policy routing: guest traffic → Mullvad table 100 ---
add network rule
set network.@rule[-1].src='${GUEST_SUBNET}/24'
set network.@rule[-1].lookup='100'
@@ -448,7 +443,7 @@ set firewall.@rule[-1].target='ACCEPT'
FW_EOF
else
# --- Bumblebee: full firewall (4 zones, guest isolation, kill switch) ---
# --- Bumblebee: full firewall (3 zones + mullvad_local added by parahub-mullvad, guest kill switch) ---
uci batch <<-FW_EOF
# --- Zone: lan (private network) ---
add firewall zone
@@ -476,25 +471,14 @@ set firewall.@zone[-1].masq='1'
set firewall.@zone[-1].mtu_fix='1'
add_list firewall.@zone[-1].network='wan'
# --- Zone: vpn_tunnel (GRE6 → VPS → Mullvad) ---
add firewall zone
set firewall.@zone[-1].name='vpn_tunnel'
set firewall.@zone[-1].input='REJECT'
set firewall.@zone[-1].output='ACCEPT'
set firewall.@zone[-1].forward='REJECT'
set firewall.@zone[-1].masq='1'
set firewall.@zone[-1].mtu_fix='1'
add_list firewall.@zone[-1].network='vpn_tunnel'
# --- Forwarding: lan → wan (internet for owner) ---
add firewall forwarding
set firewall.@forwarding[-1].src='lan'
set firewall.@forwarding[-1].dest='wan'
# --- Forwarding: guest → vpn_tunnel ONLY (kill switch: no wan!) ---
add firewall forwarding
set firewall.@forwarding[-1].src='guest'
set firewall.@forwarding[-1].dest='vpn_tunnel'
# NOTE: guest → mullvad_local forwarding is added by parahub-mullvad setup.
# Without Mullvad configured, guests have NO internet (kill switch by design).
# parahub-gw-check monitors Mullvad and sets gw_mode accordingly.
# --- Rule: guest DHCP (allow guests to get IP) ---
add firewall rule
@@ -681,7 +665,7 @@ if [ "$ROLE" != "bee" ]; then
# Generate unique keys for this node
yggdrasil -genconf | sed 's/IfName: .*/IfName: ygg0/' > /etc/yggdrasil.conf
# Add VPS gateway as static Yggdrasil peer (for GRE6 tunnel)
# Add VPS as static Yggdrasil peer (management plane: remote access, heartbeat)
sed -i 's|Peers: \[\]|Peers: ["tls://91.98.123.238:443"]|' /etc/yggdrasil.conf
# UCI network interface for yggdrasil TUN
@@ -717,13 +701,6 @@ set firewall.@rule[-1].proto='tcp'
set firewall.@rule[-1].dest_port='80'
set firewall.@rule[-1].target='ACCEPT'
# Allow GRE6 protocol input (tunnel endpoint)
add firewall rule
set firewall.@rule[-1].name='Allow GRE6 input'
set firewall.@rule[-1].src='yggdrasil'
set firewall.@rule[-1].proto='47'
set firewall.@rule[-1].target='ACCEPT'
# Allow ICMPv6 on Yggdrasil
add firewall rule
set firewall.@rule[-1].name='Allow ICMPv6 Ygg'
@@ -748,9 +725,8 @@ set firewall.@forwarding[-1].dest='yggdrasil'
YGG_FW_EOF
uci commit firewall
# Enable yggdrasil service + VPN tunnel (creates GRE6 after yggdrasil starts)
# Enable yggdrasil service
/etc/init.d/yggdrasil enable 2>/dev/null || true
/etc/init.d/parahub-vpn-tunnel enable 2>/dev/null || true
# Save yggdrasil address to node keys file
YGG_ADDR=$(yggdrasil -address -useconffile /etc/yggdrasil.conf 2>/dev/null || echo "unknown")
@@ -796,9 +772,11 @@ fi
chmod +x /usr/bin/parahub-heartbeat
chmod +x /usr/bin/parahub-autoupdate
chmod +x /usr/bin/parahub-gw-check
# Cron: heartbeat every 5 minutes + OTA update nightly at 3am
# Cron: heartbeat every 5 min, gateway health check every 2 min, OTA nightly
echo "*/5 * * * * /usr/bin/parahub-heartbeat" >> /etc/crontabs/root
echo "*/2 * * * * /usr/bin/parahub-gw-check" >> /etc/crontabs/root
echo "0 3 * * * /usr/bin/parahub-autoupdate" >> /etc/crontabs/root
/etc/init.d/cron enable
@@ -819,10 +797,10 @@ else
logger -t parahub-mesh "Guest: ${PUBLIC_SSID} @ ${GUEST_IP}/24"
logger -t parahub-mesh "Mesh ID: ${MESH_ID}"
logger -t parahub-mesh "Yggdrasil: ${YGG_ADDR}"
logger -t parahub-mesh "GRE tunnel: 172.16.0.2 → VPS gateway (Mullvad Portugal)"
logger -t parahub-mesh "Kill switch: guest→vpn_tunnel only (no wan)"
logger -t parahub-mesh "Guest internet: via local Mullvad (parahub-mullvad setup required)"
logger -t parahub-mesh "Kill switch: guest blocked without Mullvad (by design)"
logger -t parahub-mesh "Guest IPv6: Yggdrasil SLAAC (full speed, firewall restricted)"
logger -t parahub-mesh "bat0 gw_mode: server (gateway for Bee nodes)"
logger -t parahub-mesh "bat0 gw_mode: client (promoted to server by gw-check when Mullvad active)"
fi
exit 0