diff options
Diffstat (limited to 'src/op_mode')
-rwxr-xr-x | src/op_mode/firewall.py | 114 | ||||
-rwxr-xr-x | src/op_mode/format_disk.py | 11 | ||||
-rwxr-xr-x | src/op_mode/generate_firewall_rule-resequence.py | 135 | ||||
-rwxr-xr-x | src/op_mode/raid.py | 44 | ||||
-rwxr-xr-x | src/op_mode/restart_frr.py | 4 | ||||
-rwxr-xr-x | src/op_mode/zone.py | 215 |
6 files changed, 253 insertions, 270 deletions
diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py index 11cbd977d..3434707ec 100755 --- a/src/op_mode/firewall.py +++ b/src/op_mode/firewall.py @@ -24,27 +24,39 @@ from vyos.config import Config from vyos.utils.process import cmd from vyos.utils.dict import dict_search_args -def get_config_firewall(conf, hook=None, priority=None, ipv6=False): +def get_config_firewall(conf, family=None, hook=None, priority=None): config_path = ['firewall'] - if hook: - config_path += ['ipv6' if ipv6 else 'ipv4', hook] - if priority: - config_path += [priority] + if family: + config_path += [family] + if hook: + config_path += [hook] + if priority: + config_path += [priority] firewall = conf.get_config_dict(config_path, key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True) return firewall -def get_nftables_details(hook, priority, ipv6=False): - suffix = '6' if ipv6 else '' - aux = 'IPV6_' if ipv6 else '' - name_prefix = 'NAME6_' if ipv6 else 'NAME_' +def get_nftables_details(family, hook, priority): + if family == 'ipv6': + suffix = 'ip6' + name_prefix = 'NAME6_' + aux='IPV6_' + elif family == 'ipv4': + suffix = 'ip' + name_prefix = 'NAME_' + aux='' + else: + suffix = 'bridge' + name_prefix = 'NAME_' + aux='' + if hook == 'name' or hook == 'ipv6-name': - command = f'sudo nft list chain ip{suffix} vyos_filter {name_prefix}{priority}' + command = f'sudo nft list chain {suffix} vyos_filter {name_prefix}{priority}' else: up_hook = hook.upper() - command = f'sudo nft list chain ip{suffix} vyos_filter VYOS_{aux}{up_hook}_{priority}' + command = f'sudo nft list chain {suffix} vyos_filter VYOS_{aux}{up_hook}_{priority}' try: results = cmd(command) @@ -68,11 +80,10 @@ def get_nftables_details(hook, priority, ipv6=False): out[rule_id] = rule return out -def output_firewall_name(hook, priority, firewall_conf, ipv6=False, single_rule_id=None): - ip_str = 'IPv6' if ipv6 else 'IPv4' - print(f'\n---------------------------------\n{ip_str} Firewall "{hook} {priority}"\n') +def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=None): + print(f'\n---------------------------------\n{family} Firewall "{hook} {priority}"\n') - details = get_nftables_details(hook, priority, ipv6) + details = get_nftables_details(family, hook, priority) rows = [] if 'rule' in firewall_conf: @@ -103,11 +114,10 @@ def output_firewall_name(hook, priority, firewall_conf, ipv6=False, single_rule_ header = ['Rule', 'Action', 'Protocol', 'Packets', 'Bytes', 'Conditions'] print(tabulate.tabulate(rows, header) + '\n') -def output_firewall_name_statistics(hook, prior, prior_conf, ipv6=False, single_rule_id=None): - ip_str = 'IPv6' if ipv6 else 'IPv4' - print(f'\n---------------------------------\n{ip_str} Firewall "{hook} {prior}"\n') +def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule_id=None): + print(f'\n---------------------------------\n{family} Firewall "{hook} {prior}"\n') - details = get_nftables_details(hook, prior, ipv6) + details = get_nftables_details(family, hook, prior) rows = [] if 'rule' in prior_conf: @@ -210,8 +220,8 @@ def output_firewall_name_statistics(hook, prior, prior_conf, ipv6=False, single_ row.append('0') row.append('0') row.append(prior_conf['default_action']) - row.append('any') # Source - row.append('any') # Dest + row.append('any') # Source + row.append('any') # Dest row.append('any') # inbound-interface row.append('any') # outbound-interface rows.append(row) @@ -229,15 +239,11 @@ def show_firewall(): if not firewall: return - if 'ipv4' in firewall: - for hook, hook_conf in firewall['ipv4'].items(): - for prior, prior_conf in firewall['ipv4'][hook].items(): - output_firewall_name(hook, prior, prior_conf, ipv6=False) - - if 'ipv6' in firewall: - for hook, hook_conf in firewall['ipv6'].items(): - for prior, prior_conf in firewall['ipv6'][hook].items(): - output_firewall_name(hook, prior, prior_conf, ipv6=True) + for family in ['ipv4', 'ipv6', 'bridge']: + if family in firewall: + for hook, hook_conf in firewall[family].items(): + for prior, prior_conf in firewall[family][hook].items(): + output_firewall_name(family, hook, prior, prior_conf) def show_firewall_family(family): print(f'Rulesets {family} Information') @@ -245,31 +251,28 @@ def show_firewall_family(family): conf = Config() firewall = get_config_firewall(conf) - if not firewall: + if not firewall or family not in firewall: return for hook, hook_conf in firewall[family].items(): for prior, prior_conf in firewall[family][hook].items(): - if family == 'ipv6': - output_firewall_name(hook, prior, prior_conf, ipv6=True) - else: - output_firewall_name(hook, prior, prior_conf, ipv6=False) + output_firewall_name(family, hook, prior, prior_conf) -def show_firewall_name(hook, priority, ipv6=False): +def show_firewall_name(family, hook, priority): print('Ruleset Information') conf = Config() - firewall = get_config_firewall(conf, hook, priority, ipv6) + firewall = get_config_firewall(conf, family, hook, priority) if firewall: - output_firewall_name(hook, priority, firewall, ipv6) + output_firewall_name(family, hook, priority, firewall) -def show_firewall_rule(hook, priority, rule_id, ipv6=False): +def show_firewall_rule(family, hook, priority, rule_id): print('Rule Information') conf = Config() - firewall = get_config_firewall(conf, hook, priority, ipv6) + firewall = get_config_firewall(conf, family, hook, priority) if firewall: - output_firewall_name(hook, priority, firewall, ipv6, rule_id) + output_firewall_name(family, hook, priority, firewall, rule_id) def show_firewall_group(name=None): conf = Config() @@ -369,6 +372,7 @@ def show_summary(): header = ['Ruleset Hook', 'Ruleset Priority', 'Description', 'References'] v4_out = [] v6_out = [] + br_out = [] if 'ipv4' in firewall: for hook, hook_conf in firewall['ipv4'].items(): @@ -382,6 +386,12 @@ def show_summary(): description = prior_conf.get('description', '') v6_out.append([hook, prior, description]) + if 'bridge' in firewall: + for hook, hook_conf in firewall['bridge'].items(): + for prior, prior_conf in firewall['bridge'][hook].items(): + description = prior_conf.get('description', '') + br_out.append([hook, prior, description]) + if v6_out: print('\nIPv6 Ruleset:\n') print(tabulate.tabulate(v6_out, header) + '\n') @@ -390,6 +400,10 @@ def show_summary(): print('\nIPv4 Ruleset:\n') print(tabulate.tabulate(v4_out, header) + '\n') + if br_out: + print('\nBridge Ruleset:\n') + print(tabulate.tabulate(br_out, header) + '\n') + show_firewall_group() def show_statistics(): @@ -401,15 +415,11 @@ def show_statistics(): if not firewall: return - if 'ipv4' in firewall: - for hook, hook_conf in firewall['ipv4'].items(): - for prior, prior_conf in firewall['ipv4'][hook].items(): - output_firewall_name_statistics(hook,prior, prior_conf, ipv6=False) - - if 'ipv6' in firewall: - for hook, hook_conf in firewall['ipv6'].items(): - for prior, prior_conf in firewall['ipv6'][hook].items(): - output_firewall_name_statistics(hook,prior, prior_conf, ipv6=True) + for family in ['ipv4', 'ipv6', 'bridge']: + if family in firewall: + for hook, hook_conf in firewall[family].items(): + for prior, prior_conf in firewall[family][hook].items(): + output_firewall_name_statistics(family, hook,prior, prior_conf) if __name__ == '__main__': parser = argparse.ArgumentParser() @@ -425,9 +435,9 @@ if __name__ == '__main__': if args.action == 'show': if not args.rule: - show_firewall_name(args.hook, args.priority, args.ipv6) + show_firewall_name(args.family, args.hook, args.priority) else: - show_firewall_rule(args.hook, args.priority, args.rule, args.ipv6) + show_firewall_rule(args.family, args.hook, args.priority, args.rule) elif args.action == 'show_all': show_firewall() elif args.action == 'show_family': diff --git a/src/op_mode/format_disk.py b/src/op_mode/format_disk.py index 31ceb196a..dc3c96322 100755 --- a/src/op_mode/format_disk.py +++ b/src/op_mode/format_disk.py @@ -24,6 +24,7 @@ from vyos.utils.io import ask_yes_no from vyos.utils.process import call from vyos.utils.process import cmd from vyos.utils.process import DEVNULL +from vyos.utils.disk import device_from_id def list_disks(): disks = set() @@ -77,12 +78,18 @@ if __name__ == '__main__': group = parser.add_argument_group() group.add_argument('-t', '--target', type=str, required=True, help='Target device to format') group.add_argument('-p', '--proto', type=str, required=True, help='Prototype device to use as reference') + parser.add_argument('--by-id', action='store_true', help='Specify device by disk id') args = parser.parse_args() + target = args.target + proto = args.proto + if args.by_id: + target = device_from_id(target) + proto = device_from_id(proto) - target_disk = args.target + target_disk = target eligible_target_disks = list_disks() - proto_disk = args.proto + proto_disk = proto eligible_proto_disks = eligible_target_disks.copy() eligible_proto_disks.remove(target_disk) diff --git a/src/op_mode/generate_firewall_rule-resequence.py b/src/op_mode/generate_firewall_rule-resequence.py new file mode 100755 index 000000000..b5b625a80 --- /dev/null +++ b/src/op_mode/generate_firewall_rule-resequence.py @@ -0,0 +1,135 @@ +#!/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/>. +# + +import argparse +from vyos.configquery import ConfigTreeQuery + + +def convert_to_set_commands(config_dict, parent_key=''): + """ + Converts a configuration dictionary into a list of set commands. + + Args: + config_dict (dict): The configuration dictionary. + parent_key (str): The parent key for nested dictionaries. + + Returns: + list: A list of set commands. + """ + commands = [] + for key, value in config_dict.items(): + current_key = parent_key + key if parent_key else key + + if isinstance(value, dict): + if not value: + commands.append(f"set {current_key}") + else: + commands.extend( + convert_to_set_commands(value, f"{current_key} ")) + + elif isinstance(value, str): + commands.append(f"set {current_key} '{value}'") + + return commands + + +def change_rule_numbers(config_dict, start, step): + """ + Changes rule numbers in the configuration dictionary. + + Args: + config_dict (dict): The configuration dictionary. + start (int): The starting rule number. + step (int): The step to increment the rule numbers. + + Returns: + None + """ + if 'rule' in config_dict: + rule_dict = config_dict['rule'] + updated_rule_dict = {} + rule_num = start + for rule_key in sorted(rule_dict.keys()): + updated_rule_dict[str(rule_num)] = rule_dict[rule_key] + rule_num += step + config_dict['rule'] = updated_rule_dict + + for key in config_dict: + if isinstance(config_dict[key], dict): + change_rule_numbers(config_dict[key], start, step) + + +def convert_rule_keys_to_int(config_dict): + """ + Converts rule keys in the configuration dictionary to integers. + + Args: + config_dict (dict or list): The configuration dictionary or list. + + Returns: + dict or list: The modified dictionary or list. + """ + if isinstance(config_dict, dict): + new_dict = {} + for key, value in config_dict.items(): + # Convert key to integer if possible + new_key = int(key) if key.isdigit() else key + + # Recur for nested dictionaries + if isinstance(value, dict): + new_value = convert_rule_keys_to_int(value) + else: + new_value = value + + new_dict[new_key] = new_value + + return new_dict + elif isinstance(config_dict, list): + return [convert_rule_keys_to_int(item) for item in config_dict] + else: + return config_dict + + +if __name__ == "__main__": + # Parse command-line arguments + parser = argparse.ArgumentParser(description='Convert dictionary to set commands with rule number modifications.') + parser.add_argument('--start', type=int, default=100, help='Start rule number') + parser.add_argument('--step', type=int, default=10, help='Step for rule numbers (default: 10)') + args = parser.parse_args() + + config = ConfigTreeQuery() + if not config.exists('firewall'): + print('Firewall is not configured') + exit(1) + + #config_dict = config.get_config_dict('firewall') + config_dict = config.get_config_dict('firewall') + + # Convert rule keys to integers, rule "10" -> rule 10 + # This is necessary for sorting the rules + config_dict = convert_rule_keys_to_int(config_dict) + + # Apply rule number modifications + change_rule_numbers(config_dict, start=args.start, step=args.step) + + # Convert to 'set' commands + set_commands = convert_to_set_commands(config_dict) + + print() + for command in set_commands: + print(command) + print() diff --git a/src/op_mode/raid.py b/src/op_mode/raid.py new file mode 100755 index 000000000..fed8ae2c3 --- /dev/null +++ b/src/op_mode/raid.py @@ -0,0 +1,44 @@ +#!/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/>. +# +# +import sys + +import vyos.opmode +from vyos.raid import add_raid_member +from vyos.raid import delete_raid_member + +def add(raid_set_name: str, member: str, by_id: bool = False): + try: + add_raid_member(raid_set_name, member, by_id) + except ValueError as e: + raise vyos.opmode.IncorrectValue(str(e)) + +def delete(raid_set_name: str, member: str, by_id: bool = False): + try: + delete_raid_member(raid_set_name, member, by_id) + except ValueError as e: + raise vyos.opmode.IncorrectValue(str(e)) + +if __name__ == '__main__': + try: + res = vyos.opmode.run(sys.modules[__name__]) + if res: + print(res) + except (ValueError, vyos.opmode.Error) as e: + print(e) + sys.exit(1) + diff --git a/src/op_mode/restart_frr.py b/src/op_mode/restart_frr.py index 5cce377eb..820a3846c 100755 --- a/src/op_mode/restart_frr.py +++ b/src/op_mode/restart_frr.py @@ -139,7 +139,9 @@ def _reload_config(daemon): # define program arguments cmd_args_parser = argparse.ArgumentParser(description='restart frr daemons') cmd_args_parser.add_argument('--action', choices=['restart'], required=True, help='action to frr daemons') -cmd_args_parser.add_argument('--daemon', choices=['bfdd', 'bgpd', 'ldpd', 'ospfd', 'ospf6d', 'isisd', 'ripd', 'ripngd', 'staticd', 'zebra', 'babeld'], required=False, nargs='*', help='select single or multiple daemons') +# Full list of FRR 9.0/stable daemons for reference +#cmd_args_parser.add_argument('--daemon', choices=['zebra', 'staticd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', 'isisd', 'pim6d', 'ldpd', 'eigrpd', 'babeld', 'sharpd', 'bfdd', 'fabricd', 'pathd'], required=False, nargs='*', help='select single or multiple daemons') +cmd_args_parser.add_argument('--daemon', choices=['zebra', 'staticd', 'bgpd', 'ospfd', 'ospf6d', 'ripd', 'ripngd', 'isisd', 'pim6d', 'ldpd', 'babeld', 'bfdd'], required=False, nargs='*', help='select single or multiple daemons') # parse arguments cmd_args = cmd_args_parser.parse_args() diff --git a/src/op_mode/zone.py b/src/op_mode/zone.py deleted file mode 100755 index 17ce90396..000000000 --- a/src/op_mode/zone.py +++ /dev/null @@ -1,215 +0,0 @@ -#!/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/>. -import typing -import sys -import vyos.opmode - -import tabulate -from vyos.configquery import ConfigTreeQuery -from vyos.utils.dict import dict_search_args -from vyos.utils.dict import dict_search - - -def get_config_zone(conf, name=None): - config_path = ['firewall', 'zone'] - if name: - config_path += [name] - - zone_policy = conf.get_config_dict(config_path, key_mangling=('-', '_'), - get_first_key=True, - no_tag_node_value_mangle=True) - return zone_policy - - -def _convert_one_zone_data(zone: str, zone_config: dict) -> dict: - """ - Convert config dictionary of one zone to API dictionary - :param zone: Zone name - :type zone: str - :param zone_config: config dictionary - :type zone_config: dict - :return: AP dictionary - :rtype: dict - """ - list_of_rules = [] - intrazone_dict = {} - if dict_search('from', zone_config): - for from_zone, from_zone_config in zone_config['from'].items(): - from_zone_dict = {'name': from_zone} - if dict_search('firewall.name', from_zone_config): - from_zone_dict['firewall'] = dict_search('firewall.name', - from_zone_config) - if dict_search('firewall.ipv6_name', from_zone_config): - from_zone_dict['firewall_v6'] = dict_search( - 'firewall.ipv6_name', from_zone_config) - list_of_rules.append(from_zone_dict) - - zone_dict = { - 'name': zone, - 'interface': dict_search('interface', zone_config), - 'type': 'LOCAL' if dict_search('local_zone', - zone_config) is not None else None, - } - if list_of_rules: - zone_dict['from'] = list_of_rules - if dict_search('intra_zone_filtering.firewall.name', zone_config): - intrazone_dict['firewall'] = dict_search( - 'intra_zone_filtering.firewall.name', zone_config) - if dict_search('intra_zone_filtering.firewall.ipv6_name', zone_config): - intrazone_dict['firewall_v6'] = dict_search( - 'intra_zone_filtering.firewall.ipv6_name', zone_config) - if intrazone_dict: - zone_dict['intrazone'] = intrazone_dict - return zone_dict - - -def _convert_zones_data(zone_policies: dict) -> list: - """ - Convert all config dictionary to API list of zone dictionaries - :param zone_policies: config dictionary - :type zone_policies: dict - :return: API list - :rtype: list - """ - zone_list = [] - for zone, zone_config in zone_policies.items(): - zone_list.append(_convert_one_zone_data(zone, zone_config)) - return zone_list - - -def _convert_config(zones_config: dict, zone: str = None) -> list: - """ - convert config to API list - :param zones_config: zones config - :type zones_config: - :param zone: zone name - :type zone: str - :return: API list - :rtype: list - """ - if zone: - if zones_config: - output = [_convert_one_zone_data(zone, zones_config)] - else: - raise vyos.opmode.DataUnavailable(f'Zone {zone} not found') - else: - if zones_config: - output = _convert_zones_data(zones_config) - else: - raise vyos.opmode.UnconfiguredSubsystem( - 'Zone entries are not configured') - return output - - -def output_zone_list(zone_conf: dict) -> list: - """ - Format one zone row - :param zone_conf: zone config - :type zone_conf: dict - :return: formatted list of zones - :rtype: list - """ - zone_info = [zone_conf['name']] - if zone_conf['type'] == 'LOCAL': - zone_info.append('LOCAL') - else: - zone_info.append("\n".join(zone_conf['interface'])) - - from_zone = [] - firewall = [] - firewall_v6 = [] - if 'intrazone' in zone_conf: - from_zone.append(zone_conf['name']) - - v4_name = dict_search_args(zone_conf['intrazone'], 'firewall') - v6_name = dict_search_args(zone_conf['intrazone'], 'firewall_v6') - if v4_name: - firewall.append(v4_name) - else: - firewall.append('') - if v6_name: - firewall_v6.append(v6_name) - else: - firewall_v6.append('') - - if 'from' in zone_conf: - for from_conf in zone_conf['from']: - from_zone.append(from_conf['name']) - - v4_name = dict_search_args(from_conf, 'firewall') - v6_name = dict_search_args(from_conf, 'firewall_v6') - if v4_name: - firewall.append(v4_name) - else: - firewall.append('') - if v6_name: - firewall_v6.append(v6_name) - else: - firewall_v6.append('') - - zone_info.append("\n".join(from_zone)) - zone_info.append("\n".join(firewall)) - zone_info.append("\n".join(firewall_v6)) - return zone_info - - -def get_formatted_output(zone_policy: list) -> str: - """ - Formatted output of all zones - :param zone_policy: list of zones - :type zone_policy: list - :return: formatted table with zones - :rtype: str - """ - headers = ["Zone", - "Interfaces", - "From Zone", - "Firewall IPv4", - "Firewall IPv6" - ] - formatted_list = [] - for zone_conf in zone_policy: - formatted_list.append(output_zone_list(zone_conf)) - tabulate.PRESERVE_WHITESPACE = True - output = tabulate.tabulate(formatted_list, headers, numalign="left") - return output - - -def show(raw: bool, zone: typing.Optional[str]): - """ - Show zone-policy command - :param raw: if API - :type raw: bool - :param zone: zone name - :type zone: str - """ - conf: ConfigTreeQuery = ConfigTreeQuery() - zones_config: dict = get_config_zone(conf, zone) - zone_policy_api: list = _convert_config(zones_config, zone) - if raw: - return zone_policy_api - else: - return get_formatted_output(zone_policy_api) - - -if __name__ == '__main__': - try: - res = vyos.opmode.run(sys.modules[__name__]) - if res: - print(res) - except (ValueError, vyos.opmode.Error) as e: - print(e) - sys.exit(1) |