Files
abrown38andClaude Opus 5.5 34292eeebb 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>
2026-10-19 07:57:14 +01:00

150 lines
7.1 KiB
Makefile

# Housecarl build.
#
# 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])
#
# Installing, the systemd unit and the Debian packages come with the daemon
# (as in Steward's Makefile).
VERSION ?= $(shell cat VERSION 2>/dev/null || echo 0.0.0-dev)
# RELEASE_TAG marks a build of a release (the web UI then shows and links
# the release rather than the commit): set when HEAD is tagged v$(VERSION)
# and no tracked file is changed.
RELEASE_TAG ?= $(shell t=v$(VERSION); git tag --points-at HEAD 2>/dev/null | grep -qx "$$t" && git diff --quiet HEAD 2>/dev/null && echo $$t)
# DESCRIBE places other builds relative to the last tag ("3 commits after
# v0.2.0-rc.1").
DESCRIBE ?= $(shell git describe --tags --long --match 'v[0-9]*' --abbrev=12 HEAD 2>/dev/null)
LDFLAGS := -s -w -X housecarl/internal/version.Version=$(VERSION) -X housecarl/internal/version.Tag=$(RELEASE_TAG) \
-X housecarl/internal/version.Describe=$(DESCRIBE)
GOFLAGS := -trimpath
export CGO_ENABLED := 0
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
build:
go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o bin/housecarld ./cmd/housecarld
go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o bin/hc ./cmd/hc
$(MAKE) --no-print-directory completion
# Bash completion scripts, generated by the binaries themselves.
completion:
@mkdir -p bin/completion
bin/hc completion bash > bin/completion/hc
bin/housecarld completion bash > bin/completion/housecarld
vet:
go vet ./...
@test -z "$$(gofmt -l cmd internal)" || { echo "gofmt needed:"; gofmt -l cmd internal; exit 1; }
test: vet
go test ./...
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 && \
GOOS=linux GOARCH=$$arch go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o dist/housecarl-$(VERSION)-linux-$$arch/hc ./cmd/hc && \
tar -C dist -czf dist/housecarl-$(VERSION)-linux-$$arch.tar.gz housecarl-$(VERSION)-linux-$$arch || exit 1; \
done
# The platforms cli-dist builds the CLI for.
CLI_PLATFORMS ?= linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64 windows/arm64
cli-dist:
@mkdir -p dist
for p in $(CLI_PLATFORMS); do \
os=$${p%/*} arch=$${p#*/} ext=; [ $$os = windows ] && ext=.exe; \
GOOS=$$os GOARCH=$$arch go build $(GOFLAGS) -ldflags '$(LDFLAGS)' -o dist/housecarl-cli-$(VERSION)-$$os-$$arch$$ext ./cmd/hc || exit 1; \
done
clean:
rm -rf bin dist