mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-05 19:18:25 +00:00
pfSense is FreeBSD underneath, but the FreeBSD package does not work there, failing in three silent ways. pfSense runs only /usr/local/etc/rc.d/*.sh at boot and re-runs them when WAN gets a new address, so a suffixless rc script never starts; unbound.conf is generated from config.xml with no conf.d, so a drop-in is never read; and on a firewall where the default-on "Allow IPv6" has been turned off, unbound is then generated with do-ip6: no and a responder on ::1 is unreachable. So this ships fips.sh, wires the fips. zone into the DNS Resolver through config.xml, and binds the responder on 127.0.0.1 for robustness against that last case. The rc script is plain sh: what pfSense imposes is the .sh name and that a re-run leave a running daemon alone and exit 0. It identifies the daemon by process name and recovers an orphaned daemon(8) supervisor found via fstat, since a locked empty pidfile makes daemon(8) report pid -1. The DNS setup is a manual step, never run from post-install, and validates the merged options with unbound-checkconf (pfSense's test_unbound_config) before touching config.xml, so a bad merge cannot take DNS from every client behind the firewall. The daemon runs under daemon(8) -H so newsyslog can rotate its log by signalling a reopen. Packages link statically by default: pfSense runs a FreeBSD base that cannot be obtained to link against. A firmware upgrade keeps the package (pfSense-upgrade removes only pfSense-pkg-*; confirmed on a live Plus 26.03.1 -> 26.07 upgrade, aarch64 — the package survived and the daemon restarted at boot. That is a minor, FreeBSD 16 -> 16 change; the cross-major compat case is still only source-reasoned). aarch64 is refused, where a static binary faults at posix_spawn. The mechanics the two builders share — version derivation, the stage layout, the manifest fields, the @sample scripts and pkg create — live in packaging/common/pkg-lib.sh, which both source; the FreeBSD package is byte-identical before and after that extraction. One ABI can serve more than one product: CE 2.9 and Plus 26.x on Intel are both FreeBSD:16:amd64 with a byte-identical artifact, named ...-ce2.9-plus26-amd64.pkg. The pfSense package is built and checked in its own CI job — separate from the FreeBSD package, and not a dependency of the release job, so a pfSense-only failure reds that job alone and is never a release asset. It is kept as a workflow artifact until it has been installed on a real pfSense box. CI produces the CE 2.8.1 (FreeBSD:15:amd64) package; CE 2.9, Plus 26.x Intel and ARM need a FreeBSD 16 build host the CI does not have, and ARM stays build-it-yourself because rustup ships no toolchain for it. testing/check-pfsense-pkg.sh validates a built package on any FreeBSD host and runs in that CI job: contents, modes, a positive boot-script lifecycle against a stub daemon, php -l and a fips_strip_block unit test of the config.xml helper. Installing on a real pfSense box, and the firmware-upgrade behaviour, are covered only by an aarch64 hardware run and pfSense-upgrade's source; the README records what is and is not tested. Co-authored-by: Johnathan Corgan <johnathan@corganlabs.com>
131 lines
4.7 KiB
Bash
Executable File
131 lines
4.7 KiB
Bash
Executable File
#!/bin/sh
|
|
# Build a FreeBSD .pkg package for FIPS using pkg-create(8).
|
|
#
|
|
# Usage: packaging/freebsd/build-pkg.sh [--version <version>] [--no-build]
|
|
#
|
|
# Prerequisites: the pinned Rust toolchain, pkg(8).
|
|
# Output: deploy/fips-<version>-freebsd-<arch>.pkg
|
|
#
|
|
# Ships fips, fipsctl, and fipstop. fips-gateway is excluded: its NAT
|
|
# backend is nftables (Linux-only) and the binary is a stub elsewhere.
|
|
|
|
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
|
|
case "$1" in
|
|
--no-build) NO_BUILD=1 ;;
|
|
--version) VERSION="${2:?--version requires an argument}"; shift ;;
|
|
*) echo "usage: $0 [--version <version>] [--no-build]" >&2; exit 1 ;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
# CI passes a derived version that appends +<branch>.<height>.<hash> on
|
|
# branch builds; otherwise the version comes from Cargo.toml.
|
|
VERSION="$(pkg_resolve_version "$PROJECT_ROOT" "$VERSION")"
|
|
|
|
ABI="$(pkg_host_abi)"
|
|
ARCH="${ABI##*:}"
|
|
|
|
if [ "$NO_BUILD" -eq 0 ]; then
|
|
pkg_cargo_build "$PROJECT_ROOT"
|
|
fi
|
|
|
|
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}"
|
|
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).
|
|
# fips.yaml may hold a node private key (nsec:), so it is never
|
|
# world-readable — 0600 like the Debian and macOS packages.
|
|
install -m 0600 "${PROJECT_ROOT}/packaging/common/fips.yaml" \
|
|
"${STAGE}/usr/local/etc/fips/fips.yaml.sample"
|
|
install -m 0644 "${PROJECT_ROOT}/packaging/common/hosts" \
|
|
"${STAGE}/usr/local/etc/fips/hosts.sample"
|
|
|
|
install -m 0755 "${SCRIPT_DIR}/fips.rc" "${STAGE}/usr/local/etc/rc.d/fips"
|
|
install -m 0755 "${SCRIPT_DIR}/fips-dns.rc" "${STAGE}/usr/local/etc/rc.d/fips_dns"
|
|
|
|
install -m 0755 "${SCRIPT_DIR}/fips-dns-setup" \
|
|
"${SCRIPT_DIR}/fips-dns-teardown" \
|
|
"${STAGE}/usr/local/libexec/fips/"
|
|
|
|
DESC="$(cat "${SCRIPT_DIR}/pkg-descr")"
|
|
|
|
# The config files get @sample semantics — copied into place on install
|
|
# if absent, removed on deinstall only if unmodified — but spelled out as
|
|
# manifest scripts: the @sample plist keyword lives in the ports tree
|
|
# (/usr/ports/Keywords/sample.ucl), which a plain pkg-create host (e.g.
|
|
# a CI VM) does not have.
|
|
cat > "${STAGE}/+MANIFEST" <<EOF
|
|
$(pkg_manifest_header "$VERSION" "$ABI" "Self-organizing encrypted mesh network on Nostr identities" "$DESC")
|
|
scripts: {
|
|
post-install: <<EOD
|
|
# Control-socket access group: the rc script creates /var/run/fips as
|
|
# root:fips 0750, so members can use fipsctl/fipstop without root.
|
|
$(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.
|
|
$(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
|
|
if service fips enabled >/dev/null 2>&1; then
|
|
service fips start >/dev/null 2>&1 || true
|
|
fi
|
|
if service fips_dns enabled >/dev/null 2>&1; then
|
|
service fips_dns start >/dev/null 2>&1 || true
|
|
fi
|
|
fi
|
|
EOD
|
|
pre-deinstall: <<EOD
|
|
# Stop the services so the daemon binary is never replaced (upgrade) or
|
|
# removed (deinstall) under a running process. fips_dns stop also tears
|
|
# down the .fips resolver drop-in; on upgrade the new package's
|
|
# post-install re-establishes it.
|
|
service fips_dns onestop >/dev/null 2>&1 || true
|
|
service fips onestop >/dev/null 2>&1 || true
|
|
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
|
|
$(pkg_sample_purge_script fips.yaml hosts)
|
|
fi
|
|
EOD
|
|
}
|
|
EOF
|
|
|
|
cat > "${STAGE}/pkg-plist" <<'EOF'
|
|
bin/fips
|
|
bin/fipsctl
|
|
bin/fipstop
|
|
etc/fips/fips.yaml.sample
|
|
etc/fips/hosts.sample
|
|
etc/rc.d/fips
|
|
etc/rc.d/fips_dns
|
|
libexec/fips/fips-dns-setup
|
|
libexec/fips/fips-dns-teardown
|
|
@dir etc/fips
|
|
EOF
|
|
|
|
# pkg create always names the file <name>-<version>.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"
|
|
|
|
pkg_create_package "$STAGE" "${PROJECT_ROOT}/deploy" "$VERSION" "$OUT"
|