summaryrefslogtreecommitdiff
path: root/python/vyos
diff options
context:
space:
mode:
Diffstat (limited to 'python/vyos')
-rw-r--r--python/vyos/accel_ppp.py3
-rw-r--r--python/vyos/config_mgmt.py43
-rw-r--r--python/vyos/configtree.py32
-rw-r--r--python/vyos/configverify.py28
-rw-r--r--python/vyos/defaults.py39
-rw-r--r--python/vyos/ifconfig/interface.py6
-rw-r--r--python/vyos/ifconfig/loopback.py2
-rw-r--r--python/vyos/ifconfig/tunnel.py14
-rw-r--r--python/vyos/ipsec.py141
-rw-r--r--python/vyos/template.py20
10 files changed, 264 insertions, 64 deletions
diff --git a/python/vyos/accel_ppp.py b/python/vyos/accel_ppp.py
index bfc8ee5a9..0af311e57 100644
--- a/python/vyos/accel_ppp.py
+++ b/python/vyos/accel_ppp.py
@@ -38,6 +38,9 @@ def get_server_statistics(accel_statistics, pattern, sep=':') -> dict:
if key in ['starting', 'active', 'finishing']:
stat_dict['sessions'][key] = value.strip()
continue
+ if key == 'cpu':
+ stat_dict['cpu_load_percentage'] = int(re.sub(r'%', '', value.strip()))
+ continue
stat_dict[key] = value.strip()
return stat_dict
diff --git a/python/vyos/config_mgmt.py b/python/vyos/config_mgmt.py
index 22a49ff50..fade3081c 100644
--- a/python/vyos/config_mgmt.py
+++ b/python/vyos/config_mgmt.py
@@ -24,7 +24,7 @@ from datetime import datetime
from tabulate import tabulate
from vyos.config import Config
-from vyos.configtree import ConfigTree
+from vyos.configtree import ConfigTree, ConfigTreeError, show_diff
from vyos.defaults import directories
from vyos.util import is_systemd_service_active, ask_yes_no, rc_cmd
@@ -93,15 +93,7 @@ class ConfigMgmt:
# a call to compare without args is edit_level aware
edit_level = os.getenv('VYATTA_EDIT_LEVEL', '')
- edit_path = [l for l in edit_level.split('/') if l]
- if edit_path:
- eff_conf = config.show_config(edit_path, effective=True)
- self.edit_level_active_config = ConfigTree(eff_conf)
- conf = config.show_config(edit_path)
- self.edit_level_working_config = ConfigTree(conf)
- else:
- self.edit_level_active_config = None
- self.edit_level_working_config = None
+ self.edit_path = [l for l in edit_level.split('/') if l]
self.active_config = config._running_config
self.working_config = config._session_config
@@ -241,14 +233,8 @@ Proceed ?'''
revision n vs. revision m; working version vs. active version;
or working version vs. saved version.
"""
- from difflib import unified_diff
-
- ct1 = self.edit_level_active_config
- if ct1 is None:
- ct1 = self.active_config
- ct2 = self.edit_level_working_config
- if ct2 is None:
- ct2 = self.working_config
+ ct1 = self.active_config
+ ct2 = self.working_config
msg = 'No changes between working and active configurations.\n'
if saved:
ct1 = self._get_saved_config_tree()
@@ -268,19 +254,16 @@ Proceed ?'''
ct1 = self._get_config_tree_revision(rev2)
msg = f'No changes between revisions {rev2} and {rev1} configurations.\n'
- if commands:
- lines1 = ct1.to_commands().splitlines(keepends=True)
- lines2 = ct2.to_commands().splitlines(keepends=True)
- else:
- lines1 = ct1.to_string().splitlines(keepends=True)
- lines2 = ct2.to_string().splitlines(keepends=True)
-
out = ''
- comp = unified_diff(lines1, lines2)
- for line in comp:
- if re.match(r'(\-\-)|(\+\+)|(@@)', line):
- continue
- out += line
+ path = [] if commands else self.edit_path
+ try:
+ if commands:
+ out = show_diff(ct1, ct2, path=path, commands=True)
+ else:
+ out = show_diff(ct1, ct2, path=path)
+ except ConfigTreeError as e:
+ return e, 1
+
if out:
msg = out
diff --git a/python/vyos/configtree.py b/python/vyos/configtree.py
index f2358ee4f..c0b3ebd78 100644
--- a/python/vyos/configtree.py
+++ b/python/vyos/configtree.py
@@ -16,7 +16,7 @@ import os
import re
import json
-from ctypes import cdll, c_char_p, c_void_p, c_int
+from ctypes import cdll, c_char_p, c_void_p, c_int, c_bool
LIBPATH = '/usr/lib/libvyosconfig.so.0'
@@ -322,6 +322,36 @@ class ConfigTree(object):
subt = ConfigTree(address=res)
return subt
+def show_diff(left, right, path=[], commands=False, libpath=LIBPATH):
+ if left is None:
+ left = ConfigTree(config_string='\n')
+ if right is None:
+ right = ConfigTree(config_string='\n')
+ if not (isinstance(left, ConfigTree) and isinstance(right, ConfigTree)):
+ raise TypeError("Arguments must be instances of ConfigTree")
+ if path:
+ if (not left.exists(path)) and (not right.exists(path)):
+ raise ConfigTreeError(f"Path {path} doesn't exist")
+
+ check_path(path)
+ path_str = " ".join(map(str, path)).encode()
+
+ __lib = cdll.LoadLibrary(libpath)
+ __show_diff = __lib.show_diff
+ __show_diff.argtypes = [c_bool, c_char_p, c_void_p, c_void_p]
+ __show_diff.restype = c_char_p
+ __get_error = __lib.get_error
+ __get_error.argtypes = []
+ __get_error.restype = c_char_p
+
+ res = __show_diff(commands, path_str, left._get_config(), right._get_config())
+ res = res.decode()
+ if res == "#1@":
+ msg = __get_error().decode()
+ raise ConfigTreeError(msg)
+
+ return res
+
class DiffTree:
def __init__(self, left, right, path=[], libpath=LIBPATH):
if left is None:
diff --git a/python/vyos/configverify.py b/python/vyos/configverify.py
index 8e0ce701e..8fddd91d0 100644
--- a/python/vyos/configverify.py
+++ b/python/vyos/configverify.py
@@ -1,4 +1,4 @@
-# Copyright 2020-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2020-2023 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -23,6 +23,7 @@
from vyos import ConfigError
from vyos.util import dict_search
+from vyos.util import dict_search_recursive
def verify_mtu(config):
"""
@@ -35,8 +36,14 @@ def verify_mtu(config):
mtu = int(config['mtu'])
tmp = Interface(config['ifname'])
- min_mtu = tmp.get_min_mtu()
- max_mtu = tmp.get_max_mtu()
+ # Not all interfaces support min/max MTU
+ # https://vyos.dev/T5011
+ try:
+ min_mtu = tmp.get_min_mtu()
+ max_mtu = tmp.get_max_mtu()
+ except: # Fallback to defaults
+ min_mtu = 68
+ max_mtu = 9000
if mtu < min_mtu:
raise ConfigError(f'Interface MTU too low, ' \
@@ -232,7 +239,7 @@ def verify_authentication(config):
"""
if 'authentication' not in config:
return
- if not {'user', 'password'} <= set(config['authentication']):
+ if not {'username', 'password'} <= set(config['authentication']):
raise ConfigError('Authentication requires both username and ' \
'password to be set!')
@@ -414,7 +421,18 @@ def verify_accel_ppp_base_service(config, local_users=True):
if 'key' not in radius_config:
raise ConfigError(f'Missing RADIUS secret key for server "{server}"')
- if 'gateway_address' not in config:
+ # Check global gateway or gateway in named pool
+ gateway = False
+ if 'gateway_address' in config:
+ gateway = True
+ else:
+ if 'client_ip_pool' in config:
+ if dict_search_recursive(config, 'gateway_address', ['client_ip_pool', 'name']):
+ for _, v in config['client_ip_pool']['name'].items():
+ if 'gateway_address' in v:
+ gateway = True
+ break
+ if not gateway:
raise ConfigError('Server requires gateway-address to be configured!')
if 'name_server_ipv4' in config:
diff --git a/python/vyos/defaults.py b/python/vyos/defaults.py
index 7de458960..db0def8ed 100644
--- a/python/vyos/defaults.py
+++ b/python/vyos/defaults.py
@@ -1,4 +1,4 @@
-# Copyright 2018 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2018-2023 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -15,19 +15,22 @@
import os
+base_dir = '/usr/libexec/vyos/'
+
directories = {
- "data": "/usr/share/vyos/",
- "conf_mode": "/usr/libexec/vyos/conf_mode",
- "op_mode": "/usr/libexec/vyos/op_mode",
- "config": "/opt/vyatta/etc/config",
- "current": "/opt/vyatta/etc/config-migrate/current",
- "migrate": "/opt/vyatta/etc/config-migrate/migrate",
- "log": "/var/log/vyatta",
- "templates": "/usr/share/vyos/templates/",
- "certbot": "/config/auth/letsencrypt",
- "api_schema": "/usr/libexec/vyos/services/api/graphql/graphql/schema/",
- "api_templates": "/usr/libexec/vyos/services/api/graphql/session/templates/",
- "vyos_udev_dir": "/run/udev/vyos"
+ 'base' : base_dir,
+ 'data' : '/usr/share/vyos/',
+ 'conf_mode' : f'{base_dir}/conf_mode',
+ 'op_mode' : f'{base_dir}/op_mode',
+ 'config' : '/opt/vyatta/etc/config',
+ 'current' : '/opt/vyatta/etc/config-migrate/current',
+ 'migrate' : '/opt/vyatta/etc/config-migrate/migrate',
+ 'log' : '/var/log/vyatta',
+ 'templates' : '/usr/share/vyos/templates/',
+ 'certbot' : '/config/auth/letsencrypt',
+ 'api_schema': f'{base_dir}/services/api/graphql/graphql/schema/',
+ 'api_templates': f'{base_dir}/services/api/graphql/session/templates/',
+ 'vyos_udev_dir' : '/run/udev/vyos'
}
config_status = '/tmp/vyos-config-status'
@@ -50,12 +53,12 @@ api_data = {
'socket' : False,
'strict' : False,
'debug' : False,
- 'api_keys' : [ {"id": "testapp", "key": "qwerty"} ]
+ 'api_keys' : [ {'id' : 'testapp', 'key' : 'qwerty'} ]
}
vyos_cert_data = {
- "conf": "/etc/nginx/snippets/vyos-cert.conf",
- "crt": "/etc/ssl/certs/vyos-selfsigned.crt",
- "key": "/etc/ssl/private/vyos-selfsign",
- "lifetime": "365",
+ 'conf' : '/etc/nginx/snippets/vyos-cert.conf',
+ 'crt' : '/etc/ssl/certs/vyos-selfsigned.crt',
+ 'key' : '/etc/ssl/private/vyos-selfsign',
+ 'lifetime' : '365',
}
diff --git a/python/vyos/ifconfig/interface.py b/python/vyos/ifconfig/interface.py
index c50ead89f..fc33430eb 100644
--- a/python/vyos/ifconfig/interface.py
+++ b/python/vyos/ifconfig/interface.py
@@ -751,8 +751,8 @@ class Interface(Control):
elif all_rp_filter == 2: global_setting = 'loose'
from vyos.base import Warning
- Warning(f'Global source-validation is set to "{global_setting} '\
- f'this overrides per interface setting!')
+ Warning(f'Global source-validation is set to "{global_setting}", this '\
+ f'overrides per interface setting on "{self.ifname}"!')
tmp = self.get_interface('rp_filter')
if int(tmp) == value:
@@ -1365,7 +1365,7 @@ class Interface(Control):
if not isinstance(state, bool):
raise ValueError("Value out of range")
- # https://phabricator.vyos.net/T3448 - there is (yet) no RPI support for XDP
+ # https://vyos.dev/T3448 - there is (yet) no RPI support for XDP
if not os.path.exists('/usr/sbin/xdp_loader'):
return
diff --git a/python/vyos/ifconfig/loopback.py b/python/vyos/ifconfig/loopback.py
index b3babfadc..e1d041839 100644
--- a/python/vyos/ifconfig/loopback.py
+++ b/python/vyos/ifconfig/loopback.py
@@ -46,7 +46,7 @@ class LoopbackIf(Interface):
if addr in self._persistent_addresses:
# Do not allow deletion of the default loopback addresses as
# this will cause weird system behavior like snmp/ssh no longer
- # operating as expected, see https://phabricator.vyos.net/T2034.
+ # operating as expected, see https://vyos.dev/T2034.
continue
self.del_addr(addr)
diff --git a/python/vyos/ifconfig/tunnel.py b/python/vyos/ifconfig/tunnel.py
index 5258a2cb1..b7bf7d982 100644
--- a/python/vyos/ifconfig/tunnel.py
+++ b/python/vyos/ifconfig/tunnel.py
@@ -83,11 +83,6 @@ class TunnelIf(Interface):
'convert': enable_to_on,
'shellcmd': 'ip link set dev {ifname} multicast {value}',
},
- 'allmulticast': {
- 'validate': lambda v: assert_list(v, ['enable', 'disable']),
- 'convert': enable_to_on,
- 'shellcmd': 'ip link set dev {ifname} allmulticast {value}',
- },
}
}
@@ -162,6 +157,10 @@ class TunnelIf(Interface):
""" Get a synthetic MAC address. """
return self.get_mac_synthetic()
+ def set_multicast(self, enable):
+ """ Change the MULTICAST flag on the device """
+ return self.set_interface('multicast', enable)
+
def update(self, config):
""" General helper function which works on a dictionary retrived by
get_config_dict(). It's main intention is to consolidate the scattered
@@ -170,5 +169,10 @@ class TunnelIf(Interface):
# Adjust iproute2 tunnel parameters if necessary
self._change_options()
+ # IP Multicast
+ tmp = dict_search('enable_multicast', config)
+ value = 'enable' if (tmp != None) else 'disable'
+ self.set_multicast(value)
+
# call base class first
super().update(config)
diff --git a/python/vyos/ipsec.py b/python/vyos/ipsec.py
new file mode 100644
index 000000000..cb7c39ff6
--- /dev/null
+++ b/python/vyos/ipsec.py
@@ -0,0 +1,141 @@
+# Copyright 2020-2023 VyOS maintainers and contributors <maintainers@vyos.io>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library. If not, see <http://www.gnu.org/licenses/>.
+
+#Package to communicate with Strongswan VICI
+
+class ViciInitiateError(Exception):
+ """
+ VICI can't initiate a session.
+ """
+ pass
+class ViciCommandError(Exception):
+ """
+ VICI can't execute a command by any reason.
+ """
+ pass
+
+def get_vici_sas():
+ from vici import Session as vici_session
+
+ try:
+ session = vici_session()
+ except Exception:
+ raise ViciInitiateError("IPsec not initialized")
+ sas = list(session.list_sas())
+ return sas
+
+
+def get_vici_connections():
+ from vici import Session as vici_session
+
+ try:
+ session = vici_session()
+ except Exception:
+ raise ViciInitiateError("IPsec not initialized")
+ connections = list(session.list_conns())
+ return connections
+
+
+def get_vici_sas_by_name(ike_name: str, tunnel: str) -> list:
+ """
+ Find sas by IKE_SA name and/or CHILD_SA name
+ and return list of OrdinaryDicts with SASs info
+ If tunnel is not None return value is list of OrdenaryDicts contained only
+ CHILD_SAs wich names equal tunnel value.
+ :param ike_name: IKE SA name
+ :type ike_name: str
+ :param tunnel: CHILD SA name
+ :type tunnel: str
+ :return: list of Ordinary Dicts with SASs
+ :rtype: list
+ """
+ from vici import Session as vici_session
+
+ try:
+ session = vici_session()
+ except Exception:
+ raise ViciInitiateError("IPsec not initialized")
+ vici_dict = {}
+ if ike_name:
+ vici_dict['ike'] = ike_name
+ if tunnel:
+ vici_dict['child'] = tunnel
+ try:
+ sas = list(session.list_sas(vici_dict))
+ return sas
+ except Exception:
+ raise ViciCommandError(f'Failed to get SAs')
+
+
+def terminate_vici_ikeid_list(ike_id_list: list) -> None:
+ """
+ Terminate IKE SAs by their id that contained in the list
+ :param ike_id_list: list of IKE SA id
+ :type ike_id_list: list
+ """
+ from vici import Session as vici_session
+
+ try:
+ session = vici_session()
+ except Exception:
+ raise ViciInitiateError("IPsec not initialized")
+ try:
+ for ikeid in ike_id_list:
+ session_generator = session.terminate(
+ {'ike-id': ikeid, 'timeout': '-1'})
+ # a dummy `for` loop is required because of requirements
+ # from vici. Without a full iteration on the output, the
+ # command to vici may not be executed completely
+ for _ in session_generator:
+ pass
+ except Exception:
+ raise ViciCommandError(
+ f'Failed to terminate SA for IKE ids {ike_id_list}')
+
+
+def terminate_vici_by_name(ike_name: str, child_name: str) -> None:
+ """
+ Terminate IKE SAs by name if CHILD SA name is None.
+ Terminate CHILD SAs by name if CHILD SA name is specified
+ :param ike_name: IKE SA name
+ :type ike_name: str
+ :param child_name: CHILD SA name
+ :type child_name: str
+ """
+ from vici import Session as vici_session
+
+ try:
+ session = vici_session()
+ except Exception:
+ raise ViciInitiateError("IPsec not initialized")
+ try:
+ vici_dict: dict= {}
+ if ike_name:
+ vici_dict['ike'] = ike_name
+ if child_name:
+ vici_dict['child'] = child_name
+ session_generator = session.terminate(vici_dict)
+ # a dummy `for` loop is required because of requirements
+ # from vici. Without a full iteration on the output, the
+ # command to vici may not be executed completely
+ for _ in session_generator:
+ pass
+ except Exception:
+ if child_name:
+ raise ViciCommandError(
+ f'Failed to terminate SA for IPSEC {child_name}')
+ else:
+ raise ViciCommandError(
+ f'Failed to terminate SA for IKE {ike_name}')
diff --git a/python/vyos/template.py b/python/vyos/template.py
index 15240f815..6367f51e5 100644
--- a/python/vyos/template.py
+++ b/python/vyos/template.py
@@ -1,4 +1,4 @@
-# Copyright 2019-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -158,6 +158,24 @@ def force_to_list(value):
else:
return [value]
+@register_filter('seconds_to_human')
+def seconds_to_human(seconds, separator=""):
+ """ Convert seconds to human-readable values like 1d6h15m23s """
+ from vyos.util import seconds_to_human
+ return seconds_to_human(seconds, separator=separator)
+
+@register_filter('bytes_to_human')
+def bytes_to_human(bytes, initial_exponent=0, precision=2):
+ """ Convert bytes to human-readable values like 1.44M """
+ from vyos.util import bytes_to_human
+ return bytes_to_human(bytes, initial_exponent=initial_exponent, precision=precision)
+
+@register_filter('human_to_bytes')
+def human_to_bytes(value):
+ """ Convert a data amount with a unit suffix to bytes, like 2K to 2048 """
+ from vyos.util import human_to_bytes
+ return human_to_bytes(value)
+
@register_filter('ip_from_cidr')
def ip_from_cidr(prefix):
""" Take an IPv4/IPv6 CIDR host and strip cidr mask.