Changesets, as in Jarl: configuration changes are operations that can be staged in a changeset, checked as they are added (validation and nft -c), reviewed with the diff of the ruleset, and applied together as one history entry, then on probation like any change made over the network. The web UI collects edits for review by default (pending rows, a bar with Review and Apply now, a Changes page, a switch for live edits); hc stages with -C ID or HOUSECARL_CHANGESET (checked like JARL_CHANGESET) and has hc changeset create/list/show/diff/apply/discard/remove. Undo, import and takeover refuse a changeset. --dry-run shows the ruleset's diff. Bandwidth and quotas: rate limits in bytes, per source or destination; quotas per rule or per address that reset daily, weekly, monthly on a day, or by hand, with their usage carried across reloads, saved for reboots, shown by hc quotas and on the rules page, and reset with hc rule reset-quota. Rules that count traffic are checked before established connections are accepted (so they see every packet) and can't accept. Per-address limits group IPv6 by /64 by default (--group-v4/-v6). Per-source rate meters use update. The importer turns meters, byte rates and quotas into these fields. The examples in the web UI, hc's help and the docs use documentation addresses and generic names instead of the maintainer's network. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
118 lines
6.5 KiB
Markdown
118 lines
6.5 KiB
Markdown
# 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 |
|
|
| `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 |
|
|
| `flowtable_traffic` | warning | a forward rule with a quota or a byte rate while the flowtable is on: it only counts 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 |
|