Skip to content

Fix rule ordering and protocol 'any' validation#252

Merged
opoplawski merged 1 commit intopfsensible:masterfrom
djlongy:fix/rule-ordering-and-protocol-any
Mar 30, 2026
Merged

Fix rule ordering and protocol 'any' validation#252
opoplawski merged 1 commit intopfsensible:masterfrom
djlongy:fix/rule-ordering-and-protocol-any

Conversation

@djlongy
Copy link
Copy Markdown

@djlongy djlongy commented Mar 30, 2026

Problem

Two issues with pfsense_rule:

  1. Protocol validation rejects any with ports. Setting protocol: any with destination_port fails with "you can't use ports on protocols other than tcp, udp or tcp/udp", even though pfSense itself accepts this combination in the UI (Protocol dropdown includes "Any" alongside TCP, UDP, etc.).

  2. New pass rules append below existing block rules. When creating a new pass rule without explicit after or before, _get_expected_rule_xml_index() returns _get_last_rule_xml_index() + 1, which appends the rule to the end of the interface's rule list. If a block/reject rule already exists, the new pass rule ends up below it and is never evaluated by pf.

Fix

Protocol validation (_params_to_obj, line 121): Added 'any' to the allowed protocol list. Other non-port protocols (icmp, esp, gre, etc.) are still correctly rejected.

Rule ordering (_get_expected_rule_xml_index): When no after/before is specified and the rule doesn't already exist, pass/match rules now check for the first block/reject rule on the same interface via a new _get_first_deny_rule_xml_index() helper. If one exists, the pass rule is inserted before it. If no block/reject rules exist, it appends to the end as before. Block/reject rules still append to the end. Existing rules are never moved or deleted.

The after and before parameters continue to work exactly as before for users who want explicit positioning.

Changes

  • plugins/module_utils/rule.py — 20 insertions, 2 deletions
  • changelogs/fragments/ — 2 new fragments
  • tests/unit/plugins/modules/fixtures/pfsense_rule_config.xml — added a block_all_lan rule to the LAN interface for ordering tests
  • tests/unit/plugins/modules/test_pfsense_rule_create.py — 4 new tests, 1 updated error message

Tests

All 678 existing unit tests pass. New tests:

  • test_rule_create_protocol_any_with_dst_port — protocol any with port is accepted
  • test_rule_create_protocol_icmp_with_dst_port — protocol icmp with port is still rejected
  • test_rule_create_pass_before_block — new pass rule is positioned before existing block rule
  • test_rule_create_block_appends_to_end — new block rule appends after existing block rule

Tested against pfSense 2.7.2 with 239 rules across 20 VLAN interfaces.

1. Allow protocol 'any' with destination/source ports in validation.
   pfSense accepts this combination in the UI but the module rejected
   it. Added 'any' to the allowed protocol list in _params_to_obj().

2. New pass/match rules without explicit 'after' or 'before' are now
   inserted before the first block/reject rule on the same interface.
   Previously they appended to the end, placing allow rules below deny
   rules and making them ineffective. Deny rules still append to the
   end. Existing rules are never moved or deleted.

Includes unit tests for both fixes and a block rule in the LAN test
fixture for ordering validation.
@djlongy djlongy force-pushed the fix/rule-ordering-and-protocol-any branch from 64a2861 to f364d52 Compare March 30, 2026 21:32
@opoplawski opoplawski merged commit de4301a into pfsensible:master Mar 30, 2026
4 checks passed
@opoplawski
Copy link
Copy Markdown
Contributor

Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants