Files
housecarl/docs/validation.md
abrown38andClaude Opus 5.5 e9a24b14e3 Refuse link-local addresses in the antispoof lists
fe80::/10 in the IPv6 antispoof list (or your prefixes) dropped the
ISP's router adverts and DHCPv6 replies in the early chain, before the
ICMPv6 and DHCPv6 client built-ins could accept them: the router lost
its IPv6 default route. Validation now refuses it
(antispoof_link_local), the settings page says so, and the importer
leaves it out with a note.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 01:00:00 +00:00

12 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)
antispoof_link_local error an own prefix or IPv6 antispoof entry holds link-local addresses (fe80::/10): the ISP's router adverts and DHCPv6 replies come from them, so dropping them on external zones loses the IPv6 default route and, later, the delegated prefix. A configuration saved before this check keeps being applied; the next change is refused until the entry is taken out
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
stats_no_external warning traffic per device is on, but no zone is external: it counts what goes to and comes from external zones
stats_flowtable warning traffic per device with the flowtable on: its fast path skips the forward chain, so only each connection's first packets are counted

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, and the boot fallback lets nothing but loopback through without one (operations.md)

Sets and services

Code When
set_name_reserved error a set name starting with meter_, conn_, quota_, stats_ or ban_: Housecarl's own sets (rate limits, quotas, statistics, ban lists) use those
set_entry error an entry that isn't an address, prefix (without host bits) or range
set_empty warning a set (not dynamic, not from Jarl) with no entries: rules using it match nothing
set_dynamic_entries error configured entries on a dynamic set: its entries come at run time
set_timeout error a timeout on a set that isn't dynamic, or under a second
set_jarl_entries error configured entries on a set from Jarl: its addresses are its names' (jarl.md)
set_jarl_dynamic error a set both dynamic and from Jarl
set_jarl_names error a set from Jarl without names, with one that isn't a DNS name (a wildcard, say) or a bad view, or with a name twice
set_jarl_within error a set from Jarl without within, or with an entry there that is neither a zone nor an address, network or range
set_jarl_anywhere warning a set from Jarl within 0.0.0.0/0 or ::/0: any address may come in, so whoever changes the names in Jarl decides what it holds
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 ;
raw_conflict error a raw rule with other fields set (zones, addresses, services, limits, log…): it is used as written, so they would be ignored
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
rule_limit_unit error a rate's unit that isn't packets, bytes, kbytes or mbytes
rule_limit_bytes error a byte rate nftables can't hold: over 4 GB a second, 293 MB a minute, 4.9 MB an hour or 208 KB a day (the message gives it per second)
rule_limit_key error a limit both per source and per destination
rule_quota error a quota under 1 byte
rule_quota_key error a quota both per source and per destination
rule_quota_reset error a reset that isn't daily, weekly or monthly; a day with another reset than monthly; a day outside 1-31
rule_group error a grouping prefix outside 1-32 (IPv4) or 1-128 (IPv6)
rule_traffic_accept error a rule with a quota or a byte rate that accepts: it is checked before established connections are accepted, so it can only drop, reject or log
rule_every_packet_accept error a rule checked against every packet (every_packet) that accepts: it comes before established connections are accepted, so it can only drop, reject or log
quota_restarts warning a change makes a rule count its quota so that what it used can't carry over (a total to per address, per source to per destination, finer groups): it starts again. Only on the change that does it
flowtable_traffic warning a forward rule checked against every packet (a quota, a byte rate, every_packet) while the flowtable is on: it only sees each connection's first packets
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

The machine

These come from housecarld looking at the machine, not at the configuration: the dashboard and hc status show them.

Code When
nftables_service warning, host Debian's nftables.service is enabled: at boot it loads /etc/nftables.conf, and stopping or restarting it runs nft flush ruleset, deleting Housecarl's table too. Disable it with systemctl disable nftables (without --now)
conntrack_full warning, host the connection tracking table is over 80% full; once it is full, the kernel drops new connections. Raise net.netfilter.nf_conntrack_max, or find what opens so many (stats.md)
takeover_pending warning, host the table you imported from is still in force beside Housecarl's, so a packet must get past both; hc takeover TABLE deletes it once Housecarl's rules are right
shadow_unprotected warning, host shadow mode, and no other table has a filter chain on the input hook: Housecarl's ruleset blocks nothing, and nothing else protects the machine. Load your firewall, or leave shadow mode (shadow.md)
jarl_name warning, host a set from Jarl has a name that gives no addresses, and why: no A, AAAA or CNAME record, a wildcard only, a CNAME out of Jarl's zones or in a loop, below a delegation, a zone Jarl doesn't hold the records of, or in more than one view without one named (jarl.md)
jarl_outside warning, host an address a name has in Jarl is left out of its set: it isn't within the set's zones and networks (jarl.md)
jarl_unreachable warning, host reading Jarl failed (unreachable, the token refused…), for every name or one; the sets keep the addresses they had (jarl.md)
jarl_not_configured warning, host sets from Jarl, but no jarl.server in housecarl.yaml: they keep the addresses they last had
shadow_raw_left_out warning, host shadow mode leaves this raw rule out: it does more to packets than accept, drop or reject (NAT, setting a mark or field, a jump, a verdict map…). Its hits aren't counted, and the rules after it see what it would have taken (shadow.md)

In shadow mode nftables_service and takeover_pending aren't raised: another firewall beside Housecarl is the point there.

Ban lists

Code When
banlist_name error not a valid name (as for zones and sets)
banlist_name_taken error two ban lists with one name
banlist_scope error a scope other than firewall, hosts or everything
banlist_hosts error scope hosts without hosts, or hosts with another scope
banlist_address error a host or never entry that isn't an address, prefix or range
unknown_set error a host or never entry naming a set that doesn't exist
banlist_time error negative times (but max_time -1), or a default longer than the longest
banlist_entries error max_entries below 0 or above 1000000
banlist_group error group_v6 outside 16 to 128