Fix: Firewalla advertises an IPv6 default route on ULA-only
## TL;DR:
If you run IPv6 on your LANs but can't have working IPv6 to the internet (i.e., ULA or VPN client setups), firerouter will still advertise your WAN IPv6. Dual-stack clients then try IPv6 first, hit a blackhole, and wait out an eight second timeout before falling back to IPv4. The fix is a one character change to the RA router-lifetime made durable with a post_main.d hook.
## Symptoms
- Random hangs lasting 10 seconds up to 10 minutes on ssh, git, pip/npm/brew, etc., but only sometimes.
- Desktop/Electron apps showing "couldn't connect / check your network," then retrying in a loop.
- Anything with AAAA DNS records feels flaky but plain IPv4-only hosts are fine.
- Disabling IPv6 entirely "fixes" it but then your home assistant or matter devices get real sluggish if not downright defiant.
## Root cause:
firerouter hardcodes the RA router-lifetime to 3600 in /home/pi/firerouter/plugins/dhcp/dhcp6_plugin.js, so every IPv6 LAN advertises the box as a default v6 router even when it can't actually route v6 to the internet. Clients install that default route, try v6 (often over a non-routable ULA source), and blackhole until timeout.
## Fix:
set the RA router-lifetime to 0, which is effectively "not a default router." Clients keep their ULA + on-link IPv6 but stop attempting internet IPv6, so Happy Eyeballs just uses IPv4. Intra-subnet and link local v6 still work, but cross-subnet v6 routing through the firewalla is dropped. Regarding the latter, I haven't found this to be an issue because it seems everything that doesn't fallback to dhcp4 connects to a hub or something that does---even if only for setup---and host name resolution still works across both as long as you config it. Also, instead of using globs below, you could specify individual interfaces to selectively apply this fix.
## Who should NOT use this:
if you have real, currently working IPv6 internet (ISP prefix + v6 connectivity), BUT you also want your devices to use it for egress to the internet, AND you don't want to make any changes to the script the below... then it's prob better to leave this alone for now; FW sounds like they are going to implement this sorta thing in the future. This script is only for having dhcpv6 on LAN that you can configure to your liking while blocking it on WAN without having to disable it.
## The script
Drop this in post_main.d; it's idempotent and self-heals after firmware updates revert the plugin
```
#!/bin/bash
# firewalla-ipv6-no-default-route.sh
# Stop firerouter advertising the box as an IPv6 DEFAULT gateway on LANs that
# have IPv6 addressing but no working IPv6 internet path (ULA-only, or a VPN
# client without v6). firerouter hardcodes RA router-lifetime 3600 in
# plugins/dhcp/dhcp6_plugin.js; this sets it to 0 ("not a default router").
# Clients keep ULA + on-link v6 but stop attempting internet v6 (no ~8s
# blackhole). Idempotent; re-applies on boot and after firerouter updates.
#
# TESTED: Firewalla Gold, fw 2.5 / firerouter (2026-06).
# VERIFY the hardcoded line still exists on your firmware first:
#
# grep -n 'raInterval},3600' /home/pi/firerouter/plugins/dhcp/dhcp6_plugin.js
#
# UNDO: remove this file and run
# sudo sed -i 's/raInterval},0/raInterval},3600/g' \
# /home/pi/firerouter/plugins/dhcp/dhcp6_plugin.js
# sudo systemctl restart firerouter_dhcp.service
#
# UNOFFICIAL. this edits a firerouter-managed file. Use at your own risk.
#
set -uo pipefail
PLUGIN=/home/pi/firerouter/plugins/dhcp/dhcp6_plugin.js
CONF_DIR=/home/pi/.router/config/dhcp/conf
changed=0
# 1) Patch the source so every future firerouter render emits lifetime 0.
if grep -q 'raInterval},3600' "$PLUGIN" 2>/dev/null; then
sudo sed -i 's/raInterval},3600/raInterval},0/g' "$PLUGIN"; changed=1
fi
# 2) Fix any RA confs already rendered this boot.
if grep -qsE '^ra-param=br[0-9]+,[0-9]+,3600$' "$CONF_DIR"/br*_v6.conf 2>/dev/null; then
sudo sed -i -E 's/^(ra-param=br[0-9]+,[0-9]+),3600$/\1,0/' "$CONF_DIR"/br*_v6.conf; changed=1
fi
# 3) Reload the DHCP/RA dnsmasq (re-reads confs; does not re-render).
if [ "$changed" -eq 1 ]; then
sudo systemctl restart firerouter_dhcp.service
logger -t ipv6-ra-fix "RA router-lifetime set to 0 (no IPv6 default route on LANs)"
fi
```
Install:
```
sudo mkdir -p /home/pi/.firewalla/config/post_main.d
sudo nano /home/pi/.firewalla/config/post_main.d/20_ipv6_no_v6_default_route.sh # paste the script
sudo chmod +x /home/pi/.firewalla/config/post_main.d/20_ipv6_no_v6_default_route.sh
sudo bash /home/pi/.firewalla/config/post_main.d/20_ipv6_no_v6_default_route.sh # apply now
# verify (expect ,0 on each LAN):
grep -H ra-param /home/pi/.router/config/dhcp/conf/br*_v6.conf
```
post_main.d lives in the user config dir, so it survives Firewalla app updates and runs on every boot.
## Related: the open ULA gap is tracked in firewalla/firewalla#6857.
______________________________________________________________________
Please sign in to leave a comment.
Comments
0 comments