I'm writing a plugin that builds policy rules through /api/policy, and I ran into two things in repeater/policy_engine.py.
1. A nested group matches every packet
_rule_matches only looks at the top-level all or any list and hands each entry to _condition_matches, which expects a plain {field, op, value}. If an entry is itself a group (for example {"any": [...]}), it has no field, so field is None, op defaults to equals, value is None, and None == None is true. The nested group therefore matches every packet.
I expected this to drop only packets with hop_count 1. Using the engine directly with a mock packet, _rule_matches returns True whatever the packet is. For a drop rule that means it silently drops everything. The only trace is a debug-level line, so nothing shows up in a normal log.
Also, if a rule has both all and any at the top level, any is ignored without a message, and an empty all list matches every packet (all([]) is true).
Suggested minimum: either support nested groups, or reject or warn about an entry that has no field (and a group that is not at the top level) instead of treating it as a match. A rule that fails to validate would be far safer than one that matches everything.
2. No "not in list" operator
The comparison operators are equals, not_equals, greater_than, greater_or_equal, less_than, less_or_equal, contains, in, intersects, starts_with and ends_with. There is in, but no not_in, no not_contains and no not_intersects.
That makes it awkward to write "match packets whose value is not one of these" without one rule per value, and each rule costs CPU time, which matters on a Pi 3. With nested groups unavailable, not_in (and not_contains) can't be built from the existing operators either.
Would a not_in operator (and not_contains / not_intersects) be welcome? Happy to send a patch if you point me at where you'd like it.
Version: current main at the time of writing. I haven't tested older releases.
I'm writing a plugin that builds policy rules through `/api/policy`, and I ran into two things in `repeater/policy_engine.py`.
**1. A nested group matches every packet**
`_rule_matches` only looks at the top-level `all` or `any` list and hands each entry to `_condition_matches`, which expects a plain `{field, op, value}`. If an entry is itself a group (for example `{"any": [...]}`), it has no `field`, so `field` is `None`, `op` defaults to `equals`, `value` is `None`, and `None == None` is true. The nested group therefore matches every packet.
Minimal rule, built through the API:
```yaml
- id: 2
name: only nested
enabled: true
if:
all:
- any:
- {field: hop_count, op: equals, value: 1}
then: {action: drop}
```
I expected this to drop only packets with `hop_count` 1. Using the engine directly with a mock packet, `_rule_matches` returns `True` whatever the packet is. For a `drop` rule that means it silently drops everything. The only trace is a debug-level line, so nothing shows up in a normal log.
Also, if a rule has both `all` and `any` at the top level, `any` is ignored without a message, and an empty `all` list matches every packet (`all([])` is true).
Suggested minimum: either support nested groups, or reject or warn about an entry that has no `field` (and a group that is not at the top level) instead of treating it as a match. A rule that fails to validate would be far safer than one that matches everything.
**2. No "not in list" operator**
The comparison operators are `equals`, `not_equals`, `greater_than`, `greater_or_equal`, `less_than`, `less_or_equal`, `contains`, `in`, `intersects`, `starts_with` and `ends_with`. There is `in`, but no `not_in`, no `not_contains` and no `not_intersects`.
That makes it awkward to write "match packets whose value is not one of these" without one rule per value, and each rule costs CPU time, which matters on a Pi 3. With nested groups unavailable, `not_in` (and `not_contains`) can't be built from the existing operators either.
Would a `not_in` operator (and `not_contains` / `not_intersects`) be welcome? Happy to send a patch if you point me at where you'd like it.
Version: current `main` at the time of writing. I haven't tested older releases.
<!-- github-sync-id:5947169577 -->
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
I'm writing a plugin that builds policy rules through
/api/policy, and I ran into two things inrepeater/policy_engine.py.1. A nested group matches every packet
_rule_matchesonly looks at the top-levelalloranylist and hands each entry to_condition_matches, which expects a plain{field, op, value}. If an entry is itself a group (for example{"any": [...]}), it has nofield, sofieldisNone,opdefaults toequals,valueisNone, andNone == Noneis true. The nested group therefore matches every packet.Minimal rule, built through the API:
I expected this to drop only packets with
hop_count1. Using the engine directly with a mock packet,_rule_matchesreturnsTruewhatever the packet is. For adroprule that means it silently drops everything. The only trace is a debug-level line, so nothing shows up in a normal log.Also, if a rule has both
allandanyat the top level,anyis ignored without a message, and an emptyalllist matches every packet (all([])is true).Suggested minimum: either support nested groups, or reject or warn about an entry that has no
field(and a group that is not at the top level) instead of treating it as a match. A rule that fails to validate would be far safer than one that matches everything.2. No "not in list" operator
The comparison operators are
equals,not_equals,greater_than,greater_or_equal,less_than,less_or_equal,contains,in,intersects,starts_withandends_with. There isin, but nonot_in, nonot_containsand nonot_intersects.That makes it awkward to write "match packets whose value is not one of these" without one rule per value, and each rule costs CPU time, which matters on a Pi 3. With nested groups unavailable,
not_in(andnot_contains) can't be built from the existing operators either.Would a
not_inoperator (andnot_contains/not_intersects) be welcome? Happy to send a patch if you point me at where you'd like it.Version: current
mainat the time of writing. I haven't tested older releases.