From 8d4205a99a9f0475da2b286d51febb36c7350e6e Mon Sep 17 00:00:00 2001 From: Viacheslav Hletenko Date: Wed, 24 Aug 2022 11:34:38 +0000 Subject: nat66: T4626: Rewrite op-mode show nat66 rules Rewrite op-mode "show nat66 source|destination rules" to the new format use "show_rules --direction --family " Delete old script show_nat66_rules.py --- op-mode-definitions/nat.xml.in | 4 +- op-mode-definitions/nat66.xml.in | 4 +- src/op_mode/nat.py | 31 +++++++----- src/op_mode/show_nat66_rules.py | 102 --------------------------------------- 4 files changed, 22 insertions(+), 119 deletions(-) delete mode 100755 src/op_mode/show_nat66_rules.py diff --git a/op-mode-definitions/nat.xml.in b/op-mode-definitions/nat.xml.in index 7148c1128..e89c3801f 100644 --- a/op-mode-definitions/nat.xml.in +++ b/op-mode-definitions/nat.xml.in @@ -16,7 +16,7 @@ Show configured source NAT rules - ${vyos_op_scripts_dir}/nat.py show_rules --direction source + ${vyos_op_scripts_dir}/nat.py show_rules --direction source --family inet @@ -58,7 +58,7 @@ Show configured destination NAT rules - ${vyos_op_scripts_dir}/nat.py show_rules --direction destination + ${vyos_op_scripts_dir}/nat.py show_rules --direction destination --family inet diff --git a/op-mode-definitions/nat66.xml.in b/op-mode-definitions/nat66.xml.in index 1ec46eb11..aba2d6add 100644 --- a/op-mode-definitions/nat66.xml.in +++ b/op-mode-definitions/nat66.xml.in @@ -16,7 +16,7 @@ Show configured source NAT66 rules - ${vyos_op_scripts_dir}/show_nat66_rules.py --source + ${vyos_op_scripts_dir}/nat.py show_rules --direction source --family inet6 @@ -58,7 +58,7 @@ Show configured destination NAT66 rules - ${vyos_op_scripts_dir}/show_nat66_rules.py --destination + ${vyos_op_scripts_dir}/nat.py show_rules --direction destination --family inet6 diff --git a/src/op_mode/nat.py b/src/op_mode/nat.py index 12fc4c782..2dffc378b 100755 --- a/src/op_mode/nat.py +++ b/src/op_mode/nat.py @@ -27,7 +27,7 @@ from vyos.util import dict_search import vyos.opmode -def _get_json_data(direction): +def _get_json_data(direction, family): """ Get NAT format JSON """ @@ -35,14 +35,15 @@ def _get_json_data(direction): chain = 'POSTROUTING' if direction == 'destination': chain = 'PREROUTING' - return cmd(f'sudo nft --json list chain ip nat {chain}') + family = 'ip6' if family == 'inet6' else 'ip' + return cmd(f'sudo nft --json list chain {family} nat {chain}') -def _get_raw_data_rules(direction): +def _get_raw_data_rules(direction, family): """Get interested rules :returns dict """ - data = _get_json_data(direction) + data = _get_json_data(direction, family) data_dict = json.loads(data) rules = [] for rule in data_dict['nftables']: @@ -51,10 +52,12 @@ def _get_raw_data_rules(direction): return rules -def _get_formatted_output_rules(data, direction): +def _get_formatted_output_rules(data, direction, family): # Add default values before loop sport, dport, proto = 'any', 'any', 'any' - saddr, daddr = '0.0.0.0/0', '0.0.0.0/0' + saddr = '::/0' if family == 'inet6' else '0.0.0.0/0' + daddr = '::/0' if family == 'inet6' else '0.0.0.0/0' + data_entries = [] for rule in data: if 'comment' in rule['rule']: @@ -69,11 +72,13 @@ def _get_formatted_output_rules(data, direction): if 'prefix' in match['right'] or 'set' in match['right']: # Merge dict src/dst l3_l4 parameters my_dict = {**match['left']['payload'], **match['right']} + my_dict['op'] = match['op'] + op = '!' if my_dict.get('op') == '!=' else '' proto = my_dict.get('protocol').upper() if my_dict['field'] == 'saddr': - saddr = f'{my_dict["prefix"]["addr"]}/{my_dict["prefix"]["len"]}' + saddr = f'{op}{my_dict["prefix"]["addr"]}/{my_dict["prefix"]["len"]}' elif my_dict['field'] == 'daddr': - daddr = f'{my_dict["prefix"]["addr"]}/{my_dict["prefix"]["len"]}' + daddr = f'{op}{my_dict["prefix"]["addr"]}/{my_dict["prefix"]["len"]}' elif my_dict['field'] == 'sport': # Port range or single port if jmespath.search('set[*].range', my_dict): @@ -96,8 +101,8 @@ def _get_formatted_output_rules(data, direction): if jmespath.search('left.payload.field', match) == 'daddr': daddr = match.get('right') else: - saddr = '0.0.0.0/0' - daddr = '0.0.0.0/0' + saddr = '::/0' if family == 'inet6' else '0.0.0.0/0' + daddr = '::/0' if family == 'inet6' else '0.0.0.0/0' sport = 'any' dport = 'any' proto = 'any' @@ -175,12 +180,12 @@ def _get_formatted_output_statistics(data, direction): return output -def show_rules(raw: bool, direction: str): - nat_rules = _get_raw_data_rules(direction) +def show_rules(raw: bool, direction: str, family: str): + nat_rules = _get_raw_data_rules(direction, family) if raw: return nat_rules else: - return _get_formatted_output_rules(nat_rules, direction) + return _get_formatted_output_rules(nat_rules, direction, family) def show_statistics(raw: bool, direction: str): diff --git a/src/op_mode/show_nat66_rules.py b/src/op_mode/show_nat66_rules.py deleted file mode 100755 index 967ec9d37..000000000 --- a/src/op_mode/show_nat66_rules.py +++ /dev/null @@ -1,102 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2021 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 . - -import jmespath -import json - -from argparse import ArgumentParser -from jinja2 import Template -from sys import exit -from vyos.util import cmd -from vyos.util import dict_search - -parser = ArgumentParser() -group = parser.add_mutually_exclusive_group() -group.add_argument("--source", help="Show statistics for configured source NAT rules", action="store_true") -group.add_argument("--destination", help="Show statistics for configured destination NAT rules", action="store_true") -args = parser.parse_args() - -if args.source or args.destination: - tmp = cmd('sudo nft -j list table ip6 nat') - tmp = json.loads(tmp) - - format_nat66_rule = '{0: <10} {1: <50} {2: <50} {3: <10}' - print(format_nat66_rule.format("Rule", "Source" if args.source else "Destination", "Translation", "Outbound Interface" if args.source else "Inbound Interface")) - print(format_nat66_rule.format("----", "------" if args.source else "-----------", "-----------", "------------------" if args.source else "-----------------")) - - data_json = jmespath.search('nftables[?rule].rule[?chain]', tmp) - for idx in range(0, len(data_json)): - data = data_json[idx] - - # The following key values must exist - # When the rule JSON does not have some keys, this is not a rule we can work with - continue_rule = False - for key in ['comment', 'chain', 'expr']: - if key not in data: - continue_rule = True - continue - if continue_rule: - continue - - comment = data['comment'] - - # Check the annotation to see if the annotation format is created by VYOS - continue_rule = True - for comment_prefix in ['SRC-NAT66-', 'DST-NAT66-']: - if comment_prefix in comment: - continue_rule = False - if continue_rule: - continue - - # When log is detected from the second index of expr, then this rule should be ignored - if 'log' in data['expr'][2]: - continue - - rule = comment.replace('SRC-NAT66-','') - rule = rule.replace('DST-NAT66-','') - chain = data['chain'] - if not ((args.source and chain == 'POSTROUTING') or (not args.source and chain == 'PREROUTING')): - continue - interface = dict_search('match.right', data['expr'][0]) - srcdest = dict_search('match.right.prefix.addr', data['expr'][2]) - if srcdest: - addr_tmp = dict_search('match.right.prefix.len', data['expr'][2]) - if addr_tmp: - srcdest = srcdest + '/' + str(addr_tmp) - else: - srcdest = dict_search('match.right', data['expr'][2]) - - tran_addr_json = dict_search('snat.addr' if args.source else 'dnat.addr', data['expr'][3]) - if tran_addr_json: - if isinstance(srcdest_json,str): - tran_addr = tran_addr_json - - if 'prefix' in tran_addr_json: - addr_tmp = dict_search('snat.addr.prefix.addr' if args.source else 'dnat.addr.prefix.addr', data['expr'][3]) - len_tmp = dict_search('snat.addr.prefix.len' if args.source else 'dnat.addr.prefix.len', data['expr'][3]) - if addr_tmp: - tran_addr = addr_tmp + '/' + str(len_tmp) - else: - if 'masquerade' in data['expr'][3]: - tran_addr = 'masquerade' - - print(format_nat66_rule.format(rule, srcdest, tran_addr, interface)) - - exit(0) -else: - parser.print_help() - exit(1) - -- cgit v1.2.3