Map the rendered hosts/providers/routes/routing_rules sections into native
tomswall config (config.Host/Provider/StaticRoute/RoutingRule). The route's
egress interface (oif) maps to StaticRoute.Device.
The agent now maps the rendered NAT sections into native tomswall config:
- snat/masquerade -> config.SNAT, expanding a rendered rule's egress interface
list and source CIDRs into one native rule per (egress, source) pair (a native
SNAT rule takes a single dest interface); carries address/probability.
- netmap -> config.Netmap (from_net/to_net -> net1/net2 on the resolved interface).
- 1:1 nat -> config.StaticNAT.
Unit-tested end to end from RenderedConfig to config.Config.
The agent now collects the device's reachable prefixes from the kernel FIB
(including FRR-installed routes) via 'ip route show' / 'ip -6 route show' and
reports them to the control plane (POST /devices/{name}/routes) alongside its
status. tomswallapi uses these to scope which routers enforce a rule. Route
parsing (default routes, ECMP nexthop lines, route-type keywords, host routes,
v4/v6) is unit-tested; collection degrades to nil without iproute2.
- Makefile: add make patch|minor|major (tag + push), dist-build, completions,
and rpm/rpm-package targets.
- packaging/nfpm.yaml + scripts/build-rpm.sh: package the tomswall binary with
bash/zsh completions, the example config, and a systemd agent unit into an RPM.
- packaging/tomswall-agent.service + agent.env: run `tomswall agent` as a
systemd service (CAP_NET_ADMIN/CAP_NET_RAW), configured via /etc/tomswall/agent.env.
- .woodpecker/release.yaml: on v* tag, test -> build -> package RPM -> PUT to the
artifactapi rpm-internal repo. Matches node-lookup conventions.
Add `tomswall agent`: it pulls this device's compiled config from tomswallapi,
differentially applies it, and reports the applied generation. It caches the
last known-good config and, when the control plane is unreachable, keeps
applying that cache — it never fails closed.
- internal/agent: rendered-config types, HTTP client (fetch + status report),
on-disk cache, on-device DNS resolver for dns sets (honors the device's
configured resolver, fail-safe on lookup failure), and the pull-apply-report
loop behind a mockable Applier.
- Translate the interface-agnostic, address-matched rendered model into native
tomswall config using the "all:<cidr>" any-interface source/dest form, reusing
the existing differential engine. Named-set members are inlined as concrete
addresses (native nft set references are a tracked follow-up).
- cmd/tomswall: wire the `agent` subcommand (flags + TOMSWALL_* env, --once).
- Unit tests: translation, cache, and the don't-fail-closed fallback loop.
- Add DESIGN.md documenting the control-plane architecture.
Spiritual successor to shorewall — manages nftables directly via
google/nftables. Reads a single YAML config covering zones, interfaces,
hosts, policy, rules, snat, and named portgroups. Computes differential
changes against the running nftables state and applies them atomically.
Supports detecting and purging rules added outside of tomswall.