diff --git a/.github/workflows/package-freebsd.yml b/.github/workflows/package-freebsd.yml index cec6276c..4541657c 100644 --- a/.github/workflows/package-freebsd.yml +++ b/.github/workflows/package-freebsd.yml @@ -227,6 +227,99 @@ jobs: echo "Build Summary for freebsd/x86_64:" echo " Package: ${{ steps.freebsd-assets.outputs.pkg }}" + pfsense: + name: Build and check the pfSense package (x86_64) + # A job of its own, and deliberately NOT a dependency of `release`. A + # pfSense-only failure — a new key in the common dns: block, a + # dependency that stops linking statically, a checker regression — reds + # this check and nothing else; it can never hide behind the FreeBSD + # job's result, and it cannot block the FreeBSD release asset. The + # pfSense package is therefore never a release asset. It is published + # here as a workflow artifact (30-day retention) for anyone to test, + # until someone has installed it on a real pfSense box; see + # packaging/pfsense/README.md. + # + # This VM is FreeBSD 15.1, so the package it produces is FreeBSD:15:amd64 + # (pfSense CE 2.8.1). CE 2.9 and Plus 26.x are FreeBSD 16 and need a + # FreeBSD 16 host this workflow does not have. No aarch64 package is built + # here or published anywhere: rustup ships no toolchain for + # aarch64-unknown-freebsd, so such a build cannot honour the + # rust-toolchain.toml pin every published artifact is built with. ARM is + # build-it-yourself, per the README. + runs-on: ubuntu-latest + needs: determine-versioning + # Its own full release build in an emulated FreeBSD VM, like the build + # job; the same generous bound applies. + timeout-minutes: 45 + + steps: + - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 # v6 + with: + fetch-depth: 0 + + - name: Set SOURCE_DATE_EPOCH from git + run: echo "SOURCE_DATE_EPOCH=$(git log -1 --format=%ct)" >> "$GITHUB_ENV" + + - name: Build and check the pfSense package in a FreeBSD VM + uses: vmactions/freebsd-vm@f0552d3b69211736abd97f02ff3d4674c56b73b1 # v1 + env: + FREEBSD_PACKAGE_VERSION: ${{ needs.determine-versioning.outputs.freebsd_package_version }} + with: + release: "15.1" + usesh: true + sync: rsync + copyback: true + mem: 6144 + envs: "SOURCE_DATE_EPOCH CARGO_TERM_COLOR FREEBSD_PACKAGE_VERSION" + prepare: | + # curl for rustup; bash and php for testing/check-pfsense-pkg.sh + # (the checker is bash, and it runs php -l plus a fips_strip_block + # unit test on the config.xml helper). + pkg install -y curl bash php85 + run: | + set -e + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y --default-toolchain none --profile minimal + . "$HOME/.cargo/env" + + # Builds the release binaries (static by default) and packages + # them; on a FreeBSD 15.1 VM this yields the FreeBSD:15:amd64 + # package for pfSense CE 2.8.1. + packaging/pfsense/build-pkg.sh --version "$FREEBSD_PACKAGE_VERSION" + + PKG=$(ls deploy/fips-*-pfsense-*.pkg) + testing/check-pfsense-pkg.sh "$PKG" + php -l packaging/pfsense/fips-unbound-custom.php + + ( cd deploy && sha256 -q "$(basename "$PKG")" \ + | { read -r h; printf '%s %s\n' "$h" "$(basename "$PKG")"; } \ + > "$(basename "$PKG").sha256" ) + + rm -rf target + + - name: Resolve pfSense asset path + id: pfsense-asset + shell: bash + run: | + : ${GITHUB_OUTPUT:=/tmp/github_output} + set -euo pipefail + VER="${{ needs.determine-versioning.outputs.freebsd_pkg_file_version }}" + PKG=$(ls deploy/fips-${VER}-pfsense-*.pkg) + if [[ ! -f "$PKG" ]]; then + echo "No pfSense package was produced" >&2 + ls -la deploy >&2 || true + exit 1 + fi + echo "pkg=$PKG" >> "$GITHUB_OUTPUT" + + - name: Upload pfSense artifact + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 + with: + name: fips_${{ needs.determine-versioning.outputs.freebsd_package_version }}_x86_64_pfsense + path: | + ${{ steps.pfsense-asset.outputs.pkg }} + ${{ steps.pfsense-asset.outputs.pkg }}.sha256 + retention-days: 30 + release: name: Publish FreeBSD assets to GitHub Release runs-on: ubuntu-latest @@ -239,6 +332,11 @@ jobs: - name: Download FreeBSD artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 with: + # Only the FreeBSD artifact. Without a pattern this action downloads + # every artifact in the run — including the pfSense package from the + # `pfsense` job, which is a workflow artifact by design and must never + # reach a release. `needs` only orders jobs; it does not scope this. + pattern: fips_*_x86_64_freebsd path: dist merge-multiple: true @@ -248,6 +346,15 @@ jobs: set -euo pipefail cd dist + # The pfSense package is never a release asset (see the `pfsense` + # job). The download step is scoped to the FreeBSD artifact; this + # keeps the rule if that artifact is ever renamed or a new one added. + if compgen -G '*-pfsense-*' >/dev/null; then + echo "FAIL: a pfSense package reached the release stage; it must stay a workflow artifact:" >&2 + ls -la ./*-pfsense-* >&2 || true + exit 1 + fi + pkgs=$(find . -maxdepth 1 -type f -name '*.pkg' | LC_ALL=C sort) if [[ -z "$pkgs" ]]; then echo "FAIL: no .pkg artifacts were downloaded" >&2 diff --git a/CHANGELOG.md b/CHANGELOG.md index 5811e50d..c216473f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -137,6 +137,31 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 a typo'd interface name were previously the same flat `StartFailed(String)`; nothing downstream could branch on absence. +#### Packaging + +- A pfSense package (`packaging/pfsense/`, `gmake pfsense`). pfSense is + FreeBSD underneath, but the FreeBSD package fails there in three + silent ways: pfSense runs only `/usr/local/etc/rc.d/*.sh` at boot and + re-runs them on WAN IP changes, so the suffixless rc script never + starts; `unbound.conf` is generated from `config.xml` with no `conf.d`, + so the DNS drop-in is never read; and — on a firewall where the + default-on "Allow IPv6" has been turned off — the responder's `::1` + default is unreachable when unbound is then generated with + `do-ip6: no`, so it binds `127.0.0.1` for robustness. The package + ships `fips.sh`, wires the `fips.` zone into the DNS Resolver through + `config.xml`, and binds the responder on `127.0.0.1`. It links + statically by default, since pfSense runs a FreeBSD base that cannot + be obtained to link against; aarch64 is refused, where static binaries + fault at `posix_spawn`. Mechanics shared with the FreeBSD builder live + in `packaging/common/pkg-lib.sh`, which both source; the FreeBSD + package is byte-identical before and after. The pfSense package is + built and checked in its own CI job and published as a workflow + artifact, not attached to a release, until it has been installed on a + real pfSense box; CI produces the CE 2.8.1 (`FreeBSD:15:amd64`) + package, while CE 2.9 and Plus 26.x on Intel need a FreeBSD 16 build + host the CI does not have, and ARM stays build-it-yourself because + rustup ships no toolchain for it. See `packaging/pfsense/README.md`. + ### Changed - `Degraded` is now a level rather than a latch. The supervisor's reason set diff --git a/README.md b/README.md index ff3e0ba4..4d76056d 100644 --- a/README.md +++ b/README.md @@ -132,7 +132,8 @@ default `/etc/fips/fips.yaml` you can edit before starting. The package enables `fips` and `fips-dns` but starts neither, which is why the second command is there. -For macOS, Windows, FreeBSD, OpenWrt, the systemd tarball or a Nix +For macOS, Windows, FreeBSD (including a pfSense build under +`packaging/pfsense/`), OpenWrt, the systemd tarball or a Nix flake, see [docs/getting-started.md](docs/getting-started.md) for the full multi-platform installation guide. diff --git a/docs/getting-started.md b/docs/getting-started.md index ee3280f9..879754c1 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -88,6 +88,12 @@ included: its NAT backend is nftables, which is Linux-only. The Ethernet and BLE transports are unavailable on FreeBSD; UDP, TCP, Tor, and Nym are. +On **pfSense** (CE or Plus) use `packaging/pfsense/` rather than this +package: pfSense diverges from stock FreeBSD in how it boots packages, +generates the DNS resolver config, and applies upgrades, and the pfSense +package handles each. See +[packaging/pfsense/README.md](../packaging/pfsense/README.md). + **One architecture.** The published artifact is `fips--freebsd-amd64.pkg`. There is no aarch64 FreeBSD build, so on any other architecture use the from-source path below. diff --git a/packaging/Makefile b/packaging/Makefile index 69bb106f..b0cfd75a 100644 --- a/packaging/Makefile +++ b/packaging/Makefile @@ -12,6 +12,7 @@ # make aur Build fips-git AUR package and validate with namcap # make pkg Build a macOS .pkg installer # make freebsd Build a FreeBSD .pkg package (on FreeBSD; use gmake) +# make pfsense Build a pfSense .pkg package (on FreeBSD; use gmake) # make zip Build a Windows .zip package # make all Build deb and tarball (default) # make clean Remove deploy/ directory @@ -20,7 +21,7 @@ SHELL := /bin/bash PACKAGING_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) PROJECT_ROOT := $(abspath $(PACKAGING_DIR)/..) -.PHONY: all deb deb-host tarball ipk apk aur pkg freebsd zip clean +.PHONY: all deb deb-host tarball ipk apk aur pkg freebsd pfsense zip clean all: deb tarball @@ -57,6 +58,12 @@ pkg: freebsd: @sh $(PACKAGING_DIR)/freebsd/build-pkg.sh +# pfSense is FreeBSD underneath but boots, resolves and is upgraded +# differently enough that the FreeBSD package does not work there; see +# packaging/pfsense/README.md for the three divergences. +pfsense: + @sh $(PACKAGING_DIR)/pfsense/build-pkg.sh + zip: @powershell -File $(PACKAGING_DIR)/windows/build-zip.ps1 diff --git a/packaging/README.md b/packaging/README.md index 3859942e..87f4f675 100644 --- a/packaging/README.md +++ b/packaging/README.md @@ -14,6 +14,7 @@ make apk # OpenWrt .apk (apk-tools, mandatory on OpenWrt 25+) make aur # Arch Linux AUR package (fips-git, local build + namcap) make pkg # macOS .pkg installer make freebsd # FreeBSD .pkg package (on FreeBSD; use gmake) +make pfsense # pfSense .pkg package (on FreeBSD; use gmake) make zip # Windows .zip package make all # deb + tarball (default) ``` @@ -70,9 +71,11 @@ runtime dependency and is not needed to build. ```text packaging/ aur/ Arch Linux AUR packaging (PKGBUILD, supporting files) - common/ Shared assets (default config, hosts file) + common/ Shared assets (default config, hosts file) and pkg-lib.sh, + the helpers the FreeBSD and pfSense builders share debian/ Debian/Ubuntu .deb packaging via cargo-deb freebsd/ FreeBSD .pkg packaging via pkg-create(8) + pfsense/ pfSense .pkg packaging (FreeBSD-based, but not the same) macos/ macOS .pkg installer via pkgbuild nixos/ NixOS flake module (services.fips.*) systemd/ Generic Linux systemd tarball packaging @@ -212,6 +215,58 @@ service fips_dns start See [freebsd/README.md](freebsd/README.md) for host resolver setup and field-tested caveats. +### pfSense (`.pkg`) + +pfSense is FreeBSD underneath, but the FreeBSD package does not work +there, and fails silently in three ways: pfSense boots packages by +globbing `/usr/local/etc/rc.d/*.sh` (a suffixless rc script is never +run), it generates `unbound.conf` from `config.xml` and reads no +`conf.d` directory (the DNS drop-in is never read), and it writes +`do-ip6: no` unless "Allow IPv6" is enabled (so a responder on `[::1]` +is unreachable). This package ships `fips.sh`, integrates DNS through +the DNS Resolver custom options in `config.xml`, and binds the +responder on `127.0.0.1`. + +Unlike the other packages, this one **links statically by default** +(`--dynamic` opts out). pfSense runs a FreeBSD base you cannot +obtain — Netgate builds Plus from its own 16.0-CURRENT snapshot — so +a dynamically linked binary can reference a libc symbol the appliance +does not export, install cleanly, and then refuse to start. A static +package declares no shared libraries at all. + +**On aarch64 this is refused, not applied.** A statically linked +aarch64 FreeBSD binary faults where `posix_spawn` should be, so the +daemon dies the first time it shells out. ARM builds must pass +`--dynamic`, and then `ldd` on the appliance is the check that the +base drift is not real. + +The build host's architecture and FreeBSD major must still match the +target's: pfSense CE 2.8.1 is FreeBSD 15 amd64; CE 2.9.0 and Plus 26.x are +FreeBSD 16 (amd64, plus aarch64 for Plus on ARM appliances), and `pkg` refuses a +mismatched ABI. No aarch64 package is published: rustup ships no +toolchain for aarch64 FreeBSD, so such a build cannot honour the +`rust-toolchain.toml` pin. It is build-it-yourself. + +```sh +# Build (on FreeBSD; this Makefile needs GNU make — pkg install gmake) +gmake pfsense +# or directly, no gmake needed: +./packaging/pfsense/build-pkg.sh + +# Validate the package before shipping it +./testing/check-pfsense-pkg.sh deploy/fips--pfsense-ce2.8-amd64.pkg + +# Install (on the firewall, as root) +pkg add ./fips--pfsense-ce2.8-amd64.pkg +/usr/local/etc/rc.d/fips.sh start +/usr/local/libexec/fips/fips-dns-setup # edits config.xml; run deliberately +``` + +Not a Netgate-supported package, and a pfSense firmware upgrade removes +it. See [pfsense/README.md](pfsense/README.md) for the "Allow IPv6" +prerequisite the mesh depends on, firewall-rule notes, and removal +behaviour. + ### Windows (`.zip`) A ZIP archive containing binaries, default config, and PowerShell diff --git a/packaging/common/pkg-lib.sh b/packaging/common/pkg-lib.sh new file mode 100644 index 00000000..fe674cef --- /dev/null +++ b/packaging/common/pkg-lib.sh @@ -0,0 +1,174 @@ +#!/bin/sh +# Shared helpers for the FreeBSD-family package builders. +# +# packaging/freebsd/build-pkg.sh and packaging/pfsense/build-pkg.sh +# produce different packages for different systems, but the mechanics of +# getting there — deriving a pkg-legal version, locating the binaries, +# laying out the stage, and the manifest scripts that give the config +# files @sample semantics — are the same work, and were duplicated +# verbatim. They live here so a fix lands in both. +# +# What deliberately does NOT live here is anything the two packages +# disagree about: the boot script, the DNS integration, linkage, the ABI +# and product naming. Those differences are the reason there are two +# builders at all, and folding them into a shared file with flags would +# hide them. +# +# POSIX sh, sourced with `.` — no bashisms, no `local`. + +# Print the version to stamp on the package, given the project root and +# an optional override (CI passes a derived version on branch builds). +# +# '-' is the pkg name/version separator and neither '-' nor '+' is legal +# inside a pkg version, so both map to '.': 0.6.0-dev -> 0.6.0.dev. +pkg_resolve_version() { + pkg_rv_root="$1" + pkg_rv_version="${2:-}" + [ -n "$pkg_rv_version" ] \ + || pkg_rv_version="$(sed -n 's/^version = "\(.*\)"/\1/p' "${pkg_rv_root}/Cargo.toml" | head -1)" + if [ -z "$pkg_rv_version" ]; then + echo "error: could not read version from Cargo.toml" >&2 + return 1 + fi + printf '%s\n' "$pkg_rv_version" | tr -- '+-' '..' +} + +# The build host's pkg ABI, or a sane default where pkg cannot say. +pkg_host_abi() { + pkg config abi 2>/dev/null || echo "FreeBSD:15:amd64" +} + +# Fail unless every named binary is present and executable in $1. +pkg_require_binaries() { + pkg_rb_dir="$1" + shift + for pkg_rb_bin in "$@"; do + if [ ! -x "${pkg_rb_dir}/${pkg_rb_bin}" ]; then + echo "error: ${pkg_rb_dir}/${pkg_rb_bin} missing (run without --no-build)" >&2 + return 1 + fi + done + return 0 +} + +# The directory skeleton both packages install into. +pkg_stage_tree() { + install -d "$1/usr/local/bin" \ + "$1/usr/local/etc/fips" \ + "$1/usr/local/etc/rc.d" \ + "$1/usr/local/libexec/fips" +} + +# Copy the named binaries from $1 into the stage at $2. +pkg_stage_binaries() { + pkg_sb_dir="$1" + pkg_sb_stage="$2" + shift 2 + for pkg_sb_bin in "$@"; do + install -m 0755 "${pkg_sb_dir}/${pkg_sb_bin}" "${pkg_sb_stage}/usr/local/bin/" || return 1 + done + return 0 +} + +# Emit the post-install lines that copy a sample into place if the real +# file is absent. Arguments are ":" pairs, e.g. fips.yaml:0600. +# +# This is the @sample plist keyword spelled out by hand: that keyword +# lives in the ports tree (/usr/ports/Keywords/sample.ucl), which neither +# a plain pkg-create host nor pfSense has. +# +# FreeBSD has no "root" group; wheel is gid 0. +pkg_sample_seed_script() { + for pkg_ss_entry in "$@"; do + pkg_ss_name="${pkg_ss_entry%%:*}" + pkg_ss_mode="${pkg_ss_entry##*:}" + cat <-.pkg; every caller +# wants something more specific, so the rename is part of the helper +# rather than repeated after it. +pkg_create_package() { + pkg_cp_stage="$1" + pkg_cp_deploy="$2" + pkg_cp_version="$3" + pkg_cp_out="$4" + + mkdir -p "$pkg_cp_deploy" + echo "==> pkg create" + pkg create -M "${pkg_cp_stage}/+MANIFEST" -p "${pkg_cp_stage}/pkg-plist" \ + -r "$pkg_cp_stage" -o "$pkg_cp_deploy" || return $? + mv "${pkg_cp_deploy}/fips-${pkg_cp_version}.pkg" "$pkg_cp_out" || return $? + + echo "==> built:" + ls -l "$pkg_cp_out" +} + +# Emit the manifest fields both packages agree on, in the order +# pkg-create(8) expects: $1 version, $2 ABI, $3 comment, $4 description. +# +# Shared because they are shared *policy*, not merely duplicated text — +# origin, maintainer, licence and prefix describe one project, and two +# copies is two things to forget to update. Anything a package decides +# for itself (annotations, the scripts block) is appended by the caller +# after this. +pkg_manifest_header() { + cat </dev/null 2>&1 || pw groupadd fips +EOS +} + +# Build the release binaries. $1 project root, $2 optional Rust target +# triple — passing one keeps RUSTFLAGS off build scripts and proc-macros, +# and puts the output under target//release. +pkg_cargo_build() { + if [ -n "${2:-}" ]; then + echo "==> cargo build --release --target $2" + (cd "$1" && cargo build --release --target "$2") + else + echo "==> cargo build --release" + (cd "$1" && cargo build --release) + fi +} diff --git a/packaging/freebsd/README.md b/packaging/freebsd/README.md index 197c6239..5b289472 100644 --- a/packaging/freebsd/README.md +++ b/packaging/freebsd/README.md @@ -4,6 +4,11 @@ Builds a native FreeBSD `.pkg` shipping `fips`, `fipsctl`, `fipstop`, rc.d services, and `.fips` DNS integration. `fips-gateway` is excluded (its NAT backend is nftables, Linux-only). +**On pfSense?** Use [`packaging/pfsense/`](../pfsense/README.md) +instead. pfSense is FreeBSD underneath, but it boots packages, wires up +DNS and handles upgrades differently enough that this package does not +work there; the pfSense one addresses each difference. + Platform notes: the Ethernet and BLE transports are not available on FreeBSD (UDP, TCP, Tor, and Nym are). The UDP datapath deliberately uses the portable single-packet receive loop — FreeBSD's `recvmmsg(2)` diff --git a/packaging/freebsd/build-pkg.sh b/packaging/freebsd/build-pkg.sh index 27f78e83..aa0f4c2f 100755 --- a/packaging/freebsd/build-pkg.sh +++ b/packaging/freebsd/build-pkg.sh @@ -14,6 +14,10 @@ set -eu SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)" +# Mechanics shared with the pfSense builder: version derivation, the +# stage layout, the @sample manifest scripts, and pkg create. +. "${PROJECT_ROOT}/packaging/common/pkg-lib.sh" + NO_BUILD=0 VERSION="" while [ $# -gt 0 ]; do @@ -25,41 +29,25 @@ while [ $# -gt 0 ]; do shift done -# Default to the Cargo.toml version; CI passes a derived version that -# appends +.. on branch builds. Either way, map -# '-' and '+' to '.' — '-' is the pkg name/version separator and -# neither is allowed inside a pkg version (0.5.0-dev -> 0.5.0.dev). -[ -n "$VERSION" ] \ - || VERSION="$(sed -n 's/^version = "\(.*\)"/\1/p' "${PROJECT_ROOT}/Cargo.toml" | head -1)" -[ -n "$VERSION" ] || { echo "error: could not read version from Cargo.toml" >&2; exit 1; } -VERSION="$(printf '%s' "$VERSION" | tr -- '+-' '..')" +# CI passes a derived version that appends +.. on +# branch builds; otherwise the version comes from Cargo.toml. +VERSION="$(pkg_resolve_version "$PROJECT_ROOT" "$VERSION")" -ABI="$(pkg config abi 2>/dev/null || echo "FreeBSD:15:amd64")" +ABI="$(pkg_host_abi)" ARCH="${ABI##*:}" if [ "$NO_BUILD" -eq 0 ]; then - echo "==> cargo build --release" - (cd "$PROJECT_ROOT" && cargo build --release) + pkg_cargo_build "$PROJECT_ROOT" fi -for bin in fips fipsctl fipstop; do - [ -x "${PROJECT_ROOT}/target/release/${bin}" ] \ - || { echo "error: target/release/${bin} missing (run without --no-build)" >&2; exit 1; } -done +pkg_require_binaries "${PROJECT_ROOT}/target/release" fips fipsctl fipstop STAGE="$(mktemp -d "${TMPDIR:-/tmp}/fips-pkg.XXXXXX")" trap 'rm -rf "$STAGE"' EXIT echo "==> staging into ${STAGE}" -install -d "${STAGE}/usr/local/bin" \ - "${STAGE}/usr/local/etc/fips" \ - "${STAGE}/usr/local/etc/rc.d" \ - "${STAGE}/usr/local/libexec/fips" - -install -m 0755 "${PROJECT_ROOT}/target/release/fips" \ - "${PROJECT_ROOT}/target/release/fipsctl" \ - "${PROJECT_ROOT}/target/release/fipstop" \ - "${STAGE}/usr/local/bin/" +pkg_stage_tree "$STAGE" +pkg_stage_binaries "${PROJECT_ROOT}/target/release" "$STAGE" fips fipsctl fipstop # Config ships sample-style: copied into place on install if absent, # removed on deinstall only if unmodified (see the manifest scripts). @@ -85,31 +73,15 @@ DESC="$(cat "${SCRIPT_DIR}/pkg-descr")" # (/usr/ports/Keywords/sample.ucl), which a plain pkg-create host (e.g. # a CI VM) does not have. cat > "${STAGE}/+MANIFEST" </dev/null 2>&1 || pw groupadd fips +$(pkg_group_script) # Install-if-absent config. fips.yaml may hold a node private key # (nsec:), so it is 0600; FreeBSD has no "root" group, wheel is gid 0. -[ -f /usr/local/etc/fips/fips.yaml ] || install -m 0600 -o root -g wheel \\ - /usr/local/etc/fips/fips.yaml.sample /usr/local/etc/fips/fips.yaml -[ -f /usr/local/etc/fips/hosts ] || install -m 0644 -o root -g wheel \\ - /usr/local/etc/fips/hosts.sample /usr/local/etc/fips/hosts +$(pkg_sample_seed_script fips.yaml:0600 hosts:0644) # pkg upgrade runs the old package's pre-deinstall (which stops the # services); bring them back up on the new binaries if enabled. if [ "\${PKG_UPGRADE:-}" = "true" ]; then @@ -132,11 +104,7 @@ if [ "\${PKG_UPGRADE:-}" != "true" ]; then # Removal: clear the resolver drop-in even if the service was never # started through rc. /usr/local/libexec/fips/fips-dns-teardown 2>/dev/null || true - for f in fips.yaml hosts; do - s="/usr/local/etc/fips/\${f}.sample" - t="/usr/local/etc/fips/\${f}" - if [ -f "\$t" ] && cmp -s "\$t" "\$s"; then rm -f "\$t"; fi - done +$(pkg_sample_purge_script fips.yaml hosts) fi EOD } @@ -155,15 +123,8 @@ libexec/fips/fips-dns-teardown @dir etc/fips EOF -mkdir -p "${PROJECT_ROOT}/deploy" -echo "==> pkg create" -pkg create -M "${STAGE}/+MANIFEST" -p "${STAGE}/pkg-plist" \ - -r "$STAGE" -o "${PROJECT_ROOT}/deploy" - # pkg create always names the file -.pkg; add the OS and # arch so release assets stay distinct from the macOS .pkg files. OUT="${PROJECT_ROOT}/deploy/fips-${VERSION}-freebsd-${ARCH}.pkg" -mv "${PROJECT_ROOT}/deploy/fips-${VERSION}.pkg" "$OUT" -echo "==> built:" -ls -l "$OUT" +pkg_create_package "$STAGE" "${PROJECT_ROOT}/deploy" "$VERSION" "$OUT" diff --git a/packaging/pfsense/README.md b/packaging/pfsense/README.md new file mode 100644 index 00000000..f8835c6e --- /dev/null +++ b/packaging/pfsense/README.md @@ -0,0 +1,525 @@ +# FIPS pfSense packaging + +Builds a `.pkg` that installs FIPS on pfSense: `fips`, `fipsctl`, +`fipstop`, a boot script pfSense actually runs, and helpers that wire +the `.fips` zone into the DNS Resolver. `fips-gateway` is excluded (its +NAT backend is nftables, Linux-only; pfSense has pf for that). + +This is **not a Netgate-supported package** and has no GUI. Netgate +[documents third-party packages as unsupported][netgate-freebsd-pkg] +and warns they can break upgrades; treat it accordingly. + +[netgate-freebsd-pkg]: https://docs.netgate.com/pfsense/en/latest/recipes/freebsd-pkg-repo.html + +## Maintenance and reports + +This package is maintained by **fr34aky** (via the project's issue +tracker). pfSense-specific problems — a boot script that does not start, +DNS wiring, an upgrade that misbehaves — are best reported there; the +package manifest's maintainer field points at the project, so reports +reach it either way. The ABI-to-product table below tracks Netgate's +releases and needs updating when a new pfSense version ships or an old +one goes end-of-life; that is part of maintaining this package. + +## Why this is separate from `packaging/freebsd/` + +pfSense is FreeBSD underneath, but the FreeBSD package does not work +here — not "works worse", does not work — in three ways that all fail +silently: + +| | FreeBSD package | pfSense | +|---|---|---| +| Boot | `rc.d/fips`, an `rc.conf`-gated rc.subr service | pfSense's `rc.start_packages` globs `/usr/local/etc/rc.d/*.sh` and runs each as `