Build Housecarl 0.1.0: the nftables firewall manager

Zones, address sets (IPv4 and IPv6 mixed, dynamic sets with timeouts) and
services, ordered rules in the early, input, forward and output chains,
port forwards with hairpin NAT and IPv6 pinholes, source NAT, redirects,
and switchable built-ins (loopback, conntrack, ICMPv6, antispoofing, MSS
clamping, DHCPv6 client, flowtable). Every change is validated, checked
with nft -c and applied in one transaction to Housecarl's own table,
inet housecarl; changes made over the network roll back unless
confirmed, and the confirmed ruleset is loaded at boot by
housecarl-ruleset.service. An empty configuration applies nothing.

Also: hit counters and the drop log (nflog), 'hc import' of an existing
nftables ruleset and 'hc takeover', the hc CLI, the REST API and the web
UI, users, scoped tokens (sets:write:NAME), the audit log, the web UI's
certificate through Jarl, Debian packages, docs, unit tests with real
nft 1.1.3, and an e2e test with real traffic (71 checks).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
abrown38andClaude Opus 5.5 committed 2026-10-19 07:57:14 +01:00
1 parent 54beb0bba3
commit 34292eeebb
118 files changed
+22165 -114

No files matched your search

+81 -1
View File
@@ -3,6 +3,12 @@
# make build bin/housecarld and bin/hc (and their bash completion)
# make test vet, gofmt check and unit tests
# make logo rebuild the web UI's logo and the README banner from artwork/
# make e2e end-to-end test with real traffic through a firewall in Docker (scripts/e2e.sh)
# sudo make install install binaries, bash completion, systemd units,
# sysusers/tmpfiles files and an example /etc/housecarl/housecarl.yaml
# make deb Debian packages in dist/ (DEB_ARCH=arm64 for another
# architecture): housecarl (the server) and housecarl-cli (hc,
# which housecarl depends on)
# make dist static binaries for linux/amd64 and linux/arm64 in dist/
# make cli-dist the CLI alone for Linux, macOS and Windows in dist/
# (housecarl-cli-<version>-<os>-<arch>[.exe])
@@ -23,7 +29,32 @@ LDFLAGS := -s -w -X housecarl/internal/version.Version=$(VERSION) -X housecarl/i
GOFLAGS := -trimpath
export CGO_ENABLED := 0
.PHONY: all build completion test vet logo dist cli-dist clean
PREFIX ?= /usr/local
BINDIR ?= $(PREFIX)/bin
DOCDIR ?= $(PREFIX)/share/doc/housecarl
# bash-completion also looks in /usr/local/share (XDG_DATA_DIRS).
BASHCOMPDIR ?= $(PREFIX)/share/bash-completion/completions
UNITDIR ?= /etc/systemd/system
SYSUSERSDIR ?= /usr/lib/sysusers.d
TMPFILESDIR ?= /usr/lib/tmpfiles.d
DESTDIR ?=
# The binaries install-files copies (make deb points these at other
# architectures' builds).
HOUSECARLD_BIN ?= bin/housecarld
HC_BIN ?= bin/hc
# make deb: the package's architecture (Debian name) and version. A
# release is VERSION with ~ for - (0.1.0-rc.1 -> 0.1.0~rc.1, which apt
# sorts before 0.1.0). A development build is versioned after the last
# tag (0.1.0~rc.1+git3.gca0f148); uncommitted changes add the build time.
DEB_ARCH ?= $(shell dpkg --print-architecture 2>/dev/null || go env GOARCH)
DEB_DEV_VERSION := $(shell [ -n '$(DESCRIBE)' ] || exit 0; \
m=; git diff --quiet HEAD 2>/dev/null || m=.m$$(date -u +%Y%m%d%H%M%S); \
echo '$(DESCRIBE)' | sed -E 's/^v(.*)-([0-9]+)-g([0-9a-f]{7})[0-9a-f]*$$/\1+git\2.g\3/' | tr - '~' | sed "s/$$/$$m/")
DEB_VERSION ?= $(if $(RELEASE_TAG),$(subst -,~,$(VERSION)),$(or $(DEB_DEV_VERSION),$(subst -,~,$(VERSION))))
.PHONY: all build completion test vet logo e2e install install-files uninstall deb dist cli-dist clean
all: build
@@ -48,6 +79,55 @@ test: vet
logo:
python3 scripts/logo.py
e2e:
scripts/e2e.sh
install: build install-files
@if [ ! -e $(DESTDIR)/etc/housecarl/housecarl.yaml ]; then \
install -d -m 0750 $(DESTDIR)/etc/housecarl; \
bin/housecarld config --example > $(DESTDIR)/etc/housecarl/housecarl.yaml; \
chmod 0640 $(DESTDIR)/etc/housecarl/housecarl.yaml; \
echo "wrote $(DESTDIR)/etc/housecarl/housecarl.yaml"; \
fi
@echo
@echo "Next (as root): systemd-sysusers housecarl.conf && systemd-tmpfiles --create housecarl.conf"
@echo " chgrp housecarl /etc/housecarl /etc/housecarl/housecarl.yaml && systemctl daemon-reload"
@echo " systemctl enable housecarl-ruleset.service"
@echo "Then follow docs/install.md (init, import your ruleset, start)."
# Everything but /etc/housecarl/housecarl.yaml (shared by install and deb).
install-files:
install -D -m 0755 $(HOUSECARLD_BIN) $(DESTDIR)$(BINDIR)/housecarld
install -D -m 0755 $(HC_BIN) $(DESTDIR)$(BINDIR)/hc
install -D -m 0644 bin/completion/hc $(DESTDIR)$(BASHCOMPDIR)/hc
install -D -m 0644 bin/completion/housecarld $(DESTDIR)$(BASHCOMPDIR)/housecarld
for u in housecarl.service housecarl-ruleset.service housecarl-backup.service housecarl-backup.timer; do \
install -D -m 0644 deploy/systemd/$$u $(DESTDIR)$(UNITDIR)/$$u && \
sed -i 's#/usr/local/bin/housecarld#$(BINDIR)/housecarld#; s#/usr/local/share/doc/housecarl#$(DOCDIR)#' $(DESTDIR)$(UNITDIR)/$$u || exit 1; \
done
install -D -m 0644 deploy/sysusers.d/housecarl.conf $(DESTDIR)$(SYSUSERSDIR)/housecarl.conf
install -D -m 0644 deploy/tmpfiles.d/housecarl.conf $(DESTDIR)$(TMPFILESDIR)/housecarl.conf
install -D -m 0644 README.md $(DESTDIR)$(DOCDIR)/README.md
install -D -m 0644 LICENSE $(DESTDIR)$(DOCDIR)/LICENSE
install -D -m 0644 CHANGELOG.md $(DESTDIR)$(DOCDIR)/CHANGELOG.md
install -d $(DESTDIR)$(DOCDIR)/docs
install -m 0644 docs/*.md $(DESTDIR)$(DOCDIR)/docs/
uninstall:
rm -f $(DESTDIR)$(BINDIR)/housecarld $(DESTDIR)$(BINDIR)/hc $(DESTDIR)$(UNITDIR)/housecarl.service \
$(DESTDIR)$(UNITDIR)/housecarl-ruleset.service \
$(DESTDIR)$(UNITDIR)/housecarl-backup.service $(DESTDIR)$(UNITDIR)/housecarl-backup.timer \
$(DESTDIR)$(BASHCOMPDIR)/hc $(DESTDIR)$(BASHCOMPDIR)/housecarld \
$(DESTDIR)$(SYSUSERSDIR)/housecarl.conf $(DESTDIR)$(TMPFILESDIR)/housecarl.conf
rm -rf $(DESTDIR)$(DOCDIR)
@echo "Kept /etc/housecarl, /var/lib/housecarl and /var/backups/housecarl. The ruleset in force stays until the next boot."
# Debian packages, built with dpkg-deb (no root needed); scripts/mkdeb.sh
# explains the layout.
deb: build
DEB_ARCH='$(DEB_ARCH)' DEB_VERSION='$(DEB_VERSION)' VERSION='$(VERSION)' \
LDFLAGS='$(LDFLAGS)' GOFLAGS='$(GOFLAGS)' scripts/mkdeb.sh
dist: build
for arch in amd64 arm64; do \
GOOS=linux GOARCH=$$arch go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o dist/housecarl-$(VERSION)-linux-$$arch/housecarld ./cmd/housecarld && \