diff --git a/.github/workflows/package-openwrt.yml b/.github/workflows/package-openwrt.yml index dfd80513..e54e8597 100644 --- a/.github/workflows/package-openwrt.yml +++ b/.github/workflows/package-openwrt.yml @@ -489,7 +489,6 @@ jobs: ./etc/init.d/fips-gateway ./etc/fips/fips.yaml ./etc/fips/firewall.sh - ./etc/dnsmasq.d/fips.conf ./etc/sysctl.d/fips-gateway.conf ./etc/sysctl.d/fips-bridge.conf ./etc/hotplug.d/net/99-fips @@ -830,7 +829,7 @@ jobs: usr/bin/fips usr/bin/fipsctl usr/bin/fipstop usr/bin/fips-gateway \ usr/bin/fips-mesh-setup usr/bin/fips-ap-setup \ etc/init.d/fips etc/init.d/fips-gateway \ - etc/fips/fips.yaml etc/fips/firewall.sh etc/dnsmasq.d/fips.conf \ + etc/fips/fips.yaml etc/fips/firewall.sh \ etc/sysctl.d/fips-gateway.conf etc/sysctl.d/fips-bridge.conf \ etc/hotplug.d/net/99-fips etc/uci-defaults/90-fips-setup \ lib/upgrade/keep.d/fips; do diff --git a/packaging/openwrt-apk/build-apk.sh b/packaging/openwrt-apk/build-apk.sh index 89063850..399ac556 100755 --- a/packaging/openwrt-apk/build-apk.sh +++ b/packaging/openwrt-apk/build-apk.sh @@ -201,9 +201,6 @@ install -m 0755 "$FILES_DIR/etc/fips/firewall.sh" "$STAGE_DIR/etc/fips/firewall. # of the file; operators can still edit /etc/fips/fips.yaml for non-standard boards. sed -i 's|interface: "eth0"|interface: "wan"|' "$STAGE_DIR/etc/fips/fips.yaml" -install -d "$STAGE_DIR/etc/dnsmasq.d" -install -m 0644 "$FILES_DIR/etc/dnsmasq.d/fips.conf" "$STAGE_DIR/etc/dnsmasq.d/fips.conf" - install -d "$STAGE_DIR/etc/sysctl.d" install -m 0644 "$FILES_DIR/etc/sysctl.d/fips-bridge.conf" "$STAGE_DIR/etc/sysctl.d/fips-bridge.conf" install -m 0644 "$FILES_DIR/etc/sysctl.d/fips-gateway.conf" "$STAGE_DIR/etc/sysctl.d/fips-gateway.conf" diff --git a/packaging/openwrt-ipk/Makefile b/packaging/openwrt-ipk/Makefile index 6f354272..cabd0380 100644 --- a/packaging/openwrt-ipk/Makefile +++ b/packaging/openwrt-ipk/Makefile @@ -114,10 +114,6 @@ 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 - # dnsmasq drop-in: forward .fips queries to the FIPS DNS responder - $(INSTALL_DIR) $(1)/etc/dnsmasq.d - $(INSTALL_DATA) $(CURDIR)/files/etc/dnsmasq.d/fips.conf $(1)/etc/dnsmasq.d/fips.conf - # sysctl: enable br_netfilter so AF_PACKET sees frames on bridge member ports $(INSTALL_DIR) $(1)/etc/sysctl.d $(INSTALL_DATA) $(CURDIR)/files/etc/sysctl.d/fips-bridge.conf $(1)/etc/sysctl.d/fips-bridge.conf diff --git a/packaging/openwrt-ipk/README.md b/packaging/openwrt-ipk/README.md index 7971168e..bc8cb577 100644 --- a/packaging/openwrt-ipk/README.md +++ b/packaging/openwrt-ipk/README.md @@ -17,11 +17,10 @@ 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/dnsmasq.d/fips.conf` | Forwards `.fips` DNS queries to the daemon | | `/etc/sysctl.d/fips-bridge.conf` | `br_netfilter` settings for Ethernet transport | | `/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 and firewall setup | +| `/etc/uci-defaults/90-fips-setup` | First-boot kernel module, firewall and dnsmasq `.fips` forwarding setup | | `/lib/upgrade/keep.d/fips` | Preserves `/etc/fips/` across `sysupgrade` | ## Requirements diff --git a/packaging/openwrt-ipk/build-ipk.sh b/packaging/openwrt-ipk/build-ipk.sh index 1b2c200e..cdd82eec 100755 --- a/packaging/openwrt-ipk/build-ipk.sh +++ b/packaging/openwrt-ipk/build-ipk.sh @@ -173,9 +173,6 @@ install -d "$DATA_DIR/etc/fips" install -m 0600 "$FILES_DIR/etc/fips/fips.yaml" "$DATA_DIR/etc/fips/fips.yaml" install -m 0755 "$FILES_DIR/etc/fips/firewall.sh" "$DATA_DIR/etc/fips/firewall.sh" -install -d "$DATA_DIR/etc/dnsmasq.d" -install -m 0644 "$FILES_DIR/etc/dnsmasq.d/fips.conf" "$DATA_DIR/etc/dnsmasq.d/fips.conf" - install -d "$DATA_DIR/etc/sysctl.d" install -m 0644 "$FILES_DIR/etc/sysctl.d/fips-bridge.conf" "$DATA_DIR/etc/sysctl.d/fips-bridge.conf" install -m 0644 "$FILES_DIR/etc/sysctl.d/fips-gateway.conf" "$DATA_DIR/etc/sysctl.d/fips-gateway.conf" diff --git a/packaging/openwrt-ipk/files/etc/dnsmasq.d/fips.conf b/packaging/openwrt-ipk/files/etc/dnsmasq.d/fips.conf deleted file mode 100644 index d0680d9d..00000000 --- a/packaging/openwrt-ipk/files/etc/dnsmasq.d/fips.conf +++ /dev/null @@ -1,11 +0,0 @@ -# FIPS mesh DNS — forward .fips queries to the local FIPS DNS responder. -# -# server= forward all .fips queries to 127.0.0.1:5354 -# rebind-domain-ok= disable DNS-rebind protection for .fips; FIPS node -# addresses live in fd00::/8 (ULA), which dnsmasq blocks by -# default as a rebind-attack countermeasure. -# -# If your fips.yaml sets dns.port to something other than 5354, update the -# port number below to match. -server=/fips/127.0.0.1#5354 -rebind-domain-ok=/fips/ diff --git a/packaging/openwrt-ipk/files/etc/fips/fips.yaml b/packaging/openwrt-ipk/files/etc/fips/fips.yaml index 6bb09aee..a12db9b8 100644 --- a/packaging/openwrt-ipk/files/etc/fips/fips.yaml +++ b/packaging/openwrt-ipk/files/etc/fips/fips.yaml @@ -172,7 +172,8 @@ transports: # accept_connections: true # Outbound LAN gateway. dnsmasq forwards .fips queries to listen=[::1]:5353 -# (configured by the fips init script). Requires IPv6 forwarding enabled. +# while it runs (configured by the fips-gateway init script). Requires IPv6 +# forwarding enabled. gateway: enabled: true pool: "fd01::/112" diff --git a/packaging/openwrt-ipk/files/etc/init.d/fips-gateway b/packaging/openwrt-ipk/files/etc/init.d/fips-gateway index 4b9c7041..e9e16879 100755 --- a/packaging/openwrt-ipk/files/etc/init.d/fips-gateway +++ b/packaging/openwrt-ipk/files/etc/init.d/fips-gateway @@ -189,11 +189,6 @@ dnsmasq_swap_fips_upstream() { 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 } 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 654b77c2..a89c27b5 100644 --- a/packaging/openwrt-ipk/files/etc/uci-defaults/90-fips-setup +++ b/packaging/openwrt-ipk/files/etc/uci-defaults/90-fips-setup @@ -59,9 +59,11 @@ uci commit firewall # --------------------------------------------------------------------------- # 3. dnsmasq UCI registration # --------------------------------------------------------------------------- -# /etc/dnsmasq.d/fips.conf already handles runtime forwarding. -# Register via UCI as well so the settings survive a full dnsmasq config -# regeneration (e.g. after a firmware upgrade that rebuilds dnsmasq.conf). +# This UCI entry is what forwards .fips queries to the daemon: OpenWrt's +# dnsmasq init script builds its config from UCI and loads no directory under +# /etc. The daemon's DNS responder binds ::1. The 127.0.0.1 del_list removes +# the entry older packages added. While fips-gateway runs, its init script +# points this entry at the gateway's DNS port instead. uci -q del_list dhcp.@dnsmasq[0].server="/fips/127.0.0.1#5354" 2>/dev/null || true uci -q del_list dhcp.@dnsmasq[0].server="/fips/::1#5354" 2>/dev/null || true diff --git a/testing/openwrt/package-test.sh b/testing/openwrt/package-test.sh index c15ecdfa..e6f8056c 100755 --- a/testing/openwrt/package-test.sh +++ b/testing/openwrt/package-test.sh @@ -7,8 +7,10 @@ # What it checks is which maintainer scripts the .apk registers and what each # one does with apk's upgrade arguments and environment (apk-tools v3 passes # " " and a PATH-only environment to pre-upgrade and -# post-upgrade). Whether a real `apk mkpkg` accepts the result is left to the -# GitHub packaging workflow, which builds with the real tool. +# post-upgrade), and which files the .apk and the .ipk install. The .ipk is +# built for real by build-ipk.sh, which needs only tar. Whether a real +# `apk mkpkg` accepts the result is left to the GitHub packaging workflow, +# which builds with the real tool. # # Usage: package-test.sh [--keep ] # --keep copy the captured apk scripts into as post-install, @@ -222,6 +224,83 @@ for pair in pre-upgrade:prerm post-upgrade:postinst; do esac done +# ── Build the .ipk ────────────────────────────────────────────────────────── + +echo "==> build-ipk.sh" +if ! PKG_VERSION="$PKG_VERSION" \ + bash "$PROJECT_ROOT/packaging/openwrt-ipk/build-ipk.sh" --arch x86_64 --bin-dir "$BINS" \ + > "$TMP/build-ipk.log" 2>&1; then + cat "$TMP/build-ipk.log" >&2 + harness_fail "build-ipk.sh failed, so the .ipk was not checked" +fi +IPK="$PROJECT_ROOT/dist/fips_${PKG_VERSION}_x86_64.ipk" +[[ -f "$IPK" ]] || harness_fail "build-ipk.sh exited 0 but wrote no $IPK" +tar -xzf "$IPK" -O ./data.tar.gz | tar -tzf - > "$TMP/ipk-data" \ + || harness_fail "cannot list data.tar.gz in $IPK" +tar -xzf "$IPK" -O ./control.tar.gz | tar -tzf - > "$TMP/ipk-control" \ + || harness_fail "cannot list control.tar.gz in $IPK" + +# ── P1 and P2. Neither package ships the dnsmasq drop-in ──────────────────── +# OpenWrt's dnsmasq builds its config from UCI and reads no directory under +# /etc, so .fips forwarding comes from the UCI entry 90-fips-setup adds. The +# match is on the directory prefix: tar lists the directory with a trailing +# slash and the stub's find without one. +for pair in "P1:apk:$CAPTURE/payload" "P2:ipk:$TMP/ipk-data"; do + id="${pair%%:*}" + rest="${pair#*:}" + kind="${rest%%:*}" + listing="${rest#*:}" + hits="$(grep -F './etc/dnsmasq.d' "$listing" | tr '\n' ' ')" + if [[ -z "$hits" ]]; then + ok "$id the .$kind installs nothing under /etc/dnsmasq.d" + else + bad "$id the .$kind still installs: $hits" + fi +done + +# ── P3. Positive control for P1 and P2 ────────────────────────────────────── +# An empty or unreadable listing would pass P1 and P2, so each listing must +# show files that are known to ship. +for pair in "apk:$CAPTURE/payload" "ipk:$TMP/ipk-data"; do + kind="${pair%%:*}" + listing="${pair#*:}" + for path in ./etc/init.d/fips-gateway ./etc/uci-defaults/90-fips-setup; do + if grep -qxF "$path" "$listing"; then + ok "P3 the .$kind payload lists $path" + else + bad "P3 the .$kind payload does not list $path, so P1/P2 saw no real listing" + fi + done +done +for path in ./postinst ./prerm; do + if grep -qxF "$path" "$TMP/ipk-control"; then + ok "P3 the .ipk control archive lists $path" + else + bad "P3 the .ipk control archive does not list $path" + fi +done + +# ── P4. No source still names the drop-in ─────────────────────────────────── +# This is the only check on the SDK feed Makefile, which nothing here builds. +# grep exits 1 when nothing matches and 2 when it could not read a path; only +# the first is a pass. +(cd "$PROJECT_ROOT" && grep -rlF 'dnsmasq.d/fips.conf' \ + packaging/openwrt-ipk packaging/openwrt-apk .github/workflows/package-openwrt.yml) \ + > "$TMP/refs" +rc=$? +[[ $rc -le 1 ]] || harness_fail "the drop-in reference search failed (grep exit $rc)" +refs="$(tr '\n' ' ' < "$TMP/refs")" +if [[ -z "$refs" ]]; then + ok "P4 no OpenWrt packaging file names the dnsmasq drop-in" +else + bad "P4 the dnsmasq drop-in is still named in: $refs" +fi +if [[ -e "$PROJECT_ROOT/packaging/openwrt-ipk/files/etc/dnsmasq.d/fips.conf" ]]; then + bad "P4 packaging/openwrt-ipk/files/etc/dnsmasq.d/fips.conf still exists" +else + ok "P4 the drop-in source file is gone" +fi + # ── Hand the scripts to the ash scenarios ─────────────────────────────────── if [[ -n "$KEEP" ]]; then for phase in $WANT_PHASES; do