diff --git a/packaging/openwrt-ipk/Makefile b/packaging/openwrt-ipk/Makefile index a3fdbfa7..3ae6b8dc 100644 --- a/packaging/openwrt-ipk/Makefile +++ b/packaging/openwrt-ipk/Makefile @@ -118,7 +118,9 @@ define Package/fips/install # Firewall helper script (called by UCI include and hotplug) $(INSTALL_BIN) $(CURDIR)/files/etc/fips/firewall.sh $(1)/etc/fips/firewall.sh - # sysctl: enable br_netfilter so AF_PACKET sees frames on bridge member ports + # sysctl: turn off br_netfilter's call hooks (fips-bridge.conf). br_netfilter + # does not make bridge member ports usable for the Ethernet transport; the + # shipped config binds the LAN bridge instead. See fips-bridge.conf. $(INSTALL_DIR) $(1)/etc/sysctl.d $(INSTALL_DATA) $(CURDIR)/files/etc/sysctl.d/fips-bridge.conf $(1)/etc/sysctl.d/fips-bridge.conf $(INSTALL_DATA) $(CURDIR)/files/etc/sysctl.d/fips-gateway.conf $(1)/etc/sysctl.d/fips-gateway.conf diff --git a/packaging/openwrt-ipk/README.md b/packaging/openwrt-ipk/README.md index fac25610..96ce8251 100644 --- a/packaging/openwrt-ipk/README.md +++ b/packaging/openwrt-ipk/README.md @@ -17,7 +17,7 @@ OpenWrt 22.03+ router via the standard `opkg` package system. | `/etc/init.d/fips-gateway` | procd service for the gateway (disabled by default) | | `/etc/fips/fips.yaml` | Node configuration (edit before first start) | | `/etc/fips/firewall.sh` | Firewall helper — accepts traffic on `fips0` | -| `/etc/sysctl.d/fips-bridge.conf` | `br_netfilter` settings for Ethernet transport | +| `/etc/sysctl.d/fips-bridge.conf` | Turns off `br_netfilter`'s firewall call hooks | | `/etc/sysctl.d/fips-gateway.conf` | `proxy_ndp` and IPv6 forwarding for the gateway | | `/etc/hotplug.d/net/99-fips` | Applies firewall rules when `fips0` comes up | | `/etc/uci-defaults/90-fips-setup` | First-boot kernel module, firewall and dnsmasq `.fips` forwarding setup | @@ -38,7 +38,7 @@ OpenWrt 22.03+ router via the standard `opkg` package system. | Requirement | Notes | |---|---| | `kmod-tun` | Required for `fips0` TUN interface | -| `kmod-br-netfilter` | Required for Ethernet transport on bridge member ports | +| `kmod-br-netfilter` | Loaded, hooks off (`fips-bridge.conf`); see notes below | Both kernel modules are listed as package dependencies (`DEPENDS`) and will be installed automatically by `opkg`. @@ -141,11 +141,23 @@ The default config enables: - Ethernet transport, including the `wan`, `wwan` and `lan` entries For Ethernet transport, edit the interface names in the `ethernet:` section to -match your router. **Always use physical port names -(`eth0`, `eth1`, or DSA port names like `wan`/`lan1`), never bridge names -(`br-lan`).** The shipped default WAN port is `eth0` (OpenWrt 24); on OpenWrt -25 (DSA) boards the WAN port is named `wan` — the `.apk` package ships that -default. Run `ip link show` to confirm the names on your board. +match your router. **For the LAN, bind the LAN bridge (`br-lan`), never one of +its member ports** (on DSA boards `lan1`..`lanN`; on others whichever `ethN` the +bridge holds; `bridge link` lists them). A socket on a bridge member port sends +frames but never forms a link, because the bridge takes the frames that arrive +on its members; loading `br_netfilter` does not change that. +A lab test with a two-member Linux bridge found this with `br_netfilter` +unloaded, loaded with its call hooks off, and loaded with them on, while a +socket on `br-lan` worked both with `br_netfilter` unloaded and with it loaded +as shipped. Ports outside any bridge bind by their own name. The shipped +default WAN port is `eth0` (OpenWrt 24); on OpenWrt 25 (DSA) boards the WAN +port is named `wan`, and the `.apk` package ships that default. Run +`ip link show` to confirm the names on your board. + +The lab used software bridges only. A DSA switch with hardware bridge offload +has not been checked, so confirm the LAN entry forms links on such a router. +`kmod-br-netfilter`, `fips-bridge.conf` and the module load in `90-fips-setup` +are kept until their removal has been checked on a router. ## Service management diff --git a/packaging/openwrt-ipk/files/etc/fips/fips.yaml b/packaging/openwrt-ipk/files/etc/fips/fips.yaml index ea0bb1de..a3af867f 100644 --- a/packaging/openwrt-ipk/files/etc/fips/fips.yaml +++ b/packaging/openwrt-ipk/files/etc/fips/fips.yaml @@ -90,8 +90,14 @@ transports: bind_addr: "0.0.0.0:8443" # advertise_on_nostr: true - # Ethernet transport — physical port names, NOT bridge names. - # Run 'ip link show' on the router to identify port names. + # Ethernet transport. Each entry names one interface; run 'ip link show' + # on the router to see the names. For the LAN, bind the LAN bridge + # (br-lan), never one of its member ports: a socket on a bridge member + # port sends frames but never forms a link, because the bridge takes the + # frames that arrive on its members, whether or not br_netfilter is + # loaded. Ports outside any bridge (the WAN port, phy0-sta0) bind by + # their own name. A DSA switch with hardware bridge offload has not been + # checked and needs a check on the router. ethernet: wan: interface: "eth0" diff --git a/packaging/openwrt-ipk/files/etc/sysctl.d/fips-bridge.conf b/packaging/openwrt-ipk/files/etc/sysctl.d/fips-bridge.conf index ef8b28a8..4a0365a9 100644 --- a/packaging/openwrt-ipk/files/etc/sysctl.d/fips-bridge.conf +++ b/packaging/openwrt-ipk/files/etc/sysctl.d/fips-bridge.conf @@ -1,12 +1,17 @@ # FIPS: bridge netfilter settings # -# kmod-br-netfilter must be loaded for AF_PACKET sockets to receive frames -# on bridge member ports (e.g. eth1 when it is a member of br-lan). -# Without it, the bridge's rx_handler intercepts frames before they reach -# the packet socket layer. +# The package loads br_netfilter (kmod-br-netfilter) and this file turns +# off its IP/IPv6/ARP call hooks, so frames the bridge forwards are not +# also run through the firewall's IP, IPv6 and ARP tables. # -# We load br_netfilter for the AF_PACKET visibility benefit but disable its -# IP/IPv6/ARP call hooks to avoid double-processing of routed traffic. +# Loading br_netfilter does not make a bridge member port usable for the +# FIPS Ethernet transport. A lab test with a two-member Linux bridge found +# that a socket bound to a member port never forms a link, with +# br_netfilter unloaded, loaded with these hooks off, or loaded with them +# on. A socket bound to the bridge itself (br-lan) works, both with +# br_netfilter unloaded and with it loaded as this file sets it. +# Bind the bridge. The module, its dependency and this file stay until +# their removal has been checked on a router. net.bridge.bridge-nf-call-iptables=0 net.bridge.bridge-nf-call-ip6tables=0 net.bridge.bridge-nf-call-arptables=0 diff --git a/packaging/openwrt-ipk/files/etc/uci-defaults/90-fips-setup b/packaging/openwrt-ipk/files/etc/uci-defaults/90-fips-setup index 44965971..2eb43252 100644 --- a/packaging/openwrt-ipk/files/etc/uci-defaults/90-fips-setup +++ b/packaging/openwrt-ipk/files/etc/uci-defaults/90-fips-setup @@ -18,7 +18,10 @@ modprobe tun 2>/dev/null || true echo "tun" > /etc/modules.d/tun -# kmod-br-netfilter makes AF_PACKET visible on bridge member ports. +# br_netfilter is loaded with its call hooks off (fips-bridge.conf). It does +# not make a bridge member port usable for the Ethernet transport: a lab +# test found a member-port socket never forms a link either way, so the +# shipped config binds the LAN bridge. Its removal waits on a router check. modprobe br_netfilter 2>/dev/null || true echo "br_netfilter" > /etc/modules.d/br-netfilter