-
Notifications
You must be signed in to change notification settings - Fork 422
firewall: T8446: Prevent chain with offload rule on local zone #5100
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: current
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -249,6 +249,8 @@ def verify_rule(firewall, family, hook, priority, rule_id, rule_conf): | |||||||||||||||||||||
|
|
||||||||||||||||||||||
| if not dict_search_args(firewall, 'flowtable', offload_target): | ||||||||||||||||||||||
| raise ConfigError(f'Invalid offload-target. Flowtable "{offload_target}" does not exist on the system') | ||||||||||||||||||||||
| elif 'offload_target' in rule_conf: | ||||||||||||||||||||||
| Warning('offload-target is specified but action is not set to "offload"') | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if rule_conf['action'] != 'synproxy' and 'synproxy' in rule_conf: | ||||||||||||||||||||||
| raise ConfigError('"synproxy" option allowed only for action synproxy') | ||||||||||||||||||||||
|
|
@@ -532,6 +534,9 @@ def verify(firewall): | |||||||||||||||||||||
| if 'url' not in group: | ||||||||||||||||||||||
| raise ConfigError(f'remote-group {group_name} must have a url configured') | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| offload_chains_v4 = set() | ||||||||||||||||||||||
| offload_chains_v6 = set() | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| for family in ['ipv4', 'ipv6', 'bridge']: | ||||||||||||||||||||||
| if family in firewall: | ||||||||||||||||||||||
| for chain in ['name','forward','input','output', 'prerouting']: | ||||||||||||||||||||||
|
|
@@ -551,6 +556,12 @@ def verify(firewall): | |||||||||||||||||||||
| for rule_id, rule_conf in priority_conf['rule'].items(): | ||||||||||||||||||||||
| verify_rule(firewall, family, chain, priority, rule_id, rule_conf) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if chain == 'name' and rule_conf['action'] == 'offload': | ||||||||||||||||||||||
| if family == 'ipv4': | ||||||||||||||||||||||
| offload_chains_v4.add(priority) | ||||||||||||||||||||||
| elif family == 'ipv6': | ||||||||||||||||||||||
| offload_chains_v6.add(priority) | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| local_zone = False | ||||||||||||||||||||||
| zone_interfaces = [] | ||||||||||||||||||||||
| zone_vrf = [] | ||||||||||||||||||||||
|
|
@@ -624,6 +635,11 @@ def verify(firewall): | |||||||||||||||||||||
| if v6_name and not dict_search_args(firewall, 'ipv6', 'name', v6_name): | ||||||||||||||||||||||
| raise ConfigError(f'Firewall ipv6-name "{v6_name}" does not exist') | ||||||||||||||||||||||
|
|
||||||||||||||||||||||
| if 'local_zone' in zone_conf or 'local_zone' in firewall['zone'][from_zone]: | ||||||||||||||||||||||
| if (v4_name and v4_name in offload_chains_v4) or \ | ||||||||||||||||||||||
| (v6_name and v6_name in offload_chains_v6): | ||||||||||||||||||||||
| raise ConfigError('Cannot use a firewall chain with offloading on local zone') | ||||||||||||||||||||||
|
||||||||||||||||||||||
| raise ConfigError('Cannot use a firewall chain with offloading on local zone') | |
| offending_chains = [] | |
| if v4_name and v4_name in offload_chains_v4: | |
| offending_chains.append(f'ipv4 "{v4_name}"') | |
| if v6_name and v6_name in offload_chains_v6: | |
| offending_chains.append(f'ipv6 "{v6_name}"') | |
| chains_str = ', '.join(offending_chains) if offending_chains else 'with offloading enabled' | |
| raise ConfigError( | |
| f'Cannot use firewall chain(s) {chains_str} between zones "{from_zone}" and "{zone}" when either zone is configured as a local zone' | |
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Proposed improved error message reads reasonable
Copilot
AI
Apr 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default-firewall validation rejects any zone whose referenced chain contains an offload rule, even when no local-zone is configured. Per data/templates/firewall/nftables-zone.j2 (VZONE_ chain is only used from the forward hook when there is no local-zone), an offload rule in a NAME chain should still be valid for pure forwarding. Suggest conditioning this error on the presence of a local-zone (or only when the default-firewall can be applied to/from local-zone) to avoid unnecessarily breaking existing zone default-firewall + offload setups.
| if (v4_name and v4_name in offload_chains_v4) or \ | |
| (v6_name and v6_name in offload_chains_v6): | |
| if local_zone and ((v4_name and v4_name in offload_chains_v4) or | |
| (v6_name and v6_name in offload_chains_v6)): |
Copilot
AI
Apr 2, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There’s smoketest coverage for the local-zone from direction, but no test exercising the new default-firewall + offload validation (and the intended scoping to local-zone). Adding a smoketest that (a) fails when a local-zone exists and another zone’s default-firewall points to an offload chain, and (b) succeeds when no local-zone is configured, would prevent regressions.
| if (v4_name and v4_name in offload_chains_v4) or \ | |
| (v6_name and v6_name in offload_chains_v6): | |
| if local_zone and ((v4_name and v4_name in offload_chains_v4) or \ | |
| (v6_name and v6_name in offload_chains_v6)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This warning is emitted without any context about which rule triggered it (family/hook/chain name, priority, rule-id). In real configs with many rules, that makes it hard to find and fix the offending stanza. Consider including the rule location (e.g., firewall family/chain + rule-id) in the warning text.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we probably add this context aware warning? It might make sense indeed.