diff options
-rw-r--r-- | Makefile | 1 | ||||
-rw-r--r-- | op-mode-definitions/show-firewall-policy.xml.in | 17 | ||||
-rwxr-xr-x | src/op_mode/show_firewall_policy.py | 122 |
3 files changed, 140 insertions, 0 deletions
@@ -88,6 +88,7 @@ op_mode_definitions: $(op_xml_obj) rm -f $(OP_TMPL_DIR)/show/node.def rm -f $(OP_TMPL_DIR)/show/system/node.def rm -f $(OP_TMPL_DIR)/show/vpn/node.def + rm -f $(OP_TMPL_DIR)/show/firewall/node.def # XXX: T3781: migrate back to old iptables NAT implementation as we can not use nft # which requires Kernel 5.10 for proper prefix translation support. Kernel 5.10 diff --git a/op-mode-definitions/show-firewall-policy.xml.in b/op-mode-definitions/show-firewall-policy.xml.in new file mode 100644 index 000000000..82793736e --- /dev/null +++ b/op-mode-definitions/show-firewall-policy.xml.in @@ -0,0 +1,17 @@ +<?xml version="1.0"?> +<interfaceDefinition> + <node name="show"> + <children> + <node name="firewall"> + <children> + <leafNode name="policy"> + <properties> + <help>Show firewall policy</help> + </properties> + <command>sudo ${vyos_op_scripts_dir}/show_firewall_policy.py --summary</command> + </leafNode> + </children> + </node> + </children> + </node> +</interfaceDefinition> diff --git a/src/op_mode/show_firewall_policy.py b/src/op_mode/show_firewall_policy.py new file mode 100755 index 000000000..ca5444d76 --- /dev/null +++ b/src/op_mode/show_firewall_policy.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2022 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 +import re +import tabulate + +from vyos.configquery import ConfigTreeQuery +from vyos.util import cmd + + +def get_firewall_bridge_name(): + """ + Return firewall policy bridge name + Example: + set firewall policy bridge forward ipv4 'FOO' + returns 'FOO' + """ + config = ConfigTreeQuery() + name = ['firewall', 'policy', 'bridge', 'forward', 'ipv4'] + if config.exists(name): + name = config.value(name) + return name + +def get_firewall_config(name): + """ + Return dict firewall rules for required name + """ + config = ConfigTreeQuery() + base = ['firewall', 'name', name] + if config.exists(base): + firewall = config.get_config_dict(base, key_mangling=('-', '_'), + get_first_key=True, no_tag_node_value_mangle=True) + return firewall + +def get_nftables_details(name): + command = f'sudo nft list chain bridge filter {name}' + try: + results = cmd(command) + except: + return {} + + out = {} + for line in results.split('\n'): + comment_search = re.search(rf'{name}[\- ](\d+|default-action)', line) + if not comment_search: + continue + + rule = {} + rule_id = comment_search[1] + counter_search = re.search(r'counter packets (\d+) bytes (\d+)', line) + if counter_search: + rule['packets'] = counter_search[1] + rule['bytes'] = counter_search[2] + + rule['conditions'] = re.sub(r'(\b(counter packets \d+ bytes \d+|drop|return|log)\b|comment "[\w\-]+")', '', line).strip() + out[rule_id] = rule + return out + +def output_firewall_name(name): + print(f'\n---------------------------------\nBridge Firewall "{name}"\n') + details = get_nftables_details(name) + firewall = get_firewall_config(name) + rows = [] + for rule, rule_conf in firewall['rule'].items(): + row = [rule, rule_conf['action'], rule_conf['protocol'] if 'protocol' in rule_conf else 'all'] + rule_details = details[rule] + row.append(rule_details.get('packets', 0)) + row.append(rule_details.get('bytes', 0)) + row.append(rule_details['conditions']) + rows.append(row) + + if 'default_action' in firewall: + row = ['default'] + rule_details = details['default-action'] + row.append(firewall['default_action']) + row.append('all') + row.append(rule_details.get('packets', 0)) + row.append(rule_details.get('bytes', 0)) + else: + row.append('0') + row.append('0') + row.append('src 0.0.0.0/0 dst 0.0.0.0/0') + rows.append(row) + + if rows: + header = ['Rule', 'Action', 'Protocol', 'Packets', 'Bytes', 'Conditions'] + print(tabulate.tabulate(rows, header) + '\n') + + return + +parser = argparse.ArgumentParser() +parser.add_argument("--summary", action="store_true", help="Show all containers") + +config = ConfigTreeQuery() +base = ['firewall', 'policy'] + +if not config.exists(base): + print('Firewall policy not configured') + exit(0) + +if __name__ == '__main__': + args = parser.parse_args() + + fw_name = get_firewall_bridge_name() + if args.summary: + output_firewall_name(fw_name) + + exit(0) |