summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/bcast_relay.py2
-rwxr-xr-xsrc/conf_mode/conntrack.py14
-rwxr-xr-xsrc/conf_mode/conntrack_sync.py10
-rwxr-xr-xsrc/conf_mode/container.py64
-rwxr-xr-xsrc/conf_mode/dhcp_relay.py10
-rwxr-xr-xsrc/conf_mode/dhcp_server.py18
-rwxr-xr-xsrc/conf_mode/dhcpv6_relay.py13
-rwxr-xr-xsrc/conf_mode/dhcpv6_server.py2
-rwxr-xr-xsrc/conf_mode/dns_dynamic.py16
-rwxr-xr-xsrc/conf_mode/dns_forwarding.py63
-rwxr-xr-xsrc/conf_mode/firewall.py223
-rwxr-xr-xsrc/conf_mode/flow_accounting_conf.py34
-rwxr-xr-xsrc/conf_mode/high-availability.py40
-rwxr-xr-xsrc/conf_mode/http-api.py12
-rwxr-xr-xsrc/conf_mode/igmp_proxy.py15
-rwxr-xr-xsrc/conf_mode/interfaces-bonding.py8
-rwxr-xr-xsrc/conf_mode/interfaces-bridge.py26
-rwxr-xr-xsrc/conf_mode/interfaces-l2tpv3.py2
-rwxr-xr-xsrc/conf_mode/interfaces-openvpn.py15
-rwxr-xr-xsrc/conf_mode/interfaces-tunnel.py6
-rwxr-xr-xsrc/conf_mode/interfaces-vxlan.py4
-rwxr-xr-xsrc/conf_mode/interfaces-wireguard.py7
-rwxr-xr-xsrc/conf_mode/interfaces-wireless.py32
-rwxr-xr-xsrc/conf_mode/lldp.py37
-rwxr-xr-xsrc/conf_mode/load-balancing-haproxy.py14
-rwxr-xr-xsrc/conf_mode/load-balancing-wan.py51
-rwxr-xr-xsrc/conf_mode/nat.py34
-rwxr-xr-xsrc/conf_mode/nat66.py12
-rwxr-xr-xsrc/conf_mode/pki.py5
-rwxr-xr-xsrc/conf_mode/protocols_babel.py19
-rwxr-xr-xsrc/conf_mode/protocols_bfd.py17
-rwxr-xr-xsrc/conf_mode/protocols_bgp.py2
-rwxr-xr-xsrc/conf_mode/protocols_failover.py13
-rwxr-xr-xsrc/conf_mode/protocols_isis.py14
-rwxr-xr-xsrc/conf_mode/protocols_ospf.py73
-rwxr-xr-xsrc/conf_mode/protocols_ospfv3.py19
-rwxr-xr-xsrc/conf_mode/protocols_rip.py5
-rwxr-xr-xsrc/conf_mode/protocols_ripng.py5
-rwxr-xr-xsrc/conf_mode/protocols_rpki.py5
-rwxr-xr-xsrc/conf_mode/qos.py88
-rwxr-xr-xsrc/conf_mode/salt-minion.py5
-rwxr-xr-xsrc/conf_mode/service_config_sync.py10
-rwxr-xr-xsrc/conf_mode/service_console-server.py8
-rwxr-xr-xsrc/conf_mode/service_ids_fastnetmon.py10
-rwxr-xr-xsrc/conf_mode/service_monitoring_telegraf.py5
-rwxr-xr-xsrc/conf_mode/service_monitoring_zabbix-agent.py98
-rwxr-xr-xsrc/conf_mode/service_router-advert.py39
-rwxr-xr-xsrc/conf_mode/service_sla.py10
-rwxr-xr-xsrc/conf_mode/service_upnp.py7
-rwxr-xr-xsrc/conf_mode/service_webproxy.py19
-rwxr-xr-xsrc/conf_mode/snmp.py57
-rwxr-xr-xsrc/conf_mode/ssh.py6
-rwxr-xr-xsrc/conf_mode/system-ip.py9
-rwxr-xr-xsrc/conf_mode/system-ipv6.py10
-rwxr-xr-xsrc/conf_mode/system-login.py32
-rwxr-xr-xsrc/conf_mode/system-logs.py10
-rwxr-xr-xsrc/conf_mode/system-option.py27
-rwxr-xr-xsrc/conf_mode/system-syslog.py42
-rwxr-xr-xsrc/conf_mode/system_console.py10
-rwxr-xr-xsrc/conf_mode/system_sflow.py27
-rwxr-xr-xsrc/conf_mode/tftp_server.py12
-rwxr-xr-xsrc/conf_mode/vpn_ipsec.py90
-rwxr-xr-xsrc/conf_mode/vpn_openconnect.py86
-rwxr-xr-xsrc/conf_mode/vpp.py20
-rw-r--r--src/etc/dhcp/dhclient-exit-hooks.d/03-vyos-dhclient-hook (renamed from src/etc/dhcp/dhclient-exit-hooks.d/03-vyatta-dhclient-hook)3
-rwxr-xr-xsrc/helpers/vyos-domain-resolver.py10
-rwxr-xr-xsrc/init/vyos-router24
-rwxr-xr-xsrc/migration-scripts/bgp/0-to-12
-rwxr-xr-xsrc/migration-scripts/bgp/1-to-22
-rwxr-xr-xsrc/migration-scripts/bgp/2-to-32
-rwxr-xr-xsrc/migration-scripts/bgp/3-to-42
-rwxr-xr-xsrc/migration-scripts/config-management/0-to-12
-rwxr-xr-xsrc/migration-scripts/conntrack-sync/1-to-22
-rwxr-xr-xsrc/migration-scripts/conntrack/1-to-22
-rwxr-xr-xsrc/migration-scripts/conntrack/2-to-32
-rwxr-xr-xsrc/migration-scripts/container/0-to-12
-rwxr-xr-xsrc/migration-scripts/dhcp-relay/1-to-22
-rwxr-xr-xsrc/migration-scripts/dhcp-server/4-to-52
-rwxr-xr-xsrc/migration-scripts/dhcp-server/5-to-62
-rwxr-xr-xsrc/migration-scripts/dhcpv6-server/0-to-12
-rwxr-xr-xsrc/migration-scripts/dns-dynamic/0-to-12
-rwxr-xr-xsrc/migration-scripts/dns-forwarding/0-to-12
-rwxr-xr-xsrc/migration-scripts/dns-forwarding/1-to-22
-rwxr-xr-xsrc/migration-scripts/dns-forwarding/2-to-32
-rwxr-xr-xsrc/migration-scripts/dns-forwarding/3-to-42
-rwxr-xr-xsrc/migration-scripts/firewall/10-to-11374
-rwxr-xr-xsrc/migration-scripts/firewall/5-to-648
-rwxr-xr-xsrc/migration-scripts/firewall/6-to-72
-rwxr-xr-xsrc/migration-scripts/firewall/7-to-82
-rwxr-xr-xsrc/migration-scripts/firewall/8-to-92
-rwxr-xr-xsrc/migration-scripts/firewall/9-to-102
-rwxr-xr-xsrc/migration-scripts/flow-accounting/0-to-12
-rwxr-xr-xsrc/migration-scripts/https/2-to-32
-rwxr-xr-xsrc/migration-scripts/https/3-to-42
-rwxr-xr-xsrc/migration-scripts/ids/0-to-12
-rwxr-xr-xsrc/migration-scripts/interfaces/0-to-12
-rwxr-xr-xsrc/migration-scripts/interfaces/1-to-22
-rwxr-xr-xsrc/migration-scripts/interfaces/10-to-112
-rwxr-xr-xsrc/migration-scripts/interfaces/11-to-122
-rwxr-xr-xsrc/migration-scripts/interfaces/12-to-132
-rwxr-xr-xsrc/migration-scripts/interfaces/13-to-142
-rwxr-xr-xsrc/migration-scripts/interfaces/14-to-152
-rwxr-xr-xsrc/migration-scripts/interfaces/15-to-162
-rwxr-xr-xsrc/migration-scripts/interfaces/16-to-176
-rwxr-xr-xsrc/migration-scripts/interfaces/17-to-182
-rwxr-xr-xsrc/migration-scripts/interfaces/18-to-192
-rwxr-xr-xsrc/migration-scripts/interfaces/19-to-202
-rwxr-xr-xsrc/migration-scripts/interfaces/2-to-32
-rwxr-xr-xsrc/migration-scripts/interfaces/20-to-212
-rwxr-xr-xsrc/migration-scripts/interfaces/21-to-222
-rwxr-xr-xsrc/migration-scripts/interfaces/22-to-232
-rwxr-xr-xsrc/migration-scripts/interfaces/23-to-242
-rwxr-xr-xsrc/migration-scripts/interfaces/24-to-252
-rwxr-xr-xsrc/migration-scripts/interfaces/25-to-262
-rwxr-xr-xsrc/migration-scripts/interfaces/26-to-272
-rwxr-xr-xsrc/migration-scripts/interfaces/27-to-282
-rwxr-xr-xsrc/migration-scripts/interfaces/28-to-292
-rwxr-xr-xsrc/migration-scripts/interfaces/29-to-3054
-rwxr-xr-xsrc/migration-scripts/interfaces/3-to-42
-rwxr-xr-xsrc/migration-scripts/interfaces/4-to-52
-rwxr-xr-xsrc/migration-scripts/interfaces/5-to-62
-rwxr-xr-xsrc/migration-scripts/interfaces/6-to-72
-rwxr-xr-xsrc/migration-scripts/interfaces/7-to-82
-rwxr-xr-xsrc/migration-scripts/interfaces/8-to-92
-rwxr-xr-xsrc/migration-scripts/interfaces/9-to-102
-rwxr-xr-xsrc/migration-scripts/ipoe-server/0-to-12
-rwxr-xr-xsrc/migration-scripts/ipsec/10-to-112
-rwxr-xr-xsrc/migration-scripts/ipsec/11-to-122
-rwxr-xr-xsrc/migration-scripts/ipsec/4-to-52
-rwxr-xr-xsrc/migration-scripts/ipsec/5-to-62
-rwxr-xr-xsrc/migration-scripts/ipsec/6-to-72
-rwxr-xr-xsrc/migration-scripts/ipsec/7-to-82
-rwxr-xr-xsrc/migration-scripts/ipsec/8-to-92
-rwxr-xr-xsrc/migration-scripts/ipsec/9-to-102
-rwxr-xr-xsrc/migration-scripts/isis/0-to-12
-rwxr-xr-xsrc/migration-scripts/isis/1-to-22
-rwxr-xr-xsrc/migration-scripts/isis/2-to-32
-rwxr-xr-xsrc/migration-scripts/l2tp/0-to-12
-rwxr-xr-xsrc/migration-scripts/l2tp/1-to-22
-rwxr-xr-xsrc/migration-scripts/l2tp/2-to-32
-rwxr-xr-xsrc/migration-scripts/l2tp/3-to-42
-rwxr-xr-xsrc/migration-scripts/lldp/0-to-12
-rwxr-xr-xsrc/migration-scripts/monitoring/0-to-12
-rwxr-xr-xsrc/migration-scripts/nat/4-to-52
-rwxr-xr-xsrc/migration-scripts/nat66/0-to-12
-rwxr-xr-xsrc/migration-scripts/ntp/0-to-12
-rwxr-xr-xsrc/migration-scripts/ntp/1-to-22
-rwxr-xr-xsrc/migration-scripts/ntp/2-to-32
-rwxr-xr-xsrc/migration-scripts/openconnect/0-to-12
-rwxr-xr-xsrc/migration-scripts/openconnect/1-to-22
-rwxr-xr-xsrc/migration-scripts/ospf/0-to-12
-rwxr-xr-xsrc/migration-scripts/ospf/1-to-22
-rwxr-xr-xsrc/migration-scripts/policy/0-to-12
-rwxr-xr-xsrc/migration-scripts/policy/1-to-22
-rwxr-xr-xsrc/migration-scripts/policy/2-to-32
-rwxr-xr-xsrc/migration-scripts/policy/3-to-42
-rwxr-xr-xsrc/migration-scripts/policy/4-to-52
-rwxr-xr-xsrc/migration-scripts/pppoe-server/0-to-12
-rwxr-xr-xsrc/migration-scripts/pppoe-server/1-to-22
-rwxr-xr-xsrc/migration-scripts/pppoe-server/2-to-32
-rwxr-xr-xsrc/migration-scripts/pppoe-server/3-to-42
-rwxr-xr-xsrc/migration-scripts/pppoe-server/4-to-52
-rwxr-xr-xsrc/migration-scripts/pppoe-server/5-to-62
-rwxr-xr-xsrc/migration-scripts/pptp/0-to-12
-rwxr-xr-xsrc/migration-scripts/pptp/1-to-22
-rwxr-xr-xsrc/migration-scripts/qos/1-to-22
-rwxr-xr-xsrc/migration-scripts/quagga/10-to-112
-rwxr-xr-xsrc/migration-scripts/quagga/2-to-32
-rwxr-xr-xsrc/migration-scripts/quagga/3-to-42
-rwxr-xr-xsrc/migration-scripts/quagga/4-to-52
-rwxr-xr-xsrc/migration-scripts/quagga/5-to-62
-rwxr-xr-xsrc/migration-scripts/quagga/6-to-72
-rwxr-xr-xsrc/migration-scripts/quagga/7-to-82
-rwxr-xr-xsrc/migration-scripts/quagga/8-to-92
-rwxr-xr-xsrc/migration-scripts/quagga/9-to-102
-rwxr-xr-xsrc/migration-scripts/rip/0-to-12
-rwxr-xr-xsrc/migration-scripts/rpki/0-to-12
-rwxr-xr-xsrc/migration-scripts/salt/0-to-12
-rwxr-xr-xsrc/migration-scripts/snmp/0-to-12
-rwxr-xr-xsrc/migration-scripts/snmp/1-to-22
-rwxr-xr-xsrc/migration-scripts/snmp/2-to-32
-rwxr-xr-xsrc/migration-scripts/ssh/0-to-12
-rwxr-xr-xsrc/migration-scripts/ssh/1-to-22
-rwxr-xr-xsrc/migration-scripts/sstp/0-to-12
-rwxr-xr-xsrc/migration-scripts/sstp/1-to-22
-rwxr-xr-xsrc/migration-scripts/sstp/2-to-32
-rwxr-xr-xsrc/migration-scripts/sstp/3-to-42
-rwxr-xr-xsrc/migration-scripts/system/10-to-112
-rwxr-xr-xsrc/migration-scripts/system/11-to-122
-rwxr-xr-xsrc/migration-scripts/system/12-to-132
-rwxr-xr-xsrc/migration-scripts/system/13-to-142
-rwxr-xr-xsrc/migration-scripts/system/14-to-152
-rwxr-xr-xsrc/migration-scripts/system/15-to-162
-rwxr-xr-xsrc/migration-scripts/system/16-to-172
-rwxr-xr-xsrc/migration-scripts/system/17-to-182
-rwxr-xr-xsrc/migration-scripts/system/18-to-192
-rwxr-xr-xsrc/migration-scripts/system/19-to-202
-rwxr-xr-xsrc/migration-scripts/system/20-to-212
-rwxr-xr-xsrc/migration-scripts/system/21-to-222
-rwxr-xr-xsrc/migration-scripts/system/22-to-232
-rwxr-xr-xsrc/migration-scripts/system/23-to-242
-rwxr-xr-xsrc/migration-scripts/system/24-to-252
-rwxr-xr-xsrc/migration-scripts/system/25-to-262
-rwxr-xr-xsrc/migration-scripts/system/6-to-72
-rwxr-xr-xsrc/migration-scripts/system/7-to-82
-rwxr-xr-xsrc/migration-scripts/system/8-to-92
-rwxr-xr-xsrc/migration-scripts/vrf/0-to-12
-rwxr-xr-xsrc/migration-scripts/vrf/1-to-22
-rwxr-xr-xsrc/migration-scripts/vrf/2-to-32
-rwxr-xr-xsrc/migration-scripts/vrrp/1-to-22
-rwxr-xr-xsrc/migration-scripts/vrrp/2-to-32
-rwxr-xr-xsrc/migration-scripts/vrrp/3-to-42
-rwxr-xr-xsrc/migration-scripts/webproxy/1-to-22
-rwxr-xr-xsrc/op_mode/bridge.py43
-rwxr-xr-xsrc/op_mode/dhcp.py96
-rwxr-xr-xsrc/op_mode/firewall.py223
-rwxr-xr-xsrc/op_mode/pki.py20
-rwxr-xr-xsrc/op_mode/show_openconnect_otp.py38
-rw-r--r--src/op_mode/show_techsupport_report.py3
-rwxr-xr-xsrc/op_mode/webproxy_update_blacklist.sh9
-rw-r--r--src/systemd/dhclient@.service13
-rw-r--r--src/systemd/dhcp6c@.service14
-rw-r--r--src/tests/test_initial_setup.py6
-rw-r--r--src/tests/test_utils.py (renamed from src/tests/test_util.py)3
-rw-r--r--src/tests/test_utils_network.py50
-rw-r--r--src/tests/test_validate.py50
-rwxr-xr-xsrc/validators/ipv6-link-local2
227 files changed, 1462 insertions, 1609 deletions
diff --git a/src/conf_mode/bcast_relay.py b/src/conf_mode/bcast_relay.py
index ced5d212e..31c552f5a 100755
--- a/src/conf_mode/bcast_relay.py
+++ b/src/conf_mode/bcast_relay.py
@@ -24,7 +24,7 @@ from vyos.config import Config
from vyos.configverify import verify_interface_exists
from vyos.template import render
from vyos.utils.process import call
-from vyos.validate import is_afi_configured
+from vyos.utils.network import is_afi_configured
from vyos import ConfigError
from vyos import airbag
airbag.enable()
diff --git a/src/conf_mode/conntrack.py b/src/conf_mode/conntrack.py
index 2a77540f7..9c43640a9 100755
--- a/src/conf_mode/conntrack.py
+++ b/src/conf_mode/conntrack.py
@@ -20,7 +20,6 @@ import re
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.firewall import find_nftables_rule
from vyos.firewall import remove_nftables_rule
from vyos.utils.process import process_named_running
@@ -28,7 +27,6 @@ from vyos.utils.dict import dict_search
from vyos.utils.process import cmd
from vyos.utils.process import run
from vyos.template import render
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -77,16 +75,8 @@ def get_config(config=None):
base = ['system', 'conntrack']
conntrack = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True)
-
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- if 'timeout' in default_values and 'custom' in default_values['timeout']:
- del default_values['timeout']['custom']
- conntrack = dict_merge(default_values, conntrack)
+ get_first_key=True,
+ with_recursive_defaults=True)
return conntrack
diff --git a/src/conf_mode/conntrack_sync.py b/src/conf_mode/conntrack_sync.py
index a83c2274d..4fb2ce27f 100755
--- a/src/conf_mode/conntrack_sync.py
+++ b/src/conf_mode/conntrack_sync.py
@@ -18,7 +18,6 @@ import os
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configverify import verify_interface_exists
from vyos.utils.dict import dict_search
from vyos.utils.process import process_named_running
@@ -27,8 +26,7 @@ from vyos.utils.process import call
from vyos.utils.process import run
from vyos.template import render
from vyos.template import get_ipv4
-from vyos.validate import is_addr_assigned
-from vyos.xml import defaults
+from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -50,11 +48,7 @@ def get_config(config=None):
return None
conntrack = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- conntrack = dict_merge(default_values, conntrack)
+ get_first_key=True, with_defaults=True)
conntrack['hash_size'] = read_file('/sys/module/nf_conntrack/parameters/hashsize')
conntrack['table_size'] = read_file('/proc/sys/net/netfilter/nf_conntrack_max')
diff --git a/src/conf_mode/container.py b/src/conf_mode/container.py
index 3378aac63..ed7cc809c 100755
--- a/src/conf_mode/container.py
+++ b/src/conf_mode/container.py
@@ -37,7 +37,7 @@ from vyos.template import inc_ip
from vyos.template import is_ipv4
from vyos.template import is_ipv6
from vyos.template import render
-from vyos.xml import defaults
+from vyos.xml_ref import default_value
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -66,58 +66,26 @@ def get_config(config=None):
base = ['container']
container = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True, no_tag_node_value_mangle=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- # container base default values can not be merged here - remove and add them later
- if 'name' in default_values:
- del default_values['name']
- # registry will be handled below
- if 'registry' in default_values:
- del default_values['registry']
- container = dict_merge(default_values, container)
-
- # Merge per-container default values
- if 'name' in container:
- default_values = defaults(base + ['name'])
- if 'port' in default_values:
- del default_values['port']
- if 'volume' in default_values:
- del default_values['volume']
- for name in container['name']:
- container['name'][name] = dict_merge(default_values, container['name'][name])
-
- # T5047: Any container related configuration changed? We only
- # wan't to restart the required containers and not all of them ...
- tmp = is_node_changed(conf, base + ['name', name])
- if tmp:
- if 'container_restart' not in container:
- container['container_restart'] = [name]
- else:
- container['container_restart'].append(name)
-
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- if 'port' in container['name'][name]:
- for port in container['name'][name]['port']:
- default_values_port = defaults(base + ['name', 'port'])
- container['name'][name]['port'][port] = dict_merge(
- default_values_port, container['name'][name]['port'][port])
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- if 'volume' in container['name'][name]:
- for volume in container['name'][name]['volume']:
- default_values_volume = defaults(base + ['name', 'volume'])
- container['name'][name]['volume'][volume] = dict_merge(
- default_values_volume, container['name'][name]['volume'][volume])
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True)
+
+ for name in container.get('name', []):
+ # T5047: Any container related configuration changed? We only
+ # wan't to restart the required containers and not all of them ...
+ tmp = is_node_changed(conf, base + ['name', name])
+ if tmp:
+ if 'container_restart' not in container:
+ container['container_restart'] = [name]
+ else:
+ container['container_restart'].append(name)
# registry is a tagNode with default values - merge the list from
# default_values['registry'] into the tagNode variables
if 'registry' not in container:
container.update({'registry' : {}})
- default_values = defaults(base)
- for registry in default_values['registry'].split():
+ default_values = default_value(base + ['registry'])
+ for registry in default_values:
tmp = {registry : {}}
container['registry'] = dict_merge(tmp, container['registry'])
diff --git a/src/conf_mode/dhcp_relay.py b/src/conf_mode/dhcp_relay.py
index fd39bd9fe..37d708847 100755
--- a/src/conf_mode/dhcp_relay.py
+++ b/src/conf_mode/dhcp_relay.py
@@ -20,12 +20,10 @@ from sys import exit
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.base import Warning
from vyos.utils.process import call
from vyos.utils.dict import dict_search
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -41,11 +39,9 @@ def get_config(config=None):
if not conf.exists(base):
return None
- relay = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- relay = dict_merge(default_values, relay)
+ relay = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
return relay
diff --git a/src/conf_mode/dhcp_server.py b/src/conf_mode/dhcp_server.py
index c29270367..280057f04 100755
--- a/src/conf_mode/dhcp_server.py
+++ b/src/conf_mode/dhcp_server.py
@@ -23,14 +23,12 @@ from netaddr import IPRange
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.utils.dict import dict_search
from vyos.utils.process import call
from vyos.utils.process import run
-from vyos.validate import is_subnet_connected
-from vyos.validate import is_addr_assigned
-from vyos.xml import defaults
+from vyos.utils.network import is_subnet_connected
+from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -109,19 +107,15 @@ def get_config(config=None):
if not conf.exists(base):
return None
- dhcp = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True)
- # T2665: defaults include lease time per TAG node which need to be added to
- # individual subnet definitions
- default_values = defaults(base + ['shared-network-name', 'subnet'])
+ dhcp = conf.get_config_dict(base, key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True)
if 'shared_network_name' in dhcp:
for network, network_config in dhcp['shared_network_name'].items():
if 'subnet' in network_config:
for subnet, subnet_config in network_config['subnet'].items():
- if 'lease' not in subnet_config:
- dhcp['shared_network_name'][network]['subnet'][subnet] = dict_merge(
- default_values, dhcp['shared_network_name'][network]['subnet'][subnet])
-
# If exclude IP addresses are defined we need to slice them out of
# the defined ranges
if {'exclude', 'range'} <= set(subnet_config):
diff --git a/src/conf_mode/dhcpv6_relay.py b/src/conf_mode/dhcpv6_relay.py
index 0e7da6f89..6537ca3c2 100755
--- a/src/conf_mode/dhcpv6_relay.py
+++ b/src/conf_mode/dhcpv6_relay.py
@@ -19,14 +19,11 @@ import os
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.ifconfig import Interface
from vyos.template import render
from vyos.template import is_ipv6
from vyos.utils.process import call
-from vyos.utils.dict import dict_search
-from vyos.validate import is_ipv6_link_local
-from vyos.xml import defaults
+from vyos.utils.network import is_ipv6_link_local
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -42,11 +39,9 @@ def get_config(config=None):
if not conf.exists(base):
return None
- relay = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- relay = dict_merge(default_values, relay)
+ relay = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
return relay
diff --git a/src/conf_mode/dhcpv6_server.py b/src/conf_mode/dhcpv6_server.py
index f89ad5b9c..427001609 100755
--- a/src/conf_mode/dhcpv6_server.py
+++ b/src/conf_mode/dhcpv6_server.py
@@ -25,7 +25,7 @@ from vyos.template import render
from vyos.template import is_ipv6
from vyos.utils.process import call
from vyos.utils.dict import dict_search
-from vyos.validate import is_subnet_connected
+from vyos.utils.network import is_subnet_connected
from vyos import ConfigError
from vyos import airbag
airbag.enable()
diff --git a/src/conf_mode/dns_dynamic.py b/src/conf_mode/dns_dynamic.py
index d78eb70bc..ab80defe8 100755
--- a/src/conf_mode/dns_dynamic.py
+++ b/src/conf_mode/dns_dynamic.py
@@ -19,10 +19,8 @@ import os
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.utils.process import call
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -49,16 +47,10 @@ def get_config(config=None):
if not conf.exists(base_level):
return None
- dyndns = conf.get_config_dict(base_level, key_mangling=('-', '_'), get_first_key=True)
-
- if 'address' in dyndns:
- for address in dyndns['address']:
- # Apply service specific defaults (svc_type = ['rfc2136', 'service'])
- for svc_type in dyndns['address'][address]:
- default_values = defaults(base_level + ['address', svc_type])
- for svc_cfg in dyndns['address'][address][svc_type]:
- dyndns['address'][address][svc_type][svc_cfg] = dict_merge(
- default_values, dyndns['address'][address][svc_type][svc_cfg])
+ dyndns = conf.get_config_dict(base_level, key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True)
dyndns['config_file'] = config_file
return dyndns
diff --git a/src/conf_mode/dns_forwarding.py b/src/conf_mode/dns_forwarding.py
index 2d98bffe3..c186f47af 100755
--- a/src/conf_mode/dns_forwarding.py
+++ b/src/conf_mode/dns_forwarding.py
@@ -21,14 +21,12 @@ from sys import exit
from glob import glob
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.hostsd_client import Client as hostsd_client
from vyos.template import render
from vyos.template import bracketize_ipv6
from vyos.utils.process import call
from vyos.utils.permission import chown
from vyos.utils.dict import dict_search
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
@@ -52,31 +50,10 @@ def get_config(config=None):
if not conf.exists(base):
return None
- dns = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True, no_tag_node_value_mangle=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrieved.
- default_values = defaults(base)
- # T2665 due to how defaults under tag nodes work, we must clear these out before we merge
- del default_values['authoritative_domain']
- del default_values['name_server']
- del default_values['domain']['name_server']
- dns = dict_merge(default_values, dns)
-
- # T2665: we cleared default values for tag node 'name_server' above.
- # We now need to add them back back in a granular way.
- if 'name_server' in dns:
- default_values = defaults(base + ['name-server'])
- for server in dns['name_server']:
- dns['name_server'][server] = dict_merge(default_values, dns['name_server'][server])
-
- # T2665: we cleared default values for tag node 'domain' above.
- # We now need to add them back back in a granular way.
- if 'domain' in dns:
- default_values = defaults(base + ['domain', 'name-server'])
- for domain in dns['domain'].keys():
- for server in dns['domain'][domain]['name_server']:
- dns['domain'][domain]['name_server'][server] = dict_merge(
- default_values, dns['domain'][domain]['name_server'][server])
+ dns = conf.get_config_dict(base, key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True)
# some additions to the default dictionary
if 'system' in dns:
@@ -109,9 +86,6 @@ def get_config(config=None):
rdata = recorddata[rtype][subnode]
if rtype in [ 'a', 'aaaa' ]:
- rdefaults = defaults(base + ['authoritative-domain', 'records', rtype]) # T2665
- rdata = dict_merge(rdefaults, rdata)
-
if not 'address' in rdata:
dns['authoritative_zone_errors'].append(f'{subnode}.{node}: at least one address is required')
continue
@@ -127,9 +101,6 @@ def get_config(config=None):
'value': address
})
elif rtype in ['cname', 'ptr', 'ns']:
- rdefaults = defaults(base + ['authoritative-domain', 'records', rtype]) # T2665
- rdata = dict_merge(rdefaults, rdata)
-
if not 'target' in rdata:
dns['authoritative_zone_errors'].append(f'{subnode}.{node}: target is required')
continue
@@ -141,18 +112,12 @@ def get_config(config=None):
'value': '{}.'.format(rdata['target'])
})
elif rtype == 'mx':
- rdefaults = defaults(base + ['authoritative-domain', 'records', rtype]) # T2665
- del rdefaults['server']
- rdata = dict_merge(rdefaults, rdata)
-
if not 'server' in rdata:
dns['authoritative_zone_errors'].append(f'{subnode}.{node}: at least one server is required')
continue
for servername in rdata['server']:
serverdata = rdata['server'][servername]
- serverdefaults = defaults(base + ['authoritative-domain', 'records', rtype, 'server']) # T2665
- serverdata = dict_merge(serverdefaults, serverdata)
zone['records'].append({
'name': subnode,
'type': rtype.upper(),
@@ -160,9 +125,6 @@ def get_config(config=None):
'value': '{} {}.'.format(serverdata['priority'], servername)
})
elif rtype == 'txt':
- rdefaults = defaults(base + ['authoritative-domain', 'records', rtype]) # T2665
- rdata = dict_merge(rdefaults, rdata)
-
if not 'value' in rdata:
dns['authoritative_zone_errors'].append(f'{subnode}.{node}: at least one value is required')
continue
@@ -175,9 +137,6 @@ def get_config(config=None):
'value': "\"{}\"".format(value.replace("\"", "\\\""))
})
elif rtype == 'spf':
- rdefaults = defaults(base + ['authoritative-domain', 'records', rtype]) # T2665
- rdata = dict_merge(rdefaults, rdata)
-
if not 'value' in rdata:
dns['authoritative_zone_errors'].append(f'{subnode}.{node}: value is required')
continue
@@ -189,19 +148,12 @@ def get_config(config=None):
'value': '"{}"'.format(rdata['value'].replace("\"", "\\\""))
})
elif rtype == 'srv':
- rdefaults = defaults(base + ['authoritative-domain', 'records', rtype]) # T2665
- del rdefaults['entry']
- rdata = dict_merge(rdefaults, rdata)
-
if not 'entry' in rdata:
dns['authoritative_zone_errors'].append(f'{subnode}.{node}: at least one entry is required')
continue
for entryno in rdata['entry']:
entrydata = rdata['entry'][entryno]
- entrydefaults = defaults(base + ['authoritative-domain', 'records', rtype, 'entry']) # T2665
- entrydata = dict_merge(entrydefaults, entrydata)
-
if not 'hostname' in entrydata:
dns['authoritative_zone_errors'].append(f'{subnode}.{node}: hostname is required for entry {entryno}')
continue
@@ -217,19 +169,12 @@ def get_config(config=None):
'value': '{} {} {} {}.'.format(entrydata['priority'], entrydata['weight'], entrydata['port'], entrydata['hostname'])
})
elif rtype == 'naptr':
- rdefaults = defaults(base + ['authoritative-domain', 'records', rtype]) # T2665
- del rdefaults['rule']
- rdata = dict_merge(rdefaults, rdata)
-
-
if not 'rule' in rdata:
dns['authoritative_zone_errors'].append(f'{subnode}.{node}: at least one rule is required')
continue
for ruleno in rdata['rule']:
ruledata = rdata['rule'][ruleno]
- ruledefaults = defaults(base + ['authoritative-domain', 'records', rtype, 'rule']) # T2665
- ruledata = dict_merge(ruledefaults, ruledata)
flags = ""
if 'lookup-srv' in ruledata:
flags += "S"
diff --git a/src/conf_mode/firewall.py b/src/conf_mode/firewall.py
index 07166d457..e946704b3 100755
--- a/src/conf_mode/firewall.py
+++ b/src/conf_mode/firewall.py
@@ -23,7 +23,6 @@ from sys import exit
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configdict import node_changed
from vyos.configdiff import get_config_diff, Diff
from vyos.configdep import set_dependents, call_dependents
@@ -37,7 +36,6 @@ from vyos.utils.dict import dict_search_args
from vyos.utils.dict import dict_search_recursive
from vyos.utils.process import process_named_running
from vyos.utils.process import rc_cmd
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -97,19 +95,22 @@ def geoip_updated(conf, firewall):
updated = False
for key, path in dict_search_recursive(firewall, 'geoip'):
- set_name = f'GEOIP_CC_{path[1]}_{path[3]}'
- if path[0] == 'name':
+ set_name = f'GEOIP_CC_{path[1]}_{path[2]}_{path[4]}'
+ if (path[0] == 'ipv4'):
out['name'].append(set_name)
- elif path[0] == 'ipv6_name':
+ elif (path[0] == 'ipv6'):
+ set_name = f'GEOIP_CC6_{path[1]}_{path[2]}_{path[4]}'
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[1]}_{path[3]}'
- if path[0] == 'name':
+ set_name = f'GEOIP_CC_{path[1]}_{path[2]}_{path[4]}'
+ if (path[0] == 'ipv4'):
out['deleted_name'].append(set_name)
- elif path[0] == 'ipv6-name':
+ elif (path[0] == 'ipv6'):
+ set_name = f'GEOIP_CC_{path[1]}_{path[2]}_{path[4]}'
out['deleted_ipv6_name'].append(set_name)
updated = True
@@ -125,54 +126,17 @@ def get_config(config=None):
conf = Config()
base = ['firewall']
- firewall = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True,
- no_tag_node_value_mangle=True)
-
- # We have gathered the dict representation of the CLI, but there are
- # default options which we need to update into the dictionary retrived.
- # XXX: T2665: we currently have no nice way for defaults under tag
- # nodes, thus we load the defaults "by hand"
- default_values = defaults(base)
- for tmp in ['name', 'ipv6_name']:
- if tmp in default_values:
- del default_values[tmp]
-
- if 'zone' in default_values:
- del default_values['zone']
-
- firewall = dict_merge(default_values, firewall)
-
- # Merge in defaults for IPv4 ruleset
- if 'name' in firewall:
- default_values = defaults(base + ['name'])
- for name in firewall['name']:
- firewall['name'][name] = dict_merge(default_values,
- firewall['name'][name])
-
- # Merge in defaults for IPv6 ruleset
- if 'ipv6_name' in firewall:
- default_values = defaults(base + ['ipv6-name'])
- for ipv6_name in firewall['ipv6_name']:
- firewall['ipv6_name'][ipv6_name] = dict_merge(default_values,
- firewall['ipv6_name'][ipv6_name])
-
- if 'zone' in firewall:
- default_values = defaults(base + ['zone'])
- for zone in firewall['zone']:
- firewall['zone'][zone] = dict_merge(default_values, firewall['zone'][zone])
+ firewall = conf.get_config_dict(base, key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True)
+
firewall['group_resync'] = bool('group' in firewall or node_changed(conf, base + ['group']))
if firewall['group_resync']:
# Update nat and policy-route as firewall groups were updated
set_dependents('group_resync', conf)
- if 'config_trap' in firewall and firewall['config_trap'] == 'enable':
- diff = get_config_diff(conf)
- firewall['trap_diff'] = diff.get_child_nodes_diff_str(base)
- firewall['trap_targets'] = conf.get_config_dict(['service', 'snmp', 'trap-target'],
- key_mangling=('-', '_'), get_first_key=True,
- no_tag_node_value_mangle=True)
-
firewall['geoip_updated'] = geoip_updated(conf, firewall)
fqdn_config_parse(firewall)
@@ -191,11 +155,11 @@ def verify_rule(firewall, rule_conf, ipv6):
raise ConfigError('jump-target defined, but action jump needed and it is not defined')
target = rule_conf['jump_target']
if not ipv6:
- if target not in dict_search_args(firewall, 'name'):
+ if target not in dict_search_args(firewall, 'ipv4', 'name'):
raise ConfigError(f'Invalid jump-target. Firewall name {target} does not exist on the system')
else:
- if target not in dict_search_args(firewall, 'ipv6_name'):
- raise ConfigError(f'Invalid jump-target. Firewall ipv6-name {target} does not exist on the system')
+ if target not in dict_search_args(firewall, 'ipv6', 'name'):
+ raise ConfigError(f'Invalid jump-target. Firewall ipv6 name {target} does not exist on the system')
if 'queue_options' in rule_conf:
if 'queue' not in rule_conf['action']:
@@ -312,10 +276,6 @@ def verify_nested_group(group_name, group, groups, seen):
verify_nested_group(g, groups[g], groups, seen)
def verify(firewall):
- if 'config_trap' in firewall and firewall['config_trap'] == 'enable':
- if not firewall['trap_targets']:
- raise ConfigError(f'Firewall config-trap enabled but "service snmp trap-target" is not defined')
-
if 'group' in firewall:
for group_type in nested_group_types:
if group_type in firewall['group']:
@@ -323,95 +283,45 @@ def verify(firewall):
for group_name, group in groups.items():
verify_nested_group(group_name, group, groups, [])
- for name in ['name', 'ipv6_name']:
- if name in firewall:
- for name_id, name_conf in firewall[name].items():
- if 'jump' in name_conf['default_action'] and 'default_jump_target' not in name_conf:
- raise ConfigError('default-action set to jump, but no default-jump-target specified')
- if 'default_jump_target' in name_conf:
- target = name_conf['default_jump_target']
- if 'jump' not in name_conf['default_action']:
- raise ConfigError('default-jump-target defined,but default-action jump needed and it is not defined')
- if name_conf['default_jump_target'] == name_id:
- raise ConfigError(f'Loop detected on default-jump-target.')
- ## Now need to check that default-jump-target exists (other firewall chain/name)
- if target not in dict_search_args(firewall, name):
- raise ConfigError(f'Invalid jump-target. Firewall {name} {target} does not exist on the system')
-
- if 'rule' in name_conf:
- for rule_id, rule_conf in name_conf['rule'].items():
- verify_rule(firewall, rule_conf, name == 'ipv6_name')
-
- if 'interface' in firewall:
- for ifname, if_firewall in firewall['interface'].items():
- # verify ifname needs to be disabled, dynamic devices come up later
- # verify_interface_exists(ifname)
-
- for direction in ['in', 'out', 'local']:
- name = dict_search_args(if_firewall, direction, 'name')
- ipv6_name = dict_search_args(if_firewall, direction, 'ipv6_name')
-
- if name and dict_search_args(firewall, 'name', name) == None:
- raise ConfigError(f'Invalid firewall name "{name}" referenced on interface {ifname}')
-
- if ipv6_name and dict_search_args(firewall, 'ipv6_name', ipv6_name) == None:
- raise ConfigError(f'Invalid firewall ipv6-name "{ipv6_name}" referenced on interface {ifname}')
-
- local_zone = False
- zone_interfaces = []
-
- if 'zone' in firewall:
- for zone, zone_conf in firewall['zone'].items():
- if 'local_zone' not in zone_conf and 'interface' not in zone_conf:
- raise ConfigError(f'Zone "{zone}" has no interfaces and is not the local zone')
-
- if 'local_zone' in zone_conf:
- if local_zone:
- raise ConfigError('There cannot be multiple local zones')
- if 'interface' in zone_conf:
- raise ConfigError('Local zone cannot have interfaces assigned')
- if 'intra_zone_filtering' in zone_conf:
- raise ConfigError('Local zone cannot use intra-zone-filtering')
- local_zone = True
-
- if 'interface' in zone_conf:
- found_duplicates = [intf for intf in zone_conf['interface'] if intf in zone_interfaces]
-
- if found_duplicates:
- raise ConfigError(f'Interfaces cannot be assigned to multiple zones')
-
- zone_interfaces += zone_conf['interface']
-
- if 'intra_zone_filtering' in zone_conf:
- intra_zone = zone_conf['intra_zone_filtering']
-
- if len(intra_zone) > 1:
- raise ConfigError('Only one intra-zone-filtering action must be specified')
-
- if 'firewall' in intra_zone:
- v4_name = dict_search_args(intra_zone, 'firewall', 'name')
- if v4_name and not dict_search_args(firewall, 'name', v4_name):
- raise ConfigError(f'Firewall name "{v4_name}" does not exist')
-
- v6_name = dict_search_args(intra_zone, 'firewall', 'ipv6_name')
- if v6_name and not dict_search_args(firewall, 'ipv6_name', v6_name):
- raise ConfigError(f'Firewall ipv6-name "{v6_name}" does not exist')
-
- if not v4_name and not v6_name:
- raise ConfigError('No firewall names specified for intra-zone-filtering')
-
- if 'from' in zone_conf:
- for from_zone, from_conf in zone_conf['from'].items():
- if from_zone not in firewall['zone']:
- raise ConfigError(f'Zone "{zone}" refers to a non-existent or deleted zone "{from_zone}"')
-
- v4_name = dict_search_args(from_conf, 'firewall', 'name')
- if v4_name and not dict_search_args(firewall, 'name', v4_name):
- raise ConfigError(f'Firewall name "{v4_name}" does not exist')
-
- v6_name = dict_search_args(from_conf, 'firewall', 'ipv6_name')
- if v6_name and not dict_search_args(firewall, 'ipv6_name', v6_name):
- raise ConfigError(f'Firewall ipv6-name "{v6_name}" does not exist')
+ if 'ipv4' in firewall:
+ for name in ['name','forward','input','output']:
+ if name in firewall['ipv4']:
+ for name_id, name_conf in firewall['ipv4'][name].items():
+ if 'jump' in name_conf['default_action'] and 'default_jump_target' not in name_conf:
+ raise ConfigError('default-action set to jump, but no default-jump-target specified')
+ if 'default_jump_target' in name_conf:
+ target = name_conf['default_jump_target']
+ if 'jump' not in name_conf['default_action']:
+ raise ConfigError('default-jump-target defined, but default-action jump needed and it is not defined')
+ if name_conf['default_jump_target'] == name_id:
+ raise ConfigError(f'Loop detected on default-jump-target.')
+ ## Now need to check that default-jump-target exists (other firewall chain/name)
+ if target not in dict_search_args(firewall['ipv4'], 'name'):
+ raise ConfigError(f'Invalid jump-target. Firewall name {target} does not exist on the system')
+
+ if 'rule' in name_conf:
+ for rule_id, rule_conf in name_conf['rule'].items():
+ verify_rule(firewall, rule_conf, False)
+
+ if 'ipv6' in firewall:
+ for name in ['name','forward','input','output']:
+ if name in firewall['ipv6']:
+ for name_id, name_conf in firewall['ipv6'][name].items():
+ if 'jump' in name_conf['default_action'] and 'default_jump_target' not in name_conf:
+ raise ConfigError('default-action set to jump, but no default-jump-target specified')
+ if 'default_jump_target' in name_conf:
+ target = name_conf['default_jump_target']
+ if 'jump' not in name_conf['default_action']:
+ raise ConfigError('default-jump-target defined, but default-action jump needed and it is not defined')
+ if name_conf['default_jump_target'] == name_id:
+ raise ConfigError(f'Loop detected on default-jump-target.')
+ ## Now need to check that default-jump-target exists (other firewall chain/name)
+ if target not in dict_search_args(firewall['ipv6'], 'name'):
+ raise ConfigError(f'Invalid jump-target. Firewall name {target} does not exist on the system')
+
+ if 'rule' in name_conf:
+ for rule_id, rule_conf in name_conf['rule'].items():
+ verify_rule(firewall, rule_conf, True)
return None
@@ -419,19 +329,6 @@ def generate(firewall):
if not os.path.exists(nftables_conf):
firewall['first_install'] = True
- if 'zone' in firewall:
- for local_zone, local_zone_conf in firewall['zone'].items():
- if 'local_zone' not in local_zone_conf:
- continue
-
- local_zone_conf['from_local'] = {}
-
- for zone, zone_conf in firewall['zone'].items():
- if zone == local_zone or 'from' not in zone_conf:
- continue
- if local_zone in zone_conf['from']:
- local_zone_conf['from_local'][zone] = zone_conf['from'][local_zone]
-
render(nftables_conf, 'firewall/nftables.j2', firewall)
return None
@@ -440,9 +337,8 @@ def apply_sysfs(firewall):
paths = glob(conf['sysfs'])
value = None
- if name in firewall:
- conf_value = firewall[name]
-
+ if name in firewall['global_options']:
+ conf_value = firewall['global_options'][name]
if conf_value in conf:
value = conf[conf_value]
elif conf_value == 'enable':
@@ -459,9 +355,6 @@ def post_apply_trap(firewall):
if 'first_install' in firewall:
return None
- if 'config_trap' not in firewall or firewall['config_trap'] != 'enable':
- return None
-
if not process_named_running('snmpd'):
return None
diff --git a/src/conf_mode/flow_accounting_conf.py b/src/conf_mode/flow_accounting_conf.py
index bfe906c87..71acd69fa 100755
--- a/src/conf_mode/flow_accounting_conf.py
+++ b/src/conf_mode/flow_accounting_conf.py
@@ -22,14 +22,13 @@ from ipaddress import ip_address
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
+from vyos.config import config_dict_merge
from vyos.configverify import verify_vrf
from vyos.ifconfig import Section
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.process import cmd
-from vyos.validate import is_addr_assigned
-from vyos.xml import defaults
+from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -128,30 +127,19 @@ def get_config(config=None):
flow_accounting = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
+ # We have gathered the dict representation of the CLI, but there are
+ # default values which we need to conditionally update into the
+ # dictionary retrieved.
+ default_values = conf.get_config_defaults(**flow_accounting.kwargs,
+ recursive=True)
- # delete individual flow type default - should only be added if user uses
- # this feature
+ # delete individual flow type defaults - should only be added if user
+ # sets this feature
for flow_type in ['sflow', 'netflow']:
- if flow_type in default_values:
+ if flow_type not in flow_accounting and flow_type in default_values:
del default_values[flow_type]
- flow_accounting = dict_merge(default_values, flow_accounting)
- for flow_type in ['sflow', 'netflow']:
- if flow_type in flow_accounting:
- default_values = defaults(base + [flow_type])
- # we need to merge individual server configurations
- if 'server' in default_values:
- del default_values['server']
- flow_accounting[flow_type] = dict_merge(default_values, flow_accounting[flow_type])
-
- if 'server' in flow_accounting[flow_type]:
- default_values = defaults(base + [flow_type, 'server'])
- for server in flow_accounting[flow_type]['server']:
- flow_accounting[flow_type]['server'][server] = dict_merge(
- default_values,flow_accounting[flow_type]['server'][server])
+ flow_accounting = config_dict_merge(default_values, flow_accounting)
return flow_accounting
diff --git a/src/conf_mode/high-availability.py b/src/conf_mode/high-availability.py
index 0cbd4c49c..626a3757e 100755
--- a/src/conf_mode/high-availability.py
+++ b/src/conf_mode/high-availability.py
@@ -14,7 +14,6 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
from sys import exit
from ipaddress import ip_interface
@@ -23,14 +22,11 @@ from ipaddress import IPv6Interface
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.ifconfig.vrrp import VRRP
from vyos.template import render
from vyos.template import is_ipv4
from vyos.template import is_ipv6
from vyos.utils.process import call
-from vyos.utils.dict import dict_search
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -42,42 +38,12 @@ def get_config(config=None):
conf = Config()
base = ['high-availability']
- base_vrrp = ['high-availability', 'vrrp']
if not conf.exists(base):
return None
ha = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True, no_tag_node_value_mangle=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- if 'vrrp' in ha:
- if dict_search('vrrp.global_parameters.garp', ha) != None:
- default_values = defaults(base_vrrp + ['global-parameters', 'garp'])
- ha['vrrp']['global_parameters']['garp'] = dict_merge(
- default_values, ha['vrrp']['global_parameters']['garp'])
-
- if 'group' in ha['vrrp']:
- default_values = defaults(base_vrrp + ['group'])
- default_values_garp = defaults(base_vrrp + ['group', 'garp'])
-
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- if 'garp' in default_values:
- del default_values['garp']
- for group in ha['vrrp']['group']:
- ha['vrrp']['group'][group] = dict_merge(default_values, ha['vrrp']['group'][group])
-
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- if 'garp' in ha['vrrp']['group'][group]:
- ha['vrrp']['group'][group]['garp'] = dict_merge(
- default_values_garp, ha['vrrp']['group'][group]['garp'])
-
- # Merge per virtual-server default values
- if 'virtual_server' in ha:
- default_values = defaults(base + ['virtual-server'])
- for vs in ha['virtual_server']:
- ha['virtual_server'][vs] = dict_merge(default_values, ha['virtual_server'][vs])
+ no_tag_node_value_mangle=True,
+ get_first_key=True, with_defaults=True)
## Get the sync group used for conntrack-sync
conntrack_path = ['service', 'conntrack-sync', 'failover-mechanism', 'vrrp', 'sync-group']
@@ -112,7 +78,7 @@ def verify(ha):
from vyos.utils.dict import check_mutually_exclusive_options
try:
check_mutually_exclusive_options(group_config["health_check"], health_check_types, required=True)
- except ValueError as e:
+ except ValueError:
Warning(f'Health check configuration for VRRP group "{group}" will remain unused ' \
f'until it has one of the following options: {health_check_types}')
# XXX: health check has default options so we need to remove it
diff --git a/src/conf_mode/http-api.py b/src/conf_mode/http-api.py
index 7bdf448a3..793a90d88 100755
--- a/src/conf_mode/http-api.py
+++ b/src/conf_mode/http-api.py
@@ -24,12 +24,9 @@ from copy import deepcopy
import vyos.defaults
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configdep import set_dependents, call_dependents
from vyos.template import render
-from vyos.utils.process import cmd
from vyos.utils.process import call
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -72,8 +69,9 @@ def get_config(config=None):
return None
api_dict = conf.get_config_dict(base, key_mangling=('-', '_'),
- no_tag_node_value_mangle=True,
- get_first_key=True)
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True)
# One needs to 'flatten' the keys dict from the config into the
# http-api.conf format for api_keys:
@@ -93,8 +91,8 @@ def get_config(config=None):
if 'api_keys' in api_dict:
keys_added = True
- if 'graphql' in api_dict:
- api_dict = dict_merge(defaults(base), api_dict)
+ if api_dict.from_defaults(['graphql']):
+ del api_dict['graphql']
http_api.update(api_dict)
diff --git a/src/conf_mode/igmp_proxy.py b/src/conf_mode/igmp_proxy.py
index 4ec2f1835..40db417dd 100755
--- a/src/conf_mode/igmp_proxy.py
+++ b/src/conf_mode/igmp_proxy.py
@@ -21,11 +21,9 @@ from netifaces import interfaces
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.dict import dict_search
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -39,16 +37,9 @@ def get_config(config=None):
conf = Config()
base = ['protocols', 'igmp-proxy']
- igmp_proxy = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
-
- if 'interface' in igmp_proxy:
- # T2665: we must add the tagNode defaults individually until this is
- # moved to the base class
- default_values = defaults(base + ['interface'])
- for interface in igmp_proxy['interface']:
- igmp_proxy['interface'][interface] = dict_merge(default_values,
- igmp_proxy['interface'][interface])
-
+ igmp_proxy = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_defaults=True)
if conf.exists(['protocols', 'igmp']):
igmp_proxy.update({'igmp_configured': ''})
diff --git a/src/conf_mode/interfaces-bonding.py b/src/conf_mode/interfaces-bonding.py
index c2a569fa9..0bd306ed0 100755
--- a/src/conf_mode/interfaces-bonding.py
+++ b/src/conf_mode/interfaces-bonding.py
@@ -36,8 +36,8 @@ from vyos.configverify import verify_vrf
from vyos.ifconfig import BondIf
from vyos.ifconfig import Section
from vyos.utils.dict import dict_search
-from vyos.validate import has_address_configured
-from vyos.validate import has_vrf_configured
+from vyos.configdict import has_address_configured
+from vyos.configdict import has_vrf_configured
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -195,11 +195,11 @@ def verify(bond):
raise ConfigError(error_msg + 'it does not exist!')
if 'is_bridge_member' in interface_config:
- tmp = interface_config['is_bridge_member']
+ tmp = next(iter(interface_config['is_bridge_member']))
raise ConfigError(error_msg + f'it is already a member of bridge "{tmp}"!')
if 'is_bond_member' in interface_config:
- tmp = interface_config['is_bond_member']
+ tmp = next(iter(interface_config['is_bond_member']))
raise ConfigError(error_msg + f'it is already a member of bond "{tmp}"!')
if 'is_source_interface' in interface_config:
diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py
index 087ead20a..c82f01e53 100755
--- a/src/conf_mode/interfaces-bridge.py
+++ b/src/conf_mode/interfaces-bridge.py
@@ -14,10 +14,7 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-import os
-
from sys import exit
-from netifaces import interfaces
from vyos.config import Config
from vyos.configdict import get_interface_dict
@@ -25,16 +22,13 @@ from vyos.configdict import node_changed
from vyos.configdict import is_member
from vyos.configdict import is_source_interface
from vyos.configdict import has_vlan_subinterface_configured
-from vyos.configdict import dict_merge
from vyos.configverify import verify_dhcpv6
from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_vrf
from vyos.ifconfig import BridgeIf
-from vyos.validate import has_address_configured
-from vyos.validate import has_vrf_configured
-from vyos.xml import defaults
+from vyos.configdict import has_address_configured
+from vyos.configdict import has_vrf_configured
-from vyos.utils.process import cmd
from vyos.utils.dict import dict_search
from vyos import ConfigError
@@ -61,22 +55,8 @@ def get_config(config=None):
else:
bridge.update({'member' : {'interface_remove' : tmp }})
- if dict_search('member.interface', bridge) != None:
- # XXX: T2665: we need a copy of the dict keys for iteration, else we will get:
- # RuntimeError: dictionary changed size during iteration
+ if dict_search('member.interface', bridge) is not None:
for interface in list(bridge['member']['interface']):
- for key in ['cost', 'priority']:
- if interface == key:
- del bridge['member']['interface'][key]
- continue
-
- # the default dictionary is not properly paged into the dict (see T2665)
- # thus we will ammend it ourself
- default_member_values = defaults(base + ['member', 'interface'])
- for interface,interface_config in bridge['member']['interface'].items():
- bridge['member']['interface'][interface] = dict_merge(
- default_member_values, bridge['member']['interface'][interface])
-
# Check if member interface is already member of another bridge
tmp = is_member(conf, interface, 'bridge')
if tmp and bridge['ifname'] not in tmp:
diff --git a/src/conf_mode/interfaces-l2tpv3.py b/src/conf_mode/interfaces-l2tpv3.py
index 6efeac302..e1db3206e 100755
--- a/src/conf_mode/interfaces-l2tpv3.py
+++ b/src/conf_mode/interfaces-l2tpv3.py
@@ -29,7 +29,7 @@ from vyos.configverify import verify_mirror_redirect
from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import L2TPv3If
from vyos.utils.kernel import check_kmod
-from vyos.validate import is_addr_assigned
+from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import airbag
airbag.enable()
diff --git a/src/conf_mode/interfaces-openvpn.py b/src/conf_mode/interfaces-openvpn.py
index 3bef9b8f6..26b217d98 100755
--- a/src/conf_mode/interfaces-openvpn.py
+++ b/src/conf_mode/interfaces-openvpn.py
@@ -61,7 +61,7 @@ from vyos.utils.kernel import unload_kmod
from vyos.utils.process import call
from vyos.utils.permission import chown
from vyos.utils.process import cmd
-from vyos.validate import is_addr_assigned
+from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import airbag
@@ -189,16 +189,7 @@ def verify_pki(openvpn):
if dict_search_args(pki, 'certificate', tls['certificate'], 'private', 'password_protected') is not None:
raise ConfigError(f'Cannot use encrypted private key on openvpn interface {interface}')
- if mode == 'server' and 'dh_params' not in tls and not is_ec_private_key(pki, tls['certificate']):
- raise ConfigError('Must specify "tls dh-params" when not using EC keys in server mode')
-
if 'dh_params' in tls:
- if 'dh' not in pki:
- raise ConfigError('There are no DH parameters in PKI configuration')
-
- if tls['dh_params'] not in pki['dh']:
- raise ConfigError(f'Invalid dh-params on openvpn interface {interface}')
-
pki_dh = pki['dh'][tls['dh_params']]
dh_params = load_dh_parameters(pki_dh['parameters'])
dh_numbers = dh_params.parameter_numbers()
@@ -207,6 +198,7 @@ def verify_pki(openvpn):
if dh_bits < 2048:
raise ConfigError(f'Minimum DH key-size is 2048 bits')
+
if 'auth_key' in tls or 'crypt_key' in tls:
if not dict_search_args(pki, 'openvpn', 'shared_secret'):
raise ConfigError('There are no openvpn shared-secrets in PKI configuration')
@@ -495,9 +487,6 @@ def verify(openvpn):
if openvpn['protocol'] == 'tcp-active':
raise ConfigError('Cannot specify "tcp-active" when "tls role" is "passive"')
- if not dict_search('tls.dh_params', openvpn):
- raise ConfigError('Must specify "tls dh-params" when "tls role" is "passive"')
-
if 'certificate' in openvpn['tls'] and is_ec_private_key(openvpn['pki'], openvpn['tls']['certificate']):
if 'dh_params' in openvpn['tls']:
print('Warning: using dh-params and EC keys simultaneously will ' \
diff --git a/src/conf_mode/interfaces-tunnel.py b/src/conf_mode/interfaces-tunnel.py
index 6a075970e..91aed9cc3 100755
--- a/src/conf_mode/interfaces-tunnel.py
+++ b/src/conf_mode/interfaces-tunnel.py
@@ -55,6 +55,9 @@ def get_config(config=None):
tmp = is_node_changed(conf, base + [ifname, 'encapsulation'])
if tmp: tunnel.update({'encapsulation_changed': {}})
+ tmp = is_node_changed(conf, base + [ifname, 'parameters', 'ip', 'key'])
+ if tmp: tunnel.update({'key_changed': {}})
+
# We also need to inspect other configured tunnels as there are Kernel
# restrictions where we need to comply. E.g. GRE tunnel key can't be used
# twice, or with multiple GRE tunnels to the same location we must specify
@@ -197,7 +200,8 @@ def apply(tunnel):
remote = dict_search('linkinfo.info_data.remote', tmp)
if ('deleted' in tunnel or 'encapsulation_changed' in tunnel or encap in
- ['gretap', 'ip6gretap', 'erspan', 'ip6erspan'] or remote in ['any']):
+ ['gretap', 'ip6gretap', 'erspan', 'ip6erspan'] or remote in ['any'] or
+ 'key_changed' in tunnel):
if interface in interfaces():
tmp = Interface(interface)
tmp.remove()
diff --git a/src/conf_mode/interfaces-vxlan.py b/src/conf_mode/interfaces-vxlan.py
index b1536148c..a3b0867e0 100755
--- a/src/conf_mode/interfaces-vxlan.py
+++ b/src/conf_mode/interfaces-vxlan.py
@@ -87,8 +87,8 @@ def verify(vxlan):
raise ConfigError('Multicast VXLAN requires an underlaying interface')
verify_source_interface(vxlan)
- if not any(tmp in ['group', 'remote', 'source_address'] for tmp in vxlan):
- raise ConfigError('Group, remote or source-address must be configured')
+ if not any(tmp in ['group', 'remote', 'source_address', 'source_interface'] for tmp in vxlan):
+ raise ConfigError('Group, remote, source-address or source-interface must be configured')
if 'vni' not in vxlan and 'external' not in vxlan:
raise ConfigError(
diff --git a/src/conf_mode/interfaces-wireguard.py b/src/conf_mode/interfaces-wireguard.py
index a02baba82..446399255 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-2022 VyOS maintainers and contributors
+# 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
@@ -29,10 +29,12 @@ from vyos.configverify import verify_bond_bridge_member
from vyos.ifconfig import WireGuardIf
from vyos.utils.kernel import check_kmod
from vyos.utils.network import check_port_availability
+from vyos.utils.network import is_wireguard_key_pair
from vyos import ConfigError
from vyos import airbag
airbag.enable()
+
def get_config(config=None):
"""
Retrive CLI config as dictionary. Dictionary can never be empty, as at least the
@@ -105,6 +107,9 @@ def verify(wireguard):
if peer['public_key'] in public_keys:
raise ConfigError(f'Duplicate public-key defined on peer "{tmp}"')
+ if 'disable' not in peer and is_wireguard_key_pair(wireguard['private_key'], peer['public_key']):
+ raise ConfigError(f'Peer "{tmp}" has the same public key as the interface "{wireguard["ifname"]}"')
+
public_keys.append(peer['public_key'])
def apply(wireguard):
diff --git a/src/conf_mode/interfaces-wireless.py b/src/conf_mode/interfaces-wireless.py
index 42326bea0..e49ad25ac 100755
--- a/src/conf_mode/interfaces-wireless.py
+++ b/src/conf_mode/interfaces-wireless.py
@@ -79,27 +79,9 @@ def get_config(config=None):
ifname, wifi = get_interface_dict(conf, base)
- # Cleanup "delete" default values when required user selectable values are
- # not defined at all
- tmp = conf.get_config_dict(base + [ifname], key_mangling=('-', '_'),
- get_first_key=True)
- if not (dict_search('security.wpa.passphrase', tmp) or
- dict_search('security.wpa.radius', tmp)):
- if 'deleted' not in wifi:
- del wifi['security']['wpa']
- # if 'security' key is empty, drop it too
- if len(wifi['security']) == 0:
- del wifi['security']
-
- # defaults include RADIUS server specifics per TAG node which need to be
- # added to individual RADIUS servers instead - so we can simply delete them
- if dict_search('security.wpa.radius.server.port', wifi) != None:
- del wifi['security']['wpa']['radius']['server']['port']
- if not len(wifi['security']['wpa']['radius']['server']):
- del wifi['security']['wpa']['radius']
- if not len(wifi['security']['wpa']):
- del wifi['security']['wpa']
- if not len(wifi['security']):
+ if 'deleted' not in wifi:
+ # then get_interface_dict provides default keys
+ if wifi.from_defaults(['security']): # if not set by user
del wifi['security']
if 'security' in wifi and 'wpa' in wifi['security']:
@@ -120,14 +102,6 @@ def get_config(config=None):
tmp = find_other_stations(conf, base, wifi['ifname'])
if tmp: wifi['station_interfaces'] = tmp
- # Add individual RADIUS server default values
- if dict_search('security.wpa.radius.server', wifi):
- default_values = defaults(base + ['security', 'wpa', 'radius', 'server'])
-
- for server in dict_search('security.wpa.radius.server', wifi):
- wifi['security']['wpa']['radius']['server'][server] = dict_merge(
- default_values, wifi['security']['wpa']['radius']['server'][server])
-
return wifi
def verify(wifi):
diff --git a/src/conf_mode/lldp.py b/src/conf_mode/lldp.py
index 0e5fc29d3..c2e87d171 100755
--- a/src/conf_mode/lldp.py
+++ b/src/conf_mode/lldp.py
@@ -20,13 +20,11 @@ from sys import exit
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
-from vyos.validate import is_addr_assigned
-from vyos.validate import is_loopback_addr
+from vyos.utils.network import is_addr_assigned
+from vyos.utils.network import is_loopback_addr
from vyos.version import get_version_data
from vyos.utils.process import call
from vyos.utils.dict import dict_search
-from vyos.xml import defaults
from vyos.template import render
from vyos import ConfigError
from vyos import airbag
@@ -46,7 +44,9 @@ def get_config(config=None):
return {}
lldp = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True, no_tag_node_value_mangle=True)
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True)
if conf.exists(['service', 'snmp']):
lldp['system_snmp_enabled'] = ''
@@ -54,27 +54,12 @@ def get_config(config=None):
version_data = get_version_data()
lldp['version'] = version_data['version']
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- # location coordinates have a default value
- if 'interface' in lldp:
- for interface, interface_config in lldp['interface'].items():
- default_values = defaults(base + ['interface'])
- if dict_search('location.coordinate_based', interface_config) == None:
- # no location specified - no need to add defaults
- del default_values['location']['coordinate_based']['datum']
- del default_values['location']['coordinate_based']['altitude']
-
- # cleanup default_values dictionary from inner to outer
- # this might feel overkill here, but it does support easy extension
- # in the future with additional default values
- if len(default_values['location']['coordinate_based']) == 0:
- del default_values['location']['coordinate_based']
- if len(default_values['location']) == 0:
- del default_values['location']
-
- lldp['interface'][interface] = dict_merge(default_values,
- lldp['interface'][interface])
+ # prune location information if not set by user
+ for interface in lldp.get('interface', []):
+ if lldp.from_defaults(['interface', interface, 'location']):
+ del lldp['interface'][interface]['location']
+ elif lldp.from_defaults(['interface', interface, 'location','coordinate_based']):
+ del lldp['interface'][interface]['location']['coordinate_based']
return lldp
diff --git a/src/conf_mode/load-balancing-haproxy.py b/src/conf_mode/load-balancing-haproxy.py
index 2fb0edf8e..8fe429653 100755
--- a/src/conf_mode/load-balancing-haproxy.py
+++ b/src/conf_mode/load-balancing-haproxy.py
@@ -20,14 +20,12 @@ from sys import exit
from shutil import rmtree
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.utils.process import call
from vyos.utils.network import check_port_availability
from vyos.utils.network import is_listen_port_bind_service
from vyos.pki import wrap_certificate
from vyos.pki import wrap_private_key
from vyos.template import render
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -54,18 +52,8 @@ def get_config(config=None):
lb['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),
get_first_key=True, no_tag_node_value_mangle=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- if 'backend' in default_values:
- del default_values['backend']
if lb:
- lb = dict_merge(default_values, lb)
-
- if 'backend' in lb:
- for backend in lb['backend']:
- default_balues_backend = defaults(base + ['backend'])
- lb['backend'][backend] = dict_merge(default_balues_backend, lb['backend'][backend])
+ lb = conf.merge_defaults(lb, recursive=True)
return lb
diff --git a/src/conf_mode/load-balancing-wan.py b/src/conf_mode/load-balancing-wan.py
index 3533a5a04..ad9c80d72 100755
--- a/src/conf_mode/load-balancing-wan.py
+++ b/src/conf_mode/load-balancing-wan.py
@@ -21,10 +21,8 @@ from shutil import rmtree
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.utils.process import cmd
from vyos.template import render
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -41,48 +39,15 @@ def get_config(config=None):
conf = Config()
base = ['load-balancing', 'wan']
- lb = conf.get_config_dict(base,
+ lb = conf.get_config_dict(base, key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
get_first_key=True,
- key_mangling=('-', '_'),
- no_tag_node_value_mangle=True)
-
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- # lb base default values can not be merged here - remove and add them later
- if 'interface_health' in default_values:
- del default_values['interface_health']
- if 'rule' in default_values:
- del default_values['rule']
- lb = dict_merge(default_values, lb)
-
- if 'interface_health' in lb:
- for iface in lb.get('interface_health'):
- default_values_iface = defaults(base + ['interface-health'])
- if 'test' in default_values_iface:
- del default_values_iface['test']
- lb['interface_health'][iface] = dict_merge(
- default_values_iface, lb['interface_health'][iface])
- if 'test' in lb['interface_health'][iface]:
- for node_test in lb['interface_health'][iface]['test']:
- default_values_test = defaults(base +
- ['interface-health', 'test'])
- lb['interface_health'][iface]['test'][node_test] = dict_merge(
- default_values_test,
- lb['interface_health'][iface]['test'][node_test])
-
- if 'rule' in lb:
- for rule in lb.get('rule'):
- default_values_rule = defaults(base + ['rule'])
- if 'interface' in default_values_rule:
- del default_values_rule['interface']
- lb['rule'][rule] = dict_merge(default_values_rule, lb['rule'][rule])
- if not conf.exists(base + ['rule', rule, 'limit']):
- del lb['rule'][rule]['limit']
- if 'interface' in lb['rule'][rule]:
- for iface in lb['rule'][rule]['interface']:
- default_values_rule_iface = defaults(base + ['rule', 'interface'])
- lb['rule'][rule]['interface'][iface] = dict_merge(default_values_rule_iface, lb['rule'][rule]['interface'][iface])
+ with_recursive_defaults=True)
+
+ # prune limit key if not set by user
+ for rule in lb.get('rule', []):
+ if lb.from_defaults(['rule', rule, 'limit']):
+ del lb['rule'][rule]['limit']
return lb
diff --git a/src/conf_mode/nat.py b/src/conf_mode/nat.py
index e19b12937..f9d711b36 100755
--- a/src/conf_mode/nat.py
+++ b/src/conf_mode/nat.py
@@ -25,7 +25,6 @@ from netifaces import interfaces
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.template import is_ip_network
from vyos.utils.kernel import check_kmod
@@ -33,8 +32,7 @@ from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_search_args
from vyos.utils.process import cmd
from vyos.utils.process import run
-from vyos.validate import is_addr_assigned
-from vyos.xml import defaults
+from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import airbag
@@ -126,6 +124,18 @@ def verify_rule(config, err_msg, groups_dict):
if config['protocol'] not in ['tcp', 'udp', 'tcp_udp']:
raise ConfigError('Protocol must be tcp, udp, or tcp_udp when specifying a port-group')
+ if 'load_balance' in config:
+ for item in ['source-port', 'destination-port']:
+ if item in config['load_balance']['hash'] and config['protocol'] not in ['tcp', 'udp']:
+ raise ConfigError('Protocol must be tcp or udp when specifying hash ports')
+ count = 0
+ if 'backend' in config['load_balance']:
+ for member in config['load_balance']['backend']:
+ weight = config['load_balance']['backend'][member]['weight']
+ count = count + int(weight)
+ if count != 100:
+ Warning(f'Sum of weight for nat load balance rule is not 100. You may get unexpected behaviour')
+
def get_config(config=None):
if config:
conf = config
@@ -133,16 +143,9 @@ def get_config(config=None):
conf = Config()
base = ['nat']
- nat = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
-
- # T2665: we must add the tagNode defaults individually until this is
- # moved to the base class
- for direction in ['source', 'destination', 'static']:
- if direction in nat:
- default_values = defaults(base + [direction, 'rule'])
- for rule in dict_search(f'{direction}.rule', nat) or []:
- nat[direction]['rule'][rule] = dict_merge(default_values,
- nat[direction]['rule'][rule])
+ nat = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
# read in current nftable (once) for further processing
tmp = cmd('nft -j list table raw')
@@ -199,7 +202,7 @@ def verify(nat):
Warning(f'rule "{rule}" interface "{config["outbound_interface"]}" does not exist on this system')
if not dict_search('translation.address', config) and not dict_search('translation.port', config):
- if 'exclude' not in config:
+ 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)
@@ -211,7 +214,6 @@ def verify(nat):
# common rule verification
verify_rule(config, err_msg, nat['firewall_group'])
-
if dict_search('destination.rule', nat):
for rule, config in dict_search('destination.rule', nat).items():
err_msg = f'Destination NAT configuration error in rule {rule}:'
@@ -223,7 +225,7 @@ def verify(nat):
Warning(f'rule "{rule}" interface "{config["inbound_interface"]}" does not exist on this system')
if not dict_search('translation.address', config) and not dict_search('translation.port', config) and not dict_search('translation.redirect.port', config):
- if 'exclude' not in config:
+ if 'exclude' not in config and 'backend' not in config['load_balance']:
raise ConfigError(f'{err_msg} translation requires address and/or port')
# common rule verification
diff --git a/src/conf_mode/nat66.py b/src/conf_mode/nat66.py
index 25f625b84..4c12618bc 100755
--- a/src/conf_mode/nat66.py
+++ b/src/conf_mode/nat66.py
@@ -23,13 +23,11 @@ from netifaces import interfaces
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.utils.process import cmd
from vyos.utils.kernel import check_kmod
from vyos.utils.dict import dict_search
from vyos.template import is_ipv6
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -60,16 +58,6 @@ def get_config(config=None):
base = ['nat66']
nat = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # T2665: we must add the tagNode defaults individually until this is
- # moved to the base class
- for direction in ['source', 'destination']:
- if direction in nat:
- default_values = defaults(base + [direction, 'rule'])
- if 'rule' in nat[direction]:
- for rule in nat[direction]['rule']:
- nat[direction]['rule'][rule] = dict_merge(default_values,
- nat[direction]['rule'][rule])
-
# read in current nftable (once) for further processing
tmp = cmd('nft -j list table ip6 raw')
nftable_json = json.loads(tmp)
diff --git a/src/conf_mode/pki.py b/src/conf_mode/pki.py
index eb8cb3940..34ba2fe69 100755
--- a/src/conf_mode/pki.py
+++ b/src/conf_mode/pki.py
@@ -18,7 +18,6 @@ from sys import exit
from vyos.config import Config
from vyos.configdep import set_dependents, call_dependents
-from vyos.configdict import dict_merge
from vyos.configdict import node_changed
from vyos.pki import is_ca_certificate
from vyos.pki import load_certificate
@@ -28,7 +27,6 @@ from vyos.pki import load_crl
from vyos.pki import load_dh_parameters
from vyos.utils.dict import dict_search_args
from vyos.utils.dict import dict_search_recursive
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -113,8 +111,7 @@ def get_config(config=None):
# We only merge on the defaults of there is a configuration at all
if conf.exists(base):
- default_values = defaults(base)
- pki = dict_merge(default_values, pki)
+ pki = conf.merge_defaults(pki, recursive=True)
# We need to get the entire system configuration to verify that we are not
# deleting a certificate that is still referenced somewhere!
diff --git a/src/conf_mode/protocols_babel.py b/src/conf_mode/protocols_babel.py
index f5ac56f65..104711b55 100755
--- a/src/conf_mode/protocols_babel.py
+++ b/src/conf_mode/protocols_babel.py
@@ -19,13 +19,13 @@ import os
from sys import exit
from vyos.config import Config
+from vyos.config import config_dict_merge
from vyos.configdict import dict_merge
from vyos.configdict import node_changed
from vyos.configverify import verify_common_route_maps
from vyos.configverify import verify_access_list
from vyos.configverify import verify_prefix_list
from vyos.utils.dict import dict_search
-from vyos.xml import defaults
from vyos.template import render_to_string
from vyos import ConfigError
from vyos import frr
@@ -38,7 +38,8 @@ def get_config(config=None):
else:
conf = Config()
base = ['protocols', 'babel']
- babel = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+ babel = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True)
# FRR has VRF support for different routing daemons. As interfaces belong
# to VRFs - or the global VRF, we need to check for changed interfaces so
@@ -54,15 +55,13 @@ def get_config(config=None):
return babel
# We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
+ # values which we need to update into the dictionary retrieved.
+ default_values = conf.get_config_defaults(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ recursive=True)
- # XXX: T2665: we currently have no nice way for defaults under tag nodes,
- # clean them out and add them manually :(
- del default_values['interface']
-
- # merge in remaining default values
- babel = dict_merge(default_values, babel)
+ # merge in default values
+ babel = config_dict_merge(default_values, babel)
# We also need some additional information from the config, prefix-lists
# and route-maps for instance. They will be used in verify().
diff --git a/src/conf_mode/protocols_bfd.py b/src/conf_mode/protocols_bfd.py
index 0436abaf9..dab784662 100755
--- a/src/conf_mode/protocols_bfd.py
+++ b/src/conf_mode/protocols_bfd.py
@@ -17,12 +17,10 @@
import os
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configverify import verify_vrf
from vyos.template import is_ipv6
from vyos.template import render_to_string
-from vyos.validate import is_ipv6_link_local
-from vyos.xml import defaults
+from vyos.utils.network import is_ipv6_link_local
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -41,18 +39,7 @@ def get_config(config=None):
if not conf.exists(base):
return bfd
- # We have gathered the dict representation of the CLI, but there are
- # default options which we need to update into the dictionary retrived.
- # XXX: T2665: we currently have no nice way for defaults under tag
- # nodes, thus we load the defaults "by hand"
- default_values = defaults(base + ['peer'])
- if 'peer' in bfd:
- for peer in bfd['peer']:
- bfd['peer'][peer] = dict_merge(default_values, bfd['peer'][peer])
-
- if 'profile' in bfd:
- for profile in bfd['profile']:
- bfd['profile'][profile] = dict_merge(default_values, bfd['profile'][profile])
+ bfd = conf.merge_defaults(bfd, recursive=True)
return bfd
diff --git a/src/conf_mode/protocols_bgp.py b/src/conf_mode/protocols_bgp.py
index 7b9f15505..00015023c 100755
--- a/src/conf_mode/protocols_bgp.py
+++ b/src/conf_mode/protocols_bgp.py
@@ -29,7 +29,7 @@ from vyos.template import is_interface
from vyos.template import render_to_string
from vyos.utils.dict import dict_search
from vyos.utils.network import get_interface_vrf
-from vyos.validate import is_addr_assigned
+from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import frr
from vyos import airbag
diff --git a/src/conf_mode/protocols_failover.py b/src/conf_mode/protocols_failover.py
index faf56d741..e7e44db84 100755
--- a/src/conf_mode/protocols_failover.py
+++ b/src/conf_mode/protocols_failover.py
@@ -19,10 +19,8 @@ import json
from pathlib import Path
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.utils.process import call
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
@@ -42,15 +40,12 @@ def get_config(config=None):
conf = Config()
base = ['protocols', 'failover']
- failover = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
+ failover = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True)
# Set default values only if we set config
- if failover.get('route'):
- for route, route_config in failover.get('route').items():
- for next_hop, next_hop_config in route_config.get('next_hop').items():
- default_values = defaults(base + ['route'])
- failover['route'][route]['next_hop'][next_hop] = dict_merge(
- default_values['next_hop'], failover['route'][route]['next_hop'][next_hop])
+ if failover.get('route') is not None:
+ failover = conf.merge_defaults(failover, recursive=True)
return failover
diff --git a/src/conf_mode/protocols_isis.py b/src/conf_mode/protocols_isis.py
index 4c637a99f..e00c58ee4 100755
--- a/src/conf_mode/protocols_isis.py
+++ b/src/conf_mode/protocols_isis.py
@@ -28,7 +28,6 @@ from vyos.ifconfig import Interface
from vyos.utils.dict import dict_search
from vyos.utils.network import get_interface_config
from vyos.template import render_to_string
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -64,19 +63,14 @@ def get_config(config=None):
if interfaces_removed:
isis['interface_removed'] = list(interfaces_removed)
- # Bail out early if configuration tree does not exist
+ # Bail out early if configuration tree does no longer exist. this must
+ # be done after retrieving the list of interfaces to be removed.
if not conf.exists(base):
isis.update({'deleted' : ''})
return isis
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- # XXX: Note that we can not call defaults(base), as defaults does not work
- # on an instance of a tag node. As we use the exact same CLI definition for
- # both the non-vrf and vrf version this is absolutely safe!
- default_values = defaults(base_path)
# merge in default values
- isis = dict_merge(default_values, isis)
+ isis = conf.merge_defaults(isis, recursive=True)
# We also need some additional information from the config, prefix-lists
# and route-maps for instance. They will be used in verify().
@@ -254,7 +248,7 @@ def apply(isis):
if key not in isis:
continue
for interface in isis[key]:
- frr_cfg.modify_section(f'^interface {interface}{vrf}', stop_pattern='^exit', remove_stop_mark=True)
+ frr_cfg.modify_section(f'^interface {interface}', stop_pattern='^exit', remove_stop_mark=True)
if 'frr_isisd_config' in isis:
frr_cfg.add_before(frr.default_add_before, isis['frr_isisd_config'])
diff --git a/src/conf_mode/protocols_ospf.py b/src/conf_mode/protocols_ospf.py
index f2075d25b..cddd3765e 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 VyOS maintainers and contributors
+# Copyright (C) 2021-2023 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
@@ -20,6 +20,7 @@ from sys import exit
from sys import argv
from vyos.config import Config
+from vyos.config import config_dict_merge
from vyos.configdict import dict_merge
from vyos.configdict import node_changed
from vyos.configverify import verify_common_route_maps
@@ -29,7 +30,6 @@ from vyos.configverify import verify_access_list
from vyos.template import render_to_string
from vyos.utils.dict import dict_search
from vyos.utils.network import get_interface_config
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -65,17 +65,15 @@ def get_config(config=None):
if interfaces_removed:
ospf['interface_removed'] = list(interfaces_removed)
- # Bail out early if configuration tree does not exist
+ # Bail out early if configuration tree does no longer exist. this must
+ # be done after retrieving the list of interfaces to be removed.
if not conf.exists(base):
ospf.update({'deleted' : ''})
return ospf
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- # XXX: Note that we can not call defaults(base), as defaults does not work
- # on an instance of a tag node. As we use the exact same CLI definition for
- # both the non-vrf and vrf version this is absolutely safe!
- default_values = defaults(base_path)
+ default_values = conf.get_config_defaults(**ospf.kwargs, recursive=True)
# We have to cleanup the default dict, as default values could enable features
# which are not explicitly enabled on the CLI. Example: default-information
@@ -84,62 +82,27 @@ def get_config(config=None):
# need to check this first and probably drop that key.
if dict_search('default_information.originate', ospf) is None:
del default_values['default_information']
- if dict_search('area.area_type.nssa', ospf) is None:
- del default_values['area']['area_type']['nssa']
if 'mpls_te' not in ospf:
del default_values['mpls_te']
if 'graceful_restart' not in ospf:
del default_values['graceful_restart']
+ for area_num in default_values.get('area', []):
+ if dict_search(f'area.{area_num}.area_type.nssa', ospf) is None:
+ del default_values['area'][area_num]['area_type']['nssa']
- for protocol in ['babel', 'bgp', 'connected', 'isis', 'kernel', 'rip', 'static', 'table']:
- # table is a tagNode thus we need to clean out all occurances for the
- # default values and load them in later individually
- if protocol == 'table':
- del default_values['redistribute']['table']
- continue
+ for protocol in ['babel', 'bgp', 'connected', 'isis', 'kernel', 'rip', 'static']:
if dict_search(f'redistribute.{protocol}', ospf) is None:
del default_values['redistribute'][protocol]
- # XXX: T2665: we currently have no nice way for defaults under tag nodes,
- # clean them out and add them manually :(
- del default_values['neighbor']
- del default_values['area']['virtual_link']
- del default_values['interface']
-
- # merge in remaining default values
- ospf = dict_merge(default_values, ospf)
-
- if 'neighbor' in ospf:
- default_values = defaults(base + ['neighbor'])
- for neighbor in ospf['neighbor']:
- ospf['neighbor'][neighbor] = dict_merge(default_values, ospf['neighbor'][neighbor])
+ for interface in ospf.get('interface', []):
+ # We need to reload the defaults on every pass b/c of
+ # hello-multiplier dependency on dead-interval
+ # If hello-multiplier is set, we need to remove the default from
+ # dead-interval.
+ if 'hello_multiplier' in ospf['interface'][interface]:
+ del default_values['interface'][interface]['dead_interval']
- if 'area' in ospf:
- default_values = defaults(base + ['area', 'virtual-link'])
- for area, area_config in ospf['area'].items():
- if 'virtual_link' in area_config:
- for virtual_link in area_config['virtual_link']:
- ospf['area'][area]['virtual_link'][virtual_link] = dict_merge(
- default_values, ospf['area'][area]['virtual_link'][virtual_link])
-
- if 'interface' in ospf:
- for interface in ospf['interface']:
- # We need to reload the defaults on every pass b/c of
- # hello-multiplier dependency on dead-interval
- default_values = defaults(base + ['interface'])
- # If hello-multiplier is set, we need to remove the default from
- # dead-interval.
- if 'hello_multiplier' in ospf['interface'][interface]:
- del default_values['dead_interval']
-
- ospf['interface'][interface] = dict_merge(default_values,
- ospf['interface'][interface])
-
- if 'redistribute' in ospf and 'table' in ospf['redistribute']:
- default_values = defaults(base + ['redistribute', 'table'])
- for table in ospf['redistribute']['table']:
- ospf['redistribute']['table'][table] = dict_merge(default_values,
- ospf['redistribute']['table'][table])
+ ospf = config_dict_merge(default_values, ospf)
# We also need some additional information from the config, prefix-lists
# and route-maps for instance. They will be used in verify().
@@ -287,7 +250,7 @@ def apply(ospf):
if key not in ospf:
continue
for interface in ospf[key]:
- frr_cfg.modify_section(f'^interface {interface}{vrf}', stop_pattern='^exit', remove_stop_mark=True)
+ frr_cfg.modify_section(f'^interface {interface}', stop_pattern='^exit', remove_stop_mark=True)
if 'frr_ospfd_config' in ospf:
frr_cfg.add_before(frr.default_add_before, ospf['frr_ospfd_config'])
diff --git a/src/conf_mode/protocols_ospfv3.py b/src/conf_mode/protocols_ospfv3.py
index fbea51f56..5b1adce30 100755
--- a/src/conf_mode/protocols_ospfv3.py
+++ b/src/conf_mode/protocols_ospfv3.py
@@ -20,6 +20,7 @@ from sys import exit
from sys import argv
from vyos.config import Config
+from vyos.config import config_dict_merge
from vyos.configdict import dict_merge
from vyos.configdict import node_changed
from vyos.configverify import verify_common_route_maps
@@ -29,7 +30,6 @@ from vyos.template import render_to_string
from vyos.ifconfig import Interface
from vyos.utils.dict import dict_search
from vyos.utils.network import get_interface_config
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -64,17 +64,16 @@ def get_config(config=None):
if interfaces_removed:
ospfv3['interface_removed'] = list(interfaces_removed)
- # Bail out early if configuration tree does not exist
+ # Bail out early if configuration tree does no longer exist. this must
+ # be done after retrieving the list of interfaces to be removed.
if not conf.exists(base):
ospfv3.update({'deleted' : ''})
return ospfv3
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- # XXX: Note that we can not call defaults(base), as defaults does not work
- # on an instance of a tag node. As we use the exact same CLI definition for
- # both the non-vrf and vrf version this is absolutely safe!
- default_values = defaults(base_path)
+ default_values = conf.get_config_defaults(**ospfv3.kwargs,
+ recursive=True)
# We have to cleanup the default dict, as default values could enable features
# which are not explicitly enabled on the CLI. Example: default-information
@@ -86,12 +85,10 @@ def get_config(config=None):
if 'graceful_restart' not in ospfv3:
del default_values['graceful_restart']
- # XXX: T2665: we currently have no nice way for defaults under tag nodes,
- # clean them out and add them manually :(
- del default_values['interface']
+ default_values.pop('interface', {})
# merge in remaining default values
- ospfv3 = dict_merge(default_values, ospfv3)
+ ospfv3 = config_dict_merge(default_values, ospfv3)
# We also need some additional information from the config, prefix-lists
# and route-maps for instance. They will be used in verify().
@@ -170,7 +167,7 @@ def apply(ospfv3):
if key not in ospfv3:
continue
for interface in ospfv3[key]:
- frr_cfg.modify_section(f'^interface {interface}{vrf}', stop_pattern='^exit', remove_stop_mark=True)
+ frr_cfg.modify_section(f'^interface {interface}', stop_pattern='^exit', remove_stop_mark=True)
if 'new_frr_config' in ospfv3:
frr_cfg.add_before(frr.default_add_before, ospfv3['new_frr_config'])
diff --git a/src/conf_mode/protocols_rip.py b/src/conf_mode/protocols_rip.py
index 5661dc377..bd47dfd00 100755
--- a/src/conf_mode/protocols_rip.py
+++ b/src/conf_mode/protocols_rip.py
@@ -25,7 +25,6 @@ from vyos.configverify import verify_common_route_maps
from vyos.configverify import verify_access_list
from vyos.configverify import verify_prefix_list
from vyos.utils.dict import dict_search
-from vyos.xml import defaults
from vyos.template import render_to_string
from vyos import ConfigError
from vyos import frr
@@ -55,9 +54,7 @@ def get_config(config=None):
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- # merge in remaining default values
- rip = dict_merge(default_values, rip)
+ rip = conf.merge_defaults(rip, recursive=True)
# We also need some additional information from the config, prefix-lists
# and route-maps for instance. They will be used in verify().
diff --git a/src/conf_mode/protocols_ripng.py b/src/conf_mode/protocols_ripng.py
index e3c904e33..dd1550033 100755
--- a/src/conf_mode/protocols_ripng.py
+++ b/src/conf_mode/protocols_ripng.py
@@ -24,7 +24,6 @@ from vyos.configverify import verify_common_route_maps
from vyos.configverify import verify_access_list
from vyos.configverify import verify_prefix_list
from vyos.utils.dict import dict_search
-from vyos.xml import defaults
from vyos.template import render_to_string
from vyos import ConfigError
from vyos import frr
@@ -45,9 +44,7 @@ def get_config(config=None):
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- # merge in remaining default values
- ripng = dict_merge(default_values, ripng)
+ ripng = conf.merge_defaults(ripng, recursive=True)
# We also need some additional information from the config, prefix-lists
# and route-maps for instance. They will be used in verify().
diff --git a/src/conf_mode/protocols_rpki.py b/src/conf_mode/protocols_rpki.py
index 035b7db05..05e876f3b 100755
--- a/src/conf_mode/protocols_rpki.py
+++ b/src/conf_mode/protocols_rpki.py
@@ -19,10 +19,8 @@ import os
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render_to_string
from vyos.utils.dict import dict_search
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -43,8 +41,7 @@ def get_config(config=None):
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- rpki = dict_merge(default_values, rpki)
+ rpki = conf.merge_defaults(rpki, recursive=True)
return rpki
diff --git a/src/conf_mode/qos.py b/src/conf_mode/qos.py
index 53e9ff50d..5536adda2 100755
--- a/src/conf_mode/qos.py
+++ b/src/conf_mode/qos.py
@@ -38,7 +38,6 @@ from vyos.qos import TrafficShaper
from vyos.qos import TrafficShaperHFSC
from vyos.utils.process import call
from vyos.utils.dict import dict_search_recursive
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -97,63 +96,32 @@ def get_config(config=None):
type_node = path.split(" ")[1] # return only interface type node
set_dependents(type_node, conf, ifname)
- if 'policy' in qos:
- for policy in qos['policy']:
- # when calling defaults() we need to use the real CLI node, thus we
- # need a hyphen
- policy_hyphen = policy.replace('_', '-')
-
- if policy in ['random_detect']:
- for rd_name, rd_config in qos['policy'][policy].items():
- # There are eight precedence levels - ensure all are present
- # to be filled later down with the appropriate default values
- default_precedence = {'precedence' : { '0' : {}, '1' : {}, '2' : {}, '3' : {},
- '4' : {}, '5' : {}, '6' : {}, '7' : {} }}
- qos['policy']['random_detect'][rd_name] = dict_merge(
- default_precedence, qos['policy']['random_detect'][rd_name])
-
- for p_name, p_config in qos['policy'][policy].items():
- default_values = defaults(base + ['policy', policy_hyphen])
-
- if policy in ['priority_queue']:
- if 'default' not in p_config:
- raise ConfigError(f'QoS policy {p_name} misses "default" class!')
-
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- if 'class' in default_values:
- del default_values['class']
- if 'precedence' in default_values:
- del default_values['precedence']
-
- qos['policy'][policy][p_name] = dict_merge(
- default_values, qos['policy'][policy][p_name])
-
- # class is another tag node which requires individual handling
- if 'class' in p_config:
- default_values = defaults(base + ['policy', policy_hyphen, 'class'])
- for p_class in p_config['class']:
- qos['policy'][policy][p_name]['class'][p_class] = dict_merge(
- default_values, qos['policy'][policy][p_name]['class'][p_class])
-
- if 'precedence' in p_config:
- default_values = defaults(base + ['policy', policy_hyphen, 'precedence'])
- # precedence values are a bit more complex as they are calculated
- # under specific circumstances - thus we need to iterate two times.
- # first blend in the defaults from XML / CLI
- for precedence in p_config['precedence']:
- qos['policy'][policy][p_name]['precedence'][precedence] = dict_merge(
- default_values, qos['policy'][policy][p_name]['precedence'][precedence])
- # second calculate defaults based on actual dictionary
- for precedence in p_config['precedence']:
- max_thr = int(qos['policy'][policy][p_name]['precedence'][precedence]['maximum_threshold'])
- if 'minimum_threshold' not in qos['policy'][policy][p_name]['precedence'][precedence]:
- qos['policy'][policy][p_name]['precedence'][precedence]['minimum_threshold'] = str(
- int((9 + int(precedence)) * max_thr) // 18);
-
- if 'queue_limit' not in qos['policy'][policy][p_name]['precedence'][precedence]:
- qos['policy'][policy][p_name]['precedence'][precedence]['queue_limit'] = \
- str(int(4 * max_thr))
+ for policy in qos.get('policy', []):
+ if policy in ['random_detect']:
+ for rd_name in list(qos['policy'][policy]):
+ # There are eight precedence levels - ensure all are present
+ # to be filled later down with the appropriate default values
+ default_precedence = {'precedence' : { '0' : {}, '1' : {}, '2' : {}, '3' : {},
+ '4' : {}, '5' : {}, '6' : {}, '7' : {} }}
+ qos['policy']['random_detect'][rd_name] = dict_merge(
+ default_precedence, qos['policy']['random_detect'][rd_name])
+
+ qos = conf.merge_defaults(qos, recursive=True)
+
+ for policy in qos.get('policy', []):
+ for p_name, p_config in qos['policy'][policy].items():
+ if 'precedence' in p_config:
+ # precedence settings are a bit more complex as they are
+ # calculated under specific circumstances:
+ for precedence in p_config['precedence']:
+ max_thr = int(qos['policy'][policy][p_name]['precedence'][precedence]['maximum_threshold'])
+ if 'minimum_threshold' not in qos['policy'][policy][p_name]['precedence'][precedence]:
+ qos['policy'][policy][p_name]['precedence'][precedence]['minimum_threshold'] = str(
+ int((9 + int(precedence)) * max_thr) // 18);
+
+ if 'queue_limit' not in qos['policy'][policy][p_name]['precedence'][precedence]:
+ qos['policy'][policy][p_name]['precedence'][precedence]['queue_limit'] = \
+ str(int(4 * max_thr))
return qos
@@ -202,7 +170,9 @@ def verify(qos):
queue_lim = int(precedence_config['queue_limit'])
if queue_lim < max_tr:
raise ConfigError(f'Policy "{policy}" uses queue-limit "{queue_lim}" < max-threshold "{max_tr}"!')
-
+ if policy_type in ['priority_queue']:
+ if 'default' not in policy_config:
+ raise ConfigError(f'Policy {policy} misses "default" class!')
if 'default' in policy_config:
if 'bandwidth' not in policy_config['default'] and policy_type not in ['priority_queue', 'round_robin']:
raise ConfigError('Bandwidth not defined for default traffic!')
diff --git a/src/conf_mode/salt-minion.py b/src/conf_mode/salt-minion.py
index 3ff7880b2..a8fce8e01 100755
--- a/src/conf_mode/salt-minion.py
+++ b/src/conf_mode/salt-minion.py
@@ -22,12 +22,10 @@ from urllib3 import PoolManager
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configverify import verify_interface_exists
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.permission import chown
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
@@ -55,8 +53,7 @@ def get_config(config=None):
salt['id'] = gethostname()
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- salt = dict_merge(default_values, salt)
+ salt = conf.merge_defaults(salt, recursive=True)
if not conf.exists(base):
return None
diff --git a/src/conf_mode/service_config_sync.py b/src/conf_mode/service_config_sync.py
index 5cde735a1..4b8a7f6ee 100755
--- a/src/conf_mode/service_config_sync.py
+++ b/src/conf_mode/service_config_sync.py
@@ -19,8 +19,6 @@ import json
from pathlib import Path
from vyos.config import Config
-from vyos.configdict import dict_merge
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
@@ -42,12 +40,8 @@ def get_config(config=None):
base = ['service', 'config-sync']
if not conf.exists(base):
return None
- config = conf.get_config_dict(base,
- get_first_key=True,
- no_tag_node_value_mangle=True)
-
- default_values = defaults(base)
- config = dict_merge(default_values, config)
+ config = conf.get_config_dict(base, get_first_key=True,
+ with_recursive_defaults=True)
return config
diff --git a/src/conf_mode/service_console-server.py b/src/conf_mode/service_console-server.py
index 7eb41ea87..b112add3f 100755
--- a/src/conf_mode/service_console-server.py
+++ b/src/conf_mode/service_console-server.py
@@ -20,10 +20,8 @@ from sys import exit
from psutil import process_iter
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.utils.process import call
-from vyos.xml import defaults
from vyos import ConfigError
config_file = '/run/conserver/conserver.cf'
@@ -49,11 +47,7 @@ def get_config(config=None):
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- default_values = defaults(base + ['device'])
- if 'device' in proxy:
- for device in proxy['device']:
- tmp = dict_merge(default_values, proxy['device'][device])
- proxy['device'][device] = tmp
+ proxy = conf.merge_defaults(proxy, recursive=True)
return proxy
diff --git a/src/conf_mode/service_ids_fastnetmon.py b/src/conf_mode/service_ids_fastnetmon.py
index f6b80552b..276a71fcb 100755
--- a/src/conf_mode/service_ids_fastnetmon.py
+++ b/src/conf_mode/service_ids_fastnetmon.py
@@ -19,10 +19,8 @@ import os
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.utils.process import call
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -41,11 +39,9 @@ def get_config(config=None):
if not conf.exists(base):
return None
- fastnetmon = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- fastnetmon = dict_merge(default_values, fastnetmon)
+ fastnetmon = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
return fastnetmon
diff --git a/src/conf_mode/service_monitoring_telegraf.py b/src/conf_mode/service_monitoring_telegraf.py
index 0269bedd9..40eb13e23 100755
--- a/src/conf_mode/service_monitoring_telegraf.py
+++ b/src/conf_mode/service_monitoring_telegraf.py
@@ -22,7 +22,6 @@ from sys import exit
from shutil import rmtree
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configdict import is_node_changed
from vyos.configverify import verify_vrf
from vyos.ifconfig import Section
@@ -30,7 +29,6 @@ from vyos.template import render
from vyos.utils.process import call
from vyos.utils.permission import chown
from vyos.utils.process import cmd
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -83,8 +81,7 @@ def get_config(config=None):
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- monitoring = dict_merge(default_values, monitoring)
+ monitoring = conf.merge_defaults(monitoring, recursive=True)
monitoring['custom_scripts_dir'] = custom_scripts_dir
monitoring['hostname'] = get_hostname()
diff --git a/src/conf_mode/service_monitoring_zabbix-agent.py b/src/conf_mode/service_monitoring_zabbix-agent.py
new file mode 100755
index 000000000..98d8a32ca
--- /dev/null
+++ b/src/conf_mode/service_monitoring_zabbix-agent.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+
+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()
+
+
+service_name = 'zabbix-agent2'
+service_conf = f'/run/zabbix/{service_name}.conf'
+systemd_override = r'/run/systemd/system/zabbix-agent2.service.d/10-override.conf'
+
+
+def get_config(config=None):
+ if config:
+ conf = config
+ else:
+ conf = Config()
+
+ base = ['service', 'monitoring', 'zabbix-agent']
+
+ if not conf.exists(base):
+ return None
+
+ config = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ no_tag_node_value_mangle=True,
+ with_recursive_defaults=True)
+
+ # Cut the / from the end, /tmp/ => /tmp
+ if 'directory' in config and config['directory'].endswith('/'):
+ config['directory'] = config['directory'][:-1]
+
+ return config
+
+
+def verify(config):
+ # bail out early - looks like removal from running config
+ if config is None:
+ return
+
+ if 'server' not in config:
+ raise ConfigError('Server is required!')
+
+
+def generate(config):
+ # bail out early - looks like removal from running config
+ if config is None:
+ # Remove old config and return
+ config_files = [service_conf, systemd_override]
+ for file in config_files:
+ if os.path.isfile(file):
+ os.unlink(file)
+
+ return None
+
+ # Write configuration file
+ render(service_conf, 'zabbix-agent/zabbix-agent.conf.j2', config)
+ render(systemd_override, 'zabbix-agent/10-override.conf.j2', config)
+
+ return None
+
+
+def apply(config):
+ call('systemctl daemon-reload')
+ if config:
+ call(f'systemctl restart {service_name}.service')
+ else:
+ call(f'systemctl stop {service_name}.service')
+
+
+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_router-advert.py b/src/conf_mode/service_router-advert.py
index fe33c43ea..dbb47de4e 100755
--- a/src/conf_mode/service_router-advert.py
+++ b/src/conf_mode/service_router-advert.py
@@ -19,10 +19,8 @@ import os
from sys import exit
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.utils.process import call
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -35,40 +33,9 @@ def get_config(config=None):
else:
conf = Config()
base = ['service', 'router-advert']
- rtradv = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
-
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_interface_values = defaults(base + ['interface'])
- # we deal with prefix, route defaults later on
- if 'prefix' in default_interface_values:
- del default_interface_values['prefix']
- if 'route' in default_interface_values:
- del default_interface_values['route']
-
- default_prefix_values = defaults(base + ['interface', 'prefix'])
- default_route_values = defaults(base + ['interface', 'route'])
-
- if 'interface' in rtradv:
- for interface in rtradv['interface']:
- rtradv['interface'][interface] = dict_merge(
- default_interface_values, rtradv['interface'][interface])
-
- if 'prefix' in rtradv['interface'][interface]:
- for prefix in rtradv['interface'][interface]['prefix']:
- rtradv['interface'][interface]['prefix'][prefix] = dict_merge(
- default_prefix_values, rtradv['interface'][interface]['prefix'][prefix])
-
- if 'route' in rtradv['interface'][interface]:
- for route in rtradv['interface'][interface]['route']:
- rtradv['interface'][interface]['route'][route] = dict_merge(
- default_route_values, rtradv['interface'][interface]['route'][route])
-
- if 'name_server' in rtradv['interface'][interface]:
- # always use a list when dealing with nameservers - eases the template generation
- if isinstance(rtradv['interface'][interface]['name_server'], str):
- rtradv['interface'][interface]['name_server'] = [
- rtradv['interface'][interface]['name_server']]
+ rtradv = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
return rtradv
diff --git a/src/conf_mode/service_sla.py b/src/conf_mode/service_sla.py
index 54b72e029..ba5e645f0 100755
--- a/src/conf_mode/service_sla.py
+++ b/src/conf_mode/service_sla.py
@@ -19,10 +19,8 @@ import os
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.utils.process import call
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -44,11 +42,9 @@ def get_config(config=None):
if not conf.exists(base):
return None
- sla = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- sla = dict_merge(default_values, sla)
+ sla = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
# Ignore default XML values if config doesn't exists
# Delete key from dict
diff --git a/src/conf_mode/service_upnp.py b/src/conf_mode/service_upnp.py
index b37d502c2..cf26bf9ce 100755
--- a/src/conf_mode/service_upnp.py
+++ b/src/conf_mode/service_upnp.py
@@ -23,12 +23,10 @@ from ipaddress import IPv4Network
from ipaddress import IPv6Network
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.utils.process import call
from vyos.template import render
from vyos.template import is_ipv4
from vyos.template import is_ipv6
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -47,10 +45,7 @@ def get_config(config=None):
if not upnpd:
return None
- if 'rule' in upnpd:
- default_member_values = defaults(base + ['rule'])
- for rule,rule_config in upnpd['rule'].items():
- upnpd['rule'][rule] = dict_merge(default_member_values, upnpd['rule'][rule])
+ upnpd = conf.merge_defaults(upnpd, recursive=True)
uuidgen = uuid.uuid1()
upnpd.update({'uuid': uuidgen})
diff --git a/src/conf_mode/service_webproxy.py b/src/conf_mode/service_webproxy.py
index bbdb756bd..12ae4135e 100755
--- a/src/conf_mode/service_webproxy.py
+++ b/src/conf_mode/service_webproxy.py
@@ -20,14 +20,13 @@ from shutil import rmtree
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
+from vyos.config import config_dict_merge
from vyos.template import render
from vyos.utils.process import call
from vyos.utils.permission import chmod_755
from vyos.utils.dict import dict_search
from vyos.utils.file import write_file
-from vyos.validate import is_addr_assigned
-from vyos.xml import defaults
+from vyos.utils.network import is_addr_assigned
from vyos.base import Warning
from vyos import ConfigError
from vyos import airbag
@@ -125,7 +124,8 @@ def get_config(config=None):
get_first_key=True)
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- default_values = defaults(base)
+ default_values = conf.get_config_defaults(**proxy.kwargs,
+ recursive=True)
# if no authentication method is supplied, no need to add defaults
if not dict_search('authentication.method', proxy):
@@ -138,16 +138,7 @@ def get_config(config=None):
proxy['squidguard_conf'] = squidguard_config_file
proxy['squidguard_db_dir'] = squidguard_db_dir
- # XXX: T2665: blend in proper cache-peer default values later
- default_values.pop('cache_peer')
- proxy = dict_merge(default_values, proxy)
-
- # XXX: T2665: blend in proper cache-peer default values
- if 'cache_peer' in proxy:
- default_values = defaults(base + ['cache-peer'])
- for peer in proxy['cache_peer']:
- proxy['cache_peer'][peer] = dict_merge(default_values,
- proxy['cache_peer'][peer])
+ proxy = config_dict_merge(default_values, proxy)
return proxy
diff --git a/src/conf_mode/snmp.py b/src/conf_mode/snmp.py
index 0f0d97ac3..7882f8510 100755
--- a/src/conf_mode/snmp.py
+++ b/src/conf_mode/snmp.py
@@ -29,9 +29,8 @@ from vyos.template import render
from vyos.utils.process import call
from vyos.utils.permission import chmod_755
from vyos.utils.dict import dict_search
-from vyos.validate import is_addr_assigned
+from vyos.utils.network import is_addr_assigned
from vyos.version import get_version_data
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -70,26 +69,9 @@ def get_config(config=None):
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- default_values = defaults(base)
-
- # We can not merge defaults for tagNodes - those need to be blended in
- # per tagNode instance
- if 'listen_address' in default_values:
- del default_values['listen_address']
- if 'community' in default_values:
- del default_values['community']
- if 'trap_target' in default_values:
- del default_values['trap_target']
- if 'v3' in default_values:
- del default_values['v3']
- snmp = dict_merge(default_values, snmp)
+ snmp = conf.merge_defaults(snmp, recursive=True)
if 'listen_address' in snmp:
- default_values = defaults(base + ['listen-address'])
- for address in snmp['listen_address']:
- snmp['listen_address'][address] = dict_merge(
- default_values, snmp['listen_address'][address])
-
# Always listen on localhost if an explicit address has been configured
# This is a safety measure to not end up with invalid listen addresses
# that are not configured on this system. See https://vyos.dev/T850
@@ -101,41 +83,6 @@ def get_config(config=None):
tmp = {'::1': {'port': '161'}}
snmp['listen_address'] = dict_merge(tmp, snmp['listen_address'])
- if 'community' in snmp:
- default_values = defaults(base + ['community'])
- if 'network' in default_values:
- # convert multiple default networks to list
- default_values['network'] = default_values['network'].split()
- for community in snmp['community']:
- snmp['community'][community] = dict_merge(
- default_values, snmp['community'][community])
-
- if 'trap_target' in snmp:
- default_values = defaults(base + ['trap-target'])
- for trap in snmp['trap_target']:
- snmp['trap_target'][trap] = dict_merge(
- default_values, snmp['trap_target'][trap])
-
- if 'v3' in snmp:
- default_values = defaults(base + ['v3'])
- # tagNodes need to be merged in individually later on
- for tmp in ['user', 'group', 'trap_target']:
- del default_values[tmp]
- snmp['v3'] = dict_merge(default_values, snmp['v3'])
-
- for user_group in ['user', 'group']:
- if user_group in snmp['v3']:
- default_values = defaults(base + ['v3', user_group])
- for tmp in snmp['v3'][user_group]:
- snmp['v3'][user_group][tmp] = dict_merge(
- default_values, snmp['v3'][user_group][tmp])
-
- if 'trap_target' in snmp['v3']:
- default_values = defaults(base + ['v3', 'trap-target'])
- for trap in snmp['v3']['trap_target']:
- snmp['v3']['trap_target'][trap] = dict_merge(
- default_values, snmp['v3']['trap_target'][trap])
-
return snmp
def verify(snmp):
diff --git a/src/conf_mode/ssh.py b/src/conf_mode/ssh.py
index 3b63fcb7d..ee5e1eca2 100755
--- a/src/conf_mode/ssh.py
+++ b/src/conf_mode/ssh.py
@@ -21,12 +21,10 @@ from syslog import syslog
from syslog import LOG_INFO
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configdict import is_node_changed
from vyos.configverify import verify_vrf
from vyos.utils.process import call
from vyos.template import render
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -57,8 +55,8 @@ def get_config(config=None):
# We have gathered the dict representation of the CLI, but there are default
# options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- ssh = dict_merge(default_values, ssh)
+ ssh = conf.merge_defaults(ssh, recursive=True)
+
# pass config file path - used in override template
ssh['config_file'] = config_file
diff --git a/src/conf_mode/system-ip.py b/src/conf_mode/system-ip.py
index cca996e4f..63dff0e36 100755
--- a/src/conf_mode/system-ip.py
+++ b/src/conf_mode/system-ip.py
@@ -24,7 +24,6 @@ from vyos.utils.process import call
from vyos.utils.dict import dict_search
from vyos.utils.file import write_file
from vyos.utils.system import sysctl_write
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -37,11 +36,9 @@ def get_config(config=None):
conf = Config()
base = ['system', 'ip']
- opt = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- opt = dict_merge(default_values, opt)
+ opt = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
# When working with FRR we need to know the corresponding address-family
opt['afi'] = 'ip'
diff --git a/src/conf_mode/system-ipv6.py b/src/conf_mode/system-ipv6.py
index 22210c27a..8a4df11fa 100755
--- a/src/conf_mode/system-ipv6.py
+++ b/src/conf_mode/system-ipv6.py
@@ -24,7 +24,6 @@ from vyos.template import render_to_string
from vyos.utils.dict import dict_search
from vyos.utils.system import sysctl_write
from vyos.utils.file import write_file
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import frr
from vyos import airbag
@@ -37,12 +36,9 @@ def get_config(config=None):
conf = Config()
base = ['system', 'ipv6']
- opt = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
-
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- opt = dict_merge(default_values, opt)
+ opt = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
# When working with FRR we need to know the corresponding address-family
opt['afi'] = 'ipv6'
diff --git a/src/conf_mode/system-login.py b/src/conf_mode/system-login.py
index afd75913e..02c97afaa 100755
--- a/src/conf_mode/system-login.py
+++ b/src/conf_mode/system-login.py
@@ -24,7 +24,6 @@ from sys import exit
from time import sleep
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configverify import verify_vrf
from vyos.defaults import directories
from vyos.template import render
@@ -35,7 +34,6 @@ from vyos.utils.process import call
from vyos.utils.process import rc_cmd
from vyos.utils.process import run
from vyos.utils.process import DEVNULL
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -54,7 +52,7 @@ MAX_USER_UID: int = 59999
# LOGIN_TIMEOUT from /etc/loign.defs minus 10 sec
MAX_RADIUS_TIMEOUT: int = 50
# MAX_RADIUS_TIMEOUT divided by 2 sec (minimum recomended timeout)
-MAX_RADIUS_COUNT: int = 25
+MAX_RADIUS_COUNT: int = 8
# Maximum number of supported TACACS servers
MAX_TACACS_COUNT: int = 8
@@ -93,7 +91,9 @@ def get_config(config=None):
conf = Config()
base = ['system', 'login']
login = conf.get_config_dict(base, key_mangling=('-', '_'),
- no_tag_node_value_mangle=True, get_first_key=True)
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True)
# users no longer existing in the running configuration need to be deleted
local_users = get_local_users()
@@ -101,27 +101,9 @@ def get_config(config=None):
if 'user' in login:
cli_users = list(login['user'])
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- default_values = defaults(base + ['user'])
- for user in login['user']:
- login['user'][user] = dict_merge(default_values, login['user'][user])
-
- # Add TACACS global defaults
- if 'tacacs' in login:
- default_values = defaults(base + ['tacacs'])
- if 'server' in default_values:
- del default_values['server']
- login['tacacs'] = dict_merge(default_values, login['tacacs'])
-
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- for backend in ['radius', 'tacacs']:
- default_values = defaults(base + [backend, 'server'])
- for server in dict_search(f'{backend}.server', login) or []:
- login[backend]['server'][server] = dict_merge(default_values,
- login[backend]['server'][server])
-
+ # prune TACACS global defaults if not set by user
+ if login.from_defaults(['tacacs']):
+ del login['tacacs']
# create a list of all users, cli and users
all_users = list(set(local_users + cli_users))
diff --git a/src/conf_mode/system-logs.py b/src/conf_mode/system-logs.py
index 12145d641..8ad4875d4 100755
--- a/src/conf_mode/system-logs.py
+++ b/src/conf_mode/system-logs.py
@@ -19,11 +19,9 @@ from sys import exit
from vyos import ConfigError
from vyos import airbag
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.logger import syslog
from vyos.template import render
from vyos.utils.dict import dict_search
-from vyos.xml import defaults
airbag.enable()
# path to logrotate configs
@@ -38,11 +36,9 @@ def get_config(config=None):
conf = Config()
base = ['system', 'logs']
- default_values = defaults(base)
- logs_config = conf.get_config_dict(base,
- key_mangling=('-', '_'),
- get_first_key=True)
- logs_config = dict_merge(default_values, logs_config)
+ logs_config = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
return logs_config
diff --git a/src/conf_mode/system-option.py b/src/conf_mode/system-option.py
index 5172b492e..d92121b3d 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-2022 VyOS maintainers and contributors
+# Copyright (C) 2019-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
@@ -21,14 +21,12 @@ from sys import exit
from time import sleep
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configverify import verify_source_interface
from vyos.template import render
from vyos.utils.process import cmd
from vyos.utils.process import is_systemd_service_running
-from vyos.validate import is_addr_assigned
-from vyos.validate import is_intf_addr_assigned
-from vyos.xml import defaults
+from vyos.utils.network import is_addr_assigned
+from vyos.utils.network import is_intf_addr_assigned
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -36,6 +34,11 @@ airbag.enable()
curlrc_config = r'/etc/curlrc'
ssh_config = r'/etc/ssh/ssh_config.d/91-vyos-ssh-client-options.conf'
systemd_action_file = '/lib/systemd/system/ctrl-alt-del.target'
+time_format_to_locale = {
+ '12-hour': 'en_US.UTF-8',
+ '24-hour': 'en_GB.UTF-8'
+}
+
def get_config(config=None):
if config:
@@ -43,12 +46,9 @@ def get_config(config=None):
else:
conf = Config()
base = ['system', 'option']
- options = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
-
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- options = dict_merge(default_values, options)
+ options = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
return options
@@ -143,6 +143,11 @@ def apply(options):
else:
cmd('systemctl disable root-partition-auto-resize.service')
+ # Time format 12|24-hour
+ if 'time_format' in options:
+ time_format = time_format_to_locale.get(options['time_format'])
+ cmd(f'localectl set-locale LC_TIME={time_format}')
+
if __name__ == '__main__':
try:
c = get_config()
diff --git a/src/conf_mode/system-syslog.py b/src/conf_mode/system-syslog.py
index 19c87bcee..07fbb0734 100755
--- a/src/conf_mode/system-syslog.py
+++ b/src/conf_mode/system-syslog.py
@@ -19,12 +19,10 @@ import os
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configdict import is_node_changed
from vyos.configverify import verify_vrf
from vyos.utils.process import call
from vyos.template import render
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -50,43 +48,9 @@ def get_config(config=None):
tmp = is_node_changed(conf, base + ['vrf'])
if tmp: syslog.update({'restart_required': {}})
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- # XXX: some syslog default values can not be merged here (originating from
- # a tagNode - remove and add them later per individual tagNode instance
- if 'console' in default_values:
- del default_values['console']
- for entity in ['global', 'user', 'host', 'file']:
- if entity in default_values:
- del default_values[entity]
-
- syslog = dict_merge(default_values, syslog)
-
- # XXX: add defaults for "console" tree
- if 'console' in syslog and 'facility' in syslog['console']:
- default_values = defaults(base + ['console', 'facility'])
- for facility in syslog['console']['facility']:
- syslog['console']['facility'][facility] = dict_merge(default_values,
- syslog['console']['facility'][facility])
-
- # XXX: add defaults for "host" tree
- for syslog_type in ['host', 'user', 'file']:
- # Bail out early if there is nothing to do
- if syslog_type not in syslog:
- continue
-
- default_values_host = defaults(base + [syslog_type])
- if 'facility' in default_values_host:
- del default_values_host['facility']
-
- for tmp, tmp_config in syslog[syslog_type].items():
- syslog[syslog_type][tmp] = dict_merge(default_values_host, syslog[syslog_type][tmp])
- if 'facility' in tmp_config:
- default_values_facility = defaults(base + [syslog_type, 'facility'])
- for facility in tmp_config['facility']:
- syslog[syslog_type][tmp]['facility'][facility] = dict_merge(default_values_facility,
- syslog[syslog_type][tmp]['facility'][facility])
+ syslog = conf.merge_defaults(syslog, recursive=True)
+ if syslog.from_defaults(['global']):
+ del syslog['global']
return syslog
diff --git a/src/conf_mode/system_console.py b/src/conf_mode/system_console.py
index 87d587959..ebf9a113b 100755
--- a/src/conf_mode/system_console.py
+++ b/src/conf_mode/system_console.py
@@ -19,12 +19,10 @@ import re
from pathlib import Path
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.utils.process import call
from vyos.utils.file import read_file
from vyos.utils.file import write_file
from vyos.template import render
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -45,16 +43,12 @@ def get_config(config=None):
if 'device' not in console:
return console
- # convert CLI values to system values
- default_values = defaults(base + ['device'])
for device, device_config in console['device'].items():
if 'speed' not in device_config and device.startswith('hvc'):
# XEN console has a different default console speed
console['device'][device]['speed'] = 38400
- else:
- # Merge in XML defaults - the proper way to do it
- console['device'][device] = dict_merge(default_values,
- console['device'][device])
+
+ console = conf.merge_defaults(console, recursive=True)
return console
diff --git a/src/conf_mode/system_sflow.py b/src/conf_mode/system_sflow.py
index 9e3d41100..2df1bbb7a 100755
--- a/src/conf_mode/system_sflow.py
+++ b/src/conf_mode/system_sflow.py
@@ -19,11 +19,9 @@ import os
from sys import exit
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.template import render
from vyos.utils.process import call
-from vyos.validate import is_addr_assigned
-from vyos.xml import defaults
+from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -42,26 +40,9 @@ def get_config(config=None):
if not conf.exists(base):
return None
- sflow = conf.get_config_dict(base,
- key_mangling=('-', '_'),
- get_first_key=True)
-
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
-
- sflow = dict_merge(default_values, sflow)
-
- # Ignore default XML values if config doesn't exists
- # Delete key from dict
- if 'port' in sflow['server']:
- del sflow['server']['port']
-
- # Set default values per server
- if 'server' in sflow:
- for server in sflow['server']:
- default_values = defaults(base + ['server'])
- sflow['server'][server] = dict_merge(default_values, sflow['server'][server])
+ sflow = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
return sflow
diff --git a/src/conf_mode/tftp_server.py b/src/conf_mode/tftp_server.py
index 2735772dc..3ad346e2e 100755
--- a/src/conf_mode/tftp_server.py
+++ b/src/conf_mode/tftp_server.py
@@ -24,14 +24,12 @@ from sys import exit
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.configverify import verify_vrf
from vyos.template import render
from vyos.template import is_ipv4
from vyos.utils.process import call
from vyos.utils.permission import chmod_755
-from vyos.validate import is_addr_assigned
-from vyos.xml import defaults
+from vyos.utils.network import is_addr_assigned
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -48,11 +46,9 @@ def get_config(config=None):
if not conf.exists(base):
return None
- tftpd = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- tftpd = dict_merge(default_values, tftpd)
+ tftpd = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
return tftpd
def verify(tftpd):
diff --git a/src/conf_mode/vpn_ipsec.py b/src/conf_mode/vpn_ipsec.py
index b0825d0ee..fa271cbdb 100755
--- a/src/conf_mode/vpn_ipsec.py
+++ b/src/conf_mode/vpn_ipsec.py
@@ -27,7 +27,7 @@ from vyos.base import Warning
from vyos.config import Config
from vyos.configdict import leaf_node_changed
from vyos.configverify import verify_interface_exists
-from vyos.configdict import dict_merge
+from vyos.defaults import directories
from vyos.ifconfig import Interface
from vyos.pki import encode_public_key
from vyos.pki import load_private_key
@@ -39,12 +39,11 @@ from vyos.template import ip_from_cidr
from vyos.template import is_ipv4
from vyos.template import is_ipv6
from vyos.template import render
-from vyos.validate import is_ipv6_link_local
+from vyos.utils.network import is_ipv6_link_local
from vyos.utils.dict import dict_search
from vyos.utils.dict import dict_search_args
from vyos.utils.process import call
from vyos.utils.process import run
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
airbag.enable()
@@ -69,7 +68,6 @@ KEY_PATH = f'{swanctl_dir}/private/'
CA_PATH = f'{swanctl_dir}/x509ca/'
CRL_PATH = f'{swanctl_dir}/x509crl/'
-DHCP_BASE = '/var/lib/dhcp/dhclient'
DHCP_HOOK_IFLIST = '/tmp/ipsec_dhcp_waiting'
def get_config(config=None):
@@ -84,88 +82,23 @@ def get_config(config=None):
# retrieve common dictionary keys
ipsec = conf.get_config_dict(base, key_mangling=('-', '_'),
- get_first_key=True, no_tag_node_value_mangle=True)
-
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- # XXX: T2665: we must safely remove default values for tag nodes, those are
- # added in a more fine grained way later on
- del default_values['esp_group']
- del default_values['ike_group']
- del default_values['remote_access']
- del default_values['site_to_site']
- ipsec = dict_merge(default_values, ipsec)
-
- if 'esp_group' in ipsec:
- default_values = defaults(base + ['esp-group'])
- for group in ipsec['esp_group']:
- ipsec['esp_group'][group] = dict_merge(default_values,
- ipsec['esp_group'][group])
- if 'ike_group' in ipsec:
- default_values = defaults(base + ['ike-group'])
- # proposal is a tag node which may come with individual defaults per node
- if 'proposal' in default_values:
- del default_values['proposal']
-
- for group in ipsec['ike_group']:
- ipsec['ike_group'][group] = dict_merge(default_values,
- ipsec['ike_group'][group])
-
- if 'proposal' in ipsec['ike_group'][group]:
- default_values = defaults(base + ['ike-group', 'proposal'])
- for proposal in ipsec['ike_group'][group]['proposal']:
- ipsec['ike_group'][group]['proposal'][proposal] = dict_merge(default_values,
- ipsec['ike_group'][group]['proposal'][proposal])
-
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- if dict_search('remote_access.connection', ipsec):
- default_values = defaults(base + ['remote-access', 'connection'])
- for rw in ipsec['remote_access']['connection']:
- ipsec['remote_access']['connection'][rw] = dict_merge(default_values,
- ipsec['remote_access']['connection'][rw])
-
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- if dict_search('remote_access.radius.server', ipsec):
- # Fist handle the "base" stuff like RADIUS timeout
- default_values = defaults(base + ['remote-access', 'radius'])
- if 'server' in default_values:
- del default_values['server']
- ipsec['remote_access']['radius'] = dict_merge(default_values,
- ipsec['remote_access']['radius'])
-
- # Take care about individual RADIUS servers implemented as tagNodes - this
- # requires special treatment
- default_values = defaults(base + ['remote-access', 'radius', 'server'])
- for server in ipsec['remote_access']['radius']['server']:
- ipsec['remote_access']['radius']['server'][server] = dict_merge(default_values,
- ipsec['remote_access']['radius']['server'][server])
-
- # XXX: T2665: we can not safely rely on the defaults() when there are
- # tagNodes in place, it is better to blend in the defaults manually.
- if dict_search('site_to_site.peer', ipsec):
- default_values = defaults(base + ['site-to-site', 'peer'])
- for peer in ipsec['site_to_site']['peer']:
- ipsec['site_to_site']['peer'][peer] = dict_merge(default_values,
- ipsec['site_to_site']['peer'][peer])
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True)
ipsec['dhcp_no_address'] = {}
ipsec['install_routes'] = 'no' if conf.exists(base + ["options", "disable-route-autoinstall"]) else default_install_routes
ipsec['interface_change'] = leaf_node_changed(conf, base + ['interface'])
ipsec['nhrp_exists'] = conf.exists(['protocols', 'nhrp', 'tunnel'])
ipsec['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),
- get_first_key=True,
- no_tag_node_value_mangle=True)
+ no_tag_node_value_mangle=True,
+ get_first_key=True)
tmp = conf.get_config_dict(l2tp_base, key_mangling=('-', '_'),
- get_first_key=True,
- no_tag_node_value_mangle=True)
+ no_tag_node_value_mangle=True,
+ get_first_key=True)
if tmp:
- ipsec['l2tp'] = tmp
- l2tp_defaults = defaults(l2tp_base)
- ipsec['l2tp'] = dict_merge(l2tp_defaults, ipsec['l2tp'])
+ ipsec['l2tp'] = conf.merge_defaults(tmp, recursive=True)
ipsec['l2tp_outside_address'] = conf.return_value(['vpn', 'l2tp', 'remote-access', 'outside-address'])
ipsec['l2tp_ike_default'] = 'aes256-sha1-modp1024,3des-sha1-modp1024'
ipsec['l2tp_esp_default'] = 'aes256-sha1,3des-sha1'
@@ -433,8 +366,9 @@ def verify(ipsec):
dhcp_interface = peer_conf['dhcp_interface']
verify_interface_exists(dhcp_interface)
+ dhcp_base = directories['isc_dhclient_dir']
- if not os.path.exists(f'{DHCP_BASE}_{dhcp_interface}.conf'):
+ if not os.path.exists(f'{dhcp_base}/dhclient_{dhcp_interface}.conf'):
raise ConfigError(f"Invalid dhcp-interface on site-to-site peer {peer}")
address = get_dhcp_address(dhcp_interface)
diff --git a/src/conf_mode/vpn_openconnect.py b/src/conf_mode/vpn_openconnect.py
index e82862fa3..a039172c4 100755
--- a/src/conf_mode/vpn_openconnect.py
+++ b/src/conf_mode/vpn_openconnect.py
@@ -19,7 +19,6 @@ from sys import exit
from vyos.base import Warning
from vyos.config import Config
-from vyos.configdict import dict_merge
from vyos.pki import wrap_certificate
from vyos.pki import wrap_private_key
from vyos.template import render
@@ -28,7 +27,6 @@ from vyos.utils.network import check_port_availability
from vyos.utils.process import is_systemd_service_running
from vyos.utils.network import is_listen_port_bind_service
from vyos.utils.dict import dict_search
-from vyos.xml import defaults
from vyos import ConfigError
from passlib.hash import sha512_crypt
from time import sleep
@@ -47,66 +45,6 @@ radius_servers = cfg_dir + '/radius_servers'
def get_hash(password):
return sha512_crypt.hash(password)
-
-
-def _default_dict_cleanup(origin: dict, default_values: dict) -> dict:
- """
- https://vyos.dev/T2665
- Clear unnecessary key values in merged config by dict_merge function
- :param origin: config
- :type origin: dict
- :param default_values: default values
- :type default_values: dict
- :return: merged dict
- :rtype: dict
- """
- if 'mode' in origin["authentication"] and "local" in \
- origin["authentication"]["mode"]:
- del origin['authentication']['local_users']['username']['otp']
- if not origin["authentication"]["local_users"]["username"]:
- raise ConfigError(
- 'Openconnect authentication mode local requires at least one user')
- default_ocserv_usr_values = \
- default_values['authentication']['local_users']['username']['otp']
- for user, params in origin['authentication']['local_users'][
- 'username'].items():
- # Not every configuration requires OTP settings
- if origin['authentication']['local_users']['username'][user].get(
- 'otp'):
- origin['authentication']['local_users']['username'][user][
- 'otp'] = dict_merge(default_ocserv_usr_values,
- origin['authentication'][
- 'local_users']['username'][user][
- 'otp'])
-
- if 'mode' in origin["authentication"] and "radius" in \
- origin["authentication"]["mode"]:
- del origin['authentication']['radius']['server']['port']
- if not origin["authentication"]['radius']['server']:
- raise ConfigError(
- 'Openconnect authentication mode radius requires at least one RADIUS server')
- default_values_radius_port = \
- default_values['authentication']['radius']['server']['port']
- for server, params in origin['authentication']['radius'][
- 'server'].items():
- if 'port' not in params:
- params['port'] = default_values_radius_port
-
- if 'mode' in origin["accounting"] and "radius" in \
- origin["accounting"]["mode"]:
- del origin['accounting']['radius']['server']['port']
- if not origin["accounting"]['radius']['server']:
- raise ConfigError(
- 'Openconnect accounting mode radius requires at least one RADIUS server')
- default_values_radius_port = \
- default_values['accounting']['radius']['server']['port']
- for server, params in origin['accounting']['radius'][
- 'server'].items():
- if 'port' not in params:
- params['port'] = default_values_radius_port
- return origin
-
-
def get_config(config=None):
if config:
conf = config
@@ -116,16 +54,14 @@ def get_config(config=None):
if not conf.exists(base):
return None
- ocserv = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- ocserv = dict_merge(default_values, ocserv)
- # workaround a "know limitation" - https://vyos.dev/T2665
- ocserv = _default_dict_cleanup(ocserv, default_values)
+ ocserv = conf.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
+
if ocserv:
ocserv['pki'] = conf.get_config_dict(['pki'], key_mangling=('-', '_'),
- get_first_key=True, no_tag_node_value_mangle=True)
+ no_tag_node_value_mangle=True,
+ get_first_key=True)
return ocserv
@@ -142,6 +78,8 @@ def verify(ocserv):
# 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"]:
@@ -150,9 +88,13 @@ def verify(ocserv):
# Check authentication
if "authentication" in ocserv:
if "mode" in ocserv["authentication"]:
- if "local" in ocserv["authentication"]["mode"]:
- if "radius" in ocserv["authentication"]["mode"]:
+ 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["authentication"]["local_users"]:
raise ConfigError('openconnect mode local required at least one user')
if not ocserv["authentication"]["local_users"]["username"]:
diff --git a/src/conf_mode/vpp.py b/src/conf_mode/vpp.py
index 80ce1e8e3..82c2f236e 100755
--- a/src/conf_mode/vpp.py
+++ b/src/conf_mode/vpp.py
@@ -22,7 +22,6 @@ from re import search as re_search, MULTILINE as re_M
from vyos.config import Config
from vyos.configdep import set_dependents, call_dependents
-from vyos.configdict import dict_merge
from vyos.configdict import node_changed
from vyos.ifconfig import Section
from vyos.utils.boot import boot_configuration_complete
@@ -31,7 +30,6 @@ from vyos.utils.process import rc_cmd
from vyos.utils.system import sysctl_read
from vyos.utils.system import sysctl_apply
from vyos.template import render
-from vyos.xml import defaults
from vyos import ConfigError
from vyos import airbag
@@ -94,28 +92,18 @@ def get_config(config=None):
if not conf.exists(base):
return {'removed_ifaces': removed_ifaces}
- config = conf.get_config_dict(base,
+ config = conf.get_config_dict(base, key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
get_first_key=True,
- key_mangling=('-', '_'),
- no_tag_node_value_mangle=True)
-
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- if 'interface' in default_values:
- del default_values['interface']
- config = dict_merge(default_values, config)
+ with_recursive_defaults=True)
if 'interface' in config:
for iface, iface_config in config['interface'].items():
- default_values_iface = defaults(base + ['interface'])
- config['interface'][iface] = dict_merge(default_values_iface, config['interface'][iface])
# add an interface to a list of interfaces that need
# to be reinitialized after the commit
set_dependents('ethernet', conf, iface)
- # Get PCI address auto
- for iface, iface_config in config['interface'].items():
+ # Get PCI address auto
if iface_config['pci'] == 'auto':
config['interface'][iface]['pci'] = _get_pci_address_by_interface(iface)
diff --git a/src/etc/dhcp/dhclient-exit-hooks.d/03-vyatta-dhclient-hook b/src/etc/dhcp/dhclient-exit-hooks.d/03-vyos-dhclient-hook
index 49bb18372..35721d009 100644
--- a/src/etc/dhcp/dhclient-exit-hooks.d/03-vyatta-dhclient-hook
+++ b/src/etc/dhcp/dhclient-exit-hooks.d/03-vyos-dhclient-hook
@@ -28,7 +28,8 @@ if [[ $reason =~ ^(REBOOT6|INIT6|EXPIRE6|RELEASE6|STOP6|INFORM6|BOUND6|REBIND6|D
fi
if [ "$RUN" = "yes" ]; then
- LOG=/var/lib/dhcp/dhclient_"$interface"."$proto"lease
+ BASE_PATH=$(python3 -c "from vyos.defaults import directories; print(directories['isc_dhclient_dir'])")
+ LOG=${BASE_PATH}/dhclient_"$interface"."$proto"lease
echo `date` > $LOG
for i in reason interface new_expiry new_dhcp_lease_time medium \
diff --git a/src/helpers/vyos-domain-resolver.py b/src/helpers/vyos-domain-resolver.py
index 2036ca72e..7e2fe2462 100755
--- a/src/helpers/vyos-domain-resolver.py
+++ b/src/helpers/vyos-domain-resolver.py
@@ -26,7 +26,7 @@ from vyos.utils.commit import commit_in_progress
from vyos.utils.dict import dict_search_args
from vyos.utils.process import cmd
from vyos.utils.process import run
-from vyos.xml import defaults
+from vyos.xml_ref import get_defaults
base = ['firewall']
timeout = 300
@@ -49,13 +49,7 @@ def get_config(conf):
firewall = conf.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True,
no_tag_node_value_mangle=True)
- default_values = defaults(base)
- for tmp in ['name', 'ipv6_name']:
- if tmp in default_values:
- del default_values[tmp]
-
- if 'zone' in default_values:
- del default_values['zone']
+ default_values = get_defaults(base, get_first_key=True)
firewall = dict_merge(default_values, firewall)
diff --git a/src/init/vyos-router b/src/init/vyos-router
index 7b752b84b..96f163213 100755
--- a/src/init/vyos-router
+++ b/src/init/vyos-router
@@ -101,6 +101,16 @@ load_bootfile ()
)
}
+# restore if missing pre-config script
+restore_if_missing_preconfig_script ()
+{
+ if [ ! -x ${vyatta_sysconfdir}/config/scripts/vyos-preconfig-bootup.script ]; then
+ cp ${vyos_rootfs_dir}/opt/vyatta/etc/config/scripts/vyos-preconfig-bootup.script ${vyatta_sysconfdir}/config/scripts/
+ chgrp ${GROUP} ${vyatta_sysconfdir}/config/scripts/vyos-preconfig-bootup.script
+ chmod 750 ${vyatta_sysconfdir}/config/scripts/vyos-preconfig-bootup.script
+ fi
+}
+
# execute the pre-config script
run_preconfig_script ()
{
@@ -109,6 +119,16 @@ run_preconfig_script ()
fi
}
+# restore if missing post-config script
+restore_if_missing_postconfig_script ()
+{
+ if [ ! -x ${vyatta_sysconfdir}/config/scripts/vyos-postconfig-bootup.script ]; then
+ cp ${vyos_rootfs_dir}/opt/vyatta/etc/config/scripts/vyos-postconfig-bootup.script ${vyatta_sysconfdir}/config/scripts/
+ chgrp ${GROUP} ${vyatta_sysconfdir}/config/scripts/vyos-postconfig-bootup.script
+ chmod 750 ${vyatta_sysconfdir}/config/scripts/vyos-postconfig-bootup.script
+ fi
+}
+
# execute the post-config scripts
run_postconfig_scripts ()
{
@@ -360,6 +380,8 @@ start ()
log_daemon_msg "Starting VyOS router"
disabled migrate || migrate_bootfile
+ restore_if_missing_preconfig_script
+
run_preconfig_script
run_postupgrade_script
@@ -384,6 +406,8 @@ start ()
telinit q
chmod g-w,o-w /
+ restore_if_missing_postconfig_script
+
run_postconfig_scripts
}
diff --git a/src/migration-scripts/bgp/0-to-1 b/src/migration-scripts/bgp/0-to-1
index 5e9dffe1f..03c45107b 100755
--- a/src/migration-scripts/bgp/0-to-1
+++ b/src/migration-scripts/bgp/0-to-1
@@ -21,7 +21,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/bgp/1-to-2 b/src/migration-scripts/bgp/1-to-2
index e2d3fcd33..96b939b47 100755
--- a/src/migration-scripts/bgp/1-to-2
+++ b/src/migration-scripts/bgp/1-to-2
@@ -21,7 +21,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/bgp/2-to-3 b/src/migration-scripts/bgp/2-to-3
index 7ced0a3b0..34d321a96 100755
--- a/src/migration-scripts/bgp/2-to-3
+++ b/src/migration-scripts/bgp/2-to-3
@@ -21,7 +21,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/bgp/3-to-4 b/src/migration-scripts/bgp/3-to-4
index 0df2fbec4..894cdda2b 100755
--- a/src/migration-scripts/bgp/3-to-4
+++ b/src/migration-scripts/bgp/3-to-4
@@ -22,7 +22,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/config-management/0-to-1 b/src/migration-scripts/config-management/0-to-1
index 344359110..6528fd136 100755
--- a/src/migration-scripts/config-management/0-to-1
+++ b/src/migration-scripts/config-management/0-to-1
@@ -6,7 +6,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/conntrack-sync/1-to-2 b/src/migration-scripts/conntrack-sync/1-to-2
index ebbd8c35a..a8e1007f3 100755
--- a/src/migration-scripts/conntrack-sync/1-to-2
+++ b/src/migration-scripts/conntrack-sync/1-to-2
@@ -23,7 +23,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/conntrack/1-to-2 b/src/migration-scripts/conntrack/1-to-2
index 4fc88a1ed..c4fe667fc 100755
--- a/src/migration-scripts/conntrack/1-to-2
+++ b/src/migration-scripts/conntrack/1-to-2
@@ -6,7 +6,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/conntrack/2-to-3 b/src/migration-scripts/conntrack/2-to-3
index 8a8b43279..6fb457b7f 100755
--- a/src/migration-scripts/conntrack/2-to-3
+++ b/src/migration-scripts/conntrack/2-to-3
@@ -8,7 +8,7 @@ import sys
from vyos.configtree import ConfigTree
from vyos.version import get_version
-if len(sys.argv) < 1:
+if len(sys.argv) < 2:
print('Must specify file name!')
sys.exit(1)
diff --git a/src/migration-scripts/container/0-to-1 b/src/migration-scripts/container/0-to-1
index 86f89ee04..6b282e082 100755
--- a/src/migration-scripts/container/0-to-1
+++ b/src/migration-scripts/container/0-to-1
@@ -23,7 +23,7 @@ import sys
from vyos.configtree import ConfigTree
from vyos.utils.process import call
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/dhcp-relay/1-to-2 b/src/migration-scripts/dhcp-relay/1-to-2
index b72da1028..508bac6be 100755
--- a/src/migration-scripts/dhcp-relay/1-to-2
+++ b/src/migration-scripts/dhcp-relay/1-to-2
@@ -7,7 +7,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/dhcp-server/4-to-5 b/src/migration-scripts/dhcp-server/4-to-5
index 313b5279a..d15e0baf5 100755
--- a/src/migration-scripts/dhcp-server/4-to-5
+++ b/src/migration-scripts/dhcp-server/4-to-5
@@ -9,7 +9,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/dhcp-server/5-to-6 b/src/migration-scripts/dhcp-server/5-to-6
index aefe84737..f5c766a09 100755
--- a/src/migration-scripts/dhcp-server/5-to-6
+++ b/src/migration-scripts/dhcp-server/5-to-6
@@ -20,7 +20,7 @@
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/dhcpv6-server/0-to-1 b/src/migration-scripts/dhcpv6-server/0-to-1
index 6f1150da1..deae1ca29 100755
--- a/src/migration-scripts/dhcpv6-server/0-to-1
+++ b/src/migration-scripts/dhcpv6-server/0-to-1
@@ -19,7 +19,7 @@
from sys import argv, exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/dns-dynamic/0-to-1 b/src/migration-scripts/dns-dynamic/0-to-1
index cf0983b01..d80e8d44a 100755
--- a/src/migration-scripts/dns-dynamic/0-to-1
+++ b/src/migration-scripts/dns-dynamic/0-to-1
@@ -43,7 +43,7 @@ service_protocol_mapping = {
'zoneedit': 'zoneedit1'
}
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/dns-forwarding/0-to-1 b/src/migration-scripts/dns-forwarding/0-to-1
index 6e8720eef..7f4343652 100755
--- a/src/migration-scripts/dns-forwarding/0-to-1
+++ b/src/migration-scripts/dns-forwarding/0-to-1
@@ -22,7 +22,7 @@
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/dns-forwarding/1-to-2 b/src/migration-scripts/dns-forwarding/1-to-2
index a8c930be7..7df2d47e2 100755
--- a/src/migration-scripts/dns-forwarding/1-to-2
+++ b/src/migration-scripts/dns-forwarding/1-to-2
@@ -25,7 +25,7 @@ from sys import argv, exit
from vyos.ifconfig import Interface
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/dns-forwarding/2-to-3 b/src/migration-scripts/dns-forwarding/2-to-3
index 01e445b22..d7ff9e260 100755
--- a/src/migration-scripts/dns-forwarding/2-to-3
+++ b/src/migration-scripts/dns-forwarding/2-to-3
@@ -21,7 +21,7 @@
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/dns-forwarding/3-to-4 b/src/migration-scripts/dns-forwarding/3-to-4
index 55165c2c5..3d5316ed4 100755
--- a/src/migration-scripts/dns-forwarding/3-to-4
+++ b/src/migration-scripts/dns-forwarding/3-to-4
@@ -20,7 +20,7 @@
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/firewall/10-to-11 b/src/migration-scripts/firewall/10-to-11
new file mode 100755
index 000000000..716c5a240
--- /dev/null
+++ b/src/migration-scripts/firewall/10-to-11
@@ -0,0 +1,374 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# T5160: Firewall re-writing
+
+# cli changes from:
+# set firewall name <name> ...
+# set firewall ipv6-name <name> ...
+# To
+# set firewall ipv4 name <name>
+# set firewall ipv6 name <name>
+
+## Also from 'firewall interface' removed.
+## in and out:
+ # set firewall interface <iface> [in|out] [name | ipv6-name] <name>
+ # To
+ # set firewall [ipv4 | ipv6] forward filter rule <5,10,15,...> [inbound-interface | outboubd-interface] interface-name <iface>
+ # set firewall [ipv4 | ipv6] forward filter rule <5,10,15,...> action jump
+ # set firewall [ipv4 | ipv6] forward filter rule <5,10,15,...> jump-target <name>
+## local:
+ # set firewall interface <iface> local [name | ipv6-name] <name>
+ # To
+ # set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> inbound-interface interface-name <iface>
+ # set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> action jump
+ # set firewall [ipv4 | ipv6] input filter rule <5,10,15,...> jump-target <name>
+
+import re
+
+from sys import argv
+from sys import exit
+
+from vyos.configtree import ConfigTree
+from vyos.ifconfig import Section
+
+if len(argv) < 2:
+ print("Must specify file name!")
+ exit(1)
+
+file_name = argv[1]
+
+with open(file_name, 'r') as f:
+ config_file = f.read()
+
+base = ['firewall']
+config = ConfigTree(config_file)
+
+if not config.exists(base):
+ # Nothing to do
+ exit(0)
+
+### Migration of state policies
+if config.exists(base + ['state-policy']):
+ for family in ['ipv4', 'ipv6']:
+ for hook in ['forward', 'input', 'output']:
+ for priority in ['filter']:
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + [family, hook, priority, 'default-action'], value='accept')
+ position = 1
+ for state in config.list_nodes(base + ['state-policy']):
+ action = config.return_value(base + ['state-policy', state, 'action'])
+ config.set(base + [family, hook, priority, 'rule'])
+ config.set_tag(base + [family, hook, priority, 'rule'])
+ config.set(base + [family, hook, priority, 'rule', position, 'state', state], value='enable')
+ config.set(base + [family, hook, priority, 'rule', position, 'action'], value=action)
+ position = position + 1
+ config.delete(base + ['state-policy'])
+
+## migration of global options:
+for option in ['all-ping', 'broadcast-ping', 'config-trap', 'ip-src-route', 'ipv6-receive-redirects', 'ipv6-src-route', 'log-martians',
+ 'receive-redirects', 'resolver-cache', 'resolver-internal', 'send-redirects', 'source-validation', 'syn-cookies', 'twa-hazards-protection']:
+ if config.exists(base + [option]):
+ if option != 'config-trap':
+ val = config.return_value(base + [option])
+ config.set(base + ['global-options', option], value=val)
+ config.delete(base + [option])
+
+### Migration of firewall name and ipv6-name
+if config.exists(base + ['name']):
+ config.set(['firewall', 'ipv4', 'name'])
+ config.set_tag(['firewall', 'ipv4', 'name'])
+
+ for ipv4name in config.list_nodes(base + ['name']):
+ config.copy(base + ['name', ipv4name], base + ['ipv4', 'name', ipv4name])
+ config.delete(base + ['name'])
+
+if config.exists(base + ['ipv6-name']):
+ config.set(['firewall', 'ipv6', 'name'])
+ config.set_tag(['firewall', 'ipv6', 'name'])
+
+ for ipv6name in config.list_nodes(base + ['ipv6-name']):
+ config.copy(base + ['ipv6-name', ipv6name], base + ['ipv6', 'name', ipv6name])
+ config.delete(base + ['ipv6-name'])
+
+### Migration of firewall interface
+if config.exists(base + ['interface']):
+ fwd_ipv4_rule = 5
+ inp_ipv4_rule = 5
+ fwd_ipv6_rule = 5
+ inp_ipv6_rule = 5
+ for iface in config.list_nodes(base + ['interface']):
+ for direction in ['in', 'out', 'local']:
+ if config.exists(base + ['interface', iface, direction]):
+ if config.exists(base + ['interface', iface, direction, 'name']):
+ target = config.return_value(base + ['interface', iface, direction, 'name'])
+ if direction == 'in':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv4', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target)
+ fwd_ipv4_rule = fwd_ipv4_rule + 5
+ elif direction == 'out':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv4', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv4_rule, 'outbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv4_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv4_rule, 'jump-target'], value=target)
+ fwd_ipv4_rule = fwd_ipv4_rule + 5
+ else:
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'input', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv4', 'input', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [inp_ipv4_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [inp_ipv4_rule, 'action'], value='jump')
+ config.set(new_base + [inp_ipv4_rule, 'jump-target'], value=target)
+ inp_ipv4_rule = inp_ipv4_rule + 5
+
+ if config.exists(base + ['interface', iface, direction, 'ipv6-name']):
+ target = config.return_value(base + ['interface', iface, direction, 'ipv6-name'])
+ if direction == 'in':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv6', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target)
+ fwd_ipv6_rule = fwd_ipv6_rule + 5
+ elif direction == 'out':
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
+ new_base = base + ['ipv6', 'forward', 'filter', 'rule']
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [fwd_ipv6_rule, 'outbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [fwd_ipv6_rule, 'action'], value='jump')
+ config.set(new_base + [fwd_ipv6_rule, 'jump-target'], value=target)
+ fwd_ipv6_rule = fwd_ipv6_rule + 5
+ else:
+ new_base = base + ['ipv6', 'input', 'filter', 'rule']
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv6', 'input', 'filter', 'default-action'], value='accept')
+ config.set(new_base)
+ config.set_tag(new_base)
+ config.set(new_base + [inp_ipv6_rule, 'inbound-interface', 'interface-name'], value=iface)
+ config.set(new_base + [inp_ipv6_rule, 'action'], value='jump')
+ config.set(new_base + [inp_ipv6_rule, 'jump-target'], value=target)
+ inp_ipv6_rule = inp_ipv6_rule + 5
+
+ config.delete(base + ['interface'])
+
+
+### Migration of zones:
+### User interface groups
+if config.exists(base + ['zone']):
+ inp_ipv4_rule = 101
+ inp_ipv6_rule = 101
+ fwd_ipv4_rule = 101
+ fwd_ipv6_rule = 101
+ out_ipv4_rule = 101
+ out_ipv6_rule = 101
+ local_zone = 'False'
+
+ for zone in config.list_nodes(base + ['zone']):
+ if config.exists(base + ['zone', zone, 'local-zone']):
+ local_zone = 'True'
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'input', 'filter', 'default-action'], value='accept')
+ config.set(base + ['ipv6', 'input', 'filter', 'default-action'], value='accept')
+ config.set(base + ['ipv4', 'output', 'filter', 'default-action'], value='accept')
+ config.set(base + ['ipv6', 'output', 'filter', 'default-action'], value='accept')
+ for from_zone in config.list_nodes(base + ['zone', zone, 'from']):
+ group_name = 'IG_' + from_zone
+ if config.exists(base + ['zone', zone, 'from', from_zone, 'firewall', 'name']):
+ # ipv4 input ruleset
+ target_ipv4_chain = config.return_value(base + ['zone', zone, 'from', from_zone, 'firewall', 'name'])
+ config.set(base + ['ipv4', 'input', 'filter', 'rule'])
+ config.set_tag(base + ['ipv4', 'input', 'filter', 'rule'])
+ config.set(base + ['ipv4', 'input', 'filter', 'rule', inp_ipv4_rule, 'inbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv4', 'input', 'filter', 'rule', inp_ipv4_rule, 'action'], value='jump')
+ config.set(base + ['ipv4', 'input', 'filter', 'rule', inp_ipv4_rule, 'jump-target'], value=target_ipv4_chain)
+ inp_ipv4_rule = inp_ipv4_rule + 5
+ if config.exists(base + ['zone', zone, 'from', from_zone, 'firewall', 'ipv6-name']):
+ # ipv6 input ruleset
+ target_ipv6_chain = config.return_value(base + ['zone', zone, 'from', from_zone, 'firewall', 'ipv6-name'])
+ config.set(base + ['ipv6', 'input', 'filter', 'rule'])
+ config.set_tag(base + ['ipv6', 'input', 'filter', 'rule'])
+ config.set(base + ['ipv6', 'input', 'filter', 'rule', inp_ipv6_rule, 'inbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv6', 'input', 'filter', 'rule', inp_ipv6_rule, 'action'], value='jump')
+ config.set(base + ['ipv6', 'input', 'filter', 'rule', inp_ipv6_rule, 'jump-target'], value=target_ipv6_chain)
+ inp_ipv6_rule = inp_ipv6_rule + 5
+
+ # Migrate: set firewall zone <zone> default-action <action>
+ # Options: drop or reject. If not specified, is drop
+ if config.exists(base + ['zone', zone, 'default-action']):
+ local_def_action = config.return_value(base + ['zone', zone, 'default-action'])
+ else:
+ local_def_action = 'drop'
+ config.set(base + ['ipv4', 'input', 'filter', 'rule'])
+ config.set_tag(base + ['ipv4', 'input', 'filter', 'rule'])
+ config.set(base + ['ipv4', 'input', 'filter', 'rule', inp_ipv4_rule, 'action'], value=local_def_action)
+ config.set(base + ['ipv6', 'input', 'filter', 'rule'])
+ config.set_tag(base + ['ipv6', 'input', 'filter', 'rule'])
+ config.set(base + ['ipv6', 'input', 'filter', 'rule', inp_ipv6_rule, 'action'], value=local_def_action)
+ if config.exists(base + ['zone', zone, 'enable-default-log']):
+ config.set(base + ['ipv4', 'input', 'filter', 'rule', inp_ipv4_rule, 'log'], value='enable')
+ config.set(base + ['ipv6', 'input', 'filter', 'rule', inp_ipv6_rule, 'log'], value='enable')
+
+ else:
+ # It's not a local zone
+ group_name = 'IG_' + zone
+ # Add default-action== accept for compatibility reasons:
+ config.set(base + ['ipv4', 'forward', 'filter', 'default-action'], value='accept')
+ config.set(base + ['ipv6', 'forward', 'filter', 'default-action'], value='accept')
+ # intra-filtering migration. By default accept
+ intra_zone_ipv4_action = 'accept'
+ intra_zone_ipv6_action = 'accept'
+
+ if config.exists(base + ['zone', zone, 'intra-zone-filtering', 'action']):
+ intra_zone_ipv4_action = config.return_value(base + ['zone', zone, 'intra-zone-filtering', 'action'])
+ intra_zone_ipv6_action = intra_zone_ipv4_action
+ else:
+ if config.exists(base + ['zone', zone, 'intra-zone-filtering', 'firewall', 'name']):
+ intra_zone_ipv4_target = config.return_value(base + ['zone', zone, 'intra-zone-filtering', 'firewall', 'name'])
+ intra_zone_ipv4_action = 'jump'
+ if config.exists(base + ['zone', zone, 'intra-zone-filtering', 'firewall', 'ipv6-name']):
+ intra_zone_ipv6_target = config.return_value(base + ['zone', zone, 'intra-zone-filtering', 'firewall', 'ipv6-name'])
+ intra_zone_ipv6_action = 'jump'
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule'])
+ config.set_tag(base + ['ipv4', 'forward', 'filter', 'rule'])
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'outbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'inbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'action'], value=intra_zone_ipv4_action)
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule'])
+ config.set_tag(base + ['ipv6', 'forward', 'filter', 'rule'])
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'outbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'inbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'action'], value=intra_zone_ipv6_action)
+ if intra_zone_ipv4_action == 'jump':
+ if config.exists(base + ['zone', zone, 'intra-zone-filtering', 'firewall', 'name']):
+ intra_zone_ipv4_target = config.return_value(base + ['zone', zone, 'intra-zone-filtering', 'firewall', 'name'])
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'jump-target'], value=intra_zone_ipv4_target)
+ if intra_zone_ipv6_action == 'jump':
+ if config.exists(base + ['zone', zone, 'intra-zone-filtering', 'firewall', 'ipv6-name']):
+ intra_zone_ipv6_target = config.return_value(base + ['zone', zone, 'intra-zone-filtering', 'firewall', 'ipv6-name'])
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'jump-target'], value=intra_zone_ipv6_target)
+ fwd_ipv4_rule = fwd_ipv4_rule + 5
+ fwd_ipv6_rule = fwd_ipv6_rule + 5
+
+ if config.exists(base + ['zone', zone, 'interface']):
+ # Create interface group IG_<zone>
+ group_name = 'IG_' + zone
+ config.set(base + ['group', 'interface-group'], value=group_name)
+ config.set_tag(base + ['group', 'interface-group'])
+ for iface in config.return_values(base + ['zone', zone, 'interface']):
+ config.set(base + ['group', 'interface-group', group_name, 'interface'], value=iface, replace=False)
+
+ if config.exists(base + ['zone', zone, 'from']):
+ for from_zone in config.list_nodes(base + ['zone', zone, 'from']):
+ from_group = 'IG_' + from_zone
+ if config.exists(base + ['zone', zone, 'from', from_zone, 'firewall', 'name']):
+ target_ipv4_chain = config.return_value(base + ['zone', zone, 'from', from_zone, 'firewall', 'name'])
+ if config.exists(base + ['zone', from_zone, 'local-zone']):
+ # It's from LOCAL zone -> Output filtering
+ config.set(base + ['ipv4', 'output', 'filter', 'rule'])
+ config.set_tag(base + ['ipv4', 'output', 'filter', 'rule'])
+ config.set(base + ['ipv4', 'output', 'filter', 'rule', out_ipv4_rule, 'outbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv4', 'output', 'filter', 'rule', out_ipv4_rule, 'action'], value='jump')
+ config.set(base + ['ipv4', 'output', 'filter', 'rule', out_ipv4_rule, 'jump-target'], value=target_ipv4_chain)
+ out_ipv4_rule = out_ipv4_rule + 5
+ else:
+ # It's not LOCAL zone -> forward filtering
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule'])
+ config.set_tag(base + ['ipv4', 'forward', 'filter', 'rule'])
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'outbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'inbound-interface', 'interface-group'], value=from_group)
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'action'], value='jump')
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'jump-target'], value=target_ipv4_chain)
+ fwd_ipv4_rule = fwd_ipv4_rule + 5
+ if config.exists(base + ['zone', zone, 'from', from_zone, 'firewall', 'ipv6-name']):
+ target_ipv6_chain = config.return_value(base + ['zone', zone, 'from', from_zone, 'firewall', 'ipv6-name'])
+ if config.exists(base + ['zone', from_zone, 'local-zone']):
+ # It's from LOCAL zone -> Output filtering
+ config.set(base + ['ipv6', 'output', 'filter', 'rule'])
+ config.set_tag(base + ['ipv6', 'output', 'filter', 'rule'])
+ config.set(base + ['ipv6', 'output', 'filter', 'rule', out_ipv6_rule, 'outbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv6', 'output', 'filter', 'rule', out_ipv6_rule, 'action'], value='jump')
+ config.set(base + ['ipv6', 'output', 'filter', 'rule', out_ipv6_rule, 'jump-target'], value=target_ipv6_chain)
+ out_ipv6_rule = out_ipv6_rule + 5
+ else:
+ # It's not LOCAL zone -> forward filtering
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule'])
+ config.set_tag(base + ['ipv6', 'forward', 'filter', 'rule'])
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'outbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'inbound-interface', 'interface-group'], value=from_group)
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'action'], value='jump')
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'jump-target'], value=target_ipv6_chain)
+ fwd_ipv6_rule = fwd_ipv6_rule + 5
+
+ ## Now need to migrate: set firewall zone <zone> default-action <action> # action=drop if not specified.
+ if config.exists(base + ['zone', zone, 'default-action']):
+ def_action = config.return_value(base + ['zone', zone, 'default-action'])
+ else:
+ def_action = 'drop'
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule'])
+ config.set_tag(base + ['ipv4', 'forward', 'filter', 'rule'])
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'outbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'action'], value=def_action)
+ description = 'zone_' + zone + ' default-action'
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'description'], value=description)
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule'])
+ config.set_tag(base + ['ipv6', 'forward', 'filter', 'rule'])
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'outbound-interface', 'interface-group'], value=group_name)
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'action'], value=def_action)
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'description'], value=description)
+
+ if config.exists(base + ['zone', zone, 'enable-default-log']):
+ config.set(base + ['ipv4', 'forward', 'filter', 'rule', fwd_ipv4_rule, 'log'], value='enable')
+ config.set(base + ['ipv6', 'forward', 'filter', 'rule', fwd_ipv6_rule, 'log'], value='enable')
+ fwd_ipv4_rule = fwd_ipv4_rule + 5
+ fwd_ipv6_rule = fwd_ipv6_rule + 5
+
+ # Migrate default-action (force to be drop in output chain) if local zone is defined
+ if local_zone == 'True':
+ # General drop in output change if needed
+ config.set(base + ['ipv4', 'output', 'filter', 'rule'])
+ config.set_tag(base + ['ipv4', 'output', 'filter', 'rule'])
+ config.set(base + ['ipv4', 'output', 'filter', 'rule', out_ipv4_rule, 'action'], value=local_def_action)
+ config.set(base + ['ipv6', 'output', 'filter', 'rule'])
+ config.set_tag(base + ['ipv6', 'output', 'filter', 'rule'])
+ config.set(base + ['ipv6', 'output', 'filter', 'rule', out_ipv6_rule, 'action'], value=local_def_action)
+
+ config.delete(base + ['zone'])
+
+###### END migration zones
+
+try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ exit(1) \ No newline at end of file
diff --git a/src/migration-scripts/firewall/5-to-6 b/src/migration-scripts/firewall/5-to-6
index ccb86830a..e1eaea7a1 100755
--- a/src/migration-scripts/firewall/5-to-6
+++ b/src/migration-scripts/firewall/5-to-6
@@ -23,7 +23,7 @@ from sys import exit
from vyos.configtree import ConfigTree
from vyos.ifconfig import Section
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
@@ -46,12 +46,54 @@ for interface in config.list_nodes(base):
if config.exists(base + [interface, 'adjust-mss']):
section = Section.section(interface)
tmp = config.return_value(base + [interface, 'adjust-mss'])
- config.set(['interfaces', section, interface, 'ip', 'adjust-mss'], value=tmp)
+
+ vlan = interface.split('.')
+ base_interface_path = ['interfaces', section, vlan[0]]
+
+ if len(vlan) == 1:
+ # Normal interface, no VLAN
+ config.set(base_interface_path + ['ip', 'adjust-mss'], value=tmp)
+ elif len(vlan) == 2:
+ # Regular VIF or VIF-S interface - we need to check the config
+ vif = vlan[1]
+ if config.exists(base_interface_path + ['vif', vif]):
+ config.set(base_interface_path + ['vif', vif, 'ip', 'adjust-mss'], value=tmp)
+ elif config.exists(base_interface_path + ['vif-s', vif]):
+ config.set(base_interface_path + ['vif-s', vif, 'ip', 'adjust-mss'], value=tmp)
+ elif len(vlan) == 3:
+ # VIF-S interface with VIF-C subinterface
+ vif_s = vlan[1]
+ vif_c = vlan[2]
+ config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ip', 'adjust-mss'], value=tmp)
+ config.set_tag(base_interface_path + ['vif-s'])
+ config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c'])
if config.exists(base + [interface, 'adjust-mss6']):
section = Section.section(interface)
tmp = config.return_value(base + [interface, 'adjust-mss6'])
- config.set(['interfaces', section, interface, 'ipv6', 'adjust-mss'], value=tmp)
+
+ vlan = interface.split('.')
+ base_interface_path = ['interfaces', section, vlan[0]]
+
+ if len(vlan) == 1:
+ # Normal interface, no VLAN
+ config.set(['interfaces', section, interface, 'ipv6', 'adjust-mss'], value=tmp)
+ elif len(vlan) == 2:
+ # Regular VIF or VIF-S interface - we need to check the config
+ vif = vlan[1]
+ if config.exists(base_interface_path + ['vif', vif]):
+ config.set(base_interface_path + ['vif', vif, 'ipv6', 'adjust-mss'], value=tmp)
+ config.set_tag(base_interface_path + ['vif'])
+ elif config.exists(base_interface_path + ['vif-s', vif]):
+ config.set(base_interface_path + ['vif-s', vif, 'ipv6', 'adjust-mss'], value=tmp)
+ config.set_tag(base_interface_path + ['vif-s'])
+ elif len(vlan) == 3:
+ # VIF-S interface with VIF-C subinterface
+ vif_s = vlan[1]
+ vif_c = vlan[2]
+ config.set(base_interface_path + ['vif-s', vif_s, 'vif-c', vif_c, 'ipv6', 'adjust-mss'], value=tmp)
+ config.set_tag(base_interface_path + ['vif-s'])
+ config.set_tag(base_interface_path + ['vif-s', vif_s, 'vif-c'])
config.delete(['firewall', 'options'])
diff --git a/src/migration-scripts/firewall/6-to-7 b/src/migration-scripts/firewall/6-to-7
index 626d6849f..9ad887acc 100755
--- a/src/migration-scripts/firewall/6-to-7
+++ b/src/migration-scripts/firewall/6-to-7
@@ -28,7 +28,7 @@ from sys import exit
from vyos.configtree import ConfigTree
from vyos.ifconfig import Section
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/firewall/7-to-8 b/src/migration-scripts/firewall/7-to-8
index ce527acf5..d06c3150a 100755
--- a/src/migration-scripts/firewall/7-to-8
+++ b/src/migration-scripts/firewall/7-to-8
@@ -25,7 +25,7 @@ from sys import exit
from vyos.configtree import ConfigTree
from vyos.ifconfig import Section
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/firewall/8-to-9 b/src/migration-scripts/firewall/8-to-9
index f7c1bb90d..d7647354a 100755
--- a/src/migration-scripts/firewall/8-to-9
+++ b/src/migration-scripts/firewall/8-to-9
@@ -28,7 +28,7 @@ from sys import exit
from vyos.configtree import ConfigTree
from vyos.ifconfig import Section
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/firewall/9-to-10 b/src/migration-scripts/firewall/9-to-10
index 6f67cc512..a70460718 100755
--- a/src/migration-scripts/firewall/9-to-10
+++ b/src/migration-scripts/firewall/9-to-10
@@ -28,7 +28,7 @@ from sys import exit
from vyos.configtree import ConfigTree
from vyos.ifconfig import Section
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/flow-accounting/0-to-1 b/src/migration-scripts/flow-accounting/0-to-1
index 72cce77b0..0f790fd9c 100755
--- a/src/migration-scripts/flow-accounting/0-to-1
+++ b/src/migration-scripts/flow-accounting/0-to-1
@@ -21,7 +21,7 @@
from sys import argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/https/2-to-3 b/src/migration-scripts/https/2-to-3
index fa29fdd18..2beba6d2b 100755
--- a/src/migration-scripts/https/2-to-3
+++ b/src/migration-scripts/https/2-to-3
@@ -25,7 +25,7 @@ from vyos.pki import create_private_key
from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
-if (len(sys.argv) < 2):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/https/3-to-4 b/src/migration-scripts/https/3-to-4
index 5ee528b31..b3cfca201 100755
--- a/src/migration-scripts/https/3-to-4
+++ b/src/migration-scripts/https/3-to-4
@@ -20,7 +20,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 2):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/ids/0-to-1 b/src/migration-scripts/ids/0-to-1
index 9f08f7dc7..8b7850a1a 100755
--- a/src/migration-scripts/ids/0-to-1
+++ b/src/migration-scripts/ids/0-to-1
@@ -19,7 +19,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/0-to-1 b/src/migration-scripts/interfaces/0-to-1
index c7f324661..25f6842eb 100755
--- a/src/migration-scripts/interfaces/0-to-1
+++ b/src/migration-scripts/interfaces/0-to-1
@@ -37,7 +37,7 @@ def migrate_bridge(config, tree, intf):
if __name__ == '__main__':
- if (len(sys.argv) < 1):
+ if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/interfaces/1-to-2 b/src/migration-scripts/interfaces/1-to-2
index c75404d85..c95623c2b 100755
--- a/src/migration-scripts/interfaces/1-to-2
+++ b/src/migration-scripts/interfaces/1-to-2
@@ -7,7 +7,7 @@
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/interfaces/10-to-11 b/src/migration-scripts/interfaces/10-to-11
index 6b8e49ed9..cafaa3fa4 100755
--- a/src/migration-scripts/interfaces/10-to-11
+++ b/src/migration-scripts/interfaces/10-to-11
@@ -23,7 +23,7 @@ from sys import exit, argv
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/11-to-12 b/src/migration-scripts/interfaces/11-to-12
index 0dad24642..e9eb7f939 100755
--- a/src/migration-scripts/interfaces/11-to-12
+++ b/src/migration-scripts/interfaces/11-to-12
@@ -22,7 +22,7 @@ from sys import exit, argv
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/12-to-13 b/src/migration-scripts/interfaces/12-to-13
index f866ca9a6..ef1d93903 100755
--- a/src/migration-scripts/interfaces/12-to-13
+++ b/src/migration-scripts/interfaces/12-to-13
@@ -24,7 +24,7 @@ from sys import exit, argv
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/13-to-14 b/src/migration-scripts/interfaces/13-to-14
index 6e6439c36..b20d8b4db 100755
--- a/src/migration-scripts/interfaces/13-to-14
+++ b/src/migration-scripts/interfaces/13-to-14
@@ -21,7 +21,7 @@ from sys import exit, argv
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/14-to-15 b/src/migration-scripts/interfaces/14-to-15
index c38db0bf8..e21251f86 100755
--- a/src/migration-scripts/interfaces/14-to-15
+++ b/src/migration-scripts/interfaces/14-to-15
@@ -20,7 +20,7 @@ from sys import exit, argv
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/15-to-16 b/src/migration-scripts/interfaces/15-to-16
index 804c48be0..ae3441b9f 100755
--- a/src/migration-scripts/interfaces/15-to-16
+++ b/src/migration-scripts/interfaces/15-to-16
@@ -20,7 +20,7 @@ from sys import exit, argv
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/16-to-17 b/src/migration-scripts/interfaces/16-to-17
index d123be06f..75f160686 100755
--- a/src/migration-scripts/interfaces/16-to-17
+++ b/src/migration-scripts/interfaces/16-to-17
@@ -21,7 +21,7 @@ import sys
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(sys.argv) < 1):
+ if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
@@ -35,7 +35,7 @@ if __name__ == '__main__':
if not config.exists(base):
# Nothing to do
sys.exit(0)
-
+
for interface in config.list_nodes(base):
mirror_old_base = base + [interface, 'mirror']
if config.exists(mirror_old_base):
@@ -43,7 +43,7 @@ if __name__ == '__main__':
if config.exists(mirror_old_base):
config.delete(mirror_old_base)
config.set(mirror_old_base + ['ingress'],intf[0])
-
+
try:
with open(file_name, 'w') as f:
f.write(config.to_string())
diff --git a/src/migration-scripts/interfaces/17-to-18 b/src/migration-scripts/interfaces/17-to-18
index b8cb8c119..51486ac37 100755
--- a/src/migration-scripts/interfaces/17-to-18
+++ b/src/migration-scripts/interfaces/17-to-18
@@ -22,7 +22,7 @@ from sys import exit, argv
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/18-to-19 b/src/migration-scripts/interfaces/18-to-19
index a12c4a6cd..c3209f250 100755
--- a/src/migration-scripts/interfaces/18-to-19
+++ b/src/migration-scripts/interfaces/18-to-19
@@ -41,7 +41,7 @@ def replace_nat_interfaces(config, old, new):
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/19-to-20 b/src/migration-scripts/interfaces/19-to-20
index e96663e54..05abae898 100755
--- a/src/migration-scripts/interfaces/19-to-20
+++ b/src/migration-scripts/interfaces/19-to-20
@@ -19,7 +19,7 @@ from sys import exit
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/2-to-3 b/src/migration-scripts/interfaces/2-to-3
index 68d41de39..15c3bc8be 100755
--- a/src/migration-scripts/interfaces/2-to-3
+++ b/src/migration-scripts/interfaces/2-to-3
@@ -7,7 +7,7 @@
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/interfaces/20-to-21 b/src/migration-scripts/interfaces/20-to-21
index cb1c36882..14ad0fe4d 100755
--- a/src/migration-scripts/interfaces/20-to-21
+++ b/src/migration-scripts/interfaces/20-to-21
@@ -23,7 +23,7 @@ from sys import argv
from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/21-to-22 b/src/migration-scripts/interfaces/21-to-22
index 098102102..1838eb1c0 100755
--- a/src/migration-scripts/interfaces/21-to-22
+++ b/src/migration-scripts/interfaces/21-to-22
@@ -17,7 +17,7 @@
from sys import argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/22-to-23 b/src/migration-scripts/interfaces/22-to-23
index 06e07572f..8b21fce51 100755
--- a/src/migration-scripts/interfaces/22-to-23
+++ b/src/migration-scripts/interfaces/22-to-23
@@ -75,7 +75,7 @@ def migrate_ripng(config, path, interface):
config.delete(path[:-1])
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/23-to-24 b/src/migration-scripts/interfaces/23-to-24
index d1ec2ad3e..8fd79ecc6 100755
--- a/src/migration-scripts/interfaces/23-to-24
+++ b/src/migration-scripts/interfaces/23-to-24
@@ -22,7 +22,7 @@ import sys
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(sys.argv) < 1):
+ if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/interfaces/24-to-25 b/src/migration-scripts/interfaces/24-to-25
index f3a1dc464..9aa6ea5e3 100755
--- a/src/migration-scripts/interfaces/24-to-25
+++ b/src/migration-scripts/interfaces/24-to-25
@@ -53,7 +53,7 @@ def read_file_for_pki(config_auth_path):
return output
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/interfaces/25-to-26 b/src/migration-scripts/interfaces/25-to-26
index a8936235e..4967a29fa 100755
--- a/src/migration-scripts/interfaces/25-to-26
+++ b/src/migration-scripts/interfaces/25-to-26
@@ -22,7 +22,7 @@ from sys import argv
from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/26-to-27 b/src/migration-scripts/interfaces/26-to-27
index 949cc55b6..a0d043d11 100755
--- a/src/migration-scripts/interfaces/26-to-27
+++ b/src/migration-scripts/interfaces/26-to-27
@@ -22,7 +22,7 @@ from sys import argv
from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/27-to-28 b/src/migration-scripts/interfaces/27-to-28
index e36c95cc9..ad5bfa653 100755
--- a/src/migration-scripts/interfaces/27-to-28
+++ b/src/migration-scripts/interfaces/27-to-28
@@ -22,7 +22,7 @@ from sys import argv
from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/28-to-29 b/src/migration-scripts/interfaces/28-to-29
index 64c649b02..acb6ee1fb 100755
--- a/src/migration-scripts/interfaces/28-to-29
+++ b/src/migration-scripts/interfaces/28-to-29
@@ -21,7 +21,7 @@ from sys import argv
from vyos.ethtool import Ethtool
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/29-to-30 b/src/migration-scripts/interfaces/29-to-30
new file mode 100755
index 000000000..97e1b329c
--- /dev/null
+++ b/src/migration-scripts/interfaces/29-to-30
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2021-2023 VyOS maintainers and contributors
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 or later as
+# 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/>.
+#
+# Deletes Wireguard peers if they have the same public key as the router has.
+import sys
+from vyos.configtree import ConfigTree
+from vyos.utils.network import is_wireguard_key_pair
+
+if __name__ == '__main__':
+ if len(sys.argv) < 2:
+ print("Must specify file name!")
+ sys.exit(1)
+
+ file_name = sys.argv[1]
+
+ with open(file_name, 'r') as f:
+ config_file = f.read()
+
+ config = ConfigTree(config_file)
+ base = ['interfaces', 'wireguard']
+ if not config.exists(base):
+ # Nothing to do
+ sys.exit(0)
+ for interface in config.list_nodes(base):
+ private_key = config.return_value(base + [interface, 'private-key'])
+ interface_base = base + [interface]
+ if config.exists(interface_base + ['peer']):
+ for peer in config.list_nodes(interface_base + ['peer']):
+ peer_base = interface_base + ['peer', peer]
+ peer_public_key = config.return_value(peer_base + ['public-key'])
+ if config.exists(peer_base + ['public-key']):
+ if not config.exists(peer_base + ['disable']) \
+ and is_wireguard_key_pair(private_key, peer_public_key):
+ config.set(peer_base + ['disable'])
+
+ try:
+ with open(file_name, 'w') as f:
+ f.write(config.to_string())
+ except OSError as e:
+ print("Failed to save the modified config: {}".format(e))
+ sys.exit(1)
diff --git a/src/migration-scripts/interfaces/3-to-4 b/src/migration-scripts/interfaces/3-to-4
index e3bd25a68..c7fd7d01d 100755
--- a/src/migration-scripts/interfaces/3-to-4
+++ b/src/migration-scripts/interfaces/3-to-4
@@ -6,7 +6,7 @@
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/interfaces/4-to-5 b/src/migration-scripts/interfaces/4-to-5
index f645c5aeb..68d81e846 100755
--- a/src/migration-scripts/interfaces/4-to-5
+++ b/src/migration-scripts/interfaces/4-to-5
@@ -57,7 +57,7 @@ def migrate_dialer(config, tree, intf):
if __name__ == '__main__':
- if (len(sys.argv) < 1):
+ if len(sys.argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/5-to-6 b/src/migration-scripts/interfaces/5-to-6
index ae79c1d1b..9d9a49c2d 100755
--- a/src/migration-scripts/interfaces/5-to-6
+++ b/src/migration-scripts/interfaces/5-to-6
@@ -98,7 +98,7 @@ def copy_rtradv(c, old_base, interface):
c.delete(new_base + ['link-mtu'])
if __name__ == '__main__':
- if (len(sys.argv) < 1):
+ if len(sys.argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/6-to-7 b/src/migration-scripts/interfaces/6-to-7
index 220c7e601..49b853d90 100755
--- a/src/migration-scripts/interfaces/6-to-7
+++ b/src/migration-scripts/interfaces/6-to-7
@@ -20,7 +20,7 @@ import sys
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(sys.argv) < 1):
+ if len(sys.argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/7-to-8 b/src/migration-scripts/interfaces/7-to-8
index 9845098a7..9343a48a8 100755
--- a/src/migration-scripts/interfaces/7-to-8
+++ b/src/migration-scripts/interfaces/7-to-8
@@ -37,7 +37,7 @@ def migrate_default_keys():
os.rename(f'{kdir}/public.key', f'{location}/public.key')
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/8-to-9 b/src/migration-scripts/interfaces/8-to-9
index 2d1efd418..960962be7 100755
--- a/src/migration-scripts/interfaces/8-to-9
+++ b/src/migration-scripts/interfaces/8-to-9
@@ -22,7 +22,7 @@ from sys import exit, argv
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/interfaces/9-to-10 b/src/migration-scripts/interfaces/9-to-10
index 4aa2c42b5..e9b8cb784 100755
--- a/src/migration-scripts/interfaces/9-to-10
+++ b/src/migration-scripts/interfaces/9-to-10
@@ -23,7 +23,7 @@ from sys import exit, argv
from vyos.configtree import ConfigTree
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ipoe-server/0-to-1 b/src/migration-scripts/ipoe-server/0-to-1
index d768758ba..ac9d13abc 100755
--- a/src/migration-scripts/ipoe-server/0-to-1
+++ b/src/migration-scripts/ipoe-server/0-to-1
@@ -26,7 +26,7 @@ import sys
from sys import argv, exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ipsec/10-to-11 b/src/migration-scripts/ipsec/10-to-11
index 0707a5e3c..509216267 100755
--- a/src/migration-scripts/ipsec/10-to-11
+++ b/src/migration-scripts/ipsec/10-to-11
@@ -20,7 +20,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ipsec/11-to-12 b/src/migration-scripts/ipsec/11-to-12
index 8bbde5efa..e34882c23 100755
--- a/src/migration-scripts/ipsec/11-to-12
+++ b/src/migration-scripts/ipsec/11-to-12
@@ -23,7 +23,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ipsec/4-to-5 b/src/migration-scripts/ipsec/4-to-5
index 4e959a7bf..772d05787 100755
--- a/src/migration-scripts/ipsec/4-to-5
+++ b/src/migration-scripts/ipsec/4-to-5
@@ -20,7 +20,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/ipsec/5-to-6 b/src/migration-scripts/ipsec/5-to-6
index 3a8b3926d..7d7c777c6 100755
--- a/src/migration-scripts/ipsec/5-to-6
+++ b/src/migration-scripts/ipsec/5-to-6
@@ -23,7 +23,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ipsec/6-to-7 b/src/migration-scripts/ipsec/6-to-7
index 649a18cb3..71fbbe8a1 100755
--- a/src/migration-scripts/ipsec/6-to-7
+++ b/src/migration-scripts/ipsec/6-to-7
@@ -29,7 +29,7 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ipsec/7-to-8 b/src/migration-scripts/ipsec/7-to-8
index 5d48b2875..e002db0b1 100755
--- a/src/migration-scripts/ipsec/7-to-8
+++ b/src/migration-scripts/ipsec/7-to-8
@@ -31,7 +31,7 @@ from vyos.pki import load_private_key
from vyos.pki import encode_public_key
from vyos.pki import encode_private_key
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ipsec/8-to-9 b/src/migration-scripts/ipsec/8-to-9
index eb44b6216..c08411f83 100755
--- a/src/migration-scripts/ipsec/8-to-9
+++ b/src/migration-scripts/ipsec/8-to-9
@@ -19,7 +19,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ipsec/9-to-10 b/src/migration-scripts/ipsec/9-to-10
index de366ef3b..a4a71d38e 100755
--- a/src/migration-scripts/ipsec/9-to-10
+++ b/src/migration-scripts/ipsec/9-to-10
@@ -24,7 +24,7 @@ from vyos.template import is_ipv4
from vyos.template import is_ipv6
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/isis/0-to-1 b/src/migration-scripts/isis/0-to-1
index b75a7f72c..0149c0c1f 100755
--- a/src/migration-scripts/isis/0-to-1
+++ b/src/migration-scripts/isis/0-to-1
@@ -21,7 +21,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/isis/1-to-2 b/src/migration-scripts/isis/1-to-2
index f914ea995..9c110bf2a 100755
--- a/src/migration-scripts/isis/1-to-2
+++ b/src/migration-scripts/isis/1-to-2
@@ -21,7 +21,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/isis/2-to-3 b/src/migration-scripts/isis/2-to-3
index 4490feb0a..78e3c1715 100755
--- a/src/migration-scripts/isis/2-to-3
+++ b/src/migration-scripts/isis/2-to-3
@@ -22,7 +22,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/l2tp/0-to-1 b/src/migration-scripts/l2tp/0-to-1
index 686ebc655..15d229822 100755
--- a/src/migration-scripts/l2tp/0-to-1
+++ b/src/migration-scripts/l2tp/0-to-1
@@ -8,7 +8,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/l2tp/1-to-2 b/src/migration-scripts/l2tp/1-to-2
index c46eba8f8..2ffb91c53 100755
--- a/src/migration-scripts/l2tp/1-to-2
+++ b/src/migration-scripts/l2tp/1-to-2
@@ -6,7 +6,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/l2tp/2-to-3 b/src/migration-scripts/l2tp/2-to-3
index 3472ee3ed..b46b0f22e 100755
--- a/src/migration-scripts/l2tp/2-to-3
+++ b/src/migration-scripts/l2tp/2-to-3
@@ -23,7 +23,7 @@ import sys
from sys import argv, exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/l2tp/3-to-4 b/src/migration-scripts/l2tp/3-to-4
index ee6079864..8c2b909b7 100755
--- a/src/migration-scripts/l2tp/3-to-4
+++ b/src/migration-scripts/l2tp/3-to-4
@@ -29,7 +29,7 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/lldp/0-to-1 b/src/migration-scripts/lldp/0-to-1
index 5f66570e7..a936cbdfc 100755
--- a/src/migration-scripts/lldp/0-to-1
+++ b/src/migration-scripts/lldp/0-to-1
@@ -7,7 +7,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/monitoring/0-to-1 b/src/migration-scripts/monitoring/0-to-1
index 803cdb49c..384d22f8c 100755
--- a/src/migration-scripts/monitoring/0-to-1
+++ b/src/migration-scripts/monitoring/0-to-1
@@ -21,7 +21,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/nat/4-to-5 b/src/migration-scripts/nat/4-to-5
index b791996e2..ce215d455 100755
--- a/src/migration-scripts/nat/4-to-5
+++ b/src/migration-scripts/nat/4-to-5
@@ -20,7 +20,7 @@
from sys import argv,exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/nat66/0-to-1 b/src/migration-scripts/nat66/0-to-1
index 83b421926..444b2315f 100755
--- a/src/migration-scripts/nat66/0-to-1
+++ b/src/migration-scripts/nat66/0-to-1
@@ -17,7 +17,7 @@
from sys import argv,exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ntp/0-to-1 b/src/migration-scripts/ntp/0-to-1
index 294964580..cbce45b9b 100755
--- a/src/migration-scripts/ntp/0-to-1
+++ b/src/migration-scripts/ntp/0-to-1
@@ -6,7 +6,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/ntp/1-to-2 b/src/migration-scripts/ntp/1-to-2
index d1e510e4c..fd1f15d91 100755
--- a/src/migration-scripts/ntp/1-to-2
+++ b/src/migration-scripts/ntp/1-to-2
@@ -20,7 +20,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/ntp/2-to-3 b/src/migration-scripts/ntp/2-to-3
index 7d4e0bd83..a4351845e 100755
--- a/src/migration-scripts/ntp/2-to-3
+++ b/src/migration-scripts/ntp/2-to-3
@@ -24,7 +24,7 @@ from vyos.configtree import ConfigTree
from vyos.template import is_ipv4
from vyos.template import is_ipv6
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/openconnect/0-to-1 b/src/migration-scripts/openconnect/0-to-1
index b26023a5b..8be15fad1 100755
--- a/src/migration-scripts/openconnect/0-to-1
+++ b/src/migration-scripts/openconnect/0-to-1
@@ -28,7 +28,7 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/openconnect/1-to-2 b/src/migration-scripts/openconnect/1-to-2
index 51cd6bc37..7978aa56e 100755
--- a/src/migration-scripts/openconnect/1-to-2
+++ b/src/migration-scripts/openconnect/1-to-2
@@ -20,7 +20,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/ospf/0-to-1 b/src/migration-scripts/ospf/0-to-1
index 678569d9e..8f02acada 100755
--- a/src/migration-scripts/ospf/0-to-1
+++ b/src/migration-scripts/ospf/0-to-1
@@ -37,7 +37,7 @@ def ospf_passive_migration(config, ospf_base):
config.set(ospf_base + ['interface', interface, 'passive', 'disable'])
config.delete(ospf_base + ['passive-interface-exclude'])
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ospf/1-to-2 b/src/migration-scripts/ospf/1-to-2
index a6beaf04e..ba9499c60 100755
--- a/src/migration-scripts/ospf/1-to-2
+++ b/src/migration-scripts/ospf/1-to-2
@@ -22,7 +22,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/policy/0-to-1 b/src/migration-scripts/policy/0-to-1
index 7134920ad..8508b734a 100755
--- a/src/migration-scripts/policy/0-to-1
+++ b/src/migration-scripts/policy/0-to-1
@@ -23,7 +23,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/policy/1-to-2 b/src/migration-scripts/policy/1-to-2
index eebbf9d41..c70490ce9 100755
--- a/src/migration-scripts/policy/1-to-2
+++ b/src/migration-scripts/policy/1-to-2
@@ -23,7 +23,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/policy/2-to-3 b/src/migration-scripts/policy/2-to-3
index 84cb1ff4a..8a62c8e6f 100755
--- a/src/migration-scripts/policy/2-to-3
+++ b/src/migration-scripts/policy/2-to-3
@@ -23,7 +23,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/policy/3-to-4 b/src/migration-scripts/policy/3-to-4
index 49e0b4c38..1ebb248b0 100755
--- a/src/migration-scripts/policy/3-to-4
+++ b/src/migration-scripts/policy/3-to-4
@@ -98,7 +98,7 @@ def extcommunity_migrate(config: ConfigTree, rule: list[str]) -> None:
config.set(rule + ['soo'], value=community, replace=False)
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/policy/4-to-5 b/src/migration-scripts/policy/4-to-5
index 33c9e6ade..f6f889c35 100755
--- a/src/migration-scripts/policy/4-to-5
+++ b/src/migration-scripts/policy/4-to-5
@@ -24,7 +24,7 @@ from sys import exit
from vyos.configtree import ConfigTree
from vyos.ifconfig import Section
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/pppoe-server/0-to-1 b/src/migration-scripts/pppoe-server/0-to-1
index 063c7eb56..4d36f8545 100755
--- a/src/migration-scripts/pppoe-server/0-to-1
+++ b/src/migration-scripts/pppoe-server/0-to-1
@@ -20,7 +20,7 @@
from sys import argv, exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/pppoe-server/1-to-2 b/src/migration-scripts/pppoe-server/1-to-2
index 902efb86b..c73899ca1 100755
--- a/src/migration-scripts/pppoe-server/1-to-2
+++ b/src/migration-scripts/pppoe-server/1-to-2
@@ -21,7 +21,7 @@ import os
from sys import argv, exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/pppoe-server/2-to-3 b/src/migration-scripts/pppoe-server/2-to-3
index 7cae3b5bc..a7be060df 100755
--- a/src/migration-scripts/pppoe-server/2-to-3
+++ b/src/migration-scripts/pppoe-server/2-to-3
@@ -19,7 +19,7 @@
from sys import argv, exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/pppoe-server/3-to-4 b/src/migration-scripts/pppoe-server/3-to-4
index 5f9730a41..c07bbb1df 100755
--- a/src/migration-scripts/pppoe-server/3-to-4
+++ b/src/migration-scripts/pppoe-server/3-to-4
@@ -21,7 +21,7 @@ import os
from sys import argv, exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/pppoe-server/4-to-5 b/src/migration-scripts/pppoe-server/4-to-5
index 05e9c17d6..5850db673 100755
--- a/src/migration-scripts/pppoe-server/4-to-5
+++ b/src/migration-scripts/pppoe-server/4-to-5
@@ -20,7 +20,7 @@ from vyos.configtree import ConfigTree
from sys import argv
from sys import exit
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/pppoe-server/5-to-6 b/src/migration-scripts/pppoe-server/5-to-6
index e4888f4db..e079ae684 100755
--- a/src/migration-scripts/pppoe-server/5-to-6
+++ b/src/migration-scripts/pppoe-server/5-to-6
@@ -20,7 +20,7 @@ from vyos.configtree import ConfigTree
from sys import argv
from sys import exit
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/pptp/0-to-1 b/src/migration-scripts/pptp/0-to-1
index d0c7a83b5..1b7697c11 100755
--- a/src/migration-scripts/pptp/0-to-1
+++ b/src/migration-scripts/pptp/0-to-1
@@ -8,7 +8,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/pptp/1-to-2 b/src/migration-scripts/pptp/1-to-2
index a13cc3a4f..99624dceb 100755
--- a/src/migration-scripts/pptp/1-to-2
+++ b/src/migration-scripts/pptp/1-to-2
@@ -21,7 +21,7 @@ from sys import argv, exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/qos/1-to-2 b/src/migration-scripts/qos/1-to-2
index a689bacc5..cca32d06e 100755
--- a/src/migration-scripts/qos/1-to-2
+++ b/src/migration-scripts/qos/1-to-2
@@ -28,7 +28,7 @@ def bandwidth_percent_to_val(interface, percent) -> int:
speed = int(speed) *1000000 # convert to MBit/s
return speed * int(percent) // 100 # integer division
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/quagga/10-to-11 b/src/migration-scripts/quagga/10-to-11
index 04fc16f79..0ed4f5df6 100755
--- a/src/migration-scripts/quagga/10-to-11
+++ b/src/migration-scripts/quagga/10-to-11
@@ -22,7 +22,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/quagga/2-to-3 b/src/migration-scripts/quagga/2-to-3
index 4c1cd86a3..96b56da70 100755
--- a/src/migration-scripts/quagga/2-to-3
+++ b/src/migration-scripts/quagga/2-to-3
@@ -21,7 +21,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/quagga/3-to-4 b/src/migration-scripts/quagga/3-to-4
index be3528391..1e8c8e2f2 100755
--- a/src/migration-scripts/quagga/3-to-4
+++ b/src/migration-scripts/quagga/3-to-4
@@ -28,7 +28,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/quagga/4-to-5 b/src/migration-scripts/quagga/4-to-5
index f8c87ce8c..fcb496a9c 100755
--- a/src/migration-scripts/quagga/4-to-5
+++ b/src/migration-scripts/quagga/4-to-5
@@ -21,7 +21,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/quagga/5-to-6 b/src/migration-scripts/quagga/5-to-6
index a71851942..f075fc2e7 100755
--- a/src/migration-scripts/quagga/5-to-6
+++ b/src/migration-scripts/quagga/5-to-6
@@ -22,7 +22,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 2):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/quagga/6-to-7 b/src/migration-scripts/quagga/6-to-7
index 25cf5eebd..ed295a95c 100755
--- a/src/migration-scripts/quagga/6-to-7
+++ b/src/migration-scripts/quagga/6-to-7
@@ -23,7 +23,7 @@ from vyos.configtree import ConfigTree
from vyos.template import is_ipv4
from vyos.template import is_ipv6
-if (len(argv) < 2):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/quagga/7-to-8 b/src/migration-scripts/quagga/7-to-8
index 15c44924f..8f11bf390 100755
--- a/src/migration-scripts/quagga/7-to-8
+++ b/src/migration-scripts/quagga/7-to-8
@@ -22,7 +22,7 @@ from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 2):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/quagga/8-to-9 b/src/migration-scripts/quagga/8-to-9
index 38507bd3d..0f683d5a1 100755
--- a/src/migration-scripts/quagga/8-to-9
+++ b/src/migration-scripts/quagga/8-to-9
@@ -84,7 +84,7 @@ def migrate_route(config, base, path, route_route6):
config.rename(vrf_path, 'vrf')
-if (len(argv) < 2):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/quagga/9-to-10 b/src/migration-scripts/quagga/9-to-10
index 249738822..3731762f7 100755
--- a/src/migration-scripts/quagga/9-to-10
+++ b/src/migration-scripts/quagga/9-to-10
@@ -21,7 +21,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 2):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/rip/0-to-1 b/src/migration-scripts/rip/0-to-1
index 60d510001..08a866374 100755
--- a/src/migration-scripts/rip/0-to-1
+++ b/src/migration-scripts/rip/0-to-1
@@ -22,7 +22,7 @@ from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/rpki/0-to-1 b/src/migration-scripts/rpki/0-to-1
index 5b4893205..a7b5d07d5 100755
--- a/src/migration-scripts/rpki/0-to-1
+++ b/src/migration-scripts/rpki/0-to-1
@@ -18,7 +18,7 @@ from sys import exit
from sys import argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/salt/0-to-1 b/src/migration-scripts/salt/0-to-1
index 79053c056..481d9de8f 100755
--- a/src/migration-scripts/salt/0-to-1
+++ b/src/migration-scripts/salt/0-to-1
@@ -22,7 +22,7 @@ from sys import argv,exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/snmp/0-to-1 b/src/migration-scripts/snmp/0-to-1
index 096ba779d..b1e61b958 100755
--- a/src/migration-scripts/snmp/0-to-1
+++ b/src/migration-scripts/snmp/0-to-1
@@ -17,7 +17,7 @@
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/snmp/1-to-2 b/src/migration-scripts/snmp/1-to-2
index 466a624e6..e02cd1aa1 100755
--- a/src/migration-scripts/snmp/1-to-2
+++ b/src/migration-scripts/snmp/1-to-2
@@ -43,7 +43,7 @@ def migrate_keys(config, path):
config.set(config_path_priv, value=tmp)
if __name__ == '__main__':
- if (len(argv) < 1):
+ if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/snmp/2-to-3 b/src/migration-scripts/snmp/2-to-3
index 5f8d9c88d..30911aa27 100755
--- a/src/migration-scripts/snmp/2-to-3
+++ b/src/migration-scripts/snmp/2-to-3
@@ -28,7 +28,7 @@ from sys import exit
from vyos.configtree import ConfigTree
from vyos.ifconfig import Section
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/ssh/0-to-1 b/src/migration-scripts/ssh/0-to-1
index 91b832276..2595599ac 100755
--- a/src/migration-scripts/ssh/0-to-1
+++ b/src/migration-scripts/ssh/0-to-1
@@ -6,7 +6,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/ssh/1-to-2 b/src/migration-scripts/ssh/1-to-2
index 31c40df16..79d65d7d4 100755
--- a/src/migration-scripts/ssh/1-to-2
+++ b/src/migration-scripts/ssh/1-to-2
@@ -21,7 +21,7 @@
from sys import argv,exit
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/sstp/0-to-1 b/src/migration-scripts/sstp/0-to-1
index dc65bdeab..e2fe1ea8f 100755
--- a/src/migration-scripts/sstp/0-to-1
+++ b/src/migration-scripts/sstp/0-to-1
@@ -28,7 +28,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/sstp/1-to-2 b/src/migration-scripts/sstp/1-to-2
index 94cb04831..f7ecbb6d4 100755
--- a/src/migration-scripts/sstp/1-to-2
+++ b/src/migration-scripts/sstp/1-to-2
@@ -25,7 +25,7 @@ from shutil import copy2
from stat import S_IRUSR, S_IWUSR, S_IRGRP, S_IROTH
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/sstp/2-to-3 b/src/migration-scripts/sstp/2-to-3
index 963b2ba4b..245db7ad6 100755
--- a/src/migration-scripts/sstp/2-to-3
+++ b/src/migration-scripts/sstp/2-to-3
@@ -21,7 +21,7 @@ from vyos.configtree import ConfigTree
from sys import argv
from sys import exit
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/sstp/3-to-4 b/src/migration-scripts/sstp/3-to-4
index ea814fdc5..00ca7a52d 100755
--- a/src/migration-scripts/sstp/3-to-4
+++ b/src/migration-scripts/sstp/3-to-4
@@ -28,7 +28,7 @@ from vyos.pki import encode_certificate
from vyos.pki import encode_private_key
from vyos.utils.process import run
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/system/10-to-11 b/src/migration-scripts/system/10-to-11
index 3c49f0d95..5d662af40 100755
--- a/src/migration-scripts/system/10-to-11
+++ b/src/migration-scripts/system/10-to-11
@@ -6,7 +6,7 @@
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/system/11-to-12 b/src/migration-scripts/system/11-to-12
index 9cddaa1a7..880ab56dc 100755
--- a/src/migration-scripts/system/11-to-12
+++ b/src/migration-scripts/system/11-to-12
@@ -8,7 +8,7 @@
import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/system/12-to-13 b/src/migration-scripts/system/12-to-13
index 36311a19d..e6c4e3802 100755
--- a/src/migration-scripts/system/12-to-13
+++ b/src/migration-scripts/system/12-to-13
@@ -8,7 +8,7 @@ import re
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/system/13-to-14 b/src/migration-scripts/system/13-to-14
index 1751f1865..1fa781869 100755
--- a/src/migration-scripts/system/13-to-14
+++ b/src/migration-scripts/system/13-to-14
@@ -15,7 +15,7 @@ from vyos.configtree import ConfigTree
from vyos.utils.process import cmd
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/system/14-to-15 b/src/migration-scripts/system/14-to-15
index c055dad1f..feaac37de 100755
--- a/src/migration-scripts/system/14-to-15
+++ b/src/migration-scripts/system/14-to-15
@@ -11,7 +11,7 @@ ipv6_blacklist_file = '/etc/modprobe.d/vyatta_blacklist_ipv6.conf'
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/system/15-to-16 b/src/migration-scripts/system/15-to-16
index 2491e3d0d..aa1c34032 100755
--- a/src/migration-scripts/system/15-to-16
+++ b/src/migration-scripts/system/15-to-16
@@ -7,7 +7,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/system/16-to-17 b/src/migration-scripts/system/16-to-17
index e70893d55..37e02611d 100755
--- a/src/migration-scripts/system/16-to-17
+++ b/src/migration-scripts/system/16-to-17
@@ -25,7 +25,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/system/17-to-18 b/src/migration-scripts/system/17-to-18
index 8f762c0e2..f6adebb06 100755
--- a/src/migration-scripts/system/17-to-18
+++ b/src/migration-scripts/system/17-to-18
@@ -22,7 +22,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/system/18-to-19 b/src/migration-scripts/system/18-to-19
index 38479d222..fad1d17a4 100755
--- a/src/migration-scripts/system/18-to-19
+++ b/src/migration-scripts/system/18-to-19
@@ -24,7 +24,7 @@ from sys import argv, exit
from vyos.ifconfig import Interface
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/system/19-to-20 b/src/migration-scripts/system/19-to-20
index eb20fd8db..c04e6a5a6 100755
--- a/src/migration-scripts/system/19-to-20
+++ b/src/migration-scripts/system/19-to-20
@@ -21,7 +21,7 @@ import os
from sys import exit, argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/system/20-to-21 b/src/migration-scripts/system/20-to-21
index 1728995de..4bcf4edab 100755
--- a/src/migration-scripts/system/20-to-21
+++ b/src/migration-scripts/system/20-to-21
@@ -21,7 +21,7 @@ import os
from sys import argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/system/21-to-22 b/src/migration-scripts/system/21-to-22
index ad41be646..810b634ab 100755
--- a/src/migration-scripts/system/21-to-22
+++ b/src/migration-scripts/system/21-to-22
@@ -19,7 +19,7 @@ import os
from sys import exit, argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/system/22-to-23 b/src/migration-scripts/system/22-to-23
index 7f832e48a..8ed198383 100755
--- a/src/migration-scripts/system/22-to-23
+++ b/src/migration-scripts/system/22-to-23
@@ -19,7 +19,7 @@ import os
from sys import exit, argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/system/23-to-24 b/src/migration-scripts/system/23-to-24
index 97fe82462..fd68dbf22 100755
--- a/src/migration-scripts/system/23-to-24
+++ b/src/migration-scripts/system/23-to-24
@@ -22,7 +22,7 @@ from sys import exit, argv
from vyos.configtree import ConfigTree
from vyos.template import is_ipv4
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/system/24-to-25 b/src/migration-scripts/system/24-to-25
index c2f70689d..1c81a76e7 100755
--- a/src/migration-scripts/system/24-to-25
+++ b/src/migration-scripts/system/24-to-25
@@ -19,7 +19,7 @@
from sys import exit, argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/system/25-to-26 b/src/migration-scripts/system/25-to-26
index 615274430..7bdf3be98 100755
--- a/src/migration-scripts/system/25-to-26
+++ b/src/migration-scripts/system/25-to-26
@@ -21,7 +21,7 @@
from sys import exit, argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/system/6-to-7 b/src/migration-scripts/system/6-to-7
index bf07abf3a..d24521134 100755
--- a/src/migration-scripts/system/6-to-7
+++ b/src/migration-scripts/system/6-to-7
@@ -6,7 +6,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/system/7-to-8 b/src/migration-scripts/system/7-to-8
index 4cbb21f17..5d084d2bf 100755
--- a/src/migration-scripts/system/7-to-8
+++ b/src/migration-scripts/system/7-to-8
@@ -6,7 +6,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/system/8-to-9 b/src/migration-scripts/system/8-to-9
index db3fefdea..e3bb2bca8 100755
--- a/src/migration-scripts/system/8-to-9
+++ b/src/migration-scripts/system/8-to-9
@@ -6,7 +6,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/vrf/0-to-1 b/src/migration-scripts/vrf/0-to-1
index 5df751113..8187138d9 100755
--- a/src/migration-scripts/vrf/0-to-1
+++ b/src/migration-scripts/vrf/0-to-1
@@ -20,7 +20,7 @@ from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 2):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/vrf/1-to-2 b/src/migration-scripts/vrf/1-to-2
index 9bc704e02..52d4c2c7b 100755
--- a/src/migration-scripts/vrf/1-to-2
+++ b/src/migration-scripts/vrf/1-to-2
@@ -20,7 +20,7 @@ from sys import argv
from sys import exit
from vyos.configtree import ConfigTree
-if (len(argv) < 2):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/vrf/2-to-3 b/src/migration-scripts/vrf/2-to-3
index 8e0f97141..d45b185ee 100755
--- a/src/migration-scripts/vrf/2-to-3
+++ b/src/migration-scripts/vrf/2-to-3
@@ -69,7 +69,7 @@ def _search_tables(config_commands, table_num):
return table_items
-if (len(argv) < 2):
+if len(argv) < 2:
print("Must specify file name!")
exit(1)
diff --git a/src/migration-scripts/vrrp/1-to-2 b/src/migration-scripts/vrrp/1-to-2
index b2e61dd38..dba5af81c 100755
--- a/src/migration-scripts/vrrp/1-to-2
+++ b/src/migration-scripts/vrrp/1-to-2
@@ -21,7 +21,7 @@ import sys
from vyos.configtree import ConfigTree
-if (len(sys.argv) < 1):
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/migration-scripts/vrrp/2-to-3 b/src/migration-scripts/vrrp/2-to-3
index 1151ae18c..ed583b489 100755
--- a/src/migration-scripts/vrrp/2-to-3
+++ b/src/migration-scripts/vrrp/2-to-3
@@ -19,7 +19,7 @@
from sys import argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print('Must specify file name!')
exit(1)
diff --git a/src/migration-scripts/vrrp/3-to-4 b/src/migration-scripts/vrrp/3-to-4
index b0a6975c2..e5d93578c 100755
--- a/src/migration-scripts/vrrp/3-to-4
+++ b/src/migration-scripts/vrrp/3-to-4
@@ -17,7 +17,7 @@
from sys import argv
from vyos.configtree import ConfigTree
-if (len(argv) < 1):
+if len(argv) < 2:
print('Must specify file name!')
exit(1)
diff --git a/src/migration-scripts/webproxy/1-to-2 b/src/migration-scripts/webproxy/1-to-2
index 070ff356d..03f357878 100755
--- a/src/migration-scripts/webproxy/1-to-2
+++ b/src/migration-scripts/webproxy/1-to-2
@@ -7,7 +7,7 @@ import sys
from vyos.configtree import ConfigTree
-if len(sys.argv) < 1:
+if len(sys.argv) < 2:
print("Must specify file name!")
sys.exit(1)
diff --git a/src/op_mode/bridge.py b/src/op_mode/bridge.py
index 1834b9cc9..185db4f20 100755
--- a/src/op_mode/bridge.py
+++ b/src/op_mode/bridge.py
@@ -29,7 +29,6 @@ from vyos.utils.dict import dict_search
import vyos.opmode
-
def _get_json_data():
"""
Get bridge data format JSON
@@ -46,11 +45,14 @@ def _get_raw_data_summary():
return data_dict
-def _get_raw_data_vlan():
+def _get_raw_data_vlan(tunnel:bool=False):
"""
:returns dict
"""
- json_data = cmd('bridge --json --compressvlans vlan show')
+ show = 'show'
+ if tunnel:
+ show = 'tunnel'
+ json_data = cmd(f'bridge --json --compressvlans vlan {show}')
data_dict = json.loads(json_data)
return data_dict
@@ -134,10 +136,34 @@ def _get_formatted_output_vlan(data):
flags = ', '.join(flags_raw if isinstance(flags_raw,list) else "").lower()
data_entries.append([interface, vlan, flags])
- headers = ["Interface", "Vlan", "Flags"]
+ headers = ["Interface", "VLAN", "Flags"]
output = tabulate(data_entries, headers)
return output
+def _get_formatted_output_vlan_tunnel(data):
+ data_entries = []
+ for entry in data:
+ interface = entry.get('ifname')
+ first = True
+ for tunnel_entry in entry.get('tunnels'):
+ vlan = tunnel_entry.get('vlan')
+ vni = tunnel_entry.get('tunid')
+ if first:
+ data_entries.append([interface, vlan, vni])
+ first = False
+ else:
+ # Group by VXLAN interface only - no need to repeat
+ # VXLAN interface name for every VLAN <-> VNI mapping
+ #
+ # Interface VLAN VNI
+ # ----------- ------ -----
+ # vxlan0 100 100
+ # 200 200
+ data_entries.append(['', vlan, vni])
+
+ headers = ["Interface", "VLAN", "VNI"]
+ output = tabulate(data_entries, headers)
+ return output
def _get_formatted_output_fdb(data):
data_entries = []
@@ -192,12 +218,15 @@ def show(raw: bool):
return _get_formatted_output_summary(bridge_data)
-def show_vlan(raw: bool):
- bridge_vlan = _get_raw_data_vlan()
+def show_vlan(raw: bool, tunnel: typing.Optional[bool]):
+ bridge_vlan = _get_raw_data_vlan(tunnel)
if raw:
return bridge_vlan
else:
- return _get_formatted_output_vlan(bridge_vlan)
+ if tunnel:
+ return _get_formatted_output_vlan_tunnel(bridge_vlan)
+ else:
+ return _get_formatted_output_vlan(bridge_vlan)
def show_fdb(raw: bool, interface: str):
diff --git a/src/op_mode/dhcp.py b/src/op_mode/dhcp.py
index 3e51e990b..f558c18b7 100755
--- a/src/op_mode/dhcp.py
+++ b/src/op_mode/dhcp.py
@@ -14,10 +14,12 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import os
import sys
import typing
from datetime import datetime
+from glob import glob
from ipaddress import ip_address
from isc_dhcp_leases import IscDhcpLeases
from tabulate import tabulate
@@ -27,10 +29,13 @@ import vyos.opmode
from vyos.base import Warning
from vyos.configquery import ConfigTreeQuery
-from vyos.utils.process import cmd
from vyos.utils.dict import dict_search
+from vyos.utils.file import read_file
+from vyos.utils.process import cmd
from vyos.utils.process import is_systemd_service_running
+time_string = "%a %b %d %H:%M:%S %Z %Y"
+
config = ConfigTreeQuery()
lease_valid_states = ['all', 'active', 'free', 'expired', 'released', 'abandoned', 'reset', 'backup']
sort_valid_inet = ['end', 'mac', 'hostname', 'ip', 'pool', 'remaining', 'start', 'state']
@@ -287,6 +292,95 @@ def show_server_leases(raw: bool, family: ArgFamily, pool: typing.Optional[str],
return _get_formatted_server_leases(lease_data, family=family)
+def _get_raw_client_leases(family='inet', interface=None):
+ from time import mktime
+ from datetime import datetime
+ from vyos.defaults import directories
+ from vyos.utils.network import get_interface_vrf
+
+ lease_dir = directories['isc_dhclient_dir']
+ lease_files = []
+ lease_data = []
+
+ if interface:
+ tmp = f'{lease_dir}/dhclient_{interface}.lease'
+ if os.path.exists(tmp):
+ lease_files.append(tmp)
+ else:
+ # All DHCP leases
+ lease_files = glob(f'{lease_dir}/dhclient_*.lease')
+
+ for lease in lease_files:
+ tmp = {}
+ with open(lease, 'r') as f:
+ for line in f.readlines():
+ line = line.rstrip()
+ if 'last_update' not in tmp:
+ # ISC dhcp client contains least_update timestamp in human readable
+ # format this makes less sense for an API and also the expiry
+ # timestamp is provided in UNIX time. Convert string (e.g. Sun Jul
+ # 30 18:13:44 CEST 2023) to UNIX time (1690733624)
+ tmp.update({'last_update' : int(mktime(datetime.strptime(line, time_string).timetuple()))})
+ continue
+
+ k, v = line.split('=')
+ tmp.update({k : v.replace("'", "")})
+
+ if 'interface' in tmp:
+ vrf = get_interface_vrf(tmp['interface'])
+ if vrf: tmp.update({'vrf' : vrf})
+
+ lease_data.append(tmp)
+
+ return lease_data
+
+def _get_formatted_client_leases(lease_data, family):
+ from time import localtime
+ from time import strftime
+
+ from vyos.validate import is_intf_addr_assigned
+
+ data_entries = []
+ for lease in lease_data:
+ data_entries.append(["Interface", lease['interface']])
+ if 'new_ip_address' in lease:
+ tmp = '[Active]' if is_intf_addr_assigned(lease['interface'], lease['new_ip_address']) else '[Inactive]'
+ data_entries.append(["IP address", lease['new_ip_address'], tmp])
+ if 'new_subnet_mask' in lease:
+ data_entries.append(["Subnet Mask", lease['new_subnet_mask']])
+ if 'new_domain_name' in lease:
+ data_entries.append(["Domain Name", lease['new_domain_name']])
+ if 'new_routers' in lease:
+ data_entries.append(["Router", lease['new_routers']])
+ if 'new_domain_name_servers' in lease:
+ data_entries.append(["Name Server", lease['new_domain_name_servers']])
+ if 'new_dhcp_server_identifier' in lease:
+ data_entries.append(["DHCP Server", lease['new_dhcp_server_identifier']])
+ if 'new_dhcp_lease_time' in lease:
+ data_entries.append(["DHCP Server", lease['new_dhcp_lease_time']])
+ if 'vrf' in lease:
+ data_entries.append(["VRF", lease['vrf']])
+ if 'last_update' in lease:
+ tmp = strftime(time_string, localtime(int(lease['last_update'])))
+ data_entries.append(["Last Update", tmp])
+ if 'new_expiry' in lease:
+ tmp = strftime(time_string, localtime(int(lease['new_expiry'])))
+ data_entries.append(["Expiry", tmp])
+
+ # Add empty marker
+ data_entries.append([''])
+
+ output = tabulate(data_entries, tablefmt='plain')
+
+ return output
+
+def show_client_leases(raw: bool, family: ArgFamily, interface: typing.Optional[str]):
+ lease_data = _get_raw_client_leases(family=family, interface=interface)
+ if raw:
+ return lease_data
+ else:
+ return _get_formatted_client_leases(lease_data, family=family)
+
if __name__ == '__main__':
try:
res = vyos.opmode.run(sys.modules[__name__])
diff --git a/src/op_mode/firewall.py b/src/op_mode/firewall.py
index 8260bbb77..852a7248a 100755
--- a/src/op_mode/firewall.py
+++ b/src/op_mode/firewall.py
@@ -24,62 +24,27 @@ from vyos.config import Config
from vyos.utils.process import cmd
from vyos.utils.dict import dict_search_args
-def get_firewall_interfaces(firewall, name=None, ipv6=False):
- directions = ['in', 'out', 'local']
-
- if 'interface' in firewall:
- for ifname, if_conf in firewall['interface'].items():
- for direction in directions:
- if direction not in if_conf:
- continue
-
- fw_conf = if_conf[direction]
- name_str = f'({ifname},{direction})'
-
- if 'name' in fw_conf:
- fw_name = fw_conf['name']
-
- if not name:
- firewall['name'][fw_name]['interface'].append(name_str)
- elif not ipv6 and name == fw_name:
- firewall['interface'].append(name_str)
-
- if 'ipv6_name' in fw_conf:
- fw_name = fw_conf['ipv6_name']
-
- if not name:
- firewall['ipv6_name'][fw_name]['interface'].append(name_str)
- elif ipv6 and name == fw_name:
- firewall['interface'].append(name_str)
-
- return firewall
-
-def get_config_firewall(conf, name=None, ipv6=False, interfaces=True):
+def get_config_firewall(conf, hook=None, priority=None, ipv6=False, interfaces=True):
config_path = ['firewall']
- if name:
- config_path += ['ipv6-name' if ipv6 else 'name', name]
+ if hook:
+ config_path += ['ipv6' if ipv6 else 'ipv4', hook]
+ if priority:
+ config_path += [priority]
firewall = conf.get_config_dict(config_path, key_mangling=('-', '_'),
get_first_key=True, no_tag_node_value_mangle=True)
- if firewall and interfaces:
- if name:
- firewall['interface'] = {}
- else:
- if 'name' in firewall:
- for fw_name, name_conf in firewall['name'].items():
- name_conf['interface'] = []
- if 'ipv6_name' in firewall:
- for fw_name, name_conf in firewall['ipv6_name'].items():
- name_conf['interface'] = []
-
- get_firewall_interfaces(firewall, name, ipv6)
return firewall
-def get_nftables_details(name, ipv6=False):
+def get_nftables_details(hook, priority, ipv6=False):
suffix = '6' if ipv6 else ''
name_prefix = 'NAME6_' if ipv6 else 'NAME_'
- command = f'sudo nft list chain ip{suffix} vyos_filter {name_prefix}{name}'
+ if hook == 'name' or hook == 'ipv6-name':
+ command = f'sudo nft list chain ip{suffix} vyos_filter {name_prefix}{priority}'
+ else:
+ up_hook = hook.upper()
+ command = f'sudo nft list chain ip{suffix} vyos_filter VYOS_{up_hook}_{priority}'
+
try:
results = cmd(command)
except:
@@ -87,7 +52,7 @@ def get_nftables_details(name, ipv6=False):
out = {}
for line in results.split('\n'):
- comment_search = re.search(rf'{name}[\- ](\d+|default-action)', line)
+ comment_search = re.search(rf'{priority}[\- ](\d+|default-action)', line)
if not comment_search:
continue
@@ -102,18 +67,15 @@ def get_nftables_details(name, ipv6=False):
out[rule_id] = rule
return out
-def output_firewall_name(name, name_conf, ipv6=False, single_rule_id=None):
+def output_firewall_name(hook, priority, firewall_conf, ipv6=False, single_rule_id=None):
ip_str = 'IPv6' if ipv6 else 'IPv4'
- print(f'\n---------------------------------\n{ip_str} Firewall "{name}"\n')
-
- if name_conf['interface']:
- print('Active on: {0}\n'.format(" ".join(name_conf['interface'])))
+ print(f'\n---------------------------------\n{ip_str} Firewall "{hook} {priority}"\n')
- details = get_nftables_details(name, ipv6)
+ details = get_nftables_details(hook, priority, ipv6)
rows = []
- if 'rule' in name_conf:
- for rule_id, rule_conf in name_conf['rule'].items():
+ if 'rule' in firewall_conf:
+ for rule_id, rule_conf in firewall_conf['rule'].items():
if single_rule_id and rule_id != single_rule_id:
continue
@@ -128,8 +90,8 @@ def output_firewall_name(name, name_conf, ipv6=False, single_rule_id=None):
row.append(rule_details['conditions'])
rows.append(row)
- if 'default_action' in name_conf and not single_rule_id:
- row = ['default', name_conf['default_action'], 'all']
+ if 'default_action' in firewall_conf and not single_rule_id:
+ row = ['default', firewall_conf['default_action'], 'all']
if 'default-action' in details:
rule_details = details['default-action']
row.append(rule_details.get('packets', 0))
@@ -140,18 +102,15 @@ def output_firewall_name(name, name_conf, ipv6=False, single_rule_id=None):
header = ['Rule', 'Action', 'Protocol', 'Packets', 'Bytes', 'Conditions']
print(tabulate.tabulate(rows, header) + '\n')
-def output_firewall_name_statistics(name, name_conf, ipv6=False, single_rule_id=None):
+def output_firewall_name_statistics(hook, prior, prior_conf, ipv6=False, single_rule_id=None):
ip_str = 'IPv6' if ipv6 else 'IPv4'
- print(f'\n---------------------------------\n{ip_str} Firewall "{name}"\n')
+ print(f'\n---------------------------------\n{ip_str} Firewall "{hook} {prior}"\n')
- if name_conf['interface']:
- print('Active on: {0}\n'.format(" ".join(name_conf['interface'])))
-
- details = get_nftables_details(name, ipv6)
+ details = get_nftables_details(prior, ipv6)
rows = []
- if 'rule' in name_conf:
- for rule_id, rule_conf in name_conf['rule'].items():
+ if 'rule' in prior_conf:
+ for rule_id, rule_conf in prior_conf['rule'].items():
if single_rule_id and rule_id != single_rule_id:
continue
@@ -174,7 +133,7 @@ def output_firewall_name_statistics(name, name_conf, ipv6=False, single_rule_id=
row.append(dest_addr)
rows.append(row)
- if 'default_action' in name_conf and not single_rule_id:
+ if 'default_action' in prior_conf and not single_rule_id:
row = ['default']
if 'default-action' in details:
rule_details = details['default-action']
@@ -183,7 +142,7 @@ def output_firewall_name_statistics(name, name_conf, ipv6=False, single_rule_id=
else:
row.append('0')
row.append('0')
- row.append(name_conf['default_action'])
+ row.append(prior_conf['default_action'])
row.append('0.0.0.0/0') # Source
row.append('0.0.0.0/0') # Dest
rows.append(row)
@@ -201,29 +160,47 @@ def show_firewall():
if not firewall:
return
- if 'name' in firewall:
- for name, name_conf in firewall['name'].items():
- output_firewall_name(name, name_conf, ipv6=False)
+ if 'ipv4' in firewall:
+ for hook, hook_conf in firewall['ipv4'].items():
+ for prior, prior_conf in firewall['ipv4'][hook].items():
+ output_firewall_name(hook, prior, prior_conf, ipv6=False)
+
+ if 'ipv6' in firewall:
+ for hook, hook_conf in firewall['ipv6'].items():
+ for prior, prior_conf in firewall['ipv6'][hook].items():
+ output_firewall_name(hook, prior, prior_conf, ipv6=True)
- if 'ipv6_name' in firewall:
- for name, name_conf in firewall['ipv6_name'].items():
- output_firewall_name(name, name_conf, ipv6=True)
+def show_firewall_family(family):
+ print(f'Rulesets {family} Information')
-def show_firewall_name(name, ipv6=False):
+ conf = Config()
+ firewall = get_config_firewall(conf)
+
+ if not firewall:
+ return
+
+ for hook, hook_conf in firewall[family].items():
+ for prior, prior_conf in firewall[family][hook].items():
+ if family == 'ipv6':
+ output_firewall_name(hook, prior, prior_conf, ipv6=True)
+ else:
+ output_firewall_name(hook, prior, prior_conf, ipv6=False)
+
+def show_firewall_name(hook, priority, ipv6=False):
print('Ruleset Information')
conf = Config()
- firewall = get_config_firewall(conf, name, ipv6)
+ firewall = get_config_firewall(conf, hook, priority, ipv6)
if firewall:
- output_firewall_name(name, firewall, ipv6)
+ output_firewall_name(hook, priority, firewall, ipv6)
-def show_firewall_rule(name, rule_id, ipv6=False):
+def show_firewall_rule(hook, priority, rule_id, ipv6=False):
print('Rule Information')
conf = Config()
- firewall = get_config_firewall(conf, name, ipv6)
+ firewall = get_config_firewall(conf, hook, priority, ipv6)
if firewall:
- output_firewall_name(name, firewall, ipv6, rule_id)
+ output_firewall_name(hook, priority, firewall, ipv6, rule_id)
def show_firewall_group(name=None):
conf = Config()
@@ -234,19 +211,32 @@ def show_firewall_group(name=None):
def find_references(group_type, group_name):
out = []
- for name_type in ['name', 'ipv6_name']:
- if name_type not in firewall:
- continue
- for name, name_conf in firewall[name_type].items():
- if 'rule' not in name_conf:
+ family = []
+ if group_type in ['address_group', 'network_group']:
+ family = ['ipv4']
+ elif group_type == 'ipv6_address_group':
+ family = ['ipv6']
+ group_type = 'address_group'
+ elif group_type == 'ipv6_network_group':
+ family = ['ipv6']
+ group_type = 'network_group'
+ else:
+ family = ['ipv4', 'ipv6']
+
+ for item in family:
+ for name_type in ['name', 'ipv6_name', 'forward', 'input', 'output']:
+ if name_type not in firewall[item]:
continue
- for rule_id, rule_conf in name_conf['rule'].items():
- source_group = dict_search_args(rule_conf, 'source', 'group', group_type)
- dest_group = dict_search_args(rule_conf, 'destination', 'group', group_type)
- if source_group and group_name == source_group:
- out.append(f'{name}-{rule_id}')
- elif dest_group and group_name == dest_group:
- out.append(f'{name}-{rule_id}')
+ for name, name_conf in firewall[item][name_type].items():
+ if 'rule' not in name_conf:
+ continue
+ for rule_id, rule_conf in name_conf['rule'].items():
+ source_group = dict_search_args(rule_conf, 'source', 'group', group_type)
+ dest_group = dict_search_args(rule_conf, 'destination', 'group', group_type)
+ if source_group and group_name == source_group:
+ out.append(f'{name}-{rule_id}')
+ elif dest_group and group_name == dest_group:
+ out.append(f'{name}-{rule_id}')
return out
header = ['Name', 'Type', 'References', 'Members']
@@ -284,28 +274,28 @@ def show_summary():
if not firewall:
return
- header = ['Ruleset Name', 'Description', 'References']
+ header = ['Ruleset Hook', 'Ruleset Priority', 'Description', 'References']
v4_out = []
v6_out = []
- if 'name' in firewall:
- for name, name_conf in firewall['name'].items():
- description = name_conf.get('description', '')
- interfaces = ", ".join(name_conf['interface'])
- v4_out.append([name, description, interfaces])
+ if 'ipv4' in firewall:
+ for hook, hook_conf in firewall['ipv4'].items():
+ for prior, prior_conf in firewall['ipv4'][hook].items():
+ description = prior_conf.get('description', '')
+ v4_out.append([hook, prior, description])
- if 'ipv6_name' in firewall:
- for name, name_conf in firewall['ipv6_name'].items():
- description = name_conf.get('description', '')
- interfaces = ", ".join(name_conf['interface'])
- v6_out.append([name, description, interfaces or 'N/A'])
+ if 'ipv6' in firewall:
+ for hook, hook_conf in firewall['ipv6'].items():
+ for prior, prior_conf in firewall['ipv6'][hook].items():
+ description = prior_conf.get('description', '')
+ v6_out.append([hook, prior, description])
if v6_out:
- print('\nIPv6 name:\n')
+ print('\nIPv6 Ruleset:\n')
print(tabulate.tabulate(v6_out, header) + '\n')
if v4_out:
- print('\nIPv4 name:\n')
+ print('\nIPv4 Ruleset:\n')
print(tabulate.tabulate(v4_out, header) + '\n')
show_firewall_group()
@@ -319,18 +309,23 @@ def show_statistics():
if not firewall:
return
- if 'name' in firewall:
- for name, name_conf in firewall['name'].items():
- output_firewall_name_statistics(name, name_conf, ipv6=False)
+ if 'ipv4' in firewall:
+ for hook, hook_conf in firewall['ipv4'].items():
+ for prior, prior_conf in firewall['ipv4'][hook].items():
+ output_firewall_name_statistics(hook,prior, prior_conf, ipv6=False)
- if 'ipv6_name' in firewall:
- for name, name_conf in firewall['ipv6_name'].items():
- output_firewall_name_statistics(name, name_conf, ipv6=True)
+ if 'ipv6' in firewall:
+ for hook, hook_conf in firewall['ipv6'].items():
+ for prior, prior_conf in firewall['ipv6'][hook].items():
+ output_firewall_name_statistics(hook,prior, prior_conf, ipv6=True)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('--action', help='Action', required=False)
parser.add_argument('--name', help='Firewall name', required=False, action='store', nargs='?', default='')
+ parser.add_argument('--family', help='IP family', required=False, action='store', nargs='?', default='')
+ parser.add_argument('--hook', help='Firewall hook', required=False, action='store', nargs='?', default='')
+ parser.add_argument('--priority', help='Firewall priority', required=False, action='store', nargs='?', default='')
parser.add_argument('--rule', help='Firewall Rule ID', required=False)
parser.add_argument('--ipv6', help='IPv6 toggle', action='store_true')
@@ -338,11 +333,13 @@ if __name__ == '__main__':
if args.action == 'show':
if not args.rule:
- show_firewall_name(args.name, args.ipv6)
+ show_firewall_name(args.hook, args.priority, args.ipv6)
else:
- show_firewall_rule(args.name, args.rule, args.ipv6)
+ show_firewall_rule(args.hook, args.priority, args.rule, args.ipv6)
elif args.action == 'show_all':
show_firewall()
+ elif args.action == 'show_family':
+ show_firewall_family(args.family)
elif args.action == 'show_group':
show_firewall_group(args.name)
elif args.action == 'show_statistics':
diff --git a/src/op_mode/pki.py b/src/op_mode/pki.py
index 4c31291ad..aff4ad1ae 100755
--- a/src/op_mode/pki.py
+++ b/src/op_mode/pki.py
@@ -26,8 +26,8 @@ from cryptography.x509.oid import ExtendedKeyUsageOID
from vyos.config import Config
from vyos.configquery import ConfigTreeQuery
-from vyos.configdict import dict_merge
from vyos.pki import encode_certificate, encode_public_key, encode_private_key, encode_dh_parameters
+from vyos.pki import get_certificate_fingerprint
from vyos.pki import create_certificate, create_certificate_request, create_certificate_revocation_list
from vyos.pki import create_private_key
from vyos.pki import create_dh_parameters
@@ -38,7 +38,6 @@ from vyos.utils.io import ask_input
from vyos.utils.io import ask_yes_no
from vyos.utils.misc import install_into_config
from vyos.utils.process import cmd
-from vyos.xml import defaults
CERT_REQ_END = '-----END CERTIFICATE REQUEST-----'
auth_dir = '/config/auth'
@@ -49,10 +48,9 @@ def get_default_values():
# Fetch default x509 values
base = ['pki', 'x509', 'default']
x509_defaults = conf.get_config_dict(base, key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
get_first_key=True,
- no_tag_node_value_mangle=True)
- default_values = defaults(base)
- x509_defaults = dict_merge(default_values, x509_defaults)
+ with_recursive_defaults=True)
return x509_defaults
@@ -916,6 +914,12 @@ def show_certificate(name=None, pem=False):
print("Certificates:")
print(tabulate.tabulate(data, headers))
+def show_certificate_fingerprint(name, hash):
+ cert = get_config_certificate(name=name)
+ cert = load_certificate(cert['certificate'])
+
+ print(get_certificate_fingerprint(cert, hash))
+
def show_crl(name=None, pem=False):
headers = ['CA Name', 'Updated', 'Revokes']
data = []
@@ -961,6 +965,7 @@ if __name__ == '__main__':
parser.add_argument('--sign', help='Sign certificate with specified CA', required=False)
parser.add_argument('--self-sign', help='Self-sign the certificate', action='store_true')
parser.add_argument('--pem', help='Output using PEM encoding', action='store_true')
+ parser.add_argument('--fingerprint', help='Show fingerprint and exit', action='store')
# SSH
parser.add_argument('--ssh', help='SSH Key', required=False)
@@ -1057,7 +1062,10 @@ if __name__ == '__main__':
if not conf.exists(['pki', 'certificate', cert_name]):
print(f'Certificate "{cert_name}" does not exist!')
exit(1)
- show_certificate(None if args.certificate == 'all' else args.certificate, args.pem)
+ if args.fingerprint is None:
+ show_certificate(None if args.certificate == 'all' else args.certificate, args.pem)
+ else:
+ show_certificate_fingerprint(args.certificate, args.fingerprint)
elif args.crl:
show_crl(None if args.crl == 'all' else args.crl, args.pem)
else:
diff --git a/src/op_mode/show_openconnect_otp.py b/src/op_mode/show_openconnect_otp.py
index 415a5f72c..3771fb385 100755
--- a/src/op_mode/show_openconnect_otp.py
+++ b/src/op_mode/show_openconnect_otp.py
@@ -17,12 +17,11 @@
import argparse
import os
+from base64 import b32encode
from vyos.config import Config
-from vyos.xml import defaults
-from vyos.configdict import dict_merge
+from vyos.utils.dict import dict_search_args
from vyos.utils.process import popen
-from base64 import b32encode
otp_file = '/run/ocserv/users.oath'
@@ -33,7 +32,7 @@ def check_uname_otp(username):
config = Config()
base_key = ['vpn', 'openconnect', 'authentication', 'local-users', 'username', username, 'otp', 'key']
if not config.exists(base_key):
- return None
+ return False
return True
def get_otp_ocserv(username):
@@ -41,21 +40,21 @@ def get_otp_ocserv(username):
base = ['vpn', 'openconnect']
if not config.exists(base):
return None
- ocserv = config.get_config_dict(base, key_mangling=('-', '_'), get_first_key=True)
- # We have gathered the dict representation of the CLI, but there are default
- # options which we need to update into the dictionary retrived.
- default_values = defaults(base)
- ocserv = dict_merge(default_values, ocserv)
- # workaround a "know limitation" - https://vyos.dev/T2665
- del ocserv['authentication']['local_users']['username']['otp']
- if not ocserv["authentication"]["local_users"]["username"]:
+
+ ocserv = config.get_config_dict(base, key_mangling=('-', '_'),
+ get_first_key=True,
+ with_recursive_defaults=True)
+
+ user_path = ['authentication', 'local_users', 'username']
+ users = dict_search_args(ocserv, *user_path)
+
+ if users is None:
return None
- default_ocserv_usr_values = default_values['authentication']['local_users']['username']['otp']
- for user, params in ocserv['authentication']['local_users']['username'].items():
- # Not every configuration requires OTP settings
- if ocserv['authentication']['local_users']['username'][user].get('otp'):
- ocserv['authentication']['local_users']['username'][user]['otp'] = dict_merge(default_ocserv_usr_values, ocserv['authentication']['local_users']['username'][user]['otp'])
- result = ocserv['authentication']['local_users']['username'][username]
+
+ # function is called conditionally, if check_uname_otp true, so username
+ # exists
+ result = users[username]
+
return result
def display_otp_ocserv(username, params, info):
@@ -101,8 +100,7 @@ if __name__ == '__main__':
parser.add_argument('--info', action="store", type=str, default='full', help='Wich information to display')
args = parser.parse_args()
- check_otp = check_uname_otp(args.user)
- if check_otp:
+ if check_uname_otp(args.user):
user_otp_params = get_otp_ocserv(args.user)
display_otp_ocserv(args.user, user_otp_params, args.info)
else:
diff --git a/src/op_mode/show_techsupport_report.py b/src/op_mode/show_techsupport_report.py
index d27221e54..53144fd52 100644
--- a/src/op_mode/show_techsupport_report.py
+++ b/src/op_mode/show_techsupport_report.py
@@ -91,7 +91,8 @@ def show_package_repository_config() -> None:
def show_user_startup_scripts() -> None:
"""Prints the user startup scripts."""
- execute_command('cat /config/scripts/vyos-postconfig-bootup.script', 'User Startup Scripts')
+ execute_command('cat /config/scripts/vyos-preconfig-bootup.script', 'User Startup Scripts (Preconfig)')
+ execute_command('cat /config/scripts/vyos-postconfig-bootup.script', 'User Startup Scripts (Postconfig)')
def show_frr_config() -> None:
diff --git a/src/op_mode/webproxy_update_blacklist.sh b/src/op_mode/webproxy_update_blacklist.sh
index 4fb9a54c6..05ea86f9e 100755
--- a/src/op_mode/webproxy_update_blacklist.sh
+++ b/src/op_mode/webproxy_update_blacklist.sh
@@ -45,6 +45,9 @@ do
--auto-update-blacklist)
auto="yes"
;;
+ --vrf)
+ vrf="yes"
+ ;;
(-*) echo "$0: error - unrecognized option $1" 1>&2; exit 1;;
(*) break;;
esac
@@ -76,7 +79,11 @@ fi
if [[ -n $update ]] && [[ $update -eq "yes" ]]; then
tmp_blacklists='/tmp/blacklists.gz'
- curl -o $tmp_blacklists $blacklist_url
+ if [[ -n $vrf ]] && [[ $vrf -eq "yes" ]]; then
+ sudo ip vrf exec $1 curl -o $tmp_blacklists $blacklist_url
+ else
+ curl -o $tmp_blacklists $blacklist_url
+ fi
if [ $? -ne 0 ]; then
echo "Unable to download [$blacklist_url]!"
exit 1
diff --git a/src/systemd/dhclient@.service b/src/systemd/dhclient@.service
index 23cd4cfc3..099f7ed52 100644
--- a/src/systemd/dhclient@.service
+++ b/src/systemd/dhclient@.service
@@ -1,18 +1,17 @@
[Unit]
Description=DHCP client on %i
Documentation=man:dhclient(8)
-ConditionPathExists=/var/lib/dhcp/dhclient_%i.conf
-ConditionPathExists=/var/lib/dhcp/dhclient_%i.options
+StartLimitIntervalSec=0
After=vyos-router.service
[Service]
-WorkingDirectory=/var/lib/dhcp
Type=exec
-EnvironmentFile=-/var/lib/dhcp/dhclient_%i.options
-PIDFile=/var/lib/dhcp/dhclient_%i.pid
-ExecStart=/sbin/dhclient -4 $DHCLIENT_OPTS
-ExecStop=/sbin/dhclient -4 $DHCLIENT_OPTS -r
+ExecStart=/sbin/dhclient -4 -d $DHCLIENT_OPTS
+ExecStop=/sbin/dhclient -4 -r $DHCLIENT_OPTS
Restart=always
+RestartPreventExitStatus=
+RestartSec=10
+RuntimeDirectoryPreserve=yes
TimeoutStopSec=20
SendSIGKILL=true
FinalKillSignal=SIGABRT
diff --git a/src/systemd/dhcp6c@.service b/src/systemd/dhcp6c@.service
index 9a97ee261..f634bd944 100644
--- a/src/systemd/dhcp6c@.service
+++ b/src/systemd/dhcp6c@.service
@@ -1,17 +1,19 @@
[Unit]
Description=WIDE DHCPv6 client on %i
Documentation=man:dhcp6c(8) man:dhcp6c.conf(5)
-ConditionPathExists=/run/dhcp6c/dhcp6c.%i.conf
-After=vyos-router.service
StartLimitIntervalSec=0
+After=vyos-router.service
[Service]
-WorkingDirectory=/run/dhcp6c
Type=forking
+WorkingDirectory=/run/dhcp6c
+EnvironmentFile=-/run/dhcp6c/dhcp6c.%i.options
PIDFile=/run/dhcp6c/dhcp6c.%i.pid
-ExecStart=/usr/sbin/dhcp6c -D -k /run/dhcp6c/dhcp6c.%i.sock -c /run/dhcp6c/dhcp6c.%i.conf -p /run/dhcp6c/dhcp6c.%i.pid %i
-Restart=on-failure
-RestartSec=20
+ExecStart=/usr/sbin/dhcp6c $DHCP6C_OPTS
+Restart=always
+RestartPreventExitStatus=
+RestartSec=10
+RuntimeDirectoryPreserve=yes
[Install]
WantedBy=multi-user.target
diff --git a/src/tests/test_initial_setup.py b/src/tests/test_initial_setup.py
index cb843ff09..ba50d06cc 100644
--- a/src/tests/test_initial_setup.py
+++ b/src/tests/test_initial_setup.py
@@ -21,14 +21,16 @@ import vyos.configtree
import vyos.initialsetup as vis
from unittest import TestCase
-from vyos import xml
+from vyos.xml_ref import definition
+from vyos.xml_ref.pkg_cache.vyos_1x_cache import reference
class TestInitialSetup(TestCase):
def setUp(self):
with open('tests/data/config.boot.default', 'r') as f:
config_string = f.read()
self.config = vyos.configtree.ConfigTree(config_string)
- self.xml = xml.load_configuration()
+ self.xml = definition.Xml()
+ self.xml.define(reference)
def test_set_user_password(self):
vis.set_user_password(self.config, 'vyos', 'vyosvyos')
diff --git a/src/tests/test_util.py b/src/tests/test_utils.py
index 27ee648d4..9ae329ced 100644
--- a/src/tests/test_util.py
+++ b/src/tests/test_utils.py
@@ -15,8 +15,7 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from unittest import TestCase
-
-class TestVyOSUtil(TestCase):
+class TestVyOSUtils(TestCase):
def test_key_mangling(self):
from vyos.utils.dict import mangle_dict_keys
data = {"foo-bar": {"baz-quux": None}}
diff --git a/src/tests/test_utils_network.py b/src/tests/test_utils_network.py
new file mode 100644
index 000000000..5a6dc2586
--- /dev/null
+++ b/src/tests/test_utils_network.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python3
+#
+# Copyright (C) 2020-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 vyos.utils.network
+from unittest import TestCase
+
+class TestVyOSUtilsNetwork(TestCase):
+ def setUp(self):
+ pass
+
+ def test_is_addr_assigned(self):
+ self.assertTrue(vyos.utils.network.is_addr_assigned('127.0.0.1'))
+ self.assertTrue(vyos.utils.network.is_addr_assigned('::1'))
+ self.assertFalse(vyos.utils.network.is_addr_assigned('127.251.255.123'))
+
+ def test_is_ipv6_link_local(self):
+ self.assertFalse(vyos.utils.network.is_ipv6_link_local('169.254.0.1'))
+ self.assertTrue(vyos.utils.network.is_ipv6_link_local('fe80::'))
+ self.assertTrue(vyos.utils.network.is_ipv6_link_local('fe80::affe:1'))
+ self.assertTrue(vyos.utils.network.is_ipv6_link_local('fe80::affe:1%eth0'))
+ self.assertFalse(vyos.utils.network.is_ipv6_link_local('2001:db8::'))
+ self.assertFalse(vyos.utils.network.is_ipv6_link_local('2001:db8::%eth0'))
+ self.assertFalse(vyos.utils.network.is_ipv6_link_local('VyOS'))
+ self.assertFalse(vyos.utils.network.is_ipv6_link_local('::1'))
+ self.assertFalse(vyos.utils.network.is_ipv6_link_local('::1%lo'))
+
+ def test_is_ipv6_link_local(self):
+ self.assertTrue(vyos.utils.network.is_loopback_addr('127.0.0.1'))
+ self.assertTrue(vyos.utils.network.is_loopback_addr('127.0.1.1'))
+ self.assertTrue(vyos.utils.network.is_loopback_addr('127.1.1.1'))
+ self.assertTrue(vyos.utils.network.is_loopback_addr('::1'))
+
+ self.assertFalse(vyos.utils.network.is_loopback_addr('::2'))
+ self.assertFalse(vyos.utils.network.is_loopback_addr('192.0.2.1'))
+
+
+
diff --git a/src/tests/test_validate.py b/src/tests/test_validate.py
deleted file mode 100644
index 68a257d25..000000000
--- a/src/tests/test_validate.py
+++ /dev/null
@@ -1,50 +0,0 @@
-#!/usr/bin/env python3
-#
-# Copyright (C) 2020 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 vyos.validate
-from unittest import TestCase
-
-class TestVyOSValidate(TestCase):
- def setUp(self):
- pass
-
- def test_is_addr_assigned(self):
- self.assertTrue(vyos.validate.is_addr_assigned('127.0.0.1'))
- self.assertTrue(vyos.validate.is_addr_assigned('::1'))
- self.assertFalse(vyos.validate.is_addr_assigned('127.251.255.123'))
-
- def test_is_ipv6_link_local(self):
- self.assertFalse(vyos.validate.is_ipv6_link_local('169.254.0.1'))
- self.assertTrue(vyos.validate.is_ipv6_link_local('fe80::'))
- self.assertTrue(vyos.validate.is_ipv6_link_local('fe80::affe:1'))
- self.assertTrue(vyos.validate.is_ipv6_link_local('fe80::affe:1%eth0'))
- self.assertFalse(vyos.validate.is_ipv6_link_local('2001:db8::'))
- self.assertFalse(vyos.validate.is_ipv6_link_local('2001:db8::%eth0'))
- self.assertFalse(vyos.validate.is_ipv6_link_local('VyOS'))
- self.assertFalse(vyos.validate.is_ipv6_link_local('::1'))
- self.assertFalse(vyos.validate.is_ipv6_link_local('::1%lo'))
-
- def test_is_ipv6_link_local(self):
- self.assertTrue(vyos.validate.is_loopback_addr('127.0.0.1'))
- self.assertTrue(vyos.validate.is_loopback_addr('127.0.1.1'))
- self.assertTrue(vyos.validate.is_loopback_addr('127.1.1.1'))
- self.assertTrue(vyos.validate.is_loopback_addr('::1'))
-
- self.assertFalse(vyos.validate.is_loopback_addr('::2'))
- self.assertFalse(vyos.validate.is_loopback_addr('192.0.2.1'))
-
-
-
diff --git a/src/validators/ipv6-link-local b/src/validators/ipv6-link-local
index 05e693b77..6ac3ea710 100755
--- a/src/validators/ipv6-link-local
+++ b/src/validators/ipv6-link-local
@@ -1,7 +1,7 @@
#!/usr/bin/python3
import sys
-from vyos.validate import is_ipv6_link_local
+from vyos.utils.network import is_ipv6_link_local
if __name__ == '__main__':
if len(sys.argv)>1: