shadow.enabled in housecarl.yaml loads Housecarl's ruleset so that it blocks, rejects and translates nothing: drops and rejects count and accept (an accept only ends Housecarl's chain), policies accept and log what they would drop, NAT only counts, MSS clamping and the flowtable are left out, and raw rules that do more than accept, drop or reject are left out with a warning. Comments mark what would happen ([would drop]). Filter chains run after the other firewall's (+10) or before (-10); NAT chains always first. Every change is checked by nftables in both forms. No probation; takeovers and closing connections are refused. The boot fallback filters nothing. internal/tablewatch puts the table back after a flush ruleset. Mode in status, healthz, whoami, the web UI, the log and the tracer; hc ruleset --enforcing. docs/shadow.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
13 KiB
The hc CLI
hc talks to housecarld's REST API. hc help COMMAND describes each
command and its flags.
Connecting
-
On the firewall, with nothing configured, the CLI uses housecarld's local socket,
/run/housecarl/housecarl.sock. Root and thehousecarluser are administrators there without a token, and their changes need no confirmation:sudo hc status. -
From elsewhere, give the server's URL and an API token:
hc config set server https://fw.example.com:8070 hc config set token # asks for itThe settings are in
~/.config/housecarl/config.yaml(on macOS~/Library/Application Support/housecarl/config.yaml, on Windows%AppData%\housecarl\config.yaml).
| Flag | Environment | |
|---|---|---|
-s, --server URL |
HOUSECARL_SERVER |
the server; local for the local socket |
--token TOKEN or @FILE |
HOUSECARL_TOKEN |
the API token |
--config FILE |
HOUSECARL_CLI_CONFIG |
the CLI's configuration file |
HOUSECARL_SOCKET |
the local socket's path | |
--insecure, --ca-cert FILE |
TLS: skip the check, or trust another CA | |
-n, --dry-run |
check and show a change without making it, with the ruleset's diff | |
--no-confirm |
leave a change on probation instead of confirming it once hc reaches Housecarl again |
|
-C, --changeset ID |
HOUSECARL_CHANGESET (checked, see Changesets) |
stage configuration changes in this changeset instead of making them |
-o, --output FORMAT |
table (default), json, yaml or id |
|
-q, --quiet |
print only errors (and the IDs of new objects) |
Exit codes: 0 ok, 1 error, 3 not authenticated or not allowed, 4 not found, 5 conflict, 6 invalid or refused by validation or nftables, 7 server error.
Changes
Every change is checked as a whole, then by nftables, before it is put
in force. A refused change says why, with the problem's code
(validation.md). An applied one says its history entry
and any new warnings. Over the network, it is on probation, and hc
confirms it by reaching Housecarl again over a new connection
(operations.md):
$ hc rule add input --from trusted --service ssh --comment "SSH from home"
created rule input #31 (from trusted · ssh)
applied and confirmed (history 12): this client reached Housecarl again over a new connection
Through the socket the change is kept at once:
applied and saved (history 12; undo with 'hc history undo 12')
-n shows what would change without changing it, with the diff of the
ruleset; nftables checks it too.
Changesets
To review several changes and apply them together, as one entry in the history, stage them in a changeset:
export HOUSECARL_CHANGESET=$(hc changeset create "guest network" -q)
hc zone add guest -i eth1.30
hc rule add forward --in guest --out wan
hc changeset diff # the operations, problems, nftables' check, the ruleset's diff
hc changeset remove 2 # take operation 2 out
hc changeset apply # one change; over the network on probation
unset HOUSECARL_CHANGESET
$ hc rule add forward --in guest --out wan
changeset 7 (guest network, 1 operation) from HOUSECARL_CHANGESET
staged: create rule forward #52
staged in changeset 7 as operation 2 (2 operations now); review with 'hc changeset diff 7', apply with 'hc changeset apply 7'
Each change is checked as it is staged: the changeset with it must stay
valid, and nftables must accept the ruleset, so make a set before the
rule that names it. Applying checks the whole changeset again, on the
configuration as it is then; an operation whose object changed since is
named (operation 3 (update rule input #12) can't be applied: …), and
hc changeset remove takes it out.
| Command | |
|---|---|
changeset create [DESCRIPTION] |
start one; -q prints only its ID |
changeset list [--status open|applied|discarded|""] [--mine] |
open ones by default |
changeset show [ID] |
its operations |
changeset diff [ID] |
what applying it would do |
changeset apply [ID] [--description D] |
apply it |
changeset discard [ID] |
throw it away |
changeset remove [ID] OP |
take one operation out |
show, diff, apply, discard and remove work on the changeset you
name, else the one in -C, else the one in HOUSECARL_CHANGESET.
A changeset from HOUSECARL_CHANGESET is checked before anything uses
it, because an exported ID easily outlives its changeset:
- Staging into it, and
apply,discardandremoveon it, need it to be open and yours. Otherwise the command stops and says why (there is no changeset 99,changeset 42 is applied,changeset 57 is sam's). Commands that only read, andhc changeset create, don't care. - Each command says on stderr which changeset it uses:
changeset 42 (guest network, 2 operations) from HOUSECARL_CHANGESET(not with-q). - After
applyordiscard, a reminder tounset HOUSECARL_CHANGESET.
-C ID and an ID argument are used as given (housecarld still refuses a
changeset that isn't open, or another user's unless you are an
administrator). Only configuration changes are staged: dynamic set
entries, confirm and rollback are made at once; history undo is
staged like any change; import and takeover can't be staged, so they
are refused while a changeset is named. Changesets staged in the web UI show up here too,
and the other way round.
Commands
Objects are named by ID or, for zones, sets, services and port forwards, by name.
status and the ruleset
| Command | |
|---|---|
status |
the mode (in shadow mode), the ruleset (in force or not), changes on probation, problems, interfaces, other tables |
interfaces |
the machine's interfaces, their addresses and zones |
ruleset [--enforcing] |
the nftables ruleset Housecarl builds; in shadow mode, --enforcing shows the one loaded once it is off (shadow.md) |
counters |
the hits of every rule, NAT rule, built-in and policy, by mark (r12, f3, b-established, p-input) |
quotas |
what each rule's quota used (each address's, for per-address quotas), and when it resets |
log [-f] [--search TEXT] [--limit N] |
the packets logged by rules and policies (operations.md) |
connections [--search TEXT] [--limit N], connections close --search TEXT [-y] |
tracked connections; closing makes the rules check them again (operations.md); not in shadow mode |
stats [--since 24h] |
traffic per zone, drops, the busiest rules, blocked sources, devices; stats status, stats traffic, stats top devices|blocked|tried|quota ID, stats rules [--unused], stats connections (stats.md) |
matrix [FROM TO] |
what the rules do to new connections between zones; with FROM and TO, that pair's rules in order (rules.md) |
trace [--address A] [--port N] [--protocol P] [--seconds S] |
follow packets through every table's rules (operations.md) |
zone, set, service
| Command | |
|---|---|
zone list, zone show ZONE |
|
zone add NAME -i IFACE... [--external] [--comment C] |
|
zone update ZONE [-i IFACE]... [--add IFACE] [--remove IFACE] [--external[=false]] [--name N] [--comment C] |
-i replaces the interfaces; --name renames it, and the rules naming it follow |
zone delete ZONE |
refused while rules use it |
set list, set show SET |
|
set add NAME [ENTRY...] [--dynamic] [--timeout 24h] [--comment C] |
|
set update SET [--entry E]... [--add E] [--remove E] [--timeout] [--name] [--comment] |
--entry replaces the entries |
set entries SET, set entries add SET ADDRESS [--timeout 1h], set entries remove SET ADDRESS |
a dynamic set's entries |
set delete SET |
|
service list, service show SERVICE |
with the built-in ones |
service add NAME ENTRY... [--comment C] |
entries tcp/22, udp/1000-2000, icmp/echo-request, icmpv6/packet-too-big |
service update SERVICE, service delete SERVICE |
See rules.md.
rule
| Command | |
|---|---|
rule list [CHAIN] |
in order, with their hits |
rule show ID |
|
rule add CHAIN [MATCH] [-a ACTION] [--first|--before ID|--after ID] |
at the end of its chain unless placed |
rule update ID [flags] |
only the flags given |
rule move ID --before ID|--after ID|--first|--last|--chain CHAIN |
|
rule enable|disable ID |
|
rule reset-quota ID |
start a rule's quota again now |
rule delete ID |
The match flags (rule add, snat add, redirect add):
--in ZONE, --out ZONE (--not-in, --not-out) |
zones |
--from, --to (--not-from, --not-to) |
sets, addresses, prefixes, ranges |
--service |
services or entries |
--family ipv4|ipv6 |
And for rules: --state, --status, --days, --hours, --limit 10/minute|1mbytes/second[,burst=N][,over][,per-source|,per-destination],
--quota 50gbytes[,over][,per-source|,per-destination][,daily|,weekly|,monthly=DAY],
--group-v4 N, --group-v6 N, --conn-limit N, --every-packet, -a accept|drop|reject|log, --reject-with tcp-reset, --log,
--log-prefix, --raw RULE, --comment, --disabled
(rules.md).
forward, snat, redirect
| Command | |
|---|---|
forward list, forward show FORWARD |
port forwards, with their hits |
forward add PORTS --to HOST[:PORT] [--proto tcp,udp] [--public ADDR]... [--from SRC]... [--hairpin] [--hairpin-from SRC]... [--to6 HOST] [--name N] [--comment C] |
|
forward update FORWARD [flags], forward delete FORWARD |
|
snat list, snat add [MATCH] [--snat-to ADDR], snat update ID, snat delete ID |
source NAT, in order; masquerade without --snat-to |
redirect list, redirect add [MATCH] [--to-port PORT], redirect update ID, redirect delete ID |
See nat.md.
settings
| Command | |
|---|---|
settings show |
|
settings set [--input-policy|--forward-policy|--output-policy accept|drop] [--log-drops on|off] [--builtin NAME=on|off]... [--own-prefix P]... [--antispoof-v4 P]... [--antispoof-v6 P]... [--flowtable DEV]... [--probation 2m] [--auto-confirm on|off] [--stats-per-device on|off] |
lists given replace the old ones; none empties one (--flowtable none: off) |
probation, history, import
| Command | |
|---|---|
confirm |
keep the changes on probation; the ruleset is saved for the boot |
rollback |
undo the changes on probation now |
history list [--limit N] |
changes, newest first |
history show ID |
each object before and after |
history undo ID |
apply the change backwards (refused if something it touched has changed since) |
import [FILE|-] [--text FILE] [--defines FILE] [--table T] [--zone IFACE=NAME]... [--replace] |
import.md |
takeover TABLE... [-y] |
delete tables Housecarl's ruleset replaces (administrators); not in shadow mode |
cert
Administrators only (certificates.md).
| Command | |
|---|---|
cert |
the certificate: name, CA, validity, renewal, the last check |
cert check |
check that the challenge can be published through Jarl and seen, without the CA (exit code 1 if it can't) |
cert renew [-w] |
get a new certificate now; -w waits and shows the result |
users, tokens, audit
| Command | |
|---|---|
whoami |
who you are to the server, and what you may do |
user list|add|update|delete |
users (administrators); user add NAME --role operator |
token list [--all], token create NAME [--role R] [--grant G]... [--expires 90d] [--user U] [--save], token revoke ID |
API tokens |
token rotate ID|--current [--grace 1h] [--expires 90d|never] [--save] |
a new secret for a token, the old one working for the grace period |
password |
change your password |
audit [--user U] [--action PREFIX] [--search TEXT] |
the audit log |
config show, config set server|token|insecure|ca_cert [VALUE] |
this CLI's settings |
permissions.md explains roles and grants.
housecarld
The daemon's own commands work on the database directly, as root or the
housecarl user (sudo -u housecarl housecarld ...):
| Command | |
|---|---|
housecarld serve |
run (the systemd unit does) |
housecarld init [-u NAME] [--token] |
create the database and the first administrator (asks for the name on a terminal) |
housecarld user add NAME [--admin], user password NAME, user token NAME TOKEN-NAME |
when the API can't be used |
housecarld check |
check the configuration against this machine's interfaces |
housecarld backup [FILE], housecarld restore FILE |
operations.md |
housecarld config [--example] |
the settings in use, or a commented example |
housecarld version |
All take -c FILE for another configuration file.