summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorChristian Breunig <christian@breunig.cc>2024-01-22 07:56:32 +0100
committerGitHub <noreply@github.com>2024-01-22 07:56:32 +0100
commit39d0464616be1fc12be201223a84937b43c19382 (patch)
tree1143f24e0fbbb8026da16dc4092ff36d27435bf4 /src
parent4412d1ae8499de3a49d99c37f66b93c6b4693295 (diff)
parent2ec023752bdd400835eb69a8f1f9d2873cef61fa (diff)
downloadvyos-1x-39d0464616be1fc12be201223a84937b43c19382.tar.gz
vyos-1x-39d0464616be1fc12be201223a84937b43c19382.zip
Merge pull request #2856 from c-po/firewall-backports
firewall: T5729: T5681: T5217: backport subsystem from current branch
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/firewall.py31
-rwxr-xr-xsrc/conf_mode/load-balancing_wan.py5
-rwxr-xr-xsrc/conf_mode/nat.py92
-rwxr-xr-xsrc/conf_mode/nat66.py45
-rwxr-xr-xsrc/conf_mode/system_flow-accounting.py2
-rwxr-xr-xsrc/op_mode/firewall.py23
6 files changed, 58 insertions, 140 deletions
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index ee19555c4..acb7dfa41 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -39,6 +39,7 @@ from vyos.utils.process import process_named_running
from vyos.utils.process import rc_cmd
from vyos import ConfigError
from vyos import airbag
+
airbag.enable()
nftables_conf = '/run/nftables.conf'
@@ -98,7 +99,7 @@ def geoip_updated(conf, firewall):
elif (path[0] == 'ipv6'):
set_name = f'GEOIP_CC6_{path[1]}_{path[2]}_{path[4]}'
out['ipv6_name'].append(set_name)
-
+
updated = True
if 'delete' in node_diff:
@@ -138,6 +139,8 @@ def get_config(config=None):
fqdn_config_parse(firewall)
+ set_dependents('conntrack', conf)
+
return firewall
def verify_rule(firewall, rule_conf, ipv6):
@@ -167,6 +170,16 @@ def verify_rule(firewall, rule_conf, ipv6):
if not dict_search_args(firewall, 'flowtable', offload_target):
raise ConfigError(f'Invalid offload-target. Flowtable "{offload_target}" does not exist on the system')
+ if rule_conf['action'] != 'synproxy' and 'synproxy' in rule_conf:
+ raise ConfigError('"synproxy" option allowed only for action synproxy')
+ if rule_conf['action'] == 'synproxy':
+ if 'state' in rule_conf:
+ raise ConfigError('For action "synproxy" state cannot be defined')
+ if not rule_conf.get('synproxy', {}).get('tcp'):
+ raise ConfigError('synproxy TCP MSS is not defined')
+ if rule_conf.get('protocol', {}) != 'tcp':
+ raise ConfigError('For action "synproxy" the protocol must be set to TCP')
+
if 'queue_options' in rule_conf:
if 'queue' not in rule_conf['action']:
raise ConfigError('queue-options defined, but action queue needed and it is not defined')
@@ -434,17 +447,6 @@ def generate(firewall):
if local_zone in zone_conf['from']:
local_zone_conf['from_local'][zone] = zone_conf['from'][local_zone]
- # Determine if conntrack is needed
- firewall['ipv4_conntrack_action'] = 'return'
- firewall['ipv6_conntrack_action'] = 'return'
-
- for rules, path in dict_search_recursive(firewall, 'rule'):
- if any(('state' in rule_conf or 'connection_status' in rule_conf) for rule_conf in rules.values()):
- if path[0] == 'ipv4':
- firewall['ipv4_conntrack_action'] = 'accept'
- elif path[0] == 'ipv6':
- firewall['ipv6_conntrack_action'] = 'accept'
-
render(nftables_conf, 'firewall/nftables.j2', firewall)
return None
@@ -474,8 +476,7 @@ def apply(firewall):
apply_sysfs(firewall)
- if firewall['group_resync']:
- call_dependents()
+ call_dependents()
# T970 Enable a resolver (systemd daemon) that checks
# domain-group/fqdn addresses and update entries for domains by timeout
diff --git a/src/conf_mode/load-balancing_wan.py b/src/conf_mode/load-balancing_wan.py
index ad9c80d72..5da0b906b 100755
--- a/src/conf_mode/load-balancing_wan.py
+++ b/src/conf_mode/load-balancing_wan.py
@@ -21,6 +21,7 @@ from shutil import rmtree
from vyos.base import Warning
from vyos.config import Config
+from vyos.configdep import set_dependents, call_dependents
from vyos.utils.process import cmd
from vyos.template import render
from vyos import ConfigError
@@ -49,6 +50,8 @@ def get_config(config=None):
if lb.from_defaults(['rule', rule, 'limit']):
del lb['rule'][rule]['limit']
+ set_dependents('conntrack', conf)
+
return lb
@@ -132,6 +135,8 @@ def apply(lb):
cmd('sudo sysctl -w net.netfilter.nf_conntrack_acct=1')
cmd(f'systemctl restart {systemd_service}')
+ call_dependents()
+
return None
diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py
index ffd4a33e7..bd9b5162c 100755
--- a/src/conf_mode/nat.py
+++ b/src/conf_mode/nat.py
@@ -18,13 +18,12 @@ import jmespath
import json
import os
-from distutils.version import LooseVersion
-from platform import release as kernel_version
from sys import exit
from netifaces import interfaces
from vyos.base import Warning
from vyos.config import Config
+from vyos.configdep import set_dependents, call_dependents
from vyos.template import render
from vyos.template import is_ip_network
from vyos.utils.kernel import check_kmod
@@ -38,10 +37,7 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-if LooseVersion(kernel_version()) > LooseVersion('5.1'):
- k_mod = ['nft_nat', 'nft_chain_nat']
-else:
- k_mod = ['nft_nat', 'nft_chain_nat_ipv4']
+k_mod = ['nft_nat', 'nft_chain_nat']
nftables_nat_config = '/run/nftables_nat.conf'
nftables_static_nat_conf = '/run/nftables_static-nat-rules.nft'
@@ -53,18 +49,27 @@ valid_groups = [
'port_group'
]
-def get_handler(json, chain, target):
- """ Get nftable rule handler number of given chain/target combination.
- Handler is required when adding NAT/Conntrack helper targets """
- for x in json:
- if x['chain'] != chain:
- continue
- if x['target'] != target:
- continue
- return x['handle']
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
- return None
+ base = ['nat']
+ nat = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
+ set_dependents('conntrack', conf)
+
+ if not conf.exists(base):
+ nat['deleted'] = ''
+ return nat
+
+ nat['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), get_first_key=True,
+ no_tag_node_value_mangle=True)
+
+ return nat
def verify_rule(config, err_msg, groups_dict):
""" Common verify steps used for both source and destination NAT """
@@ -105,7 +110,7 @@ def verify_rule(config, err_msg, groups_dict):
group_obj = dict_search_args(groups_dict, group, group_name)
if group_obj is None:
- raise ConfigError(f'Invalid {error_group} "{group_name}" on firewall rule')
+ raise ConfigError(f'Invalid {error_group} "{group_name}" on nat rule')
if not group_obj:
Warning(f'{error_group} "{group_name}" has no members!')
@@ -129,62 +134,11 @@ def verify_rule(config, err_msg, groups_dict):
if count != 100:
Warning(f'Sum of weight for nat load balance rule is not 100. You may get unexpected behaviour')
-def get_config(config=None):
- if config:
- conf = config
- else:
- conf = Config()
-
- base = ['nat']
- nat = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True,
- with_recursive_defaults=True)
-
- # read in current nftable (once) for further processing
- tmp = cmd('nft -j list table raw')
- nftable_json = json.loads(tmp)
-
- # condense the full JSON table into a list with only relevand informations
- pattern = 'nftables[?rule].rule[?expr[].jump].{chain: chain, handle: handle, target: expr[].jump.target | [0]}'
- condensed_json = jmespath.search(pattern, nftable_json)
-
- if not conf.exists(base):
- if get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_HELPER'):
- nat['helper_functions'] = 'remove'
-
- # Retrieve current table handler positions
- nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_HELPER')
- nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK')
- nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_HELPER')
- nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'NAT_CONNTRACK')
- nat['deleted'] = ''
- return nat
-
- nat['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), get_first_key=True,
- no_tag_node_value_mangle=True)
-
- # check if NAT connection tracking helpers need to be set up - this has to
- # be done only once
- if not get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK'):
- nat['helper_functions'] = 'add'
-
- # Retrieve current table handler positions
- nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_IGNORE')
- nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_PREROUTING_HOOK')
- nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_IGNORE')
- nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_OUTPUT_HOOK')
-
- return nat
-
def verify(nat):
if not nat or 'deleted' in nat:
# no need to verify the CLI as NAT is going to be deactivated
return None
- if 'helper_functions' in nat:
- if not (nat['pre_ct_ignore'] or nat['pre_ct_conntrack'] or nat['out_ct_ignore'] or nat['out_ct_conntrack']):
- raise Exception('could not determine nftable ruleset handlers')
-
if dict_search('source.rule', nat):
for rule, config in dict_search('source.rule', nat).items():
err_msg = f'Source NAT configuration error in rule {rule}:'
@@ -265,6 +219,8 @@ def apply(nat):
os.unlink(nftables_nat_config)
os.unlink(nftables_static_nat_conf)
+ call_dependents()
+
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py
index ed716b2a2..4c1ead258 100755
--- a/src/conf_mode/nat66.py
+++ b/src/conf_mode/nat66.py
@@ -23,6 +23,7 @@ from netifaces import interfaces
from vyos.base import Warning
from vyos.config import Config
+from vyos.configdep import set_dependents, call_dependents
from vyos.template import render
from vyos.utils.process import cmd
from vyos.utils.kernel import check_kmod
@@ -36,18 +37,6 @@ k_mod = ['nft_nat', 'nft_chain_nat']
nftables_nat66_config = '/run/nftables_nat66.nft'
-def get_handler(json, chain, target):
- """ Get nftable rule handler number of given chain/target combination.
- Handler is required when adding NAT66/Conntrack helper targets """
- for x in json:
- if x['chain'] != chain:
- continue
- if x['target'] != target:
- continue
- return x['handle']
-
- return None
-
def get_config(config=None):
if config:
conf = config
@@ -57,35 +46,10 @@ def get_config(config=None):
base = ['nat66']
nat = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # read in current nftable (once) for further processing
- tmp = cmd('nft -j list table ip6 raw')
- nftable_json = json.loads(tmp)
-
- # condense the full JSON table into a list with only relevand informations
- pattern = 'nftables[?rule].rule[?expr[].jump].{chain: chain, handle: handle, target: expr[].jump.target | [0]}'
- condensed_json = jmespath.search(pattern, nftable_json)
+ set_dependents('conntrack', conf)
if not conf.exists(base):
- nat['helper_functions'] = 'remove'
- nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_HELPER')
- nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK')
- nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_HELPER')
- nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'NAT_CONNTRACK')
nat['deleted'] = ''
- return nat
-
- # check if NAT66 connection tracking helpers need to be set up - this has to
- # be done only once
- if not get_handler(condensed_json, 'PREROUTING', 'NAT_CONNTRACK'):
- nat['helper_functions'] = 'add'
-
- # Retrieve current table handler positions
- nat['pre_ct_ignore'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_IGNORE')
- nat['pre_ct_conntrack'] = get_handler(condensed_json, 'PREROUTING', 'VYOS_CT_PREROUTING_HOOK')
- nat['out_ct_ignore'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_IGNORE')
- nat['out_ct_conntrack'] = get_handler(condensed_json, 'OUTPUT', 'VYOS_CT_OUTPUT_HOOK')
- else:
- nat['helper_functions'] = 'has'
return nat
@@ -94,10 +58,6 @@ def verify(nat):
# no need to verify the CLI as NAT66 is going to be deactivated
return None
- if 'helper_functions' in nat and nat['helper_functions'] != 'has':
- if not (nat['pre_ct_conntrack'] or nat['out_ct_conntrack']):
- raise Exception('could not determine nftable ruleset handlers')
-
if dict_search('source.rule', nat):
for rule, config in dict_search('source.rule', nat).items():
err_msg = f'Source NAT66 configuration error in rule {rule}:'
@@ -147,6 +107,7 @@ def apply(nat):
return None
cmd(f'nft -f {nftables_nat66_config}')
+ call_dependents()
return None
diff --git a/src/conf_mode/system_flow-accounting.py b/src/conf_mode/system_flow-accounting.py
index f29fc94fb..206f513c8 100755
--- a/src/conf_mode/system_flow-accounting.py
+++ b/src/conf_mode/system_flow-accounting.py
@@ -38,7 +38,7 @@ uacctd_conf_path = '/run/pmacct/uacctd.conf'
systemd_service = 'uacctd.service'
systemd_override = f'/run/systemd/system/{systemd_service}.d/override.conf'
nftables_nflog_table = 'raw'
-nftables_nflog_chain = 'VYOS_CT_PREROUTING_HOOK'
+nftables_nflog_chain = 'VYOS_PREROUTING_HOOK'
egress_nftables_nflog_table = 'inet mangle'
egress_nftables_nflog_chain = 'FORWARD'
diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py
index d426b62e5..36bb013fe 100755
--- a/src/op_mode/firewall.py
+++ b/src/op_mode/firewall.py
@@ -113,19 +113,14 @@ def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=N
if hook in ['input', 'forward', 'output']:
def_action = firewall_conf['default_action'] if 'default_action' in firewall_conf else 'accept'
- row = ['default', def_action, 'all']
- rule_details = details['default-action']
- row.append(rule_details.get('packets', 0))
- row.append(rule_details.get('bytes', 0))
- rows.append(row)
+ else:
+ def_action = firewall_conf['default_action'] if 'default_action' in firewall_conf else 'drop'
+ row = ['default', def_action, 'all']
+ rule_details = details['default-action']
+ row.append(rule_details.get('packets', 0))
+ row.append(rule_details.get('bytes', 0))
- elif 'default_action' in firewall_conf and not single_rule_id:
- row = ['default', firewall_conf['default_action'], 'all']
- if 'default-action' in details:
- rule_details = details['default-action']
- row.append(rule_details.get('packets', 0))
- row.append(rule_details.get('bytes', 0))
- rows.append(row)
+ rows.append(row)
if rows:
header = ['Rule', 'Action', 'Protocol', 'Packets', 'Bytes', 'Conditions']
@@ -314,7 +309,7 @@ def show_firewall_group(name=None):
family = ['ipv6']
group_type = 'network_group'
else:
- family = ['ipv4', 'ipv6']
+ family = ['ipv4', 'ipv6', 'bridge']
for item in family:
# Look references in firewall
@@ -540,4 +535,4 @@ if __name__ == '__main__':
elif args.action == 'show_statistics':
show_statistics()
elif args.action == 'show_summary':
- show_summary() \ No newline at end of file
+ show_summary()