usr/local/bin/backupctrl
#usr/local/bin/clamavctrl
usr/local/bin/collectdctrl
+usr/local/bin/ddnsctrl
usr/local/bin/dhcpctrl
usr/local/bin/dnsmasqctrl
usr/local/bin/extrahdctrl
--- /dev/null
+../../../common/ddns
\ No newline at end of file
etc/rc.d/init.d/networking/red.up/99-geoip-database
etc/rc.d/rcsysinit.d/S90network-trigger
srv/web/ipfire/cgi-bin/country.cgi
+srv/web/ipfire/cgi-bin/ddns.cgi
srv/web/ipfire/cgi-bin/firewall.cgi
srv/web/ipfire/cgi-bin/fwhosts.cgi
srv/web/ipfire/cgi-bin/geoip-block.cgi
usr/lib/firewall/firewall-lib.pl
usr/lib/firewall/rules.pl
usr/local/bin/backupiso
+usr/local/bin/ddnsctrl
usr/local/bin/xt_geoip_build
usr/local/bin/xt_geoip_update
var/ipfire/general-functions.pl
fcrontab -z &>/dev/null
+# Generate ddns configuration file
+sudo -u nobody /srv/web/ipfire/cgi-bin/ddns.cgi
# Update Language cache
perl -e "require '/var/ipfire/lang.pl'; &Lang::BuildCacheLang"
# Config file to store the configured ddns providers.
my $datafile = "${General::swroot}/ddns/config";
-# Dynamic ddns programm call.
-my @ddnsprog = ("/usr/bin/ddns", "--config",
- "/var/ipfire/ddns/ddns.conf",
- "update-all");
+# Call the ddnsctrl helper binary to perform the update.
+my @ddnsprog = ("/usr/local/bin/ddnsctrl", "update-all");
my %settings=();
my $errormessage = '';
@$(PREBUILD)
@rm -rf $(DIR_APP) && cd $(DIR_SRC) && tar axf $(DIR_DL)/$(DL_FILE)
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/ddns/001-ddns-007-perform-lazy-database-init.patch
+ cd $(DIR_APP) && patch -Np1 < $(DIR_SRC)/src/patches/ddns/002-ddns-007-also-open-database-for-search-operations.patch
+
cd $(DIR_APP) && [ -x "configure" ] || sh ./autogen.sh
cd $(DIR_APP) && ./configure \
--prefix=/usr \
redctrl syslogdctrl extrahdctrl sambactrl upnpctrl tripwirectrl \
smartctrl clamavctrl addonctrl pakfire mpfirectrl wlanapctrl \
setaliases urlfilterctrl updxlratorctrl fireinfoctrl rebuildroutes \
- getconntracktable wirelessclient dnsmasqctrl torctrl
+ getconntracktable wirelessclient dnsmasqctrl torctrl ddnsctrl
SUID_UPDX = updxsetperms
OBJS = $(patsubst %,%.o,$(PROGS) $(SUID_PROGS))
--- /dev/null
+/* This file is part of the IPFire Firewall.
+*
+* This program is distributed under the terms of the GNU General Public
+* Licence. See the file COPYING for details.
+*
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "setuid.h"
+
+const char *conffile = "/var/ipfire/ddns/ddns.conf";
+
+int main(int argc, char *argv[]) {
+ char cmd[STRING_SIZE];
+
+ if (!(initsetuid()))
+ exit(1);
+
+ if (argc < 2) {
+ fprintf(stderr, "\nNo argument given.\n\nddnsctrl (update-all)\n\n");
+ exit(1);
+ }
+
+ if (strcmp(argv[1], "update-all") == 0) {
+ snprintf(cmd, sizeof(cmd), "/usr/bin/ddns --config %s update-all >/dev/null 2>&1", conffile);
+ safe_system(cmd);
+ } else {
+ fprintf(stderr, "\nBad argument given.\n\nddnsctrl (update-all)\n\n");
+ exit(1);
+ }
+
+ return 0;
+}
--- /dev/null
+commit 63e16feedea3639ef1f21fecbff9ed2ae256728b
+Author: Michael Tremer <michael.tremer@ipfire.org>
+Date: Sat Apr 25 13:18:07 2015 +0200
+
+ Perform lazy initialization of the database
+
+ The database will only be initialized when it is actually
+ needed. That makes starting up ddns a bit faster and allows
+ us to execute it as non-root for simple commands like
+ "list-providers".
+
+ If the database path is not writable at all, the database
+ feature is disable and an error message is logged. This
+ will hopefully help us to perform the DNS update even when
+ there is a local misconfiguration.
+
+diff --git a/src/ddns/database.py b/src/ddns/database.py
+index 5d4ffc9..42c3433 100644
+--- a/src/ddns/database.py
++++ b/src/ddns/database.py
+@@ -20,7 +20,7 @@
+ ###############################################################################
+
+ import datetime
+-import os.path
++import os
+ import sqlite3
+
+ # Initialize the logger.
+@@ -31,9 +31,11 @@ logger.propagate = 1
+ class DDNSDatabase(object):
+ def __init__(self, core, path):
+ self.core = core
++ self.path = path
+
+- # Open the database file
+- self._db = self._open_database(path)
++ # We won't open the connection to the database directly
++ # so that we do not do it unnecessarily.
++ self._db = None
+
+ def __del__(self):
+ self._close_database()
+@@ -46,7 +48,7 @@ class DDNSDatabase(object):
+ conn = sqlite3.connect(path, detect_types=sqlite3.PARSE_DECLTYPES|sqlite3.PARSE_COLNAMES)
+ conn.isolation_level = None
+
+- if not exists:
++ if not exists and self.is_writable():
+ logger.debug("Initialising database layout")
+ c = conn.cursor()
+ c.executescript("""
+@@ -68,12 +70,25 @@ class DDNSDatabase(object):
+
+ return conn
+
++ def is_writable(self):
++ # Check if the database file exists and is writable.
++ ret = os.access(self.path, os.W_OK)
++ if ret:
++ return True
++
++ # If not, we check if we are able to write to the directory.
++ # In that case the database file will be created in _open_database().
++ return os.access(os.path.dirname(self.path), os.W_OK)
++
+ def _close_database(self):
+ if self._db:
+ self._db_close()
+ self._db = None
+
+ def _execute(self, query, *parameters):
++ if self._db is None:
++ self._db = self._open_database(self.path)
++
+ c = self._db.cursor()
+ try:
+ c.execute(query, parameters)
+@@ -81,6 +96,10 @@ class DDNSDatabase(object):
+ c.close()
+
+ def add_update(self, hostname, status, message=None):
++ if not self.is_writable():
++ logger.warning("Could not log any updates because the database is not writable")
++ return
++
+ self._execute("INSERT INTO updates(hostname, status, message, timestamp) \
+ VALUES(?, ?, ?, ?)", hostname, status, message, datetime.datetime.utcnow())
+
--- /dev/null
+commit f62fa5baffe2d225604460ecd03b8159b987df8f
+Author: Michael Tremer <michael.tremer@ipfire.org>
+Date: Sun Apr 26 20:15:33 2015 +0200
+
+ database: Open database for the search operations, too
+
+diff --git a/src/ddns/database.py b/src/ddns/database.py
+index 42c3433..70a7363 100644
+--- a/src/ddns/database.py
++++ b/src/ddns/database.py
+@@ -122,6 +122,9 @@ class DDNSDatabase(object):
+ """
+ Returns the timestamp of the last update (with the given status code).
+ """
++ if self._db is None:
++ self._db = self._open_database(self.path)
++
+ c = self._db.cursor()
+
+ try:
+@@ -141,6 +144,9 @@ class DDNSDatabase(object):
+ """
+ Returns the update status of the last update.
+ """
++ if self._db is None:
++ self._db = self._open_database(self.path)
++
+ c = self._db.cursor()
+
+ try:
+@@ -156,6 +162,9 @@ class DDNSDatabase(object):
+ """
+ Returns the reason string for the last failed update (if any).
+ """
++ if self._db is None:
++ self._db = self._open_database(self.path)
++
+ c = self._db.cursor()
+
+ try:
+++ /dev/null
-commit 78046ffe2187d91c61d6c2f910249b8a5be71b08
-Author: Stefan Schantl <stefan.schantl@ipfire.org>
-Date: Wed Oct 22 21:39:09 2014 +0200
-
- Add changeip.com as new provider.
-
- Fixes #10639.
-
-diff --git a/README b/README
-index 5944102..6a06f4b 100644
---- a/README
-+++ b/README
-@@ -49,6 +49,7 @@ INSTALLATION:
-
- SUPPORTED PROVIDERS:
- all-inkl.com
-+ changeip.com
- dhs.org
- dns.lightningwirelabs.com
- dnspark.com
-diff --git a/ddns.conf.sample b/ddns.conf.sample
-index d3ac53f..0048a46 100644
---- a/ddns.conf.sample
-+++ b/ddns.conf.sample
-@@ -30,6 +30,11 @@
- # secret = XYZ
- # ttl = 60
-
-+# [test.changeip.com]
-+# provider = changeip.com
-+# username = user
-+# password = pass
-+
- # [test.dhs.org]
- # provider = dhs.org
- # username = user
-diff --git a/src/ddns/providers.py b/src/ddns/providers.py
-index 1e88995..587d5ff 100644
---- a/src/ddns/providers.py
-+++ b/src/ddns/providers.py
-@@ -539,6 +539,44 @@ class DDNSProviderBindNsupdate(DDNSProvider):
- return "\n".join(scriptlet)
-
-
-+class DDNSProviderChangeIP(DDNSProvider):
-+ handle = "changeip.com"
-+ name = "ChangeIP.com"
-+ website = "https://changeip.com"
-+ protocols = ("ipv4",)
-+
-+ # Detailed information about the update api can be found here.
-+ # http://www.changeip.com/accounts/knowledgebase.php?action=displayarticle&id=34
-+
-+ url = "https://nic.changeip.com/nic/update"
-+ can_remove_records = False
-+
-+ def update_protocol(self, proto):
-+ data = {
-+ "hostname" : self.hostname,
-+ "myip" : self.get_address(proto),
-+ }
-+
-+ # Send update to the server.
-+ try:
-+ response = self.send_request(self.url, username=self.username, password=self.password,
-+ data=data)
-+
-+ # Handle error codes.
-+ except urllib2.HTTPError, e:
-+ if e.code == 422:
-+ raise DDNSRequestError(_("Domain not found."))
-+
-+ raise
-+
-+ # Handle success message.
-+ if response.code == 200:
-+ return
-+
-+ # If we got here, some other update error happened.
-+ raise DDNSUpdateError(_("Server response: %s") % output)
-+
-+
- class DDNSProviderDHS(DDNSProvider):
- handle = "dhs.org"
- name = "DHS International"
+++ /dev/null
-commit 25f39b4e437627bd1a49393280271d59ad28b86e
-Author: Stefan Schantl <stefan.schantl@ipfire.org>
-Date: Mon Jan 5 21:37:55 2015 +0100
-
- spdns.de: Fix authentication.
-
- There was a simple copy and paste issue which prevents a
- correct authentication with username and password against the
- providers API.
-
-diff --git a/src/ddns/providers.py b/src/ddns/providers.py
-index 587d5ff..bcfb088 100644
---- a/src/ddns/providers.py
-+++ b/src/ddns/providers.py
-@@ -1271,7 +1271,7 @@ class DDNSProviderSPDNS(DDNSProtocolDynDNS2, DDNSProvider):
-
- @property
- def password(self):
-- return self.get("username") or self.token
-+ return self.get("password") or self.token
-
-
- class DDNSProviderStrato(DDNSProtocolDynDNS2, DDNSProvider):