Rules order randomly changes
-
I don’t know exactly what triggers this bug, but the fact remains that if I start creating or deleting some firewall rules—possibly NAT, possibly regular ones—or changing their order by dragging them with the mouse, SOMETIMES, when applying the changes, the rule order gets shuffled randomly, which, of course, causes a lot of issues.
I usually notice it in the Ethernet rules tab because some change in rule order there results in a complete loss of internet connectivity. However, I’ve also observed that rules can randomly shift on other tabs as well.
As far as I remember, this started happening around pfSense 23.xx versions, but I’m not entirely sure… I’ve only been using Ethernet rules relatively recently, and I only noticed the issue because of them.
HOW SHOULD IT BE:
BROKEN:
Has anyone else encountered this?
-
Hmm...
It looks like everything revolves around two functions:
filter_rules_sort() and filter_rules_compare(), along with pfBlockerNG.It seems that if the 'seq' number—which appears to be a temporary sequential rule number—matches one of pfBlockerNG's numbers, issues arise. I discovered this after modifying the code to save those numbers into config.xml instead of just handling them in RAM.
After trial and error, I ended up with...
function filter_rules_compare($a, $b) { // 1️⃣ If both rules have `seq`, use it as the primary sorting criterion if (isset($a['seq']) && isset($b['seq'])) { return $a['seq'] - $b['seq']; } // 2️⃣ Ensure Floating and Ethernet rules are placed above standard rules $a_is_special = isset($a['floating']) || isset($a['ethernet']); $b_is_special = isset($b['floating']) || isset($b['ethernet']); if ($a_is_special && !$b_is_special) { return -1; // Floating/Ethernet rule comes first } if ($b_is_special && !$a_is_special) { return 1; // Standard rule comes after special rules } // 3️⃣ If both rules belong to the same interface, sort by `seq` if available if ($a['interface'] == $b['interface']) { if (isset($a['seq']) && isset($b['seq'])) { return $a['seq'] - $b['seq']; } } // 4️⃣ As a last resort, compare interface names return compare_interface_friendly_names($a['interface'], $b['interface']); }
and
function filter_rules_sort() { $rules = config_get_path('filter/rule', []); /* Step 1: Collect all existing `seq` values */ $existing_seq = []; foreach ($rules as $rule) { if (isset($rule['seq']) && is_numeric($rule['seq'])) { $existing_seq[] = $rule['seq']; } } /* Step 2: Find the next available unique `seq` */ $max_seq = empty($existing_seq) ? 0 : max($existing_seq); $used_seq = array_flip($existing_seq); /* Step 3: Assign unique `seq` only to new rules */ foreach ($rules as &$rule) { if (!isset($rule['seq']) || !is_numeric($rule['seq']) || isset($used_seq[$rule['seq']])) { do { $max_seq++; } while (isset($used_seq[$max_seq])); // Ensure `seq` is unique $rule['seq'] = $max_seq; $used_seq[$max_seq] = true; } } /* Step 4: Sort rules strictly by `seq` */ usort($rules, "filter_rules_compare"); /* ✅ Save `seq` in `config.xml` */ config_set_path('filter/rule', $rules); write_config("Updated firewall rule order"); }
I'm not sure if that's everything or if there's still something left to do—I'm still testing it as it is for now.
Of course, I'm not a real programmer—it's just ChatGPT and my pathetic attempts.
-
@w0w And this was on 25.03?
Recently I found one of our routers had several rules moved from near the top to the bottom of the list…still in order but last. I was upgrading from 24.03 to 24.11 and I’m not sure if it happened before or after.
Two others the separator bar had moved slightly but IIRC that was a bug a while back for that if adding or maybe copying rules, so I didn’t think much of that since the order was the same.
-
-
Not the same but perhaps related, rule numbers are not a fixed thing
And separator lines do not stay on their place. That is not new I did discover that I think two years ago.
One of the reasons I was looking into that is that I am exporting the rule list in favor of a GrayLog lookup table. I Graylog I like to see the rule description
I am still exporting that rule list now and than, but the rule numbers are unfortunately not completely stable.
One of the ways I did test this, in favor of the list but also in favor of rule groups, is that I did add a recognizable dummy rule at the to of each interface and interface group and on at the bottum. Those dummy rules (doing nothing) had an interface ID and a begin / start identifier hidden in the rule port number like "port is <90001> at the beginning of interface 9 and <90002> at the end of the rules related to inteface 9.
Perhaps this helps to track problems
-
@louis2
What packages you have installed? PfBlockerNG?