summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/completion/list_ipsec_profile_tunnels.py5
-rwxr-xr-xsrc/completion/list_openvpn_clients.py5
-rwxr-xr-xsrc/completion/list_openvpn_users.py5
-rwxr-xr-xsrc/conf_mode/container.py18
-rwxr-xr-xsrc/conf_mode/firewall.py10
-rwxr-xr-xsrc/conf_mode/interfaces_bonding.py10
-rwxr-xr-xsrc/conf_mode/interfaces_ethernet.py34
-rwxr-xr-xsrc/conf_mode/interfaces_geneve.py8
-rwxr-xr-xsrc/conf_mode/interfaces_l2tpv3.py8
-rwxr-xr-xsrc/conf_mode/interfaces_loopback.py4
-rwxr-xr-xsrc/conf_mode/interfaces_macsec.py8
-rwxr-xr-xsrc/conf_mode/interfaces_openvpn.py11
-rwxr-xr-xsrc/conf_mode/interfaces_pppoe.py6
-rwxr-xr-xsrc/conf_mode/interfaces_pseudo-ethernet.py9
-rwxr-xr-xsrc/conf_mode/interfaces_tunnel.py11
-rwxr-xr-xsrc/conf_mode/interfaces_virtual-ethernet.py9
-rwxr-xr-xsrc/conf_mode/interfaces_vti.py4
-rwxr-xr-xsrc/conf_mode/interfaces_vxlan.py10
-rwxr-xr-xsrc/conf_mode/interfaces_wireguard.py3
-rwxr-xr-xsrc/conf_mode/load-balancing_reverse-proxy.py16
-rwxr-xr-xsrc/conf_mode/nat.py12
-rwxr-xr-xsrc/conf_mode/nat64.py3
-rwxr-xr-xsrc/conf_mode/nat66.py6
-rwxr-xr-xsrc/conf_mode/nat_cgnat.py288
-rwxr-xr-xsrc/conf_mode/netns.py5
-rwxr-xr-xsrc/conf_mode/policy_local-route.py11
-rwxr-xr-xsrc/conf_mode/policy_route.py4
-rwxr-xr-xsrc/conf_mode/protocols_babel.py5
-rwxr-xr-xsrc/conf_mode/protocols_bfd.py4
-rwxr-xr-xsrc/conf_mode/protocols_bgp.py21
-rwxr-xr-xsrc/conf_mode/protocols_igmp-proxy.py7
-rwxr-xr-xsrc/conf_mode/protocols_isis.py2
-rwxr-xr-xsrc/conf_mode/protocols_nhrp.py5
-rwxr-xr-xsrc/conf_mode/protocols_ospfv3.py2
-rwxr-xr-xsrc/conf_mode/protocols_rip.py4
-rwxr-xr-xsrc/conf_mode/protocols_ripng.py4
-rwxr-xr-xsrc/conf_mode/protocols_segment-routing.py4
-rwxr-xr-xsrc/conf_mode/protocols_static.py4
-rwxr-xr-xsrc/conf_mode/protocols_static_neighbor-proxy.py12
-rwxr-xr-xsrc/conf_mode/qos.py14
-rwxr-xr-xsrc/conf_mode/service_dhcp-server.py18
-rwxr-xr-xsrc/conf_mode/service_dhcpv6-server.py7
-rwxr-xr-xsrc/conf_mode/service_dns_forwarding.py5
-rwxr-xr-xsrc/conf_mode/service_https.py39
-rwxr-xr-xsrc/conf_mode/service_ipoe-server.py4
-rwxr-xr-xsrc/conf_mode/service_lldp.py3
-rwxr-xr-xsrc/conf_mode/service_mdns_repeater.py8
-rwxr-xr-xsrc/conf_mode/service_pppoe-server.py27
-rwxr-xr-xsrc/conf_mode/service_ssh.py16
-rwxr-xr-xsrc/conf_mode/service_tftp-server.py3
-rwxr-xr-xsrc/conf_mode/service_upnp.py4
-rwxr-xr-xsrc/conf_mode/system_conntrack.py7
-rwxr-xr-xsrc/conf_mode/system_console.py5
-rwxr-xr-xsrc/conf_mode/system_flow-accounting.py10
-rwxr-xr-xsrc/conf_mode/system_frr.py3
-rwxr-xr-xsrc/conf_mode/system_host-name.py6
-rwxr-xr-xsrc/conf_mode/system_ip.py8
-rwxr-xr-xsrc/conf_mode/system_login.py26
-rwxr-xr-xsrc/conf_mode/system_option.py6
-rwxr-xr-xsrc/conf_mode/system_timezone.py3
-rwxr-xr-xsrc/conf_mode/system_update-check.py5
-rwxr-xr-xsrc/conf_mode/vpn_ipsec.py6
-rwxr-xr-xsrc/conf_mode/vpn_openconnect.py52
-rwxr-xr-xsrc/conf_mode/vpn_sstp.py65
-rwxr-xr-xsrc/conf_mode/vrf.py11
-rw-r--r--src/conf_mode/vrf_vni.py3
-rw-r--r--src/etc/dhcp/dhclient-enter-hooks.d/04-vyos-resolvconf16
-rwxr-xr-xsrc/etc/dhcp/dhclient-exit-hooks.d/99-ipsec-dhclient-hook6
-rw-r--r--src/etc/systemd/system/ssh@.service.d/vrf-override.conf13
-rwxr-xr-xsrc/helpers/vyos-config-encrypt.py2
-rwxr-xr-xsrc/helpers/vyos-domain-resolver.py7
-rwxr-xr-xsrc/helpers/vyos-failover.py3
-rwxr-xr-xsrc/helpers/vyos-merge-config.py3
-rwxr-xr-xsrc/helpers/vyos_config_sync.py66
-rwxr-xr-xsrc/init/vyos-router2
-rwxr-xr-xsrc/migration-scripts/conntrack/2-to-31
-rwxr-xr-xsrc/migration-scripts/container/1-to-250
-rwxr-xr-xsrc/migration-scripts/dhcp-server/9-to-103
-rwxr-xr-xsrc/migration-scripts/dhcpv6-server/3-to-41
-rwxr-xr-xsrc/migration-scripts/firewall/10-to-1113
-rwxr-xr-xsrc/migration-scripts/firewall/11-to-127
-rwxr-xr-xsrc/migration-scripts/firewall/12-to-137
-rwxr-xr-xsrc/migration-scripts/firewall/14-to-1546
-rwxr-xr-xsrc/migration-scripts/firewall/6-to-780
-rwxr-xr-xsrc/migration-scripts/firewall/7-to-85
-rwxr-xr-xsrc/migration-scripts/firewall/8-to-99
-rwxr-xr-xsrc/migration-scripts/firewall/9-to-1013
-rwxr-xr-xsrc/migration-scripts/interfaces/26-to-274
-rwxr-xr-xsrc/migration-scripts/interfaces/27-to-283
-rwxr-xr-xsrc/migration-scripts/interfaces/28-to-294
-rwxr-xr-xsrc/migration-scripts/interfaces/29-to-304
-rwxr-xr-xsrc/migration-scripts/ipoe-server/0-to-174
-rwxr-xr-xsrc/migration-scripts/ipoe-server/1-to-2101
-rwxr-xr-xsrc/migration-scripts/ipoe-server/2-to-33
-rwxr-xr-xsrc/migration-scripts/ipsec/11-to-124
-rwxr-xr-xsrc/migration-scripts/ipsec/12-to-132
-rwxr-xr-xsrc/migration-scripts/ipsec/7-to-83
-rwxr-xr-xsrc/migration-scripts/ipsec/9-to-105
-rwxr-xr-xsrc/migration-scripts/l2tp/2-to-36
-rwxr-xr-xsrc/migration-scripts/l2tp/3-to-43
-rwxr-xr-xsrc/migration-scripts/l2tp/4-to-54
-rwxr-xr-xsrc/migration-scripts/l2tp/5-to-66
-rwxr-xr-xsrc/migration-scripts/l2tp/6-to-73
-rwxr-xr-xsrc/migration-scripts/l2tp/7-to-83
-rwxr-xr-xsrc/migration-scripts/l2tp/8-to-95
-rwxr-xr-xsrc/migration-scripts/nat/5-to-6120
-rwxr-xr-xsrc/migration-scripts/openconnect/0-to-13
-rwxr-xr-xsrc/migration-scripts/ospf/0-to-13
-rwxr-xr-xsrc/migration-scripts/policy/4-to-53
-rwxr-xr-xsrc/migration-scripts/policy/5-to-63
-rwxr-xr-xsrc/migration-scripts/policy/6-to-79
-rwxr-xr-xsrc/migration-scripts/pppoe-server/1-to-25
-rwxr-xr-xsrc/migration-scripts/pppoe-server/3-to-44
-rwxr-xr-xsrc/migration-scripts/pppoe-server/6-to-74
-rwxr-xr-xsrc/migration-scripts/pppoe-server/7-to-85
-rwxr-xr-xsrc/migration-scripts/pppoe-server/8-to-93
-rwxr-xr-xsrc/migration-scripts/pptp/2-to-34
-rwxr-xr-xsrc/migration-scripts/pptp/3-to-43
-rwxr-xr-xsrc/migration-scripts/pptp/4-to-53
-rwxr-xr-xsrc/migration-scripts/snmp/2-to-35
-rwxr-xr-xsrc/migration-scripts/sstp/0-to-13
-rwxr-xr-xsrc/migration-scripts/sstp/3-to-43
-rwxr-xr-xsrc/migration-scripts/sstp/4-to-55
-rwxr-xr-xsrc/migration-scripts/sstp/5-to-64
-rwxr-xr-xsrc/migration-scripts/system/15-to-161
-rwxr-xr-xsrc/migration-scripts/system/16-to-173
-rwxr-xr-xsrc/migration-scripts/system/19-to-204
-rwxr-xr-xsrc/migration-scripts/system/20-to-214
-rwxr-xr-xsrc/migration-scripts/system/21-to-224
-rwxr-xr-xsrc/migration-scripts/system/22-to-234
-rwxr-xr-xsrc/migration-scripts/system/23-to-244
-rwxr-xr-xsrc/op_mode/bridge.py4
-rwxr-xr-xsrc/op_mode/conntrack.py26
-rwxr-xr-xsrc/op_mode/conntrack_sync.py3
-rwxr-xr-xsrc/op_mode/container.py4
-rwxr-xr-xsrc/op_mode/dhcp.py10
-rwxr-xr-xsrc/op_mode/firewall.py60
-rwxr-xr-xsrc/op_mode/generate_ovpn_client_file.py5
-rwxr-xr-xsrc/op_mode/generate_tech-support_archive.py2
-rwxr-xr-xsrc/op_mode/ikev2_profile_generator.py3
-rwxr-xr-xsrc/op_mode/image_info.py8
-rwxr-xr-xsrc/op_mode/image_installer.py17
-rwxr-xr-xsrc/op_mode/image_manager.py44
-rwxr-xr-xsrc/op_mode/interfaces_wireless.py3
-rwxr-xr-xsrc/op_mode/openvpn.py7
-rwxr-xr-xsrc/op_mode/otp.py18
-rwxr-xr-xsrc/op_mode/policy_route.py3
-rwxr-xr-xsrc/op_mode/powerctrl.py4
-rwxr-xr-xsrc/op_mode/restart_dhcp_relay.py3
-rwxr-xr-xsrc/op_mode/reverseproxy.py4
-rwxr-xr-xsrc/op_mode/sflow.py3
-rw-r--r--src/op_mode/show_techsupport_report.py4
-rwxr-xr-xsrc/op_mode/snmp.py8
-rwxr-xr-xsrc/op_mode/system.py7
-rwxr-xr-xsrc/op_mode/vpn_ike_sa.py3
-rwxr-xr-xsrc/op_mode/vrrp.py6
-rw-r--r--src/services/api/graphql/generate/composite_function.py4
-rw-r--r--src/services/api/graphql/graphql/auth_token_mutation.py8
-rw-r--r--src/services/api/graphql/graphql/directives.py4
-rw-r--r--src/services/api/graphql/graphql/mutations.py8
-rw-r--r--src/services/api/graphql/graphql/queries.py8
-rw-r--r--src/services/api/graphql/libs/op_mode.py6
-rwxr-xr-xsrc/services/api/graphql/session/composite/system_status.py11
-rw-r--r--src/services/api/graphql/session/session.py3
-rwxr-xr-xsrc/services/vyos-http-api-server38
-rwxr-xr-xsrc/system/keepalived-fifo.py4
-rw-r--r--src/tests/test_config_diff.py3
-rw-r--r--src/tests/test_config_parser.py3
-rw-r--r--src/tests/test_initial_setup.py5
-rw-r--r--src/tests/test_template.py6
170 files changed, 1209 insertions, 928 deletions
diff --git a/src/completion/list_ipsec_profile_tunnels.py b/src/completion/list_ipsec_profile_tunnels.py
index 4a917dbd6..95a4ca3ce 100644
--- a/src/completion/list_ipsec_profile_tunnels.py
+++ b/src/completion/list_ipsec_profile_tunnels.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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
@@ -14,8 +14,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 os
-import sys
import argparse
from vyos.config import Config
@@ -45,4 +43,3 @@ if __name__ == "__main__":
tunnels = get_tunnels_from_ipsecprofile(args.profile)
print(" ".join(tunnels))
-
diff --git a/src/completion/list_openvpn_clients.py b/src/completion/list_openvpn_clients.py
index b443520ea..c1d8eaeb3 100755
--- a/src/completion/list_openvpn_clients.py
+++ b/src/completion/list_openvpn_clients.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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
@@ -14,8 +14,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 os
-import sys
import argparse
from vyos.ifconfig import Section
@@ -57,4 +55,3 @@ if __name__ == "__main__":
clients += get_client_from_interface(interface)
print(" ".join(clients))
-
diff --git a/src/completion/list_openvpn_users.py b/src/completion/list_openvpn_users.py
index b2b0149fc..f2c648476 100755
--- a/src/completion/list_openvpn_users.py
+++ b/src/completion/list_openvpn_users.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2021 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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
@@ -14,8 +14,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 os
-import sys
import argparse
from vyos.config import Config
@@ -45,4 +43,3 @@ if __name__ == "__main__":
users = get_user_from_interface(args.interface)
print(" ".join(users))
-
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py
index e967bee71..a73a18ffa 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -32,6 +32,7 @@ from vyos.utils.file import write_file
from vyos.utils.process import call
from vyos.utils.process import cmd
from vyos.utils.process import run
+from vyos.utils.network import interface_exists
from vyos.template import bracketize_ipv6
from vyos.template import inc_ip
from vyos.template import is_ipv4
@@ -261,12 +262,11 @@ def generate_run_arguments(name, container_config):
restart = container_config['restart']
# Add capability options. Should be in uppercase
- cap_add = ''
- if 'cap_add' in container_config:
- for c in container_config['cap_add']:
- c = c.upper()
- c = c.replace('-', '_')
- cap_add += f' --cap-add={c}'
+ capabilities = ''
+ if 'capability' in container_config:
+ for cap in container_config['capability']:
+ cap = cap.upper().replace('-', '_')
+ capabilities += f' --cap-add={cap}'
# Add a host device to the container /dev/x:/dev/x
device = ''
@@ -329,7 +329,7 @@ def generate_run_arguments(name, container_config):
prop = vol_config['propagation']
volume += f' --volume {svol}:{dvol}:{mode},{prop}'
- container_base_cmd = f'--detach --interactive --tty --replace {cap_add} ' \
+ container_base_cmd = f'--detach --interactive --tty --replace {capabilities} ' \
f'--memory {memory}m --shm-size {shared_memory}m --memory-swap 0 --restart {restart} ' \
f'--name {name} {hostname} {device} {port} {volume} {env_opt} {label} {uid}'
@@ -471,10 +471,10 @@ def apply(container):
# T5147: Networks are started only as soon as there is a consumer.
# If only a network is created in the first place, no need to assign
# it to a VRF as there's no consumer, yet.
- if os.path.exists(f'/sys/class/net/{network_name}'):
+ if interface_exists(network_name):
tmp = Interface(network_name)
- tmp.add_ipv6_eui64_address('fe80::/64')
tmp.set_vrf(network_config.get('vrf', ''))
+ tmp.add_ipv6_eui64_address('fe80::/64')
return None
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index 810437dda..e96e57154 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -18,7 +18,6 @@ import os
import re
from glob import glob
-from json import loads
from sys import exit
from vyos.base import Warning
@@ -31,11 +30,9 @@ from vyos.ethtool import Ethtool
from vyos.firewall import fqdn_config_parse
from vyos.firewall import geoip_update
from vyos.template import render
-from vyos.utils.process import call
-from vyos.utils.process import cmd
from vyos.utils.dict import dict_search_args
from vyos.utils.dict import dict_search_recursive
-from vyos.utils.process import process_named_running
+from vyos.utils.process import call
from vyos.utils.process import rc_cmd
from vyos import ConfigError
from vyos import airbag
@@ -47,6 +44,7 @@ nftables_conf = '/run/nftables.conf'
sysfs_config = {
'all_ping': {'sysfs': '/proc/sys/net/ipv4/icmp_echo_ignore_all', 'enable': '0', 'disable': '1'},
'broadcast_ping': {'sysfs': '/proc/sys/net/ipv4/icmp_echo_ignore_broadcasts', 'enable': '0', 'disable': '1'},
+ 'directed_broadcast' : {'sysfs': '/proc/sys/net/ipv4/conf/all/bc_forwarding', 'enable': '1', 'disable': '0'},
'ip_src_route': {'sysfs': '/proc/sys/net/ipv4/conf/*/accept_source_route'},
'ipv6_receive_redirects': {'sysfs': '/proc/sys/net/ipv6/conf/*/accept_redirects'},
'ipv6_src_route': {'sysfs': '/proc/sys/net/ipv6/conf/*/accept_source_route', 'enable': '0', 'disable': '-1'},
@@ -491,7 +489,7 @@ def apply_sysfs(firewall):
f.write(value)
def apply(firewall):
- install_result, output = rc_cmd(f'nft -f {nftables_conf}')
+ install_result, output = rc_cmd(f'nft --file {nftables_conf}')
if install_result == 1:
raise ConfigError(f'Failed to apply firewall: {output}')
diff --git a/src/conf_mode/interfaces_bonding.py b/src/conf_mode/interfaces_bonding.py
index 8184d8415..371b219c0 100755
--- a/src/conf_mode/interfaces_bonding.py
+++ b/src/conf_mode/interfaces_bonding.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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
@@ -14,10 +14,8 @@
# 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
-
from sys import exit
-from netifaces import interfaces
+
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configdict import is_node_changed
@@ -29,7 +27,6 @@ from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_dhcpv6
from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_mtu_ipv6
-from vyos.configverify import verify_source_interface
from vyos.configverify import verify_vlan_config
from vyos.configverify import verify_vrf
from vyos.ifconfig import BondIf
@@ -38,6 +35,7 @@ from vyos.ifconfig import Section
from vyos.template import render_to_string
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_to_paths_values
+from vyos.utils.network import interface_exists
from vyos.configdict import has_address_configured
from vyos.configdict import has_vrf_configured
from vyos.configdep import set_dependents, call_dependents
@@ -209,7 +207,7 @@ def verify(bond):
if interface == 'lo':
raise ConfigError('Loopback interface "lo" can not be added to a bond')
- if interface not in interfaces():
+ if not interface_exists(interface):
raise ConfigError(error_msg + 'it does not exist!')
if 'is_bridge_member' in interface_config:
diff --git a/src/conf_mode/interfaces_ethernet.py b/src/conf_mode/interfaces_ethernet.py
index 2c0f846c3..6da7e6a69 100755
--- a/src/conf_mode/interfaces_ethernet.py
+++ b/src/conf_mode/interfaces_ethernet.py
@@ -15,9 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import pprint
-from glob import glob
from sys import exit
from vyos.base import Warning
@@ -26,7 +24,6 @@ from vyos.configdict import get_interface_dict
from vyos.configdict import is_node_changed
from vyos.configverify import verify_address
from vyos.configverify import verify_dhcpv6
-from vyos.configverify import verify_eapol
from vyos.configverify import verify_interface_exists
from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_mtu
@@ -34,6 +31,8 @@ from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_vlan_config
from vyos.configverify import verify_vrf
from vyos.configverify import verify_bond_bridge_member
+from vyos.configverify import verify_pki_certificate
+from vyos.configverify import verify_pki_ca_certificate
from vyos.ethtool import Ethtool
from vyos.ifconfig import EthernetIf
from vyos.ifconfig import BondIf
@@ -153,6 +152,19 @@ def get_config(config=None):
base = ['interfaces', 'ethernet']
ifname, ethernet = get_interface_dict(conf, base, with_pki=True)
+ # T5862 - default MTU is not acceptable in some environments
+ # There are cloud environments available where the maximum supported
+ # ethernet MTU is e.g. 1450 bytes, thus we clamp this to the adapters
+ # maximum MTU value or 1500 bytes - whatever is lower
+ if 'mtu' not in ethernet:
+ try:
+ ethernet['mtu'] = '1500'
+ max_mtu = EthernetIf(ifname).get_max_mtu()
+ if max_mtu < int(ethernet['mtu']):
+ ethernet['mtu'] = str(max_mtu)
+ except:
+ pass
+
if 'is_bond_member' in ethernet:
update_bond_options(conf, ethernet)
@@ -263,6 +275,22 @@ def verify_allowedbond_changes(ethernet: dict):
f' on interface "{ethernet["ifname"]}".' \
f' Interface is a bond member')
+def verify_eapol(ethernet: dict):
+ """
+ Common helper function used by interface implementations to perform
+ recurring validation of EAPoL configuration.
+ """
+ if 'eapol' not in ethernet:
+ return
+
+ if 'certificate' not in ethernet['eapol']:
+ raise ConfigError('Certificate must be specified when using EAPoL!')
+
+ verify_pki_certificate(ethernet, ethernet['eapol']['certificate'], no_password_protected=True)
+
+ if 'ca_certificate' in ethernet['eapol']:
+ for ca_cert in ethernet['eapol']['ca_certificate']:
+ verify_pki_ca_certificate(ethernet, ca_cert)
def verify(ethernet):
if 'deleted' in ethernet:
diff --git a/src/conf_mode/interfaces_geneve.py b/src/conf_mode/interfaces_geneve.py
index f6694ddde..769139e0f 100755
--- a/src/conf_mode/interfaces_geneve.py
+++ b/src/conf_mode/interfaces_geneve.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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,7 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from sys import exit
-from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
@@ -26,6 +25,7 @@ from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import GeneveIf
+from vyos.utils.network import interface_exists
from vyos import ConfigError
from vyos import airbag
@@ -77,8 +77,8 @@ def generate(geneve):
def apply(geneve):
# Check if GENEVE interface already exists
if 'rebuild_required' in geneve or 'delete' in geneve:
- if geneve['ifname'] in interfaces():
- g = GeneveIf(geneve['ifname'])
+ if interface_exists(geneve['ifname']):
+ g = GeneveIf(**geneve)
# GENEVE is super picky and the tunnel always needs to be recreated,
# thus we can simply always delete it first.
g.remove()
diff --git a/src/conf_mode/interfaces_l2tpv3.py b/src/conf_mode/interfaces_l2tpv3.py
index e1db3206e..e25793543 100755
--- a/src/conf_mode/interfaces_l2tpv3.py
+++ b/src/conf_mode/interfaces_l2tpv3.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2020 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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
@@ -14,10 +14,7 @@
# 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
-
from sys import exit
-from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
@@ -30,6 +27,7 @@ from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import L2TPv3If
from vyos.utils.kernel import check_kmod
from vyos.utils.network import is_addr_assigned
+from vyos.utils.network import interface_exists
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -87,7 +85,7 @@ def generate(l2tpv3):
def apply(l2tpv3):
# Check if L2TPv3 interface already exists
- if l2tpv3['ifname'] in interfaces():
+ if interface_exists(l2tpv3['ifname']):
# L2TPv3 is picky when changing tunnels/sessions, thus we can simply
# always delete it first.
l = L2TPv3If(**l2tpv3)
diff --git a/src/conf_mode/interfaces_loopback.py b/src/conf_mode/interfaces_loopback.py
index 08d34477a..a784e9ec2 100755
--- a/src/conf_mode/interfaces_loopback.py
+++ b/src/conf_mode/interfaces_loopback.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2020 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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
@@ -14,8 +14,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 os
-
from sys import exit
from vyos.config import Config
diff --git a/src/conf_mode/interfaces_macsec.py b/src/conf_mode/interfaces_macsec.py
index 0a927ac88..eb0ca9a8b 100755
--- a/src/conf_mode/interfaces_macsec.py
+++ b/src/conf_mode/interfaces_macsec.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -16,7 +16,6 @@
import os
-from netifaces import interfaces
from sys import exit
from vyos.config import Config
@@ -35,6 +34,7 @@ from vyos.ifconfig import Interface
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.dict import dict_search
+from vyos.utils.network import interface_exists
from vyos.utils.process import is_systemd_service_running
from vyos import ConfigError
from vyos import airbag
@@ -172,8 +172,8 @@ def apply(macsec):
if 'deleted' in macsec or 'shutdown_required' in macsec:
call(f'systemctl stop {systemd_service}')
- if macsec['ifname'] in interfaces():
- tmp = MACsecIf(macsec['ifname'])
+ if interface_exists(macsec['ifname']):
+ tmp = MACsecIf(**macsec)
tmp.remove()
if 'deleted' in macsec:
diff --git a/src/conf_mode/interfaces_openvpn.py b/src/conf_mode/interfaces_openvpn.py
index 45569dd21..0ecffd3be 100755
--- a/src/conf_mode/interfaces_openvpn.py
+++ b/src/conf_mode/interfaces_openvpn.py
@@ -16,7 +16,6 @@
import os
import re
-import tempfile
from cryptography.hazmat.primitives.asymmetric import ec
from glob import glob
@@ -26,7 +25,6 @@ from ipaddress import IPv4Network
from ipaddress import IPv6Address
from ipaddress import IPv6Network
from ipaddress import summarize_address_range
-from netifaces import interfaces
from secrets import SystemRandom
from shutil import rmtree
@@ -63,6 +61,7 @@ from vyos.utils.process import call
from vyos.utils.permission import chown
from vyos.utils.process import cmd
from vyos.utils.network import is_addr_assigned
+from vyos.utils.network import interface_exists
from vyos import ConfigError
from vyos import airbag
@@ -199,6 +198,12 @@ def verify_pki(openvpn):
raise ConfigError(f'Cannot use encrypted private key on openvpn interface {interface}')
if 'dh_params' in tls:
+ if 'dh' not in pki:
+ raise ConfigError(f'pki dh is not configured')
+ proposed_dh = tls['dh_params']
+ if proposed_dh not in pki['dh'].keys():
+ raise ConfigError(f"pki dh '{proposed_dh}' is not configured")
+
pki_dh = pki['dh'][tls['dh_params']]
dh_params = load_dh_parameters(pki_dh['parameters'])
dh_numbers = dh_params.parameter_numbers()
@@ -683,7 +688,7 @@ def apply(openvpn):
if os.path.isfile(cleanup_file):
os.unlink(cleanup_file)
- if interface in interfaces():
+ if interface_exists(interface):
VTunIf(interface).remove()
# dynamically load/unload DCO Kernel extension if requested
diff --git a/src/conf_mode/interfaces_pppoe.py b/src/conf_mode/interfaces_pppoe.py
index 42f084309..412676c7d 100755
--- a/src/conf_mode/interfaces_pppoe.py
+++ b/src/conf_mode/interfaces_pppoe.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2021 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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,16 +17,12 @@
import os
from sys import exit
-from copy import deepcopy
-from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configdict import is_node_changed
-from vyos.configdict import get_pppoe_interfaces
from vyos.configverify import verify_authentication
from vyos.configverify import verify_source_interface
-from vyos.configverify import verify_interface_exists
from vyos.configverify import verify_vrf
from vyos.configverify import verify_mtu_ipv6
from vyos.configverify import verify_mirror_redirect
diff --git a/src/conf_mode/interfaces_pseudo-ethernet.py b/src/conf_mode/interfaces_pseudo-ethernet.py
index dce5c2358..446beffd3 100755
--- a/src/conf_mode/interfaces_pseudo-ethernet.py
+++ b/src/conf_mode/interfaces_pseudo-ethernet.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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,7 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from sys import exit
-from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
@@ -29,8 +28,8 @@ from vyos.configverify import verify_source_interface
from vyos.configverify import verify_vlan_config
from vyos.configverify import verify_mtu_parent
from vyos.configverify import verify_mirror_redirect
-from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import MACVLANIf
+from vyos.utils.network import interface_exists
from vyos import ConfigError
from vyos import airbag
@@ -84,8 +83,8 @@ def generate(peth):
def apply(peth):
# Check if the MACVLAN interface already exists
if 'rebuild_required' in peth or 'deleted' in peth:
- if peth['ifname'] in interfaces():
- p = MACVLANIf(peth['ifname'])
+ if interface_exists(peth['ifname']):
+ p = MACVLANIf(**peth)
# MACVLAN is always needs to be recreated,
# thus we can simply always delete it first.
p.remove()
diff --git a/src/conf_mode/interfaces_tunnel.py b/src/conf_mode/interfaces_tunnel.py
index efa5ebc64..43ba72857 100755
--- a/src/conf_mode/interfaces_tunnel.py
+++ b/src/conf_mode/interfaces_tunnel.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2022 yOS maintainers and contributors
+# Copyright (C) 2018-2024 yOS 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
@@ -14,10 +14,7 @@
# 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
-
from sys import exit
-from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
@@ -31,10 +28,10 @@ from vyos.configverify import verify_vrf
from vyos.configverify import verify_tunnel
from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import Interface
-from vyos.ifconfig import Section
from vyos.ifconfig import TunnelIf
-from vyos.utils.network import get_interface_config
from vyos.utils.dict import dict_search
+from vyos.utils.network import get_interface_config
+from vyos.utils.network import interface_exists
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -202,7 +199,7 @@ def apply(tunnel):
if ('deleted' in tunnel or 'encapsulation_changed' in tunnel or encap in
['gretap', 'ip6gretap', 'erspan', 'ip6erspan'] or remote in ['any'] or
'key_changed' in tunnel):
- if interface in interfaces():
+ if interface_exists(interface):
tmp = Interface(interface)
tmp.remove()
if 'deleted' in tunnel:
diff --git a/src/conf_mode/interfaces_virtual-ethernet.py b/src/conf_mode/interfaces_virtual-ethernet.py
index 8efe89c41..cb6104f59 100755
--- a/src/conf_mode/interfaces_virtual-ethernet.py
+++ b/src/conf_mode/interfaces_virtual-ethernet.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -16,7 +16,6 @@
from sys import exit
-from netifaces import interfaces
from vyos import ConfigError
from vyos import airbag
from vyos.config import Config
@@ -25,7 +24,7 @@ from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_vrf
from vyos.ifconfig import VethIf
-
+from vyos.utils.network import interface_exists
airbag.enable()
def get_config(config=None):
@@ -92,8 +91,8 @@ def generate(peth):
def apply(veth):
# Check if the Veth interface already exists
if 'rebuild_required' in veth or 'deleted' in veth:
- if veth['ifname'] in interfaces():
- p = VethIf(veth['ifname'])
+ if interface_exists(veth['ifname']):
+ p = VethIf(**veth)
p.remove()
if 'deleted' not in veth:
diff --git a/src/conf_mode/interfaces_vti.py b/src/conf_mode/interfaces_vti.py
index 9871810ae..e6a833df7 100755
--- a/src/conf_mode/interfaces_vti.py
+++ b/src/conf_mode/interfaces_vti.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -14,14 +14,12 @@
# 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 netifaces import interfaces
from sys import exit
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configverify import verify_mirror_redirect
from vyos.ifconfig import VTIIf
-from vyos.utils.dict import dict_search
from vyos import ConfigError
from vyos import airbag
airbag.enable()
diff --git a/src/conf_mode/interfaces_vxlan.py b/src/conf_mode/interfaces_vxlan.py
index 4251e611b..39365968a 100755
--- a/src/conf_mode/interfaces_vxlan.py
+++ b/src/conf_mode/interfaces_vxlan.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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
@@ -14,10 +14,7 @@
# 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
-
from sys import exit
-from netifaces import interfaces
from vyos.base import Warning
from vyos.config import Config
@@ -35,6 +32,7 @@ from vyos.ifconfig import Interface
from vyos.ifconfig import VXLANIf
from vyos.template import is_ipv6
from vyos.utils.dict import dict_search
+from vyos.utils.network import interface_exists
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -212,8 +210,8 @@ def generate(vxlan):
def apply(vxlan):
# Check if the VXLAN interface already exists
if 'rebuild_required' in vxlan or 'delete' in vxlan:
- if vxlan['ifname'] in interfaces():
- v = VXLANIf(vxlan['ifname'])
+ if interface_exists(vxlan['ifname']):
+ v = VXLANIf(**vxlan)
# VXLAN is super picky and the tunnel always needs to be recreated,
# thus we can simply always delete it first.
v.remove()
diff --git a/src/conf_mode/interfaces_wireguard.py b/src/conf_mode/interfaces_wireguard.py
index 79e5d3f44..0e0b77877 100755
--- a/src/conf_mode/interfaces_wireguard.py
+++ b/src/conf_mode/interfaces_wireguard.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2023 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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,7 +17,6 @@
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configdict import get_interface_dict
from vyos.configdict import is_node_changed
from vyos.configverify import verify_vrf
diff --git a/src/conf_mode/load-balancing_reverse-proxy.py b/src/conf_mode/load-balancing_reverse-proxy.py
index 7338fe573..694a4e1ea 100755
--- a/src/conf_mode/load-balancing_reverse-proxy.py
+++ b/src/conf_mode/load-balancing_reverse-proxy.py
@@ -20,6 +20,9 @@ from sys import exit
from shutil import rmtree
from vyos.config import Config
+from vyos.configverify import verify_pki_certificate
+from vyos.configverify import verify_pki_ca_certificate
+from vyos.utils.dict import dict_search
from vyos.utils.process import call
from vyos.utils.network import check_port_availability
from vyos.utils.network import is_listen_port_bind_service
@@ -33,8 +36,7 @@ airbag.enable()
load_balancing_dir = '/run/haproxy'
load_balancing_conf_file = f'{load_balancing_dir}/haproxy.cfg'
systemd_service = 'haproxy.service'
-systemd_override = r'/run/systemd/system/haproxy.service.d/10-override.conf'
-
+systemd_override = '/run/systemd/system/haproxy.service.d/10-override.conf'
def get_config(config=None):
if config:
@@ -54,7 +56,6 @@ def get_config(config=None):
return lb
-
def verify(lb):
if not lb:
return None
@@ -83,6 +84,15 @@ def verify(lb):
if {'send_proxy', 'send_proxy_v2'} <= set(bk_server_conf):
raise ConfigError(f'Cannot use both "send-proxy" and "send-proxy-v2" for server "{bk_server}"')
+ for front, front_config in lb['service'].items():
+ for cert in dict_search('ssl.certificate', front_config) or []:
+ verify_pki_certificate(lb, cert)
+
+ for back, back_config in lb['backend'].items():
+ tmp = dict_search('ssl.ca_certificate', front_config)
+ if tmp: verify_pki_ca_certificate(lb, tmp)
+
+
def generate(lb):
if not lb:
# Delete /run/haproxy/haproxy.cfg
diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py
index b3f38c04a..4cd9b570d 100755
--- a/src/conf_mode/nat.py
+++ b/src/conf_mode/nat.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -14,8 +14,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 jmespath
-import json
import os
from sys import exit
@@ -223,19 +221,19 @@ def generate(nat):
render(nftables_static_nat_conf, 'firewall/nftables-static-nat.j2', nat)
# dry-run newly generated configuration
- tmp = run(f'nft -c -f {nftables_nat_config}')
+ tmp = run(f'nft --check --file {nftables_nat_config}')
if tmp > 0:
raise ConfigError('Configuration file errors encountered!')
- tmp = run(f'nft -c -f {nftables_static_nat_conf}')
+ tmp = run(f'nft --check --file {nftables_static_nat_conf}')
if tmp > 0:
raise ConfigError('Configuration file errors encountered!')
return None
def apply(nat):
- cmd(f'nft -f {nftables_nat_config}')
- cmd(f'nft -f {nftables_static_nat_conf}')
+ cmd(f'nft --file {nftables_nat_config}')
+ cmd(f'nft --file {nftables_static_nat_conf}')
if not nat or 'deleted' in nat:
os.unlink(nftables_nat_config)
diff --git a/src/conf_mode/nat64.py b/src/conf_mode/nat64.py
index 6026c61d0..c1e7ebf85 100755
--- a/src/conf_mode/nat64.py
+++ b/src/conf_mode/nat64.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -26,7 +26,6 @@ from json import dumps as json_write
from vyos import ConfigError
from vyos import airbag
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configdict import is_node_changed
from vyos.utils.dict import dict_search
from vyos.utils.file import write_file
diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py
index 4c1ead258..fe017527d 100755
--- a/src/conf_mode/nat66.py
+++ b/src/conf_mode/nat66.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -14,8 +14,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 jmespath
-import json
import os
from sys import exit
@@ -106,7 +104,7 @@ def apply(nat):
if not nat:
return None
- cmd(f'nft -f {nftables_nat66_config}')
+ cmd(f'nft --file {nftables_nat66_config}')
call_dependents()
return None
diff --git a/src/conf_mode/nat_cgnat.py b/src/conf_mode/nat_cgnat.py
new file mode 100755
index 000000000..f41d66c66
--- /dev/null
+++ b/src/conf_mode/nat_cgnat.py
@@ -0,0 +1,288 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 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 ipaddress
+import jmespath
+import os
+
+from sys import exit
+
+from vyos.config import Config
+from vyos.template import render
+from vyos.utils.process import cmd
+from vyos.utils.process import run
+from vyos import ConfigError
+from vyos import airbag
+
+airbag.enable()
+
+
+nftables_cgnat_config = '/run/nftables-cgnat.nft'
+
+
+class IPOperations:
+ def __init__(self, ip_prefix: str):
+ self.ip_prefix = ip_prefix
+ self.ip_network = ipaddress.ip_network(ip_prefix) if '/' in ip_prefix else None
+
+ def get_ips_count(self) -> int:
+ """Returns the number of IPs in a prefix or range.
+
+ Example:
+ % ip = IPOperations('192.0.2.0/30')
+ % ip.get_ips_count()
+ 4
+ % ip = IPOperations('192.0.2.0-192.0.2.2')
+ % ip.get_ips_count()
+ 3
+ """
+ if '-' in self.ip_prefix:
+ start_ip, end_ip = self.ip_prefix.split('-')
+ start_ip = ipaddress.ip_address(start_ip)
+ end_ip = ipaddress.ip_address(end_ip)
+ return int(end_ip) - int(start_ip) + 1
+ elif '/31' in self.ip_prefix:
+ return 2
+ elif '/32' in self.ip_prefix:
+ return 1
+ else:
+ return sum(
+ 1
+ for _ in [self.ip_network.network_address]
+ + list(self.ip_network.hosts())
+ + [self.ip_network.broadcast_address]
+ )
+
+ def convert_prefix_to_list_ips(self) -> list:
+ """Converts a prefix or IP range to a list of IPs including the network and broadcast addresses.
+
+ Example:
+ % ip = IPOperations('192.0.2.0/30')
+ % ip.convert_prefix_to_list_ips()
+ ['192.0.2.0', '192.0.2.1', '192.0.2.2', '192.0.2.3']
+ %
+ % ip = IPOperations('192.0.0.1-192.0.2.5')
+ % ip.convert_prefix_to_list_ips()
+ ['192.0.2.1', '192.0.2.2', '192.0.2.3', '192.0.2.4', '192.0.2.5']
+ """
+ if '-' in self.ip_prefix:
+ start_ip, end_ip = self.ip_prefix.split('-')
+ start_ip = ipaddress.ip_address(start_ip)
+ end_ip = ipaddress.ip_address(end_ip)
+ return [
+ str(ipaddress.ip_address(ip))
+ for ip in range(int(start_ip), int(end_ip) + 1)
+ ]
+ elif '/31' in self.ip_prefix:
+ return [
+ str(ip)
+ for ip in [
+ self.ip_network.network_address,
+ self.ip_network.broadcast_address,
+ ]
+ ]
+ elif '/32' in self.ip_prefix:
+ return [str(self.ip_network.network_address)]
+ else:
+ return [
+ str(ip)
+ for ip in [self.ip_network.network_address]
+ + list(self.ip_network.hosts())
+ + [self.ip_network.broadcast_address]
+ ]
+
+
+def generate_port_rules(
+ external_hosts: list,
+ internal_hosts: list,
+ port_count: int,
+ global_port_range: str = '1024-65535',
+) -> list:
+ """Generates list of nftables rules for the batch file."""
+ rules = []
+ proto_map_elements = []
+ other_map_elements = []
+ start_port, end_port = map(int, global_port_range.split('-'))
+ total_possible_ports = (end_port - start_port) + 1
+
+ # Calculate the required number of ports per host
+ required_ports_per_host = port_count
+
+ # Check if there are enough external addresses for all internal hosts
+ if required_ports_per_host * len(internal_hosts) > total_possible_ports * len(
+ external_hosts
+ ):
+ raise ConfigError("Not enough ports available for the specified parameters!")
+
+ current_port = start_port
+ current_external_index = 0
+
+ for internal_host in internal_hosts:
+ external_host = external_hosts[current_external_index]
+ next_end_port = current_port + required_ports_per_host - 1
+
+ # If the port range exceeds the end_port, move to the next external host
+ while next_end_port > end_port:
+ current_external_index = (current_external_index + 1) % len(external_hosts)
+ external_host = external_hosts[current_external_index]
+ current_port = start_port
+ next_end_port = current_port + required_ports_per_host - 1
+
+ # Ensure the same port is not assigned to the same external host
+ if any(
+ rule.endswith(f'{external_host}:{current_port}-{next_end_port}')
+ for rule in rules
+ ):
+ raise ConfigError("Not enough ports available for the specified parameters")
+
+ proto_map_elements.append(
+ f'{internal_host} : {external_host} . {current_port}-{next_end_port}'
+ )
+ other_map_elements.append(f'{internal_host} : {external_host}')
+
+ current_port = next_end_port + 1
+ if current_port > end_port:
+ current_port = start_port
+ current_external_index += 1 # Move to the next external host
+
+ return [proto_map_elements, other_map_elements]
+
+
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
+
+ base = ['nat', 'cgnat']
+ config = conf.get_config_dict(
+ base,
+ get_first_key=True,
+ key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
+ with_recursive_defaults=True,
+ )
+
+ return config
+
+
+def verify(config):
+ # bail out early - looks like removal from running config
+ if not config:
+ return None
+
+ if 'pool' not in config:
+ raise ConfigError(f'Pool must be defined!')
+ if 'rule' not in config:
+ raise ConfigError(f'Rule must be defined!')
+
+ # As PoC allow only one rule for CGNAT translations
+ # one internal pool and one external pool
+ if len(config['rule']) > 1:
+ raise ConfigError(f'Only one rule is allowed for translations!')
+
+ for pool in ('external', 'internal'):
+ if pool not in config['pool']:
+ raise ConfigError(f'{pool} pool must be defined!')
+ for pool_name, pool_config in config['pool'][pool].items():
+ if 'range' not in pool_config:
+ raise ConfigError(
+ f'Range for "{pool} pool {pool_name}" must be defined!'
+ )
+
+ for rule, rule_config in config['rule'].items():
+ if 'source' not in rule_config:
+ raise ConfigError(f'Rule "{rule}" source pool must be defined!')
+ if 'pool' not in rule_config['source']:
+ raise ConfigError(f'Rule "{rule}" source pool must be defined!')
+
+ if 'translation' not in rule_config:
+ raise ConfigError(f'Rule "{rule}" translation pool must be defined!')
+
+
+def generate(config):
+ if not config:
+ return None
+ # first external pool as we allow only one as PoC
+ ext_pool_name = jmespath.search("rule.*.translation | [0]", config).get('pool')
+ int_pool_name = jmespath.search("rule.*.source | [0]", config).get('pool')
+ ext_query = f"pool.external.{ext_pool_name}.range | keys(@)"
+ int_query = f"pool.internal.{int_pool_name}.range"
+ external_ranges = jmespath.search(ext_query, config)
+ internal_ranges = [jmespath.search(int_query, config)]
+
+ external_list_count = []
+ external_list_hosts = []
+ internal_list_count = []
+ internal_list_hosts = []
+ for ext_range in external_ranges:
+ # External hosts count
+ e_count = IPOperations(ext_range).get_ips_count()
+ external_list_count.append(e_count)
+ # External hosts list
+ e_hosts = IPOperations(ext_range).convert_prefix_to_list_ips()
+ external_list_hosts.extend(e_hosts)
+ for int_range in internal_ranges:
+ # Internal hosts count
+ i_count = IPOperations(int_range).get_ips_count()
+ internal_list_count.append(i_count)
+ # Internal hosts list
+ i_hosts = IPOperations(int_range).convert_prefix_to_list_ips()
+ internal_list_hosts.extend(i_hosts)
+
+ external_host_count = sum(external_list_count)
+ internal_host_count = sum(internal_list_count)
+ ports_per_user = int(
+ jmespath.search(f'pool.external.{ext_pool_name}.per_user_limit.port', config)
+ )
+ external_port_range: str = jmespath.search(
+ f'pool.external.{ext_pool_name}.external_port_range', config
+ )
+
+ proto_maps, other_maps = generate_port_rules(
+ external_list_hosts, internal_list_hosts, ports_per_user, external_port_range
+ )
+
+ config['proto_map_elements'] = ', '.join(proto_maps)
+ config['other_map_elements'] = ', '.join(other_maps)
+
+ render(nftables_cgnat_config, 'firewall/nftables-cgnat.j2', config)
+
+ # dry-run newly generated configuration
+ tmp = run(f'nft --check --file {nftables_cgnat_config}')
+ if tmp > 0:
+ raise ConfigError('Configuration file errors encountered!')
+
+
+def apply(config):
+ if not config:
+ # Cleanup cgnat
+ cmd('nft delete table ip cgnat')
+ if os.path.isfile(nftables_cgnat_config):
+ os.unlink(nftables_cgnat_config)
+ return None
+ cmd(f'nft --file {nftables_cgnat_config}')
+
+
+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/conf_mode/netns.py b/src/conf_mode/netns.py
index 7cee33bc6..b57e46a0d 100755
--- a/src/conf_mode/netns.py
+++ b/src/conf_mode/netns.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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,14 +17,11 @@
import os
from sys import exit
-from tempfile import NamedTemporaryFile
from vyos.config import Config
from vyos.configdict import node_changed
-from vyos.ifconfig import Interface
from vyos.utils.process import call
from vyos.utils.dict import dict_search
-from vyos.utils.network import get_interface_config
from vyos import ConfigError
from vyos import airbag
airbag.enable()
diff --git a/src/conf_mode/policy_local-route.py b/src/conf_mode/policy_local-route.py
index 91e4fce2c..f458f4e82 100755
--- a/src/conf_mode/policy_local-route.py
+++ b/src/conf_mode/policy_local-route.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -14,23 +14,19 @@
# 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
-
from itertools import product
from sys import exit
-from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import dict_merge
from vyos.configdict import node_changed
from vyos.configdict import leaf_node_changed
-from vyos.template import render
+from vyos.configverify import verify_interface_exists
from vyos.utils.process import call
from vyos import ConfigError
from vyos import airbag
airbag.enable()
-
def get_config(config=None):
if config:
@@ -227,8 +223,7 @@ def verify(pbr):
if 'inbound_interface' in pbr_route['rule'][rule]:
interface = pbr_route['rule'][rule]['inbound_interface']
- if interface not in interfaces():
- raise ConfigError(f'Interface "{interface}" does not exist')
+ verify_interface_exists(interface)
return None
diff --git a/src/conf_mode/policy_route.py b/src/conf_mode/policy_route.py
index 6d7a06714..c58fe1bce 100755
--- a/src/conf_mode/policy_route.py
+++ b/src/conf_mode/policy_route.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -177,7 +177,7 @@ def cleanup_table_marks():
cmd(f'{cmd_str} rule del fwmark {fwmark} table {table}')
def apply(policy):
- install_result = run(f'nft -f {nftables_conf}')
+ install_result = run(f'nft --file {nftables_conf}')
if install_result == 1:
raise ConfigError('Failed to apply policy based routing')
diff --git a/src/conf_mode/protocols_babel.py b/src/conf_mode/protocols_babel.py
index 104711b55..90b6e4a31 100755
--- a/src/conf_mode/protocols_babel.py
+++ b/src/conf_mode/protocols_babel.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -14,15 +14,12 @@
# 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
-
from sys import exit
from vyos.config import Config
from vyos.config import config_dict_merge
from vyos.configdict import dict_merge
from vyos.configdict import node_changed
-from vyos.configverify import verify_common_route_maps
from vyos.configverify import verify_access_list
from vyos.configverify import verify_prefix_list
from vyos.utils.dict import dict_search
diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py
index 37421efb4..1c01a9013 100755
--- a/src/conf_mode/protocols_bfd.py
+++ b/src/conf_mode/protocols_bfd.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2021 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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
@@ -14,8 +14,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 os
-
from vyos.config import Config
from vyos.configverify import verify_vrf
from vyos.template import is_ipv6
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py
index f1c59cbde..2b16de775 100755
--- a/src/conf_mode/protocols_bgp.py
+++ b/src/conf_mode/protocols_bgp.py
@@ -285,6 +285,7 @@ def verify(bgp):
elif tmp != 'default':
raise ConfigError(f'{error_msg} "{tmp}"!')
+ peer_groups_context = dict()
# Common verification for both peer-group and neighbor statements
for neighbor in ['neighbor', 'peer_group']:
# bail out early if there is no neighbor or peer-group statement
@@ -301,6 +302,18 @@ def verify(bgp):
raise ConfigError(f'Specified peer-group "{peer_group}" for '\
f'neighbor "{neighbor}" does not exist!')
+ if 'remote_as' in peer_config:
+ is_ibgp = True
+ if peer_config['remote_as'] != 'internal' and \
+ peer_config['remote_as'] != bgp['system_as']:
+ is_ibgp = False
+
+ if peer_group not in peer_groups_context:
+ peer_groups_context[peer_group] = is_ibgp
+ elif peer_groups_context[peer_group] != is_ibgp:
+ raise ConfigError(f'Peer-group members must be '
+ f'all internal or all external')
+
if 'local_role' in peer_config:
#Ensure Local Role has only one value.
if len(peer_config['local_role']) > 1:
@@ -450,15 +463,15 @@ def verify(bgp):
verify_route_map(afi_config['route_map'][tmp], bgp)
if 'route_reflector_client' in afi_config:
- if 'remote_as' in peer_config and peer_config['remote_as'] != 'internal' and peer_config['remote_as'] != bgp['system_as']:
+ peer_group_as = peer_config.get('remote_as')
+
+ if peer_group_as is None or (peer_group_as != 'internal' and peer_group_as != bgp['system_as']):
raise ConfigError('route-reflector-client only supported for iBGP peers')
else:
if 'peer_group' in peer_config:
peer_group_as = dict_search(f'peer_group.{peer_group}.remote_as', bgp)
- if peer_group_as != None and peer_group_as != 'internal' and peer_group_as != bgp['system_as']:
+ if peer_group_as is None or (peer_group_as != 'internal' and peer_group_as != bgp['system_as']):
raise ConfigError('route-reflector-client only supported for iBGP peers')
- else:
- raise ConfigError('route-reflector-client only supported for iBGP peers')
# Throw an error if a peer group is not configured for allow range
for prefix in dict_search('listen.range', bgp) or []:
diff --git a/src/conf_mode/protocols_igmp-proxy.py b/src/conf_mode/protocols_igmp-proxy.py
index 40db417dd..afcef0985 100755
--- a/src/conf_mode/protocols_igmp-proxy.py
+++ b/src/conf_mode/protocols_igmp-proxy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2020 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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,10 +17,10 @@
import os
from sys import exit
-from netifaces import interfaces
from vyos.base import Warning
from vyos.config import Config
+from vyos.configverify import verify_interface_exists
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.dict import dict_search
@@ -65,8 +65,7 @@ def verify(igmp_proxy):
upstream = 0
for interface, config in igmp_proxy['interface'].items():
- if interface not in interfaces():
- raise ConfigError(f'Interface "{interface}" does not exist')
+ verify_interface_exists(interface)
if dict_search('role', config) == 'upstream':
upstream += 1
diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py
index 6c9925b80..9cadfd081 100755
--- a/src/conf_mode/protocols_isis.py
+++ b/src/conf_mode/protocols_isis.py
@@ -14,8 +14,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 os
-
from sys import exit
from sys import argv
diff --git a/src/conf_mode/protocols_nhrp.py b/src/conf_mode/protocols_nhrp.py
index c339c6391..0bd68b7d8 100755
--- a/src/conf_mode/protocols_nhrp.py
+++ b/src/conf_mode/protocols_nhrp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -19,7 +19,6 @@ import os
from vyos.config import Config
from vyos.configdict import node_changed
from vyos.template import render
-from vyos.utils.process import process_named_running
from vyos.utils.process import run
from vyos import ConfigError
from vyos import airbag
@@ -93,7 +92,7 @@ def generate(nhrp):
return None
def apply(nhrp):
- nft_rc = run(f'nft -f {nhrp_nftables_conf}')
+ nft_rc = run(f'nft --file {nhrp_nftables_conf}')
if nft_rc != 0:
raise ConfigError('Failed to apply NHRP tunnel firewall rules')
diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py
index afd767dbf..1bb172293 100755
--- a/src/conf_mode/protocols_ospfv3.py
+++ b/src/conf_mode/protocols_ospfv3.py
@@ -14,8 +14,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 os
-
from sys import exit
from sys import argv
diff --git a/src/conf_mode/protocols_rip.py b/src/conf_mode/protocols_rip.py
index bd47dfd00..9afac544d 100755
--- a/src/conf_mode/protocols_rip.py
+++ b/src/conf_mode/protocols_rip.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2022 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -14,8 +14,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 os
-
from sys import exit
from vyos.config import Config
diff --git a/src/conf_mode/protocols_ripng.py b/src/conf_mode/protocols_ripng.py
index dd1550033..23416ff96 100755
--- a/src/conf_mode/protocols_ripng.py
+++ b/src/conf_mode/protocols_ripng.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -14,8 +14,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 os
-
from sys import exit
from vyos.config import Config
diff --git a/src/conf_mode/protocols_segment-routing.py b/src/conf_mode/protocols_segment-routing.py
index d865c2ac0..b36c2ca11 100755
--- a/src/conf_mode/protocols_segment-routing.py
+++ b/src/conf_mode/protocols_segment-routing.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -14,8 +14,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 os
-
from sys import exit
from vyos.config import Config
diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py
index 5def8d645..a2373218a 100755
--- a/src/conf_mode/protocols_static.py
+++ b/src/conf_mode/protocols_static.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -14,8 +14,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 os
-
from sys import exit
from sys import argv
diff --git a/src/conf_mode/protocols_static_neighbor-proxy.py b/src/conf_mode/protocols_static_neighbor-proxy.py
index 10cc1e748..8a1ea1df9 100755
--- a/src/conf_mode/protocols_static_neighbor-proxy.py
+++ b/src/conf_mode/protocols_static_neighbor-proxy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -14,19 +14,14 @@
# 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
-
from sys import exit
from vyos.config import Config
-from vyos.configdict import node_changed
from vyos.utils.process import call
from vyos import ConfigError
from vyos import airbag
-
airbag.enable()
-
def get_config(config=None):
if config:
conf = config
@@ -38,9 +33,7 @@ def get_config(config=None):
return config
-
def verify(config):
-
if 'arp' in config:
for neighbor, neighbor_conf in config['arp'].items():
if 'interface' not in neighbor_conf:
@@ -55,11 +48,9 @@ def verify(config):
f"ARP neighbor-proxy for '{neighbor}' requires an interface to be set!"
)
-
def generate(config):
pass
-
def apply(config):
if not config:
# Cleanup proxy
@@ -83,7 +74,6 @@ def apply(config):
for interface in neighbor_conf['interface']:
call(f'ip -6 neighbor add proxy {neighbor} dev {interface}')
-
if __name__ == '__main__':
try:
c = get_config()
diff --git a/src/conf_mode/qos.py b/src/conf_mode/qos.py
index 4a0b4d0c5..3dfb4bab8 100755
--- a/src/conf_mode/qos.py
+++ b/src/conf_mode/qos.py
@@ -14,15 +14,14 @@
# 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
-
from sys import exit
from netifaces import interfaces
-from vyos.base import Warning
from vyos.config import Config
-from vyos.configdep import set_dependents, call_dependents
+from vyos.configdep import set_dependents
+from vyos.configdep import call_dependents
from vyos.configdict import dict_merge
+from vyos.configverify import verify_interface_exists
from vyos.ifconfig import Section
from vyos.qos import CAKE
from vyos.qos import DropTail
@@ -36,8 +35,8 @@ from vyos.qos import RateLimiter
from vyos.qos import RoundRobin
from vyos.qos import TrafficShaper
from vyos.qos import TrafficShaperHFSC
-from vyos.utils.process import run
from vyos.utils.dict import dict_search_recursive
+from vyos.utils.process import run
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -214,11 +213,10 @@ def apply(qos):
return None
for interface, interface_config in qos['interface'].items():
- if not os.path.exists(f'/sys/class/net/{interface}'):
+ if not verify_interface_exists(interface, warning_only=True):
# When shaper is bound to a dialup (e.g. PPPoE) interface it is
# possible that it is yet not availbale when to QoS code runs.
- # Skip the configuration and inform the user
- Warning(f'Interface "{interface}" does not exist!')
+ # Skip the configuration and inform the user via warning_only=True
continue
for direction in ['egress', 'ingress']:
diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py
index ba3d69b07..e89448e2d 100755
--- a/src/conf_mode/service_dhcp-server.py
+++ b/src/conf_mode/service_dhcp-server.py
@@ -16,6 +16,7 @@
import os
+from glob import glob
from ipaddress import ip_address
from ipaddress import ip_network
from netaddr import IPRange
@@ -28,6 +29,7 @@ from vyos.template import render
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_search_args
from vyos.utils.file import chmod_775
+from vyos.utils.file import chown
from vyos.utils.file import makedir
from vyos.utils.file import write_file
from vyos.utils.process import call
@@ -42,6 +44,7 @@ ctrl_config_file = '/run/kea/kea-ctrl-agent.conf'
ctrl_socket = '/run/kea/dhcp4-ctrl-socket'
config_file = '/run/kea/kea-dhcp4.conf'
lease_file = '/config/dhcp/dhcp4-leases.csv'
+lease_file_glob = '/config/dhcp/dhcp4-leases*'
systemd_override = r'/run/systemd/system/kea-ctrl-agent.service.d/10-override.conf'
user_group = '_kea'
@@ -143,8 +146,12 @@ def get_config(config=None):
dhcp['shared_network_name'][network]['subnet'][subnet].update(
{'range' : new_range_dict})
- if dict_search('high_availability.certificate', dhcp):
- dhcp['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True)
+ if len(dhcp['high_availability']) == 1:
+ ## only default value for mode is set, need to remove ha node
+ del dhcp['high_availability']
+ else:
+ if dict_search('high_availability.certificate', dhcp):
+ dhcp['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True)
return dhcp
@@ -161,7 +168,6 @@ def verify(dhcp):
# Inspect shared-network/subnet
listen_ok = False
subnets = []
- failover_ok = False
shared_networks = len(dhcp['shared_network_name'])
disabled_shared_networks = 0
@@ -316,7 +322,7 @@ def verify(dhcp):
raise ConfigError(f'Invalid CA certificate specified for DHCP high-availability')
for address in (dict_search('listen_address', dhcp) or []):
- if is_addr_assigned(address):
+ if is_addr_assigned(address, include_vrf=True):
listen_ok = True
# no need to probe further networks, we have one that is valid
continue
@@ -351,6 +357,10 @@ def generate(dhcp):
makedir(lease_dir, group='vyattacfg')
chmod_775(lease_dir)
+ # Ensure correct permissions on lease files + backups
+ for file in glob(lease_file_glob):
+ chown(file, user=user_group, group='vyattacfg')
+
# Create lease file if necessary and let kea own it - 'kea-lfc' expects it that way
if not os.path.exists(lease_file):
write_file(lease_file, '', user=user_group, group=user_group, mode=0o644)
diff --git a/src/conf_mode/service_dhcpv6-server.py b/src/conf_mode/service_dhcpv6-server.py
index add83eb0d..c7333dd3a 100755
--- a/src/conf_mode/service_dhcpv6-server.py
+++ b/src/conf_mode/service_dhcpv6-server.py
@@ -16,6 +16,7 @@
import os
+from glob import glob
from ipaddress import ip_address
from ipaddress import ip_network
from sys import exit
@@ -24,6 +25,7 @@ from vyos.config import Config
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.file import chmod_775
+from vyos.utils.file import chown
from vyos.utils.file import makedir
from vyos.utils.file import write_file
from vyos.utils.dict import dict_search
@@ -35,6 +37,7 @@ airbag.enable()
config_file = '/run/kea/kea-dhcp6.conf'
ctrl_socket = '/run/kea/dhcp6-ctrl-socket'
lease_file = '/config/dhcp/dhcp6-leases.csv'
+lease_file_glob = '/config/dhcp/dhcp6-leases*'
user_group = '_kea'
def get_config(config=None):
@@ -224,6 +227,10 @@ def generate(dhcpv6):
makedir(lease_dir, group='vyattacfg')
chmod_775(lease_dir)
+ # Ensure correct permissions on lease files + backups
+ for file in glob(lease_file_glob):
+ chown(file, user=user_group, group='vyattacfg')
+
# Create lease file if necessary and let kea own it - 'kea-lfc' expects it that way
if not os.path.exists(lease_file):
write_file(lease_file, '', user=user_group, group=user_group, mode=0o644)
diff --git a/src/conf_mode/service_dns_forwarding.py b/src/conf_mode/service_dns_forwarding.py
index ecad765f4..7e863073a 100755
--- a/src/conf_mode/service_dns_forwarding.py
+++ b/src/conf_mode/service_dns_forwarding.py
@@ -16,7 +16,6 @@
import os
-from netifaces import interfaces
from sys import exit
from glob import glob
@@ -24,9 +23,9 @@ from vyos.config import Config
from vyos.hostsd_client import Client as hostsd_client
from vyos.template import render
from vyos.template import bracketize_ipv6
+from vyos.utils.network import interface_exists
from vyos.utils.process import call
from vyos.utils.permission import chown
-
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -330,7 +329,7 @@ def apply(dns):
# names (DHCP) to use DNS servers. We need to check if the
# value is an interface name - only if this is the case, add the
# interface based DNS forwarder.
- if interface in interfaces():
+ if interface_exists(interface):
hc.add_name_server_tags_recursor(['dhcp-' + interface,
'dhcpv6-' + interface ])
diff --git a/src/conf_mode/service_https.py b/src/conf_mode/service_https.py
index 46efc3c93..9e58b4c72 100755
--- a/src/conf_mode/service_https.py
+++ b/src/conf_mode/service_https.py
@@ -24,13 +24,14 @@ from time import sleep
from vyos.base import Warning
from vyos.config import Config
from vyos.config import config_dict_merge
-from vyos.configdiff import get_config_diff
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_pki_certificate
+from vyos.configverify import verify_pki_ca_certificate
+from vyos.configverify import verify_pki_dh_parameters
from vyos.defaults import api_config_state
from vyos.pki import wrap_certificate
from vyos.pki import wrap_private_key
from vyos.pki import wrap_dh_parameters
-from vyos.pki import load_dh_parameters
from vyos.template import render
from vyos.utils.dict import dict_search
from vyos.utils.process import call
@@ -84,33 +85,14 @@ def verify(https):
if https is None:
return None
- if 'certificates' in https and 'certificate' in https['certificates']:
- cert_name = https['certificates']['certificate']
- if 'pki' not in https:
- raise ConfigError('PKI is not configured!')
-
- if cert_name not in https['pki']['certificate']:
- raise ConfigError('Invalid certificate in configuration!')
+ if dict_search('certificates.certificate', https) != None:
+ verify_pki_certificate(https, https['certificates']['certificate'])
- pki_cert = https['pki']['certificate'][cert_name]
-
- if 'certificate' not in pki_cert:
- raise ConfigError('Missing certificate in configuration!')
+ tmp = dict_search('certificates.ca_certificate', https)
+ if tmp != None: verify_pki_ca_certificate(https, tmp)
- if 'private' not in pki_cert or 'key' not in pki_cert['private']:
- raise ConfigError('Missing certificate private key in configuration!')
-
- if 'dh_params' in https['certificates']:
- dh_name = https['certificates']['dh_params']
- if dh_name not in https['pki']['dh']:
- raise ConfigError('Invalid DH parameter in configuration!')
-
- pki_dh = https['pki']['dh'][dh_name]
- dh_params = load_dh_parameters(pki_dh['parameters'])
- dh_numbers = dh_params.parameter_numbers()
- dh_bits = dh_numbers.p.bit_length()
- if dh_bits < 2048:
- raise ConfigError(f'Minimum DH key-size is 2048 bits')
+ tmp = dict_search('certificates.dh_params', https)
+ if tmp != None: verify_pki_dh_parameters(https, tmp, 2048)
else:
Warning('No certificate specified, using build-in self-signed certificates. '\
@@ -214,7 +196,8 @@ def apply(https):
https_service_name = 'nginx.service'
if https is None:
- call(f'systemctl stop {http_api_service_name}')
+ if is_systemd_service_active(http_api_service_name):
+ call(f'systemctl stop {http_api_service_name}')
call(f'systemctl stop {https_service_name}')
return
diff --git a/src/conf_mode/service_ipoe-server.py b/src/conf_mode/service_ipoe-server.py
index 852b714eb..11e950782 100755
--- a/src/conf_mode/service_ipoe-server.py
+++ b/src/conf_mode/service_ipoe-server.py
@@ -68,8 +68,8 @@ def verify(ipoe):
for interface, iface_config in ipoe['interface'].items():
verify_interface_exists(interface)
if 'client_subnet' in iface_config and 'vlan' in iface_config:
- raise ConfigError('Option "client-subnet" incompatible with "vlan"!'
- 'Use "ipoe client-ip-pool" instead.')
+ raise ConfigError('Option "client-subnet" and "vlan" are mutually exclusive, '
+ 'use "client-ip-pool" instead!')
verify_accel_ppp_authentication(ipoe, local_users=False)
verify_accel_ppp_ip_pool(ipoe)
diff --git a/src/conf_mode/service_lldp.py b/src/conf_mode/service_lldp.py
index 3c647a0e8..04b1db880 100755
--- a/src/conf_mode/service_lldp.py
+++ b/src/conf_mode/service_lldp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2017-2022 VyOS maintainers and contributors
+# Copyright (C) 2017-2024 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
@@ -24,7 +24,6 @@ from vyos.utils.network import is_addr_assigned
from vyos.utils.network import is_loopback_addr
from vyos.version import get_version_data
from vyos.utils.process import call
-from vyos.utils.dict import dict_search
from vyos.template import render
from vyos import ConfigError
from vyos import airbag
diff --git a/src/conf_mode/service_mdns_repeater.py b/src/conf_mode/service_mdns_repeater.py
index 6526c23d1..207da5e03 100755
--- a/src/conf_mode/service_mdns_repeater.py
+++ b/src/conf_mode/service_mdns_repeater.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2017-2022 VyOS maintainers and contributors
+# Copyright (C) 2017-2024 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
@@ -18,9 +18,10 @@ import os
from json import loads
from sys import exit
-from netifaces import ifaddresses, interfaces, AF_INET, AF_INET6
+from netifaces import ifaddresses, AF_INET, AF_INET6
from vyos.config import Config
+from vyos.configverify import verify_interface_exists
from vyos.ifconfig.vrrp import VRRP
from vyos.template import render
from vyos.utils.process import call
@@ -64,8 +65,7 @@ def verify(mdns):
# For mdns-repeater to work it is essential that the interfaces has
# an IPv4 address assigned
for interface in mdns['interface']:
- if interface not in interfaces():
- raise ConfigError(f'Interface "{interface}" does not exist!')
+ verify_interface_exists(interface)
if mdns['ip_version'] in ['ipv4', 'both'] and AF_INET not in ifaddresses(interface):
raise ConfigError('mDNS repeater requires an IPv4 address to be '
diff --git a/src/conf_mode/service_pppoe-server.py b/src/conf_mode/service_pppoe-server.py
index c9d1e805f..b9d174933 100755
--- a/src/conf_mode/service_pppoe-server.py
+++ b/src/conf_mode/service_pppoe-server.py
@@ -38,6 +38,16 @@ airbag.enable()
pppoe_conf = r'/run/accel-pppd/pppoe.conf'
pppoe_chap_secrets = r'/run/accel-pppd/pppoe.chap-secrets'
+def convert_pado_delay(pado_delay):
+ new_pado_delay = {'delays_without_sessions': [],
+ 'delays_with_sessions': []}
+ for delay, sessions in pado_delay.items():
+ if not sessions:
+ new_pado_delay['delays_without_sessions'].append(delay)
+ else:
+ new_pado_delay['delays_with_sessions'].append((delay, int(sessions['sessions'])))
+ return new_pado_delay
+
def get_config(config=None):
if config:
conf = config
@@ -54,6 +64,10 @@ def get_config(config=None):
# Multiple named pools require ordered values T5099
pppoe['ordered_named_pools'] = get_pools_in_order(dict_search('client_ip_pool', pppoe))
+ if dict_search('pado_delay', pppoe):
+ pado_delay = dict_search('pado_delay', pppoe)
+ pppoe['pado_delay'] = convert_pado_delay(pado_delay)
+
# reload-or-restart does not implemented in accel-ppp
# use this workaround until it will be implemented
# https://phabricator.accel-ppp.org/T3
@@ -65,6 +79,17 @@ def get_config(config=None):
pppoe['server_type'] = 'pppoe'
return pppoe
+def verify_pado_delay(pppoe):
+ if 'pado_delay' in pppoe:
+ pado_delay = pppoe['pado_delay']
+
+ delays_without_sessions = pado_delay['delays_without_sessions']
+ if len(delays_without_sessions) > 1:
+ raise ConfigError(
+ f'Cannot add more then ONE pado-delay without sessions, '
+ f'but {len(delays_without_sessions)} were set'
+ )
+
def verify(pppoe):
if not pppoe:
return None
@@ -73,7 +98,7 @@ def verify(pppoe):
verify_accel_ppp_ip_pool(pppoe)
verify_accel_ppp_name_servers(pppoe)
verify_accel_ppp_wins_servers(pppoe)
-
+ verify_pado_delay(pppoe)
if 'interface' not in pppoe:
raise ConfigError('At least one listen interface must be defined!')
diff --git a/src/conf_mode/service_ssh.py b/src/conf_mode/service_ssh.py
index ee5e1eca2..9abdd33dc 100755
--- a/src/conf_mode/service_ssh.py
+++ b/src/conf_mode/service_ssh.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2022 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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
@@ -30,7 +30,6 @@ from vyos import airbag
airbag.enable()
config_file = r'/run/sshd/sshd_config'
-systemd_override = r'/run/systemd/system/ssh.service.d/override.conf'
sshguard_config_file = '/etc/sshguard/sshguard.conf'
sshguard_whitelist = '/etc/sshguard/whitelist'
@@ -81,8 +80,6 @@ def generate(ssh):
if not ssh:
if os.path.isfile(config_file):
os.unlink(config_file)
- if os.path.isfile(systemd_override):
- os.unlink(systemd_override)
return None
@@ -99,13 +96,10 @@ def generate(ssh):
call(f'ssh-keygen -q -N "" -t ed25519 -f {key_ed25519}')
render(config_file, 'ssh/sshd_config.j2', ssh)
- render(systemd_override, 'ssh/override.conf.j2', ssh)
if 'dynamic_protection' in ssh:
render(sshguard_config_file, 'ssh/sshguard_config.j2', ssh)
render(sshguard_whitelist, 'ssh/sshguard_whitelist.j2', ssh)
- # Reload systemd manager configuration
- call('systemctl daemon-reload')
return None
@@ -114,7 +108,7 @@ def apply(ssh):
systemd_service_sshguard = 'sshguard.service'
if not ssh:
# SSH access is removed in the commit
- call(f'systemctl stop {systemd_service_ssh}')
+ call(f'systemctl stop ssh@*.service')
call(f'systemctl stop {systemd_service_sshguard}')
return None
@@ -126,9 +120,13 @@ def apply(ssh):
# we need to restart the service if e.g. the VRF name changed
systemd_action = 'reload-or-restart'
if 'restart_required' in ssh:
+ # this is only true if something for the VRFs changed, thus we
+ # stop all VRF services and only restart then new ones
+ call(f'systemctl stop ssh@*.service')
systemd_action = 'restart'
- call(f'systemctl {systemd_action} {systemd_service_ssh}')
+ for vrf in ssh['vrf']:
+ call(f'systemctl {systemd_action} ssh@{vrf}.service')
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/service_tftp-server.py b/src/conf_mode/service_tftp-server.py
index 3ad346e2e..5b7303c40 100755
--- a/src/conf_mode/service_tftp-server.py
+++ b/src/conf_mode/service_tftp-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2020 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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,7 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import stat
import pwd
from copy import deepcopy
diff --git a/src/conf_mode/service_upnp.py b/src/conf_mode/service_upnp.py
index cf26bf9ce..0df8dc09e 100755
--- a/src/conf_mode/service_upnp.py
+++ b/src/conf_mode/service_upnp.py
@@ -54,9 +54,7 @@ def get_config(config=None):
def get_all_interface_addr(prefix, filter_dev, filter_family):
list_addr = []
- interfaces = netifaces.interfaces()
-
- for interface in interfaces:
+ for interface in netifaces.interfaces():
if filter_dev and interface in filter_dev:
continue
addrs = netifaces.ifaddresses(interface)
diff --git a/src/conf_mode/system_conntrack.py b/src/conf_mode/system_conntrack.py
index 3d42389f6..031fe63b0 100755
--- a/src/conf_mode/system_conntrack.py
+++ b/src/conf_mode/system_conntrack.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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,19 +15,16 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import re
from sys import exit
from vyos.config import Config
from vyos.configdep import set_dependents, call_dependents
-from vyos.utils.process import process_named_running
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_search_args
from vyos.utils.dict import dict_search_recursive
from vyos.utils.process import cmd
from vyos.utils.process import rc_cmd
-from vyos.utils.process import run
from vyos.template import render
from vyos import ConfigError
from vyos import airbag
@@ -223,7 +220,7 @@ def apply(conntrack):
cmd(f'modprobe -a {module_str}')
# Load new nftables ruleset
- install_result, output = rc_cmd(f'nft -f {nftables_ct_file}')
+ install_result, output = rc_cmd(f'nft --file {nftables_ct_file}')
if install_result == 1:
raise ConfigError(f'Failed to apply configuration: {output}')
diff --git a/src/conf_mode/system_console.py b/src/conf_mode/system_console.py
index a888b125e..19bbb8875 100755
--- a/src/conf_mode/system_console.py
+++ b/src/conf_mode/system_console.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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,13 +15,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import re
from pathlib import Path
from vyos.config import Config
from vyos.utils.process import call
-from vyos.utils.file import read_file
-from vyos.utils.file import write_file
from vyos.system import grub_util
from vyos.template import render
from vyos import ConfigError
diff --git a/src/conf_mode/system_flow-accounting.py b/src/conf_mode/system_flow-accounting.py
index 206f513c8..2dacd92da 100755
--- a/src/conf_mode/system_flow-accounting.py
+++ b/src/conf_mode/system_flow-accounting.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2023 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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
@@ -20,11 +20,10 @@ import re
from sys import exit
from ipaddress import ip_address
-from vyos.base import Warning
from vyos.config import Config
from vyos.config import config_dict_merge
from vyos.configverify import verify_vrf
-from vyos.ifconfig import Section
+from vyos.configverify import verify_interface_exists
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.process import cmd
@@ -184,10 +183,7 @@ def verify(flow_config):
# check that all configured interfaces exists in the system
for interface in flow_config['interface']:
- if interface not in Section.interfaces():
- # Changed from error to warning to allow adding dynamic interfaces
- # and interface templates
- Warning(f'Interface "{interface}" is not presented in the system')
+ verify_interface_exists(interface, warning_only=True)
# check sFlow configuration
if 'sflow' in flow_config:
diff --git a/src/conf_mode/system_frr.py b/src/conf_mode/system_frr.py
index 07f291000..d9ac543d0 100755
--- a/src/conf_mode/system_frr.py
+++ b/src/conf_mode/system_frr.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -14,7 +14,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/>.
-from pathlib import Path
from sys import exit
from vyos import ConfigError
diff --git a/src/conf_mode/system_host-name.py b/src/conf_mode/system_host-name.py
index 6204cf247..8975cadb6 100755
--- a/src/conf_mode/system_host-name.py
+++ b/src/conf_mode/system_host-name.py
@@ -71,9 +71,9 @@ def get_config(config=None):
hosts['nameserver'].append(ns)
else:
tmp = ''
- if_type = Section.section(ns)
- if conf.exists(['interfaces', if_type, ns, 'address']):
- tmp = conf.return_values(['interfaces', if_type, ns, 'address'])
+ config_path = Section.get_config_path(ns)
+ if conf.exists(['interfaces', config_path, 'address']):
+ tmp = conf.return_values(['interfaces', config_path, 'address'])
hosts['nameservers_dhcp_interfaces'].update({ ns : tmp })
diff --git a/src/conf_mode/system_ip.py b/src/conf_mode/system_ip.py
index 833f89554..2a0bda91a 100755
--- a/src/conf_mode/system_ip.py
+++ b/src/conf_mode/system_ip.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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
@@ -22,7 +22,6 @@ from vyos.configverify import verify_route_map
from vyos.template import render_to_string
from vyos.utils.dict import dict_search
from vyos.utils.file import write_file
-from vyos.utils.process import call
from vyos.utils.process import is_systemd_service_active
from vyos.utils.system import sysctl_write
@@ -82,11 +81,6 @@ def apply(opt):
value = '0' if (tmp != None) else '1'
write_file('/proc/sys/net/ipv4/conf/all/forwarding', value)
- # enable/disable IPv4 directed broadcast forwarding
- tmp = dict_search('disable_directed_broadcast', opt)
- value = '0' if (tmp != None) else '1'
- write_file('/proc/sys/net/ipv4/conf/all/bc_forwarding', value)
-
# configure multipath
tmp = dict_search('multipath.ignore_unreachable_nexthops', opt)
value = '1' if (tmp != None) else '0'
diff --git a/src/conf_mode/system_login.py b/src/conf_mode/system_login.py
index 49306c894..20121f170 100755
--- a/src/conf_mode/system_login.py
+++ b/src/conf_mode/system_login.py
@@ -336,27 +336,31 @@ def apply(login):
command += f' --groups frr,frrvty,vyattacfg,sudo,adm,dip,disk,_kea {user}'
try:
cmd(command)
- # we should not rely on the value stored in
- # user_config['home_directory'], as a crazy user will choose
- # username root or any other system user which will fail.
+ # we should not rely on the value stored in user_config['home_directory'], as a
+ # crazy user will choose username root or any other system user which will fail.
#
# XXX: Should we deny using root at all?
home_dir = getpwnam(user).pw_dir
- # T5875: ensure UID is properly set on home directory if user is re-added
- # the home directory will always exist, as it's created above by --create-home,
- # retrieve current owner of home directory and adjust it on demand
- dir_owner = getpwuid(os.stat(home_dir).st_uid).pw_name
- if dir_owner != user:
- chown(home_dir, user=user, recursive=True)
-
+ # always re-render SSH keys with appropriate permissions
render(f'{home_dir}/.ssh/authorized_keys', 'login/authorized_keys.j2',
user_config, permission=0o600,
formater=lambda _: _.replace("&quot;", '"'),
user=user, group='users')
-
except Exception as e:
raise ConfigError(f'Adding user "{user}" raised exception: "{e}"')
+ # T5875: ensure UID is properly set on home directory if user is re-added
+ # the home directory will always exist, as it's created above by --create-home,
+ # retrieve current owner of home directory and adjust on demand
+ dir_owner = None
+ try:
+ dir_owner = getpwuid(os.stat(home_dir).st_uid).pw_name
+ except:
+ pass
+
+ if dir_owner != user:
+ chown(home_dir, user=user, recursive=True)
+
# Generate 2FA/MFA One-Time-Pad configuration
if dict_search('authentication.otp.key', user_config):
enable_otp = True
diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py
index 7ed451e16..a2e5db575 100755
--- a/src/conf_mode/system_option.py
+++ b/src/conf_mode/system_option.py
@@ -16,12 +16,12 @@
import os
-from netifaces import interfaces
from sys import exit
from time import sleep
from vyos.config import Config
from vyos.configverify import verify_source_interface
+from vyos.configverify import verify_interface_exists
from vyos.system import grub_util
from vyos.template import render
from vyos.utils.process import cmd
@@ -56,9 +56,7 @@ def verify(options):
if 'http_client' in options:
config = options['http_client']
if 'source_interface' in config:
- if not config['source_interface'] in interfaces():
- raise ConfigError(f'Source interface {source_interface} does not '
- f'exist'.format(**config))
+ verify_interface_exists(config['source_interface'])
if {'source_address', 'source_interface'} <= set(config):
raise ConfigError('Can not define both HTTP source-interface and source-address')
diff --git a/src/conf_mode/system_timezone.py b/src/conf_mode/system_timezone.py
index cd3d4b229..39770fdb4 100755
--- a/src/conf_mode/system_timezone.py
+++ b/src/conf_mode/system_timezone.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019 VyOS maintainers and contributors
+# Copyright (C) 2019-2024 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,7 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
-import os
from copy import deepcopy
from vyos.config import Config
diff --git a/src/conf_mode/system_update-check.py b/src/conf_mode/system_update-check.py
index 8d641a97d..71ac13e51 100755
--- a/src/conf_mode/system_update-check.py
+++ b/src/conf_mode/system_update-check.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -14,9 +14,7 @@
# 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 json
-import jmespath
from pathlib import Path
from sys import exit
@@ -27,7 +25,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-
base = ['system', 'update-check']
service_name = 'vyos-system-update'
service_conf = Path(f'/run/{service_name}.conf')
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index 0c2f232df..dc78c755e 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -21,7 +21,6 @@ import jmespath
from sys import exit
from time import sleep
-from time import time
from vyos.base import Warning
from vyos.config import Config
@@ -47,7 +46,6 @@ from vyos.utils.network import interface_exists
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_search_args
from vyos.utils.process import call
-from vyos.utils.process import run
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -168,9 +166,7 @@ def verify(ipsec):
for interface in ipsec['interface']:
# exclude check interface for dynamic interfaces
if tmp.match(interface):
- if not interface_exists(interface):
- Warning(f'Interface "{interface}" does not exist yet and cannot be used '
- f'for IPsec until it is up!')
+ verify_interface_exists(interface, warning_only=True)
else:
verify_interface_exists(interface)
diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py
index 08e4fc6db..8159fedea 100755
--- a/src/conf_mode/vpn_openconnect.py
+++ b/src/conf_mode/vpn_openconnect.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2023 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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
@@ -19,6 +19,8 @@ from sys import exit
from vyos.base import Warning
from vyos.config import Config
+from vyos.configverify import verify_pki_certificate
+from vyos.configverify import verify_pki_ca_certificate
from vyos.pki import wrap_certificate
from vyos.pki import wrap_private_key
from vyos.template import render
@@ -75,7 +77,7 @@ def verify(ocserv):
if "accounting" in ocserv:
if "mode" in ocserv["accounting"] and "radius" in ocserv["accounting"]["mode"]:
if not origin["accounting"]['radius']['server']:
- raise ConfigError('Openconnect accounting mode radius requires at least one RADIUS server')
+ raise ConfigError('OpenConnect accounting mode radius requires at least one RADIUS server')
if "authentication" not in ocserv or "mode" not in ocserv["authentication"]:
raise ConfigError('Accounting depends on OpenConnect authentication configuration')
elif "radius" not in ocserv["authentication"]["mode"]:
@@ -89,12 +91,12 @@ def verify(ocserv):
raise ConfigError('OpenConnect authentication modes are mutually-exclusive, remove either local or radius from your configuration')
if "radius" in ocserv["authentication"]["mode"]:
if not ocserv["authentication"]['radius']['server']:
- raise ConfigError('Openconnect authentication mode radius requires at least one RADIUS server')
+ raise ConfigError('OpenConnect authentication mode radius requires at least one RADIUS server')
if "local" in ocserv["authentication"]["mode"]:
if not ocserv.get("authentication", {}).get("local_users"):
- raise ConfigError('openconnect mode local required at least one user')
+ raise ConfigError('OpenConnect mode local required at least one user')
if not ocserv["authentication"]["local_users"]["username"]:
- raise ConfigError('openconnect mode local required at least one user')
+ raise ConfigError('OpenConnect mode local required at least one user')
else:
# For OTP mode: verify that each local user has an OTP key
if "otp" in ocserv["authentication"]["mode"]["local"]:
@@ -127,40 +129,20 @@ def verify(ocserv):
if 'default_config' not in ocserv["authentication"]["identity_based_config"]:
raise ConfigError('OpenConnect identity-based-config enabled but default-config not set')
else:
- raise ConfigError('openconnect authentication mode required')
+ raise ConfigError('OpenConnect authentication mode required')
else:
- raise ConfigError('openconnect authentication credentials required')
+ raise ConfigError('OpenConnect authentication credentials required')
# Check ssl
if 'ssl' not in ocserv:
- raise ConfigError('openconnect ssl required')
+ raise ConfigError('SSL missing on OpenConnect config!')
- if not ocserv['pki'] or 'certificate' not in ocserv['pki']:
- raise ConfigError('PKI not configured')
+ if 'certificate' not in ocserv['ssl']:
+ raise ConfigError('SSL certificate missing on OpenConnect config!')
+ verify_pki_certificate(ocserv, ocserv['ssl']['certificate'])
- ssl = ocserv['ssl']
- if 'certificate' not in ssl:
- raise ConfigError('openconnect ssl certificate required')
-
- cert_name = ssl['certificate']
-
- if cert_name not in ocserv['pki']['certificate']:
- raise ConfigError('Invalid openconnect ssl certificate')
-
- cert = ocserv['pki']['certificate'][cert_name]
-
- if 'certificate' not in cert:
- raise ConfigError('Missing certificate in PKI')
-
- if 'private' not in cert or 'key' not in cert['private']:
- raise ConfigError('Missing private key in PKI')
-
- if 'ca_certificate' in ssl:
- if 'ca' not in ocserv['pki']:
- raise ConfigError('PKI not configured')
-
- if ssl['ca_certificate'] not in ocserv['pki']['ca']:
- raise ConfigError('Invalid openconnect ssl CA certificate')
+ if 'ca_certificate' in ocserv['ssl']:
+ verify_pki_ca_certificate(ocserv, ocserv['ssl']['ca_certificate'])
# Check network settings
if "network_settings" in ocserv:
@@ -172,7 +154,7 @@ def verify(ocserv):
else:
ocserv["network_settings"]["push_route"] = ["default"]
else:
- raise ConfigError('openconnect network settings required')
+ raise ConfigError('OpenConnect network settings required!')
def generate(ocserv):
if not ocserv:
@@ -276,7 +258,7 @@ def apply(ocserv):
break
sleep(0.250)
if counter > 5:
- raise ConfigError('openconnect failed to start, check the logs for details')
+ raise ConfigError('OpenConnect failed to start, check the logs for details')
break
counter += 1
diff --git a/src/conf_mode/vpn_sstp.py b/src/conf_mode/vpn_sstp.py
index 8661a8aff..7490fd0e0 100755
--- a/src/conf_mode/vpn_sstp.py
+++ b/src/conf_mode/vpn_sstp.py
@@ -20,6 +20,8 @@ from sys import exit
from vyos.config import Config
from vyos.configdict import get_accel_dict
+from vyos.configverify import verify_pki_certificate
+from vyos.configverify import verify_pki_ca_certificate
from vyos.pki import wrap_certificate
from vyos.pki import wrap_private_key
from vyos.template import render
@@ -46,51 +48,6 @@ cert_key_path = os.path.join(cfg_dir, 'sstp-cert.key')
ca_cert_file_path = os.path.join(cfg_dir, 'sstp-ca.pem')
-def verify_certificate(config):
- #
- # SSL certificate checks
- #
- if not config['pki']:
- raise ConfigError('PKI is not configured')
-
- if 'ssl' not in config:
- raise ConfigError('SSL missing on SSTP config')
-
- ssl = config['ssl']
-
- # CA
- if 'ca_certificate' not in ssl:
- raise ConfigError('SSL CA certificate missing on SSTP config')
-
- ca_name = ssl['ca_certificate']
-
- if ca_name not in config['pki']['ca']:
- raise ConfigError('Invalid CA certificate on SSTP config')
-
- if 'certificate' not in config['pki']['ca'][ca_name]:
- raise ConfigError('Missing certificate data for CA certificate on SSTP config')
-
- # Certificate
- if 'certificate' not in ssl:
- raise ConfigError('SSL certificate missing on SSTP config')
-
- cert_name = ssl['certificate']
-
- if cert_name not in config['pki']['certificate']:
- raise ConfigError('Invalid certificate on SSTP config')
-
- pki_cert = config['pki']['certificate'][cert_name]
-
- if 'certificate' not in pki_cert:
- raise ConfigError('Missing certificate data for certificate on SSTP config')
-
- if 'private' not in pki_cert or 'key' not in pki_cert['private']:
- raise ConfigError('Missing private key for certificate on SSTP config')
-
- if 'password_protected' in pki_cert['private']:
- raise ConfigError('Encrypted private key is not supported on SSTP config')
-
-
def get_config(config=None):
if config:
conf = config
@@ -124,7 +81,17 @@ def verify(sstp):
verify_accel_ppp_ip_pool(sstp)
verify_accel_ppp_name_servers(sstp)
verify_accel_ppp_wins_servers(sstp)
- verify_certificate(sstp)
+
+ if 'ssl' not in sstp:
+ raise ConfigError('SSL missing on SSTP config!')
+
+ if 'certificate' not in sstp['ssl']:
+ raise ConfigError('SSL certificate missing on SSTP config!')
+ verify_pki_certificate(sstp, sstp['ssl']['certificate'])
+
+ if 'ca_certificate' not in sstp['ssl']:
+ raise ConfigError('SSL CA certificate missing on SSTP config!')
+ verify_pki_ca_certificate(sstp, sstp['ssl']['ca_certificate'])
def generate(sstp):
@@ -154,15 +121,15 @@ def generate(sstp):
def apply(sstp):
+ systemd_service = 'accel-ppp@sstp.service'
if not sstp:
- call('systemctl stop accel-ppp@sstp.service')
+ call(f'systemctl stop {systemd_service}')
for file in [sstp_chap_secrets, sstp_conf]:
if os.path.exists(file):
os.unlink(file)
-
return None
- call('systemctl restart accel-ppp@sstp.service')
+ call(f'systemctl reload-or-restart {systemd_service}')
if __name__ == '__main__':
diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py
index 16908100f..1fc813189 100755
--- a/src/conf_mode/vrf.py
+++ b/src/conf_mode/vrf.py
@@ -14,8 +14,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 os
-
from sys import exit
from json import loads
@@ -33,6 +31,7 @@ from vyos.utils.network import get_vrf_members
from vyos.utils.network import interface_exists
from vyos.utils.process import call
from vyos.utils.process import cmd
+from vyos.utils.process import popen
from vyos.utils.system import sysctl_write
from vyos import ConfigError
from vyos import frr
@@ -227,7 +226,11 @@ def apply(vrf):
# Remove nftables conntrack zone map item
nft_del_element = f'delete element inet vrf_zones ct_iface_map {{ "{tmp}" }}'
- cmd(f'nft {nft_del_element}')
+ # Check if deleting is possible first to avoid raising errors
+ _, err = popen(f'nft --check {nft_del_element}')
+ if not err:
+ # Remove map element
+ cmd(f'nft {nft_del_element}')
# Delete the VRF Kernel interface
call(f'ip link delete dev {tmp}')
@@ -307,7 +310,7 @@ def apply(vrf):
if vrf['conntrack']:
for chain, rule in nftables_rules.items():
cmd(f'nft add rule inet vrf_zones {chain} {rule}')
-
+
if 'name' not in vrf or not vrf['conntrack']:
for chain, rule in nftables_rules.items():
cmd(f'nft flush chain inet vrf_zones {chain}')
diff --git a/src/conf_mode/vrf_vni.py b/src/conf_mode/vrf_vni.py
index 23b341079..8dab164d7 100644
--- a/src/conf_mode/vrf_vni.py
+++ b/src/conf_mode/vrf_vni.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -19,7 +19,6 @@ from sys import exit
from vyos.config import Config
from vyos.template import render_to_string
-from vyos.utils.dict import dict_search
from vyos import ConfigError
from vyos import frr
from vyos import airbag
diff --git a/src/etc/dhcp/dhclient-enter-hooks.d/04-vyos-resolvconf b/src/etc/dhcp/dhclient-enter-hooks.d/04-vyos-resolvconf
index 518abeaec..9a8a53bfd 100644
--- a/src/etc/dhcp/dhclient-enter-hooks.d/04-vyos-resolvconf
+++ b/src/etc/dhcp/dhclient-enter-hooks.d/04-vyos-resolvconf
@@ -14,14 +14,6 @@ if /usr/bin/systemctl -q is-active vyos-hostsd; then
hostsd_changes=y
fi
- if [ -n "$new_dhcp6_domain_search" ]; then
- logmsg info "Deleting search domains with tag \"dhcpv6-$interface\" via vyos-hostsd-client"
- $hostsd_client --delete-search-domains --tag "dhcpv6-$interface"
- logmsg info "Adding search domain \"$new_dhcp6_domain_search\" with tag \"dhcpv6-$interface\" via vyos-hostsd-client"
- $hostsd_client --add-search-domains "$new_dhcp6_domain_search" --tag "dhcpv6-$interface"
- hostsd_changes=y
- fi
-
if [ -n "$new_domain_name_servers" ]; then
logmsg info "Deleting nameservers with tag \"dhcp-$interface\" via vyos-hostsd-client"
$hostsd_client --delete-name-servers --tag "dhcp-$interface"
@@ -30,14 +22,6 @@ if /usr/bin/systemctl -q is-active vyos-hostsd; then
hostsd_changes=y
fi
- if [ -n "$new_dhcp6_name_servers" ]; then
- logmsg info "Deleting nameservers with tag \"dhcpv6-$interface\" via vyos-hostsd-client"
- $hostsd_client --delete-name-servers --tag "dhcpv6-$interface"
- logmsg info "Adding nameservers \"$new_dhcp6_name_servers\" with tag \"dhcpv6-$interface\" via vyos-hostsd-client"
- $hostsd_client --add-name-servers $new_dhcp6_name_servers --tag "dhcpv6-$interface"
- hostsd_changes=y
- fi
-
if [ $hostsd_changes ]; then
logmsg info "Applying changes via vyos-hostsd-client"
$hostsd_client --apply
diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/99-ipsec-dhclient-hook b/src/etc/dhcp/dhclient-exit-hooks.d/99-ipsec-dhclient-hook
index ebb100e8b..57f803055 100755
--- a/src/etc/dhcp/dhclient-exit-hooks.d/99-ipsec-dhclient-hook
+++ b/src/etc/dhcp/dhclient-exit-hooks.d/99-ipsec-dhclient-hook
@@ -17,7 +17,7 @@
DHCP_HOOK_IFLIST="/tmp/ipsec_dhcp_interfaces"
if ! { [ -f $DHCP_HOOK_IFLIST ] && grep -qw $interface $DHCP_HOOK_IFLIST; }; then
- exit 0
+ return 0
fi
# Re-generate the config on the following events:
@@ -26,10 +26,10 @@ fi
# - REBIND: re-generate if the IP address changed
if [ "$reason" == "RENEW" ] || [ "$reason" == "REBIND" ]; then
if [ "$old_ip_address" == "$new_ip_address" ]; then
- exit 0
+ return 0
fi
elif [ "$reason" != "BOUND" ]; then
- exit 0
+ return 0
fi
# Best effort wait for any active commit to finish
diff --git a/src/etc/systemd/system/ssh@.service.d/vrf-override.conf b/src/etc/systemd/system/ssh@.service.d/vrf-override.conf
new file mode 100644
index 000000000..b8952d86c
--- /dev/null
+++ b/src/etc/systemd/system/ssh@.service.d/vrf-override.conf
@@ -0,0 +1,13 @@
+[Unit]
+StartLimitIntervalSec=0
+After=vyos-router.service
+ConditionPathExists=/run/sshd/sshd_config
+
+[Service]
+EnvironmentFile=
+ExecStart=
+ExecStart=ip vrf exec %i /usr/sbin/sshd -f /run/sshd/sshd_config
+Restart=always
+RestartPreventExitStatus=
+RestartSec=10
+RuntimeDirectoryPreserve=yes
diff --git a/src/helpers/vyos-config-encrypt.py b/src/helpers/vyos-config-encrypt.py
index 8f7359767..0f9c63b1c 100755
--- a/src/helpers/vyos-config-encrypt.py
+++ b/src/helpers/vyos-config-encrypt.py
@@ -15,7 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import os
-import re
import shutil
import sys
@@ -25,7 +24,6 @@ from tempfile import NamedTemporaryFile
from tempfile import TemporaryDirectory
from vyos.tpm import clear_tpm_key
-from vyos.tpm import init_tpm
from vyos.tpm import read_tpm_key
from vyos.tpm import write_tpm_key
from vyos.util import ask_input
diff --git a/src/helpers/vyos-domain-resolver.py b/src/helpers/vyos-domain-resolver.py
index eac3d37af..57cfcabd7 100755
--- a/src/helpers/vyos-domain-resolver.py
+++ b/src/helpers/vyos-domain-resolver.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022-2023 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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,7 +15,6 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
-import os
import time
from vyos.configdict import dict_merge
@@ -95,7 +94,7 @@ def nft_output(table, set_name, ip_list):
def nft_valid_sets():
try:
valid_sets = []
- sets_json = cmd('nft -j list sets')
+ sets_json = cmd('nft --json list sets')
sets_obj = json.loads(sets_json)
for obj in sets_obj['nftables']:
@@ -155,7 +154,7 @@ def update(firewall):
count += 1
nft_conf_str = "\n".join(conf_lines) + "\n"
- code = run(f'nft -f -', input=nft_conf_str)
+ code = run(f'nft --file -', input=nft_conf_str)
print(f'Updated {count} sets - result: {code}')
diff --git a/src/helpers/vyos-failover.py b/src/helpers/vyos-failover.py
index cc7610370..f34c18916 100755
--- a/src/helpers/vyos-failover.py
+++ b/src/helpers/vyos-failover.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022-2023 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -16,7 +16,6 @@
import argparse
import json
-import subprocess
import socket
import time
diff --git a/src/helpers/vyos-merge-config.py b/src/helpers/vyos-merge-config.py
index 8997705fe..35424626e 100755
--- a/src/helpers/vyos-merge-config.py
+++ b/src/helpers/vyos-merge-config.py
@@ -1,6 +1,6 @@
#!/usr/bin/python3
-# Copyright 2019-2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2019-2024 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
@@ -16,7 +16,6 @@
# License along with this library. If not, see <http://www.gnu.org/licenses/>.
import sys
-import os
import tempfile
import vyos.defaults
import vyos.remote
diff --git a/src/helpers/vyos_config_sync.py b/src/helpers/vyos_config_sync.py
index 77f7cd810..0604b2837 100755
--- a/src/helpers/vyos_config_sync.py
+++ b/src/helpers/vyos_config_sync.py
@@ -21,9 +21,11 @@ import json
import requests
import urllib3
import logging
-from typing import Optional, List, Union, Dict, Any
+from typing import Optional, List, Tuple, Dict, Any
from vyos.config import Config
+from vyos.configtree import ConfigTree
+from vyos.configtree import mask_inclusive
from vyos.template import bracketize_ipv6
@@ -61,39 +63,45 @@ def post_request(url: str,
-def retrieve_config(section: Optional[List[str]] = None) -> Optional[Dict[str, Any]]:
+def retrieve_config(sections: List[list[str]]) -> Tuple[Dict[str, Any], Dict[str, Any]]:
"""Retrieves the configuration from the local server.
Args:
- section: List[str]: The section of the configuration to retrieve.
- Default is None.
+ sections: List[list[str]]: The list of sections of the configuration
+ to retrieve, given as list of paths.
Returns:
- Optional[Dict[str, Any]]: The retrieved configuration as a
- dictionary, or None if an error occurred.
+ Tuple[Dict[str, Any],Dict[str,Any]]: The tuple (mask, config) where:
+ - mask: The tree of paths of sections, as a dictionary.
+ - config: The subtree of masked config data, as a dictionary.
"""
- if section is None:
- section = []
- conf = Config()
- config = conf.get_config_dict(section, get_first_key=True)
- if config:
- return config
- return None
+ mask = ConfigTree('')
+ for section in sections:
+ mask.set(section)
+ mask_dict = json.loads(mask.to_json())
+
+ config = Config()
+ config_tree = config.get_config_tree()
+ masked = mask_inclusive(config_tree, mask)
+ config_dict = json.loads(masked.to_json())
+ return mask_dict, config_dict
def set_remote_config(
address: str,
key: str,
- commands: List[Dict[str, Any]]) -> Optional[Dict[str, Any]]:
+ op: str,
+ mask: Dict[str, Any],
+ config: Dict[str, Any]) -> Optional[Dict[str, Any]]:
"""Loads the VyOS configuration in JSON format to a remote host.
Args:
address (str): The address of the remote host.
key (str): The key to use for loading the configuration.
- commands (list): List of set/load commands for request, given as:
- [{'op': str, 'path': list[str], 'section': dict},
- ...]
+ op (str): The operation to perform (set or load).
+ mask (dict): The dict of paths in sections.
+ config (dict): The dict of masked config data.
Returns:
Optional[Dict[str, Any]]: The response from the remote host as a
@@ -107,7 +115,9 @@ def set_remote_config(
url = f'https://{address}/configure-section'
data = json.dumps({
- 'commands': commands,
+ 'op': op,
+ 'mask': mask,
+ 'config': config,
'key': key
})
@@ -140,23 +150,15 @@ def config_sync(secondary_address: str,
)
# Sync sections ("nat", "firewall", etc)
- commands = []
- for section in sections:
- config_json = retrieve_config(section=section)
- # Check if config path deesn't exist, for example "set nat"
- # we set empty value for config_json data
- # As we cannot send to the remote host section "nat None" config
- if not config_json:
- config_json = {}
- logger.debug(
- f"Retrieved config for section '{section}': {config_json}")
-
- d = {'op': mode, 'path': section, 'section': config_json}
- commands.append(d)
+ mask_dict, config_dict = retrieve_config(sections)
+ logger.debug(
+ f"Retrieved config for sections '{sections}': {config_dict}")
set_config = set_remote_config(address=secondary_address,
key=secondary_key,
- commands=commands)
+ op=mode,
+ mask=mask_dict,
+ config=config_dict)
logger.debug(f"Set config for sections '{sections}': {set_config}")
diff --git a/src/init/vyos-router b/src/init/vyos-router
index adf892371..06fea140d 100755
--- a/src/init/vyos-router
+++ b/src/init/vyos-router
@@ -430,7 +430,7 @@ start ()
nfct helper add rpc inet6 tcp
nfct helper add rpc inet6 udp
nfct helper add tns inet6 tcp
- nft -f /usr/share/vyos/vyos-firewall-init.conf || log_failure_msg "could not initiate firewall rules"
+ nft --file /usr/share/vyos/vyos-firewall-init.conf || log_failure_msg "could not initiate firewall rules"
# As VyOS does not execute commands that are not present in the CLI we call
# the script by hand to have a single source for the login banner and MOTD
diff --git a/src/migration-scripts/conntrack/2-to-3 b/src/migration-scripts/conntrack/2-to-3
index 6fb457b7f..6bb42be1e 100755
--- a/src/migration-scripts/conntrack/2-to-3
+++ b/src/migration-scripts/conntrack/2-to-3
@@ -6,7 +6,6 @@
import sys
from vyos.configtree import ConfigTree
-from vyos.version import get_version
if len(sys.argv) < 2:
print('Must specify file name!')
diff --git a/src/migration-scripts/container/1-to-2 b/src/migration-scripts/container/1-to-2
new file mode 100755
index 000000000..408faf978
--- /dev/null
+++ b/src/migration-scripts/container/1-to-2
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2024 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/>.
+
+# T6208: container: rename "cap-add" CLI node to "capability"
+
+from sys import argv
+from sys import exit
+from vyos.configtree import ConfigTree
+
+if len(argv) < 2:
+ print("Must specify file name!")
+ exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+base = ['container', 'name']
+config = ConfigTree(config_file)
+
+# Check if containers exist and we need to perform image manipulation
+if not config.exists(base):
+ # Nothing to do
+ exit(0)
+
+for container in config.list_nodes(base):
+ cap_path = base + [container, 'cap-add']
+ if config.exists(cap_path):
+ config.rename(cap_path, 'capability')
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print(f'Failed to save the modified config: {e}')
+ exit(1)
diff --git a/src/migration-scripts/dhcp-server/9-to-10 b/src/migration-scripts/dhcp-server/9-to-10
index 810e403a6..a459b65b5 100755
--- a/src/migration-scripts/dhcp-server/9-to-10
+++ b/src/migration-scripts/dhcp-server/9-to-10
@@ -19,7 +19,6 @@
# - Add subnet IDs to existing subnets
import sys
-import re
from vyos.configtree import ConfigTree
if len(sys.argv) < 2:
@@ -57,7 +56,7 @@ for network in config.list_nodes(base):
if config.exists(base + [network, 'subnet']):
for subnet in config.list_nodes(base + [network, 'subnet']):
base_subnet = base + [network, 'subnet', subnet]
-
+
for option in option_nodes:
if config.exists(base_subnet + [option]):
config.set(base_subnet + ['option'])
diff --git a/src/migration-scripts/dhcpv6-server/3-to-4 b/src/migration-scripts/dhcpv6-server/3-to-4
index 4747ebd60..7efc492a5 100755
--- a/src/migration-scripts/dhcpv6-server/3-to-4
+++ b/src/migration-scripts/dhcpv6-server/3-to-4
@@ -20,7 +20,6 @@
# - Migrate address-range to range tagNode
import sys
-import re
from vyos.configtree import ConfigTree
if len(sys.argv) < 2:
diff --git a/src/migration-scripts/firewall/10-to-11 b/src/migration-scripts/firewall/10-to-11
index abb804a28..854d5a558 100755
--- a/src/migration-scripts/firewall/10-to-11
+++ b/src/migration-scripts/firewall/10-to-11
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -16,12 +16,12 @@
# T5160: Firewall re-writing
-# cli changes from:
+# cli changes from:
# set firewall name <name> ...
# set firewall ipv6-name <name> ...
# To
-# set firewall ipv4 name <name>
-# set firewall ipv6 name <name>
+# set firewall ipv4 name <name>
+# set firewall ipv6 name <name>
## Also from 'firewall interface' removed.
## in and out:
@@ -37,13 +37,10 @@
# set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> action jump
# set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> jump-target <name>
-import re
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.ifconfig import Section
if len(argv) < 2:
print("Must specify file name!")
@@ -207,4 +204,4 @@ try:
f.write(config.to_string())
except OSError as e:
print("Failed to save the modified config: {}".format(e))
- exit(1) \ No newline at end of file
+ exit(1)
diff --git a/src/migration-scripts/firewall/11-to-12 b/src/migration-scripts/firewall/11-to-12
index ba8374d66..f9122e74c 100755
--- a/src/migration-scripts/firewall/11-to-12
+++ b/src/migration-scripts/firewall/11-to-12
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -22,13 +22,10 @@
# set firewall ... rule <rule> [inbound-interface | outboubd-interface] name <iface>
# set firewall ... rule <rule> [inbound-interface | outboubd-interface] group <iface_group>
-import re
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.ifconfig import Section
if len(argv) < 2:
print("Must specify file name!")
@@ -71,4 +68,4 @@ try:
f.write(config.to_string())
except OSError as e:
print("Failed to save the modified config: {}".format(e))
- exit(1) \ No newline at end of file
+ exit(1)
diff --git a/src/migration-scripts/firewall/12-to-13 b/src/migration-scripts/firewall/12-to-13
index 8396dd9d1..d72ba834d 100755
--- a/src/migration-scripts/firewall/12-to-13
+++ b/src/migration-scripts/firewall/12-to-13
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -25,13 +25,10 @@
# set firewall ... rule <rule> state <state>
# Remove command if log=disable or <state>=disable
-import re
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.ifconfig import Section
if len(argv) < 2:
print("Must specify file name!")
@@ -89,4 +86,4 @@ try:
f.write(config.to_string())
except OSError as e:
print("Failed to save the modified config: {}".format(e))
- exit(1) \ No newline at end of file
+ exit(1)
diff --git a/src/migration-scripts/firewall/14-to-15 b/src/migration-scripts/firewall/14-to-15
new file mode 100755
index 000000000..735839365
--- /dev/null
+++ b/src/migration-scripts/firewall/14-to-15
@@ -0,0 +1,46 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2022-2024 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/>.
+
+# T5535: Migrate <set system ip disable-directed-broadcast> to <set firewall global-options directed-broadcas [enable|disable]
+
+from sys import argv
+from sys import exit
+
+from vyos.configtree import ConfigTree
+
+if len(argv) < 2:
+ print("Must specify file name!")
+ exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+config = ConfigTree(config_file)
+
+base = ['firewall']
+
+if config.exists(['system', 'ip', 'disable-directed-broadcast']):
+ config.set(['firewall', 'global-options', 'directed-broadcast'], value='disable')
+ config.delete(['system', 'ip', 'disable-directed-broadcast'])
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1) \ No newline at end of file
diff --git a/src/migration-scripts/firewall/6-to-7 b/src/migration-scripts/firewall/6-to-7
index 72f07880b..938044c6d 100755
--- a/src/migration-scripts/firewall/6-to-7
+++ b/src/migration-scripts/firewall/6-to-7
@@ -107,6 +107,12 @@ icmpv6_translations = {
'unknown-option': [4, 2]
}
+v4_found = False
+v6_found = False
+v4_groups = ["address-group", "network-group", "port-group"]
+v6_groups = ["ipv6-address-group", "ipv6-network-group", "port-group"]
+translated_dict = {}
+
if config.exists(base + ['group']):
for group_type in config.list_nodes(base + ['group']):
for group_name in config.list_nodes(base + ['group', group_type]):
@@ -114,6 +120,19 @@ if config.exists(base + ['group']):
if config.exists(name_description):
tmp = config.return_value(name_description)
config.set(name_description, value=tmp[:max_len_description])
+ if '+' in group_name:
+ replacement_string = "_"
+ if group_type in v4_groups and not v4_found:
+ v4_found = True
+ if group_type in v6_groups and not v6_found:
+ v6_found = True
+ new_group_name = group_name.replace('+', replacement_string)
+ while config.exists(base + ['group', group_type, new_group_name]):
+ replacement_string = replacement_string + "_"
+ new_group_name = group_name.replace('+', replacement_string)
+ translated_dict[group_name] = new_group_name
+ config.copy(base + ['group', group_type, group_name], base + ['group', group_type, new_group_name])
+ config.delete(base + ['group', group_type, group_name])
if config.exists(base + ['name']):
for name in config.list_nodes(base + ['name']):
@@ -173,11 +192,31 @@ if config.exists(base + ['name']):
config.set(rule_icmp + ['type'], value=translate[0])
config.set(rule_icmp + ['code'], value=translate[1])
- for src_dst in ['destination', 'source']:
- pg_base = base + ['name', name, 'rule', rule, src_dst, 'group', 'port-group']
- proto_base = base + ['name', name, 'rule', rule, 'protocol']
- if config.exists(pg_base) and not config.exists(proto_base):
- config.set(proto_base, value='tcp_udp')
+ for direction in ['destination', 'source']:
+ if config.exists(base + ['name', name, 'rule', rule, direction]):
+ if config.exists(base + ['name', name, 'rule', rule, direction, 'group']) and v4_found:
+ for group_type in config.list_nodes(base + ['name', name, 'rule', rule, direction, 'group']):
+ group_name = config.return_value(base + ['name', name, 'rule', rule, direction, 'group', group_type])
+ if '+' in group_name:
+ if group_name[0] == "!":
+ new_group_name = "!" + translated_dict[group_name[1:]]
+ else:
+ new_group_name = translated_dict[group_name]
+ config.set(base + ['name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name)
+
+ pg_base = base + ['name', name, 'rule', rule, direction, 'group', 'port-group']
+ proto_base = base + ['name', name, 'rule', rule, 'protocol']
+ if config.exists(pg_base) and not config.exists(proto_base):
+ config.set(proto_base, value='tcp_udp')
+
+ if '+' in name:
+ replacement_string = "_"
+ new_name = name.replace('+', replacement_string)
+ while config.exists(base + ['name', new_name]):
+ replacement_string = replacement_string + "_"
+ new_name = name.replace('+', replacement_string)
+ config.copy(base + ['name', name], base + ['name', new_name])
+ config.delete(base + ['name', name])
if config.exists(base + ['ipv6-name']):
for name in config.list_nodes(base + ['ipv6-name']):
@@ -250,12 +289,31 @@ if config.exists(base + ['ipv6-name']):
else:
config.rename(rule_icmp + ['type'], 'type-name')
- for src_dst in ['destination', 'source']:
- pg_base = base + ['ipv6-name', name, 'rule', rule, src_dst, 'group', 'port-group']
- proto_base = base + ['ipv6-name', name, 'rule', rule, 'protocol']
- if config.exists(pg_base) and not config.exists(proto_base):
- config.set(proto_base, value='tcp_udp')
-
+ for direction in ['destination', 'source']:
+ if config.exists(base + ['ipv6-name', name, 'rule', rule, direction]):
+ if config.exists(base + ['ipv6-name', name, 'rule', rule, direction, 'group']) and v6_found:
+ for group_type in config.list_nodes(base + ['ipv6-name', name, 'rule', rule, direction, 'group']):
+ group_name = config.return_value(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type])
+ if '+' in group_name:
+ if group_name[0] == "!":
+ new_group_name = "!" + translated_dict[group_name[1:]]
+ else:
+ new_group_name = translated_dict[group_name]
+ config.set(base + ['ipv6-name', name, 'rule', rule, direction, 'group', group_type], value=new_group_name)
+
+ pg_base = base + ['ipv6-name', name, 'rule', rule, direction, 'group', 'port-group']
+ proto_base = base + ['ipv6-name', name, 'rule', rule, 'protocol']
+ if config.exists(pg_base) and not config.exists(proto_base):
+ config.set(proto_base, value='tcp_udp')
+
+ if '+' in name:
+ replacement_string = "_"
+ new_name = name.replace('+', replacement_string)
+ while config.exists(base + ['ipv6-name', new_name]):
+ replacement_string = replacement_string + "_"
+ new_name = name.replace('+', replacement_string)
+ config.copy(base + ['ipv6-name', name], base + ['ipv6-name', new_name])
+ config.delete(base + ['ipv6-name', name])
try:
with open(file_name, 'w') as f:
f.write(config.to_string())
diff --git a/src/migration-scripts/firewall/7-to-8 b/src/migration-scripts/firewall/7-to-8
index d06c3150a..bbaba113a 100755
--- a/src/migration-scripts/firewall/7-to-8
+++ b/src/migration-scripts/firewall/7-to-8
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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,13 +17,10 @@
# T2199: Migrate interface firewall nodes to firewall interfaces <ifname> <direction> name/ipv6-name <name>
# T2199: Migrate zone-policy to firewall node
-import re
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.ifconfig import Section
if len(argv) < 2:
print("Must specify file name!")
diff --git a/src/migration-scripts/firewall/8-to-9 b/src/migration-scripts/firewall/8-to-9
index d7647354a..6e019beb2 100755
--- a/src/migration-scripts/firewall/8-to-9
+++ b/src/migration-scripts/firewall/8-to-9
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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,18 +15,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# T4780: Add firewall interface group
-# cli changes from:
+# cli changes from:
# set firewall [name | ipv6-name] <name> rule <number> [inbound-interface | outbound-interface] <interface_name>
# To
# set firewall [name | ipv6-name] <name> rule <number> [inbound-interface | outbound-interface] [interface-name | interface-group] <interface_name | interface_group>
-import re
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.ifconfig import Section
if len(argv) < 2:
print("Must specify file name!")
@@ -88,4 +85,4 @@ try:
f.write(config.to_string())
except OSError as e:
print("Failed to save the modified config: {}".format(e))
- exit(1) \ No newline at end of file
+ exit(1)
diff --git a/src/migration-scripts/firewall/9-to-10 b/src/migration-scripts/firewall/9-to-10
index a70460718..ce509a731 100755
--- a/src/migration-scripts/firewall/9-to-10
+++ b/src/migration-scripts/firewall/9-to-10
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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,18 +15,15 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# T5050: Log options
-# cli changes from:
+# cli changes from:
# set firewall [name | ipv6-name] <name> rule <number> log-level <log_level>
# To
# set firewall [name | ipv6-name] <name> rule <number> log-options level <log_level>
-import re
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.ifconfig import Section
if len(argv) < 2:
print("Must specify file name!")
@@ -50,7 +47,7 @@ if config.exists(base + ['name']):
continue
for rule in config.list_nodes(base + ['name', name, 'rule']):
- log_options_base = base + ['name', name, 'rule', rule, 'log-options']
+ log_options_base = base + ['name', name, 'rule', rule, 'log-options']
rule_log_level = base + ['name', name, 'rule', rule, 'log-level']
if config.exists(rule_log_level):
@@ -64,7 +61,7 @@ if config.exists(base + ['ipv6-name']):
continue
for rule in config.list_nodes(base + ['ipv6-name', name, 'rule']):
- log_options_base = base + ['ipv6-name', name, 'rule', rule, 'log-options']
+ log_options_base = base + ['ipv6-name', name, 'rule', rule, 'log-options']
rule_log_level = base + ['ipv6-name', name, 'rule', rule, 'log-level']
if config.exists(rule_log_level):
@@ -77,4 +74,4 @@ try:
f.write(config.to_string())
except OSError as e:
print("Failed to save the modified config: {}".format(e))
- exit(1) \ No newline at end of file
+ exit(1)
diff --git a/src/migration-scripts/interfaces/26-to-27 b/src/migration-scripts/interfaces/26-to-27
index 4967a29fa..429ab650f 100755
--- a/src/migration-scripts/interfaces/26-to-27
+++ b/src/migration-scripts/interfaces/26-to-27
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -18,8 +18,6 @@
# present for DHCP
from sys import argv
-
-from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
if len(argv) < 2:
diff --git a/src/migration-scripts/interfaces/27-to-28 b/src/migration-scripts/interfaces/27-to-28
index a0d043d11..9f5e93b5f 100755
--- a/src/migration-scripts/interfaces/27-to-28
+++ b/src/migration-scripts/interfaces/27-to-28
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -19,7 +19,6 @@
from sys import argv
-from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
if len(argv) < 2:
diff --git a/src/migration-scripts/interfaces/28-to-29 b/src/migration-scripts/interfaces/28-to-29
index ad5bfa653..0437977dc 100755
--- a/src/migration-scripts/interfaces/28-to-29
+++ b/src/migration-scripts/interfaces/28-to-29
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -18,8 +18,6 @@
# valueless node.
from sys import argv
-
-from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
if len(argv) < 2:
diff --git a/src/migration-scripts/interfaces/29-to-30 b/src/migration-scripts/interfaces/29-to-30
index acb6ee1fb..80aad1d44 100755
--- a/src/migration-scripts/interfaces/29-to-30
+++ b/src/migration-scripts/interfaces/29-to-30
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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,8 +17,6 @@
# T5286: remove XDP support in favour of VPP
from sys import argv
-
-from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
if len(argv) < 2:
diff --git a/src/migration-scripts/ipoe-server/0-to-1 b/src/migration-scripts/ipoe-server/0-to-1
deleted file mode 100755
index ac9d13abc..000000000
--- a/src/migration-scripts/ipoe-server/0-to-1
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/env python3
-#
-# 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
-# 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/>.
-
-# - T4703: merge vlan-id and vlan-range to vlan CLI node
-
-# L2|L3 -> l2|l3
-# mac-address -> mac
-# network-mode -> mode
-
-import os
-import sys
-
-from sys import argv, exit
-from vyos.configtree import ConfigTree
-
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-base = ['service', 'ipoe-server']
-if not config.exists(base):
- # Nothing to do
- exit(0)
-
-if config.exists(base + ['authentication', 'interface']):
- for interface in config.list_nodes(base + ['authentication', 'interface']):
- config.rename(base + ['authentication', 'interface', interface, 'mac-address'], 'mac')
-
- mac_base = base + ['authentication', 'interface', interface, 'mac']
- for mac in config.list_nodes(mac_base):
- vlan_config = mac_base + [mac, 'vlan-id']
- if config.exists(vlan_config):
- config.rename(vlan_config, 'vlan')
-
-for interface in config.list_nodes(base + ['interface']):
- base_path = base + ['interface', interface]
- for vlan in ['vlan-id', 'vlan-range']:
- if config.exists(base_path + [vlan]):
- print(interface, vlan)
- for tmp in config.return_values(base_path + [vlan]):
- config.set(base_path + ['vlan'], value=tmp, replace=False)
- config.delete(base_path + [vlan])
-
- if config.exists(base_path + ['network-mode']):
- tmp = config.return_value(base_path + ['network-mode'])
- config.delete(base_path + ['network-mode'])
- # Change L2|L3 to lower case l2|l3
- config.set(base_path + ['mode'], value=tmp.lower())
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
diff --git a/src/migration-scripts/ipoe-server/1-to-2 b/src/migration-scripts/ipoe-server/1-to-2
index 11d7911e9..6a7111541 100755
--- a/src/migration-scripts/ipoe-server/1-to-2
+++ b/src/migration-scripts/ipoe-server/1-to-2
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -14,6 +14,11 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+# - T4703: merge vlan-id and vlan-range to vlan CLI node
+# L2|L3 -> l2|l3
+# mac-address -> mac
+# network-mode -> mode
+
# - changed cli of all named pools
# - moved gateway-address from pool to global configuration with / netmask
# gateway can exist without pool if radius is used
@@ -23,8 +28,6 @@
# 1. The first pool that contains next-poll.
# 2. Else, the first pool in the list
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
@@ -41,43 +44,67 @@ with open(file_name, 'r') as f:
config = ConfigTree(config_file)
base = ['service', 'ipoe-server']
-pool_base = base + ['client-ip-pool']
+
if not config.exists(base):
exit(0)
-if not config.exists(pool_base):
- exit(0)
-default_pool = ''
-gateway = ''
-
-#named pool migration
-namedpools_base = pool_base + ['name']
-
-for pool_name in config.list_nodes(namedpools_base):
- pool_path = namedpools_base + [pool_name]
- if config.exists(pool_path + ['subnet']):
- subnet = config.return_value(pool_path + ['subnet'])
- config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
- # Get netmask from subnet
- mask = subnet.split("/")[1]
- if config.exists(pool_path + ['next-pool']):
- next_pool = config.return_value(pool_path + ['next-pool'])
- config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
- if not default_pool:
- default_pool = pool_name
- if config.exists(pool_path + ['gateway-address']) and mask:
- gateway = f'{config.return_value(pool_path + ["gateway-address"])}/{mask}'
- config.set(base + ['gateway-address'], value=gateway, replace=False)
-
-if not default_pool and config.list_nodes(namedpools_base):
- default_pool = config.list_nodes(namedpools_base)[0]
-
-config.delete(namedpools_base)
-
-if default_pool:
- config.set(base + ['default-pool'], value=default_pool)
-# format as tag node
-config.set_tag(pool_base)
+if config.exists(base + ['authentication', 'interface']):
+ for interface in config.list_nodes(base + ['authentication', 'interface']):
+ config.rename(base + ['authentication', 'interface', interface, 'mac-address'], 'mac')
+
+ mac_base = base + ['authentication', 'interface', interface, 'mac']
+ for mac in config.list_nodes(mac_base):
+ vlan_config = mac_base + [mac, 'vlan-id']
+ if config.exists(vlan_config):
+ config.rename(vlan_config, 'vlan')
+
+for interface in config.list_nodes(base + ['interface']):
+ base_path = base + ['interface', interface]
+ for vlan in ['vlan-id', 'vlan-range']:
+ if config.exists(base_path + [vlan]):
+ for tmp in config.return_values(base_path + [vlan]):
+ config.set(base_path + ['vlan'], value=tmp, replace=False)
+ config.delete(base_path + [vlan])
+
+ if config.exists(base_path + ['network-mode']):
+ tmp = config.return_value(base_path + ['network-mode'])
+ config.delete(base_path + ['network-mode'])
+ # Change L2|L3 to lower case l2|l3
+ config.set(base_path + ['mode'], value=tmp.lower())
+
+pool_base = base + ['client-ip-pool']
+if config.exists(pool_base):
+ default_pool = ''
+ gateway = ''
+
+ #named pool migration
+ namedpools_base = pool_base + ['name']
+
+ for pool_name in config.list_nodes(namedpools_base):
+ pool_path = namedpools_base + [pool_name]
+ if config.exists(pool_path + ['subnet']):
+ subnet = config.return_value(pool_path + ['subnet'])
+ config.set(pool_base + [pool_name, 'range'], value=subnet, replace=False)
+ # Get netmask from subnet
+ mask = subnet.split("/")[1]
+ if config.exists(pool_path + ['next-pool']):
+ next_pool = config.return_value(pool_path + ['next-pool'])
+ config.set(pool_base + [pool_name, 'next-pool'], value=next_pool)
+ if not default_pool:
+ default_pool = pool_name
+ if config.exists(pool_path + ['gateway-address']) and mask:
+ gateway = f'{config.return_value(pool_path + ["gateway-address"])}/{mask}'
+ config.set(base + ['gateway-address'], value=gateway, replace=False)
+
+ if not default_pool and config.list_nodes(namedpools_base):
+ default_pool = config.list_nodes(namedpools_base)[0]
+
+ config.delete(namedpools_base)
+
+ if default_pool:
+ config.set(base + ['default-pool'], value=default_pool)
+ # format as tag node
+ config.set_tag(pool_base)
try:
with open(file_name, 'w') as f:
diff --git a/src/migration-scripts/ipoe-server/2-to-3 b/src/migration-scripts/ipoe-server/2-to-3
index d4ae0a7ba..0909315a8 100755
--- a/src/migration-scripts/ipoe-server/2-to-3
+++ b/src/migration-scripts/ipoe-server/2-to-3
@@ -16,13 +16,10 @@
# Migrating to named ipv6 pools
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ipsec/11-to-12 b/src/migration-scripts/ipsec/11-to-12
index e34882c23..4833d0876 100755
--- a/src/migration-scripts/ipsec/11-to-12
+++ b/src/migration-scripts/ipsec/11-to-12
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -16,8 +16,6 @@
# Remove legacy ipsec.conf and ipsec.secrets - Not supported with swanctl
-import re
-
from sys import argv
from sys import exit
diff --git a/src/migration-scripts/ipsec/12-to-13 b/src/migration-scripts/ipsec/12-to-13
index c11f708bd..d90c70314 100755
--- a/src/migration-scripts/ipsec/12-to-13
+++ b/src/migration-scripts/ipsec/12-to-13
@@ -17,8 +17,6 @@
# Changed value of dead-peer-detection.action from hold to trap
# Changed value of close-action from hold to trap and from restart to start
-import re
-
from sys import argv
from sys import exit
diff --git a/src/migration-scripts/ipsec/7-to-8 b/src/migration-scripts/ipsec/7-to-8
index e002db0b1..9acc737d5 100755
--- a/src/migration-scripts/ipsec/7-to-8
+++ b/src/migration-scripts/ipsec/7-to-8
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -26,7 +26,6 @@ from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.pki import load_public_key
from vyos.pki import load_private_key
from vyos.pki import encode_public_key
from vyos.pki import encode_private_key
diff --git a/src/migration-scripts/ipsec/9-to-10 b/src/migration-scripts/ipsec/9-to-10
index a4a71d38e..bc10e1997 100755
--- a/src/migration-scripts/ipsec/9-to-10
+++ b/src/migration-scripts/ipsec/9-to-10
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -20,9 +20,6 @@ from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.template import is_ipv4
-from vyos.template import is_ipv6
-
if len(argv) < 2:
print("Must specify file name!")
diff --git a/src/migration-scripts/l2tp/2-to-3 b/src/migration-scripts/l2tp/2-to-3
index b46b0f22e..8527c2d4a 100755
--- a/src/migration-scripts/l2tp/2-to-3
+++ b/src/migration-scripts/l2tp/2-to-3
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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,9 +17,6 @@
# - remove primary/secondary identifier from nameserver
# - TODO: remove radius server req-limit
-import os
-import sys
-
from sys import argv, exit
from vyos.configtree import ConfigTree
@@ -38,7 +35,6 @@ if not config.exists(base):
# Nothing to do
exit(0)
else:
-
# Migrate IPv4 DNS servers
dns_base = base + ['dns-servers']
if config.exists(dns_base):
diff --git a/src/migration-scripts/l2tp/3-to-4 b/src/migration-scripts/l2tp/3-to-4
index 8c2b909b7..14b86ff04 100755
--- a/src/migration-scripts/l2tp/3-to-4
+++ b/src/migration-scripts/l2tp/3-to-4
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -23,7 +23,6 @@ from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
-from vyos.pki import load_crl
from vyos.pki import load_private_key
from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
diff --git a/src/migration-scripts/l2tp/4-to-5 b/src/migration-scripts/l2tp/4-to-5
index 3176f895a..b7f4d2677 100755
--- a/src/migration-scripts/l2tp/4-to-5
+++ b/src/migration-scripts/l2tp/4-to-5
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -19,8 +19,6 @@
# 'subnet' migrate to namedpool 'default-subnet-pool'
# 'default-subnet-pool' is the next pool for 'default-range-pool'
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/l2tp/5-to-6 b/src/migration-scripts/l2tp/5-to-6
index ca0b13dcc..ac40b89c8 100755
--- a/src/migration-scripts/l2tp/5-to-6
+++ b/src/migration-scripts/l2tp/5-to-6
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2024 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
@@ -14,14 +14,10 @@
# 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
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/l2tp/6-to-7 b/src/migration-scripts/l2tp/6-to-7
index f49c4ab08..1c536585c 100755
--- a/src/migration-scripts/l2tp/6-to-7
+++ b/src/migration-scripts/l2tp/6-to-7
@@ -16,13 +16,10 @@
# Migrating to named ipv6 pools
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/l2tp/7-to-8 b/src/migration-scripts/l2tp/7-to-8
index 4956e1155..e429ed057 100755
--- a/src/migration-scripts/l2tp/7-to-8
+++ b/src/migration-scripts/l2tp/7-to-8
@@ -17,13 +17,10 @@
# Migrate from 'ccp-disable' to 'ppp-options.disable-ccp'
# Migration ipv6 options
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/l2tp/8-to-9 b/src/migration-scripts/l2tp/8-to-9
index e85a3892b..672180e25 100755
--- a/src/migration-scripts/l2tp/8-to-9
+++ b/src/migration-scripts/l2tp/8-to-9
@@ -16,13 +16,10 @@
# Deleted 'dhcp-interface' from l2tp
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
@@ -37,7 +34,7 @@ base = ['vpn', 'l2tp', 'remote-access']
if not config.exists(base):
exit(0)
-#deleting unused dhcp-interface
+# deleting unused dhcp-interface
if config.exists(base + ['dhcp-interface']):
config.delete(base + ['dhcp-interface'])
diff --git a/src/migration-scripts/nat/5-to-6 b/src/migration-scripts/nat/5-to-6
index c83b93d84..cfe98ddcf 100755
--- a/src/migration-scripts/nat/5-to-6
+++ b/src/migration-scripts/nat/5-to-6
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2024 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
@@ -18,46 +18,84 @@
# to
# 'set nat [source|destination] rule X [inbound-interface|outbound interface] interface-name <iface>'
+# T6100: Migration from 1.3.X to 1.4
+# Change IP/netmask to Network/netmask in
+# 'set nat [source|destination] rule X [source| destination| translation] address <IP/Netmask| !IP/Netmask>'
+
+import ipaddress
from sys import argv,exit
from vyos.configtree import ConfigTree
-if len(argv) < 2:
- print("Must specify file name!")
- exit(1)
-
-file_name = argv[1]
-
-with open(file_name, 'r') as f:
- config_file = f.read()
-
-config = ConfigTree(config_file)
-
-if not config.exists(['nat']):
- # Nothing to do
- exit(0)
-
-for direction in ['source', 'destination']:
- # If a node doesn't exist, we obviously have nothing to do.
- if not config.exists(['nat', direction]):
- continue
-
- # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
- # but there are no rules under it.
- if not config.list_nodes(['nat', direction]):
- continue
-
- for rule in config.list_nodes(['nat', direction, 'rule']):
- base = ['nat', direction, 'rule', rule]
- for iface in ['inbound-interface','outbound-interface']:
- if config.exists(base + [iface]):
- tmp = config.return_value(base + [iface])
- if tmp:
- config.delete(base + [iface])
- config.set(base + [iface, 'interface-name'], value=tmp)
-
-try:
- with open(file_name, 'w') as f:
- f.write(config.to_string())
-except OSError as e:
- print("Failed to save the modified config: {}".format(e))
- exit(1)
+
+def _func_T5643(conf, base_path):
+ for iface in ['inbound-interface', 'outbound-interface']:
+ if conf.exists(base_path + [iface]):
+ tmp = conf.return_value(base_path + [iface])
+ if tmp:
+ conf.delete(base_path + [iface])
+ conf.set(base_path + [iface, 'interface-name'], value=tmp)
+ return
+
+
+def _func_T6100(conf, base_path):
+ for addr_type in ['source', 'destination', 'translation']:
+ base_addr_type = base_path + [addr_type]
+ if not conf.exists(base_addr_type) or not conf.exists(
+ base_addr_type + ['address']):
+ continue
+
+ address = conf.return_value(base_addr_type + ['address'])
+
+ if not address or '/' not in address:
+ continue
+
+ negative = ''
+ network = address
+ if '!' in address:
+ negative = '!'
+ network = str(address.split(negative)[1])
+
+ network_ip = ipaddress.ip_network(network, strict=False)
+ if str(network_ip) != network:
+ network = f'{negative}{str(network_ip)}'
+ conf.set(base_addr_type + ['address'], value=network)
+ return
+
+
+if __name__ == '__main__':
+ if len(argv) < 2:
+ print("Must specify file name!")
+ exit(1)
+
+ file_name = argv[1]
+
+ with open(file_name, 'r') as f:
+ config_file = f.read()
+
+ config = ConfigTree(config_file)
+
+ if not config.exists(['nat']):
+ # Nothing to do
+ exit(0)
+
+ for direction in ['source', 'destination']:
+ # If a node doesn't exist, we obviously have nothing to do.
+ if not config.exists(['nat', direction]):
+ continue
+
+ # However, we also need to handle the case when a 'source' or 'destination' sub-node does exist,
+ # but there are no rules under it.
+ if not config.list_nodes(['nat', direction]):
+ continue
+
+ for rule in config.list_nodes(['nat', direction, 'rule']):
+ base = ['nat', direction, 'rule', rule]
+ _func_T5643(config,base)
+ _func_T6100(config,base)
+
+ try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+ except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1)
diff --git a/src/migration-scripts/openconnect/0-to-1 b/src/migration-scripts/openconnect/0-to-1
index 8be15fad1..c64b16cb2 100755
--- a/src/migration-scripts/openconnect/0-to-1
+++ b/src/migration-scripts/openconnect/0-to-1
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -22,7 +22,6 @@ from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
-from vyos.pki import load_crl
from vyos.pki import load_private_key
from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
diff --git a/src/migration-scripts/ospf/0-to-1 b/src/migration-scripts/ospf/0-to-1
index a6cb9feb8..4085423a2 100755
--- a/src/migration-scripts/ospf/0-to-1
+++ b/src/migration-scripts/ospf/0-to-1
@@ -31,7 +31,8 @@ def ospf_passive_migration(config, ospf_base):
config.set_tag(ospf_base + ['interface'])
config.delete(ospf_base + ['passive-interface'])
- config.set(ospf_base + ['passive-interface'], value='default')
+ if default:
+ config.set(ospf_base + ['passive-interface'], value='default')
if config.exists(ospf_base + ['passive-interface-exclude']):
for interface in config.return_values(ospf_base + ['passive-interface-exclude']):
diff --git a/src/migration-scripts/policy/4-to-5 b/src/migration-scripts/policy/4-to-5
index 5b8fee17e..738850f67 100755
--- a/src/migration-scripts/policy/4-to-5
+++ b/src/migration-scripts/policy/4-to-5
@@ -16,13 +16,10 @@
# T2199: Migrate interface policy nodes to policy route <name> interface <ifname>
-import re
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.ifconfig import Section
if len(argv) < 2:
print("Must specify file name!")
diff --git a/src/migration-scripts/policy/5-to-6 b/src/migration-scripts/policy/5-to-6
index f1545cddb..86287d578 100755
--- a/src/migration-scripts/policy/5-to-6
+++ b/src/migration-scripts/policy/5-to-6
@@ -16,13 +16,10 @@
# T5165: Migrate policy local-route rule <tag> destination|source
-import re
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.ifconfig import Section
if len(argv) < 2:
print("Must specify file name!")
diff --git a/src/migration-scripts/policy/6-to-7 b/src/migration-scripts/policy/6-to-7
index 727b8487a..cdefc6837 100755
--- a/src/migration-scripts/policy/6-to-7
+++ b/src/migration-scripts/policy/6-to-7
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -22,13 +22,10 @@
# set policy [route | route6] ... rule <rule> log
# Remove command if log=disable
-import re
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.ifconfig import Section
if len(argv) < 2:
print("Must specify file name!")
@@ -48,7 +45,7 @@ if not config.exists(base):
for family in ['route', 'route6']:
if config.exists(base + [family]):
-
+
for policy_name in config.list_nodes(base + [family]):
if config.exists(base + [family, policy_name, 'rule']):
for rule in config.list_nodes(base + [family, policy_name, 'rule']):
@@ -76,4 +73,4 @@ try:
f.write(config.to_string())
except OSError as e:
print("Failed to save the modified config: {}".format(e))
- exit(1) \ No newline at end of file
+ exit(1)
diff --git a/src/migration-scripts/pppoe-server/1-to-2 b/src/migration-scripts/pppoe-server/1-to-2
index c73899ca1..b266893c0 100755
--- a/src/migration-scripts/pppoe-server/1-to-2
+++ b/src/migration-scripts/pppoe-server/1-to-2
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -16,8 +16,6 @@
# change mppe node to a leaf node with value prefer
-import os
-
from sys import argv, exit
from vyos.configtree import ConfigTree
@@ -58,4 +56,3 @@ else:
except OSError as e:
print("Failed to save the modified config: {}".format(e))
exit(1)
-
diff --git a/src/migration-scripts/pppoe-server/3-to-4 b/src/migration-scripts/pppoe-server/3-to-4
index c07bbb1df..477ed6f22 100755
--- a/src/migration-scripts/pppoe-server/3-to-4
+++ b/src/migration-scripts/pppoe-server/3-to-4
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -16,8 +16,6 @@
# - remove primary/secondary identifier from nameserver
-import os
-
from sys import argv, exit
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/pppoe-server/6-to-7 b/src/migration-scripts/pppoe-server/6-to-7
index b94ce57f9..d51c1c9d8 100755
--- a/src/migration-scripts/pppoe-server/6-to-7
+++ b/src/migration-scripts/pppoe-server/6-to-7
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -24,8 +24,6 @@
# If there are not named pools, namedless pool will be default.
# 2. If authentication mode = 'radius' then namedless pool will be default
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/pppoe-server/7-to-8 b/src/migration-scripts/pppoe-server/7-to-8
index b0d9bb464..0381f0bf9 100755
--- a/src/migration-scripts/pppoe-server/7-to-8
+++ b/src/migration-scripts/pppoe-server/7-to-8
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -16,13 +16,10 @@
# Migrating to named ipv6 pools
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/pppoe-server/8-to-9 b/src/migration-scripts/pppoe-server/8-to-9
index ad75c28a1..4932a766f 100755
--- a/src/migration-scripts/pppoe-server/8-to-9
+++ b/src/migration-scripts/pppoe-server/8-to-9
@@ -17,13 +17,10 @@
# Change from 'ccp' to 'disable-ccp' in ppp-option section
# Migration ipv6 options
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/pptp/2-to-3 b/src/migration-scripts/pptp/2-to-3
index 091cb68ec..42c4dedf4 100755
--- a/src/migration-scripts/pptp/2-to-3
+++ b/src/migration-scripts/pptp/2-to-3
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -18,8 +18,6 @@
# 'start-stop' migrate to namedpool 'default-range-pool'
# 'default-subnet-pool' is the next pool for 'default-range-pool'
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/pptp/3-to-4 b/src/migration-scripts/pptp/3-to-4
index 0a8dad2f4..ebd343028 100755
--- a/src/migration-scripts/pptp/3-to-4
+++ b/src/migration-scripts/pptp/3-to-4
@@ -16,13 +16,10 @@
# - Move 'mppe' from 'authentication' node to 'ppp-options'
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/pptp/4-to-5 b/src/migration-scripts/pptp/4-to-5
index d4b3f9a14..83632b6d8 100755
--- a/src/migration-scripts/pptp/4-to-5
+++ b/src/migration-scripts/pptp/4-to-5
@@ -17,13 +17,10 @@
# - Move 'require' from 'protocols' in 'authentication' node
# - Migrate to new default values in radius timeout and acct-timeout
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/snmp/2-to-3 b/src/migration-scripts/snmp/2-to-3
index 30911aa27..ab9b5dcba 100755
--- a/src/migration-scripts/snmp/2-to-3
+++ b/src/migration-scripts/snmp/2-to-3
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -20,13 +20,10 @@
# To
# set service snmp oid-enable ip-forward
-import re
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-from vyos.ifconfig import Section
if len(argv) < 2:
print("Must specify file name!")
diff --git a/src/migration-scripts/sstp/0-to-1 b/src/migration-scripts/sstp/0-to-1
index e2fe1ea8f..150127aaf 100755
--- a/src/migration-scripts/sstp/0-to-1
+++ b/src/migration-scripts/sstp/0-to-1
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -23,7 +23,6 @@
# - do not migrate radius server req-limit, use default of unlimited
# - migrate SSL certificate path
-import os
import sys
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/sstp/3-to-4 b/src/migration-scripts/sstp/3-to-4
index 00ca7a52d..5b7757e60 100755
--- a/src/migration-scripts/sstp/3-to-4
+++ b/src/migration-scripts/sstp/3-to-4
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2023 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -22,7 +22,6 @@ from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
from vyos.pki import load_certificate
-from vyos.pki import load_crl
from vyos.pki import load_private_key
from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
diff --git a/src/migration-scripts/sstp/4-to-5 b/src/migration-scripts/sstp/4-to-5
index 95e482713..6907240a0 100755
--- a/src/migration-scripts/sstp/4-to-5
+++ b/src/migration-scripts/sstp/4-to-5
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -18,13 +18,10 @@
# 'subnet' migrate to namedpool 'default-subnet-pool'
# 'default-subnet-pool' is the next pool for 'default-range-pool'
-import os
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/sstp/5-to-6 b/src/migration-scripts/sstp/5-to-6
index bac9975b2..43b99044d 100755
--- a/src/migration-scripts/sstp/5-to-6
+++ b/src/migration-scripts/sstp/5-to-6
@@ -16,14 +16,10 @@
# Migrating to named ipv6 pools
-import os
-import pprint
-
from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-
if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/system/15-to-16 b/src/migration-scripts/system/15-to-16
index aa1c34032..2944cdb1e 100755
--- a/src/migration-scripts/system/15-to-16
+++ b/src/migration-scripts/system/15-to-16
@@ -2,7 +2,6 @@
#
# Make 'system options reboot-on-panic' valueless
-import os
import sys
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/system/16-to-17 b/src/migration-scripts/system/16-to-17
index 37e02611d..afa171a9b 100755
--- a/src/migration-scripts/system/16-to-17
+++ b/src/migration-scripts/system/16-to-17
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -20,7 +20,6 @@
# This is the only privilege level left and also the default, what is the
# sense in keeping this orphaned node?
-import os
import sys
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/system/19-to-20 b/src/migration-scripts/system/19-to-20
index c04e6a5a6..177173c50 100755
--- a/src/migration-scripts/system/19-to-20
+++ b/src/migration-scripts/system/19-to-20
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -16,8 +16,6 @@
# T3048: remove smp-affinity node from ethernet and use tuned instead
-import os
-
from sys import exit, argv
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/system/20-to-21 b/src/migration-scripts/system/20-to-21
index 4bcf4edab..24e042ce2 100755
--- a/src/migration-scripts/system/20-to-21
+++ b/src/migration-scripts/system/20-to-21
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -16,8 +16,6 @@
# T3795: merge "system name-servers-dhcp" into "system name-server"
-import os
-
from sys import argv
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/system/21-to-22 b/src/migration-scripts/system/21-to-22
index 810b634ab..2a1b603c6 100755
--- a/src/migration-scripts/system/21-to-22
+++ b/src/migration-scripts/system/21-to-22
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -14,8 +14,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 os
-
from sys import exit, argv
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/system/22-to-23 b/src/migration-scripts/system/22-to-23
index 8ed198383..f83279b88 100755
--- a/src/migration-scripts/system/22-to-23
+++ b/src/migration-scripts/system/22-to-23
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -14,8 +14,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 os
-
from sys import exit, argv
from vyos.configtree import ConfigTree
diff --git a/src/migration-scripts/system/23-to-24 b/src/migration-scripts/system/23-to-24
index fd68dbf22..1fd61d83b 100755
--- a/src/migration-scripts/system/23-to-24
+++ b/src/migration-scripts/system/23-to-24
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -14,8 +14,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 os
-
from ipaddress import ip_interface
from ipaddress import ip_address
from sys import exit, argv
diff --git a/src/op_mode/bridge.py b/src/op_mode/bridge.py
index 412a4eba8..d04f1541f 100755
--- a/src/op_mode/bridge.py
+++ b/src/op_mode/bridge.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022-2023 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -19,13 +19,11 @@ import json
import sys
import typing
-from sys import exit
from tabulate import tabulate
from vyos.utils.process import cmd
from vyos.utils.process import rc_cmd
from vyos.utils.process import call
-from vyos.utils.dict import dict_search
import vyos.opmode
diff --git a/src/op_mode/conntrack.py b/src/op_mode/conntrack.py
index 6ea213bec..c379c3e60 100755
--- a/src/op_mode/conntrack.py
+++ b/src/op_mode/conntrack.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022-2023 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -20,7 +20,6 @@ import xmltodict
from tabulate import tabulate
from vyos.utils.process import cmd
-from vyos.utils.process import run
import vyos.opmode
@@ -63,7 +62,7 @@ def _get_raw_data(family):
def _get_raw_statistics():
entries = []
- data = cmd('sudo conntrack -S')
+ data = cmd('sudo conntrack --stats')
data = data.replace(' \t', '').split('\n')
for entry in data:
entries.append(entry.split())
@@ -71,8 +70,25 @@ def _get_raw_statistics():
def get_formatted_statistics(entries):
- headers = ["CPU", "Found", "Invalid", "Insert", "Insert fail", "Drop", "Early drop", "Errors", "Search restart"]
- output = tabulate(entries, headers, numalign="left")
+ headers = [
+ "CPU",
+ "Found",
+ "Invalid",
+ "Insert",
+ "Insert fail",
+ "Drop",
+ "Early drop",
+ "Errors",
+ "Search restart",
+ "",
+ "",
+ ]
+ # Process each entry to extract and format the values after '='
+ processed_entries = [
+ [value.split('=')[-1] for value in entry]
+ for entry in entries
+ ]
+ output = tabulate(processed_entries, headers, numalign="left")
return output
diff --git a/src/op_mode/conntrack_sync.py b/src/op_mode/conntrack_sync.py
index a38688e45..6c86ff492 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) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -21,7 +21,6 @@ import xmltodict
import vyos.opmode
-from argparse import ArgumentParser
from vyos.configquery import CliShellApiConfigQuery
from vyos.configquery import ConfigTreeQuery
from vyos.utils.commit import commit_in_progress
diff --git a/src/op_mode/container.py b/src/op_mode/container.py
index d29af8821..05f65df1f 100755
--- a/src/op_mode/container.py
+++ b/src/op_mode/container.py
@@ -17,12 +17,8 @@
import json
import sys
-from sys import exit
-
from vyos.utils.process import cmd
-from vyos.utils.process import call
from vyos.utils.process import rc_cmd
-
import vyos.opmode
def _get_json_data(command: str) -> list:
diff --git a/src/op_mode/dhcp.py b/src/op_mode/dhcp.py
index a2f947400..f6029c748 100755
--- a/src/op_mode/dhcp.py
+++ b/src/op_mode/dhcp.py
@@ -80,14 +80,20 @@ def _get_raw_server_leases(family='inet', pool=None, sorted=None, state=[], orig
:return list
"""
inet_suffix = '6' if family == 'inet6' else '4'
- leases = kea_get_leases(inet_suffix)
+ try:
+ leases = kea_get_leases(inet_suffix)
+ except:
+ raise vyos.opmode.DataUnavailable('Cannot fetch DHCP server lease information')
if pool is None:
pool = _get_dhcp_pools(family=family)
else:
pool = [pool]
- active_config = kea_get_active_config(inet_suffix)
+ try:
+ active_config = kea_get_active_config(inet_suffix)
+ except:
+ raise vyos.opmode.DataUnavailable('Cannot fetch DHCP server configuration')
data = []
for lease in leases:
diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py
index 4dcffc412..25554b781 100755
--- a/src/op_mode/firewall.py
+++ b/src/op_mode/firewall.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -16,9 +16,9 @@
import argparse
import ipaddress
-import json
import re
import tabulate
+import textwrap
from vyos.config import Config
from vyos.utils.process import cmd
@@ -89,6 +89,14 @@ def get_nftables_details(family, hook, priority):
out[rule_id] = rule
return out
+def output_firewall_vertical(rules, headers):
+ for rule in rules:
+ adjusted_rule = rule + [""] * (len(headers) - len(rule)) # account for different header length, like default-action
+ transformed_rule = [[header, textwrap.fill(adjusted_rule[i].replace('\n', ' '), 65)] for i, header in enumerate(headers)] # create key-pair list from headers and rules lists; wrap at 100 char
+
+ print(tabulate.tabulate(transformed_rule, tablefmt="presto"))
+ print()
+
def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=None):
print(f'\n---------------------------------\n{family} Firewall "{hook} {priority}"\n')
@@ -103,7 +111,7 @@ def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=N
if 'disable' in rule_conf:
continue
- row = [rule_id, rule_conf['action'], rule_conf['protocol'] if 'protocol' in rule_conf else 'all']
+ row = [rule_id, textwrap.fill(rule_conf.get('description') or '', 50), rule_conf['action'], rule_conf['protocol'] if 'protocol' in rule_conf else 'all']
if rule_id in details:
rule_details = details[rule_id]
row.append(rule_details.get('packets', 0))
@@ -115,7 +123,7 @@ def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=N
def_action = firewall_conf['default_action'] if 'default_action' in firewall_conf else 'accept'
else:
def_action = firewall_conf['default_action'] if 'default_action' in firewall_conf else 'drop'
- row = ['default', def_action, 'all']
+ row = ['default', '', def_action, 'all']
rule_details = details['default-action']
row.append(rule_details.get('packets', 0))
row.append(rule_details.get('bytes', 0))
@@ -123,8 +131,17 @@ def output_firewall_name(family, hook, priority, firewall_conf, single_rule_id=N
rows.append(row)
if rows:
- header = ['Rule', 'Action', 'Protocol', 'Packets', 'Bytes', 'Conditions']
- print(tabulate.tabulate(rows, header) + '\n')
+ if args.rule:
+ rows.pop()
+
+ if args.detail:
+ header = ['Rule', 'Description', 'Action', 'Protocol', 'Packets', 'Bytes', 'Conditions']
+ output_firewall_vertical(rows, header)
+ else:
+ header = ['Rule', 'Action', 'Protocol', 'Packets', 'Bytes', 'Conditions']
+ for i in rows:
+ rows[rows.index(i)].pop(1)
+ print(tabulate.tabulate(rows, header) + '\n')
def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule_id=None):
print(f'\n---------------------------------\n{family} Firewall "{hook} {prior}"\n')
@@ -192,7 +209,7 @@ def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule
if not oiface:
oiface = 'any'
- row = [rule_id]
+ row = [rule_id, textwrap.fill(rule_conf.get('description') or '', 50)]
if rule_id in details:
rule_details = details[rule_id]
row.append(rule_details.get('packets', 0))
@@ -209,7 +226,7 @@ def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule
if hook in ['input', 'forward', 'output']:
- row = ['default']
+ row = ['default', '']
rule_details = details['default-action']
row.append(rule_details.get('packets', 0))
row.append(rule_details.get('bytes', 0))
@@ -224,7 +241,7 @@ def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule
rows.append(row)
elif 'default_action' in prior_conf and not single_rule_id:
- row = ['default']
+ row = ['default', '']
if 'default-action' in details:
rule_details = details['default-action']
row.append(rule_details.get('packets', 0))
@@ -240,8 +257,14 @@ def output_firewall_name_statistics(family, hook, prior, prior_conf, single_rule
rows.append(row)
if rows:
- header = ['Rule', 'Packets', 'Bytes', 'Action', 'Source', 'Destination', 'Inbound-Interface', 'Outbound-interface']
- print(tabulate.tabulate(rows, header) + '\n')
+ if args.detail:
+ header = ['Rule', 'Description', 'Packets', 'Bytes', 'Action', 'Source', 'Destination', 'Inbound-Interface', 'Outbound-interface']
+ output_firewall_vertical(rows, header)
+ else:
+ header = ['Rule', 'Packets', 'Bytes', 'Action', 'Source', 'Destination', 'Inbound-Interface', 'Outbound-interface']
+ for i in rows:
+ rows[rows.index(i)].pop(1)
+ print(tabulate.tabulate(rows, header) + '\n')
def show_firewall():
print('Rulesets Information')
@@ -429,7 +452,6 @@ def show_firewall_group(name=None):
return out
- header = ['Name', 'Type', 'References', 'Members']
rows = []
for group_type, group_type_conf in firewall['group'].items():
@@ -441,7 +463,7 @@ def show_firewall_group(name=None):
continue
references = find_references(group_type, group_name)
- row = [group_name, group_type, '\n'.join(references) or 'N/D']
+ row = [group_name, textwrap.fill(group_conf.get('description') or '', 50), group_type, '\n'.join(references) or 'N/D']
if 'address' in group_conf:
row.append("\n".join(sorted(group_conf['address'])))
elif 'network' in group_conf:
@@ -461,13 +483,20 @@ def show_firewall_group(name=None):
if dynamic_type in firewall['group']['dynamic_group']:
for dynamic_name, dynamic_conf in firewall['group']['dynamic_group'][dynamic_type].items():
references = find_references(dynamic_type, dynamic_name)
- row = [dynamic_name, dynamic_type + '(dynamic)', '\n'.join(references) or 'N/D']
+ row = [dynamic_name, textwrap.fill(dynamic_conf.get('description') or '', 50), dynamic_type + '(dynamic)', '\n'.join(references) or 'N/D']
row.append('N/D')
rows.append(row)
if rows:
print('Firewall Groups\n')
- print(tabulate.tabulate(rows, header))
+ if args.detail:
+ header = ['Name', 'Description','Type', 'References', 'Members']
+ output_firewall_vertical(rows, header)
+ else:
+ header = ['Name', 'Type', 'References', 'Members']
+ for i in rows:
+ rows[rows.index(i)].pop(1)
+ print(tabulate.tabulate(rows, header))
def show_summary():
print('Ruleset Summary')
@@ -539,6 +568,7 @@ if __name__ == '__main__':
parser.add_argument('--priority', help='Firewall priority', required=False, action='store', nargs='?', default='')
parser.add_argument('--rule', help='Firewall Rule ID', required=False)
parser.add_argument('--ipv6', help='IPv6 toggle', action='store_true')
+ parser.add_argument('--detail', help='Firewall view select', required=False)
args = parser.parse_args()
diff --git a/src/op_mode/generate_ovpn_client_file.py b/src/op_mode/generate_ovpn_client_file.py
index cec370a07..2d96fe217 100755
--- a/src/op_mode/generate_ovpn_client_file.py
+++ b/src/op_mode/generate_ovpn_client_file.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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,15 +15,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import argparse
-import os
from jinja2 import Template
from textwrap import fill
from vyos.configquery import ConfigTreeQuery
from vyos.ifconfig import Section
-from vyos.utils.process import cmd
-
client_config = """
diff --git a/src/op_mode/generate_tech-support_archive.py b/src/op_mode/generate_tech-support_archive.py
index c490b0137..41b53cd15 100755
--- a/src/op_mode/generate_tech-support_archive.py
+++ b/src/op_mode/generate_tech-support_archive.py
@@ -120,7 +120,7 @@ if __name__ == '__main__':
# Temporary directory creation
tmp_dir_path = f'{tmp_path}/drops-debug_{time_now}'
tmp_dir: Path = Path(tmp_dir_path)
- tmp_dir.mkdir()
+ tmp_dir.mkdir(parents=True)
report_file: Path = Path(f'{tmp_dir_path}/show_tech-support_report.txt')
report_file.touch()
diff --git a/src/op_mode/ikev2_profile_generator.py b/src/op_mode/ikev2_profile_generator.py
index 5454cc0ce..2b29f94bf 100755
--- a/src/op_mode/ikev2_profile_generator.py
+++ b/src/op_mode/ikev2_profile_generator.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -16,7 +16,6 @@
import argparse
-from jinja2 import Template
from sys import exit
from socket import getfqdn
from cryptography.x509.oid import NameOID
diff --git a/src/op_mode/image_info.py b/src/op_mode/image_info.py
index 791001e00..56aefcd6e 100755
--- a/src/op_mode/image_info.py
+++ b/src/op_mode/image_info.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2023 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2023-2024 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This file is part of VyOS.
#
@@ -18,12 +18,14 @@
# VyOS. If not, see <https://www.gnu.org/licenses/>.
import sys
-from typing import List, Union
+from typing import Union
from tabulate import tabulate
from vyos import opmode
-from vyos.system import disk, grub, image
+from vyos.system import disk
+from vyos.system import grub
+from vyos.system import image
from vyos.utils.convert import bytes_to_human
diff --git a/src/op_mode/image_installer.py b/src/op_mode/image_installer.py
index b0567305a..9f6949fb3 100755
--- a/src/op_mode/image_installer.py
+++ b/src/op_mode/image_installer.py
@@ -23,7 +23,6 @@ from shutil import copy, chown, rmtree, copytree
from glob import glob
from sys import exit
from os import environ
-from time import sleep
from typing import Union
from urllib.parse import urlparse
from passlib.hosts import linux_context
@@ -57,6 +56,8 @@ MSG_INFO_INSTALL_DISK_CONFIRM: str = 'Installation will delete all data on the d
MSG_INFO_INSTALL_RAID_CONFIRM: str = 'Installation will delete all data on both drives. Continue?'
MSG_INFO_INSTALL_PARTITONING: str = 'Creating partition table...'
MSG_INPUT_CONFIG_FOUND: str = 'An active configuration was found. Would you like to copy it to the new image?'
+MSG_INPUT_CONFIG_CHOICE: str = 'The following config files are available for boot:'
+MSG_INPUT_CONFIG_CHOOSE: str = 'Which file would you like as boot config?'
MSG_INPUT_IMAGE_NAME: str = 'What would you like to name this image?'
MSG_INPUT_IMAGE_DEFAULT: str = 'Would you like to set the new image as the default one for boot?'
MSG_INPUT_PASSWORD: str = 'Please enter a password for the "vyos" user'
@@ -703,6 +704,10 @@ def install_image() -> None:
valid_responses=['K', 'S', 'U'])
console_dict: dict[str, str] = {'K': 'tty', 'S': 'ttyS', 'U': 'ttyUSB'}
+ config_boot_list = ['/opt/vyatta/etc/config/config.boot',
+ '/opt/vyatta/etc/config.boot.default']
+ default_config = config_boot_list[0]
+
disks: dict[str, int] = find_disks()
install_target: Union[disk.DiskDetails, raid.RaidDetails, None] = None
@@ -711,6 +716,14 @@ def install_image() -> None:
if install_target is None:
install_target = ask_single_disk(disks)
+ # if previous install was selected in search_previous_installation,
+ # directory /mnt/config was prepared for copy below; if not, prompt:
+ if not Path('/mnt/config').exists():
+ default_config: str = select_entry(config_boot_list,
+ MSG_INPUT_CONFIG_CHOICE,
+ MSG_INPUT_CONFIG_CHOOSE,
+ default_entry=1) # select_entry indexes from 1
+
# create directories for installation media
prepare_tmp_disr()
@@ -732,7 +745,7 @@ def install_image() -> None:
chown(target_config_dir, group='vyattacfg')
chmod_2775(target_config_dir)
# copy config
- copy('/opt/vyatta/etc/config/config.boot', target_config_dir)
+ copy(default_config, f'{target_config_dir}/config.boot')
configure_authentication(f'{target_config_dir}/config.boot',
user_password)
Path(f'{target_config_dir}/.vyatta_config').touch()
diff --git a/src/op_mode/image_manager.py b/src/op_mode/image_manager.py
index 1510a667c..1cfb5f5a1 100755
--- a/src/op_mode/image_manager.py
+++ b/src/op_mode/image_manager.py
@@ -33,27 +33,31 @@ DELETE_IMAGE_PROMPT_MSG: str = 'Select an image to delete:'
MSG_DELETE_IMAGE_RUNNING: str = 'Currently running image cannot be deleted; reboot into another image first'
MSG_DELETE_IMAGE_DEFAULT: str = 'Default image cannot be deleted; set another image as default first'
-def annotated_list(images_list: list[str]) -> list[str]:
+def annotate_list(images_list: list[str]) -> list[str]:
"""Annotate list of images with additional info
Args:
images_list (list[str]): a list of image names
Returns:
- list[str]: a list of image names with additional info
+ dict[str, str]: a dict of annotations indexed by image name
"""
- index_running: int = None
- index_default: int = None
- try:
- index_running = images_list.index(image.get_running_image())
- index_default = images_list.index(image.get_default_image())
- except ValueError:
- pass
- if index_running is not None:
- images_list[index_running] += ' (running)'
- if index_default is not None:
- images_list[index_default] += ' (default boot)'
- return images_list
+ running = image.get_running_image()
+ default = image.get_default_image()
+ annotated = {}
+ for image_name in images_list:
+ annotated[image_name] = f'{image_name}'
+ if running in images_list:
+ annotated[running] = annotated[running] + ' (running)'
+ if default in images_list:
+ annotated[default] = annotated[default] + ' (default boot)'
+ return annotated
+
+def define_format(images):
+ annotated = annotate_list(images)
+ def format_selection(image_name):
+ return annotated[image_name]
+ return format_selection
@compat.grub_cfg_update
def delete_image(image_name: Optional[str] = None,
@@ -63,14 +67,16 @@ def delete_image(image_name: Optional[str] = None,
Args:
image_name (str): a name of image to delete
"""
- available_images: list[str] = annotated_list(grub.version_list())
+ available_images: list[str] = grub.version_list()
+ format_selection = define_format(available_images)
if image_name is None:
if no_prompt:
exit('An image name is required for delete action')
else:
image_name = select_entry(available_images,
DELETE_IMAGE_LIST_MSG,
- DELETE_IMAGE_PROMPT_MSG)
+ DELETE_IMAGE_PROMPT_MSG,
+ format_selection)
if image_name == image.get_running_image():
exit(MSG_DELETE_IMAGE_RUNNING)
if image_name == image.get_default_image():
@@ -113,14 +119,16 @@ def set_image(image_name: Optional[str] = None,
Args:
image_name (str): an image name
"""
- available_images: list[str] = annotated_list(grub.version_list())
+ available_images: list[str] = grub.version_list()
+ format_selection = define_format(available_images)
if image_name is None:
if not prompt:
exit('An image name is required for set action')
else:
image_name = select_entry(available_images,
SET_IMAGE_LIST_MSG,
- SET_IMAGE_PROMPT_MSG)
+ SET_IMAGE_PROMPT_MSG,
+ format_selection)
if image_name == image.get_default_image():
exit(f'The image "{image_name}" already configured as default')
if image_name not in available_images:
diff --git a/src/op_mode/interfaces_wireless.py b/src/op_mode/interfaces_wireless.py
index 259fd3900..bf6e462f3 100755
--- a/src/op_mode/interfaces_wireless.py
+++ b/src/op_mode/interfaces_wireless.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -16,7 +16,6 @@
import re
import sys
-import typing
import vyos.opmode
from copy import deepcopy
diff --git a/src/op_mode/openvpn.py b/src/op_mode/openvpn.py
index fd9d2db92..d54a67199 100755
--- a/src/op_mode/openvpn.py
+++ b/src/op_mode/openvpn.py
@@ -205,11 +205,11 @@ def _format_openvpn(data: list) -> str:
intf = d['intf']
l_host = d['local_host']
l_port = d['local_port']
+ out += f'\nOpenVPN status on {intf}\n\n'
for client in d['clients']:
r_host = client['remote_host']
r_port = client['remote_port']
- out += f'\nOpenVPN status on {intf}\n\n'
name = client['name']
remote = r_host + ':' + r_port if r_host and r_port else 'N/A'
tunnel = client['tunnel']
@@ -220,9 +220,8 @@ def _format_openvpn(data: list) -> str:
data_out.append([name, remote, tunnel, local, tx_bytes,
rx_bytes, online_since])
- if data_out:
- out += tabulate(data_out, headers)
- out += "\n"
+ out += tabulate(data_out, headers)
+ out += "\n"
return out
diff --git a/src/op_mode/otp.py b/src/op_mode/otp.py
index 6d4298894..a4ab9b22b 100755
--- a/src/op_mode/otp.py
+++ b/src/op_mode/otp.py
@@ -20,9 +20,7 @@ import sys
import os
import vyos.opmode
from jinja2 import Template
-from vyos.configquery import ConfigTreeQuery
-from vyos.xml import defaults
-from vyos.configdict import dict_merge
+from vyos.config import Config
from vyos.utils.process import popen
@@ -61,7 +59,7 @@ def _check_uname_otp(username:str):
"""
Check if "username" exists and have an OTP key
"""
- config = ConfigTreeQuery()
+ config = Config()
base_key = ['system', 'login', 'user', username, 'authentication', 'otp', 'key']
if not config.exists(base_key):
return None
@@ -71,15 +69,13 @@ def _get_login_otp(username: str, info:str):
"""
Retrieve user settings from configuration and set some defaults
"""
- config = ConfigTreeQuery()
+ config = Config()
base = ['system', 'login', 'user', username]
if not config.exists(base):
return None
- user_otp = config.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(['system', 'login', 'user'])
- user_otp = dict_merge(default_values, user_otp)
+ user_otp = config.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
result = user_otp['authentication']['otp']
# Filling in the system and default options
result['info'] = info
@@ -94,7 +90,7 @@ def _get_login_otp(username: str, info:str):
result['otp_url'] = ''.join(["otpauth://",token_type_acrn,"/",username,"@",\
result['hostname'],"?secret=",result['key_base32'],"&digits=",\
result['otp_length'],"&period=",result['interval']])
- result['qrcode'],err = popen('qrencode -t ansiutf8', input=result['otp_url'])
+ result['qrcode'],_ = popen('qrencode -t ansiutf8', input=result['otp_url'])
return result
def show_login(raw: bool, username: str, info:str):
diff --git a/src/op_mode/policy_route.py b/src/op_mode/policy_route.py
index eff99de7f..d12465008 100755
--- a/src/op_mode/policy_route.py
+++ b/src/op_mode/policy_route.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright (C) 2021-2024 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
@@ -20,7 +20,6 @@ import tabulate
from vyos.config import Config
from vyos.utils.process import cmd
-from vyos.utils.dict import dict_search_args
def get_config_policy(conf, name=None, ipv6=False):
config_path = ['policy']
diff --git a/src/op_mode/powerctrl.py b/src/op_mode/powerctrl.py
index c07d0c4bd..6c8f802b5 100755
--- a/src/op_mode/powerctrl.py
+++ b/src/op_mode/powerctrl.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -18,7 +18,7 @@ import os
import re
from argparse import ArgumentParser
-from datetime import datetime, timedelta, time as type_time, date as type_date
+from datetime import datetime
from sys import exit
from time import time
diff --git a/src/op_mode/restart_dhcp_relay.py b/src/op_mode/restart_dhcp_relay.py
index 3ead97f4c..42626cac4 100755
--- a/src/op_mode/restart_dhcp_relay.py
+++ b/src/op_mode/restart_dhcp_relay.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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
@@ -20,7 +20,6 @@
import sys
import argparse
-import os
import vyos.config
from vyos.utils.process import call
diff --git a/src/op_mode/reverseproxy.py b/src/op_mode/reverseproxy.py
index 44ffd7a37..19704182a 100755
--- a/src/op_mode/reverseproxy.py
+++ b/src/op_mode/reverseproxy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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,9 +17,7 @@
import json
import socket
import sys
-import typing
-from sys import exit
from tabulate import tabulate
from vyos.configquery import ConfigTreeQuery
diff --git a/src/op_mode/sflow.py b/src/op_mode/sflow.py
index dca7f44cb..0f3feb35a 100755
--- a/src/op_mode/sflow.py
+++ b/src/op_mode/sflow.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -20,7 +20,6 @@ import sys
from tabulate import tabulate
from vyos.configquery import ConfigTreeQuery
-from vyos.utils.process import cmd
import vyos.opmode
diff --git a/src/op_mode/show_techsupport_report.py b/src/op_mode/show_techsupport_report.py
index 53144fd52..230fb252d 100644
--- a/src/op_mode/show_techsupport_report.py
+++ b/src/op_mode/show_techsupport_report.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -14,8 +14,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 os
-
from typing import List
from vyos.utils.process import rc_cmd
from vyos.ifconfig import Section
diff --git a/src/op_mode/snmp.py b/src/op_mode/snmp.py
index 43f5d9e0a..3d6cd220a 100755
--- a/src/op_mode/snmp.py
+++ b/src/op_mode/snmp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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
@@ -13,13 +13,7 @@
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-#
-# File: snmp.py
-# Purpose:
-# Show SNMP community/remote hosts
-# Used by the "run show snmp community" commands.
-import os
import sys
import argparse
diff --git a/src/op_mode/system.py b/src/op_mode/system.py
index 11a3a8730..854b4b699 100755
--- a/src/op_mode/system.py
+++ b/src/op_mode/system.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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,12 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import jmespath
-import json
import sys
-import requests
-import typing
-
-from sys import exit
from vyos.configquery import ConfigTreeQuery
diff --git a/src/op_mode/vpn_ike_sa.py b/src/op_mode/vpn_ike_sa.py
index 7186bdec2..5e2aaae6b 100755
--- a/src/op_mode/vpn_ike_sa.py
+++ b/src/op_mode/vpn_ike_sa.py
@@ -15,14 +15,13 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import argparse
-import re
import sys
import vici
from vyos.utils.process import process_named_running
ike_sa_peer_prefix = """\
-Peer ID / IP Local ID / IP
+Peer ID / IP Local ID / IP
------------ -------------"""
ike_sa_tunnel_prefix = """
diff --git a/src/op_mode/vrrp.py b/src/op_mode/vrrp.py
index b3ab55cc3..60be86065 100755
--- a/src/op_mode/vrrp.py
+++ b/src/op_mode/vrrp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2023 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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,14 +15,10 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
-import time
import argparse
-import json
-import tabulate
from vyos.configquery import ConfigTreeQuery
from vyos.ifconfig.vrrp import VRRP
-from vyos.ifconfig.vrrp import VRRPError
from vyos.ifconfig.vrrp import VRRPNoData
parser = argparse.ArgumentParser()
diff --git a/src/services/api/graphql/generate/composite_function.py b/src/services/api/graphql/generate/composite_function.py
index bc9d80fbb..d6626fd1f 100644
--- a/src/services/api/graphql/generate/composite_function.py
+++ b/src/services/api/graphql/generate/composite_function.py
@@ -1,11 +1,7 @@
# typing information for composite functions: those that invoke several
# elementary requests, and return the result as a single dict
-import typing
-
def system_status():
pass
queries = {'system_status': system_status}
-
mutations = {}
-
diff --git a/src/services/api/graphql/graphql/auth_token_mutation.py b/src/services/api/graphql/graphql/auth_token_mutation.py
index 603a13758..a53fa4d60 100644
--- a/src/services/api/graphql/graphql/auth_token_mutation.py
+++ b/src/services/api/graphql/graphql/auth_token_mutation.py
@@ -1,4 +1,4 @@
-# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2022-2024 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
@@ -13,10 +13,10 @@
# 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/>.
-import jwt
import datetime
-from typing import Any, Dict
-from ariadne import ObjectType, UnionType
+from typing import Any
+from typing import Dict
+from ariadne import ObjectType
from graphql import GraphQLResolveInfo
from .. libs.token_auth import generate_token
diff --git a/src/services/api/graphql/graphql/directives.py b/src/services/api/graphql/graphql/directives.py
index a7919854a..3927aee58 100644
--- a/src/services/api/graphql/graphql/directives.py
+++ b/src/services/api/graphql/graphql/directives.py
@@ -1,4 +1,4 @@
-# Copyright 2021 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2021-2024 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
@@ -13,7 +13,7 @@
# 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/>.
-from ariadne import SchemaDirectiveVisitor, ObjectType
+from ariadne import SchemaDirectiveVisitor
from . queries import *
from . mutations import *
diff --git a/src/services/api/graphql/graphql/mutations.py b/src/services/api/graphql/graphql/mutations.py
index 8254e22b1..d115a8e94 100644
--- a/src/services/api/graphql/graphql/mutations.py
+++ b/src/services/api/graphql/graphql/mutations.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2021-2024 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
@@ -14,11 +14,13 @@
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from importlib import import_module
-from typing import Any, Dict, Optional
from ariadne import ObjectType, convert_camel_case_to_snake
-from graphql import GraphQLResolveInfo
from makefun import with_signature
+# used below by func_sig
+from typing import Any, Dict, Optional # pylint: disable=W0611
+from graphql import GraphQLResolveInfo # pylint: disable=W0611
+
from .. import state
from .. libs import key_auth
from api.graphql.session.session import Session
diff --git a/src/services/api/graphql/graphql/queries.py b/src/services/api/graphql/graphql/queries.py
index daccc19b2..717098259 100644
--- a/src/services/api/graphql/graphql/queries.py
+++ b/src/services/api/graphql/graphql/queries.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2021-2024 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
@@ -14,11 +14,13 @@
# along with this library. If not, see <http://www.gnu.org/licenses/>.
from importlib import import_module
-from typing import Any, Dict, Optional
from ariadne import ObjectType, convert_camel_case_to_snake
-from graphql import GraphQLResolveInfo
from makefun import with_signature
+# used below by func_sig
+from typing import Any, Dict, Optional # pylint: disable=W0611
+from graphql import GraphQLResolveInfo # pylint: disable=W0611
+
from .. import state
from .. libs import key_auth
from api.graphql.session.session import Session
diff --git a/src/services/api/graphql/libs/op_mode.py b/src/services/api/graphql/libs/op_mode.py
index 5022f7d4e..86e38eae6 100644
--- a/src/services/api/graphql/libs/op_mode.py
+++ b/src/services/api/graphql/libs/op_mode.py
@@ -1,4 +1,4 @@
-# Copyright 2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2022-2024 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
@@ -16,7 +16,9 @@
import os
import re
import typing
-from typing import Union, Tuple, Optional
+
+from typing import Union
+from typing import Optional
from humps import decamelize
from vyos.defaults import directories
diff --git a/src/services/api/graphql/session/composite/system_status.py b/src/services/api/graphql/session/composite/system_status.py
index d809f32e3..516a4eff6 100755
--- a/src/services/api/graphql/session/composite/system_status.py
+++ b/src/services/api/graphql/session/composite/system_status.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright (C) 2022-2024 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
@@ -13,15 +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 os
-import sys
-import json
-import importlib.util
-
-from vyos.defaults import directories
from api.graphql.libs.op_mode import load_op_mode_as_module
diff --git a/src/services/api/graphql/session/session.py b/src/services/api/graphql/session/session.py
index 3c5a062b6..6ae44b9bf 100644
--- a/src/services/api/graphql/session/session.py
+++ b/src/services/api/graphql/session/session.py
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2021-2024 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
@@ -21,7 +21,6 @@ from ariadne import convert_camel_case_to_snake
from vyos.config import Config
from vyos.configtree import ConfigTree
from vyos.defaults import directories
-from vyos.template import render
from vyos.opmode import Error as OpModeError
from api.graphql.libs.op_mode import load_op_mode_as_module, split_compound_op_mode_name
diff --git a/src/services/vyos-http-api-server b/src/services/vyos-http-api-server
index 77870a84c..ecbf6fcf9 100755
--- a/src/services/vyos-http-api-server
+++ b/src/services/vyos-http-api-server
@@ -140,6 +140,14 @@ class ConfigSectionModel(ApiModel, BaseConfigSectionModel):
class ConfigSectionListModel(ApiModel):
commands: List[BaseConfigSectionModel]
+class BaseConfigSectionTreeModel(BaseModel):
+ op: StrictStr
+ mask: Dict
+ config: Dict
+
+class ConfigSectionTreeModel(ApiModel, BaseConfigSectionTreeModel):
+ pass
+
class RetrieveModel(ApiModel):
op: StrictStr
path: List[StrictStr]
@@ -374,7 +382,7 @@ class MultipartRequest(Request):
self.form_err = (400,
f"Malformed command '{c}': missing 'op' field")
if endpoint not in ('/config-file', '/container-image',
- '/image'):
+ '/image', '/configure-section'):
if 'path' not in c:
self.form_err = (400,
f"Malformed command '{c}': missing 'path' field")
@@ -392,12 +400,9 @@ class MultipartRequest(Request):
self.form_err = (400,
f"Malformed command '{c}': 'value' field must be a string")
if endpoint in ('/configure-section'):
- if 'section' not in c:
- self.form_err = (400,
- f"Malformed command '{c}': missing 'section' field")
- elif not isinstance(c['section'], dict):
+ if 'section' not in c and 'config' not in c:
self.form_err = (400,
- f"Malformed command '{c}': 'section' field must be JSON of dict")
+ f"Malformed command '{c}': missing 'section' or 'config' field")
if 'key' not in forms and 'key' not in merge:
self.form_err = (401, "Valid API key is required")
@@ -455,7 +460,8 @@ def call_commit(s: ConfigSession):
logger.warning(f"ConfigSessionError: {e}")
def _configure_op(data: Union[ConfigureModel, ConfigureListModel,
- ConfigSectionModel, ConfigSectionListModel],
+ ConfigSectionModel, ConfigSectionListModel,
+ ConfigSectionTreeModel],
request: Request, background_tasks: BackgroundTasks):
session = app.state.vyos_session
env = session.get_session_env()
@@ -481,7 +487,8 @@ def _configure_op(data: Union[ConfigureModel, ConfigureListModel,
try:
for c in data:
op = c.op
- path = c.path
+ if not isinstance(c, BaseConfigSectionTreeModel):
+ path = c.path
if isinstance(c, BaseConfigureModel):
if c.value:
@@ -495,6 +502,10 @@ def _configure_op(data: Union[ConfigureModel, ConfigureListModel,
elif isinstance(c, BaseConfigSectionModel):
section = c.section
+ elif isinstance(c, BaseConfigSectionTreeModel):
+ mask = c.mask
+ config = c.config
+
if isinstance(c, BaseConfigureModel):
if op == 'set':
session.set(path, value=value)
@@ -514,6 +525,14 @@ def _configure_op(data: Union[ConfigureModel, ConfigureListModel,
session.load_section(path, section)
else:
raise ConfigSessionError(f"'{op}' is not a valid operation")
+
+ elif isinstance(c, BaseConfigSectionTreeModel):
+ if op == 'set':
+ session.set_section_tree(config)
+ elif op == 'load':
+ session.load_section_tree(mask, config)
+ else:
+ raise ConfigSessionError(f"'{op}' is not a valid operation")
# end for
config = Config(session_env=env)
d = get_config_diff(config)
@@ -554,7 +573,8 @@ def configure_op(data: Union[ConfigureModel,
@app.post('/configure-section')
def configure_section_op(data: Union[ConfigSectionModel,
- ConfigSectionListModel],
+ ConfigSectionListModel,
+ ConfigSectionTreeModel],
request: Request, background_tasks: BackgroundTasks):
return _configure_op(data, request, background_tasks)
diff --git a/src/system/keepalived-fifo.py b/src/system/keepalived-fifo.py
index 6d33e372d..24733803a 100755
--- a/src/system/keepalived-fifo.py
+++ b/src/system/keepalived-fifo.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2021 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -20,13 +20,11 @@ import signal
import argparse
import threading
import re
-import json
import logging
from queue import Queue
from logging.handlers import SysLogHandler
-from vyos.ifconfig.vrrp import VRRP
from vyos.configquery import ConfigTreeQuery
from vyos.utils.process import cmd
from vyos.utils.dict import dict_search
diff --git a/src/tests/test_config_diff.py b/src/tests/test_config_diff.py
index f61cbc4a2..61a2f3487 100644
--- a/src/tests/test_config_diff.py
+++ b/src/tests/test_config_diff.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright (C) 2023-2024 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
@@ -14,7 +14,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 os
import vyos.configtree
from unittest import TestCase
diff --git a/src/tests/test_config_parser.py b/src/tests/test_config_parser.py
index 8148aa79b..c69732daa 100644
--- a/src/tests/test_config_parser.py
+++ b/src/tests/test_config_parser.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2020 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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
@@ -14,7 +14,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 os
import vyos.configtree
from unittest import TestCase
diff --git a/src/tests/test_initial_setup.py b/src/tests/test_initial_setup.py
index ba50d06cc..f85bf1265 100644
--- a/src/tests/test_initial_setup.py
+++ b/src/tests/test_initial_setup.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018 VyOS maintainers and contributors
+# Copyright (C) 2018-2024 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
@@ -14,8 +14,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 os
-import tempfile
import unittest
import vyos.configtree
import vyos.initialsetup as vis
@@ -101,4 +99,3 @@ class TestInitialSetup(TestCase):
if __name__ == "__main__":
unittest.main()
-
diff --git a/src/tests/test_template.py b/src/tests/test_template.py
index aba97015e..dbb86b40b 100644
--- a/src/tests/test_template.py
+++ b/src/tests/test_template.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2023 VyOS maintainers and contributors
+# Copyright (C) 2020-2024 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
@@ -14,9 +14,9 @@
# 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 vyos.template
+from vyos.utils.network import interface_exists
from ipaddress import ip_network
from unittest import TestCase
@@ -26,7 +26,7 @@ class TestVyOSTemplate(TestCase):
def test_is_interface(self):
for interface in ['lo', 'eth0']:
- if os.path.exists(f'/sys/class/net/{interface}'):
+ if interface_exists(interface):
self.assertTrue(vyos.template.is_interface(interface))
else:
self.assertFalse(vyos.template.is_interface(interface))