diff options
author | Christian Breunig <christian@breunig.cc> | 2023-10-25 20:30:08 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-25 20:30:08 +0200 |
commit | ef55eab3c7cdac7b8febca9af15b5118aa475c45 (patch) | |
tree | cdd435b79159542d8ccbfe3d3fdfe8a16356c3ee /src | |
parent | 73eb7777a5d3a3bce48719f651c6b0f3a1c1a79d (diff) | |
parent | 51abbc0f1b2ccf4785cf7f29f1fe6f4af6007ee6 (diff) | |
download | vyos-1x-ef55eab3c7cdac7b8febca9af15b5118aa475c45.tar.gz vyos-1x-ef55eab3c7cdac7b8febca9af15b5118aa475c45.zip |
Merge pull request #2406 from nicolas-fort/T5681
T5681: Firewall,Nat and Nat66: simplified and standarize interface matcher
Diffstat (limited to 'src')
-rwxr-xr-x | src/conf_mode/firewall.py | 4 | ||||
-rwxr-xr-x | src/conf_mode/nat.py | 20 | ||||
-rwxr-xr-x | src/conf_mode/nat66.py | 22 | ||||
-rwxr-xr-x | src/migration-scripts/firewall/11-to-12 | 75 | ||||
-rwxr-xr-x | src/migration-scripts/nat/6-to-7 | 67 | ||||
-rwxr-xr-x | src/migration-scripts/nat66/1-to-2 | 63 |
6 files changed, 229 insertions, 22 deletions
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py index 9791cf009..8028492a7 100755 --- a/src/conf_mode/firewall.py +++ b/src/conf_mode/firewall.py @@ -283,8 +283,8 @@ def verify_rule(firewall, rule_conf, ipv6): for direction in ['inbound_interface','outbound_interface']: if direction in rule_conf: - if 'interface_name' in rule_conf[direction] and 'interface_group' in rule_conf[direction]: - raise ConfigError(f'Cannot specify both interface-group and interface-name for {direction}') + if 'name' in rule_conf[direction] and 'group' in rule_conf[direction]: + raise ConfigError(f'Cannot specify both interface group and interface name for {direction}') def verify_nested_group(group_name, group, groups, seen): if 'include' not in group: diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py index cb97a8662..44b13d413 100755 --- a/src/conf_mode/nat.py +++ b/src/conf_mode/nat.py @@ -151,11 +151,11 @@ def verify(nat): err_msg = f'Source NAT configuration error in rule {rule}:' if 'outbound_interface' in config: - if 'interface_name' in config['outbound_interface'] and 'interface_group' in config['outbound_interface']: - raise ConfigError(f'Cannot specify both interface-group and interface-name for nat source rule "{rule}"') - elif 'interface_name' in config['outbound_interface']: - if config['outbound_interface']['interface_name'] not in 'any' and config['outbound_interface']['interface_name'] not in interfaces(): - Warning(f'rule "{rule}" interface "{config["outbound_interface"]["interface_name"]}" does not exist on this system') + if 'name' in config['outbound_interface'] and 'group' in config['outbound_interface']: + raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for nat source rule "{rule}"') + elif 'name' in config['outbound_interface']: + if config['outbound_interface']['name'] not in 'any' and config['outbound_interface']['name'] not in interfaces(): + Warning(f'{err_msg} - interface "{config["outbound_interface"]["name"]}" does not exist on this system') if not dict_search('translation.address', config) and not dict_search('translation.port', config): if 'exclude' not in config and 'backend' not in config['load_balance']: @@ -175,11 +175,11 @@ def verify(nat): err_msg = f'Destination NAT configuration error in rule {rule}:' if 'inbound_interface' in config: - if 'interface_name' in config['inbound_interface'] and 'interface_group' in config['inbound_interface']: - raise ConfigError(f'Cannot specify both interface-group and interface-name for destination nat rule "{rule}"') - elif 'interface_name' in config['inbound_interface']: - if config['inbound_interface']['interface_name'] not in 'any' and config['inbound_interface']['interface_name'] not in interfaces(): - Warning(f'rule "{rule}" interface "{config["inbound_interface"]["interface_name"]}" does not exist on this system') + if 'name' in config['inbound_interface'] and 'group' in config['inbound_interface']: + raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for destination nat rule "{rule}"') + elif 'name' in config['inbound_interface']: + if config['inbound_interface']['name'] not in 'any' and config['inbound_interface']['name'] not in interfaces(): + Warning(f'{err_msg} - interface "{config["inbound_interface"]["name"]}" does not exist on this system') if not dict_search('translation.address', config) and not dict_search('translation.port', config) and 'redirect' not in config['translation']: if 'exclude' not in config and 'backend' not in config['load_balance']: diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py index 46d796bc8..0ba08aef3 100755 --- a/src/conf_mode/nat66.py +++ b/src/conf_mode/nat66.py @@ -62,11 +62,13 @@ def verify(nat): 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}:' - if 'outbound_interface' not in config: - raise ConfigError(f'{err_msg} outbound-interface not specified') - if config['outbound_interface'] not in interfaces(): - raise ConfigError(f'rule "{rule}" interface "{config["outbound_interface"]}" does not exist on this system') + if 'outbound_interface' in config: + if 'name' in config['outbound_interface'] and 'group' in config['outbound_interface']: + raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for nat source rule "{rule}"') + elif 'name' in config['outbound_interface']: + if config['outbound_interface']['name'] not in 'any' and config['outbound_interface']['name'] not in interfaces(): + Warning(f'{err_msg} - interface "{config["outbound_interface"]["name"]}" does not exist on this system') addr = dict_search('translation.address', config) if addr != None: @@ -85,12 +87,12 @@ def verify(nat): for rule, config in dict_search('destination.rule', nat).items(): err_msg = f'Destination NAT66 configuration error in rule {rule}:' - if 'inbound_interface' not in config: - raise ConfigError(f'{err_msg}\n' \ - 'inbound-interface not specified') - else: - if config['inbound_interface'] not in 'any' and config['inbound_interface'] not in interfaces(): - Warning(f'rule "{rule}" interface "{config["inbound_interface"]}" does not exist on this system') + if 'inbound_interface' in config: + if 'name' in config['inbound_interface'] and 'group' in config['inbound_interface']: + raise ConfigError(f'{err_msg} - Cannot specify both interface group and interface name for destination nat rule "{rule}"') + elif 'name' in config['inbound_interface']: + if config['inbound_interface']['name'] not in 'any' and config['inbound_interface']['name'] not in interfaces(): + Warning(f'{err_msg} - interface "{config["inbound_interface"]["name"]}" does not exist on this system') return None diff --git a/src/migration-scripts/firewall/11-to-12 b/src/migration-scripts/firewall/11-to-12 new file mode 100755 index 000000000..51b2fa860 --- /dev/null +++ b/src/migration-scripts/firewall/11-to-12 @@ -0,0 +1,75 @@ +#!/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/>. + +# T5681: Firewall re-writing. Simplify cli when mathcing interface +# From + # set firewall ... rule <rule> [inbound-interface | outboubd-interface] interface-name <iface> + # set firewall ... rule <rule> [inbound-interface | outboubd-interface] interface-group <iface_group> +# To + # set firewall ... rule <rule> [inbound-interface | outboubd-interface] name <iface> + # set firewall ... rule <rule> [inbound-interface | outboubd-interface] group <iface_group> + +import re + +from sys import argv +from sys import exit + +from vyos.configtree import ConfigTree +from vyos.ifconfig import Section + +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 = ['firewall'] +config = ConfigTree(config_file) + +if not config.exists(base): + # Nothing to do + exit(0) + +## FORT +## Migration from base chains +#if config.exists(base + ['interface', iface, direction]): +for family in ['ipv4', 'ipv6']: + if config.exists(base + [family]): + for hook in ['forward', 'input', 'output', 'name']: + if config.exists(base + [family, hook]): + for priority in config.list_nodes(base + [family, hook]): + if config.exists(base + [family, hook, priority, 'rule']): + for rule in config.list_nodes(base + [family, hook, priority, 'rule']): + for direction in ['inbound-interface', 'outbound-interface']: + if config.exists(base + [family, hook, priority, 'rule', rule, direction]): + if config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']): + iface = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']) + config.set(base + [family, hook, priority, 'rule', rule, direction, 'name'], value=iface) + config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-name']) + elif config.exists(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']): + group = config.return_value(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']) + config.set(base + [family, hook, priority, 'rule', rule, direction, 'group'], value=group) + config.delete(base + [family, hook, priority, 'rule', rule, direction, 'interface-group']) + +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)
\ No newline at end of file diff --git a/src/migration-scripts/nat/6-to-7 b/src/migration-scripts/nat/6-to-7 new file mode 100755 index 000000000..b5f6328ef --- /dev/null +++ b/src/migration-scripts/nat/6-to-7 @@ -0,0 +1,67 @@ +#!/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/>. + +# T5681: Firewall re-writing. Simplify cli when mathcing interface +# From +# 'set nat [source|destination] rule X [inbound-interface|outbound interface] interface-name <iface>' +# 'set nat [source|destination] rule X [inbound-interface|outbound interface] interface-group <iface_group>' +# to +# 'set nat [source|destination] rule X [inbound-interface|outbound interface] name <iface>' +# 'set nat [source|destination] rule X [inbound-interface|outbound interface] group <iface_group>' + +from sys import argv,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() + +config = ConfigTree(config_file) + +if not config.exists(['nat']): + # Nothing to do + exit(0) + +for direction in ['source', 'destination']: + # If a node doesn't exist, we obviously have nothing to do. + if not config.exists(['nat', direction]): + continue + + # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, + # but there are no rules under it. + if not config.list_nodes(['nat', direction]): + continue + + for rule in config.list_nodes(['nat', direction, 'rule']): + base = ['nat', direction, 'rule', rule] + for iface in ['inbound-interface','outbound-interface']: + if config.exists(base + [iface]): + if config.exists(base + [iface, 'interface-name']): + tmp = config.return_value(base + [iface, 'interface-name']) + config.delete(base + [iface, 'interface-name']) + config.set(base + [iface, 'name'], value=tmp) + +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) diff --git a/src/migration-scripts/nat66/1-to-2 b/src/migration-scripts/nat66/1-to-2 new file mode 100755 index 000000000..b7d4e3f6b --- /dev/null +++ b/src/migration-scripts/nat66/1-to-2 @@ -0,0 +1,63 @@ +#!/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/>. + +# T5681: Firewall re-writing. Simplify cli when mathcing interface +# From +# 'set nat66 [source|destination] rule X [inbound-interface|outbound interface] <iface>' +# to +# 'set nat66 [source|destination] rule X [inbound-interface|outbound interface] name <iface>' + +from sys import argv,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() + +config = ConfigTree(config_file) +if not config.exists(['nat66']): + # Nothing to do + exit(0) + +for direction in ['source', 'destination']: + # If a node doesn't exist, we obviously have nothing to do. + if not config.exists(['nat66', direction]): + continue + + # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist, + # but there are no rules under it. + if not config.list_nodes(['nat66', direction]): + continue + + for rule in config.list_nodes(['nat66', direction, 'rule']): + base = ['nat66', direction, 'rule', rule] + for iface in ['inbound-interface','outbound-interface']: + if config.exists(base + [iface]): + tmp = config.return_value(base + [iface]) + config.delete(base + [iface]) + config.set(base + [iface, 'name'], value=tmp) + +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) |