diff options
author | Christian Breunig <christian@breunig.cc> | 2023-12-30 23:25:20 +0100 |
---|---|---|
committer | Christian Breunig <christian@breunig.cc> | 2023-12-31 23:49:48 +0100 |
commit | 4ef110fd2c501b718344c72d495ad7e16d2bd465 (patch) | |
tree | e98bf08f93c029ec4431a3b6ca078e7562e0cc58 /src/conf_mode/conntrack.py | |
parent | 2286b8600da6c631b17e1d5b9b341843e50f9abf (diff) | |
download | vyos-1x-4ef110fd2c501b718344c72d495ad7e16d2bd465.tar.gz vyos-1x-4ef110fd2c501b718344c72d495ad7e16d2bd465.zip |
T5474: establish common file name pattern for XML conf mode commands
We will use _ as CLI level divider. The XML definition filename and also
the Python helper should match the CLI node.
Example:
set interfaces ethernet -> interfaces_ethernet.xml.in
set interfaces bond -> interfaces_bond.xml.in
set service dhcp-server -> service_dhcp-server-xml.in
Diffstat (limited to 'src/conf_mode/conntrack.py')
-rwxr-xr-x | src/conf_mode/conntrack.py | 243 |
1 files changed, 0 insertions, 243 deletions
diff --git a/src/conf_mode/conntrack.py b/src/conf_mode/conntrack.py deleted file mode 100755 index 7f6c71440..000000000 --- a/src/conf_mode/conntrack.py +++ /dev/null @@ -1,243 +0,0 @@ -#!/usr/bin/env python3 -# -# 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 -# published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program. If not, see <http://www.gnu.org/licenses/>. - -import os -import re - -from sys import exit - -from vyos.config import Config -from vyos.configdep import set_dependents, call_dependents -from vyos.utils.process import process_named_running -from vyos.utils.dict import dict_search -from vyos.utils.dict import dict_search_args -from vyos.utils.dict import dict_search_recursive -from vyos.utils.process import cmd -from vyos.utils.process import rc_cmd -from vyos.utils.process import run -from vyos.template import render -from vyos import ConfigError -from vyos import airbag -airbag.enable() - -conntrack_config = r'/etc/modprobe.d/vyatta_nf_conntrack.conf' -sysctl_file = r'/run/sysctl/10-vyos-conntrack.conf' -nftables_ct_file = r'/run/nftables-ct.conf' - -# Every ALG (Application Layer Gateway) consists of either a Kernel Object -# also called a Kernel Module/Driver or some rules present in iptables -module_map = { - 'ftp': { - 'ko': ['nf_nat_ftp', 'nf_conntrack_ftp'], - 'nftables': ['ct helper set "ftp_tcp" tcp dport {21} return'] - }, - 'h323': { - 'ko': ['nf_nat_h323', 'nf_conntrack_h323'], - 'nftables': ['ct helper set "ras_udp" udp dport {1719} return', - 'ct helper set "q931_tcp" tcp dport {1720} return'] - }, - 'nfs': { - 'nftables': ['ct helper set "rpc_tcp" tcp dport {111} return', - 'ct helper set "rpc_udp" udp dport {111} return'] - }, - 'pptp': { - 'ko': ['nf_nat_pptp', 'nf_conntrack_pptp'], - 'nftables': ['ct helper set "pptp_tcp" tcp dport {1723} return'], - 'ipv4': True - }, - 'sip': { - 'ko': ['nf_nat_sip', 'nf_conntrack_sip'], - 'nftables': ['ct helper set "sip_tcp" tcp dport {5060,5061} return', - 'ct helper set "sip_udp" udp dport {5060,5061} return'] - }, - 'sqlnet': { - 'nftables': ['ct helper set "tns_tcp" tcp dport {1521,1525,1536} return'] - }, - 'tftp': { - 'ko': ['nf_nat_tftp', 'nf_conntrack_tftp'], - 'nftables': ['ct helper set "tftp_udp" udp dport {69} return'] - }, -} - -valid_groups = [ - 'address_group', - 'domain_group', - 'network_group', - 'port_group' -] - -def get_config(config=None): - if config: - conf = config - else: - conf = Config() - base = ['system', 'conntrack'] - - conntrack = conf.get_config_dict(base, key_mangling=('-', '_'), - get_first_key=True, - with_recursive_defaults=True) - - conntrack['firewall'] = conf.get_config_dict(['firewall'], key_mangling=('-', '_'), - get_first_key=True, - no_tag_node_value_mangle=True) - - conntrack['ipv4_nat_action'] = 'accept' if conf.exists(['nat']) else 'return' - conntrack['ipv6_nat_action'] = 'accept' if conf.exists(['nat66']) else 'return' - conntrack['wlb_action'] = 'accept' if conf.exists(['load-balancing', 'wan']) else 'return' - conntrack['wlb_local_action'] = conf.exists(['load-balancing', 'wan', 'enable-local-traffic']) - - conntrack['module_map'] = module_map - - if conf.exists(['service', 'conntrack-sync']): - set_dependents('conntrack_sync', conf) - - return conntrack - -def verify(conntrack): - for inet in ['ipv4', 'ipv6']: - if dict_search_args(conntrack, 'ignore', inet, 'rule') != None: - for rule, rule_config in conntrack['ignore'][inet]['rule'].items(): - if dict_search('destination.port', rule_config) or \ - dict_search('destination.group.port_group', rule_config) or \ - dict_search('source.port', rule_config) or \ - dict_search('source.group.port_group', rule_config): - if 'protocol' not in rule_config or rule_config['protocol'] not in ['tcp', 'udp']: - raise ConfigError(f'Port requires tcp or udp as protocol in rule {rule}') - - tcp_flags = dict_search_args(rule_config, 'tcp', 'flags') - if tcp_flags: - if dict_search_args(rule_config, 'protocol') != 'tcp': - raise ConfigError('Protocol must be tcp when specifying tcp flags') - - not_flags = dict_search_args(rule_config, 'tcp', 'flags', 'not') - if not_flags: - duplicates = [flag for flag in tcp_flags if flag in not_flags] - if duplicates: - raise ConfigError(f'Cannot match a tcp flag as set and not set') - - for side in ['destination', 'source']: - if side in rule_config: - side_conf = rule_config[side] - - if 'group' in side_conf: - if len({'address_group', 'network_group', 'domain_group'} & set(side_conf['group'])) > 1: - raise ConfigError('Only one address-group, network-group or domain-group can be specified') - - for group in valid_groups: - if group in side_conf['group']: - group_name = side_conf['group'][group] - error_group = group.replace("_", "-") - - if group in ['address_group', 'network_group', 'domain_group']: - if 'address' in side_conf: - raise ConfigError(f'{error_group} and address cannot both be defined') - - if group_name and group_name[0] == '!': - group_name = group_name[1:] - - if inet == 'ipv6': - group = f'ipv6_{group}' - - group_obj = dict_search_args(conntrack['firewall'], 'group', group, group_name) - - if group_obj is None: - raise ConfigError(f'Invalid {error_group} "{group_name}" on ignore rule') - - if not group_obj: - Warning(f'{error_group} "{group_name}" has no members!') - - if dict_search_args(conntrack, 'timeout', 'custom', inet, 'rule') != None: - for rule, rule_config in conntrack['timeout']['custom'][inet]['rule'].items(): - if 'protocol' not in rule_config: - raise ConfigError(f'Conntrack custom timeout rule {rule} requires protocol tcp or udp') - else: - if 'tcp' in rule_config['protocol'] and 'udp' in rule_config['protocol']: - raise ConfigError(f'conntrack custom timeout rule {rule} - Cant use both tcp and udp protocol') - return None - -def generate(conntrack): - if not os.path.exists(nftables_ct_file): - conntrack['first_install'] = True - - # Determine if conntrack is needed - conntrack['ipv4_firewall_action'] = 'return' - conntrack['ipv6_firewall_action'] = 'return' - - for rules, path in dict_search_recursive(conntrack['firewall'], 'rule'): - if any(('state' in rule_conf or 'connection_status' in rule_conf or 'offload_target' in rule_conf) for rule_conf in rules.values()): - if path[0] == 'ipv4': - conntrack['ipv4_firewall_action'] = 'accept' - elif path[0] == 'ipv6': - conntrack['ipv6_firewall_action'] = 'accept' - - render(conntrack_config, 'conntrack/vyos_nf_conntrack.conf.j2', conntrack) - render(sysctl_file, 'conntrack/sysctl.conf.j2', conntrack) - render(nftables_ct_file, 'conntrack/nftables-ct.j2', conntrack) - return None - -def apply(conntrack): - # Depending on the enable/disable state of the ALG (Application Layer Gateway) - # modules we need to either insmod or rmmod the helpers. - - add_modules = [] - rm_modules = [] - - for module, module_config in module_map.items(): - if dict_search_args(conntrack, 'modules', module) is None: - if 'ko' in module_config: - unloaded = [mod for mod in module_config['ko'] if os.path.exists(f'/sys/module/{mod}')] - rm_modules.extend(unloaded) - else: - if 'ko' in module_config: - add_modules.extend(module_config['ko']) - - # Add modules before nftables uses them - if add_modules: - module_str = ' '.join(add_modules) - cmd(f'modprobe -a {module_str}') - - # Load new nftables ruleset - install_result, output = rc_cmd(f'nft -f {nftables_ct_file}') - if install_result == 1: - raise ConfigError(f'Failed to apply configuration: {output}') - - # Remove modules after nftables stops using them - if rm_modules: - module_str = ' '.join(rm_modules) - cmd(f'rmmod {module_str}') - - try: - call_dependents() - except ConfigError: - # Ignore config errors on dependent due to being called too early. Example: - # ConfigError("ConfigError('Interface ethN requires an IP address!')") - pass - - # We silently ignore all errors - # See: https://bugzilla.redhat.com/show_bug.cgi?id=1264080 - cmd(f'sysctl -f {sysctl_file}') - - return None - -if __name__ == '__main__': - try: - c = get_config() - verify(c) - generate(c) - apply(c) - except ConfigError as e: - print(e) - exit(1) |