diff options
Diffstat (limited to 'src/op_mode')
-rwxr-xr-x | src/op_mode/bgp.py | 170 | ||||
-rwxr-xr-x | src/op_mode/conntrack_sync.py | 219 | ||||
-rwxr-xr-x | src/op_mode/dhcp.py | 6 | ||||
-rwxr-xr-x | src/op_mode/dynamic_dns.py | 16 | ||||
-rwxr-xr-x | src/op_mode/ipsec.py | 216 | ||||
-rwxr-xr-x | src/op_mode/pki.py | 3 | ||||
-rw-r--r-- | src/op_mode/show_techsupport_report.py | 703 | ||||
-rwxr-xr-x | src/op_mode/show_vpn_ra.py | 56 | ||||
-rwxr-xr-x | src/op_mode/show_wwan.py | 8 |
9 files changed, 740 insertions, 657 deletions
diff --git a/src/op_mode/bgp.py b/src/op_mode/bgp.py index 3f6d45dd7..af9ea788b 100755 --- a/src/op_mode/bgp.py +++ b/src/op_mode/bgp.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2022 VyOS maintainers and contributors +# 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 @@ -15,101 +15,133 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # # Purpose: -# Displays bgp neighbors information. -# Used by the "show bgp (vrf <tag>) ipv4|ipv6 neighbors" commands. +# Displays BGP neighbors and tables information. import re import sys import typing -import jmespath from jinja2 import Template -from humps import decamelize - -from vyos.configquery import ConfigTreeQuery import vyos.opmode -ArgFamily = typing.Literal['inet', 'inet6'] - frr_command_template = Template(""" -{% if family %} - show bgp - {{ 'vrf ' ~ vrf if vrf else '' }} - {{ 'ipv6' if family == 'inet6' else 'ipv4'}} - {{ 'neighbor ' ~ peer if peer else 'summary' }} +show bgp + +{## VRF and family modifiers that may precede any options ##} + +{% if vrf %} + vrf {{vrf}} +{% endif %} + +{% if family == "inet" %} + ipv4 +{% elif family == "inet6" %} + ipv6 +{% elif family == "l2vpn" %} + l2vpn evpn +{% endif %} + +{% if family_modifier == "unicast" %} + unicast +{% elif family_modifier == "multicast" %} + multicast +{% elif family_modifier == "flowspec" %} + flowspec +{% elif family_modifier == "vpn" %} + vpn +{% endif %} + +{## Mutually exclusive query parameters ##} + +{# Network prefix #} +{% if prefix %} + {{prefix}} + + {% if longer_prefixes %} + longer-prefixes + {% elif best_path %} + bestpath + {% endif %} {% endif %} +{# Regex #} +{% if regex %} + regex {{regex}} +{% endif %} + +{## Raw modifier ##} + {% if raw %} json {% endif %} """) +ArgFamily = typing.Literal['inet', 'inet6', 'l2vpn'] +ArgFamilyModifier = typing.Literal['unicast', 'labeled_unicast', 'multicast', 'vpn', 'flowspec'] + +def show_summary(raw: bool): + from vyos.util import cmd + + if raw: + from json import loads + + output = cmd(f"vtysh -c 'show bgp summary json'").strip() -def _verify(func): - """Decorator checks if BGP config exists - BGP configuration can be present under vrf <tag> - If we do npt get arg 'peer' then it can be 'bgp summary' - """ - from functools import wraps - - @wraps(func) - def _wrapper(*args, **kwargs): - config = ConfigTreeQuery() - afi = 'ipv6' if kwargs.get('family') == 'inet6' else 'ipv4' - global_vrfs = ['all', 'default'] - peer = kwargs.get('peer') - vrf = kwargs.get('vrf') - unconf_message = f'BGP or neighbor is not configured' - # Add option to check the specific neighbor if we have arg 'peer' - peer_opt = f'neighbor {peer} address-family {afi}-unicast' if peer else '' - vrf_opt = '' - if vrf and vrf not in global_vrfs: - vrf_opt = f'vrf name {vrf}' - # Check if config does not exist - if not config.exists(f'{vrf_opt} protocols bgp {peer_opt}'): - raise vyos.opmode.UnconfiguredSubsystem(unconf_message) - return func(*args, **kwargs) - - return _wrapper - - -@_verify -def show_neighbors(raw: bool, - family: ArgFamily, - peer: typing.Optional[str], - vrf: typing.Optional[str]): - kwargs = dict(locals()) - frr_command = frr_command_template.render(kwargs) - frr_command = re.sub(r'\s+', ' ', frr_command) + # FRR 8.5 correctly returns an empty object when BGP is not running, + # we don't need to do anything special here + return loads(output) + else: + output = cmd(f"vtysh -c 'show bgp summary'") + return output +def show_neighbors(raw: bool): from vyos.util import cmd - output = cmd(f"vtysh -c '{frr_command}'") + from vyos.utils.dict import dict_to_list if raw: from json import loads - data = loads(output) - # Get list of the peers - peers = jmespath.search('*.peers | [0]', data) - if peers: - # Create new dict, delete old key 'peers' - # add key 'peers' neighbors to the list - list_peers = [] - new_dict = jmespath.search('* | [0]', data) - if 'peers' in new_dict: - new_dict.pop('peers') - - for neighbor, neighbor_options in peers.items(): - neighbor_options['neighbor'] = neighbor - list_peers.append(neighbor_options) - new_dict['peers'] = list_peers - return decamelize(new_dict) - data = jmespath.search('* | [0]', data) - return decamelize(data) + output = cmd(f"vtysh -c 'show bgp neighbors json'").strip() + d = loads(output) + return dict_to_list(d, save_key_to="neighbor") else: + output = cmd(f"vtysh -c 'show bgp neighbors'") return output +def show(raw: bool, + family: ArgFamily, + family_modifier: ArgFamilyModifier, + prefix: typing.Optional[str], + longer_prefixes: typing.Optional[bool], + best_path: typing.Optional[bool], + regex: typing.Optional[str], + vrf: typing.Optional[str]): + from vyos.utils.dict import dict_to_list + + if (longer_prefixes or best_path) and (prefix is None): + raise ValueError("longer_prefixes and best_path can only be used when prefix is given") + elif (family == "l2vpn") and (family_modifier is not None): + raise ValueError("l2vpn family does not accept any modifiers") + else: + kwargs = dict(locals()) + + frr_command = frr_command_template.render(kwargs) + frr_command = re.sub(r'\s+', ' ', frr_command) + + from vyos.util import cmd + output = cmd(f"vtysh -c '{frr_command}'") + + if raw: + from json import loads + d = loads(output) + if not ("routes" in d): + raise vyos.opmode.InternalError("FRR returned a BGP table with no routes field") + d = d["routes"] + routes = dict_to_list(d, save_key_to="route_key") + return routes + else: + return output if __name__ == '__main__': try: diff --git a/src/op_mode/conntrack_sync.py b/src/op_mode/conntrack_sync.py index 54ecd6d0e..c3345a936 100755 --- a/src/op_mode/conntrack_sync.py +++ b/src/op_mode/conntrack_sync.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# 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 @@ -15,9 +15,12 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. import os +import sys import syslog import xmltodict +import vyos.opmode + from argparse import ArgumentParser from vyos.configquery import CliShellApiConfigQuery from vyos.configquery import ConfigTreeQuery @@ -31,36 +34,23 @@ conntrackd_bin = '/usr/sbin/conntrackd' conntrackd_config = '/run/conntrackd/conntrackd.conf' failover_state_file = '/var/run/vyatta-conntrackd-failover-state' -parser = ArgumentParser(description='Conntrack Sync') -group = parser.add_mutually_exclusive_group() -group.add_argument('--restart', help='Restart connection tracking synchronization service', action='store_true') -group.add_argument('--reset-cache-internal', help='Reset internal cache', action='store_true') -group.add_argument('--reset-cache-external', help='Reset external cache', action='store_true') -group.add_argument('--show-internal', help='Show internal (main) tracking cache', action='store_true') -group.add_argument('--show-external', help='Show external (main) tracking cache', action='store_true') -group.add_argument('--show-internal-expect', help='Show internal (expect) tracking cache', action='store_true') -group.add_argument('--show-external-expect', help='Show external (expect) tracking cache', action='store_true') -group.add_argument('--show-statistics', help='Show connection syncing statistics', action='store_true') -group.add_argument('--show-status', help='Show conntrack-sync status', action='store_true') - def is_configured(): """ Check if conntrack-sync service is configured """ config = CliShellApiConfigQuery() if not config.exists(['service', 'conntrack-sync']): - print('Service conntrackd-sync not configured!') - exit(1) + raise vyos.opmode.UnconfiguredSubsystem("conntrack-sync is not configured!") def send_bulk_update(): """ send bulk update of internal-cache to other systems """ tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -B') if tmp > 0: - print('ERROR: failed to send bulk update to other conntrack-sync systems') + raise vyos.opmode.Error('Failed to send bulk update to other conntrack-sync systems') def request_sync(): """ request resynchronization with other systems """ tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -n') if tmp > 0: - print('ERROR: failed to request resynchronization of external cache') + raise vyos.opmode.Error('Failed to request resynchronization of external cache') def flush_cache(direction): """ flush conntrackd cache (internal or external) """ @@ -68,9 +58,9 @@ def flush_cache(direction): raise ValueError() tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -f {direction}') if tmp > 0: - print('ERROR: failed to clear {direction} cache') + raise vyos.opmode.Error('Failed to clear {direction} cache') -def xml_to_stdout(xml): +def from_xml(raw, xml): out = [] for line in xml.splitlines(): if line == '\n': @@ -78,108 +68,131 @@ def xml_to_stdout(xml): parsed = xmltodict.parse(line) out.append(parsed) - print(render_to_string('conntrackd/conntrackd.op-mode.j2', {'data' : out})) - -if __name__ == '__main__': - args = parser.parse_args() - syslog.openlog(ident='conntrack-tools', logoption=syslog.LOG_PID, - facility=syslog.LOG_INFO) + if raw: + return out + else: + return render_to_string('conntrackd/conntrackd.op-mode.j2', {'data' : out}) + +def restart(): + is_configured() + if commit_in_progress(): + raise vyos.opmode.CommitInProgress('Cannot restart conntrackd while a commit is in progress') + + syslog.syslog('Restarting conntrack sync service...') + cmd('systemctl restart conntrackd.service') + # request resynchronization with other systems + request_sync() + # send bulk update of internal-cache to other systems + send_bulk_update() + +def reset_external_cache(): + is_configured() + syslog.syslog('Resetting external cache of conntrack sync service...') + + # flush the external cache + flush_cache('external') + # request resynchronization with other systems + request_sync() + +def reset_internal_cache(): + is_configured() + syslog.syslog('Resetting internal cache of conntrack sync service...') + # flush the internal cache + flush_cache('internal') + + # request resynchronization of internal cache with kernel conntrack table + tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -R') + if tmp > 0: + print('ERROR: failed to resynchronize internal cache with kernel conntrack table') - if args.restart: - is_configured() - if commit_in_progress(): - print('Cannot restart conntrackd while a commit is in progress') - exit(1) - - syslog.syslog('Restarting conntrack sync service...') - cmd('systemctl restart conntrackd.service') - # request resynchronization with other systems - request_sync() - # send bulk update of internal-cache to other systems - send_bulk_update() - - elif args.reset_cache_external: - is_configured() - syslog.syslog('Resetting external cache of conntrack sync service...') + # send bulk update of internal-cache to other systems + send_bulk_update() - # flush the external cache - flush_cache('external') - # request resynchronization with other systems - request_sync() +def _show_cache(raw, opts): + is_configured() + out = cmd(f'{conntrackd_bin} -C {conntrackd_config} {opts} -x') + return from_xml(raw, out) - elif args.reset_cache_internal: - is_configured() - syslog.syslog('Resetting internal cache of conntrack sync service...') - # flush the internal cache - flush_cache('internal') +def show_external_cache(raw: bool): + opts = '-e ct' + return _show_cache(raw, opts) - # request resynchronization of internal cache with kernel conntrack table - tmp = run(f'{conntrackd_bin} -C {conntrackd_config} -R') - if tmp > 0: - print('ERROR: failed to resynchronize internal cache with kernel conntrack table') +def show_external_expect(raw: bool): + opts = '-e expect' + return _show_cache(raw, opts) - # send bulk update of internal-cache to other systems - send_bulk_update() +def show_internal_cache(raw: bool): + opts = '-i ct' + return _show_cache(raw, opts) - elif args.show_external or args.show_internal or args.show_external_expect or args.show_internal_expect: - is_configured() - opt = '' - if args.show_external: - opt = '-e ct' - elif args.show_external_expect: - opt = '-e expect' - elif args.show_internal: - opt = '-i ct' - elif args.show_internal_expect: - opt = '-i expect' - - if args.show_external or args.show_internal: - print('Main Table Entries:') - else: - print('Expect Table Entries:') - out = cmd(f'sudo {conntrackd_bin} -C {conntrackd_config} {opt} -x') - xml_to_stdout(out) +def show_internal_expect(raw: bool): + opts = '-i expect' + return _show_cache(raw, opts) - elif args.show_statistics: +def show_statistics(raw: bool): + if raw: + raise vyos.opmode.UnsupportedOperation("Machine-readable conntrack-sync statistics are not available yet") + else: is_configured() config = ConfigTreeQuery() print('\nMain Table Statistics:\n') - call(f'sudo {conntrackd_bin} -C {conntrackd_config} -s') + call(f'{conntrackd_bin} -C {conntrackd_config} -s') print() if config.exists(['service', 'conntrack-sync', 'expect-sync']): print('\nExpect Table Statistics:\n') - call(f'sudo {conntrackd_bin} -C {conntrackd_config} -s exp') + call(f'{conntrackd_bin} -C {conntrackd_config} -s exp') print() - elif args.show_status: - is_configured() - config = ConfigTreeQuery() - ct_sync_intf = config.list_nodes(['service', 'conntrack-sync', 'interface']) - ct_sync_intf = ', '.join(ct_sync_intf) - failover_state = "no transition yet!" - expect_sync_protocols = "disabled" - - if config.exists(['service', 'conntrack-sync', 'failover-mechanism', 'vrrp']): - failover_mechanism = "vrrp" - vrrp_sync_grp = config.value(['service', 'conntrack-sync', 'failover-mechanism', 'vrrp', 'sync-group']) - - if os.path.isfile(failover_state_file): - with open(failover_state_file, "r") as f: - failover_state = f.readline() - - if config.exists(['service', 'conntrack-sync', 'expect-sync']): - expect_sync_protocols = config.values(['service', 'conntrack-sync', 'expect-sync']) - if 'all' in expect_sync_protocols: - expect_sync_protocols = ["ftp", "sip", "h323", "nfs", "sqlnet"] +def show_status(raw: bool): + is_configured() + config = ConfigTreeQuery() + ct_sync_intf = config.list_nodes(['service', 'conntrack-sync', 'interface']) + ct_sync_intf = ', '.join(ct_sync_intf) + failover_state = "no transition yet!" + expect_sync_protocols = [] + + if config.exists(['service', 'conntrack-sync', 'failover-mechanism', 'vrrp']): + failover_mechanism = "vrrp" + vrrp_sync_grp = config.value(['service', 'conntrack-sync', 'failover-mechanism', 'vrrp', 'sync-group']) + + if os.path.isfile(failover_state_file): + with open(failover_state_file, "r") as f: + failover_state = f.readline() + + if config.exists(['service', 'conntrack-sync', 'expect-sync']): + expect_sync_protocols = config.values(['service', 'conntrack-sync', 'expect-sync']) + if 'all' in expect_sync_protocols: + expect_sync_protocols = ["ftp", "sip", "h323", "nfs", "sqlnet"] + + if raw: + status_data = { + "sync_interface": ct_sync_intf, + "failover_mechanism": failover_mechanism, + "sync_group": vrrp_sync_grp, + "last_transition": failover_state, + "sync_protocols": expect_sync_protocols + } + + return status_data + else: + if expect_sync_protocols: expect_sync_protocols = ', '.join(expect_sync_protocols) - + else: + expect_sync_protocols = "disabled" show_status = (f'\nsync-interface : {ct_sync_intf}\n' f'failover-mechanism : {failover_mechanism} [sync-group {vrrp_sync_grp}]\n' - f'last state transition : {failover_state}' + f'last state transition : {failover_state}\n' f'ExpectationSync : {expect_sync_protocols}') - print(show_status) + return show_status - else: - parser.print_help() - exit(1) +if __name__ == '__main__': + syslog.openlog(ident='conntrack-tools', logoption=syslog.LOG_PID, facility=syslog.LOG_INFO) + + 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/dhcp.py b/src/op_mode/dhcp.py index 41da14065..fe7f252ba 100755 --- a/src/op_mode/dhcp.py +++ b/src/op_mode/dhcp.py @@ -264,8 +264,10 @@ def show_pool_statistics(raw: bool, family: ArgFamily, pool: typing.Optional[str def show_server_leases(raw: bool, family: ArgFamily, pool: typing.Optional[str], sorted: typing.Optional[str], state: typing.Optional[ArgState]): # if dhcp server is down, inactive leases may still be shown as active, so warn the user. - if not is_systemd_service_running('isc-dhcp-server.service'): - Warning('DHCP server is configured but not started. Data may be stale.') + v = '6' if family == 'inet6' else '' + service_name = 'DHCPv6' if family == 'inet6' else 'DHCP' + if not is_systemd_service_running(f'isc-dhcp-server{v}.service'): + Warning(f'{service_name} server is configured but not started. Data may be stale.') v = 'v6' if family == 'inet6' else '' if pool and pool not in _get_dhcp_pools(family=family): diff --git a/src/op_mode/dynamic_dns.py b/src/op_mode/dynamic_dns.py index 2cba33cc8..d41a74db3 100755 --- a/src/op_mode/dynamic_dns.py +++ b/src/op_mode/dynamic_dns.py @@ -21,6 +21,7 @@ import time from tabulate import tabulate from vyos.config import Config +from vyos.template import is_ipv4, is_ipv6 from vyos.util import call cache_file = r'/run/ddclient/ddclient.cache' @@ -46,7 +47,7 @@ def _get_formatted_host_records(host_data): def show_status(): - # A ddclient status file must not always exist + # A ddclient status file might not always exist if not os.path.exists(cache_file): sys.exit(0) @@ -62,9 +63,20 @@ def show_status(): # we pick up the ones we are interested in for kvraw in line.split(' ')[0].split(','): k, v = kvraw.split('=') - if k in columns.keys(): + if k in list(columns.keys()) + ['ip', 'status']: # ip and status are legacy keys props[k] = v + # Extract IPv4 and IPv6 address and status from legacy keys + # Dual-stack isn't supported in legacy format, 'ip' and 'status' are for one of IPv4 or IPv6 + if 'ip' in props: + if is_ipv4(props['ip']): + props['ipv4'] = props['ip'] + props['status-ipv4'] = props['status'] + elif is_ipv6(props['ip']): + props['ipv6'] = props['ip'] + props['status-ipv6'] = props['status'] + del props['ip'] + # Convert mtime to human readable format if 'mtime' in props: props['mtime'] = time.strftime( diff --git a/src/op_mode/ipsec.py b/src/op_mode/ipsec.py index 7f4fb72e5..db4948d7a 100755 --- a/src/op_mode/ipsec.py +++ b/src/op_mode/ipsec.py @@ -13,7 +13,6 @@ # # 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 re import sys import typing @@ -24,6 +23,7 @@ from tabulate import tabulate from vyos.util import convert_data from vyos.util import seconds_to_human +from vyos.util import cmd from vyos.configquery import ConfigTreeQuery import vyos.opmode @@ -46,6 +46,25 @@ def _get_raw_data_sas(): except (vyos.ipsec.ViciInitiateError) as err: raise vyos.opmode.UnconfiguredSubsystem(err) + +def _get_output_swanctl_sas_from_list(ra_output_list: list) -> str: + """ + Template for output for VICI + Inserts \n after each IKE SA + :param ra_output_list: IKE SAs list + :type ra_output_list: list + :return: formatted string + :rtype: str + """ + output = ''; + for sa_val in ra_output_list: + for sa in sa_val.values(): + swanctl_output: str = cmd( + f'sudo swanctl -l --ike-id {sa["uniqueid"]}') + output = f'{output}{swanctl_output}\n\n' + return output + + def _get_formatted_output_sas(sas): sa_data = [] for sa in sas: @@ -444,6 +463,7 @@ def reset_peer(peer: str, tunnel: typing.Optional[str] = None): except (vyos.ipsec.ViciCommandError) as err: raise vyos.opmode.IncorrectValue(err) + def reset_all_peers(): sitetosite_list = _get_all_sitetosite_peers_name_list() if sitetosite_list: @@ -457,6 +477,7 @@ def reset_all_peers(): raise vyos.opmode.UnconfiguredSubsystem( 'VPN IPSec site-to-site is not configured, aborting') + def _get_ra_session_list_by_username(username: typing.Optional[str] = None): """ Return list of remote-access IKE_SAs uniqueids @@ -466,15 +487,15 @@ def _get_ra_session_list_by_username(username: typing.Optional[str] = None): :rtype: """ list_sa_id = [] - sa_list = vyos.ipsec.get_vici_sas() + sa_list = _get_raw_data_sas() for sa_val in sa_list: for sa in sa_val.values(): if 'remote-eap-id' in sa: if username: - if username == sa['remote-eap-id'].decode(): - list_sa_id.append(sa['uniqueid'].decode()) + if username == sa['remote-eap-id']: + list_sa_id.append(sa['uniqueid']) else: - list_sa_id.append(sa['uniqueid'].decode()) + list_sa_id.append(sa['uniqueid']) return list_sa_id @@ -556,6 +577,24 @@ def show_sa(raw: bool): return _get_formatted_output_sas(sa_data) +def _get_output_sas_detail(ra_output_list: list) -> str: + """ + Formate all IKE SAs detail output + :param ra_output_list: IKE SAs list + :type ra_output_list: list + :return: formatted RA IKE SAs detail output + :rtype: str + """ + return _get_output_swanctl_sas_from_list(ra_output_list) + + +def show_sa_detail(raw: bool): + sa_data = _get_raw_data_sas() + if raw: + return sa_data + return _get_output_sas_detail(sa_data) + + def show_connections(raw: bool): list_conns = _get_convert_data_connections() list_sas = _get_raw_data_sas() @@ -573,6 +612,173 @@ def show_connections_summary(raw: bool): return _get_raw_connections_summary(list_conns, list_sas) +def _get_ra_sessions(username: typing.Optional[str] = None) -> list: + """ + Return list of remote-access IKE_SAs from VICI by username. + If username unspecified, return all remote-access IKE_SAs + :param username: Username of RA connection + :type username: str + :return: list of ra remote-access IKE_SAs + :rtype: list + """ + list_sa = [] + sa_list = _get_raw_data_sas() + for conn in sa_list: + for sa in conn.values(): + if 'remote-eap-id' in sa: + if username: + if username == sa['remote-eap-id']: + list_sa.append(conn) + else: + list_sa.append(conn) + return list_sa + + +def _filter_ikesas(list_sa: list, filter_key: str, filter_value: str) -> list: + """ + Filter IKE SAs by specifice key + :param list_sa: list of IKE SAs + :type list_sa: list + :param filter_key: Filter Key + :type filter_key: str + :param filter_value: Filter Value + :type filter_value: str + :return: Filtered list of IKE SAs + :rtype: list + """ + filtered_sa_list = [] + for conn in list_sa: + for sa in conn.values(): + if sa[filter_key] and sa[filter_key] == filter_value: + filtered_sa_list.append(conn) + return filtered_sa_list + + +def _get_last_installed_childsa(sa: dict) -> str: + """ + Return name of last installed active Child SA + :param sa: Dictionary with Child SAs + :type sa: dict + :return: Name of the Last installed active Child SA + :rtype: str + """ + child_sa_name = None + child_sa_id = 0 + for sa_name, child_sa in sa['child-sas'].items(): + if child_sa['state'] == 'INSTALLED': + if child_sa_id == 0 or int(child_sa['uniqueid']) > child_sa_id: + child_sa_id = int(child_sa['uniqueid']) + child_sa_name = sa_name + return child_sa_name + + +def _get_formatted_ike_proposal(sa: dict) -> str: + """ + Return IKE proposal string in format + EncrALG-EncrKeySize/PFR/HASH/DH-GROUP + :param sa: IKE SA + :type sa: dict + :return: IKE proposal string + :rtype: str + """ + proposal = '' + proposal = f'{proposal}{sa["encr-alg"]}' if 'encr-alg' in sa else proposal + proposal = f'{proposal}-{sa["encr-keysize"]}' if 'encr-keysize' in sa else proposal + proposal = f'{proposal}/{sa["prf-alg"]}' if 'prf-alg' in sa else proposal + proposal = f'{proposal}/{sa["integ-alg"]}' if 'integ-alg' in sa else proposal + proposal = f'{proposal}/{sa["dh-group"]}' if 'dh-group' in sa else proposal + return proposal + + +def _get_formatted_ipsec_proposal(sa: dict) -> str: + """ + Return IPSec proposal string in format + Protocol: EncrALG-EncrKeySize/HASH/PFS + :param sa: Child SA + :type sa: dict + :return: IPSec proposal string + :rtype: str + """ + proposal = '' + proposal = f'{proposal}{sa["protocol"]}' if 'protocol' in sa else proposal + proposal = f'{proposal}:{sa["encr-alg"]}' if 'encr-alg' in sa else proposal + proposal = f'{proposal}-{sa["encr-keysize"]}' if 'encr-keysize' in sa else proposal + proposal = f'{proposal}/{sa["integ-alg"]}' if 'integ-alg' in sa else proposal + proposal = f'{proposal}/{sa["dh-group"]}' if 'dh-group' in sa else proposal + return proposal + + +def _get_output_ra_sas_detail(ra_output_list: list) -> str: + """ + Formate RA IKE SAs detail output + :param ra_output_list: IKE SAs list + :type ra_output_list: list + :return: formatted RA IKE SAs detail output + :rtype: str + """ + return _get_output_swanctl_sas_from_list(ra_output_list) + + +def _get_formatted_output_ra_summary(ra_output_list: list): + sa_data = [] + for conn in ra_output_list: + for sa in conn.values(): + sa_id = sa['uniqueid'] if 'uniqueid' in sa else '' + sa_username = sa['remote-eap-id'] if 'remote-eap-id' in sa else '' + sa_protocol = f'IKEv{sa["version"]}' if 'version' in sa else '' + sa_remotehost = sa['remote-host'] if 'remote-host' in sa else '' + sa_remoteid = sa['remote-id'] if 'remote-id' in sa else '' + sa_ike_proposal = _get_formatted_ike_proposal(sa) + sa_tunnel_ip = sa['remote-vips'] + child_sa_key = _get_last_installed_childsa(sa) + if child_sa_key: + child_sa = sa['child-sas'][child_sa_key] + sa_ipsec_proposal = _get_formatted_ipsec_proposal(child_sa) + sa_state = "UP" + sa_uptime = seconds_to_human(sa['established']) + else: + sa_ipsec_proposal = '' + sa_state = "DOWN" + sa_uptime = '' + sa_data.append( + [sa_id, sa_username, sa_protocol, sa_state, sa_uptime, + sa_tunnel_ip, + sa_remotehost, sa_remoteid, sa_ike_proposal, + sa_ipsec_proposal]) + + headers = ["Connection ID", "Username", "Protocol", "State", "Uptime", + "Tunnel IP", "Remote Host", "Remote ID", "IKE Proposal", + "IPSec Proposal"] + sa_data = sorted(sa_data, key=_alphanum_key) + output = tabulate(sa_data, headers) + return output + + +def show_ra_detail(raw: bool, username: typing.Optional[str] = None, + conn_id: typing.Optional[str] = None): + list_sa: list = _get_ra_sessions() + if username: + list_sa = _filter_ikesas(list_sa, 'remote-eap-id', username) + elif conn_id: + list_sa = _filter_ikesas(list_sa, 'uniqueid', conn_id) + if not list_sa: + raise vyos.opmode.IncorrectValue( + f'No active connections found, aborting') + if raw: + return list_sa + return _get_output_ra_sas_detail(list_sa) + + +def show_ra_summary(raw: bool): + list_sa: list = _get_ra_sessions() + if not list_sa: + raise vyos.opmode.IncorrectValue( + f'No active connections found, aborting') + if raw: + return list_sa + return _get_formatted_output_ra_summary(list_sa) + + if __name__ == '__main__': try: res = vyos.opmode.run(sys.modules[__name__]) diff --git a/src/op_mode/pki.py b/src/op_mode/pki.py index 1e78c3a03..b054690b0 100755 --- a/src/op_mode/pki.py +++ b/src/op_mode/pki.py @@ -87,6 +87,9 @@ def get_config_certificate(name=None): def get_certificate_ca(cert, ca_certs): # Find CA certificate for given certificate + if not ca_certs: + return None + for ca_name, ca_dict in ca_certs.items(): if 'certificate' not in ca_dict: continue diff --git a/src/op_mode/show_techsupport_report.py b/src/op_mode/show_techsupport_report.py index 13ed9a3c1..782004144 100644 --- a/src/op_mode/show_techsupport_report.py +++ b/src/op_mode/show_techsupport_report.py @@ -14,425 +14,290 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see <http://www.gnu.org/licenses/>. -from vyos.util import call import os +from typing import List +from vyos.util import rc_cmd +from vyos.ifconfig import Section +from vyos.ifconfig import Interface -def header(cmd): - print(16 * '-' + '\n' + cmd + '\n' + 16 * '-') - return - - -# get intefaces info -interfaces_list = os.popen('ls /sys/class/net/ | grep eth').read().split() -bridges_list = os.popen('ls /sys/class/net/ | grep br').read().split() - -###################### THE PART OF CONFIGURATION ###################### - -cmd_list_conf = [ - "VyOS Version and Package Changes%/opt/vyatta/bin/vyatta-op-cmd-wrapper show version all", - "Configuration File%cat /opt/vyatta/etc/config/config.boot", - "Running configuration%/opt/vyatta/bin/vyatta-op-cmd-wrapper show configuration", - "Package Repository Configuration File%cat /etc/apt/sources.list", - "User Startup Scripts%cat /etc/rc.local", - "Quagga Configuration%vtysh -c 'show run'" -] - - -def CONFIGURATION(cmd): - for command_line in cmd: - line = command_line.split('%') - head = line[0] - command = line[1] - header(head) - call(command) - return - - -###################### THE PART OF INTERFACES ###################### - -cmd_list_int = [ - "Interfaces%/opt/vyatta/bin/vyatta-op-cmd-wrapper show interfaces", - "Ethernet", - "Interface statistics%ip -s link show", - "Physical Interface statistics for%ethtool -S", - "Physical Interface Details for %/opt/vyatta/bin/vyatta-op-cmd-wrapper show interfaces ethernet%ethtool -k $eth", - "ARP Table (Total entries)%/opt/vyatta/bin/vyatta-op-cmd-wrapper show arp", - "Number of incomplete entries in ARP table%show arp | grep incomplete | wc -l", - "Bridges" -] - - -def INTERFACES(cmd): - for command_line in cmd: - line = command_line.split('%') - head = line[0] - if command_line.startswith("Ethernet"): - header(command_line) - elif command_line.startswith("Physical Interface statistics"): - for command_interface in interfaces_list: - header(f'{head} {command_interface}') - call(f'{line[1]} {command_interface}') - elif command_line.startswith("Physical Interface Details"): - for command_interface in interfaces_list: - header(f'{head} {command_interface}') - call(f'{line[1]} {command_interface} physical') - call(f'{line[2]} {command_interface}') - elif command_line.startswith("Bridges"): - header(command_line) - for command_interface in bridges_list: - header(f'Information for {command_interface}') - call(f'/sbin/brctl showstp {command_interface}') - call(f'/sbin/brctl showmacs {command_interface}') - else: - command = line[1] - header(head) - call(command) - return - - -###################### THE PART OF ROUTING ###################### - -cmd_list_route = [ - "show ip route bgp", - "show ip route cache", - "show ip route connected", - "show ip route forward", - "show ip route isis", - "show ip route kernel", - "show ip route ospf", - "show ip route rip", - "show ip route static", - "show ip route summary", - "show ip route supernets-only", - "show ip route table", - "show ip route tag", - "show ip route vrf", - "show ipv6 route bgp", - "show ipv6 route cache", - "show ipv6 route connected", - "show ipv6 route forward", - "show ipv6 route isis", - "show ipv6 route kernel", - "show ipv6 route ospf", - "show ipv6 route rip", - "show ipv6 route static", - "show ipv6 route summary", - "show ipv6 route supernets-only", - "show ipv6 route table", - "show ipv6 route tag", - "show ipv6 route vrf", -] - - -def ROUTING(cmd): - for command_line in cmd: - head = command_line - command = command_line - header(head) - call(f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {command}') - return - - -###################### THE PART OF IPTABLES ###################### - -cmd_list_iptables = [ - "Filter Chain Details%sudo /sbin/iptables -L -vn", - "Nat Chain Details%sudo /sbin/iptables -t nat -L -vn", - "Mangle Chain Details%sudo /sbin/iptables -t mangle -L -vn", - "Raw Chain Details%sudo /sbin/iptables -t raw -L -vn", - "Save Iptables Rule-Set%sudo iptables-save -c" -] - - -def IPTABLES(cmd): - for command_line in cmd: - line = command_line.split('%') - head = line[0] - command = line[1] - header(head) - call(command) - return - - -###################### THE PART OF SYSTEM ###################### - -cmd_list_system = [ - "Show System Image Version%show system image version", - "Show System Image Storage%show system image storage", - "Current Time%date", - "Installed Packages%dpkg -l", - "Loaded Modules%cat /proc/modules", - "CPU", - "Installed CPU/s%lscpu", - "Cumulative CPU Time Used by Running Processes%top -n1 -b -S", - "Hardware Interrupt Counters%cat /proc/interrupts", - "Load Average%cat /proc/loadavg" -] - - -def SYSTEM(cmd): - for command_line in cmd: - line = command_line.split('%') - head = line[0] - if command_line.startswith("CPU"): - header(command_line) - elif line[1].startswith("show"): - header(head) - command = line[1] - call(f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {command}') - else: - header(head) - command = line[1] - call(command) - return - - -###################### THE PART OF PROCESSES ###################### - -cmd_list_processes = [ - "Running Processes%ps -ef", - "Memory", - "Installed Memory%cat /proc/meminfo", - " Memory Usage%free", - "Storage", - "Devices%cat /proc/devices", - "Partitions%cat /proc/partitions", - "Partitioning for disks%fdisk -l /dev/" -] - - -def PROCESSES(cmd): - for command_line in cmd: - line = command_line.split('%') - head = line[0] - if command_line.startswith("Memory"): - header(command_line) - elif command_line.startswith("Storage"): - header(command_line) - elif command_line.startswith("Partitioning for disks"): - header(head) - disks = set() - with open('/proc/partitions') as partitions_file: - for line in partitions_file: - fields = line.strip().split() - if len(fields) == 4 and fields[3].isalpha() and fields[3] != 'name': - disks.add(fields[3]) - for disk in disks: - call(f'fdisk -l /dev/{disk}') - else: - header(head) - command = line[1] - call(command) - return - - -###################### THE PART OF CORE SECTION ###################### - -cmd_list_core = [ - "Mounts%cat /proc/mounts", - "Diskstats%cat /proc/diskstats", - "Hard Drive Usage%df -h -x squashfs", - # "General System", - "Boot Messages%cat /var/log/dmesg", - "Recent Kernel messages (dmesg)%dmesg", - "PCI Info%sudo lspci -vvx", - "PCI Vendor and Device Codes%sudo lspci -nn", - # "System Info%${vyatta_bindir}/vyatta-show-dmi", - "GRUB Command line%cat /proc/cmdline", - "Open Ports%sudo lsof -P -n -i", - "System Startup Files%ls -l /etc/rc?.d", - "Login History%last -ix", - "Recent Log Messages%tail -n 250 /var/log/messages", - "NTP%/opt/vyatta/bin/vyatta-op-cmd-wrapper show ntp", -] - - -def CORE(cmd): - for command_line in cmd: - line = command_line.split('%') - command = line[1] - header(line[0]) - call(command) - return - - -###################### THE PART OF VyOS INFORMATION ###################### - -cmd_list_vyos = [ - "BGP", - "header BGP Summary", - "show ip bgp summary", - "header BGP Neighbors", - "show ip bgp neighbors", - "header BGP Debugging Information", - "show monitoring protocols bgp", - "CLUSTERING", - "Cluster Status", - "show cluster status", - "DHCP Server", - "DHCP Leases", - "show dhcp server leases", - "DHCP Statistics", - "show dhcp server statistics", - "DHCP Client", - "DHCP Client Leases", - "show dhcp client leases", - "DHCPV6 Server", - "DHCPV6 Server Status", - "show dhcpv6 server status", - "DHCPV6 Server Leases", - "show dhcpv6 server leases", - "DHCPV6 Relay", - "DHCPV6 Relay Status", - "show dhcpv6 relay-agent status", - "DHCPV6 Client", - "DHCPV6 Client Leases", - "show dhcpv6 client leases", - "DNS", - "DNS Dynamic Status", - "show dns dynamic status", - "DNS Forwarding Statistics", - "show dns forwarding statistics", - "DNS Forwarding Nameservers", - "show dns forwarding nameservers", - "FIREWALL", - "Firewall Group", - "show firewall group", - "Firewall Summary", - "show firewall summary", - "Firewall Statistics", - "show firewall statistics", - "IPSec", - "IPSec Status", - "show vpn ipsec status", - "IPSec sa", - "show vpn ipsec sa", - "IPSec sa Detail", - "show vpn ipsec sa detail", - "IPSec sa Statistics", - "show vpn ipsec sa statistics", - "/etc/ipsec.conf", - "cat /etc/ipsec.conf", - "/etc/ipsec.secrets", - "cat /etc/ipsec.secrets", - "NAT", - "NAT Rules", - "show nat rules", - "NAT Statistics", - "show nat statistics", - "NAT Translations Detail", - "show nat translations detail", - "FlowAccounting", - "show flow-accounting", - "OPENVPN", - "OpenVPN Interfaces", - "show interfaces openvpn detail", - "OpenVPN Server Status", - "show openvpn status server", - "OSPF", - "OSPF Neighbor", - "show ip ospf neighbor", - "OSPF Route", - "show ip ospf route", - "OSPF Debugging Information", - "show monitoring protocols ospf", - "OSPFV3", - "OSPFV3 Debugging Information", - "show monitoring protocols ospfv3", - "Policy", - "IP Route Maps", - "show ip protocol", - "Route-Map", - "show route-map", - # header IP Access Lists - # show ip access-lists - "IP Community List", - "show ip community-list", - "Traffic Policy", - "Current Traffic Policies", - "show queueing", - "RIP", - "IP RIP", - "show ip rip", - "RIP Status", - "show ip rip status", - "RIP Debugging Information", - "show monitoring protocols rip", - "RIPNG", - "RIPNG Debugging Information", - "show monitoring protocols ripng", - "VPN-L2TP", - "VPN ike secrets", - "show vpn ike secrets", - "VPN rsa-keys", - "show vpn ike rsa-keys", - "VPN ike sa", - "show vpn ike sa", - "VPN ike Status", - "show vpn ike status", - "VPN Remote-Access", - "show vpn remote-access", - "VPN Debug Detail", - "show vpn debug detail", - "VPN-PPTP", - "VPN Remote-Access", - "show vpn remote-access", - "VRRP", - # XXX: not checking if configured, we'd have to walk all VIFs - "show vrrp detail", - "WAN LOAD BALANCING", - "Wan Load Balance", - "show wan-load-balance", - "Wan Load Balance Status", - "show wan-load-balance status", - "Wan Load Balance Connection", - "show wan-load-balance connection", - "WEBPROXY/URL-FILTERING", - "WebProxy Blacklist Categories", - "show webproxy blacklist categories", - "WebProxy Blacklist Domains", - "show webproxy blacklist domains", - "WebProxy Blacklist URLs", - "show webproxy blacklist urls", - "WebProxy Blacklist Log", - "show webproxy blacklist log summary", -] - - -def VyOS(cmd): - for command_line in cmd: - if command_line.startswith("show"): - call(f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {command_line}') - elif command_line.startswith("cat"): - call(command_line) - else: - header(command_line) - return - - -###################### execute all the commands ###################### - -header('CONFIGURATION') -CONFIGURATION(cmd_list_conf) - -header('INTERFACES') -INTERFACES(cmd_list_int) - -header('ROUTING') -ROUTING(cmd_list_route) - -header('IPTABLES') -IPTABLES(cmd_list_iptables) - -header('SYSTEM') -SYSTEM(cmd_list_system) - -header('PROCESSES') -PROCESSES(cmd_list_processes) - -header('CORE') -CORE(cmd_list_core) - -header('VyOS Information') -VyOS(cmd_list_vyos) + +def print_header(command: str) -> None: + """Prints a command with headers '-'. + + Example: + + % print_header('Example command') + + --------------- + Example command + --------------- + """ + header_length = len(command) * '-' + print(f"\n{header_length}\n{command}\n{header_length}") + + +def execute_command(command: str, header_text: str) -> None: + """Executes a command and prints the output with a header. + + Example: + % execute_command('uptime', "Uptime of the system") + + -------------------- + Uptime of the system + -------------------- + 20:21:57 up 9:04, 5 users, load average: 0.00, 0.00, 0.0 + + """ + print_header(header_text) + try: + rc, output = rc_cmd(command) + print(output) + except Exception as e: + print(f"Error executing command: {command}") + print(f"Error message: {e}") + + +def op(cmd: str) -> str: + """Returns a command with the VyOS operational mode wrapper.""" + return f'/opt/vyatta/bin/vyatta-op-cmd-wrapper {cmd}' + + +def get_ethernet_interfaces() -> List[Interface]: + """Returns a list of Ethernet interfaces.""" + return Section.interfaces('ethernet') + + +def show_version() -> None: + """Prints the VyOS version and package changes.""" + execute_command(op('show version'), 'VyOS Version and Package Changes') + + +def show_config_file() -> None: + """Prints the contents of a configuration file with a header.""" + execute_command('cat /opt/vyatta/etc/config/config.boot', 'Configuration file') + + +def show_running_config() -> None: + """Prints the running configuration.""" + execute_command(op('show configuration'), 'Running configuration') + + +def show_package_repository_config() -> None: + """Prints the package repository configuration file.""" + execute_command('cat /etc/apt/sources.list', 'Package Repository Configuration File') + execute_command('ls -l /etc/apt/sources.list.d/', 'Repositories') + + +def show_user_startup_scripts() -> None: + """Prints the user startup scripts.""" + execute_command('cat /config/scripts/vyos-postconfig-bootup.script', 'User Startup Scripts') + + +def show_frr_config() -> None: + """Prints the FRR configuration.""" + execute_command('vtysh -c "show run"', 'FRR configuration') + + +def show_interfaces() -> None: + """Prints the interfaces.""" + execute_command(op('show interfaces'), 'Interfaces') + + +def show_interface_statistics() -> None: + """Prints the interface statistics.""" + execute_command('ip -s link show', 'Interface statistics') + + +def show_physical_interface_statistics() -> None: + """Prints the physical interface statistics.""" + execute_command('/usr/bin/true', 'Physical Interface statistics') + for iface in get_ethernet_interfaces(): + # Exclude vlans + if '.' in iface: + continue + execute_command(f'ethtool --driver {iface}', f'ethtool --driver {iface}') + execute_command(f'ethtool --statistics {iface}', f'ethtool --statistics {iface}') + execute_command(f'ethtool --show-ring {iface}', f'ethtool --show-ring {iface}') + execute_command(f'ethtool --show-coalesce {iface}', f'ethtool --show-coalesce {iface}') + execute_command(f'ethtool --pause {iface}', f'ethtool --pause {iface}') + execute_command(f'ethtool --show-features {iface}', f'ethtool --show-features {iface}') + execute_command(f'ethtool --phy-statistics {iface}', f'ethtool --phy-statistics {iface}') + execute_command('netstat --interfaces', 'netstat --interfaces') + execute_command('netstat --listening', 'netstat --listening') + execute_command('cat /proc/net/dev', 'cat /proc/net/dev') + + +def show_bridge() -> None: + """Show bridge interfaces.""" + execute_command(op('show bridge'), 'Show bridge') + + +def show_arp() -> None: + """Prints ARP entries.""" + execute_command(op('show arp'), 'ARP Table (Total entries)') + execute_command(op('show ipv6 neighbors'), 'show ipv6 neighbors') + + +def show_route() -> None: + """Prints routing information.""" + + cmd_list_route = [ + "show ip route bgp | head -108", + "show ip route cache", + "show ip route connected", + "show ip route forward", + "show ip route isis | head -108", + "show ip route kernel", + "show ip route ospf | head -108", + "show ip route rip", + "show ip route static", + "show ip route summary", + "show ip route supernets-only", + "show ip route table all", + "show ip route vrf all", + "show ipv6 route bgp | head 108", + "show ipv6 route cache", + "show ipv6 route connected", + "show ipv6 route forward", + "show ipv6 route isis", + "show ipv6 route kernel", + "show ipv6 route ospf", + "show ipv6 route rip", + "show ipv6 route static", + "show ipv6 route summary", + "show ipv6 route table all", + "show ipv6 route vrf all", + ] + for command in cmd_list_route: + execute_command(op(command), command) + + +def show_firewall() -> None: + """Prints firweall information.""" + execute_command('sudo nft list ruleset', 'nft list ruleset') + + +def show_system() -> None: + """Prints system parameters.""" + execute_command(op('show system image version'), 'Show System Image Version') + execute_command(op('show system image storage'), 'Show System Image Storage') + + +def show_date() -> None: + """Print the current date.""" + execute_command('date', 'Current Time') + + +def show_installed_packages() -> None: + """Prints installed packages.""" + execute_command('dpkg --list', 'Installed Packages') + + +def show_loaded_modules() -> None: + """Prints loaded modules /proc/modules""" + execute_command('cat /proc/modules', 'Loaded Modules') + + +def show_cpu_statistics() -> None: + """Prints CPU statistics.""" + execute_command('/usr/bin/true', 'CPU') + execute_command('lscpu', 'Installed CPU\'s') + execute_command('top --iterations 1 --batch-mode --accum-time-toggle', 'Cumulative CPU Time Used by Running Processes') + execute_command('cat /proc/loadavg', 'Load Average') + + +def show_system_interrupts() -> None: + """Prints system interrupts.""" + execute_command('cat /proc/interrupts', 'Hardware Interrupt Counters') + + +def show_soft_irqs() -> None: + """Prints soft IRQ's.""" + execute_command('cat /proc/softirqs', 'Soft IRQ\'s') + + +def show_softnet_statistics() -> None: + """Prints softnet statistics.""" + execute_command('cat /proc/net/softnet_stat', 'cat /proc/net/softnet_stat') + + +def show_running_processes() -> None: + """Prints current running processes""" + execute_command('ps -ef', 'Running Processes') + + +def show_memory_usage() -> None: + """Prints memory usage""" + execute_command('/usr/bin/true', 'Memory') + execute_command('cat /proc/meminfo', 'Installed Memory') + execute_command('free', 'Memory Usage') + + +def list_disks(): + disks = set() + with open('/proc/partitions') as partitions_file: + for line in partitions_file: + fields = line.strip().split() + if len(fields) == 4 and fields[3].isalpha() and fields[3] != 'name': + disks.add(fields[3]) + return disks + + +def show_storage() -> None: + """Prints storage information.""" + execute_command('cat /proc/devices', 'Devices') + execute_command('cat /proc/partitions', 'Partitions') + + for disk in list_disks(): + execute_command(f'fdisk --list /dev/{disk}', f'Partitioning for disk {disk}') + + +def main(): + # Configuration data + show_version() + show_config_file() + show_running_config() + show_package_repository_config() + show_user_startup_scripts() + show_frr_config() + + # Interfaces + show_interfaces() + show_interface_statistics() + show_physical_interface_statistics() + show_bridge() + show_arp() + + # Routing + show_route() + + # Firewall + show_firewall() + + # System + show_system() + show_date() + show_installed_packages() + show_loaded_modules() + + # CPU + show_cpu_statistics() + show_system_interrupts() + show_soft_irqs() + show_softnet_statistics() + + # Memory + show_memory_usage() + + # Storage + show_storage() + + # Processes + show_running_processes() + + # TODO: Get information from clouds + + +if __name__ == "__main__": + main() diff --git a/src/op_mode/show_vpn_ra.py b/src/op_mode/show_vpn_ra.py deleted file mode 100755 index 73688c4ea..000000000 --- a/src/op_mode/show_vpn_ra.py +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env python3 -# -# Copyright (C) 2019 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 os -import sys -import re - -from vyos.util import popen - -# chech connection to pptp and l2tp daemon -def get_sessions(): - absent_pptp = False - absent_l2tp = False - pptp_cmd = "accel-cmd -p 2003 show sessions" - l2tp_cmd = "accel-cmd -p 2004 show sessions" - err_pattern = "^Connection.+failed$" - # This value for chack only output header without sessions. - len_def_header = 170 - - # Check pptp - output, err = popen(pptp_cmd, decode='utf-8') - if not err and len(output) > len_def_header and not re.search(err_pattern, output): - print(output) - else: - absent_pptp = True - - # Check l2tp - output, err = popen(l2tp_cmd, decode='utf-8') - if not err and len(output) > len_def_header and not re.search(err_pattern, output): - print(output) - else: - absent_l2tp = True - - if absent_l2tp and absent_pptp: - print("No active remote access VPN sessions") - - -def main(): - get_sessions() - - -if __name__ == '__main__': - main() diff --git a/src/op_mode/show_wwan.py b/src/op_mode/show_wwan.py index 529b5bd0f..eb601a456 100755 --- a/src/op_mode/show_wwan.py +++ b/src/op_mode/show_wwan.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -# Copyright (C) 2021 VyOS maintainers and contributors +# Copyright (C) 2021-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 @@ -17,6 +17,7 @@ import argparse from sys import exit +from vyos.configquery import ConfigTreeQuery from vyos.util import cmd parser = argparse.ArgumentParser() @@ -49,6 +50,11 @@ def qmi_cmd(device, command, silent=False): if __name__ == '__main__': args = parser.parse_args() + tmp = ConfigTreeQuery() + if not tmp.exists(['interfaces', 'wwan', args.interface]): + print(f'Interface "{args.interface}" unconfigured!') + exit(1) + # remove the WWAN prefix from the interface, required for the CDC interface if_num = args.interface.replace('wwan','') cdc = f'/dev/cdc-wdm{if_num}' |