Firewall Rules
Firewall rules filter traffic in both directions on address, port and protocol. Where Access Rules answer is this address allowed?, firewall rules answer is this conversation allowed? — and they can stop a host from reaching out, not just from being reached.
Enforcement is stateless and runs in the kernel at the TC hook, so nothing sits in the application's path.
What it gives you
- Egress control. Stop a compromised workload calling home, without an outbound proxy.
- Port and protocol matching, including port ranges, on top of address and prefix.
- Ordered rules with an explicit default. You decide what happens to traffic no rule mentions.
- Separate IPv4 and IPv6 handling, so a rule cannot accidentally span both.
How it works
- A packet is inspected at the TC hook — ingress or egress.
- Rules are evaluated in order, lowest
ordervalue first. - The first matching rule wins, and the packet is allowed or dropped accordingly.
- If nothing matches, the configured default action applies.
Evaluation stops at the first match. An allow placed below a broad drop never runs — the drop
has already decided. Give exceptions a lower order value than the rules they are meant to escape.
What a rule matches on
| Dimension | Detail |
|---|---|
| Address | Source and destination, each with a CIDR prefix length |
| Port | Source and destination ranges, low and high bounds; unset means any |
| Protocol | IP protocol number — TCP, UDP, or any |
| IP version | IPv4 or IPv6, chosen per rule |
| TCP flags | A mask and the value it must equal — see below |
| Direction | ingress or egress |
| Action | allow or drop |
Only active rules are loaded into the kernel, so disabling a rule takes it out of the datapath rather than leaving it inert but resident.
TCP flags
Flag matching is expressed as flags & mask == value — you name the flags you
care about, and what they must be. That is the same primitive nftables and iptables
use natively, so a rule means the same thing whichever backend enforces it.
| You want | Mask | Value |
|---|---|---|
| SYN set, nothing else constrained | syn | syn |
| An ACK that is not a SYN-ACK | syn,ack | ack |
| SYN without ACK — a connection attempt | syn,ack | syn |
| No RST | rst | (empty) |
tcp_flags: "ack" has three defensible readings, and firewall vendors genuinely
disagree about which they mean: ACK set with everything else unconstrained, ACK set
and nothing else, or any of the listed flags set. For one flag the readings coincide;
for a list they diverge completely — under the third reading
syn,ack,fin,rst,psh,urg matches every TCP packet, and under the second it matches
essentially none.
Rather than pick a convention and let you discover it in production, the mask must be stated. It is one extra field and it removes the ambiguity entirely.
Firewall rules or access rules?
| Access Rules | Firewall Rules | |
|---|---|---|
| Hook | XDP, before routing | TC, after ingress and before egress |
| Direction | Inbound only | Inbound and outbound |
| Matches | IP address | IP, port range, protocol |
| Cost | The cheapest drop available | Slightly higher, still in-kernel |
| Reach for it when | Absorbing a known-bad address at volume | Expressing a specific allowed conversation |
Both are enforced by Hillock and both are driven by decisions Amygdala makes. Neither is a substitute for the other: address blocking is cheaper, conversation control is more precise.
One rule, whichever backend runs it
Rules are written once and enforced by whatever the host can actually offer. Synapse picks the best available and falls back rather than failing:
XDP / eBPF → nftables → iptables
A modern kernel gets in-kernel eBPF enforcement. A host without it falls back to nftables, and one without that to iptables. The rule you wrote does not change — only the machinery underneath it does, which is why the same policy can cover a fleet that is not uniform.
The intent is one firewall platform across Linux and Windows, with the same rule model on both. The Windows firewall backend is still in development — today, plan Windows enforcement as a roadmap item rather than something to build policy on.
Limits worth knowing
- Stateless. Rules match each packet on its own; there is no connection tracking, so a rule permitting a reply must exist in its own right.
- No application awareness. Matching stops at the transport header. For TLS SNI, HTTP paths or fingerprints, use Amygdala — it evaluates those on the host and installs the resulting block here.
Use cases
- Deny egress by default and allow only the destinations a workload legitimately needs.
- Contain a compromised host by cutting its outbound paths while leaving inbound monitoring intact.
- Restrict a management port to one source range without touching the service itself.
- Prove an allow-list before enforcing it by ordering a permissive rule above a broad deny, then removing it.
See also
-
Smart Firewall — fingerprint-driven blocks, installed into this same kernel firewall
-
Access Rules — faster, address-only, inbound
-
Configuration — the agent's firewall settings
-
Hillock — the kernel firewall that enforces these
-
Amygdala — evaluates richer conditions and installs the resulting blocks