summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorIndrajit Raychaudhuri <irc@indrajit.com>2026-04-13 03:11:35 -0500
committerIndrajit Raychaudhuri <irc@indrajit.com>2026-07-24 12:17:23 -0500
commitced95444e5233c4fef5e274220dc665bbe836e69 (patch)
tree61cad47d689c868e9fe69c43e6a807ee793d6a7a /src
parent98f83eb047c994c30cc254ea7a415b1135765d8b (diff)
downloadvyos-1x-ced95444e5233c4fef5e274220dc665bbe836e69.tar.gz
vyos-1x-ced95444e5233c4fef5e274220dc665bbe836e69.zip
ddclient: T6981: Reformat for ruff compliance
Diffstat (limited to 'src')
-rwxr-xr-xsrc/conf_mode/service_dns_dynamic.py178
1 files changed, 136 insertions, 42 deletions
diff --git a/src/conf_mode/service_dns_dynamic.py b/src/conf_mode/service_dns_dynamic.py
index 92b067dcc..b6daba6ff 100755
--- a/src/conf_mode/service_dns_dynamic.py
+++ b/src/conf_mode/service_dns_dynamic.py
@@ -27,36 +27,89 @@ from vyos.utils.process import call
from vyos.utils.network import interface_exists
from vyos import ConfigError
from vyos import airbag
+
airbag.enable()
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', 'digitalocean', 'godaddy', 'hetzner', 'gandi',
- 'nfsn', 'nsupdate']
+zone_necessary = [
+ 'cloudflare',
+ 'digitalocean',
+ 'godaddy',
+ 'hetzner',
+ 'gandi',
+ 'nfsn',
+ 'nsupdate',
+]
zone_supported = zone_necessary + ['dnsexit2', 'porkbun', 'zoneedit1']
# Protocols that do not require username
-username_unnecessary = ['1984', 'cloudflare', 'cloudns', 'ddns.fm', 'digitalocean',
- 'dnsexit2', 'duckdns', 'freemyip', 'gandi', 'he.net',
- 'hetzner', 'keysystems', 'njalla', 'nsupdate', 'regfishde']
+username_unnecessary = [
+ '1984',
+ 'cloudflare',
+ 'cloudns',
+ 'ddns.fm',
+ 'digitalocean',
+ 'dnsexit2',
+ 'duckdns',
+ 'freemyip',
+ 'gandi',
+ 'he.net',
+ 'hetzner',
+ 'keysystems',
+ 'njalla',
+ 'nsupdate',
+ 'regfishde',
+]
# Protocols that support TTL
-ttl_supported = ['cloudflare', 'dnsexit2', 'gandi', 'hetzner', 'godaddy', 'nfsn',
- 'nsupdate', 'porkbun']
+ttl_supported = [
+ 'cloudflare',
+ 'dnsexit2',
+ 'gandi',
+ 'hetzner',
+ 'godaddy',
+ 'nfsn',
+ 'nsupdate',
+ 'porkbun',
+]
# Protocols that support both IPv4 and IPv6
-dualstack_supported = ['cloudflare', 'ddns.fm', 'digitalocean', 'dnsexit2',
- 'domeneshop', 'duckdns', 'dyndns2', 'easydns', 'freedns',
- 'gandi', 'godaddy', 'he.net', 'hetzner', 'infomaniak',
- 'inwx', 'mythicdyn', 'njalla', 'noip', 'nsupdate',
- 'porkbun', 'regfishde']
+dualstack_supported = [
+ 'cloudflare',
+ 'ddns.fm',
+ 'digitalocean',
+ 'dnsexit2',
+ 'domeneshop',
+ 'duckdns',
+ 'dyndns2',
+ 'easydns',
+ 'freedns',
+ 'gandi',
+ 'godaddy',
+ 'he.net',
+ 'hetzner',
+ 'infomaniak',
+ 'inwx',
+ 'mythicdyn',
+ 'njalla',
+ 'noip',
+ 'nsupdate',
+ 'porkbun',
+ 'regfishde',
+]
# dyndns2 protocol in ddclient honors dual stack for selective servers
# because of the way it is implemented in ddclient
-dyndns_dualstack_servers = ['members.dyndns.org', 'dynv6.com', 'app.luadns.com',
- 'update.dedyn.io']
+dyndns_dualstack_servers = [
+ 'app.luadns.com',
+ 'dynv6.com',
+ 'members.dyndns.org',
+ 'update.dedyn.io',
+]
+
def get_config(config=None):
if config:
@@ -68,14 +121,18 @@ def get_config(config=None):
if not conf.exists(base):
return None
- dyndns = conf.get_config_dict(base, key_mangling=('-', '_'),
- no_tag_node_value_mangle=True,
- get_first_key=True,
- with_recursive_defaults=True)
+ dyndns = conf.get_config_dict(
+ base,
+ key_mangling=('-', '_'),
+ no_tag_node_value_mangle=True,
+ get_first_key=True,
+ with_recursive_defaults=True,
+ )
dyndns['config_file'] = config_file
return dyndns
+
def verify(dyndns):
# bail out early - looks like removal from running config
if not dyndns or 'name' not in dyndns:
@@ -91,11 +148,15 @@ def verify(dyndns):
raise ConfigError(f'"{field.replace("_", "-")}" {error_msg_req}')
if not any(x in config['address'] for x in ['interface', 'web']):
- raise ConfigError(f'Either "interface" or "web" {error_msg_req} '
- f'with protocol "{config["protocol"]}"')
+ raise ConfigError(
+ f'Either "interface" or "web" {error_msg_req} '
+ f'with protocol "{config["protocol"]}"'
+ )
if all(x in config['address'] for x in ['interface', 'web']):
- raise ConfigError(f'Both "interface" and "web" at the same time {error_msg_uns} '
- f'with protocol "{config["protocol"]}"')
+ raise ConfigError(
+ f'Both "interface" and "web" at the same time {error_msg_uns} '
+ f'with protocol "{config["protocol"]}"'
+ )
# If dyndns address is an interface, ensure that the interface exists
# and warn if a non-active dynamic interface is used
@@ -104,16 +165,22 @@ def verify(dyndns):
# exclude check interface for dynamic interfaces
if tmp.match(config['address']['interface']):
if not interface_exists(config['address']['interface']):
- Warning(f'Interface "{config["address"]["interface"]}" does not exist yet and '
- f'cannot be used for Dynamic DNS service "{service}" until it is up!')
+ Warning(
+ f'Interface "{config["address"]["interface"]}" does not exist yet and '
+ f'cannot be used for Dynamic DNS service "{service}" until it is up!'
+ )
else:
verify_interface_exists(dyndns, config['address']['interface'])
if 'web' in config['address']:
# If 'skip' is specified, 'url' is required as well
- if 'skip' in config['address']['web'] and 'url' not in config['address']['web']:
- raise ConfigError(f'"url" along with "skip" {error_msg_req} '
- f'with protocol "{config["protocol"]}"')
+ if (
+ 'skip' in config['address']['web']
+ and 'url' not in config['address']['web']
+ ):
+ raise ConfigError(
+ f'"url" along with "skip" {error_msg_req} with protocol "{config["protocol"]}"'
+ )
# RFC2136 uses 'key' instead of 'password'
if config['protocol'] != 'nsupdate' and 'password' not in config:
@@ -122,38 +189,63 @@ def verify(dyndns):
# Other RFC2136 specific configuration validation
if config['protocol'] == 'nsupdate':
if 'password' in config:
- raise ConfigError(f'"password" {error_msg_uns} with protocol "{config["protocol"]}"')
+ raise ConfigError(
+ f'"password" {error_msg_uns} with protocol "{config["protocol"]}"'
+ )
for field in ['server', 'key']:
if field not in config:
- raise ConfigError(f'"{field}" {error_msg_req} with protocol "{config["protocol"]}"')
+ raise ConfigError(
+ f'"{field}" {error_msg_req} with protocol "{config["protocol"]}"'
+ )
if config['protocol'] in zone_necessary and 'zone' not in config:
- raise ConfigError(f'"zone" {error_msg_req} with protocol "{config["protocol"]}"')
+ raise ConfigError(
+ f'"zone" {error_msg_req} with protocol "{config["protocol"]}"'
+ )
if config['protocol'] not in zone_supported and 'zone' in config:
- raise ConfigError(f'"zone" {error_msg_uns} with protocol "{config["protocol"]}"')
+ raise ConfigError(
+ f'"zone" {error_msg_uns} with protocol "{config["protocol"]}"'
+ )
if config['protocol'] not in username_unnecessary and 'username' not in config:
- raise ConfigError(f'"username" {error_msg_req} with protocol "{config["protocol"]}"')
+ raise ConfigError(
+ f'"username" {error_msg_req} with protocol "{config["protocol"]}"'
+ )
if config['protocol'] not in ttl_supported and 'ttl' in config:
- raise ConfigError(f'"ttl" {error_msg_uns} with protocol "{config["protocol"]}"')
+ raise ConfigError(
+ f'"ttl" {error_msg_uns} with protocol "{config["protocol"]}"'
+ )
if config['ip_version'] == 'both':
if config['protocol'] not in dualstack_supported:
- raise ConfigError(f'Both IPv4 and IPv6 at the same time {error_msg_uns} '
- f'with protocol "{config["protocol"]}"')
+ raise ConfigError(
+ f'Both IPv4 and IPv6 at the same time {error_msg_uns} '
+ f'with protocol "{config["protocol"]}"'
+ )
# 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'Both IPv4 and IPv6 at the same time {error_msg_uns} '
- f'for "{config["server"]}" with protocol "{config["protocol"]}"')
-
- 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" for '
- f'Dynamic DNS service "{service}"')
+ if (
+ config['protocol'] == 'dyndns2'
+ and 'server' in config
+ and config['server'] not in dyndns_dualstack_servers
+ ):
+ raise ConfigError(
+ f'Both IPv4 and IPv6 at the same time {error_msg_uns} '
+ f'for "{config["server"]}" with protocol "{config["protocol"]}"'
+ )
+
+ 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" for '
+ f'Dynamic DNS service "{service}"'
+ )
return None
+
def generate(dyndns):
# bail out early - looks like removal from running config
if not dyndns or 'name' not in dyndns:
@@ -184,6 +276,7 @@ def generate(dyndns):
render(systemd_override, 'dns-dynamic/override.conf.j2', dyndns)
return None
+
def apply(dyndns):
systemd_service = 'ddclient.service'
# Reload systemd manager configuration
@@ -199,6 +292,7 @@ def apply(dyndns):
return None
+
if __name__ == '__main__':
try:
c = get_config()