diff options
| author | Christian Breunig <christian@breunig.cc> | 2023-09-06 20:26:06 +0200 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-09-06 20:26:06 +0200 | 
| commit | 50f3e9f66abfd7e0cad344c4c0fac0df7bc322df (patch) | |
| tree | 8d23d4fbc9763801f2a0259792509349b559b0a3 /src | |
| parent | c37f78087ba985e9c53c73ce51169dfbdbd5e553 (diff) | |
| parent | 2c88d01697eefbcd0188ec91dcbc589dee529db7 (diff) | |
| download | vyos-1x-50f3e9f66abfd7e0cad344c4c0fac0df7bc322df.tar.gz vyos-1x-50f3e9f66abfd7e0cad344c4c0fac0df7bc322df.zip | |
Merge pull request #2199 from sarthurdev/T4309
conntrack: T4309: T4903: Refactor `system conntrack ignore`, add IPv6 support and firewall groups
Diffstat (limited to 'src')
| -rwxr-xr-x | src/conf_mode/conntrack.py | 91 | ||||
| -rwxr-xr-x | src/conf_mode/nat.py | 2 | ||||
| -rwxr-xr-x | src/helpers/vyos-domain-resolver.py | 6 | ||||
| -rwxr-xr-x | src/init/vyos-router | 3 | ||||
| -rwxr-xr-x | src/migration-scripts/conntrack/3-to-4 | 50 | 
5 files changed, 126 insertions, 26 deletions
| diff --git a/src/conf_mode/conntrack.py b/src/conf_mode/conntrack.py index 9c43640a9..a0de914bc 100755 --- a/src/conf_mode/conntrack.py +++ b/src/conf_mode/conntrack.py @@ -24,7 +24,9 @@ from vyos.firewall import find_nftables_rule  from vyos.firewall import remove_nftables_rule  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.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 @@ -62,6 +64,13 @@ module_map = {       },  } +valid_groups = [ +    'address_group', +    'domain_group', +    'network_group', +    'port_group' +] +  def resync_conntrackd():      tmp = run('/usr/libexec/vyos/conf_mode/conntrack_sync.py')      if tmp > 0: @@ -78,15 +87,53 @@ def get_config(config=None):                                       get_first_key=True,                                       with_recursive_defaults=True) +    conntrack['firewall_group'] = conf.get_config_dict(['firewall', 'group'], key_mangling=('-', '_'), +                                                 get_first_key=True, +                                                 no_tag_node_value_mangle=True) +      return conntrack  def verify(conntrack): -    if dict_search('ignore.rule', conntrack) != None: -        for rule, rule_config in conntrack['ignore']['rule'].items(): -            if dict_search('destination.port', rule_config) or \ -               dict_search('source.port', 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}') +    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}') + +                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!')      return None @@ -94,26 +141,18 @@ def generate(conntrack):      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) - -    # dry-run newly generated configuration -    tmp = run(f'nft -c -f {nftables_ct_file}') -    if tmp > 0: -        if os.path.exists(nftables_ct_file): -            os.unlink(nftables_ct_file) -        raise ConfigError('Configuration file errors encountered!') -      return None -def find_nftables_ct_rule(rule): +def find_nftables_ct_rule(table, chain, rule):      helper_search = re.search('ct helper set "(\w+)"', rule)      if helper_search:          rule = helper_search[1] -    return find_nftables_rule('raw', 'VYOS_CT_HELPER', [rule]) +    return find_nftables_rule(table, chain, [rule]) -def find_remove_rule(rule): -    handle = find_nftables_ct_rule(rule) +def find_remove_rule(table, chain, rule): +    handle = find_nftables_ct_rule(table, chain, rule)      if handle: -        remove_nftables_rule('raw', 'VYOS_CT_HELPER', handle) +        remove_nftables_rule(table, chain, handle)  def apply(conntrack):      # Depending on the enable/disable state of the ALG (Application Layer Gateway) @@ -127,18 +166,24 @@ def apply(conntrack):                          cmd(f'rmmod {mod}')              if 'nftables' in module_config:                  for rule in module_config['nftables']: -                    find_remove_rule(rule) +                    find_remove_rule('raw', 'VYOS_CT_HELPER', rule) +                    find_remove_rule('ip6 raw', 'VYOS_CT_HELPER', rule)          else:              if 'ko' in module_config:                  for mod in module_config['ko']:                      cmd(f'modprobe {mod}')              if 'nftables' in module_config:                  for rule in module_config['nftables']: -                    if not find_nftables_ct_rule(rule): -                        cmd(f'nft insert rule ip raw VYOS_CT_HELPER {rule}') +                    if not find_nftables_ct_rule('raw', 'VYOS_CT_HELPER', rule): +                        cmd(f'nft insert rule raw VYOS_CT_HELPER {rule}') + +                    if not find_nftables_ct_rule('ip6 raw', 'VYOS_CT_HELPER', rule): +                        cmd(f'nft insert rule ip6 raw VYOS_CT_HELPER {rule}')      # Load new nftables ruleset -    cmd(f'nft -f {nftables_ct_file}') +    install_result, output = rc_cmd(f'nft -f {nftables_ct_file}') +    if install_result == 1: +        raise ConfigError(f'Failed to apply configuration: {output}')      if process_named_running('conntrackd'):          # Reload conntrack-sync daemon to fetch new sysctl values diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py index 9da7fbe80..08e96f10b 100755 --- a/src/conf_mode/nat.py +++ b/src/conf_mode/nat.py @@ -112,7 +112,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!') diff --git a/src/helpers/vyos-domain-resolver.py b/src/helpers/vyos-domain-resolver.py index 7e2fe2462..eac3d37af 100755 --- a/src/helpers/vyos-domain-resolver.py +++ b/src/helpers/vyos-domain-resolver.py @@ -37,12 +37,14 @@ domain_state = {}  ipv4_tables = {      'ip vyos_mangle',      'ip vyos_filter', -    'ip vyos_nat' +    'ip vyos_nat', +    'ip raw'  }  ipv6_tables = {      'ip6 vyos_mangle', -    'ip6 vyos_filter' +    'ip6 vyos_filter', +    'ip6 raw'  }  def get_config(conf): diff --git a/src/init/vyos-router b/src/init/vyos-router index 96f163213..a5d1a31fa 100755 --- a/src/init/vyos-router +++ b/src/init/vyos-router @@ -335,6 +335,9 @@ start ()      nfct helper add rpc inet tcp      nfct helper add rpc inet udp      nfct helper add tns inet tcp +    nfct helper add rpc inet6 tcp +    nfct helper add rpc inet6 udp +    nfct helper add tns inet6 tcp      nft -f /usr/share/vyos/vyos-firewall-init.conf || log_failure_msg "could not initiate firewall rules"      rm -f /etc/hostname diff --git a/src/migration-scripts/conntrack/3-to-4 b/src/migration-scripts/conntrack/3-to-4 new file mode 100755 index 000000000..e90c383af --- /dev/null +++ b/src/migration-scripts/conntrack/3-to-4 @@ -0,0 +1,50 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 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/>. + +# Add support for IPv6 conntrack ignore, move existing nodes to `system conntrack ignore ipv4` + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree + +if len(argv) < 2: +    print("Must specify file name!") +    exit(1) + +file_name = argv[1] + +with open(file_name, 'r') as f: +    config_file = f.read() + +base = ['system', 'conntrack'] +config = ConfigTree(config_file) + +if not config.exists(base): +    # Nothing to do +    exit(0) + +if config.exists(base + ['ignore', 'rule']): +    config.set(base + ['ignore', 'ipv4']) +    config.copy(base + ['ignore', 'rule'], base + ['ignore', 'ipv4', 'rule']) +    config.delete(base + ['ignore', 'rule']) + +try: +    with open(file_name, 'w') as f: +        f.write(config.to_string()) +except OSError as e: +    print("Failed to save the modified config: {}".format(e)) +    exit(1) | 
