Files
housecarl/docs/validation.md
T
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

5.5 KiB

Validation

Every change is checked as a whole configuration before it is applied. An error stops the change; a warning is reported with it, and stays on the dashboard and in hc status until fixed. Each problem has a stable code, shown by the CLI as [code] and in the API as problems[].code. housecarld check runs the checks on the saved configuration.

After Housecarl's own checks, nftables checks the rendered ruleset (nft -c). What it refuses (mostly raw rules) comes back as a firewall error with nftables' message, and nothing is changed.

The warnings marked host compare the configuration with this machine's interfaces.

Names

Zones, sets, services and port forwards have names (a forward's is optional): a letter, then letters, digits, - and _, up to 48. Names are unique per kind, ignoring case.

Code When
zone_name, set_name, service_name, forward_name error not a valid name, or one that looks like an address
zone_name_taken, set_name_taken, service_name_taken, forward_name_taken error another object of the kind has that name

Settings

Code When
policy error a policy that isn't accept or drop
settings_address error an own prefix or antispoof entry that isn't an address or prefix, or is in the wrong list (an IPv6 prefix in the IPv4 list)
flowtable_device error a flowtable device with a wildcard: name each device
flowtable_device_missing warning, host a flowtable device doesn't exist; the flowtable is left out until it does
probation_range error the probation isn't 10 to 3600 seconds

Zones

Code When
zone_empty error no interfaces
zone_interface error not an interface name (up to 15 characters; a trailing * matches many)
zone_interface_taken error the interface is in another zone already
zone_interface_missing warning, host the interface doesn't exist here (yet); its rules match once it does
no_external_zone warning no zone is external: antispoofing, MSS clamping, the DHCPv6 client rule and port forwards without public addresses need one

Sets and services

Code When
set_entry error an entry that isn't an address, prefix (without host bits) or range
set_empty warning a set (not dynamic) with no entries: rules using it match nothing
set_timeout error a timeout on a set that isn't dynamic, or under a second
service_empty error a service with no entries
service_entry error an entry that isn't PROTO/PORTS (tcp, udp, sctp; a port or range) or icmp/TYPE, icmpv6/TYPE with a type nftables knows

Matches

These apply to rules, source NAT and redirects.

Code When
unknown_zone error a zone that doesn't exist
match_in_zone error in zones on the output chain (it has no incoming interface)
match_out_zone error out zones on the input or early chain, or on a redirect
match_address error an address that can't be read
unknown_set error a name that is neither an address nor a set
unknown_service error a service that is neither built in nor yours
family error a family that isn't ipv4 or ipv6
match_never error the addresses, services and family can't all match the same packet (IPv4 sources and an icmpv6 service)

Rules

Code When
rule_chain error a chain that isn't input, forward, output or early
rule_action error an action that isn't accept, drop, reject or log
raw_rule error a raw rule over several lines, or with ;
early_conntrack error connection states, limits or a connection limit in the early chain, which runs before connection tracking
early_reject error reject in the early chain: drop instead
ct_state, ct_status error an unknown connection state or status
rule_day, rule_hours error an unknown day, or hours that aren't HH:MM, or only one of them
rule_limit error a rate that isn't a number per second, minute, hour or day
rule_conn_limit error a connection limit under 1
reject_with error tcp-reset on a rule that matches more than TCP, or with an action other than reject
log_prefix error a log prefix over 100 characters

Port forwards

Code When
forward_protocol error no protocols, or one that isn't tcp, udp or sctp
forward_ports error the public port isn't a port or range
forward_to_port error the inside port isn't one port, or is given for a range of public ports
forward_target error neither to nor to6, or to that isn't one IPv4 address, or to6 one IPv6 address
forward_public error no public addresses and no external zone, or an IPv6 public address
forward_overlap error another forward has the same protocol, port and public address
forward_hairpin warning hairpin without public addresses: inside clients' connections can't be recognised

Source NAT and redirects

Code When
snat_to error to isn't one address, or of another family than the rule (give the rule the family)
snat_everything warning no out zones and no sources: everything leaving the firewall is translated
redirect_service error no service, or one without TCP, UDP or SCTP ports
redirect_to_port error the local port isn't one port