Files
fips/packaging/openwrt-ipk/files/etc/init.d/fips-gateway
T
Origami74andJohnathan Corgan 1e4f375dcc Add gateway packaging: CI, systemd, Debian, AUR, OpenWrt
Add fips-gateway binary to CI artifact and Docker build. Systemd
service unit with After=fips.service dependency and security
hardening. Debian and AUR package entries.

OpenWrt packaging: procd init script managing dnsmasq forwarding,
proxy NDP, RA route advertisements for the virtual IP pool, and a
global IPv6 prefix on br-lan to work around Android suppressing AAAA
queries on ULA-only networks. Sysctl config for IPv6 forwarding.
Gateway enabled by default in OpenWrt config. Ethernet transport
enabled by default.

Default gateway config section (commented out) in common fips.yaml.
2026-04-09 16:53:41 +00:00

185 lines
5.8 KiB
Bash
Executable File

#!/bin/sh /etc/rc.common
# FIPS outbound LAN gateway — procd init script for OpenWrt
#
# Not enabled by default. Enable with:
# service fips-gateway enable
# service fips-gateway start
#
# Requires: fips daemon running, gateway section in /etc/fips/fips.yaml,
# IPv6 forwarding enabled.
USE_PROCD=1
START=96
STOP=09
PROG=/usr/bin/fips-gateway
CONFIG=/etc/fips/fips.yaml
# Port the gateway DNS listens on (must match dns.listen in fips.yaml).
GW_DNS_PORT=5353
# Port the FIPS daemon DNS listens on.
DAEMON_DNS_PORT=5354
# Global-scope IPv6 prefix assigned to br-lan so Android/Chrome clients
# believe they have full IPv6 and actually send AAAA queries.
# Uses RFC 5180 (benchmarking) range — not routed on the public internet.
GLOBAL_PREFIX="2001:2:f1b5::1/64"
start_service() {
# Apply gateway sysctls (proxy_ndp, IPv6 forwarding).
sysctl -p /etc/sysctl.d/fips-gateway.conf 2>/dev/null || true
# Load conntrack module for /proc/net/nf_conntrack.
modprobe nf_conntrack 2>/dev/null || true
# Redirect dnsmasq .fips forwarding from daemon (5354) to gateway (5353)
# so LAN clients get virtual IPs instead of raw mesh addresses.
# Done early and synchronously so dnsmasq is ready before the gateway
# starts accepting DNS queries.
dnsmasq_swap_fips_upstream "$GW_DNS_PORT"
sleep 1
# Add a global-scope IPv6 prefix to br-lan so Android/Chrome clients
# send AAAA queries (they suppress AAAA when only ULA addresses exist).
# Also set ra_default=2 so odhcpd advertises a default route even
# without upstream IPv6 — needed for clients to accept the prefix.
gateway_add_global_prefix
# Advertise the virtual IP pool via Router Advertisement so LAN clients
# learn a route to the pool automatically.
gateway_add_ra_route
procd_open_instance
procd_set_param command "$PROG" --config "$CONFIG"
procd_set_param respawn 3600 5 5
procd_set_param stdout 1
procd_set_param stderr 1
procd_close_instance
}
stop_service() {
# Restore dnsmasq .fips forwarding back to the daemon.
dnsmasq_swap_fips_upstream "$DAEMON_DNS_PORT"
# Remove the RA route for the virtual IP pool.
gateway_remove_ra_route
# Remove the global prefix and ra_default override.
gateway_remove_global_prefix
}
reload_service() {
restart
}
# Extract the gateway pool CIDR from fips.yaml.
# Looks for "pool:" indented under the top-level "gateway:" block.
gateway_pool_cidr() {
awk '/^gateway:/{found=1; next} found && /^[^ ]/{found=0} found && /pool:/{gsub(/.*pool:[[:space:]]*/, ""); gsub(/["'"'"']/, ""); print; exit}' "$CONFIG"
}
# Add an RA-advertised route for the virtual IP pool so LAN clients
# automatically learn how to reach virtual IPs.
gateway_add_ra_route() {
local pool
pool="$(gateway_pool_cidr)"
[ -z "$pool" ] && return 0
# Add a kernel route on br-lan (needed for RA to advertise it).
ip -6 route replace "$pool" dev br-lan proto static 2>/dev/null || true
# Add a UCI route6 entry for odhcpd to include in Router Advertisements.
# Remove any stale entry first.
gateway_remove_ra_route_uci
uci add dhcp route6 >/dev/null
uci set dhcp.@route6[-1].interface='lan'
uci set dhcp.@route6[-1].target="$pool"
uci commit dhcp
/etc/init.d/odhcpd restart 2>/dev/null || true
}
# Remove the RA route.
gateway_remove_ra_route() {
local pool
pool="$(gateway_pool_cidr)"
[ -z "$pool" ] && return 0
ip -6 route del "$pool" dev br-lan proto static 2>/dev/null || true
gateway_remove_ra_route_uci
/etc/init.d/odhcpd restart 2>/dev/null || true
}
# Remove any existing UCI route6 entries for the pool.
gateway_remove_ra_route_uci() {
local i=0
while uci -q get "dhcp.@route6[$i]" >/dev/null 2>&1; do
if [ "$(uci -q get "dhcp.@route6[$i].target")" = "$(gateway_pool_cidr)" ]; then
uci delete "dhcp.@route6[$i]"
uci commit dhcp
return 0
fi
i=$((i + 1))
done
}
# Add a global-scope IPv6 prefix to br-lan and enable RA default route.
gateway_add_global_prefix() {
# Add the global prefix via UCI (idempotent — remove first).
local current
current="$(uci -q get network.lan.ip6addr 2>/dev/null || echo "")"
if [ "$current" != "$GLOBAL_PREFIX" ]; then
uci set network.lan.ip6addr="$GLOBAL_PREFIX"
uci commit network
fi
# Force odhcpd to advertise a default route even without upstream IPv6.
local ra_default
ra_default="$(uci -q get dhcp.lan.ra_default 2>/dev/null || echo "")"
if [ "$ra_default" != "2" ]; then
uci set dhcp.lan.ra_default='2'
uci commit dhcp
fi
# Apply network change immediately (odhcpd restarted by gateway_add_ra_route).
/etc/init.d/network reload 2>/dev/null || true
}
# Remove the global prefix and ra_default override.
gateway_remove_global_prefix() {
local current
current="$(uci -q get network.lan.ip6addr 2>/dev/null || echo "")"
if [ "$current" = "$GLOBAL_PREFIX" ]; then
uci delete network.lan.ip6addr
uci commit network
/etc/init.d/network reload 2>/dev/null || true
fi
uci -q delete dhcp.lan.ra_default 2>/dev/null || true
uci commit dhcp
/etc/init.d/odhcpd restart 2>/dev/null || true
}
# Swap the dnsmasq .fips forwarding port via UCI and restart dnsmasq.
# $1 = target port number
dnsmasq_swap_fips_upstream() {
local port="$1"
# Remove both possible entries, then add the correct one.
uci -q del_list dhcp.@dnsmasq[0].server="/fips/127.0.0.1#${DAEMON_DNS_PORT}" 2>/dev/null
uci -q del_list dhcp.@dnsmasq[0].server="/fips/127.0.0.1#${GW_DNS_PORT}" 2>/dev/null
# Also handle IPv6 loopback variants.
uci -q del_list dhcp.@dnsmasq[0].server="/fips/::1#${DAEMON_DNS_PORT}" 2>/dev/null
uci -q del_list dhcp.@dnsmasq[0].server="/fips/::1#${GW_DNS_PORT}" 2>/dev/null
uci add_list dhcp.@dnsmasq[0].server="/fips/::1#${port}"
uci commit dhcp
# Update the drop-in config file as well (belt-and-suspenders).
if [ -f /etc/dnsmasq.d/fips.conf ]; then
sed -i "s|^server=/fips/.*|server=/fips/::1#${port}|" /etc/dnsmasq.d/fips.conf
fi
# Restart dnsmasq to pick up the change.
/etc/init.d/dnsmasq restart 2>/dev/null || true
}