diff options
-rw-r--r-- | interface-definitions/nat.xml.in | 1 | ||||
-rw-r--r-- | op-mode-definitions/nat.xml.in | 20 | ||||
-rw-r--r-- | op-mode-definitions/show-log.xml.in | 50 | ||||
-rw-r--r-- | python/vyos/nat.py | 6 | ||||
-rwxr-xr-x | src/op_mode/cgnat.py | 44 |
5 files changed, 104 insertions, 17 deletions
diff --git a/interface-definitions/nat.xml.in b/interface-definitions/nat.xml.in index 0a639bd80..73a748137 100644 --- a/interface-definitions/nat.xml.in +++ b/interface-definitions/nat.xml.in @@ -141,6 +141,7 @@ </children> </node> #include <include/inbound-interface.xml.i> + #include <include/firewall/log.xml.i> <node name="translation"> <properties> <help>Translation address or prefix</help> diff --git a/op-mode-definitions/nat.xml.in b/op-mode-definitions/nat.xml.in index 6398c0e07..13e7fd81d 100644 --- a/op-mode-definitions/nat.xml.in +++ b/op-mode-definitions/nat.xml.in @@ -16,6 +16,26 @@ <properties> <help>Show allocated CGNAT parameters</help> </properties> + <children> + <tagNode name="external-address"> + <properties> + <help>Show CGNAT allocations for an external IP address</help> + <completionHelp> + <list><x.x.x.x></list> + </completionHelp> + </properties> + <command>sudo ${vyos_op_scripts_dir}/cgnat.py show_allocation --external-address "$6"</command> + </tagNode> + <tagNode name="internal-address"> + <properties> + <help>Show CGNAT allocations for an internal IP address</help> + <completionHelp> + <list><x.x.x.x></list> + </completionHelp> + </properties> + <command>sudo ${vyos_op_scripts_dir}/cgnat.py show_allocation --internal-address "$6"</command> + </tagNode> + </children> <command>sudo ${vyos_op_scripts_dir}/cgnat.py show_allocation</command> </node> </children> diff --git a/op-mode-definitions/show-log.xml.in b/op-mode-definitions/show-log.xml.in index e13270364..c3aa324ba 100644 --- a/op-mode-definitions/show-log.xml.in +++ b/op-mode-definitions/show-log.xml.in @@ -464,12 +464,56 @@ </properties> <command>journalctl --no-hostname --boot --unit lldpd.service</command> </leafNode> - <leafNode name="nat"> + <node name="nat"> <properties> <help>Show log for Network Address Translation (NAT)</help> </properties> - <command>egrep -i "kernel:.*\[NAT-[A-Z]{3,}-[0-9]+(-MASQ)?\]" $(find /var/log -maxdepth 1 -type f -name messages\* | sort -t. -k2nr)</command> - </leafNode> + <children> + <node name="destination"> + <properties> + <help>Show NAT destination log</help> + </properties> + <command>journalctl --no-hostname --boot -k | egrep "\[DST-NAT-[0-9]+\]"</command> + <children> + <tagNode name="rule"> + <properties> + <help>Show NAT destination log for specified rule</help> + </properties> + <command>journalctl --no-hostname --boot -k | egrep "\[DST-NAT-$6\]"</command> + </tagNode> + </children> + </node> + <node name="source"> + <properties> + <help>Show NAT source log</help> + </properties> + <command>journalctl --no-hostname --boot -k | egrep "\[SRC-NAT-[0-9]+(-MASQ)?\]"""</command> + <children> + <tagNode name="rule"> + <properties> + <help>Show NAT source log for specified rule</help> + </properties> + <command>journalctl --no-hostname --boot -k | egrep "\[SRC-NAT-$6(-MASQ)?\]"</command> + </tagNode> + </children> + </node> + <node name="static"> + <properties> + <help>Show NAT static log</help> + </properties> + <command>journalctl --no-hostname --boot -k | egrep "\[STATIC-(SRC|DST)-NAT-[0-9]+\]"</command> + <children> + <tagNode name="rule"> + <properties> + <help>Show NAT static log for specified rule</help> + </properties> + <command>journalctl --no-hostname --boot -k | egrep "\[STATIC-(SRC|DST)-NAT-$6\]"</command> + </tagNode> + </children> + </node> + </children> + <command>journalctl --no-hostname --boot -k | egrep "\[(STATIC-)?(DST|SRC)-NAT-[0-9]+(-MASQ)?\]"</command> + </node> <leafNode name="ndp-proxy"> <properties> <help>Show log for Neighbor Discovery Protocol (NDP) Proxy</help> diff --git a/python/vyos/nat.py b/python/vyos/nat.py index 2ada29add..e54548788 100644 --- a/python/vyos/nat.py +++ b/python/vyos/nat.py @@ -300,12 +300,12 @@ def parse_nat_static_rule(rule_conf, rule_id, nat_type): output.append('counter') - if translation_str: - output.append(translation_str) - if 'log' in rule_conf: output.append(f'log prefix "[{log_prefix}{log_suffix}]"') + if translation_str: + output.append(translation_str) + output.append(f'comment "{log_prefix}"') return " ".join(output) diff --git a/src/op_mode/cgnat.py b/src/op_mode/cgnat.py index e58b15809..9ad8f92f9 100755 --- a/src/op_mode/cgnat.py +++ b/src/op_mode/cgnat.py @@ -16,6 +16,7 @@ import json import sys +import typing from tabulate import tabulate @@ -27,15 +28,11 @@ from vyos.utils.process import cmd CGNAT_TABLE = 'cgnat' -def _get_raw_data(): - """ Get CGNAT dictionary - """ +def _get_raw_data(external_address: str = '', internal_address: str = '') -> list[dict]: + """Get CGNAT dictionary and filter by external or internal address if provided.""" cmd_output = cmd(f'nft --json list table ip {CGNAT_TABLE}') data = json.loads(cmd_output) - return data - -def _get_formatted_output(data): elements = data['nftables'][2]['map']['elem'] allocations = [] for elem in elements: @@ -44,23 +41,48 @@ def _get_formatted_output(data): start_port = elem[1]['concat'][1]['range'][0] end_port = elem[1]['concat'][1]['range'][1] port_range = f'{start_port}-{end_port}' - allocations.append((internal, external, port_range)) + if (internal_address and internal != internal_address) or ( + external_address and external != external_address + ): + continue + + allocations.append( + { + 'internal_address': internal, + 'external_address': external, + 'port_range': port_range, + } + ) + + return allocations + + +def _get_formatted_output(allocations: list[dict]) -> str: + # Convert the list of dictionaries to a list of tuples for tabulate headers = ['Internal IP', 'External IP', 'Port range'] - output = tabulate(allocations, headers, numalign="left") + data = [ + (alloc['internal_address'], alloc['external_address'], alloc['port_range']) + for alloc in allocations + ] + output = tabulate(data, headers, numalign="left") return output -def show_allocation(raw: bool): +def show_allocation( + raw: bool, + external_address: typing.Optional[str], + internal_address: typing.Optional[str], +) -> str: config = ConfigTreeQuery() if not config.exists('nat cgnat'): raise vyos.opmode.UnconfiguredSubsystem('CGNAT is not configured') if raw: - return _get_raw_data() + return _get_raw_data(external_address, internal_address) else: - raw_data = _get_raw_data() + raw_data = _get_raw_data(external_address, internal_address) return _get_formatted_output(raw_data) |