4.5 KiB
go-firewalld
A comprehensive Go client for the firewalld D-Bus API,
built on github.com/godbus/dbus/v5.
- Runtime + permanent operations, mirroring
firewall-cmd(transient vs--permanent). - Version/capability aware: one binary serves both old (EL7, firewalld 0.6.x)
and new (EL9+, firewalld 1.x/2.x) servers. The dict (
a{sv}) settings path and zone-to-zone policies are used where supported and transparently fall back to the v1 tuple path where they are not. - Typed,
errors.Is-able errors mapped from firewalld exceptions (ErrAlreadyEnabled,ErrNotEnabled,ErrInvalidZone, …).
Install
go get github.com/grmrgecko/go-firewalld
Usage
ctx := context.Background()
conn, err := firewalld.Connect(ctx)
if err != nil {
log.Fatal(err)
}
defer conn.Close()
fmt.Println(conn.Version()) // e.g. "1.3.4"
fmt.Println(conn.Supports(firewalld.Policies)) // false on EL7, true on EL9+
// Permanent edits (apply after a reload).
zone := conn.Permanent().Zone("public")
if err := zone.AddPort(ctx, firewalld.Port{Port: "4242", Protocol: "udp"}); err != nil {
if errors.Is(err, firewalld.ErrAlreadyEnabled) {
// idempotent no-op
} else {
log.Fatal(err)
}
}
_ = zone.SetTarget(ctx, firewalld.TargetDROP)
_ = conn.Reload(ctx)
// Read settings (transport chosen automatically by server capability).
s, _ := conn.Permanent().Zone("public").Settings(ctx)
fmt.Println(s.Services, s.Ports, s.Forward)
// Runtime (transient) edits, with an optional timeout.
_ = conn.Runtime().Zone("public").AddRichRule(ctx,
`rule family="ipv4" source address="10.0.0.0/8" reject`, 30*time.Second)
// Low-level escape hatch for anything not yet wrapped.
var out []string
_ = conn.Call(ctx, "/org/fedoraproject/FirewallD1",
"org.fedoraproject.FirewallD1.zone", "getZones", []any{&out})
Coverage
| Area | Types / handles |
|---|---|
| Connection & lifecycle | Connect, Open, Version, Supports, Reload, CompleteReload, RuntimeToPermanent, ResetToDefaults, CheckPermanentConfig, panic mode, log-denied, default zone |
| Zones (permanent) | Permanent().Zone(name): settings, update, add/remove/query for port/source/source-port/service/protocol/forward-port/masquerade/icmp-block/icmp-block-inversion/interface/rich-rule, target/short/description/version, rename, remove, load-defaults |
| Zones (runtime) | Runtime().Zone(name): same element set with timeouts; change-interface/change-source (move between zones); active zones, zone-of-interface/source; wholesale Runtime().SetSettings (dict servers) |
| Config management | zone names/paths, add-zone, zone-of-interface/source |
| Daemon properties | RuntimeInfo (state, IPv4/IPv6/IPSet/bridge support, ipset & icmp types), DaemonConfig (backend, rp-filter, cleanup, …) get/set |
| IPSets | runtime + permanent: settings, entries, options, existence query |
| Services | list, read (tuple/dict), permanent editor incl. includes |
| ICMP types | list, read, permanent editor |
| Helpers (conntrack) | list, read, permanent editor |
| Policies (≥ 0.9) | runtime + permanent, capability-gated |
| Direct interface | runtime chains/rules/passthroughs + permanent direct config blob |
| Lockdown | enable/disable/query + whitelist (command/context/user/uid) |
| Signals | WatchSignals, WatchReloaded |
Deliberately omitted as redundant with Settings()/Update(): the per-field bulk
setX list-setters and scalar getX getters on config objects. Legacy/no-op
methods (authorizeAll, isImmutable, *AutomaticHelpers, the changeZone
alias) are also skipped.
Testing
Unit tests need no bus and cover encode/decode round-trips plus
dbus.SignatureOf assertions for every compound type:
go test ./...
Integration tests run against a live firewalld and are gated behind a build tag. They operate only on throwaway zones/ipsets/policies they create and remove, so a failure cannot disturb the default zone or an SSH session. Build a test binary and run it on the target host (no Go toolchain needed there):
CGO_ENABLED=0 GOOS=linux GOARCH=amd64 \
go test -c -tags firewalld_integration -o firewalld.itest .
scp firewalld.itest root@host:/tmp/
ssh root@host '/tmp/firewalld.itest -test.v'
Verified against firewalld 0.6.3 (CentOS 7, iptables backend) and 1.3.4 (Rocky 9, nftables backend); signature tests additionally cover 2.4.3.