Skip to content

Commit c035c4d

Browse files
authored
Merge pull request #4698 from l0crian1/fw-disable-conntrack
firewall: T7475: Add an option to disable conntrack for individual firewall chaisn
2 parents cd04de9 + 61e234a commit c035c4d

File tree

10 files changed

+134
-0
lines changed

10 files changed

+134
-0
lines changed

data/templates/firewall/nftables.j2

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,25 @@ table ip vyos_filter {
140140
{% endfor %}
141141
{% endif %}
142142

143+
{% if ipv4.forward.filter.disable_conntrack is vyos_defined or ipv4.input.filter.disable_conntrack is vyos_defined %}
144+
chain VYOS_DISABLE_CONNTRACK_INP_FWD {
145+
type filter hook prerouting priority -320; policy accept;
146+
{% if ipv4.forward.filter.disable_conntrack is vyos_defined %}
147+
fib daddr . iif type unicast notrack counter comment "DISABLE-CT-FWD"
148+
{% endif %}
149+
{% if ipv4.input.filter.disable_conntrack is vyos_defined %}
150+
fib daddr . iif type local notrack counter comment "DISABLE-CT-INP"
151+
{% endif %}
152+
}
153+
{% endif %}
154+
155+
{% if ipv4.output.filter.disable_conntrack is vyos_defined %}
156+
chain VYOS_DISABLE_CONNTRACK_OUT {
157+
type filter hook output priority -320; policy accept;
158+
notrack counter comment "DISABLE-CT-OUT"
159+
}
160+
{% endif %}
161+
143162
{% for set_name in ns.sets %}
144163
set RECENT_{{ set_name }} {
145164
type ipv4_addr
@@ -308,6 +327,25 @@ table ip6 vyos_filter {
308327
{% endfor %}
309328
{% endif %}
310329

330+
{% if ipv6.forward.filter.disable_conntrack is vyos_defined or ipv6.input.filter.disable_conntrack is vyos_defined %}
331+
chain VYOS_DISABLE_CONNTRACK_INP_FWD_V6 {
332+
type filter hook prerouting priority -320; policy accept;
333+
{% if ipv6.forward.filter.disable_conntrack is vyos_defined %}
334+
fib daddr . iif type unicast notrack counter comment "DISABLE-CT-FWD-V6"
335+
{% endif %}
336+
{% if ipv6.input.filter.disable_conntrack is vyos_defined %}
337+
fib daddr . iif type local notrack counter comment "DISABLE-CT-INP-V6"
338+
{% endif %}
339+
}
340+
{% endif %}
341+
342+
{% if ipv6.output.filter.disable_conntrack is vyos_defined %}
343+
chain VYOS_DISABLE_CONNTRACK_OUT_V6 {
344+
type filter hook output priority -320; policy accept;
345+
notrack counter comment "DISABLE-CT-OUT-V6"
346+
}
347+
{% endif %}
348+
311349
{% for set_name in ns.sets %}
312350
set RECENT6_{{ set_name }} {
313351
type ipv6_addr
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<!-- include start from firewall/disable-conntrack.xml.i -->
2+
<leafNode name="disable-conntrack">
3+
<properties>
4+
<help>Disable conntrack within this chain</help>
5+
<valueless/>
6+
</properties>
7+
</leafNode>
8+
<!-- include end -->

interface-definitions/include/firewall/ipv4-hook-forward.xml.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<help>IPv4 firewall forward filter</help>
1010
</properties>
1111
<children>
12+
#include <include/firewall/disable-conntrack.xml.i>
1213
#include <include/firewall/default-action-base-chains.xml.i>
1314
#include <include/firewall/default-log.xml.i>
1415
#include <include/generic-description.xml.i>

interface-definitions/include/firewall/ipv4-hook-input.xml.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<help>IPv4 firewall input filter</help>
1010
</properties>
1111
<children>
12+
#include <include/firewall/disable-conntrack.xml.i>
1213
#include <include/firewall/default-action-base-chains.xml.i>
1314
#include <include/firewall/default-log.xml.i>
1415
#include <include/generic-description.xml.i>

interface-definitions/include/firewall/ipv4-hook-output.xml.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<help>IPv4 firewall output filter</help>
1010
</properties>
1111
<children>
12+
#include <include/firewall/disable-conntrack.xml.i>
1213
#include <include/firewall/default-action-base-chains.xml.i>
1314
#include <include/firewall/default-log.xml.i>
1415
#include <include/generic-description.xml.i>

interface-definitions/include/firewall/ipv6-hook-forward.xml.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<help>IPv6 firewall forward filter</help>
1010
</properties>
1111
<children>
12+
#include <include/firewall/disable-conntrack.xml.i>
1213
#include <include/firewall/default-action-base-chains.xml.i>
1314
#include <include/firewall/default-log.xml.i>
1415
#include <include/generic-description.xml.i>

interface-definitions/include/firewall/ipv6-hook-input.xml.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<help>IPv6 firewall input filter</help>
1010
</properties>
1111
<children>
12+
#include <include/firewall/disable-conntrack.xml.i>
1213
#include <include/firewall/default-action-base-chains.xml.i>
1314
#include <include/firewall/default-log.xml.i>
1415
#include <include/generic-description.xml.i>

interface-definitions/include/firewall/ipv6-hook-output.xml.i

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
<help>IPv6 firewall output filter</help>
1010
</properties>
1111
<children>
12+
#include <include/firewall/disable-conntrack.xml.i>
1213
#include <include/firewall/default-action-base-chains.xml.i>
1314
#include <include/firewall/default-log.xml.i>
1415
#include <include/generic-description.xml.i>

smoketest/scripts/cli/test_firewall.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1404,5 +1404,55 @@ def test_remote_group(self):
14041404
self.verify_nftables(nftables_v6_search, 'ip6 vyos_filter')
14051405

14061406

1407+
def test_disable_conntrack_per_chain(self):
1408+
# If conntrack is disabled in either the input or output chain,
1409+
# state cannot be matched in either the input or outchain
1410+
self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'disable-conntrack'])
1411+
self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '1', 'action', 'accept'])
1412+
self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'rule', '1', 'state', 'established'])
1413+
with self.assertRaises(ConfigSessionError):
1414+
self.cli_commit()
1415+
1416+
self.cli_discard()
1417+
1418+
# If conntrack is disabled in the forward chain,
1419+
# state cannot be matched in the forward chain
1420+
self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'disable-conntrack'])
1421+
self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'action', 'accept'])
1422+
self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'rule', '1', 'state', 'established'])
1423+
with self.assertRaises(ConfigSessionError):
1424+
self.cli_commit()
1425+
1426+
self.cli_discard()
1427+
1428+
# Disable conntrack in all chains for both ipv4 and ipv6
1429+
self.cli_set(['firewall', 'ipv4', 'output', 'filter', 'disable-conntrack'])
1430+
self.cli_set(['firewall', 'ipv4', 'input', 'filter', 'disable-conntrack'])
1431+
self.cli_set(['firewall', 'ipv4', 'forward', 'filter', 'disable-conntrack'])
1432+
self.cli_set(['firewall', 'ipv6', 'output', 'filter', 'disable-conntrack'])
1433+
self.cli_set(['firewall', 'ipv6', 'input', 'filter', 'disable-conntrack'])
1434+
self.cli_set(['firewall', 'ipv6', 'forward', 'filter', 'disable-conntrack'])
1435+
1436+
self.cli_commit()
1437+
1438+
nftables_search = [
1439+
['VYOS_DISABLE_CONNTRACK_INP_FWD'],
1440+
['VYOS_DISABLE_CONNTRACK_OUT'],
1441+
['fib daddr . iif type unicast notrack counter'],
1442+
['fib daddr . iif type local notrack counter ']
1443+
]
1444+
1445+
self.verify_nftables(nftables_search, 'ip vyos_filter')
1446+
1447+
nftables_search = [
1448+
['VYOS_DISABLE_CONNTRACK_INP_FWD_V6'],
1449+
['VYOS_DISABLE_CONNTRACK_OUT_V6'],
1450+
['fib daddr . iif type unicast notrack counter'],
1451+
['fib daddr . iif type local notrack counter ']
1452+
]
1453+
1454+
self.verify_nftables(nftables_search, 'ip6 vyos_filter')
1455+
1456+
14071457
if __name__ == '__main__':
14081458
unittest.main(verbosity=2)

