summaryrefslogtreecommitdiff
path: root/src/conf_mode
diff options
context:
space:
mode:
Diffstat (limited to 'src/conf_mode')
-rwxr-xr-xsrc/conf_mode/container.py14
-rwxr-xr-xsrc/conf_mode/firewall.py39
-rwxr-xr-xsrc/conf_mode/high-availability.py2
-rwxr-xr-xsrc/conf_mode/interfaces_bonding.py2
-rwxr-xr-xsrc/conf_mode/interfaces_bridge.py15
-rwxr-xr-xsrc/conf_mode/interfaces_dummy.py2
-rwxr-xr-xsrc/conf_mode/interfaces_ethernet.py36
-rwxr-xr-xsrc/conf_mode/interfaces_geneve.py2
-rwxr-xr-xsrc/conf_mode/interfaces_input.py2
-rwxr-xr-xsrc/conf_mode/interfaces_l2tpv3.py2
-rwxr-xr-xsrc/conf_mode/interfaces_loopback.py2
-rwxr-xr-xsrc/conf_mode/interfaces_macsec.py2
-rwxr-xr-xsrc/conf_mode/interfaces_openvpn.py2
-rwxr-xr-xsrc/conf_mode/interfaces_pppoe.py2
-rwxr-xr-xsrc/conf_mode/interfaces_pseudo-ethernet.py4
-rwxr-xr-xsrc/conf_mode/interfaces_sstpc.py2
-rwxr-xr-xsrc/conf_mode/interfaces_tunnel.py2
-rwxr-xr-xsrc/conf_mode/interfaces_virtual-ethernet.py4
-rwxr-xr-xsrc/conf_mode/interfaces_vti.py4
-rwxr-xr-xsrc/conf_mode/interfaces_vxlan.py2
-rwxr-xr-xsrc/conf_mode/interfaces_wireguard.py32
-rwxr-xr-xsrc/conf_mode/interfaces_wireless.py2
-rwxr-xr-xsrc/conf_mode/interfaces_wwan.py9
-rw-r--r--src/conf_mode/load-balancing_haproxy.py37
-rwxr-xr-xsrc/conf_mode/load-balancing_wan.py2
-rwxr-xr-xsrc/conf_mode/nat.py16
-rwxr-xr-xsrc/conf_mode/nat64.py2
-rwxr-xr-xsrc/conf_mode/nat66.py6
-rwxr-xr-xsrc/conf_mode/nat_cgnat.py2
-rwxr-xr-xsrc/conf_mode/netns.py2
-rwxr-xr-xsrc/conf_mode/pki.py101
-rwxr-xr-xsrc/conf_mode/policy.py18
-rwxr-xr-xsrc/conf_mode/policy_local-route.py2
-rwxr-xr-xsrc/conf_mode/policy_route.py49
-rwxr-xr-xsrc/conf_mode/protocols_babel.py2
-rwxr-xr-xsrc/conf_mode/protocols_bfd.py2
-rwxr-xr-xsrc/conf_mode/protocols_bgp.py21
-rwxr-xr-xsrc/conf_mode/protocols_eigrp.py2
-rwxr-xr-xsrc/conf_mode/protocols_failover.py2
-rwxr-xr-xsrc/conf_mode/protocols_igmp-proxy.py2
-rwxr-xr-xsrc/conf_mode/protocols_isis.py2
-rwxr-xr-xsrc/conf_mode/protocols_mpls.py2
-rwxr-xr-xsrc/conf_mode/protocols_nhrp.py2
-rw-r--r--src/conf_mode/protocols_openfabric.py2
-rwxr-xr-xsrc/conf_mode/protocols_ospf.py13
-rwxr-xr-xsrc/conf_mode/protocols_ospfv3.py2
-rwxr-xr-xsrc/conf_mode/protocols_pim.py2
-rwxr-xr-xsrc/conf_mode/protocols_pim6.py2
-rwxr-xr-xsrc/conf_mode/protocols_rip.py2
-rwxr-xr-xsrc/conf_mode/protocols_ripng.py2
-rwxr-xr-xsrc/conf_mode/protocols_rpki.py19
-rwxr-xr-xsrc/conf_mode/protocols_segment-routing.py2
-rwxr-xr-xsrc/conf_mode/protocols_static.py2
-rwxr-xr-xsrc/conf_mode/protocols_static_arp.py2
-rwxr-xr-xsrc/conf_mode/protocols_static_neighbor-proxy.py2
-rwxr-xr-xsrc/conf_mode/qos.py10
-rwxr-xr-xsrc/conf_mode/service_aws_glb.py2
-rwxr-xr-xsrc/conf_mode/service_broadcast-relay.py2
-rwxr-xr-xsrc/conf_mode/service_config-sync.py2
-rwxr-xr-xsrc/conf_mode/service_conntrack-sync.py2
-rwxr-xr-xsrc/conf_mode/service_console-server.py2
-rwxr-xr-xsrc/conf_mode/service_dhcp-relay.py2
-rwxr-xr-xsrc/conf_mode/service_dhcp-server.py49
-rwxr-xr-xsrc/conf_mode/service_dhcpv6-relay.py2
-rwxr-xr-xsrc/conf_mode/service_dhcpv6-server.py2
-rwxr-xr-xsrc/conf_mode/service_dns_dynamic.py2
-rwxr-xr-xsrc/conf_mode/service_dns_forwarding.py9
-rwxr-xr-xsrc/conf_mode/service_event-handler.py2
-rwxr-xr-xsrc/conf_mode/service_https.py16
-rwxr-xr-xsrc/conf_mode/service_ids_ddos-protection.py104
-rwxr-xr-xsrc/conf_mode/service_ipoe-server.py8
-rwxr-xr-xsrc/conf_mode/service_lldp.py2
-rwxr-xr-xsrc/conf_mode/service_mdns_repeater.py2
-rw-r--r--src/conf_mode/service_monitoring_network_event.py2
-rwxr-xr-xsrc/conf_mode/service_monitoring_prometheus.py30
-rwxr-xr-xsrc/conf_mode/service_monitoring_telegraf.py2
-rwxr-xr-xsrc/conf_mode/service_monitoring_zabbix-agent.py2
-rwxr-xr-xsrc/conf_mode/service_ndp-proxy.py2
-rwxr-xr-xsrc/conf_mode/service_ntp.py2
-rwxr-xr-xsrc/conf_mode/service_pppoe-server.py6
-rwxr-xr-xsrc/conf_mode/service_router-advert.py2
-rwxr-xr-xsrc/conf_mode/service_salt-minion.py2
-rwxr-xr-xsrc/conf_mode/service_sla.py2
-rwxr-xr-xsrc/conf_mode/service_snmp.py2
-rwxr-xr-xsrc/conf_mode/service_ssh.py78
-rw-r--r--src/conf_mode/service_stunnel.py2
-rwxr-xr-xsrc/conf_mode/service_suricata.py2
-rwxr-xr-xsrc/conf_mode/service_tftp-server.py2
-rwxr-xr-xsrc/conf_mode/service_webproxy.py2
-rwxr-xr-xsrc/conf_mode/system_acceleration.py2
-rwxr-xr-xsrc/conf_mode/system_config-management.py2
-rwxr-xr-xsrc/conf_mode/system_conntrack.py4
-rwxr-xr-xsrc/conf_mode/system_console.py2
-rwxr-xr-xsrc/conf_mode/system_flow-accounting.py2
-rwxr-xr-xsrc/conf_mode/system_frr.py2
-rwxr-xr-xsrc/conf_mode/system_host-name.py4
-rwxr-xr-xsrc/conf_mode/system_ip.py7
-rwxr-xr-xsrc/conf_mode/system_ipv6.py2
-rwxr-xr-xsrc/conf_mode/system_lcd.py2
-rwxr-xr-xsrc/conf_mode/system_login.py52
-rwxr-xr-xsrc/conf_mode/system_login_banner.py2
-rwxr-xr-xsrc/conf_mode/system_logs.py2
-rwxr-xr-xsrc/conf_mode/system_option.py56
-rwxr-xr-xsrc/conf_mode/system_proxy.py2
-rwxr-xr-xsrc/conf_mode/system_sflow.py2
-rwxr-xr-xsrc/conf_mode/system_sysctl.py2
-rwxr-xr-xsrc/conf_mode/system_syslog.py4
-rwxr-xr-xsrc/conf_mode/system_task-scheduler.py2
-rwxr-xr-xsrc/conf_mode/system_timezone.py2
-rwxr-xr-xsrc/conf_mode/system_update-check.py2
-rw-r--r--src/conf_mode/system_wireless.py2
-rwxr-xr-xsrc/conf_mode/vpn_ipsec.py4
-rwxr-xr-xsrc/conf_mode/vpn_l2tp.py2
-rwxr-xr-xsrc/conf_mode/vpn_openconnect.py329
-rwxr-xr-xsrc/conf_mode/vpn_pptp.py2
-rwxr-xr-xsrc/conf_mode/vpn_sstp.py2
-rwxr-xr-xsrc/conf_mode/vrf.py13
117 files changed, 890 insertions, 492 deletions
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py
index 18d660a4e..4ec9b8849 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -310,12 +310,13 @@ def generate_run_arguments(name, container_config):
memory = container_config['memory']
shared_memory = container_config['shared_memory']
restart = container_config['restart']
+ log_driver = container_config['log_driver']
# Add sysctl options
sysctl_opt = ''
if 'sysctl' in container_config and 'parameter' in container_config['sysctl']:
for k, v in container_config['sysctl']['parameter'].items():
- sysctl_opt += f" --sysctl {k}={v['value']}"
+ sysctl_opt += f" --sysctl \"{k}={v['value']}\""
# Add capability options. Should be in uppercase
capabilities = ''
@@ -324,6 +325,11 @@ def generate_run_arguments(name, container_config):
cap = cap.upper().replace('-', '_')
capabilities += f' --cap-add={cap}'
+ # Grant root capabilities to the container
+ privileged = ''
+ if 'privileged' in container_config:
+ privileged = '--privileged'
+
# Add a host device to the container /dev/x:/dev/x
device = ''
if 'device' in container_config:
@@ -402,8 +408,8 @@ def generate_run_arguments(name, container_config):
for ns in container_config['name_server']:
name_server += f'--dns {ns}'
- container_base_cmd = f'--detach --interactive --tty --replace {capabilities} --cpus {cpu_quota} {sysctl_opt} ' \
- f'--memory {memory}m --shm-size {shared_memory}m --memory-swap 0 --restart {restart} ' \
+ container_base_cmd = f'--detach --interactive --tty --replace {capabilities} {privileged} --cpus {cpu_quota} {sysctl_opt} ' \
+ f'--memory {memory}m --shm-size {shared_memory}m --memory-swap 0 --restart {restart} --log-driver={log_driver} ' \
f'--name {name} {hostname} {device} {port} {name_server} {volume} {tmpfs} {env_opt} {label} {uid} {host_pid}'
entrypoint = ''
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index cebe57092..90fdded99 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -17,6 +17,8 @@
import os
import re
+from glob import glob
+
from sys import exit
from vyos.base import Warning
from vyos.config import Config
@@ -30,6 +32,7 @@ from vyos.firewall import geoip_update
from vyos.template import render
from vyos.utils.dict import dict_search_args
from vyos.utils.dict import dict_search_recursive
+from vyos.utils.file import write_file
from vyos.utils.process import call
from vyos.utils.process import cmd
from vyos.utils.process import rc_cmd
@@ -37,7 +40,6 @@ from vyos.utils.network import get_vrf_members
from vyos.utils.network import get_interface_vrf
from vyos import ConfigError
from vyos import airbag
-from pathlib import Path
from subprocess import run as subp_run
airbag.enable()
@@ -205,7 +207,7 @@ def verify_rule(firewall, family, hook, priority, rule_id, rule_conf):
if 'jump' not in rule_conf['action']:
raise ConfigError('jump-target defined, but action jump needed and it is not defined')
target = rule_conf['jump_target']
- if hook != 'name': # This is a bit clumsy, but consolidates a chunk of code.
+ if hook != 'name': # This is a bit clumsy, but consolidates a chunk of code.
verify_jump_target(firewall, hook, target, family, recursive=True)
else:
verify_jump_target(firewall, hook, target, family, recursive=False)
@@ -268,12 +270,12 @@ def verify_rule(firewall, family, hook, priority, rule_id, rule_conf):
if dict_search_args(rule_conf, 'gre', 'flags', 'checksum') is None:
# There is no builtin match in nftables for the GRE key, so we need to do a raw lookup.
- # The offset of the key within the packet shifts depending on the C-flag.
- # 99% of the time, nobody will have checksums enabled - it's usually a manual config option.
- # We can either assume it is unset unless otherwise directed
+ # The offset of the key within the packet shifts depending on the C-flag.
+ # 99% of the time, nobody will have checksums enabled - it's usually a manual config option.
+ # We can either assume it is unset unless otherwise directed
# (confusing, requires doco to explain why it doesn't work sometimes)
- # or, demand an explicit selection to be made for this specific match rule.
- # This check enforces the latter. The user is free to create rules for both cases.
+ # or, demand an explicit selection to be made for this specific match rule.
+ # This check enforces the latter. The user is free to create rules for both cases.
raise ConfigError('Matching GRE tunnel key requires an explicit checksum flag match. For most cases, use "gre flags checksum unset"')
if dict_search_args(rule_conf, 'gre', 'flags', 'key', 'unset') is not None:
@@ -286,7 +288,7 @@ def verify_rule(firewall, family, hook, priority, rule_id, rule_conf):
if gre_inner_value < 0 or gre_inner_value > 65535:
raise ConfigError('inner-proto outside valid ethertype range 0-65535')
except ValueError:
- pass # Symbolic constant, pre-validated before reaching here.
+ pass # Symbolic constant, pre-validated before reaching here.
tcp_flags = dict_search_args(rule_conf, 'tcp', 'flags')
if tcp_flags:
@@ -437,6 +439,16 @@ def verify(firewall):
for ifname in interfaces:
verify_hardware_offload(ifname)
+ if 'offload' in firewall.get('global_options', {}).get('state_policy', {}):
+ offload_path = firewall['global_options']['state_policy']['offload']
+ if 'offload_target' not in offload_path:
+ raise ConfigError('offload-target must be specified')
+
+ offload_target = offload_path['offload_target']
+
+ if not dict_search_args(firewall, 'flowtable', offload_target):
+ raise ConfigError(f'Invalid offload-target. Flowtable "{offload_target}" does not exist on the system')
+
if 'group' in firewall:
for group_type in nested_group_types:
if group_type in firewall['group']:
@@ -616,10 +628,11 @@ def apply(firewall):
domain_action = 'restart'
if dict_search_args(firewall, 'group', 'remote_group') or dict_search_args(firewall, 'group', 'domain_group') or firewall['ip_fqdn'].items() or firewall['ip6_fqdn'].items():
text = f'# Automatically generated by firewall.py\nThis file indicates that vyos-domain-resolver service is used by the firewall.\n'
- Path(domain_resolver_usage).write_text(text)
+ write_file(domain_resolver_usage, text)
else:
- Path(domain_resolver_usage).unlink(missing_ok=True)
- if not Path('/run').glob('use-vyos-domain-resolver*'):
+ if os.path.exists(domain_resolver_usage):
+ os.unlink(domain_resolver_usage)
+ if not glob('/run/use-vyos-domain-resolver*'):
domain_action = 'stop'
call(f'systemctl {domain_action} vyos-domain-resolver.service')
@@ -627,7 +640,7 @@ def apply(firewall):
# Call helper script to Update set contents
if 'name' in firewall['geoip_updated'] or 'ipv6_name' in firewall['geoip_updated']:
print('Updating GeoIP. Please wait...')
- geoip_update(firewall)
+ geoip_update(firewall=firewall)
return None
diff --git a/src/conf_mode/high-availability.py b/src/conf_mode/high-availability.py
index c726db8b2..005bb6cce 100755
--- a/src/conf_mode/high-availability.py
+++ b/src/conf_mode/high-availability.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_bonding.py b/src/conf_mode/interfaces_bonding.py
index 84316c16e..4a2317f85 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_bridge.py b/src/conf_mode/interfaces_bridge.py
index aff93af2a..8cb0c515a 100755
--- a/src/conf_mode/interfaces_bridge.py
+++ b/src/conf_mode/interfaces_bridge.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,6 +25,7 @@ from vyos.configdict import has_vlan_subinterface_configured
from vyos.configverify import verify_dhcpv6
from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_mtu_ipv6
from vyos.ifconfig import BridgeIf
from vyos.configdict import has_address_configured
from vyos.configdict import has_vrf_configured
@@ -110,6 +111,11 @@ def get_config(config=None):
elif interface.startswith('wlan') and interface_exists(interface):
set_dependents('wlan', conf, interface)
+ if interface.startswith('vtun'):
+ _, tmp_config = get_interface_dict(conf, ['interfaces', 'openvpn'], interface)
+ tmp = tmp_config.get('device_type') == 'tap'
+ bridge['member']['interface'][interface].update({'valid_ovpn' : tmp})
+
# delete empty dictionary keys - no need to run code paths if nothing is there to do
if 'member' in bridge:
if 'interface' in bridge['member'] and len(bridge['member']['interface']) == 0:
@@ -136,6 +142,7 @@ def verify(bridge):
verify_dhcpv6(bridge)
verify_vrf(bridge)
+ verify_mtu_ipv6(bridge)
verify_mirror_redirect(bridge)
ifname = bridge['ifname']
@@ -165,6 +172,9 @@ def verify(bridge):
if 'has_vrf' in interface_config:
raise ConfigError(error_msg + 'it has a VRF assigned!')
+ if 'bpdu_guard' in interface_config and 'root_guard' in interface_config:
+ raise ConfigError(error_msg + 'bpdu-guard and root-guard cannot be configured at the same time!')
+
if 'enable_vlan' in bridge:
if 'has_vlan' in interface_config:
raise ConfigError(error_msg + 'it has VLAN subinterface(s) assigned!')
@@ -173,6 +183,9 @@ def verify(bridge):
if option in interface_config:
raise ConfigError('Can not use VLAN options on non VLAN aware bridge')
+ if interface.startswith('vtun') and not interface_config['valid_ovpn']:
+ raise ConfigError(error_msg + 'OpenVPN device-type must be set to "tap"')
+
if 'enable_vlan' in bridge:
if dict_search('vif.1', bridge):
raise ConfigError(f'VLAN 1 sub interface cannot be set for VLAN aware bridge {ifname}, and VLAN 1 is always the parent interface')
diff --git a/src/conf_mode/interfaces_dummy.py b/src/conf_mode/interfaces_dummy.py
index db768b94d..0a83eb23b 100755
--- a/src/conf_mode/interfaces_dummy.py
+++ b/src/conf_mode/interfaces_dummy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_ethernet.py b/src/conf_mode/interfaces_ethernet.py
index 41c89fdf8..b112b244e 100755
--- a/src/conf_mode/interfaces_ethernet.py
+++ b/src/conf_mode/interfaces_ethernet.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,6 +22,7 @@ from vyos.base import Warning
from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configdict import is_node_changed
+from vyos.configdict import get_flowtable_interfaces
from vyos.configverify import verify_address
from vyos.configverify import verify_dhcpv6
from vyos.configverify import verify_interface_exists
@@ -168,6 +169,8 @@ def get_config(config=None):
tmp = is_node_changed(conf, base + [ifname, 'evpn'])
if tmp: ethernet.update({'frr_dict' : get_frrender_dict(conf)})
+ ethernet['flowtable_interfaces'] = get_flowtable_interfaces(conf)
+
return ethernet
def verify_speed_duplex(ethernet: dict, ethtool: Ethtool):
@@ -269,7 +272,38 @@ def verify_allowedbond_changes(ethernet: dict):
f' on interface "{ethernet["ifname"]}".' \
f' Interface is a bond member')
+def verify_flowtable(ethernet: dict):
+ ifname = ethernet['ifname']
+
+ if 'deleted' in ethernet and ifname in ethernet['flowtable_interfaces']:
+ raise ConfigError(f'Cannot delete interface "{ifname}", still referenced on a flowtable')
+
+ if 'vif_remove' in ethernet:
+ for vif in ethernet['vif_remove']:
+ vifname = f'{ifname}.{vif}'
+
+ if vifname in ethernet['flowtable_interfaces']:
+ raise ConfigError(f'Cannot delete interface "{vifname}", still referenced on a flowtable')
+
+ if 'vif_s_remove' in ethernet:
+ for vifs in ethernet['vif_s_remove']:
+ vifsname = f'{ifname}.{vifs}'
+
+ if vifsname in ethernet['flowtable_interfaces']:
+ raise ConfigError(f'Cannot delete interface "{vifsname}", still referenced on a flowtable')
+
+ if 'vif_s' in ethernet:
+ for vifs, vifs_conf in ethernet['vif_s'].items():
+ if 'vif_c_delete' in vifs_conf:
+ for vifc in vifs_conf['vif_c_delete']:
+ vifcname = f'{ifname}.{vifs}.{vifc}'
+
+ if vifcname in ethernet['flowtable_interfaces']:
+ raise ConfigError(f'Cannot delete interface "{vifcname}", still referenced on a flowtable')
+
def verify(ethernet):
+ verify_flowtable(ethernet)
+
if 'deleted' in ethernet:
return None
if 'is_bond_member' in ethernet:
diff --git a/src/conf_mode/interfaces_geneve.py b/src/conf_mode/interfaces_geneve.py
index 1c5b4d0e7..11b349002 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_input.py b/src/conf_mode/interfaces_input.py
index ad248843d..6ed0bd2cf 100755
--- a/src/conf_mode/interfaces_input.py
+++ b/src/conf_mode/interfaces_input.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_l2tpv3.py b/src/conf_mode/interfaces_l2tpv3.py
index f0a70436e..8eca1cedc 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_loopback.py b/src/conf_mode/interfaces_loopback.py
index a784e9ec2..bac36b7f0 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_macsec.py b/src/conf_mode/interfaces_macsec.py
index 3ede4377a..683e12ec3 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_openvpn.py b/src/conf_mode/interfaces_openvpn.py
index a9b4e570d..5cc09da89 100755
--- a/src/conf_mode/interfaces_openvpn.py
+++ b/src/conf_mode/interfaces_openvpn.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_pppoe.py b/src/conf_mode/interfaces_pppoe.py
index 412676c7d..976702aba 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_pseudo-ethernet.py b/src/conf_mode/interfaces_pseudo-ethernet.py
index 446beffd3..6edd3f248 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -27,6 +27,7 @@ from vyos.configverify import verify_bridge_delete
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_mtu_ipv6
from vyos.configverify import verify_mirror_redirect
from vyos.ifconfig import MACVLANIf
from vyos.utils.network import interface_exists
@@ -71,6 +72,7 @@ def verify(peth):
verify_vrf(peth)
verify_address(peth)
verify_mtu_parent(peth, peth['parent'])
+ verify_mtu_ipv6(peth)
verify_mirror_redirect(peth)
# use common function to verify VLAN configuration
verify_vlan_config(peth)
diff --git a/src/conf_mode/interfaces_sstpc.py b/src/conf_mode/interfaces_sstpc.py
index b9d7a74fb..276fab4f9 100755
--- a/src/conf_mode/interfaces_sstpc.py
+++ b/src/conf_mode/interfaces_sstpc.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_tunnel.py b/src/conf_mode/interfaces_tunnel.py
index ee1436e49..4cf5ef115 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-2025 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_virtual-ethernet.py b/src/conf_mode/interfaces_virtual-ethernet.py
index cb6104f59..f85c3d1de 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,6 +23,7 @@ from vyos.configdict import get_interface_dict
from vyos.configverify import verify_address
from vyos.configverify import verify_bridge_delete
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_mtu_ipv6
from vyos.ifconfig import VethIf
from vyos.utils.network import interface_exists
airbag.enable()
@@ -62,6 +63,7 @@ def verify(veth):
return None
verify_vrf(veth)
+ verify_mtu_ipv6(veth)
verify_address(veth)
if 'peer_name' not in veth:
diff --git a/src/conf_mode/interfaces_vti.py b/src/conf_mode/interfaces_vti.py
index 20629c6c1..0461c4f68 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,6 +20,7 @@ from vyos.config import Config
from vyos.configdict import get_interface_dict
from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_mtu_ipv6
from vyos.ifconfig import VTIIf
from vyos import ConfigError
from vyos import airbag
@@ -40,6 +41,7 @@ def get_config(config=None):
def verify(vti):
verify_vrf(vti)
+ verify_mtu_ipv6(vti)
verify_mirror_redirect(vti)
return None
diff --git a/src/conf_mode/interfaces_vxlan.py b/src/conf_mode/interfaces_vxlan.py
index 256b65708..34eb3ef5c 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_wireguard.py b/src/conf_mode/interfaces_wireguard.py
index 192937dba..33d782ec6 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,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
+
+from glob import glob
from sys import exit
from vyos.config import Config
@@ -35,7 +38,6 @@ from vyos.utils.network import is_wireguard_key_pair
from vyos.utils.process import call
from vyos import ConfigError
from vyos import airbag
-from pathlib import Path
airbag.enable()
@@ -97,7 +99,7 @@ def verify(wireguard):
if 'port' in wireguard and 'port_changed' in wireguard:
listen_port = int(wireguard['port'])
- if check_port_availability('0.0.0.0', listen_port, 'udp') is not True:
+ if check_port_availability(None, listen_port, protocol='udp') is not True:
raise ConfigError(f'UDP port {listen_port} is busy or unavailable and '
'cannot be used for the interface!')
@@ -145,19 +147,11 @@ def generate(wireguard):
def apply(wireguard):
check_kmod('wireguard')
- if 'rebuild_required' in wireguard or 'deleted' in wireguard:
- wg = WireGuardIf(**wireguard)
- # WireGuard only supports peer removal based on the configured public-key,
- # by deleting the entire interface this is the shortcut instead of parsing
- # out all peers and removing them one by one.
- #
- # Peer reconfiguration will always come with a short downtime while the
- # WireGuard interface is recreated (see below)
- wg.remove()
+ wg = WireGuardIf(**wireguard)
- # Create the new interface if required
- if 'deleted' not in wireguard:
- wg = WireGuardIf(**wireguard)
+ if 'deleted' in wireguard:
+ wg.remove()
+ else:
wg.update(wireguard)
domain_resolver_usage = '/run/use-vyos-domain-resolver-interfaces-wireguard-' + wireguard['ifname']
@@ -168,12 +162,12 @@ def apply(wireguard):
from vyos.utils.file import write_file
text = f'# Automatically generated by interfaces_wireguard.py\nThis file indicates that vyos-domain-resolver service is used by the interfaces_wireguard.\n'
- text += "intefaces:\n" + "".join([f" - {peer}\n" for peer in wireguard['peers_need_resolve']])
- Path(domain_resolver_usage).write_text(text)
+ text += "interfaces:\n" + "".join([f" - {peer}\n" for peer in wireguard['peers_need_resolve']])
write_file(domain_resolver_usage, text)
else:
- Path(domain_resolver_usage).unlink(missing_ok=True)
- if not Path('/run').glob('use-vyos-domain-resolver*'):
+ if os.path.exists(domain_resolver_usage):
+ os.unlink(domain_resolver_usage)
+ if not glob('/run/use-vyos-domain-resolver*'):
domain_action = 'stop'
call(f'systemctl {domain_action} vyos-domain-resolver.service')
diff --git a/src/conf_mode/interfaces_wireless.py b/src/conf_mode/interfaces_wireless.py
index d24675ee6..b3b909046 100755
--- a/src/conf_mode/interfaces_wireless.py
+++ b/src/conf_mode/interfaces_wireless.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/interfaces_wwan.py b/src/conf_mode/interfaces_wwan.py
index 230eb14d6..ddddbe5e8 100755
--- a/src/conf_mode/interfaces_wwan.py
+++ b/src/conf_mode/interfaces_wwan.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2022 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,8 +26,10 @@ from vyos.configverify import verify_authentication
from vyos.configverify import verify_interface_exists
from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_vrf
+from vyos.configverify import verify_mtu_ipv6
from vyos.ifconfig import WWANIf
from vyos.utils.dict import dict_search
+from vyos.utils.network import is_wwan_connected
from vyos.utils.process import cmd
from vyos.utils.process import call
from vyos.utils.process import DEVNULL
@@ -98,6 +100,7 @@ def verify(wwan):
verify_interface_exists(wwan, ifname)
verify_authentication(wwan)
verify_vrf(wwan)
+ verify_mtu_ipv6(wwan)
verify_mirror_redirect(wwan)
return None
@@ -135,7 +138,7 @@ def apply(wwan):
break
sleep(0.250)
- if 'shutdown_required' in wwan:
+ if 'shutdown_required' in wwan or (not is_wwan_connected(wwan['ifname'])):
# we only need the modem number. wwan0 -> 0, wwan1 -> 1
modem = wwan['ifname'].lstrip('wwan')
base_cmd = f'mmcli --modem {modem}'
@@ -157,7 +160,7 @@ def apply(wwan):
return None
- if 'shutdown_required' in wwan:
+ if 'shutdown_required' in wwan or (not is_wwan_connected(wwan['ifname'])):
ip_type = 'ipv4'
slaac = dict_search('ipv6.address.autoconf', wwan) != None
if 'address' in wwan:
diff --git a/src/conf_mode/load-balancing_haproxy.py b/src/conf_mode/load-balancing_haproxy.py
index 5fd1beec9..4c26ed0b4 100644
--- a/src/conf_mode/load-balancing_haproxy.py
+++ b/src/conf_mode/load-balancing_haproxy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,7 @@ import os
from sys import exit
from shutil import rmtree
+from vyos.defaults import systemd_services
from vyos.config import Config
from vyos.configverify import verify_pki_certificate
from vyos.configverify import verify_pki_ca_certificate
@@ -39,7 +40,6 @@ airbag.enable()
load_balancing_dir = '/run/haproxy'
load_balancing_conf_file = f'{load_balancing_dir}/haproxy.cfg'
-systemd_service = 'haproxy.service'
systemd_override = '/run/systemd/system/haproxy.service.d/10-override.conf'
def get_config(config=None):
@@ -65,18 +65,18 @@ def verify(lb):
return None
if 'backend' not in lb or 'service' not in lb:
- raise ConfigError(f'"service" and "backend" must be configured!')
+ raise ConfigError('Both "service" and "backend" must be configured!')
for front, front_config in lb['service'].items():
if 'port' not in front_config:
raise ConfigError(f'"{front} service port" must be configured!')
# Check if bind address:port are used by another service
- tmp_address = front_config.get('address', '0.0.0.0')
+ tmp_address = front_config.get('address', None)
tmp_port = front_config['port']
if check_port_availability(tmp_address, int(tmp_port), 'tcp') is not True and \
not is_listen_port_bind_service(int(tmp_port), 'haproxy'):
- raise ConfigError(f'"TCP" port "{tmp_port}" is used by another service')
+ raise ConfigError(f'TCP port "{tmp_port}" is used by another service')
if 'http_compression' in front_config:
if front_config['mode'] != 'http':
@@ -85,16 +85,19 @@ def verify(lb):
raise ConfigError(f'service {front} must have at least one mime-type configured to use'
f'http_compression!')
+ for cert in dict_search('ssl.certificate', front_config) or []:
+ verify_pki_certificate(lb, cert)
+
for back, back_config in lb['backend'].items():
if 'http_check' in back_config:
http_check = back_config['http_check']
if 'expect' in http_check and 'status' in http_check['expect'] and 'string' in http_check['expect']:
- raise ConfigError(f'"expect status" and "expect string" can not be configured together!')
+ raise ConfigError('"expect status" and "expect string" can not be configured together!')
if 'health_check' in back_config:
if back_config['mode'] != 'tcp':
raise ConfigError(f'backend "{back}" can only be configured with {back_config["health_check"]} ' +
- f'health-check whilst in TCP mode!')
+ 'health-check whilst in TCP mode!')
if 'http_check' in back_config:
raise ConfigError(f'backend "{back}" cannot be configured with both http-check and health-check!')
@@ -112,20 +115,15 @@ def verify(lb):
if {'no_verify', 'ca_certificate'} <= set(back_config['ssl']):
raise ConfigError(f'backend {back} cannot have both ssl options no-verify and ca-certificate set!')
+ tmp = dict_search('ssl.ca_certificate', back_config)
+ if tmp: verify_pki_ca_certificate(lb, tmp)
+
# Check if http-response-headers are configured in any frontend/backend where mode != http
for group in ['service', 'backend']:
for config_name, config in lb[group].items():
if 'http_response_headers' in config and config['mode'] != 'http':
raise ConfigError(f'{group} {config_name} must be set to http mode to use http_response_headers!')
- 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', back_config)
- if tmp: verify_pki_ca_certificate(lb, tmp)
-
def generate(lb):
if not lb:
@@ -193,12 +191,11 @@ def generate(lb):
return None
def apply(lb):
+ action = 'stop'
+ if lb:
+ action = 'reload-or-restart'
call('systemctl daemon-reload')
- if not lb:
- call(f'systemctl stop {systemd_service}')
- else:
- call(f'systemctl reload-or-restart {systemd_service}')
-
+ call(f'systemctl {action} {systemd_services["haproxy"]}')
return None
diff --git a/src/conf_mode/load-balancing_wan.py b/src/conf_mode/load-balancing_wan.py
index 92d9acfba..dc7f1c838 100755
--- a/src/conf_mode/load-balancing_wan.py
+++ b/src/conf_mode/load-balancing_wan.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023-2025 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py
index 504b3e82a..8763da886 100755
--- a/src/conf_mode/nat.py
+++ b/src/conf_mode/nat.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,14 +16,13 @@
import os
+from glob import glob
from sys import exit
-from pathlib import Path
from vyos.base import Warning
from vyos.config import Config
from vyos.configdep import set_dependents, call_dependents
from vyos.template import render
-from vyos.template import is_ip_network
from vyos.utils.kernel import check_kmod
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_search_args
@@ -31,7 +30,6 @@ from vyos.utils.file import write_file
from vyos.utils.process import cmd
from vyos.utils.process import run
from vyos.utils.process import call
-from vyos.utils.network import is_addr_assigned
from vyos.utils.network import interface_exists
from vyos.firewall import fqdn_config_parse
from vyos import ConfigError
@@ -176,12 +174,6 @@ def verify(nat):
if 'exclude' not in config and 'backend' not in config['load_balance']:
raise ConfigError(f'{err_msg} translation requires address and/or port')
- addr = dict_search('translation.address', config)
- if addr != None and addr != 'masquerade' and not is_ip_network(addr):
- for ip in addr.split('-'):
- if not is_addr_assigned(ip):
- Warning(f'IP address {ip} does not exist on the system!')
-
# common rule verification
verify_rule(config, err_msg, nat['firewall_group'])
@@ -265,9 +257,9 @@ def apply(nat):
text = f'# Automatically generated by nat.py\nThis file indicates that vyos-domain-resolver service is used by nat.\n'
write_file(domain_resolver_usage, text)
elif os.path.exists(domain_resolver_usage):
- Path(domain_resolver_usage).unlink(missing_ok=True)
+ os.unlink(domain_resolver_usage)
- if not Path('/run').glob('use-vyos-domain-resolver*'):
+ if not glob('/run/use-vyos-domain-resolver*'):
domain_action = 'stop'
call(f'systemctl {domain_action} vyos-domain-resolver.service')
diff --git a/src/conf_mode/nat64.py b/src/conf_mode/nat64.py
index df501ce7f..4f8853661 100755
--- a/src/conf_mode/nat64.py
+++ b/src/conf_mode/nat64.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py
index 95dfae3a5..aea187d18 100755
--- a/src/conf_mode/nat66.py
+++ b/src/conf_mode/nat66.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -92,6 +92,10 @@ def verify(nat):
if prefix != None:
if not is_ipv6(prefix):
raise ConfigError(f'{err_msg} source-prefix not specified')
+
+ if 'destination' in config and 'group' in config['destination']:
+ if len({'address_group', 'network_group', 'domain_group'} & set(config['destination']['group'])) > 1:
+ raise ConfigError('Only one address-group, network-group or domain-group can be specified')
if dict_search('destination.rule', nat):
for rule, config in dict_search('destination.rule', nat).items():
diff --git a/src/conf_mode/nat_cgnat.py b/src/conf_mode/nat_cgnat.py
index 3484e5873..312688b53 100755
--- a/src/conf_mode/nat_cgnat.py
+++ b/src/conf_mode/nat_cgnat.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/netns.py b/src/conf_mode/netns.py
index b57e46a0d..5a3c4e7fa 100755
--- a/src/conf_mode/netns.py
+++ b/src/conf_mode/netns.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/pki.py b/src/conf_mode/pki.py
index 724f97555..fa6958130 100755
--- a/src/conf_mode/pki.py
+++ b/src/conf_mode/pki.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,7 @@ import os
from sys import argv
from sys import exit
+from vyos.base import Message
from vyos.config import Config
from vyos.config import config_dict_merge
from vyos.configdep import set_dependents
@@ -27,6 +28,8 @@ from vyos.configdict import node_changed
from vyos.configdiff import Diff
from vyos.configdiff import get_config_diff
from vyos.defaults import directories
+from vyos.defaults import internal_ports
+from vyos.defaults import systemd_services
from vyos.pki import encode_certificate
from vyos.pki import is_ca_certificate
from vyos.pki import load_certificate
@@ -42,9 +45,11 @@ 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.file import read_file
+from vyos.utils.network import check_port_availability
from vyos.utils.process import call
from vyos.utils.process import cmd
from vyos.utils.process import is_systemd_service_active
+from vyos.utils.process import is_systemd_service_running
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -59,6 +64,10 @@ sync_search = [
'path': ['service', 'https'],
},
{
+ 'keys': ['key'],
+ 'path': ['service', 'ssh'],
+ },
+ {
'keys': ['certificate', 'ca_certificate'],
'path': ['interfaces', 'ethernet'],
},
@@ -128,8 +137,20 @@ def certbot_request(name: str, config: dict, dry_run: bool=True):
f'--standalone --agree-tos --no-eff-email --expand --server {config["url"]} '\
f'--email {config["email"]} --key-type rsa --rsa-key-size {config["rsa_key_size"]} '\
f'{domains}'
+
+ listen_address = None
if 'listen_address' in config:
- tmp += f' --http-01-address {config["listen_address"]}'
+ listen_address = config['listen_address']
+
+ # When ACME is used behind a reverse proxy, we always bind to localhost
+ # whatever the CLI listen-address is configured for.
+ if ('used_by' in config and 'haproxy' in config['used_by'] and
+ is_systemd_service_running(systemd_services['haproxy']) and
+ not check_port_availability(listen_address, 80)):
+ tmp += f' --http-01-address 127.0.0.1 --http-01-port {internal_ports["certbot_haproxy"]}'
+ elif listen_address:
+ tmp += f' --http-01-address {listen_address}'
+
# verify() does not need to actually request a cert but only test for plausability
if dry_run:
tmp += ' --dry-run'
@@ -150,14 +171,18 @@ def get_config(config=None):
if len(argv) > 1 and argv[1] == 'certbot_renew':
pki['certbot_renew'] = {}
- changed_keys = ['ca', 'certificate', 'dh', 'key-pair', 'openssh', 'openvpn']
+ # Walk through the list of sync_translate mapping and build a list
+ # which is later used to check if the node was changed in the CLI config
+ changed_keys = []
+ for value in sync_translate.values():
+ if value not in changed_keys:
+ changed_keys.append(value)
+ # Check for changes to said given keys in the CLI config
for key in changed_keys:
tmp = node_changed(conf, base + [key], recursive=True, expand_nodes=Diff.DELETE | Diff.ADD)
-
if 'changed' not in pki:
pki.update({'changed':{}})
-
pki['changed'].update({key.replace('-', '_') : tmp})
# We only merge on the defaults of there is a configuration at all
@@ -219,8 +244,8 @@ def get_config(config=None):
continue
path = search['path']
- path_str = ' '.join(path + found_path)
- #print(f'PKI: Updating config: {path_str} {item_name}')
+ path_str = ' '.join(path + found_path).replace('_','-')
+ Message(f'Updating configuration: "{path_str} {item_name}"')
if path[0] == 'interfaces':
ifname = found_path[0]
@@ -230,6 +255,24 @@ def get_config(config=None):
if not D.node_changed_presence(path):
set_dependents(path[1], conf)
+ # Check PKI certificates if they are auto-generated by ACME. If they are,
+ # traverse the current configuration and determine the service where the
+ # certificate is used by.
+ # Required to check if we might need to run certbot behing a reverse proxy.
+ if 'certificate' in pki:
+ for name, cert_config in pki['certificate'].items():
+ if 'acme' not in cert_config:
+ continue
+ if not dict_search('system.load_balancing.haproxy', pki):
+ continue
+ used_by = []
+ for cert_list, _ in dict_search_recursive(
+ pki['system']['load_balancing']['haproxy'], 'certificate'):
+ if name in cert_list:
+ used_by.append('haproxy')
+ if used_by:
+ pki['certificate'][name]['acme'].update({'used_by': used_by})
+
return pki
def is_valid_certificate(raw_data):
@@ -321,6 +364,15 @@ def verify(pki):
raise ConfigError(f'An email address is required to request '\
f'certificate for "{name}" via ACME!')
+ listen_address = None
+ if 'listen_address' in cert_conf['acme']:
+ listen_address = cert_conf['acme']['listen_address']
+
+ if 'used_by' not in cert_conf['acme']:
+ if not check_port_availability(listen_address, 80):
+ raise ConfigError('Port 80 is already in use and not available '\
+ f'to provide ACME challenge for "{name}"!')
+
if 'certbot_renew' not in pki:
# Only run the ACME command if something on this entity changed,
# as this is time intensive
@@ -366,7 +418,8 @@ def verify(pki):
if 'country' in default_values:
country = default_values['country']
if len(country) != 2 or not country.isalpha():
- raise ConfigError(f'Invalid default country value. Value must be 2 alpha characters.')
+ raise ConfigError('Invalid default country value. '\
+ 'Value must be 2 alpha characters.')
if 'changed' in pki:
# if the list is getting longer, we can move to a dict() and also embed the
@@ -374,27 +427,35 @@ def verify(pki):
for search in sync_search:
for key in search['keys']:
changed_key = sync_translate[key]
-
if changed_key not in pki['changed']:
continue
-
for item_name in pki['changed'][changed_key]:
node_present = False
if changed_key == 'openvpn':
node_present = dict_search_args(pki, 'openvpn', 'shared_secret', item_name)
else:
node_present = dict_search_args(pki, changed_key, item_name)
+ # If the node is still present, we can skip the check
+ # as we are not deleting it
+ if node_present:
+ continue
- if not node_present:
- search_dict = dict_search_args(pki['system'], *search['path'])
-
- if not search_dict:
- continue
+ search_dict = dict_search_args(pki['system'], *search['path'])
+ if not search_dict:
+ continue
- for found_name, found_path in dict_search_recursive(search_dict, key):
- if found_name == item_name:
- path_str = " ".join(search['path'] + found_path)
- raise ConfigError(f'PKI object "{item_name}" still in use by "{path_str}"')
+ for found_name, found_path in dict_search_recursive(search_dict, key):
+ # Check if the name matches either by string compare, or beeing
+ # part of a list
+ if ((isinstance(found_name, str) and found_name == item_name) or
+ (isinstance(found_name, list) and item_name in found_name)):
+ # We do not support _ in CLI paths - this is only a convenience
+ # as we mangle all - to _, now it's time to reverse this!
+ path_str = ' '.join(search['path'] + found_path).replace('_','-')
+ object = changed_key.replace('_','-')
+ tmp = f'Embedded PKI {object} with name "{item_name}" is still '\
+ f'in use by CLI path "{path_str}"'
+ raise ConfigError(tmp)
return None
@@ -490,7 +551,7 @@ def generate(pki):
if not ca_cert_present:
tmp = dict_search_args(pki, 'ca', f'{autochain_prefix}{cert}', 'certificate')
if not bool(tmp) or tmp != cert_chain_base64:
- print(f'Adding/replacing automatically imported CA certificate for "{cert}" ...')
+ Message(f'Add/replace automatically imported CA certificate for "{cert}" ...')
add_cli_node(['pki', 'ca', f'{autochain_prefix}{cert}', 'certificate'], value=cert_chain_base64)
return None
diff --git a/src/conf_mode/policy.py b/src/conf_mode/policy.py
index a90e33e81..84962c807 100755
--- a/src/conf_mode/policy.py
+++ b/src/conf_mode/policy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,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 re
from sys import exit
from vyos.config import Config
@@ -24,9 +25,20 @@ from vyos.frrender import get_frrender_dict
from vyos.utils.dict import dict_search
from vyos.utils.process import is_systemd_service_running
from vyos import ConfigError
+from vyos.base import Warning
from vyos import airbag
airbag.enable()
+# Sanity checks for large-community-list regex:
+# * Require complete 3-tuples, no blank members. Catch missed & doubled colons.
+# * Permit appropriate community separators (whitespace, underscore)
+# * Permit common regex between tuples while requiring at least one separator
+# (eg, "1:1:1_.*_4:4:4", matching "1:1:1 4:4:4" and "1:1:1 2:2:2 4:4:4",
+# but not "1:1:13 24:4:4")
+# Best practice: stick with basic patterns, mind your wildcards and whitespace.
+# Regex that doesn't match this pattern will be allowed with a warning.
+large_community_regex_pattern = r'([^: _]+):([^: _]+):([^: _]+)([ _]([^:]+):([^: _]+):([^: _]+))*'
+
def community_action_compatibility(actions: dict) -> bool:
"""
Check compatibility of values in community and large community sections
@@ -147,6 +159,10 @@ def verify(config_dict):
if 'regex' not in rule_config:
raise ConfigError(f'A regex {mandatory_error}')
+ if policy_type == 'large_community_list':
+ if not re.fullmatch(large_community_regex_pattern, rule_config['regex']):
+ Warning(f'"policy large-community-list {instance} rule {rule} regex" does not follow expected form and may not match as expected.')
+
if policy_type in ['prefix_list', 'prefix_list6']:
if 'prefix' not in rule_config:
raise ConfigError(f'A prefix {mandatory_error}')
diff --git a/src/conf_mode/policy_local-route.py b/src/conf_mode/policy_local-route.py
index 9be2bc227..77b39e59f 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/policy_route.py b/src/conf_mode/policy_route.py
index 223175b8a..15d735f75 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,13 +21,16 @@ from sys import exit
from vyos.base import Warning
from vyos.config import Config
+from vyos.configdiff import get_config_diff, Diff
from vyos.template import render
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 run
from vyos.utils.network import get_vrf_tableid
from vyos.defaults import rt_global_table
from vyos.defaults import rt_global_vrf
+from vyos.firewall import geoip_update
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -43,6 +46,43 @@ valid_groups = [
'interface_group'
]
+def geoip_updated(conf, policy):
+ diff = get_config_diff(conf)
+ node_diff = diff.get_child_nodes_diff(['policy'], expand_nodes=Diff.DELETE, recursive=True)
+
+ out = {
+ 'name': [],
+ 'ipv6_name': [],
+ 'deleted_name': [],
+ 'deleted_ipv6_name': []
+ }
+ updated = False
+
+ for key, path in dict_search_recursive(policy, 'geoip'):
+ set_name = f'GEOIP_CC_{path[0]}_{path[1]}_{path[3]}'
+ if (path[0] == 'route'):
+ out['name'].append(set_name)
+ elif (path[0] == 'route6'):
+ set_name = f'GEOIP_CC6_{path[0]}_{path[1]}_{path[3]}'
+ out['ipv6_name'].append(set_name)
+
+ updated = True
+
+ if 'delete' in node_diff:
+ for key, path in dict_search_recursive(node_diff['delete'], 'geoip'):
+ set_name = f'GEOIP_CC_{path[0]}_{path[1]}_{path[3]}'
+ if (path[0] == 'route'):
+ out['deleted_name'].append(set_name)
+ elif (path[0] == 'route6'):
+ set_name = f'GEOIP_CC6_{path[0]}_{path[1]}_{path[3]}'
+ out['deleted_ipv6_name'].append(set_name)
+ updated = True
+
+ if updated:
+ return out
+
+ return False
+
def get_config(config=None):
if config:
conf = config
@@ -60,6 +100,7 @@ def get_config(config=None):
if 'dynamic_group' in policy['firewall_group']:
del policy['firewall_group']['dynamic_group']
+ policy['geoip_updated'] = geoip_updated(conf, policy)
return policy
def verify_rule(policy, name, rule_conf, ipv6, rule_id):
@@ -203,6 +244,12 @@ def apply(policy):
apply_table_marks(policy)
+ if policy['geoip_updated']:
+ # Call helper script to Update set contents
+ if 'name' in policy['geoip_updated'] or 'ipv6_name' in policy['geoip_updated']:
+ print('Updating GeoIP. Please wait...')
+ geoip_update(policy=policy)
+
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/protocols_babel.py b/src/conf_mode/protocols_babel.py
index 80a847af8..a683031bd 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py
index d3bc3e961..953611f24 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py
index 53e83c3b4..bc7925d28 100755
--- a/src/conf_mode/protocols_bgp.py
+++ b/src/conf_mode/protocols_bgp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -413,15 +413,19 @@ def verify(config_dict):
verify_route_map(afi_config['route_map'][tmp], bgp)
if 'route_reflector_client' in afi_config:
- peer_group_as = peer_config.get('remote_as')
+ peer_as = peer_config.get('remote_as')
- if peer_group_as is None or (peer_group_as != 'internal' and peer_group_as != bgp['system_as']):
+ if peer_as is not None and (peer_as != 'internal' and peer_as != bgp['system_as']):
raise ConfigError('route-reflector-client only supported for iBGP peers')
else:
+ # Check into the peer group for the remote as, if we are in a peer group, check in peer itself
if 'peer_group' in peer_config:
peer_group_as = dict_search(f'peer_group.{peer_group}.remote_as', bgp)
- 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')
+ elif neighbor == 'peer_group':
+ 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')
# T5833 not all AFIs are supported for VRF
if 'vrf' in bgp and 'address_family' in peer_config:
@@ -523,11 +527,15 @@ def verify(config_dict):
raise ConfigError(
'Please unconfigure import vrf commands before using vpn commands in dependent VRFs!')
+ # Verify if the route-map exists
+ if dict_search('route_map.vrf.import', afi_config) is not None:
+ verify_route_map(afi_config['route_map']['vrf']['import'], bgp)
+
if (dict_search('route_map.vrf.import', afi_config) is not None
or dict_search('import.vrf', afi_config) is not None):
# FRR error: please unconfigure vpn to vrf commands before
# using import vrf commands
- if ('vpn' in afi_config['import']
+ if (dict_search('import.vpn', afi_config) is not None
or dict_search('export.vpn', afi_config) is not None):
raise ConfigError('Please unconfigure VPN to VRF commands before '\
'using "import vrf" commands!')
@@ -537,7 +545,6 @@ def verify(config_dict):
raise ConfigError('Please unconfigure route-map VPN to VRF commands before '\
'using "import vrf" commands!')
-
# Verify that the export/import route-maps do exist
for export_import in ['export', 'import']:
tmp = dict_search(f'route_map.vpn.{export_import}', afi_config)
diff --git a/src/conf_mode/protocols_eigrp.py b/src/conf_mode/protocols_eigrp.py
index 324ff883f..e127a3a07 100755
--- a/src/conf_mode/protocols_eigrp.py
+++ b/src/conf_mode/protocols_eigrp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_failover.py b/src/conf_mode/protocols_failover.py
index e7e44db84..9b50cc1ed 100755
--- a/src/conf_mode/protocols_failover.py
+++ b/src/conf_mode/protocols_failover.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_igmp-proxy.py b/src/conf_mode/protocols_igmp-proxy.py
index 9a07adf05..c2d2fea5b 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py
index 1c994492e..8b1408f57 100755
--- a/src/conf_mode/protocols_isis.py
+++ b/src/conf_mode/protocols_isis.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_mpls.py b/src/conf_mode/protocols_mpls.py
index 33d9a6dae..d534ad2e3 100755
--- a/src/conf_mode/protocols_mpls.py
+++ b/src/conf_mode/protocols_mpls.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_nhrp.py b/src/conf_mode/protocols_nhrp.py
index ac92c9d99..be08080b1 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-2025 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_openfabric.py b/src/conf_mode/protocols_openfabric.py
index 7df11fb20..f490d28bf 100644
--- a/src/conf_mode/protocols_openfabric.py
+++ b/src/conf_mode/protocols_openfabric.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py
index c06c0aafc..9421765a1 100755
--- a/src/conf_mode/protocols_ospf.py
+++ b/src/conf_mode/protocols_ospf.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -17,6 +17,7 @@
from sys import exit
from sys import argv
+from vyos.base import Warning
from vyos.config import Config
from vyos.configverify import verify_common_route_maps
from vyos.configverify import verify_route_map
@@ -62,6 +63,16 @@ def verify(config_dict):
if 'area' in ospf:
networks = []
for area, area_config in ospf['area'].items():
+ # Implemented as warning to not break existing configurations
+ if area == '0' and dict_search('area_type.nssa', area_config) != None:
+ Warning('You cannot configure NSSA to backbone!')
+ # Implemented as warning to not break existing configurations
+ if area == '0' and dict_search('area_type.stub', area_config) != None:
+ Warning('You cannot configure STUB to backbone!')
+ # Implemented as warning to not break existing configurations
+ if len(area_config['area_type']) > 1:
+ Warning(f'Only one area-type is supported for area "{area}"!')
+
if 'import_list' in area_config:
acl_import = area_config['import_list']
if acl_import: verify_access_list(acl_import, ospf)
diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py
index 2563eb7d5..1d2eceb8f 100755
--- a/src/conf_mode/protocols_ospfv3.py
+++ b/src/conf_mode/protocols_ospfv3.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_pim.py b/src/conf_mode/protocols_pim.py
index 632099964..bb55aada0 100755
--- a/src/conf_mode/protocols_pim.py
+++ b/src/conf_mode/protocols_pim.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_pim6.py b/src/conf_mode/protocols_pim6.py
index 03a79139a..f7803246a 100755
--- a/src/conf_mode/protocols_pim6.py
+++ b/src/conf_mode/protocols_pim6.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_rip.py b/src/conf_mode/protocols_rip.py
index ec9dfbb8b..c6adcde5b 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_ripng.py b/src/conf_mode/protocols_ripng.py
index 9a9ac8ec8..e5babf2e8 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_rpki.py b/src/conf_mode/protocols_rpki.py
index ef0250e3d..5ba23c141 100755
--- a/src/conf_mode/protocols_rpki.py
+++ b/src/conf_mode/protocols_rpki.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,6 +18,7 @@ import os
from glob import glob
from sys import exit
+from sys import argv
from vyos.config import Config
from vyos.configverify import has_frr_protocol_in_dict
@@ -39,13 +40,18 @@ def get_config(config=None):
conf = config
else:
conf = Config()
- return get_frrender_dict(conf)
+ return get_frrender_dict(conf, argv)
def verify(config_dict):
if not has_frr_protocol_in_dict(config_dict, 'rpki'):
return None
- rpki = config_dict['rpki']
+ vrf = None
+ if 'vrf_context' in config_dict:
+ vrf = config_dict['vrf_context']
+
+ # eqivalent of the C foo ? 'a' : 'b' statement
+ rpki = vrf and config_dict['vrf']['name'][vrf]['protocols']['rpki'] or config_dict['rpki']
if 'cache' in rpki:
preferences = []
@@ -79,7 +85,12 @@ def generate(config_dict):
if not has_frr_protocol_in_dict(config_dict, 'rpki'):
return None
- rpki = config_dict['rpki']
+ vrf = None
+ if 'vrf_context' in config_dict:
+ vrf = config_dict['vrf_context']
+
+ # eqivalent of the C foo ? 'a' : 'b' statement
+ rpki = vrf and config_dict['vrf']['name'][vrf]['protocols']['rpki'] or config_dict['rpki']
if 'cache' in rpki:
for cache, cache_config in rpki['cache'].items():
diff --git a/src/conf_mode/protocols_segment-routing.py b/src/conf_mode/protocols_segment-routing.py
index f2bd42a79..4020a0917 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_static.py b/src/conf_mode/protocols_static.py
index 1b9e51167..7c730ca81 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_static_arp.py b/src/conf_mode/protocols_static_arp.py
index b141f1141..87dc5229e 100755
--- a/src/conf_mode/protocols_static_arp.py
+++ b/src/conf_mode/protocols_static_arp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2022 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/protocols_static_neighbor-proxy.py b/src/conf_mode/protocols_static_neighbor-proxy.py
index 8a1ea1df9..bda737e75 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/qos.py b/src/conf_mode/qos.py
index 59e307a39..326d617a2 100755
--- a/src/conf_mode/qos.py
+++ b/src/conf_mode/qos.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -85,7 +85,13 @@ def _clean_conf_dict(conf):
}
"""
if isinstance(conf, dict):
- return {node: _clean_conf_dict(val) for node, val in conf.items() if val != {} and _clean_conf_dict(val) != {}}
+ preserve_empty_nodes = {'syn', 'ack'}
+
+ return {
+ node: _clean_conf_dict(val)
+ for node, val in conf.items()
+ if (val != {} and _clean_conf_dict(val) != {}) or node in preserve_empty_nodes
+ }
else:
return conf
diff --git a/src/conf_mode/service_aws_glb.py b/src/conf_mode/service_aws_glb.py
index d1ed5a07b..aa5ec5ebe 100755
--- a/src/conf_mode/service_aws_glb.py
+++ b/src/conf_mode/service_aws_glb.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_broadcast-relay.py b/src/conf_mode/service_broadcast-relay.py
index d35954718..f7f2875f5 100755
--- a/src/conf_mode/service_broadcast-relay.py
+++ b/src/conf_mode/service_broadcast-relay.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2017-2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_config-sync.py b/src/conf_mode/service_config-sync.py
index 4b8a7f6ee..32001ce57 100755
--- a/src/conf_mode/service_config-sync.py
+++ b/src/conf_mode/service_config-sync.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_conntrack-sync.py b/src/conf_mode/service_conntrack-sync.py
index 3a233a172..5eb4ca0e5 100755
--- a/src/conf_mode/service_conntrack-sync.py
+++ b/src/conf_mode/service_conntrack-sync.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_console-server.py b/src/conf_mode/service_console-server.py
index b83c6dfb1..82386babf 100755
--- a/src/conf_mode/service_console-server.py
+++ b/src/conf_mode/service_console-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2025 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_dhcp-relay.py b/src/conf_mode/service_dhcp-relay.py
index 37d708847..ebdf5e8ee 100755
--- a/src/conf_mode/service_dhcp-relay.py
+++ b/src/conf_mode/service_dhcp-relay.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2020 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_dhcp-server.py b/src/conf_mode/service_dhcp-server.py
index 5a729af74..6bbe72e90 100755
--- a/src/conf_mode/service_dhcp-server.py
+++ b/src/conf_mode/service_dhcp-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2025 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -41,9 +41,9 @@ from vyos import airbag
airbag.enable()
-ctrl_config_file = '/run/kea/kea-ctrl-agent.conf'
ctrl_socket = '/run/kea/dhcp4-ctrl-socket'
config_file = '/run/kea/kea-dhcp4.conf'
+config_file_d2 = '/run/kea/kea-dhcp-ddns.conf'
lease_file = '/config/dhcp/dhcp4-leases.csv'
lease_file_glob = '/config/dhcp/dhcp4-leases*'
user_group = '_kea'
@@ -171,6 +171,15 @@ def get_config(config=None):
return dhcp
+def verify_ddns_domain_servers(domain_type, domain):
+ if 'dns_server' in domain:
+ invalid_servers = []
+ for server_no, server_config in domain['dns_server'].items():
+ if 'address' not in server_config:
+ invalid_servers.append(server_no)
+ if len(invalid_servers) > 0:
+ raise ConfigError(f'{domain_type} DNS servers {", ".join(invalid_servers)} in DDNS configuration need to have an IP address')
+ return None
def verify(dhcp):
# bail out early - looks like removal from running config
@@ -423,6 +432,22 @@ def verify(dhcp):
if not interface_exists(interface):
raise ConfigError(f'listen-interface "{interface}" does not exist')
+ if 'dynamic_dns_update' in dhcp:
+ ddns = dhcp['dynamic_dns_update']
+ if 'tsig_key' in ddns:
+ invalid_keys = []
+ for tsig_key_name, tsig_key_config in ddns['tsig_key'].items():
+ if not ('algorithm' in tsig_key_config and 'secret' in tsig_key_config):
+ invalid_keys.append(tsig_key_name)
+ if len(invalid_keys) > 0:
+ raise ConfigError(f'Both algorithm and secret need to be set for TSIG keys: {", ".join(invalid_keys)}')
+
+ if 'forward_domain' in ddns:
+ verify_ddns_domain_servers('Forward', ddns['forward_domain'])
+
+ if 'reverse_domain' in ddns:
+ verify_ddns_domain_servers('Reverse', ddns['reverse_domain'])
+
return None
@@ -480,25 +505,26 @@ def generate(dhcp):
dhcp['high_availability']['ca_cert_file'] = ca_cert_file
render(
- ctrl_config_file,
- 'dhcp-server/kea-ctrl-agent.conf.j2',
- dhcp,
- user=user_group,
- group=user_group,
- )
- render(
config_file,
'dhcp-server/kea-dhcp4.conf.j2',
dhcp,
user=user_group,
group=user_group,
)
+ if 'dynamic_dns_update' in dhcp:
+ render(
+ config_file_d2,
+ 'dhcp-server/kea-dhcp-ddns.conf.j2',
+ dhcp,
+ user=user_group,
+ group=user_group
+ )
return None
def apply(dhcp):
- services = ['kea-ctrl-agent', 'kea-dhcp4-server', 'kea-dhcp-ddns-server']
+ services = ['kea-dhcp4-server', 'kea-dhcp-ddns-server']
if not dhcp or 'disable' in dhcp:
for service in services:
@@ -515,9 +541,6 @@ def apply(dhcp):
if service == 'kea-dhcp-ddns-server' and 'dynamic_dns_update' not in dhcp:
action = 'stop'
- if service == 'kea-ctrl-agent' and 'high_availability' not in dhcp:
- action = 'stop'
-
call(f'systemctl {action} {service}.service')
return None
diff --git a/src/conf_mode/service_dhcpv6-relay.py b/src/conf_mode/service_dhcpv6-relay.py
index 6537ca3c2..4547b608c 100755
--- a/src/conf_mode/service_dhcpv6-relay.py
+++ b/src/conf_mode/service_dhcpv6-relay.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2020 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_dhcpv6-server.py b/src/conf_mode/service_dhcpv6-server.py
index 7af88007c..07dd08337 100755
--- a/src/conf_mode/service_dhcpv6-server.py
+++ b/src/conf_mode/service_dhcpv6-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_dns_dynamic.py b/src/conf_mode/service_dns_dynamic.py
index 5f5303856..b321d5f51 100755
--- a/src/conf_mode/service_dns_dynamic.py
+++ b/src/conf_mode/service_dns_dynamic.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_dns_forwarding.py b/src/conf_mode/service_dns_forwarding.py
index e3bdbc9f8..cd0c6a38a 100755
--- a/src/conf_mode/service_dns_forwarding.py
+++ b/src/conf_mode/service_dns_forwarding.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -366,6 +366,13 @@ def apply(dns):
hc.add_name_server_tags_recursor(['dhcp-' + interface,
'dhcpv6-' + interface ])
+ # add dhcp interfaces
+ if 'dhcp' in dns:
+ for interface in dns['dhcp']:
+ if interface_exists(interface):
+ hc.add_name_server_tags_recursor(['dhcp-' + interface,
+ 'dhcpv6-' + interface ])
+
# hostsd will generate the forward-zones file
# the list and keys() are required as get returns a dict, not list
hc.delete_forward_zones(list(hc.get_forward_zones().keys()))
diff --git a/src/conf_mode/service_event-handler.py b/src/conf_mode/service_event-handler.py
index 5028ef52f..1b9e7ff53 100755
--- a/src/conf_mode/service_event-handler.py
+++ b/src/conf_mode/service_event-handler.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_https.py b/src/conf_mode/service_https.py
index 9e58b4c72..38bb485e7 100755
--- a/src/conf_mode/service_https.py
+++ b/src/conf_mode/service_https.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -28,6 +28,7 @@ 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.configdiff import get_config_diff
from vyos.defaults import api_config_state
from vyos.pki import wrap_certificate
from vyos.pki import wrap_private_key
@@ -79,6 +80,14 @@ def get_config(config=None):
# merge CLI and default dictionary
https = config_dict_merge(default_values, https)
+
+ # some settings affecting nginx will require a restart:
+ # for example, a reload will not suffice when binding the listen address
+ # after nginx has started and dropped privileges; add flag here
+ diff = get_config_diff(conf)
+ children_changed = diff.node_changed_children(base)
+ https['nginx_restart_required'] = bool(set(children_changed) != set(['api']))
+
return https
def verify(https):
@@ -208,7 +217,10 @@ def apply(https):
elif is_systemd_service_active(http_api_service_name):
call(f'systemctl stop {http_api_service_name}')
- call(f'systemctl reload-or-restart {https_service_name}')
+ if https['nginx_restart_required']:
+ call(f'systemctl restart {https_service_name}')
+ else:
+ call(f'systemctl reload-or-restart {https_service_name}')
if __name__ == '__main__':
try:
diff --git a/src/conf_mode/service_ids_ddos-protection.py b/src/conf_mode/service_ids_ddos-protection.py
deleted file mode 100755
index 276a71fcb..000000000
--- a/src/conf_mode/service_ids_ddos-protection.py
+++ /dev/null
@@ -1,104 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2018-2023 VyOS maintainers and contributors
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License version 2 or later as
-# published by the Free Software Foundation.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see <http://www.gnu.org/licenses/>.
-
-import os
-
-from sys import exit
-
-from vyos.config import Config
-from vyos.template import render
-from vyos.utils.process import call
-from vyos import ConfigError
-from vyos import airbag
-airbag.enable()
-
-config_file = r'/run/fastnetmon/fastnetmon.conf'
-networks_list = r'/run/fastnetmon/networks_list'
-excluded_networks_list = r'/run/fastnetmon/excluded_networks_list'
-attack_dir = '/var/log/fastnetmon_attacks'
-
-def get_config(config=None):
- if config:
- conf = config
- else:
- conf = Config()
- base = ['service', 'ids', 'ddos-protection']
- if not conf.exists(base):
- return None
-
- fastnetmon = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True,
- with_recursive_defaults=True)
-
- return fastnetmon
-
-def verify(fastnetmon):
- if not fastnetmon:
- return None
-
- if 'mode' not in fastnetmon:
- raise ConfigError('Specify operating mode!')
-
- if fastnetmon.get('mode') == 'mirror' and 'listen_interface' not in fastnetmon:
- raise ConfigError("Incorrect settings for 'mode mirror': must specify interface(s) for traffic mirroring")
-
- if fastnetmon.get('mode') == 'sflow' and 'listen_address' not in fastnetmon.get('sflow', {}):
- raise ConfigError("Incorrect settings for 'mode sflow': must specify sFlow 'listen-address'")
-
- if 'alert_script' in fastnetmon:
- if os.path.isfile(fastnetmon['alert_script']):
- # Check script permissions
- if not os.access(fastnetmon['alert_script'], os.X_OK):
- raise ConfigError('Script "{alert_script}" is not executable!'.format(fastnetmon['alert_script']))
- else:
- raise ConfigError('File "{alert_script}" does not exists!'.format(fastnetmon))
-
-def generate(fastnetmon):
- if not fastnetmon:
- for file in [config_file, networks_list]:
- if os.path.isfile(file):
- os.unlink(file)
-
- return None
-
- # Create dir for log attack details
- if not os.path.exists(attack_dir):
- os.mkdir(attack_dir)
-
- render(config_file, 'ids/fastnetmon.j2', fastnetmon)
- render(networks_list, 'ids/fastnetmon_networks_list.j2', fastnetmon)
- render(excluded_networks_list, 'ids/fastnetmon_excluded_networks_list.j2', fastnetmon)
- return None
-
-def apply(fastnetmon):
- systemd_service = 'fastnetmon.service'
- if not fastnetmon:
- # Stop fastnetmon service if removed
- call(f'systemctl stop {systemd_service}')
- else:
- call(f'systemctl reload-or-restart {systemd_service}')
-
- return None
-
-if __name__ == '__main__':
- try:
- c = get_config()
- verify(c)
- generate(c)
- apply(c)
- except ConfigError as e:
- print(e)
- exit(1)
diff --git a/src/conf_mode/service_ipoe-server.py b/src/conf_mode/service_ipoe-server.py
index a14d4b5b6..50628947e 100755
--- a/src/conf_mode/service_ipoe-server.py
+++ b/src/conf_mode/service_ipoe-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -88,6 +88,12 @@ def verify(ipoe):
'Can configure username with Lua script only for RADIUS authentication'
)
+ if dict_search('external_dhcp.dhcp_relay', iface_config):
+ if not dict_search('external_dhcp.giaddr', iface_config):
+ raise ConfigError(
+ f'"external-dhcp dhcp-relay" requires "giaddr" to be set for interface {interface}'
+ )
+
verify_accel_ppp_authentication(ipoe, local_users=False)
verify_accel_ppp_ip_pool(ipoe)
verify_accel_ppp_name_servers(ipoe)
diff --git a/src/conf_mode/service_lldp.py b/src/conf_mode/service_lldp.py
index 04b1db880..50e9a49e6 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_mdns_repeater.py b/src/conf_mode/service_mdns_repeater.py
index b0ece031c..360b94588 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_monitoring_network_event.py b/src/conf_mode/service_monitoring_network_event.py
index 104e6ce23..f43ea23ca 100644
--- a/src/conf_mode/service_monitoring_network_event.py
+++ b/src/conf_mode/service_monitoring_network_event.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_monitoring_prometheus.py b/src/conf_mode/service_monitoring_prometheus.py
index 9a07d8593..b02f9f154 100755
--- a/src/conf_mode/service_monitoring_prometheus.py
+++ b/src/conf_mode/service_monitoring_prometheus.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,6 +23,7 @@ from vyos.configdict import is_node_changed
from vyos.configverify import verify_vrf
from vyos.template import render
from vyos.utils.process import call
+from vyos.utils.process import is_systemd_service_active
from vyos import ConfigError
from vyos import airbag
@@ -48,9 +49,21 @@ def get_config(config=None):
if not conf.exists(base):
return None
- monitoring = conf.get_config_dict(
- base, key_mangling=('-', '_'), get_first_key=True, with_recursive_defaults=True
- )
+ monitoring = {}
+ exporters = {
+ 'node_exporter': base + ['node-exporter'],
+ 'frr_exporter': base + ['frr-exporter'],
+ 'blackbox_exporter': base + ['blackbox-exporter'],
+ }
+
+ for exporter_name, exporter_base in exporters.items():
+ if conf.exists(exporter_base):
+ monitoring[exporter_name] = conf.get_config_dict(
+ exporter_base,
+ key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True,
+ )
tmp = is_node_changed(conf, base + ['node-exporter', 'vrf'])
if tmp:
@@ -161,11 +174,14 @@ def apply(monitoring):
# Reload systemd manager configuration
call('systemctl daemon-reload')
if not monitoring or 'node_exporter' not in monitoring:
- call(f'systemctl stop {node_exporter_systemd_service}')
+ if is_systemd_service_active(node_exporter_systemd_service):
+ call(f'systemctl stop {node_exporter_systemd_service}')
if not monitoring or 'frr_exporter' not in monitoring:
- call(f'systemctl stop {frr_exporter_systemd_service}')
+ if is_systemd_service_active(frr_exporter_systemd_service):
+ call(f'systemctl stop {frr_exporter_systemd_service}')
if not monitoring or 'blackbox_exporter' not in monitoring:
- call(f'systemctl stop {blackbox_exporter_systemd_service}')
+ if is_systemd_service_active(blackbox_exporter_systemd_service):
+ call(f'systemctl stop {blackbox_exporter_systemd_service}')
if not monitoring:
return
diff --git a/src/conf_mode/service_monitoring_telegraf.py b/src/conf_mode/service_monitoring_telegraf.py
index db870aae5..de8097e11 100755
--- a/src/conf_mode/service_monitoring_telegraf.py
+++ b/src/conf_mode/service_monitoring_telegraf.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_monitoring_zabbix-agent.py b/src/conf_mode/service_monitoring_zabbix-agent.py
index f17146a8d..5f3a8d4b5 100755
--- a/src/conf_mode/service_monitoring_zabbix-agent.py
+++ b/src/conf_mode/service_monitoring_zabbix-agent.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_ndp-proxy.py b/src/conf_mode/service_ndp-proxy.py
index 024ad79f2..f42ee9be8 100755
--- a/src/conf_mode/service_ndp-proxy.py
+++ b/src/conf_mode/service_ndp-proxy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_ntp.py b/src/conf_mode/service_ntp.py
index 32563aa0e..fbdcd6b58 100755
--- a/src/conf_mode/service_ntp.py
+++ b/src/conf_mode/service_ntp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_pppoe-server.py b/src/conf_mode/service_pppoe-server.py
index ac697c509..d910e770d 100755
--- a/src/conf_mode/service_pppoe-server.py
+++ b/src/conf_mode/service_pppoe-server.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -73,7 +73,9 @@ def get_config(config=None):
# https://phabricator.accel-ppp.org/T3
conditions = [is_node_changed(conf, base + ['client-ip-pool']),
is_node_changed(conf, base + ['client-ipv6-pool']),
- is_node_changed(conf, base + ['interface'])]
+ is_node_changed(conf, base + ['interface']),
+ is_node_changed(conf, base + ['authentication','radius','dynamic-author']),
+ is_node_changed(conf, base + ['authentication','mode'])]
if any(conditions):
pppoe.update({'restart_required': {}})
pppoe['server_type'] = 'pppoe'
diff --git a/src/conf_mode/service_router-advert.py b/src/conf_mode/service_router-advert.py
index 88d767bb8..4345bea1d 100755
--- a/src/conf_mode/service_router-advert.py
+++ b/src/conf_mode/service_router-advert.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_salt-minion.py b/src/conf_mode/service_salt-minion.py
index edf74b0c0..9e9940175 100755
--- a/src/conf_mode/service_salt-minion.py
+++ b/src/conf_mode/service_salt-minion.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2022 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_sla.py b/src/conf_mode/service_sla.py
index ba5e645f0..0a7b81073 100755
--- a/src/conf_mode/service_sla.py
+++ b/src/conf_mode/service_sla.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2022 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_snmp.py b/src/conf_mode/service_snmp.py
index c64c59af7..c6059c260 100755
--- a/src/conf_mode/service_snmp.py
+++ b/src/conf_mode/service_snmp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2025 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_ssh.py b/src/conf_mode/service_ssh.py
index 759f87bb2..bf8afe8b7 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,14 +23,15 @@ from syslog import LOG_INFO
from vyos.config import Config
from vyos.configdict import is_node_changed
from vyos.configverify import verify_vrf
-from vyos.configverify import verify_pki_ca_certificate
+from vyos.configverify import verify_pki_openssh_key
+from vyos.defaults import config_files
from vyos.utils.process import call
from vyos.template import render
from vyos import ConfigError
from vyos import airbag
-from vyos.pki import find_chain
-from vyos.pki import encode_certificate
-from vyos.pki import load_certificate
+from vyos.pki import encode_public_key
+from vyos.pki import load_openssh_public_key
+from vyos.utils.dict import dict_search_recursive
from vyos.utils.file import write_file
airbag.enable()
@@ -44,8 +45,7 @@ key_rsa = '/etc/ssh/ssh_host_rsa_key'
key_dsa = '/etc/ssh/ssh_host_dsa_key'
key_ed25519 = '/etc/ssh/ssh_host_ed25519_key'
-trusted_user_ca_key = '/etc/ssh/trusted_user_ca_key'
-
+trusted_user_ca = config_files['sshd_user_ca']
def get_config(config=None):
if config:
@@ -55,10 +55,8 @@ def get_config(config=None):
base = ['service', 'ssh']
if not conf.exists(base):
return None
-
- ssh = conf.get_config_dict(
- base, key_mangling=('-', '_'), get_first_key=True, with_pki=True
- )
+ ssh = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True, with_pki=True)
tmp = is_node_changed(conf, base + ['vrf'])
if tmp:
@@ -68,14 +66,27 @@ def get_config(config=None):
# options which we need to update into the dictionary retrived.
ssh = conf.merge_defaults(ssh, recursive=True)
- # pass config file path - used in override template
- ssh['config_file'] = config_file
-
# Ignore default XML values if config doesn't exists
# Delete key from dict
if not conf.exists(base + ['dynamic-protection']):
del ssh['dynamic_protection']
+ # See if any user has specified a list of principal names that are accepted
+ # for certificate authentication.
+ tmp = conf.get_config_dict(['system', 'login', 'user'],
+ key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
+ get_first_key=True)
+
+ for value, _ in dict_search_recursive(tmp, 'principal'):
+ # Only enable principal handling if SSH trusted-user-ca is set
+ if 'trusted_user_ca' in ssh:
+ ssh['has_principals'] = {}
+ # We do only need to execute this code path once as we need to know
+ # if any one of the local users has a principal set or not - this
+ # accounts for the entire system.
+ break
+
return ssh
@@ -86,15 +97,8 @@ def verify(ssh):
if 'rekey' in ssh and 'data' not in ssh['rekey']:
raise ConfigError('Rekey data is required!')
- if 'trusted_user_ca_key' in ssh:
- if 'ca_certificate' not in ssh['trusted_user_ca_key']:
- raise ConfigError('CA certificate is required for TrustedUserCAKey')
-
- ca_key_name = ssh['trusted_user_ca_key']['ca_certificate']
- verify_pki_ca_certificate(ssh, ca_key_name)
- pki_ca_cert = ssh['pki']['ca'][ca_key_name]
- if 'certificate' not in pki_ca_cert or not pki_ca_cert['certificate']:
- raise ConfigError(f"CA certificate '{ca_key_name}' is not valid or missing")
+ if 'trusted_user_ca' in ssh:
+ verify_pki_openssh_key(ssh, ssh['trusted_user_ca'])
verify_vrf(ssh)
return None
@@ -119,23 +123,17 @@ def generate(ssh):
syslog(LOG_INFO, 'SSH ed25519 host key not found, generating new key!')
call(f'ssh-keygen -q -N "" -t ed25519 -f {key_ed25519}')
- if 'trusted_user_ca_key' in ssh:
- ca_key_name = ssh['trusted_user_ca_key']['ca_certificate']
- pki_ca_cert = ssh['pki']['ca'][ca_key_name]
-
- loaded_ca_cert = load_certificate(pki_ca_cert['certificate'])
- loaded_ca_certs = {
- load_certificate(c['certificate'])
- for c in ssh['pki']['ca'].values()
- if 'certificate' in c
- }
-
- ca_full_chain = find_chain(loaded_ca_cert, loaded_ca_certs)
- write_file(
- trusted_user_ca_key, '\n'.join(encode_certificate(c) for c in ca_full_chain)
- )
- elif os.path.exists(trusted_user_ca_key):
- os.unlink(trusted_user_ca_key)
+ if 'trusted_user_ca' in ssh:
+ key_name = ssh['trusted_user_ca']
+ openssh_cert = ssh['pki']['openssh'][key_name]
+ loaded_ca_cert = load_openssh_public_key(openssh_cert['public']['key'],
+ openssh_cert['public']['type'])
+ tmp = encode_public_key(loaded_ca_cert, encoding='OpenSSH',
+ key_format='OpenSSH')
+ write_file(trusted_user_ca, tmp, trailing_newline=True)
+ else:
+ if os.path.exists(trusted_user_ca):
+ os.unlink(trusted_user_ca)
render(config_file, 'ssh/sshd_config.j2', ssh)
diff --git a/src/conf_mode/service_stunnel.py b/src/conf_mode/service_stunnel.py
index 8ec762548..eb1d4dea2 100644
--- a/src/conf_mode/service_stunnel.py
+++ b/src/conf_mode/service_stunnel.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_suricata.py b/src/conf_mode/service_suricata.py
index 1ce170145..728c5607e 100755
--- a/src/conf_mode/service_suricata.py
+++ b/src/conf_mode/service_suricata.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_tftp-server.py b/src/conf_mode/service_tftp-server.py
index 5b7303c40..dc5ec5674 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/service_webproxy.py b/src/conf_mode/service_webproxy.py
index 12ae4135e..7a4954de2 100755
--- a/src/conf_mode/service_webproxy.py
+++ b/src/conf_mode/service_webproxy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_acceleration.py b/src/conf_mode/system_acceleration.py
index d2cf44ff0..954bf8bba 100755
--- a/src/conf_mode/system_acceleration.py
+++ b/src/conf_mode/system_acceleration.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_config-management.py b/src/conf_mode/system_config-management.py
index a3ce66512..c1d83af34 100755
--- a/src/conf_mode/system_config-management.py
+++ b/src/conf_mode/system_config-management.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_conntrack.py b/src/conf_mode/system_conntrack.py
index f25ed8d10..eed1a4458 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -32,7 +32,6 @@ from vyos import ConfigError
from vyos import airbag
airbag.enable()
-conntrack_config = r'/etc/modprobe.d/vyatta_nf_conntrack.conf'
sysctl_file = r'/run/sysctl/10-vyos-conntrack.conf'
nftables_ct_file = r'/run/nftables-ct.conf'
vyos_conntrack_logger_config = r'/run/vyos-conntrack-logger.conf'
@@ -204,7 +203,6 @@ def generate(conntrack):
elif path[0] == 'ipv6':
conntrack['ipv6_firewall_action'] = 'accept'
- render(conntrack_config, 'conntrack/vyos_nf_conntrack.conf.j2', conntrack)
render(sysctl_file, 'conntrack/sysctl.conf.j2', conntrack)
render(nftables_ct_file, 'conntrack/nftables-ct.j2', conntrack)
diff --git a/src/conf_mode/system_console.py b/src/conf_mode/system_console.py
index b380e0521..90648e2b8 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_flow-accounting.py b/src/conf_mode/system_flow-accounting.py
index 925c4a562..618227fc0 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_frr.py b/src/conf_mode/system_frr.py
index d9ac543d0..06af37ad8 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_host-name.py b/src/conf_mode/system_host-name.py
index fef034d1c..2a5592484 100755
--- a/src/conf_mode/system_host-name.py
+++ b/src/conf_mode/system_host-name.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2025 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -175,7 +175,7 @@ def apply(config):
# Restart services that use the hostname
if hostname_new != hostname_old:
- tmp = systemd_services['rsyslog']
+ tmp = systemd_services['syslog']
call(f'systemctl restart {tmp}')
# If SNMP is running, restart it too
diff --git a/src/conf_mode/system_ip.py b/src/conf_mode/system_ip.py
index 7f3796168..13471eb3b 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -53,6 +53,11 @@ def verify(config_dict):
for protocol, protocol_options in opt['protocol'].items():
if 'route_map' in protocol_options:
verify_route_map(protocol_options['route_map'], opt)
+
+ if dict_search('import_table', opt):
+ for table_num, import_config in opt['import_table'].items():
+ if dict_search('route_map', import_config):
+ verify_route_map(import_config['route_map'], opt)
return
def generate(config_dict):
diff --git a/src/conf_mode/system_ipv6.py b/src/conf_mode/system_ipv6.py
index 309869b2f..35f343d82 100755
--- a/src/conf_mode/system_ipv6.py
+++ b/src/conf_mode/system_ipv6.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_lcd.py b/src/conf_mode/system_lcd.py
index eb88224d1..1e97414dc 100755
--- a/src/conf_mode/system_lcd.py
+++ b/src/conf_mode/system_lcd.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright 2020-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_login.py b/src/conf_mode/system_login.py
index 3fed6d273..00cacccd1 100755
--- a/src/conf_mode/system_login.py
+++ b/src/conf_mode/system_login.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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 warnings
from passlib.hosts import linux_context
from psutil import users
@@ -27,15 +26,14 @@ from time import sleep
from vyos.base import Warning
from vyos.config import Config
+from vyos.configdep import set_dependents
+from vyos.configdep import call_dependents
from vyos.configverify import verify_vrf
from vyos.template import render
from vyos.template import is_ipv4
-from vyos.utils.auth import (
- DEFAULT_PASSWORD,
- EPasswdStrength,
- evaluate_strength,
- get_current_user
-)
+from vyos.utils.auth import EPasswdStrength
+from vyos.utils.auth import evaluate_strength
+from vyos.utils.auth import get_current_user
from vyos.utils.configfs import delete_cli_node
from vyos.utils.configfs import add_cli_node
from vyos.utils.dict import dict_search
@@ -133,6 +131,7 @@ def get_config(config=None):
max_uid=MIN_TACACS_UID) + cli_users
login['tacacs_min_uid'] = MIN_TACACS_UID
+ set_dependents('ssh', conf)
return login
def verify(login):
@@ -349,6 +348,17 @@ def apply(login):
user_config, permission=0o600,
formater=lambda _: _.replace("&quot;", '"'),
user=user, group='users')
+
+ principals_file = f'{home_dir}/.ssh/authorized_principals'
+ if dict_search('authentication.principal', user_config):
+ render(principals_file, 'login/authorized_principals.j2',
+ user_config, permission=0o600,
+ formater=lambda _: _.replace("&quot;", '"'),
+ user=user, group='users')
+ else:
+ if os.path.exists(principals_file):
+ os.unlink(principals_file)
+
except Exception as e:
raise ConfigError(f'Adding user "{user}" raised exception: "{e}"')
@@ -365,14 +375,15 @@ def apply(login):
chown(home_dir, user=user, recursive=True)
# Generate 2FA/MFA One-Time-Pad configuration
+ google_auth_file = f'{home_dir}/.google_authenticator'
if dict_search('authentication.otp.key', user_config):
enable_otp = True
- render(f'{home_dir}/.google_authenticator', 'login/pam_otp_ga.conf.j2',
+ render(google_auth_file, 'login/pam_otp_ga.conf.j2',
user_config, permission=0o400, user=user, group='users')
else:
# delete configuration as it's not enabled for the user
- if os.path.exists(f'{home_dir}/.google_authenticator'):
- os.remove(f'{home_dir}/.google_authenticator')
+ if os.path.exists(google_auth_file):
+ os.unlink(google_auth_file)
# Lock/Unlock local user account
lock_unlock = '--unlock'
@@ -386,6 +397,22 @@ def apply(login):
# Disable user to prevent re-login
call(f'usermod -s /sbin/nologin {user}')
+ home_dir = getpwnam(user).pw_dir
+ # Remove SSH authorized keys file
+ authorized_keys_file = f'{home_dir}/.ssh/authorized_keys'
+ if os.path.exists(authorized_keys_file):
+ os.unlink(authorized_keys_file)
+
+ # Remove SSH authorized principals file
+ principals_file = f'{home_dir}/.ssh/authorized_principals'
+ if os.path.exists(principals_file):
+ os.unlink(principals_file)
+
+ # Remove Google Authenticator file
+ google_auth_file = f'{home_dir}/.google_authenticator'
+ if os.path.exists(google_auth_file):
+ os.unlink(google_auth_file)
+
# Logout user if he is still logged in
if user in list(set([tmp[0] for tmp in users()])):
print(f'{user} is logged in, forcing logout!')
@@ -424,8 +451,9 @@ def apply(login):
# Enable/disable Google authenticator
cmd('pam-auth-update --disable mfa-google-authenticator')
if enable_otp:
- cmd(f'pam-auth-update --enable mfa-google-authenticator')
+ cmd('pam-auth-update --enable mfa-google-authenticator')
+ call_dependents()
return None
diff --git a/src/conf_mode/system_login_banner.py b/src/conf_mode/system_login_banner.py
index cdd066649..9d5fba65f 100755
--- a/src/conf_mode/system_login_banner.py
+++ b/src/conf_mode/system_login_banner.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_logs.py b/src/conf_mode/system_logs.py
index 8ad4875d4..f0e742d1b 100755
--- a/src/conf_mode/system_logs.py
+++ b/src/conf_mode/system_logs.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_option.py b/src/conf_mode/system_option.py
index 064a1aa91..fbe7231df 100755
--- a/src/conf_mode/system_option.py
+++ b/src/conf_mode/system_option.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -122,7 +122,14 @@ def generate(options):
render(ssh_config, 'system/ssh_config.j2', options)
render(usb_autosuspend, 'system/40_usb_autosuspend.j2', options)
+ # XXX: This code path and if statements must be kept in sync with the Kernel
+ # option handling in image_installer.py:get_cli_kernel_options(). This
+ # occurance is used for having the appropriate options passed to GRUB
+ # when re-configuring options on the CLI.
cmdline_options = []
+ kernel_opts = options.get('kernel', {})
+ k_cpu_opts = kernel_opts.get('cpu', {})
+ k_memory_opts = kernel_opts.get('memory', {})
if 'kernel' in options:
if 'disable_mitigations' in options['kernel']:
cmdline_options.append('mitigations=off')
@@ -131,8 +138,51 @@ def generate(options):
if 'amd_pstate_driver' in options['kernel']:
mode = options['kernel']['amd_pstate_driver']
cmdline_options.append(
- f'initcall_blacklist=acpi_cpufreq_init amd_pstate={mode}'
- )
+ f'initcall_blacklist=acpi_cpufreq_init amd_pstate={mode}')
+ if 'quiet' in options['kernel']:
+ cmdline_options.append('quiet')
+
+ if 'disable_hpet' in kernel_opts:
+ cmdline_options.append('hpet=disable')
+
+ if 'disable_mce' in kernel_opts:
+ cmdline_options.append('mce=off')
+
+ if 'disable_softlockup' in kernel_opts:
+ cmdline_options.append('nosoftlockup')
+
+ # CPU options
+ isol_cpus = k_cpu_opts.get('isolate_cpus')
+ if isol_cpus:
+ cmdline_options.append(f'isolcpus={isol_cpus}')
+
+ nohz_full = k_cpu_opts.get('nohz_full')
+ if nohz_full:
+ cmdline_options.append(f'nohz_full={nohz_full}')
+
+ rcu_nocbs = k_cpu_opts.get('rcu_no_cbs')
+ if rcu_nocbs:
+ cmdline_options.append(f'rcu_nocbs={rcu_nocbs}')
+
+ if 'disable_nmi_watchdog' in k_cpu_opts:
+ cmdline_options.append('nmi_watchdog=0')
+
+ # Memory options
+ if 'disable_numa_balancing' in k_memory_opts:
+ cmdline_options.append('numa_balancing=disable')
+
+ default_hp_size = k_memory_opts.get('default_hugepage_size')
+ if default_hp_size:
+ cmdline_options.append(f'default_hugepagesz={default_hp_size}')
+
+ hp_sizes = k_memory_opts.get('hugepage_size')
+ if hp_sizes:
+ for size, settings in hp_sizes.items():
+ cmdline_options.append(f'hugepagesz={size}')
+ count = settings.get('hugepage_count')
+ if count:
+ cmdline_options.append(f'hugepages={count}')
+
grub_util.update_kernel_cmdline_options(' '.join(cmdline_options))
return None
diff --git a/src/conf_mode/system_proxy.py b/src/conf_mode/system_proxy.py
index 079c43e7e..3843ad527 100755
--- a/src/conf_mode/system_proxy.py
+++ b/src/conf_mode/system_proxy.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2022 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_sflow.py b/src/conf_mode/system_sflow.py
index a22dac36f..86a344ff7 100755
--- a/src/conf_mode/system_sflow.py
+++ b/src/conf_mode/system_sflow.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2023-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_sysctl.py b/src/conf_mode/system_sysctl.py
index f6b02023d..8e018ec0b 100755
--- a/src/conf_mode/system_sysctl.py
+++ b/src/conf_mode/system_sysctl.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_syslog.py b/src/conf_mode/system_syslog.py
index 414bd4b6b..c1a8baa1d 100755
--- a/src/conf_mode/system_syslog.py
+++ b/src/conf_mode/system_syslog.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2025 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -35,7 +35,7 @@ rsyslog_conf = '/run/rsyslog/rsyslog.conf'
logrotate_conf = '/etc/logrotate.d/vyos-rsyslog'
systemd_socket = 'syslog.socket'
-systemd_service = systemd_services['rsyslog']
+systemd_service = systemd_services['syslog']
def get_config(config=None):
if config:
diff --git a/src/conf_mode/system_task-scheduler.py b/src/conf_mode/system_task-scheduler.py
index 129be5d3c..c0253006a 100755
--- a/src/conf_mode/system_task-scheduler.py
+++ b/src/conf_mode/system_task-scheduler.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2017 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_timezone.py b/src/conf_mode/system_timezone.py
index 39770fdb4..54ffb88ee 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_update-check.py b/src/conf_mode/system_update-check.py
index 71ac13e51..7ed736eac 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/system_wireless.py b/src/conf_mode/system_wireless.py
index e0ca0ab8e..2d377c50a 100644
--- a/src/conf_mode/system_wireless.py
+++ b/src/conf_mode/system_wireless.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index 2754314f7..1871956b2 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2021-2025 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -727,7 +727,7 @@ def generate(ipsec):
for remote_prefix in remote_prefixes:
local_net = ipaddress.ip_network(local_prefix)
remote_net = ipaddress.ip_network(remote_prefix)
- if local_net.overlaps(remote_net):
+ if local_net.subnet_of(remote_net):
if passthrough is None:
passthrough = []
passthrough.append(local_prefix)
diff --git a/src/conf_mode/vpn_l2tp.py b/src/conf_mode/vpn_l2tp.py
index 04ccbcec3..d6f5e4c28 100755
--- a/src/conf_mode/vpn_l2tp.py
+++ b/src/conf_mode/vpn_l2tp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py
index 42785134f..78cdaa179 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-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
@@ -37,19 +37,22 @@ from passlib.hash import sha512_crypt
from time import sleep
from vyos import airbag
+
airbag.enable()
-cfg_dir = '/run/ocserv'
-ocserv_conf = cfg_dir + '/ocserv.conf'
-ocserv_passwd = cfg_dir + '/ocpasswd'
+cfg_dir = '/run/ocserv'
+ocserv_conf = cfg_dir + '/ocserv.conf'
+ocserv_passwd = cfg_dir + '/ocpasswd'
ocserv_otp_usr = cfg_dir + '/users.oath'
-radius_cfg = cfg_dir + '/radiusclient.conf'
+radius_cfg = cfg_dir + '/radiusclient.conf'
radius_servers = cfg_dir + '/radius_servers'
+
# Generate hash from user cleartext password
def get_hash(password):
return sha512_crypt.hash(password)
+
def get_config(config=None):
if config:
conf = config
@@ -59,78 +62,133 @@ def get_config(config=None):
if not conf.exists(base):
return None
- ocserv = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True,
- with_recursive_defaults=True,
- with_pki=True)
+ ocserv = conf.get_config_dict(
+ base,
+ key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True,
+ with_pki=True,
+ )
return ocserv
+
def verify(ocserv):
if ocserv is None:
return None
# Check if listen-ports not binded other services
# It can be only listen by 'ocserv-main'
for proto, port in ocserv.get('listen_ports').items():
- if check_port_availability(ocserv['listen_address'], int(port), proto) is not True and \
- not is_listen_port_bind_service(int(port), 'ocserv-main'):
+ if check_port_availability(
+ ocserv['listen_address'], int(port), proto
+ ) is not True and not is_listen_port_bind_service(int(port), 'ocserv-main'):
raise ConfigError(f'"{proto}" port "{port}" is used by another service')
# Check accounting
- 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')
- 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"]:
- raise ConfigError('RADIUS accounting must be used with RADIUS authentication')
+ if 'accounting' in ocserv:
+ if 'mode' in ocserv['accounting'] and 'radius' in ocserv['accounting']['mode']:
+ if not ocserv['accounting']['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']:
+ raise ConfigError(
+ 'RADIUS accounting must be used with RADIUS authentication'
+ )
# Check authentication
- if "authentication" in ocserv:
- if "mode" in ocserv["authentication"]:
- if ("local" in ocserv["authentication"]["mode"] and
- "radius" in ocserv["authentication"]["mode"]):
- 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')
- if "local" in ocserv["authentication"]["mode"]:
- if not ocserv.get("authentication", {}).get("local_users"):
- 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')
+ if 'authentication' in ocserv:
+ if 'mode' in ocserv['authentication']:
+ if (
+ 'local' in ocserv['authentication']['mode']
+ and 'radius' in ocserv['authentication']['mode']
+ ):
+ raise ConfigError(
+ 'OpenConnect authentication modes are mutually-exclusive, remove either local or radius from your configuration'
+ )
+ if 'radius' in ocserv['authentication']['mode']:
+ if 'server' not in ocserv['authentication']['radius']:
+ 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'
+ )
+ if not ocserv['authentication']['local_users']['username']:
+ 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"]:
+ if 'otp' in ocserv['authentication']['mode']['local']:
users_wo_key = []
- for user, user_config in ocserv["authentication"]["local_users"]["username"].items():
+ for user, user_config in ocserv['authentication'][
+ 'local_users'
+ ]['username'].items():
# User has no OTP key defined
- if dict_search('otp.key', user_config) == None:
+ if dict_search('otp.key', user_config) is None:
users_wo_key.append(user)
if users_wo_key:
- raise ConfigError(f'OTP enabled, but no OTP key is configured for these users:\n{users_wo_key}')
+ raise ConfigError(
+ f'OTP enabled, but no OTP key is configured for these users:\n{users_wo_key}'
+ )
# For password (and default) mode: verify that each local user has password
- if "password" in ocserv["authentication"]["mode"]["local"] or "otp" not in ocserv["authentication"]["mode"]["local"]:
+ if (
+ 'password' in ocserv['authentication']['mode']['local']
+ or 'otp' not in ocserv['authentication']['mode']['local']
+ ):
users_wo_pswd = []
- for user in ocserv["authentication"]["local_users"]["username"]:
- if not "password" in ocserv["authentication"]["local_users"]["username"][user]:
+ for user in ocserv['authentication']['local_users']['username']:
+ if (
+ 'password'
+ not in ocserv['authentication']['local_users'][
+ 'username'
+ ][user]
+ ):
users_wo_pswd.append(user)
if users_wo_pswd:
- raise ConfigError(f'password required for users:\n{users_wo_pswd}')
+ raise ConfigError(
+ f'password required for users:\n{users_wo_pswd}'
+ )
# Validate that if identity-based-config is configured all child config nodes are set
- if 'identity_based_config' in ocserv["authentication"]:
- if 'disabled' not in ocserv["authentication"]["identity_based_config"]:
- Warning("Identity based configuration files is a 3rd party addition. Use at your own risk, this might break the ocserv daemon!")
- if 'mode' not in ocserv["authentication"]["identity_based_config"]:
- raise ConfigError('OpenConnect radius identity-based-config enabled but mode not selected')
- elif 'group' in ocserv["authentication"]["identity_based_config"]["mode"] and "radius" not in ocserv["authentication"]["mode"]:
- raise ConfigError('OpenConnect config-per-group must be used with radius authentication')
- if 'directory' not in ocserv["authentication"]["identity_based_config"]:
- raise ConfigError('OpenConnect identity-based-config enabled but directory not set')
- if 'default_config' not in ocserv["authentication"]["identity_based_config"]:
- raise ConfigError('OpenConnect identity-based-config enabled but default-config not set')
+ if 'identity_based_config' in ocserv['authentication']:
+ if 'disabled' not in ocserv['authentication']['identity_based_config']:
+ Warning(
+ 'Identity based configuration files is a 3rd party addition. Use at your own risk, this might break the ocserv daemon!'
+ )
+ if 'mode' not in ocserv['authentication']['identity_based_config']:
+ raise ConfigError(
+ 'OpenConnect radius identity-based-config enabled but mode not selected'
+ )
+ elif (
+ 'group'
+ in ocserv['authentication']['identity_based_config']['mode']
+ and 'radius' not in ocserv['authentication']['mode']
+ ):
+ raise ConfigError(
+ 'OpenConnect config-per-group must be used with radius authentication'
+ )
+ if (
+ 'directory'
+ not in ocserv['authentication']['identity_based_config']
+ ):
+ raise ConfigError(
+ 'OpenConnect identity-based-config enabled but directory not set'
+ )
+ 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')
else:
@@ -149,94 +207,162 @@ def verify(ocserv):
verify_pki_ca_certificate(ocserv, ca_cert)
# Check network settings
- if "network_settings" in ocserv:
- if "push_route" in ocserv["network_settings"]:
+ if 'network_settings' in ocserv:
+ if 'push_route' in ocserv['network_settings']:
# Replace default route
- if "0.0.0.0/0" in ocserv["network_settings"]["push_route"]:
- ocserv["network_settings"]["push_route"].remove("0.0.0.0/0")
- ocserv["network_settings"]["push_route"].append("default")
+ if '0.0.0.0/0' in ocserv['network_settings']['push_route']:
+ ocserv['network_settings']['push_route'].remove('0.0.0.0/0')
+ ocserv['network_settings']['push_route'].append('default')
else:
- ocserv["network_settings"]["push_route"] = ["default"]
+ ocserv['network_settings']['push_route'] = ['default']
else:
raise ConfigError('OpenConnect network settings required!')
+
def generate(ocserv):
if not ocserv:
return None
- if "radius" in ocserv["authentication"]["mode"]:
+ if 'radius' in ocserv['authentication']['mode']:
if dict_search(ocserv, 'accounting.mode.radius'):
# Render radius client configuration
render(radius_cfg, 'ocserv/radius_conf.j2', ocserv)
- merged_servers = ocserv["accounting"]["radius"]["server"] | ocserv["authentication"]["radius"]["server"]
+ merged_servers = (
+ ocserv['accounting']['radius']['server']
+ | ocserv['authentication']['radius']['server']
+ )
# Render radius servers
# Merge the accounting and authentication servers into a single dictionary
- render(radius_servers, 'ocserv/radius_servers.j2', {'server': merged_servers})
+ render(
+ radius_servers, 'ocserv/radius_servers.j2', {'server': merged_servers}
+ )
else:
# Render radius client configuration
render(radius_cfg, 'ocserv/radius_conf.j2', ocserv)
# Render radius servers
- render(radius_servers, 'ocserv/radius_servers.j2', ocserv["authentication"]["radius"])
- elif "local" in ocserv["authentication"]["mode"]:
+ render(
+ radius_servers,
+ 'ocserv/radius_servers.j2',
+ ocserv['authentication']['radius'],
+ )
+ elif 'local' in ocserv['authentication']['mode']:
# if mode "OTP", generate OTP users file parameters
- if "otp" in ocserv["authentication"]["mode"]["local"]:
- if "local_users" in ocserv["authentication"]:
- for user in ocserv["authentication"]["local_users"]["username"]:
+ if 'otp' in ocserv['authentication']['mode']['local']:
+ if 'local_users' in ocserv['authentication']:
+ for user in ocserv['authentication']['local_users']['username']:
# OTP token type from CLI parameters:
- otp_interval = str(ocserv["authentication"]["local_users"]["username"][user]["otp"].get("interval"))
- token_type = ocserv["authentication"]["local_users"]["username"][user]["otp"].get("token_type")
- otp_length = str(ocserv["authentication"]["local_users"]["username"][user]["otp"].get("otp_length"))
- if token_type == "hotp-time":
- otp_type = "HOTP/T" + otp_interval
- elif token_type == "hotp-event":
- otp_type = "HOTP/E"
+ otp_interval = str(
+ ocserv['authentication']['local_users']['username'][user][
+ 'otp'
+ ].get('interval')
+ )
+ token_type = ocserv['authentication']['local_users']['username'][
+ user
+ ]['otp'].get('token_type')
+ otp_length = str(
+ ocserv['authentication']['local_users']['username'][user][
+ 'otp'
+ ].get('otp_length')
+ )
+ if token_type == 'hotp-time':
+ otp_type = 'HOTP/T' + otp_interval
+ elif token_type == 'hotp-event':
+ otp_type = 'HOTP/E'
else:
- otp_type = "HOTP/T" + otp_interval
- ocserv["authentication"]["local_users"]["username"][user]["otp"]["token_tmpl"] = otp_type + "/" + otp_length
+ otp_type = 'HOTP/T' + otp_interval
+ ocserv['authentication']['local_users']['username'][user]['otp'][
+ 'token_tmpl'
+ ] = otp_type + '/' + otp_length
# if there is a password, generate hash
- if "password" in ocserv["authentication"]["mode"]["local"] or not "otp" in ocserv["authentication"]["mode"]["local"]:
- if "local_users" in ocserv["authentication"]:
- for user in ocserv["authentication"]["local_users"]["username"]:
- ocserv["authentication"]["local_users"]["username"][user]["hash"] = get_hash(ocserv["authentication"]["local_users"]["username"][user]["password"])
-
- if "password-otp" in ocserv["authentication"]["mode"]["local"]:
+ if (
+ 'password' in ocserv['authentication']['mode']['local']
+ or 'otp' not in ocserv['authentication']['mode']['local']
+ ):
+ if 'local_users' in ocserv['authentication']:
+ for user in ocserv['authentication']['local_users']['username']:
+ ocserv['authentication']['local_users']['username'][user][
+ 'hash'
+ ] = get_hash(
+ ocserv['authentication']['local_users']['username'][user][
+ 'password'
+ ]
+ )
+
+ if 'password-otp' in ocserv['authentication']['mode']['local']:
# Render local users ocpasswd
- render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
+ render(
+ ocserv_passwd,
+ 'ocserv/ocserv_passwd.j2',
+ ocserv['authentication']['local_users'],
+ )
# Render local users OTP keys
- render(ocserv_otp_usr, 'ocserv/ocserv_otp_usr.j2', ocserv["authentication"]["local_users"])
- elif "password" in ocserv["authentication"]["mode"]["local"]:
+ render(
+ ocserv_otp_usr,
+ 'ocserv/ocserv_otp_usr.j2',
+ ocserv['authentication']['local_users'],
+ )
+ elif 'password' in ocserv['authentication']['mode']['local']:
# Render local users ocpasswd
- render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
- elif "otp" in ocserv["authentication"]["mode"]["local"]:
+ render(
+ ocserv_passwd,
+ 'ocserv/ocserv_passwd.j2',
+ ocserv['authentication']['local_users'],
+ )
+ elif 'otp' in ocserv['authentication']['mode']['local']:
# Render local users OTP keys
- render(ocserv_otp_usr, 'ocserv/ocserv_otp_usr.j2', ocserv["authentication"]["local_users"])
+ render(
+ ocserv_otp_usr,
+ 'ocserv/ocserv_otp_usr.j2',
+ ocserv['authentication']['local_users'],
+ )
else:
# Render local users ocpasswd
- render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
+ render(
+ ocserv_passwd,
+ 'ocserv/ocserv_passwd.j2',
+ ocserv['authentication']['local_users'],
+ )
else:
- if "local_users" in ocserv["authentication"]:
- for user in ocserv["authentication"]["local_users"]["username"]:
- ocserv["authentication"]["local_users"]["username"][user]["hash"] = get_hash(ocserv["authentication"]["local_users"]["username"][user]["password"])
+ if 'local_users' in ocserv['authentication']:
+ for user in ocserv['authentication']['local_users']['username']:
+ ocserv['authentication']['local_users']['username'][user]['hash'] = (
+ get_hash(
+ ocserv['authentication']['local_users']['username'][user][
+ 'password'
+ ]
+ )
+ )
# Render local users
- render(ocserv_passwd, 'ocserv/ocserv_passwd.j2', ocserv["authentication"]["local_users"])
+ render(
+ ocserv_passwd,
+ 'ocserv/ocserv_passwd.j2',
+ ocserv['authentication']['local_users'],
+ )
- if "ssl" in ocserv:
+ if 'ssl' in ocserv:
cert_file_path = os.path.join(cfg_dir, 'cert.pem')
cert_key_path = os.path.join(cfg_dir, 'cert.key')
-
if 'certificate' in ocserv['ssl']:
cert_name = ocserv['ssl']['certificate']
pki_cert = ocserv['pki']['certificate'][cert_name]
loaded_pki_cert = load_certificate(pki_cert['certificate'])
- loaded_ca_certs = {load_certificate(c['certificate'])
- for c in ocserv['pki']['ca'].values()} if 'ca' in ocserv['pki'] else {}
+ loaded_ca_certs = (
+ {
+ load_certificate(c['certificate'])
+ for c in ocserv['pki']['ca'].values()
+ }
+ if 'ca' in ocserv['pki']
+ else {}
+ )
cert_full_chain = find_chain(loaded_pki_cert, loaded_ca_certs)
- write_file(cert_file_path,
- '\n'.join(encode_certificate(c) for c in cert_full_chain))
+ write_file(
+ cert_file_path,
+ '\n'.join(encode_certificate(c) for c in cert_full_chain),
+ )
if 'private' in pki_cert and 'key' in pki_cert['private']:
write_file(cert_key_path, wrap_private_key(pki_cert['private']['key']))
@@ -250,7 +376,8 @@ def generate(ocserv):
loaded_ca_cert = load_certificate(pki_ca_cert['certificate'])
ca_full_chain = find_chain(loaded_ca_cert, loaded_ca_certs)
ca_chains.append(
- '\n'.join(encode_certificate(c) for c in ca_full_chain))
+ '\n'.join(encode_certificate(c) for c in ca_full_chain)
+ )
write_file(ca_cert_file_path, '\n'.join(ca_chains))
@@ -269,11 +396,13 @@ def apply(ocserv):
counter = 0
while True:
# exit early when service runs
- if is_systemd_service_running("ocserv.service"):
+ if is_systemd_service_running('ocserv.service'):
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_pptp.py b/src/conf_mode/vpn_pptp.py
index c0d8330bd..c11619779 100755
--- a/src/conf_mode/vpn_pptp.py
+++ b/src/conf_mode/vpn_pptp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2023 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/vpn_sstp.py b/src/conf_mode/vpn_sstp.py
index 7490fd0e0..5382fc711 100755
--- a/src/conf_mode/vpn_sstp.py
+++ b/src/conf_mode/vpn_sstp.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2018-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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
diff --git a/src/conf_mode/vrf.py b/src/conf_mode/vrf.py
index 8baf55857..1eacba112 100755
--- a/src/conf_mode/vrf.py
+++ b/src/conf_mode/vrf.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2020-2024 VyOS maintainers and contributors
+# Copyright VyOS maintainers and contributors <maintainers@vyos.io>
#
# 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,6 +18,8 @@ from sys import exit
from jmespath import search
from json import loads
+import vyos.defaults
+
from vyos.config import Config
from vyos.configdict import node_changed
from vyos.configverify import verify_route_map
@@ -163,6 +165,11 @@ def verify(vrf):
if 'table' not in vrf_config:
raise ConfigError(f'VRF "{name}" table id is mandatory!')
+ if int(vrf_config['table']) == vyos.defaults.rt_global_vrf:
+ raise ConfigError(
+ f'VRF "{name}" table id {vrf_config["table"]} cannot be used!'
+ )
+
# routing table id can't be changed - OS restriction
if interface_exists(name):
tmp = get_vrf_tableid(name)
@@ -233,7 +240,7 @@ def apply(vrf):
vrf_iface.set_dhcpv6(False)
# Remove nftables conntrack zone map item
- nft_del_element = f'delete element inet vrf_zones ct_iface_map {{ "{tmp}" }}'
+ nft_del_element = f'delete element inet vrf_zones ct_iface_map {{ \'"{tmp}"\' }}'
# Check if deleting is possible first to avoid raising errors
_, err = popen(f'nft --check {nft_del_element}')
if not err:
@@ -313,7 +320,7 @@ def apply(vrf):
state = 'down' if 'disable' in config else 'up'
vrf_if.set_admin_state(state)
# Add nftables conntrack zone map item
- nft_add_element = f'add element inet vrf_zones ct_iface_map {{ "{name}" : {table} }}'
+ nft_add_element = f'add element inet vrf_zones ct_iface_map {{ \'"{name}"\' : {table} }}'
cmd(f'nft {nft_add_element}')
# Only call into nftables as long as there is nothing setup to avoid wasting