diff options
25 files changed, 499 insertions, 145 deletions
diff --git a/data/configd-include.json b/data/configd-include.json index 2f1d39006..456211caa 100644 --- a/data/configd-include.json +++ b/data/configd-include.json @@ -85,5 +85,6 @@ "vpn_l2tp.py", "vpn_pptp.py", "vpn_sstp.py", -"vrf.py" +"vrf.py", +"vrf_vni.py" ] diff --git a/data/templates/frr/zebra.vrf.route-map.frr.j2 b/data/templates/frr/zebra.vrf.route-map.frr.j2 index eb6abd8e7..3c5791c4c 100644 --- a/data/templates/frr/zebra.vrf.route-map.frr.j2 +++ b/data/templates/frr/zebra.vrf.route-map.frr.j2 @@ -18,7 +18,7 @@ vrf {{ vrf }} {% if vrf_config.vni is vyos_defined %} vni {{ vrf_config.vni }} {% endif %} +exit-vrf {% endfor %} - exit-vrf ! {% endif %} diff --git a/debian/control b/debian/control index 3126e6ad9..4a2706fc3 100644 --- a/debian/control +++ b/debian/control @@ -16,7 +16,7 @@ Build-Depends: build-essential, libvyosconfig0 (>= 0.0.7), libzmq3-dev, - python3, + python3 (>= 3.10), python3-coverage, python3-lxml, python3-netifaces, @@ -33,7 +33,7 @@ Standards-Version: 3.9.6 Package: vyos-1x Architecture: amd64 arm64 Depends: - ${python3:Depends}, + ${python3:Depends} (>= 3.10), aardvark-dns, accel-ppp, auditd, diff --git a/interface-definitions/include/bgp/protocol-common-config.xml.i b/interface-definitions/include/bgp/protocol-common-config.xml.i index 527eaf991..bcc131f83 100644 --- a/interface-definitions/include/bgp/protocol-common-config.xml.i +++ b/interface-definitions/include/bgp/protocol-common-config.xml.i @@ -810,12 +810,6 @@ </node> </children> </node> - <leafNode name="advertise-all-vni"> - <properties> - <help>Advertise All local VNIs</help> - <valueless/> - </properties> - </leafNode> #include <include/bgp/afi-l2vpn-common.xml.i> <leafNode name="advertise-pip"> <properties> diff --git a/interface-definitions/protocols-bgp.xml.in b/interface-definitions/protocols-bgp.xml.in index e1a822999..78b461f9d 100644 --- a/interface-definitions/protocols-bgp.xml.in +++ b/interface-definitions/protocols-bgp.xml.in @@ -9,6 +9,20 @@ </properties> <children> #include <include/bgp/protocol-common-config.xml.i> + <node name="address-family"> + <children> + <node name="l2vpn-evpn"> + <children> + <leafNode name="advertise-all-vni"> + <properties> + <help>Advertise all local VNIs</help> + <valueless/> + </properties> + </leafNode> + </children> + </node> + </children> + </node> </children> </node> </children> diff --git a/interface-definitions/vrf.xml.in b/interface-definitions/vrf.xml.in index a7efe146a..3783785ce 100644 --- a/interface-definitions/vrf.xml.in +++ b/interface-definitions/vrf.xml.in @@ -121,7 +121,20 @@ <constraintErrorMessage>VRF routing table must be in range from 100 to 65535</constraintErrorMessage> </properties> </leafNode> - #include <include/vni.xml.i> + <leafNode name="vni" owner="${vyos_conf_scripts_dir}/vrf_vni.py $VAR(../@)"> + <properties> + <help>Virtual Network Identifier</help> + <!-- must be after BGP to keep correct order when removing L3VNIs in FRR --> + <priority>822</priority> + <valueHelp> + <format>u32:0-16777214</format> + <description>VXLAN virtual network identifier</description> + </valueHelp> + <constraint> + <validator name="numeric" argument="--range 0-16777214"/> + </constraint> + </properties> + </leafNode> </children> </tagNode> </children> diff --git a/op-mode-definitions/include/bgp/evpn-type-1.xml.i b/op-mode-definitions/include/bgp/evpn-type-1.xml.i new file mode 100644 index 000000000..b5097c8b1 --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-1.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-1.xml.i --> +<leafNode name="1"> + <properties> + <help>EAD (Type-1) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-2.xml.i b/op-mode-definitions/include/bgp/evpn-type-2.xml.i new file mode 100644 index 000000000..827298d62 --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-2.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-2.xml.i --> +<leafNode name="2"> + <properties> + <help>MAC-IP (Type-2) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-3.xml.i b/op-mode-definitions/include/bgp/evpn-type-3.xml.i new file mode 100644 index 000000000..ae90b2e5c --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-3.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-3.xml.i --> +<leafNode name="3"> + <properties> + <help>Multicast (Type-3) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-4.xml.i b/op-mode-definitions/include/bgp/evpn-type-4.xml.i new file mode 100644 index 000000000..7248b4753 --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-4.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-4.xml.i --> +<leafNode name="4"> + <properties> + <help>Ethernet Segment (Type-4) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-5.xml.i b/op-mode-definitions/include/bgp/evpn-type-5.xml.i new file mode 100644 index 000000000..e3a72168a --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-5.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-5.xml.i --> +<leafNode name="5"> + <properties> + <help>Prefix (Type-5) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-ead.xml.i b/op-mode-definitions/include/bgp/evpn-type-ead.xml.i new file mode 100644 index 000000000..452de2f9a --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-ead.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-ead.xml.i --> +<leafNode name="ead"> + <properties> + <help>EAD (Type-1) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-es.xml.i b/op-mode-definitions/include/bgp/evpn-type-es.xml.i new file mode 100644 index 000000000..50c40151a --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-es.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-es.xml.i --> +<leafNode name="es"> + <properties> + <help>Ethernet Segment (Type-4) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-macip.xml.i b/op-mode-definitions/include/bgp/evpn-type-macip.xml.i new file mode 100644 index 000000000..6f601eb3f --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-macip.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-macip.xml.i --> +<leafNode name="macip"> + <properties> + <help>MAC-IP (Type-2) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-multicast.xml.i b/op-mode-definitions/include/bgp/evpn-type-multicast.xml.i new file mode 100644 index 000000000..5194dbb56 --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-multicast.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-multicast.xml.i --> +<leafNode name="multicast"> + <properties> + <help>Multicast (Type-3) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/evpn-type-prefix.xml.i b/op-mode-definitions/include/bgp/evpn-type-prefix.xml.i new file mode 100644 index 000000000..d5054d86b --- /dev/null +++ b/op-mode-definitions/include/bgp/evpn-type-prefix.xml.i @@ -0,0 +1,8 @@ +<!-- included start from bgp/evpn-type-prefix.xml.i --> +<leafNode name="prefix"> + <properties> + <help>Prefix (Type-5) route</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> +</leafNode> +<!-- included end --> diff --git a/op-mode-definitions/include/bgp/show-bgp-common.xml.i b/op-mode-definitions/include/bgp/show-bgp-common.xml.i index c9a112fca..de794a879 100644 --- a/op-mode-definitions/include/bgp/show-bgp-common.xml.i +++ b/op-mode-definitions/include/bgp/show-bgp-common.xml.i @@ -171,66 +171,16 @@ <help>Specify Route type</help> </properties> <children> - <leafNode name="1"> - <properties> - <help>EAD (Type-1) route</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> - <leafNode name="2"> - <properties> - <help>MAC-IP (Type-2) route</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> - <leafNode name="3"> - <properties> - <help>Multicast (Type-3) route</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> - <leafNode name="4"> - <properties> - <help>Ethernet Segment (Type-4) route</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> - <leafNode name="5"> - <properties> - <help>Prefix (Type-5) route</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> - <leafNode name="ead"> - <properties> - <help>EAD (Type-1) route</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> - <leafNode name="es"> - <properties> - <help>Ethernet Segment (Type-4) route</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> - <leafNode name="macip"> - <properties> - <help>MAC-IP (Type-2) route</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> - <leafNode name="multicast"> - <properties> - <help>Multicast (Type-3) route</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> - <leafNode name="prefix"> - <properties> - <help>Prefix (Type-5) route</help> - </properties> - <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> - </leafNode> + #include <include/bgp/evpn-type-1.xml.i> + #include <include/bgp/evpn-type-2.xml.i> + #include <include/bgp/evpn-type-3.xml.i> + #include <include/bgp/evpn-type-4.xml.i> + #include <include/bgp/evpn-type-5.xml.i> + #include <include/bgp/evpn-type-ead.xml.i> + #include <include/bgp/evpn-type-es.xml.i> + #include <include/bgp/evpn-type-macip.xml.i> + #include <include/bgp/evpn-type-multicast.xml.i> + #include <include/bgp/evpn-type-prefix.xml.i> </children> </node> #include <include/vni-tagnode-all.xml.i> diff --git a/op-mode-definitions/include/ospf-common.xml.i b/op-mode-definitions/include/ospf-common.xml.i index aebbae5ff..979ffb07e 100644 --- a/op-mode-definitions/include/ospf-common.xml.i +++ b/op-mode-definitions/include/ospf-common.xml.i @@ -541,10 +541,19 @@ </properties> <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> </tagNode> -<leafNode name="route"> +<node name="route"> <properties> <help>Show IPv4 OSPF route information</help> </properties> <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> -</leafNode> -<!-- included end -->
\ No newline at end of file + <children> + <leafNode name="detail"> + <properties> + <help>Show detailed IPv4 OSPF route information</help> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </leafNode> + </children> +</node> +<!-- included end --> + diff --git a/op-mode-definitions/show-bgp.xml.in b/op-mode-definitions/show-bgp.xml.in index 974147621..3c212614c 100644 --- a/op-mode-definitions/show-bgp.xml.in +++ b/op-mode-definitions/show-bgp.xml.in @@ -51,6 +51,33 @@ </properties> <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> </leafNode> + #include <include/vni-tagnode-all.xml.i> + <tagNode name="vni"> + <children> + <tagNode name="vtep"> + <properties> + <help>Remote VTEP IP address</help> + <completionHelp> + <list><x.x.x.x></list> + </completionHelp> + </properties> + <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command> + </tagNode> + <node name="type"> + <properties> + <help>Display number of prefixes for all afi/safi</help> + </properties> + <children> + #include <include/bgp/evpn-type-1.xml.i> + #include <include/bgp/evpn-type-2.xml.i> + #include <include/bgp/evpn-type-3.xml.i> + #include <include/bgp/evpn-type-ead.xml.i> + #include <include/bgp/evpn-type-macip.xml.i> + #include <include/bgp/evpn-type-multicast.xml.i> + </children> + </node> + </children> + </tagNode> <leafNode name="vrf"> <properties> <help>Show BGP VRF information</help> diff --git a/op-mode-definitions/vpn-ipsec.xml.in b/op-mode-definitions/vpn-ipsec.xml.in index 5a7e6dd63..1eb5a3709 100644 --- a/op-mode-definitions/vpn-ipsec.xml.in +++ b/op-mode-definitions/vpn-ipsec.xml.in @@ -204,12 +204,37 @@ </properties> <command>sudo ip xfrm policy list</command> </node> - <leafNode name="remote-access"> - <properties> - <help>Show active VPN server sessions</help> - </properties> - <command>${vyos_op_scripts_dir}/show_vpn_ra.py</command> - </leafNode> + <node name="remote-access"> + <properties> + <help>Show active VPN server sessions</help> + </properties> + <children> + <node name="detail"> + <properties> + <help>Show detail active IKEv2 RA sessions</help> + </properties> + <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_ra_detail; else echo "IPsec process not running" ; fi</command> + </node> + <tagNode name="connection-id"> + <properties> + <help>Show detail active IKEv2 RA sessions by connection-id</help> + </properties> + <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_ra_detail --conn_id="$6"; else echo "IPsec process not running" ; fi</command> + </tagNode> + <node name="summary"> + <properties> + <help>Show active IKEv2 RA sessions summary</help> + </properties> + <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_ra_summary; else echo "IPsec process not running" ; fi</command> + </node> + <tagNode name="username"> + <properties> + <help>Show detail active IKEv2 RA sessions by username</help> + </properties> + <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_ra_detail --username="$6"; else echo "IPsec process not running" ; fi</command> + </tagNode> + </children> + </node> <node name="sa"> <properties> <help>Show all active IPsec Security Associations (SA)</help> @@ -241,11 +266,11 @@ <command></command> </tagNode> --> - <node name="verbose"> + <node name="detail"> <properties> <help>Show Verbose Detail on all active IPsec Security Associations (SA)</help> </properties> - <command>if systemctl is-active --quiet strongswan ; then sudo /usr/sbin/ipsec statusall ; else echo "IPsec process not running" ; fi</command> + <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_sa_detail ; else echo "IPsec process not running" ; fi</command> </node> </children> <command>if systemctl is-active --quiet strongswan ; then sudo ${vyos_op_scripts_dir}/ipsec.py show_sa ; else echo "IPsec process not running" ; fi</command> diff --git a/src/conf_mode/vrf_vni.py b/src/conf_mode/vrf_vni.py new file mode 100644 index 000000000..0cf52a2ef --- /dev/null +++ b/src/conf_mode/vrf_vni.py @@ -0,0 +1,86 @@ +#!/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/>. + +from sys import argv +from sys import exit + +from vyos.config import Config +from vyos.template import render_to_string +from vyos import ConfigError +from vyos import frr +from vyos import airbag +airbag.enable() + +def get_config(config=None): + if config: + conf = config + else: + conf = Config() + + vrf_name = None + if len(argv) > 1: + vrf_name = argv[1] + + base = ['vrf', 'name', vrf_name] + tmp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=False) + if not tmp: + return None + vrf = { 'name' : conf.get_config_dict(base, key_mangling=('-', '_'), + get_first_key=False) } + + return vrf + +def verify(vrf): + if not vrf: + return + + if len(argv) < 2: + raise ConfigError('VRF parameter not specified when valling vrf_vni.py') + + return None + +def generate(vrf): + if not vrf: + return + + vrf['new_frr_config'] = render_to_string('frr/zebra.vrf.route-map.frr.j2', vrf) + return None + +def apply(vrf): + frr_daemon = 'zebra' + + # add configuration to FRR + frr_cfg = frr.FRRConfig() + frr_cfg.load_configuration(frr_daemon) + # There is only one VRF inside the dict as we read only one in get_config() + if vrf and 'name' in vrf: + vrf_name = next(iter(vrf['name'])) + frr_cfg.modify_section(f'^vrf {vrf_name}', stop_pattern='^exit-vrf', remove_stop_mark=True) + if vrf and 'new_frr_config' in vrf: + frr_cfg.add_before(frr.default_add_before, vrf['new_frr_config']) + frr_cfg.commit_configuration(frr_daemon) + + return None + +if __name__ == '__main__': + try: + c = get_config() + verify(c) + generate(c) + apply(c) + except ConfigError as e: + print(e) + 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/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_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() |