src/conf_mode/firewall.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
from vyos.firewall import fqdn_config_parse
3131
from vyos.firewall import geoip_update
3232
from vyos.template import render
33+
from vyos.utils.dict import dict_search
3334
from vyos.utils.dict import dict_search_args
3435
from vyos.utils.dict import dict_search_recursive
3536
from vyos.utils.file import write_file
@@ -267,6 +268,24 @@ def verify_rule(firewall, family, hook, priority, rule_id, rule_conf):
267268
if rule_conf.get('protocol', {}) != 'tcp':
268269
raise ConfigError('For action "synproxy" the protocol must be set to TCP')
269270

271+
if 'state' in rule_conf:
272+
disable_conntrack = dict_search(f'{family}.{hook}.{priority}.disable_conntrack', firewall)
273+
conntrack_disabled_list = []
274+
275+
# Check if conntrack is disabled in the input or output chain
276+
for nft_chain in ['input', 'output']:
277+
if dict_search(f'{family}.{nft_chain}.filter.disable_conntrack', firewall) == {}:
278+
conntrack_disabled_list.append(nft_chain)
279+
280+
# If conntrack is disabled in the input or output chain,
281+
# state cannot be matched in the input or output chain
282+
if hook in ['input', 'output'] and conntrack_disabled_list:
283+
raise ConfigError(f'state cannot be matched in {hook} when conntrack is disabled in input or output chains')
284+
# If conntrack is disabled in the forward chain,
285+
# state cannot be matched in the forward chain
286+
if hook == 'forward' and disable_conntrack == {}:
287+
raise ConfigError(f'state cannot be matched in {hook} when conntrack is disabled in {hook} chain')
288+
270289
if 'queue_options' in rule_conf:
271290
if 'queue' not in rule_conf['action']:
272291
raise ConfigError('queue-options defined, but action queue needed and it is not defined')
@@ -480,6 +499,19 @@ def verify(firewall):
480499
for ifname in interfaces:
481500
verify_hardware_offload(ifname)
482501

502+
if dict_search('global_options.state_policy', firewall) is not None:
503+
# Generate list of chains where conntrack is disabled
504+
conntrack_disabled_list = []
505+
for inet_family in ['ipv4', 'ipv6']:
506+
for nft_chain in ['input', 'forward', 'output']:
507+
if dict_search(f'{inet_family}.{nft_chain}.filter.disable_conntrack', firewall) == {}:
508+
conntrack_disabled_list.append(f'{inet_family}-{nft_chain}')
509+
510+
# If conntrack is disabled in any chain,
511+
# print a warning message
512+
if conntrack_disabled_list:
513+
Warning(f'global-state: conntrack is disabled in the following chains: {", ".join(conntrack_disabled_list)}')
514+
483515
if 'offload' in firewall.get('global_options', {}).get('state_policy', {}):
484516
offload_path = firewall['global_options']['state_policy']['offload']
485517
if 'offload_target' not in offload_path:

0 commit comments

Comments
 (0)