Firewall Rules & Aliases¶
A firewall ruleset is an ordered list, not a set of independent statements — order determines behaviour as much as the rules themselves. This page covers the evaluation model common to most packet filters, then how pfSense expresses it, including aliases and the ordering traps that make correct-looking rules silently do nothing. It assumes the interface and subnet groundwork from VLAN Basics in pfSense and Routing and VLANs in pfSense, and pairs with Stateful Firewalls & Connection Tracking.
A Standard Public VLAN Ruleset¶
The common case: a VLAN carrying untrusted clients — public or guest wireless — that needs internet access and nothing else. The rules below sit on that VLAN's interface tab, top to bottom, and assume a Network alias INTERNAL_NETS listing every internal subnet. GUEST net is the built-in macro for the subnet on the interface the rules belong to.
| # | Action | Source | Destination | Port | Description |
|---|---|---|---|---|---|
| 1 | Pass | GUEST net |
This Firewall (self) | 53 (TCP/UDP) | ALLOW DNS to firewall |
| 2 | Block | GUEST net |
This Firewall (self) | any | BLOCK all other access to firewall |
| 3 | Block | GUEST net |
INTERNAL_NETS |
any | BLOCK to other subnets |
| 4 | Pass | GUEST net |
any | any | ALLOW internet |
What each rule does:
- 1 — DNS. Clients resolve against the firewall's resolver. Without this, rule 2 blocks it and every lookup fails while the connection otherwise appears up. Only needed where the firewall is the DNS server handed out by DHCP; if clients are pointed at an external resolver, omit it and let rule 4 carry the traffic.
- 2 — Lock out the firewall itself. Everything on the firewall not explicitly permitted above is refused: web GUI, SSH, and any service bound to an interface address. Without this rule, rule 4 permits guests to reach the firewall's own addresses, since "any" includes them.
- 3 — Isolation. Stops the VLAN reaching other internal subnets. One alias reference covers all of them, so adding a subnet later means editing the alias, not this rule. Must sit above rule 4, or the catch-all permits the traffic first.
- 4 — Internet. The catch-all. Anything not caught by 2 or 3 is, by elimination, destined off-network, so this is a permit for internet access rather than the blanket "allow everything" it looks like in isolation.
Rule 1 is the pattern for any service the firewall hosts for this VLAN: an explicit pass above rule 2, or rule 2 blocks it. NTP is the other candidate — a pass to This Firewall (self) on UDP 123 — but only where clients are actually pointed at the firewall for time, which means the NTP server address is set in the VLAN's DHCP scope. Enabling the NTP service is not sufficient on its own; a listening server nothing is directed to sees no traffic. Clients left on their vendor defaults use external time servers and are covered by rule 4.
Points that are easy to miss:
- No rule is needed for return traffic. The firewall is stateful — a permitted outbound connection has its replies allowed automatically. See Stateful Firewalls & Connection Tracking.
- No rule is needed for DHCP. Where a DHCP server is enabled on the interface, pfSense generates the pass rules automatically, ahead of this list.
- Nothing permits inbound traffic to this VLAN from elsewhere. That is the default deny doing its job; no explicit block is required to achieve it.
- Client-to-client traffic within the VLAN never reaches the firewall. It is switched locally, so no rule here can affect it. Isolating wireless clients from each other is a function of the access point — client isolation, or an equivalent AP setting.
- Set the address family to match. A rule set to IPv4 only will not filter IPv6, so where IPv6 is active on the VLAN, rules 2 and 3 leak unless they are IPv4+IPv6 and the alias holds the IPv6 subnets too.
- Reject rather than Block on rules 2 and 3 if fast failure is more useful than silence — the client gets an immediate error instead of a timeout.
Common additions to this pattern: a block on outbound TCP/UDP 53 to anything other than the firewall, forcing clients onto the local resolver; and a bandwidth limiter applied to rule 4. Restricting the VLAN to specific outbound ports rather than any is possible, but tends to break more than it protects on a network serving arbitrary client devices.
The rest of this page covers why the order above is the order it is, and what happens when it is not.
The Evaluation Model¶
Three properties define how a ruleset behaves; most "the rule is there but it isn't working" cases come from misreading one of them.
- First match wins. Rules on an interface tab are evaluated top to bottom. The first rule whose criteria match the packet decides the outcome, and evaluation stops there.
- Rules are evaluated on the interface where traffic enters the firewall. A rule controlling traffic from subnet A to subnet B belongs on interface A, not interface B.
- Default deny. Anything not explicitly passed is dropped by an implicit final rule. That rule is not shown in the rule list, but blocked packets appear in the firewall log attributed to it.
A pass rule placed below a block rule that also matches the same traffic is dead code — never reached, never logged, and still looking correct in the GUI.
Evaluation runs in stages: Floating rules, then interface group rules, then the interface tab. A packet matched at an earlier stage never reaches a later one, so an interface rule cannot override a matching interface-group rule.
Ahead of all of those, pfSense generates automatic rules that appear nowhere in the GUI — the anti-lockout rule, rules permitting DHCP where a DHCP server is enabled on an interface, and rules for enabled IPsec tunnels. These are quick rules and take effect regardless of what the interface tab contains.
Anatomy of a Rule¶
| Field | Purpose |
|---|---|
| Action | Pass, Block (drop silently) or Reject (drop and reply) |
| Disabled | Deactivates a rule without deleting it |
| Interface | The interface traffic enters on |
| Address Family | IPv4, IPv6 or IPv4+IPv6 — a rule set to IPv4 only will not match IPv6 traffic |
| Protocol | TCP, UDP, TCP/UDP, ICMP, or Any — see TCP vs UDP & Common Ports |
| Source / Destination | Address, network, alias or built-in macro |
| Destination Port Range | Only settable once a port-bearing protocol is chosen |
| Log | Records matches to the firewall log; off by default on user-created rules |
| Description | Free text, display only, but the primary tool for keeping a ruleset readable |
Block leaves the client waiting for a timeout. Reject returns a TCP RST or an ICMP unreachable so the client fails immediately — but only for TCP and UDP, since no reject mechanism exists for other IP protocols, which are dropped silently under either action. Netgate's guidance is Block on WAN, where any reply confirms the address is live, and Reject on internal interfaces, where fast, obvious failure is more useful than silence.
Aliases¶
An alias is a named, reusable group of values that can be referenced by name anywhere a Source, Destination or Port would otherwise be typed. Aliases are managed under Firewall → Aliases.
| Type | Contains | Notes |
|---|---|---|
| Host | Individual IP addresses or FQDNs | A range such as 10.0.10.1-10.0.10.20 is expanded into individual addresses on save |
| Network | CIDR networks, or FQDNs | /32 for a single IPv4 address, /128 for IPv6 |
| Port | Port numbers and ranges, written 1194:1199 |
Usable with TCP, UDP and SCTP |
| URL (IPs) / URL (Ports) | A remote list imported once into an ordinary alias | Entry count is capped; unsuitable for large lists |
| URL Table (IPs) / URL Table (Ports) | A remote list held in a file and re-fetched on an interval set in days | The type to use for large or externally maintained lists |
- Aliases nest inside other aliases of a compatible type: Host and Network nest into each other, URL and URL Table nest only within their own kind, and port aliases cannot nest into address aliases.
- FQDN entries are re-resolved periodically — 300 seconds by default, adjustable under System → Advanced → Firewall & NAT. Only forward A/AAAA lookups are performed, with no wildcard or pattern matching, so FQDN aliases are unreliable for names that return rotating addresses.
Why Aliases Matter¶
- Without aliases, isolating each internal subnet from every other one needs one block rule per remote subnet, on every interface. Ten subnets means roughly ninety rules to write and keep aligned.
- With a single Network alias listing every internal subnet, each interface needs one rule: block from
this interface netto that alias. Ten interfaces, ten rules. - Adding an eleventh subnet later means editing the alias once. Every interface picks up the change, with no risk that one was missed.
- Alias names appear directly in the rule list, so
INTERNAL_NETSreads as intent where a column of raw CIDRs does not.
The Ordering Trap¶
This is the failure mode that catches people out with alias-based isolation.
A Network alias named INTERNAL_NETS contains every internal subnet — including 10.0.20.0/24, the subnet on the interface where the rule will sit. A block rule on that interface reading source: any, destination: INTERNAL_NETS therefore also matches traffic destined for 10.0.20.1, the firewall's own address on that interface, because the interface address is inside its own subnet.
Clients on that subnet then lose DNS resolution against the firewall and access to the web GUI, from a rule that appears to be about other subnets. Nothing in the rule text signals it. DHCP survives, because the automatic DHCP rules are quick and sit ahead of the interface ruleset. On the LAN interface the anti-lockout rule keeps the GUI reachable for the same reason, so the symptom usually appears first on VLAN and OPT interfaces, which have no such protection.
The fix is ordering. Any pass rule for services hosted on the firewall itself must sit above the block, or it is unreachable. A working pattern on an internal interface, top to bottom:
| # | Action | Source | Destination | Port | Purpose |
|---|---|---|---|---|---|
| 1 | Pass | <iface> net |
This Firewall (self) | 53 (TCP/UDP) | DNS resolution against the firewall |
| 2 | Pass | MGMT_HOSTS |
This Firewall (self) | 443 | Administrative access exception |
| 3 | Block | <iface> net |
INTERNAL_NETS |
any | Isolation from other subnets |
| 4 | Pass | <iface> net |
any | any | Everything else, i.e. internet |
Reverse rules 1 and 3 and the ruleset still looks reasonable, still saves without complaint, and DNS stops working. Reverse rules 3 and 4 and the isolation is gone entirely, because the permissive rule matches first.
The general principle: specific exceptions above broad blocks, broad blocks above catch-all permits.
"This Firewall (self)"¶
This Firewall (self) is a built-in macro selectable as a source or destination. Netgate documents it as matching every IP address on every firewall interface; in practice that also covers virtual IPs and localhost.
- A rule permitting a host to reach This Firewall (self) on port 443 permits that host to reach the web GUI on the WAN-side address as well as the internal one.
- Traffic still has to be routed to that address and pass the rules on the interface it enters, so this is not a bypass — but it is broader than the phrase suggests.
- Where management access is meant to be restricted to one address, name the specific interface address rather than the macro. See Management Plane Isolation for the full pattern.
Descriptions, Separators and Readability¶
- Every rule should carry a description. An undescribed ruleset cannot be audited, and shadowed rules are invisible without one.
- Use a consistent scheme across interfaces, so the same intent reads identically everywhere — for example
ALLOW DNS to firewall,BLOCK to other subnets,ALLOW internet. Scanning two interfaces side by side then makes drift and shadowing obvious at a glance. - Separators are coloured, labelled bars inserted between rules for grouping. They take no action on traffic and have no effect on evaluation. They cannot be edited after creation — changing the text or colour means adding a new separator and deleting the old one.
- Separator positions have historically drifted when rules were deleted in bulk or copied between interfaces. Those defects are fixed in current releases, but the positions are worth checking after any bulk operation.
- Disabled rules remain visible but are skipped during evaluation. Disabling is safer than deleting while testing, since the rule and its description are preserved.
Floating Rules¶
Firewall → Rules → Floating holds rules that are not tied to a single interface tab. They differ from interface rules in three ways:
- They can apply to several interfaces at once, and to a chosen Direction — in, out or any — where interface rules are always inbound only.
- With Quick ticked they behave like ordinary first-match-wins rules. Without Quick, the rule only takes effect if no other rule matches the packet, inverting the usual reading of the list.
- In the outbound direction they are evaluated after outbound NAT, so an outbound floating rule sees the translated source address rather than the private one — see NAT & Private IP Ranges.
That makes floating rules harder to reason about, so they are best reserved for cases genuinely needing breadth: traffic shaping, filtering traffic the firewall itself originates, or a policy applied uniformly across every interface. Ordinary per-subnet policy belongs on the interface tabs.
Verification¶
The rule list alone does not prove what is happening. Two places in the GUI show actual behaviour:
- Status → System Logs → Firewall shows passed and blocked packets. Each entry links back to the rule that matched, which immediately identifies a shadowing problem — the matched rule will not be the one expected.
- Diagnostics → States lists live connections, confirming that a pass rule genuinely created state rather than the traffic being permitted by some earlier, broader rule.
The ruleset actually loaded — automatic rules included — can be read directly. From the pfSense shell (Diagnostics → Command Prompt, or an SSH session to the firewall — see Netgate 6100 MAX Administration):
# Loaded ruleset in evaluation order, with per-rule match counters
pfctl -vvsr
# The ruleset pfSense generates from the configuration before loading it
cat /tmp/rules.debug
Rule changes take effect on Apply Changes, but connections already in the state table continue under the old policy until they expire. After tightening a rule, clear the relevant states to test properly — see Stateful Firewalls & Connection Tracking. To confirm what is on the wire rather than what the firewall reports, see Packet Capture as a Decision Procedure.
GUI labels: menu paths and field labels shift between pfSense releases, and the shipping product can be ahead of the published documentation. Where a label here does not match the screen, the location described should still be correct — confirm the exact wording in the interface.
Related¶
- Stateful Firewalls & Connection Tracking
- Management Plane Isolation
- VLAN Basics in pfSense
- Routing and VLANs in pfSense
- TCP vs UDP & Common Ports
- NAT & Private IP Ranges — port forwards and their associated pass rules
- Packet Capture as a Decision Procedure
- Security Hardening — the switch-side ACL equivalent