summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data/config-mode-dependencies/vyos-1x.json3
-rw-r--r--data/templates/accel-ppp/config_shaper_radius.j22
-rw-r--r--data/templates/dns-dynamic/ddclient.conf.j22
-rw-r--r--debian/control2
-rw-r--r--debian/vyos-1x.preinst1
-rw-r--r--interface-definitions/dns-dynamic.xml.in6
-rw-r--r--interface-definitions/include/version/dns-dynamic-version.xml.i2
-rw-r--r--op-mode-definitions/include/bgp/show-bgp-common.xml.i16
-rw-r--r--op-mode-definitions/mdns-reflector.xml.in62
-rwxr-xr-xsmoketest/scripts/cli/test_service_dns_dynamic.py11
-rwxr-xr-xsmoketest/scripts/cli/test_service_pppoe-server.py2
-rwxr-xr-xsrc/completion/list_ddclient_protocols.sh2
-rwxr-xr-xsrc/conf_mode/dns_dynamic.py38
-rwxr-xr-xsrc/conf_mode/interfaces-bridge.py18
-rwxr-xr-xsrc/conf_mode/service_pppoe-server.py7
-rw-r--r--src/etc/udev/rules.d/99-vyos-systemd.rules79
-rwxr-xr-xsrc/helpers/strip-private.py4
-rwxr-xr-xsrc/migration-scripts/dns-dynamic/1-to-270
-rwxr-xr-xsrc/validators/ddclient-protocol2
19 files changed, 291 insertions, 38 deletions
diff --git a/data/config-mode-dependencies/vyos-1x.json b/data/config-mode-dependencies/vyos-1x.json
index f87185d6a..918fb0f17 100644
--- a/data/config-mode-dependencies/vyos-1x.json
+++ b/data/config-mode-dependencies/vyos-1x.json
@@ -9,6 +9,9 @@
"interfaces_bonding": {
"ethernet": ["interfaces-ethernet"]
},
+ "interfaces_bridge": {
+ "vxlan": ["interfaces-vxlan"]
+ },
"load_balancing_wan": {
"conntrack": ["conntrack"],
"conntrack_sync": ["conntrack_sync"]
diff --git a/data/templates/accel-ppp/config_shaper_radius.j2 b/data/templates/accel-ppp/config_shaper_radius.j2
index 0cf6a6a92..fcd68f69e 100644
--- a/data/templates/accel-ppp/config_shaper_radius.j2
+++ b/data/templates/accel-ppp/config_shaper_radius.j2
@@ -1,6 +1,7 @@
{% if authentication.mode is vyos_defined('radius') or shaper is vyos_defined %}
[shaper]
verbose=1
+down-limiter=tbf
{% if authentication.radius.rate_limit.enable is vyos_defined %}
attr={{ authentication.radius.rate_limit.attribute }}
{% if authentication.radius.rate_limit.vendor is vyos_defined %}
@@ -13,7 +14,6 @@ rate-multiplier={{ authentication.radius.rate_limit.multiplier }}
{% if shaper is vyos_defined %}
{% if shaper.fwmark is vyos_defined %}
fwmark={{ shaper.fwmark }}
-down-limiter=htb
{% endif %}
{% endif %}
{% endif %} \ No newline at end of file
diff --git a/data/templates/dns-dynamic/ddclient.conf.j2 b/data/templates/dns-dynamic/ddclient.conf.j2
index 6e77abdb5..879887a1f 100644
--- a/data/templates/dns-dynamic/ddclient.conf.j2
+++ b/data/templates/dns-dynamic/ddclient.conf.j2
@@ -21,7 +21,7 @@ if{{ ipv }}={{ address }}, \
{{ host }}
{% endmacro %}
### Autogenerated by dns_dynamic.py ###
-daemon={{ timeout }}
+daemon={{ interval }}
syslog=yes
ssl=yes
pid={{ config_file | replace('.conf', '.pid') }}
diff --git a/debian/control b/debian/control
index 32de13f1b..d2ed3991a 100644
--- a/debian/control
+++ b/debian/control
@@ -155,7 +155,7 @@ Depends:
# For "set service aws glb"
aws-gwlbtun,
# For "service dns dynamic"
- ddclient (>= 3.9.1),
+ ddclient (>= 3.11.1),
# End "service dns dynamic"
# # For "service ids"
fastnetmon [amd64],
diff --git a/debian/vyos-1x.preinst b/debian/vyos-1x.preinst
index 9bd6331a8..08f48cac2 100644
--- a/debian/vyos-1x.preinst
+++ b/debian/vyos-1x.preinst
@@ -9,3 +9,4 @@ dpkg-divert --package vyos-1x --add --no-rename /etc/sysctl.d/80-vpp.conf
dpkg-divert --package vyos-1x --add --no-rename /etc/netplug/netplugd.conf
dpkg-divert --package vyos-1x --add --no-rename /etc/netplug/netplug
dpkg-divert --package vyos-1x --add --no-rename /etc/rsyslog.d/45-frr.conf
+dpkg-divert --package vyos-1x --add --no-rename /lib/udev/rules.d/99-systemd.rules
diff --git a/interface-definitions/dns-dynamic.xml.in b/interface-definitions/dns-dynamic.xml.in
index 723223f1c..07b1bf1b8 100644
--- a/interface-definitions/dns-dynamic.xml.in
+++ b/interface-definitions/dns-dynamic.xml.in
@@ -134,9 +134,9 @@
</tagNode>
</children>
</tagNode>
- <leafNode name="timeout">
+ <leafNode name="interval">
<properties>
- <help>Time in seconds to wait between DNS updates</help>
+ <help>Interval in seconds to wait between Dynamic DNS updates</help>
<valueHelp>
<format>u32:60-3600</format>
<description>Time in seconds</description>
@@ -144,7 +144,7 @@
<constraint>
<validator name="numeric" argument="--range 60-3600"/>
</constraint>
- <constraintErrorMessage>Timeout must be between 60 and 3600 seconds</constraintErrorMessage>
+ <constraintErrorMessage>Interval must be between 60 and 3600 seconds</constraintErrorMessage>
</properties>
<defaultValue>300</defaultValue>
</leafNode>
diff --git a/interface-definitions/include/version/dns-dynamic-version.xml.i b/interface-definitions/include/version/dns-dynamic-version.xml.i
index b25fc6e76..7bdb90a35 100644
--- a/interface-definitions/include/version/dns-dynamic-version.xml.i
+++ b/interface-definitions/include/version/dns-dynamic-version.xml.i
@@ -1,3 +1,3 @@
<!-- include start from include/version/dns-dynamic-version.xml.i -->
-<syntaxVersion component='dns-dynamic' version='1'></syntaxVersion>
+<syntaxVersion component='dns-dynamic' version='2'></syntaxVersion>
<!-- include end -->
diff --git a/op-mode-definitions/include/bgp/show-bgp-common.xml.i b/op-mode-definitions/include/bgp/show-bgp-common.xml.i
index de794a879..d888bc3b0 100644
--- a/op-mode-definitions/include/bgp/show-bgp-common.xml.i
+++ b/op-mode-definitions/include/bgp/show-bgp-common.xml.i
@@ -107,6 +107,12 @@
#include <include/vni-tagnode.xml.i>
</children>
</node>
+ <leafNode name="es-vrf">
+ <properties>
+ <help>Ethernet Segment per VRF</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ </leafNode>
<leafNode name="import-rt">
<properties>
<help>Show import route target</help>
@@ -136,11 +142,17 @@
</leafNode>
</children>
</tagNode>
+ <leafNode name="next-hops">
+ <properties>
+ <help>EVPN Nexthops</help>
+ </properties>
+ <command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
+ </leafNode>
<tagNode name="rd">
<properties>
- <help>Show detailed BGP neighbor information</help>
+ <help>Display information for a route distinguisher</help>
<completionHelp>
- <list>ASN:NN IPADDRESS:NN</list>
+ <list>ASN:NN IPADDRESS:NN all</list>
</completionHelp>
</properties>
<command>${vyos_op_scripts_dir}/vtysh_wrapper.sh $@</command>
diff --git a/op-mode-definitions/mdns-reflector.xml.in b/op-mode-definitions/mdns-reflector.xml.in
new file mode 100644
index 000000000..a90d4d385
--- /dev/null
+++ b/op-mode-definitions/mdns-reflector.xml.in
@@ -0,0 +1,62 @@
+<?xml version="1.0"?>
+<interfaceDefinition>
+ <node name="monitor">
+ <children>
+ <node name="log">
+ <children>
+ <node name="mdns">
+ <properties>
+ <help>Monitor last lines of multicast Domain Name System related services</help>
+ </properties>
+ <children>
+ <node name="repeater">
+ <properties>
+ <help>Monitor last lines of mDNS repeater service</help>
+ </properties>
+ <command>journalctl --no-hostname --follow --boot --unit avahi-daemon.service</command>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+ <node name="show">
+ <children>
+ <node name="log">
+ <children>
+ <node name="mdns">
+ <properties>
+ <help>Show log for multicast Domain Name System related services</help>
+ </properties>
+ <children>
+ <node name="repeater">
+ <properties>
+ <help>Show log for mDNS repeater service</help>
+ </properties>
+ <command>journalctl --no-hostname --boot --unit avahi-daemon.service</command>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+ <node name="restart">
+ <children>
+ <node name="mdns">
+ <properties>
+ <help>Restart specific multicast Domain Name System service</help>
+ </properties>
+ <children>
+ <node name="repeater">
+ <properties>
+ <help>Restart mDNS repeater service</help>
+ </properties>
+ <command>sudo systemctl restart avahi-daemon.service</command>
+ </node>
+ </children>
+ </node>
+ </children>
+ </node>
+</interfaceDefinition>
diff --git a/smoketest/scripts/cli/test_service_dns_dynamic.py b/smoketest/scripts/cli/test_service_dns_dynamic.py
index acabc0070..9624f823f 100755
--- a/smoketest/scripts/cli/test_service_dns_dynamic.py
+++ b/smoketest/scripts/cli/test_service_dns_dynamic.py
@@ -112,7 +112,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
# IPv6 only DDNS service configuration
def test_02_dyndns_service_ipv6(self):
- timeout = '60'
+ interval = '60'
svc_path = ['address', interface, 'service', 'dynv6']
proto = 'dyndns2'
ip_version = 'ipv6'
@@ -120,7 +120,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
expiry_time_good = '3600'
expiry_time_bad = '360'
- self.cli_set(base_path + ['timeout', timeout])
+ self.cli_set(base_path + ['interval', interval])
self.cli_set(base_path + svc_path + ['ip-version', ip_version])
self.cli_set(base_path + svc_path + ['protocol', proto])
self.cli_set(base_path + svc_path + ['server', server])
@@ -140,7 +140,7 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
# Check the generating config parameters
ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
- self.assertIn(f'daemon={timeout}', ddclient_conf)
+ self.assertIn(f'daemon={interval}', ddclient_conf)
self.assertIn(f'usev6=ifv6', ddclient_conf)
self.assertIn(f'ifv6={interface}', ddclient_conf)
self.assertIn(f'protocol={proto}', ddclient_conf)
@@ -246,10 +246,11 @@ class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
self.assertIn(f'{name}', ddclient_conf)
def test_06_dyndns_vrf(self):
- vrf_name = f'vyos-test-{"".join(random.choices(string.ascii_letters + string.digits, k=5))}'
+ vrf_table = "".join(random.choices(string.digits, k=5))
+ vrf_name = f'vyos-test-{vrf_table}'
svc_path = ['address', interface, 'service', 'cloudflare']
- self.cli_set(['vrf', 'name', vrf_name, 'table', '12345'])
+ self.cli_set(['vrf', 'name', vrf_name, 'table', vrf_table])
self.cli_set(base_path + ['vrf', vrf_name])
self.cli_set(base_path + svc_path + ['protocol', 'cloudflare'])
diff --git a/smoketest/scripts/cli/test_service_pppoe-server.py b/smoketest/scripts/cli/test_service_pppoe-server.py
index 963784f0a..969abd3d5 100755
--- a/smoketest/scripts/cli/test_service_pppoe-server.py
+++ b/smoketest/scripts/cli/test_service_pppoe-server.py
@@ -144,7 +144,7 @@ class TestServicePPPoEServer(BasicAccelPPPTest.TestCase):
subnet = '172.18.0.0/24'
fwmark = '223'
- limiter = 'htb'
+ limiter = 'tbf'
self.set(['client-ip-pool', 'subnet', subnet])
diff --git a/src/completion/list_ddclient_protocols.sh b/src/completion/list_ddclient_protocols.sh
index 3b4eff4d6..c8855b5d1 100755
--- a/src/completion/list_ddclient_protocols.sh
+++ b/src/completion/list_ddclient_protocols.sh
@@ -14,4 +14,4 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
-echo -n $(ddclient -list-protocols | grep -vE 'nsupdate|cloudns')
+echo -n $(ddclient -list-protocols | grep -vE 'nsupdate|cloudns|porkbun')
diff --git a/src/conf_mode/dns_dynamic.py b/src/conf_mode/dns_dynamic.py
index 874c4b689..d6ef620fe 100755
--- a/src/conf_mode/dns_dynamic.py
+++ b/src/conf_mode/dns_dynamic.py
@@ -30,16 +30,21 @@ config_file = r'/run/ddclient/ddclient.conf'
systemd_override = r'/run/systemd/system/ddclient.service.d/override.conf'
# Protocols that require zone
-zone_necessary = ['cloudflare', 'godaddy', 'hetzner', 'gandi', 'nfsn']
+zone_necessary = ['cloudflare', 'digitalocean', 'godaddy', 'hetzner', 'gandi', 'nfsn']
+zone_supported = zone_necessary + ['dnsexit2', 'zoneedit1']
# Protocols that do not require username
-username_unnecessary = ['1984', 'cloudflare', 'cloudns', 'duckdns', 'freemyip', 'hetzner', 'keysystems', 'njalla']
+username_unnecessary = ['1984', 'cloudflare', 'cloudns', 'digitalocean', 'dnsexit2',
+ 'duckdns', 'freemyip', 'hetzner', 'keysystems', 'njalla',
+ 'regfishde']
# Protocols that support TTL
-ttl_supported = ['cloudflare', 'gandi', 'hetzner', 'dnsexit', 'godaddy', 'nfsn']
+ttl_supported = ['cloudflare', 'dnsexit2', 'gandi', 'hetzner', 'godaddy', 'nfsn']
# Protocols that support both IPv4 and IPv6
-dualstack_supported = ['cloudflare', 'dyndns2', 'freedns', 'njalla']
+dualstack_supported = ['cloudflare', 'digitalocean', 'dnsexit2', 'duckdns',
+ 'dyndns2', 'easydns', 'freedns', 'hetzner', 'infomaniak',
+ 'njalla']
# dyndns2 protocol in ddclient honors dual stack for selective servers
# because of the way it is implemented in ddclient
@@ -82,34 +87,37 @@ def verify(dyndns):
f'based Dynamic DNS service on "{address}"')
# Dynamic DNS service provider - configuration validation
+ if 'web_options' in dyndns['address'][address] and address != 'web':
+ raise ConfigError(f'"web-options" is applicable only when using HTTP(S) web request to obtain the IP address')
+
+ # Dynamic DNS service provider - configuration validation
if 'service' in dyndns['address'][address]:
for service, config in dyndns['address'][address]['service'].items():
- error_msg = f'is required for Dynamic DNS service "{service}" on "{address}"'
+ error_msg_req = f'is required for Dynamic DNS service "{service}" on "{address}" with protocol "{config["protocol"]}"'
+ error_msg_uns = f'is not supported for Dynamic DNS service "{service}" on "{address}" with protocol "{config["protocol"]}"'
for field in ['host_name', 'password', 'protocol']:
if field not in config:
- raise ConfigError(f'"{field.replace("_", "-")}" {error_msg}')
+ raise ConfigError(f'"{field.replace("_", "-")}" {error_msg_req}')
if config['protocol'] in zone_necessary and 'zone' not in config:
- raise ConfigError(f'"zone" {error_msg}')
+ raise ConfigError(f'"zone" {error_msg_req}')
- if config['protocol'] not in zone_necessary and 'zone' in config:
- raise ConfigError(f'"{config["protocol"]}" does not support "zone"')
+ if config['protocol'] not in zone_supported and 'zone' in config:
+ raise ConfigError(f'"zone" {error_msg_uns}')
if config['protocol'] not in username_unnecessary and 'username' not in config:
- raise ConfigError(f'"username" {error_msg}')
+ raise ConfigError(f'"username" {error_msg_req}')
if config['protocol'] not in ttl_supported and 'ttl' in config:
- raise ConfigError(f'"{config["protocol"]}" does not support "ttl"')
+ raise ConfigError(f'"ttl" {error_msg_uns}')
if config['ip_version'] == 'both':
if config['protocol'] not in dualstack_supported:
- raise ConfigError(f'"{config["protocol"]}" does not support '
- f'both IPv4 and IPv6 at the same time')
+ raise ConfigError(f'Both IPv4 and IPv6 at the same time {error_msg_uns}')
# dyndns2 protocol in ddclient honors dual stack only for dyn.com (dyndns.org)
if config['protocol'] == 'dyndns2' and 'server' in config and config['server'] not in dyndns_dualstack_servers:
- raise ConfigError(f'"{config["protocol"]}" does not support '
- f'both IPv4 and IPv6 at the same time for "{config["server"]}"')
+ raise ConfigError(f'Both IPv4 and IPv6 at the same time {error_msg_uns} for "{config["server"]}"')
if {'wait_time', 'expiry_time'} <= config.keys() and int(config['expiry_time']) < int(config['wait_time']):
raise ConfigError(f'"expiry-time" must be greater than "wait-time"')
diff --git a/src/conf_mode/interfaces-bridge.py b/src/conf_mode/interfaces-bridge.py
index c82f01e53..31508a3c5 100755
--- a/src/conf_mode/interfaces-bridge.py
+++ b/src/conf_mode/interfaces-bridge.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
#
-# Copyright (C) 2019-2020 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
@@ -28,7 +28,8 @@ from vyos.configverify import verify_vrf
from vyos.ifconfig import BridgeIf
from vyos.configdict import has_address_configured
from vyos.configdict import has_vrf_configured
-
+from vyos.configdep import set_dependents
+from vyos.configdep import call_dependents
from vyos.utils.dict import dict_search
from vyos import ConfigError
@@ -83,6 +84,12 @@ def get_config(config=None):
if 'enable_vlan' in bridge and tmp:
bridge['member']['interface'][interface].update({'has_vlan' : ''})
+ # When using VXLAN member interfaces that are configured for Single
+ # VXLAN Device (SVD) we need to call the VXLAN conf-mode script to re-create
+ # VLAN to VNI mappings if required
+ if interface.startswith('vxlan'):
+ set_dependents('vxlan', conf, interface)
+
# delete empty dictionary keys - no need to run code paths if nothing is there to do
if 'member' in bridge:
if 'interface' in bridge['member'] and len(bridge['member']['interface']) == 0:
@@ -159,6 +166,13 @@ def apply(bridge):
else:
br.update(bridge)
+ for interface in dict_search('member.interface', bridge) or []:
+ if interface.startswith('vxlan'):
+ try:
+ call_dependents()
+ except ConfigError:
+ raise ConfigError('Error in updating VXLAN interface after changing bridge!')
+
return None
if __name__ == '__main__':
diff --git a/src/conf_mode/service_pppoe-server.py b/src/conf_mode/service_pppoe-server.py
index aace267a7..87660c127 100755
--- a/src/conf_mode/service_pppoe-server.py
+++ b/src/conf_mode/service_pppoe-server.py
@@ -48,9 +48,12 @@ def get_config(config=None):
# reload-or-restart does not implemented in accel-ppp
# use this workaround until it will be implemented
# https://phabricator.accel-ppp.org/T3
- if is_node_changed(conf, base + ['client-ip-pool']) or is_node_changed(
- conf, base + ['client-ipv6-pool']):
+ conditions = [is_node_changed(conf, base + ['client-ip-pool']),
+ is_node_changed(conf, base + ['client-ipv6-pool']),
+ is_node_changed(conf, base + ['interface'])]
+ if any(conditions):
pppoe.update({'restart_required': {}})
+
return pppoe
def verify(pppoe):
diff --git a/src/etc/udev/rules.d/99-vyos-systemd.rules b/src/etc/udev/rules.d/99-vyos-systemd.rules
new file mode 100644
index 000000000..54aea668c
--- /dev/null
+++ b/src/etc/udev/rules.d/99-vyos-systemd.rules
@@ -0,0 +1,79 @@
+# The main reason that we store this file is systemd-udevd interfaces excludes
+# /lib/systemd/systemd-sysctl for dynamic interfaces (ppp|ipoe|l2tp etc)
+
+ACTION=="remove", GOTO="systemd_end"
+
+SUBSYSTEM=="tty", KERNEL=="tty[a-zA-Z]*|hvc*|xvc*|hvsi*|ttysclp*|sclp_line*|3270/tty[0-9]*", TAG+="systemd"
+KERNEL=="vport*", TAG+="systemd"
+
+SUBSYSTEM=="ptp", TAG+="systemd"
+
+SUBSYSTEM=="ubi", TAG+="systemd"
+
+SUBSYSTEM=="block", TAG+="systemd"
+
+# We can't make any conclusions about suspended DM devices so let's just import previous SYSTEMD_READY state and skip other rules
+SUBSYSTEM=="block", ENV{DM_SUSPENDED}=="1", IMPORT{db}="SYSTEMD_READY", GOTO="systemd_end"
+SUBSYSTEM=="block", ACTION=="add", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}=="1", ENV{SYSTEMD_READY}="0"
+
+# Ignore encrypted devices with no identified superblock on it, since
+# we are probably still calling mke2fs or mkswap on it.
+SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{ID_PART_TABLE_TYPE}=="", ENV{ID_FS_USAGE}=="", ENV{SYSTEMD_READY}="0"
+
+# Explicitly set SYSTEMD_READY=1 for DM devices that don't have it set yet, so that we always have something to import above
+SUBSYSTEM=="block", ENV{DM_UUID}=="?*", ENV{SYSTEMD_READY}=="", ENV{SYSTEMD_READY}="1"
+
+# add symlink to GPT root disk
+SUBSYSTEM=="block", ENV{ID_PART_GPT_AUTO_ROOT}=="1", ENV{ID_FS_TYPE}!="crypto_LUKS", SYMLINK+="gpt-auto-root"
+SUBSYSTEM=="block", ENV{ID_PART_GPT_AUTO_ROOT}=="1", ENV{ID_FS_TYPE}=="crypto_LUKS", SYMLINK+="gpt-auto-root-luks"
+SUBSYSTEM=="block", ENV{DM_UUID}=="CRYPT-*", ENV{DM_NAME}=="root", SYMLINK+="gpt-auto-root"
+
+# Ignore raid devices that are not yet assembled and started
+SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", TEST!="md/array_state", ENV{SYSTEMD_READY}="0"
+SUBSYSTEM=="block", ENV{DEVTYPE}=="disk", KERNEL=="md*", ATTR{md/array_state}=="|clear|inactive", ENV{SYSTEMD_READY}="0"
+
+# Ignore loop devices that don't have any file attached
+SUBSYSTEM=="block", KERNEL=="loop[0-9]*", ENV{DEVTYPE}=="disk", TEST!="loop/backing_file", ENV{SYSTEMD_READY}="0"
+
+# Ignore nbd devices until the PID file exists (which signals a connected device)
+SUBSYSTEM=="block", KERNEL=="nbd*", ENV{DEVTYPE}=="disk", TEST!="pid", ENV{SYSTEMD_READY}="0"
+
+# We need a hardware independent way to identify network devices. We
+# use the /sys/subsystem/ path for this. Kernel "bus" and "class" names
+# should be treated as one namespace, like udev handles it. This is mostly
+# just an identification string for systemd, so whether the path actually is
+# accessible or not does not matter as long as it is unique and in the
+# filesystem namespace.
+
+SUBSYSTEM=="net", KERNEL!="lo", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/net/devices/$name"
+SUBSYSTEM=="bluetooth", TAG+="systemd", ENV{SYSTEMD_ALIAS}+="/sys/subsystem/bluetooth/devices/%k", \
+ ENV{SYSTEMD_WANTS}+="bluetooth.target", ENV{SYSTEMD_USER_WANTS}+="bluetooth.target"
+
+ENV{ID_SMARTCARD_READER}=="?*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="smartcard.target", ENV{SYSTEMD_USER_WANTS}+="smartcard.target"
+SUBSYSTEM=="sound", KERNEL=="controlC*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sound.target", ENV{SYSTEMD_USER_WANTS}+="sound.target"
+
+SUBSYSTEM=="printer", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target", ENV{SYSTEMD_USER_WANTS}+="printer.target"
+SUBSYSTEM=="usb", KERNEL=="lp*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target", ENV{SYSTEMD_USER_WANTS}+="printer.target"
+SUBSYSTEM=="usb", ENV{DEVTYPE}=="usb_device", ENV{ID_USB_INTERFACES}=="*:0701??:*", TAG+="systemd", ENV{SYSTEMD_WANTS}+="printer.target", ENV{SYSTEMD_USER_WANTS}+="printer.target"
+
+SUBSYSTEM=="udc", ACTION=="add", TAG+="systemd", ENV{SYSTEMD_WANTS}+="usb-gadget.target"
+
+# Apply sysctl variables to network devices (and only to those) as they appear.
+# T5706. Exclude: lo, dummy*, ppp*, ipoe*, l2tp*, pptp*, sslvpn* and sstp*.
+ACTION=="add", SUBSYSTEM=="net", KERNEL!="lo|dummy*|ppp*|ipoe*|l2tp*|pptp*|sslvpn*|sstp*", RUN+="/lib/systemd/systemd-sysctl --prefix=/net/ipv4/conf/$name --prefix=/net/ipv4/neigh/$name --prefix=/net/ipv6/conf/$name --prefix=/net/ipv6/neigh/$name"
+
+# Pull in backlight save/restore for all backlight devices and
+# keyboard backlights
+SUBSYSTEM=="backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight@backlight:$name.service"
+SUBSYSTEM=="leds", KERNEL=="*kbd_backlight", TAG+="systemd", IMPORT{builtin}="path_id", ENV{SYSTEMD_WANTS}+="systemd-backlight@leds:$name.service"
+
+# Pull in rfkill save/restore for all rfkill devices
+SUBSYSTEM=="rfkill", ENV{SYSTEMD_RFKILL}="1"
+SUBSYSTEM=="rfkill", IMPORT{builtin}="path_id"
+SUBSYSTEM=="misc", KERNEL=="rfkill", TAG+="systemd", ENV{SYSTEMD_WANTS}+="systemd-rfkill.socket"
+
+# Asynchronously mount file systems implemented by these modules as soon as they are loaded.
+SUBSYSTEM=="module", KERNEL=="fuse", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-fs-fuse-connections.mount"
+SUBSYSTEM=="module", KERNEL=="configfs", TAG+="systemd", ENV{SYSTEMD_WANTS}+="sys-kernel-config.mount"
+
+LABEL="systemd_end"
diff --git a/src/helpers/strip-private.py b/src/helpers/strip-private.py
index eb584edaf..cb29069cf 100755
--- a/src/helpers/strip-private.py
+++ b/src/helpers/strip-private.py
@@ -1,6 +1,6 @@
#!/usr/bin/python3
-# Copyright 2021-2022 VyOS maintainers and contributors <maintainers@vyos.io>
+# Copyright 2021-2023 VyOS maintainers and contributors <maintainers@vyos.io>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
@@ -21,7 +21,6 @@ import sys
from netaddr import IPNetwork, AddrFormatError
-
parser = argparse.ArgumentParser(description='strip off private information from VyOS config')
strictness = parser.add_mutually_exclusive_group()
@@ -119,6 +118,7 @@ if __name__ == "__main__":
(True, re.compile(r'(shared-secret-key-file|ca-cert-file|cert-file|dh-file|key-file|client) (\S+)'), r'\1 xxxxxx'),
# Strip IPSEC secrets
(True, re.compile(r'pre-shared-secret \S+'), 'pre-shared-secret xxxxxx'),
+ (True, re.compile(r'secret \S+'), 'secret xxxxxx'),
# Strip OSPF md5-key
(True, re.compile(r'md5-key \S+'), 'md5-key xxxxxx'),
# Strip WireGuard private-key
diff --git a/src/migration-scripts/dns-dynamic/1-to-2 b/src/migration-scripts/dns-dynamic/1-to-2
new file mode 100755
index 000000000..8b599b57a
--- /dev/null
+++ b/src/migration-scripts/dns-dynamic/1-to-2
@@ -0,0 +1,70 @@
+#!/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/>.
+
+# T5708:
+# - migrate "service dns dynamic timeout ..."
+# to "service dns dynamic interval ..."
+# - remove "service dns dynamic address <interface> web-options ..." when <interface> != "web"
+# - migrate "service dns dynamic address <interface> service <service> protocol dnsexit"
+# to "service dns dynamic address <interface> service <service> protocol dnsexit2"
+
+import sys
+from vyos.configtree import ConfigTree
+
+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_path = ['service', 'dns', 'dynamic']
+timeout_path = base_path + ['timeout']
+address_path = base_path + ['address']
+
+if not config.exists(base_path):
+ # Nothing to do
+ sys.exit(0)
+
+# Migrate "service dns dynamic timeout ..."
+# to "service dns dynamic interval ..."
+if config.exists(timeout_path):
+ config.rename(timeout_path, 'interval')
+
+# Remove "service dns dynamic address <interface> web-options ..." when <interface> != "web"
+for address in config.list_nodes(address_path):
+ if config.exists(address_path + [address, 'web-options']) and address != 'web':
+ config.delete(address_path + [address, 'web-options'])
+
+# Migrate "service dns dynamic address <interface> service <service> protocol dnsexit"
+# to "service dns dynamic address <interface> service <service> protocol dnsexit2"
+for address in config.list_nodes(address_path):
+ for svc_cfg in config.list_nodes(address_path + [address, 'service']):
+ if config.exists(address_path + [address, 'service', svc_cfg, 'protocol']):
+ protocol = config.return_value(address_path + [address, 'service', svc_cfg, 'protocol'])
+ if protocol == 'dnsexit':
+ config.set(address_path + [address, 'service', svc_cfg, 'protocol'], 'dnsexit2')
+
+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/validators/ddclient-protocol b/src/validators/ddclient-protocol
index bc6826120..8f455e12e 100755
--- a/src/validators/ddclient-protocol
+++ b/src/validators/ddclient-protocol
@@ -14,7 +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/>.
-ddclient -list-protocols | grep -vE 'nsupdate|cloudns' | grep -qw $1
+ddclient -list-protocols | grep -vE 'nsupdate|cloudns|porkbun' | grep -qw $1
if [ $? -gt 0 ]; then
echo "Error: $1 is not a valid protocol, please choose from the supported list of protocols"