diff --git a/dns/ddclient/Makefile b/dns/ddclient/Makefile
index 091f84cee..d2d3a3d02 100644
--- a/dns/ddclient/Makefile
+++ b/dns/ddclient/Makefile
@@ -1,6 +1,6 @@
PLUGIN_NAME= ddclient
-PLUGIN_VERSION= 1.13
-PLUGIN_REVISION= 2
+PLUGIN_VERSION= 1.14
+#PLUGIN_REVISION= 1
PLUGIN_DEPENDS= ddclient-devel
PLUGIN_COMMENT= Dynamic DNS client
PLUGIN_MAINTAINER= ad@opnsense.org
diff --git a/dns/ddclient/src/opnsense/mvc/app/controllers/OPNsense/DynDNS/forms/dialogAccount.xml b/dns/ddclient/src/opnsense/mvc/app/controllers/OPNsense/DynDNS/forms/dialogAccount.xml
index c0aac07e9..7afd4b9c4 100644
--- a/dns/ddclient/src/opnsense/mvc/app/controllers/OPNsense/DynDNS/forms/dialogAccount.xml
+++ b/dns/ddclient/src/opnsense/mvc/app/controllers/OPNsense/DynDNS/forms/dialogAccount.xml
@@ -27,7 +27,10 @@
account.server
text
- DynDNS Server
+ DynDNS Server hostname or uri to use (depending on the protocol).
+ When a URI is provided, the tag __MYIP__ will be replaced with the current detected address for this service
+ and __HOSTNAME__ will contain the (comma separated) list of hostnames provided.
+
diff --git a/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.php b/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.php
index 00726445e..969d52691 100644
--- a/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.php
+++ b/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.php
@@ -1,7 +1,7 @@
getFlatNodes() as $key => $node) {
+ $tagName = $node->getInternalXMLTagName();
+ $parentNode = $node->getParentNode();
+ if ($validateFullModel || $node->isFieldChanged()) {
+ if ($parentNode->getInternalXMLTagName() === 'account' && in_array($tagName, ['protocol', 'server'])) {
+ $parentKey = $parentNode->__reference;
+ $validate_servers[$parentKey] = $parentNode;
+ }
+ }
+ }
+ foreach ($validate_servers as $key => $node) {
+ if ((string)$node->service != 'custom') {
+ continue;
+ }
+ $srv = (string)$node->server;
+ if ((string)$node->protocol == 'post') {
+ if (empty($srv) || filter_var($srv, FILTER_VALIDATE_URL) === false) {
+ $messages->appendMessage(
+ new Message(
+ gettext("A valid URI is required."),
+ $key . ".server"
+ )
+ );
+ }
+ } else {
+ if (empty($srv) || filter_var($srv, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) === false) {
+ $messages->appendMessage(
+ new Message(
+ gettext("A valid domain is required."),
+ $key . ".server"
+ )
+ );
+ }
+ }
+ }
+ return $messages;
+ }
}
diff --git a/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.xml b/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.xml
index a04ca3794..1bc908dec 100644
--- a/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.xml
+++ b/dns/ddclient/src/opnsense/mvc/app/models/OPNsense/DynDNS/DynDNS.xml
@@ -93,11 +93,11 @@
DynDns1
DynDns2
+ custom POST
-
+
N
- N
N
@@ -105,7 +105,7 @@
The username contains invalid characters.
- Y
+ N
/^[^\n]*$/
diff --git a/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/__init__.py b/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/__init__.py
index b74f08c3c..e143cc28b 100755
--- a/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/__init__.py
+++ b/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/__init__.py
@@ -120,6 +120,7 @@ class BaseAccount:
interface = self.settings['interface'] if self.settings.get('interface' ,'').strip() != '' else None
)
+
if self._current_address != '' and (
self._state.get('ip') is None or
self._current_address != self._state.get('ip') or
diff --git a/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/azure.py b/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/azure.py
index 11fd3c637..64a635ab0 100755
--- a/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/azure.py
+++ b/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/azure.py
@@ -84,6 +84,7 @@ class Azure(BaseAccount):
def known_services():
return Azure._services
+ @staticmethod
def match(account):
return account.get('service') in Azure._services
diff --git a/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/cloudflare.py b/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/cloudflare.py
index 388c2b147..1fd15ada8 100755
--- a/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/cloudflare.py
+++ b/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/cloudflare.py
@@ -44,6 +44,7 @@ class Cloudflare(BaseAccount):
def known_services():
return Cloudflare._services.keys()
+ @staticmethod
def match(account):
return account.get('service') in Cloudflare._services
diff --git a/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/dyndns2.py b/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/dyndns2.py
index e53b14c83..aef23eb43 100755
--- a/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/dyndns2.py
+++ b/dns/ddclient/src/opnsense/scripts/ddclient/lib/account/dyndns2.py
@@ -55,35 +55,46 @@ class DynDNS2(BaseAccount):
def known_services():
return list(DynDNS2._services.keys()) + ['custom']
+ @staticmethod
def match(account):
- if account.get('service') in DynDNS2._services or (
- account.get('server') is not None and account.get('protocol') in ['dyndns2', 'dyndns1']
- ):
+ if account.get('service') in DynDNS2.known_services():
return True
else:
return False
def execute(self):
if super().execute():
- proto = 'https' if self.settings.get('force_ssl', False) else 'http'
- if self.settings.get('service') in self._services:
- url = "%s://%s/nic/update" % (proto, self._services[self.settings.get('service')])
+ protocol = self.settings.get('protocol', None)
+ if protocol == 'post':
+ url = self.settings.get('server')
+ url = url.replace('__MYIP__', self.current_address)
+ url = url.replace('__HOSTNAME__', self.settings.get('hostnames'))
+ req = requests.post(
+ url=url,
+ headers={'User-Agent': 'OPNsense-dyndns'},
+ auth=HTTPBasicAuth(self.settings.get('username'), self.settings.get('password'))
+ )
else:
- url = "%s://%s/nic/update" % (proto, self.settings.get('server'))
+ uri_proto = 'https' if self.settings.get('force_ssl', False) else 'http'
+ if self.settings.get('service') in self._services:
+ url = "%s://%s/nic/update" % (uri_proto, self._services[self.settings.get('service')])
+ else:
+ url = "%s://%s/nic/update" % (uri_proto, self.settings.get('server'))
- req_opts = {
- 'url': url,
- 'params': {
- 'hostname': self.settings.get('hostnames'),
- 'myip': self.current_address,
- 'wildcard': 'ON' if self.settings.get('wildcard', False) else 'NOCHG'
- },
- 'auth': HTTPBasicAuth(self.settings.get('username'), self.settings.get('password')),
- 'headers': {
- 'User-Agent': 'OPNsense-dyndns'
+ req_opts = {
+ 'url': url,
+ 'params': {
+ 'hostname': self.settings.get('hostnames'),
+ 'myip': self.current_address,
+ 'wildcard': 'ON' if self.settings.get('wildcard', False) else 'NOCHG'
+ },
+ 'auth': HTTPBasicAuth(self.settings.get('username'), self.settings.get('password')),
+ 'headers': {
+ 'User-Agent': 'OPNsense-dyndns'
+ }
}
- }
- req = requests.get(**req_opts)
+ req = requests.get(**req_opts)
+
if req.status_code == 200:
if self.is_verbose:
syslog.syslog(