Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 3 additions & 12 deletions data/templates/dns-dynamic/ddclient.conf.j2
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ if{{ ipv }}={{ address }}, \
{{ host }}
{% endmacro %}
### Autogenerated by service_dns_dynamic.py ###
ssl=yes
{# ddclient default (web=dyndns) doesn't support ssl and results in process lockup #}
web=googledomains
{# ddclient default (use=ip) results in confusing warning message in log #}
use=no

{% if name is vyos_defined %}
{% for service, config in name.items() %}
Expand All @@ -34,21 +29,17 @@ use=no
# {{ config.description }}
{% endif %}
{% for host in config.host_name if config.host_name is vyos_defined %}
{# ip_suffixes can be either of ['v4'], ['v6'], ['v4', 'v6'] for all protocols except 'nsupdate'
ip_suffixes must be [''] for nsupdate since it doesn't support usevX/wantipvX yet #}
{# ip_suffixes can be either of ['v4'], ['v6'], ['v4', 'v6'] for all protocols #}
{% set ip_suffixes = ['v4', 'v6'] if config.ip_version == 'both'
else ([config.ip_version[2:]] if config.protocol != 'nsupdate'
else ['']) %}
{% set password = config.key if config.protocol == 'nsupdate'
else config.password %}
else [config.ip_version[2:]] %}
{% set address = 'web' if config.address.web is vyos_defined
else config.address.interface %}
{% set web_options = config.address.web | default({}) %}

# Web service dynamic DNS configuration for {{ service }}: [{{ config.protocol }}, {{ host }}]
{{ render_config(host, address, web_options, ip_suffixes,
protocol=config.protocol, server=config.server, zone=config.zone,
login=config.username, password=password, ttl=config.ttl,
login=config.username, password=config.password, ttl=config.ttl,
min_interval=config.wait_time, max_interval=config.expiry_time) }}
{% endfor %}
{% endfor %}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
<!-- include start from include/version/dns-dynamic-version.xml.i -->
<syntaxVersion component='dns-dynamic' version='4'></syntaxVersion>
<syntaxVersion component='dns-dynamic' version='5'></syntaxVersion>
<!-- include end -->
2 changes: 1 addition & 1 deletion interface-definitions/service_dns_dynamic.xml.in
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
</leafNode>
<leafNode name="zone">
<properties>
<help>DNS zone to be updated</help>
<help>DNS zone or root domain to be updated</help>
<valueHelp>
<format>txt</format>
<description>Name of DNS zone</description>
Expand Down
57 changes: 37 additions & 20 deletions smoketest/scripts/cli/test_service_dns_dynamic.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
ttl = '300'
interface = 'eth0'


class TestServiceDDNS(VyOSUnitTestSHIM.TestCase):
@classmethod
def setUpClass(cls):
Expand All @@ -64,9 +65,11 @@ def tearDown(self):

# IPv4 standard DDNS service configuration
def test_01_dyndns_service_standard(self):
services = {'cloudflare': {'protocol': 'cloudflare'},
'freedns': {'protocol': 'freedns', 'username': username},
'zoneedit': {'protocol': 'zoneedit1', 'username': username}}
services = {
'cloudflare': {'protocol': 'cloudflare'},
'freedns': {'protocol': 'freedns', 'username': username},
'zoneedit': {'protocol': 'zoneedit1', 'username': username},
}

for svc, details in services.items():
self.cli_set(name_path + [svc, 'address', 'interface', interface])
Expand Down Expand Up @@ -102,7 +105,7 @@ def test_01_dyndns_service_standard(self):
ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
self.assertIn(f'usev4=ifv4', ddclient_conf)
self.assertIn(f'ifv4={interface}', ddclient_conf)
self.assertIn(f'password=\'{password}\'', ddclient_conf)
self.assertIn(f"password='{password}'", ddclient_conf)

# Check default interval of 300 seconds
systemd_override = read_file(DDCLIENT_SYSTEMD_UNIT)
Expand Down Expand Up @@ -152,7 +155,7 @@ def test_02_dyndns_service_ipv6(self):
self.assertIn(f'protocol={proto}', ddclient_conf)
self.assertIn(f'server={server}', ddclient_conf)
self.assertIn(f'login={username}', ddclient_conf)
self.assertIn(f'password=\'{password}\'', ddclient_conf)
self.assertIn(f"password='{password}'", ddclient_conf)
self.assertIn(f'min-interval={wait_time}', ddclient_conf)
self.assertIn(f'max-interval={expiry_time_good}', ddclient_conf)

Expand All @@ -162,9 +165,11 @@ def test_02_dyndns_service_ipv6(self):

# IPv4+IPv6 dual DDNS service configuration
def test_03_dyndns_service_dual_stack(self):
services = {'cloudflare': {'protocol': 'cloudflare', 'zone': zone},
'freedns': {'protocol': 'freedns', 'username': username},
'google': {'protocol': 'googledomains', 'username': username}}
services = {
'cloudflare': {'protocol': 'cloudflare', 'zone': zone},
'freedns': {'protocol': 'freedns', 'username': username},
'changeip': {'protocol': 'changeip', 'username': username},
}
ip_version = 'both'

for name, details in services.items():
Expand All @@ -174,7 +179,7 @@ def test_03_dyndns_service_dual_stack(self):
for opt, value in details.items():
self.cli_set(name_path + [name, opt, value])

# Dual stack is supported by 'cloudflare' and 'freedns' but not 'googledomains'
# Dual stack is supported by 'cloudflare' and 'freedns' but not 'changeip'
# exception is raised for unsupported ones
self.cli_set(name_path + [name, 'ip-version', ip_version])
if details['protocol'] not in ['cloudflare', 'freedns']:
Expand All @@ -189,13 +194,15 @@ def test_03_dyndns_service_dual_stack(self):
ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
if details['protocol'] not in ['cloudflare', 'freedns']:
self.assertIn(f'usev4=ifv4', ddclient_conf)
self.assertNotIn(f'usev6=ifv6', ddclient_conf)
self.assertIn(f'ifv4={interface}', ddclient_conf)
self.assertNotIn(f'ifv6={interface}', ddclient_conf)
else:
self.assertIn(f'usev4=ifv4', ddclient_conf)
self.assertIn(f'usev6=ifv6', ddclient_conf)
self.assertIn(f'ifv4={interface}', ddclient_conf)
self.assertIn(f'ifv6={interface}', ddclient_conf)
self.assertIn(f'password=\'{password}\'', ddclient_conf)
self.assertIn(f"password='{password}'", ddclient_conf)

for opt in details.keys():
if opt == 'username':
Expand All @@ -205,6 +212,9 @@ def test_03_dyndns_service_dual_stack(self):
tmp = details[opt]
self.assertIn(f'{opt}={tmp}', ddclient_conf)

# cleanup for next iteration
self.cli_delete(name_path + [name])

def test_04_dyndns_rfc2136(self):
# Check if DDNS service can be configured and runs
svc_path = name_path + ['vyos']
Expand All @@ -220,18 +230,21 @@ def test_04_dyndns_rfc2136(self):
self.cli_set(svc_path + ['key', key_file.name])
self.cli_set(svc_path + ['ttl', ttl])
self.cli_set(svc_path + ['host-name', hostname])
self.cli_set(svc_path + ['ip-version', 'both'])

# commit changes
self.cli_commit()

# Check some generating config parameters
ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
self.assertIn(f'use=if', ddclient_conf)
self.assertIn(f'if={interface}', ddclient_conf)
self.assertIn(f'usev4=ifv4', ddclient_conf)
self.assertIn(f'usev6=ifv6', ddclient_conf)
self.assertIn(f'ifv4={interface}', ddclient_conf)
self.assertIn(f'ifv6={interface}', ddclient_conf)
self.assertIn(f'protocol={proto}', ddclient_conf)
self.assertIn(f'server={server}', ddclient_conf)
self.assertIn(f'zone={zone}', ddclient_conf)
self.assertIn(f'password=\'{key_file.name}\'', ddclient_conf)
self.assertIn(f"password='{key_file.name}'", ddclient_conf)
self.assertIn(f'ttl={ttl}', ddclient_conf)

def test_05_dyndns_hostname(self):
Expand All @@ -256,7 +269,7 @@ def test_05_dyndns_hostname(self):
self.assertIn(f'protocol={proto}', ddclient_conf)
self.assertIn(f'server={server}', ddclient_conf)
self.assertIn(f'login={username}', ddclient_conf)
self.assertIn(f'password=\'{password}\'', ddclient_conf)
self.assertIn(f"password='{password}'", ddclient_conf)
self.assertIn(f'{name}', ddclient_conf)

def test_06_dyndns_web_options(self):
Expand Down Expand Up @@ -294,10 +307,10 @@ def test_06_dyndns_web_options(self):
ddclient_conf = cmd(f'sudo cat {DDCLIENT_CONF}')
self.assertIn(f'usev4=webv4', ddclient_conf)
self.assertIn(f'webv4={web_url}', ddclient_conf)
self.assertIn(f'webv4-skip=\'{web_skip}\'', ddclient_conf)
self.assertIn(f"webv4-skip='{web_skip}'", ddclient_conf)
self.assertIn(f'protocol={proto}', ddclient_conf)
self.assertIn(f'zone={zone}', ddclient_conf)
self.assertIn(f'password=\'{password}\'', ddclient_conf)
self.assertIn(f"password='{password}'", ddclient_conf)
self.assertIn(f'{hostname}', ddclient_conf)

def test_07_dyndns_dynamic_interface(self):
Expand Down Expand Up @@ -326,7 +339,7 @@ def test_07_dyndns_dynamic_interface(self):
self.assertIn(f'protocol={proto}', ddclient_conf)
self.assertIn(f'server={server}', ddclient_conf)
self.assertIn(f'login={username}', ddclient_conf)
self.assertIn(f'password=\'{password}\'', ddclient_conf)
self.assertIn(f"password='{password}'", ddclient_conf)
self.assertIn(f'{hostname}', ddclient_conf)

def test_08_dyndns_vrf(self):
Expand All @@ -350,9 +363,12 @@ def test_08_dyndns_vrf(self):

# Check for process in VRF
systemd_override = read_file(DDCLIENT_SYSTEMD_UNIT)
self.assertIn(f'ExecStart=ip vrf exec {vrf_name} /usr/bin/ddclient ' \
f'--file {DDCLIENT_CONF} --cache {DDCLIENT_CONF.replace("conf", "cache")} ' \
f'--foreground --daemon {default_interval}', systemd_override)
self.assertIn(
f'ExecStart=ip vrf exec {vrf_name} /usr/bin/ddclient '
f'--file {DDCLIENT_CONF} --cache {DDCLIENT_CONF.replace("conf", "cache")} '
f'--foreground --daemon {default_interval}',
systemd_override,
)

# Check for process in VRF
proc = cmd(f'ip vrf pids {vrf_name}')
Expand All @@ -361,5 +377,6 @@ def test_08_dyndns_vrf(self):
# Cleanup VRF
self.cli_delete(['vrf', 'name', vrf_name])


if __name__ == '__main__':
unittest.main(verbosity=2, failfast=VyOSUnitTestSHIM.TestCase.debug_on())
2 changes: 1 addition & 1 deletion src/completion/list_ddclient_protocols.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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 'cloudns|porkbun')
echo -n $(ddclient --list-protocols | grep -vE 'cloudns|directnic|emailonly')
Loading
Loading