]> git.ipfire.org Git - ddns.git/blobdiff - src/ddns/providers.py
FreeDNSAfraid: Readd missing lines.
[ddns.git] / src / ddns / providers.py
index 91e02272da07d5ad0bb690c232f4689894a2b4d8..278d18af39d5b691a5d8146de54a228fb4501e48 100644 (file)
@@ -20,6 +20,7 @@
 ###############################################################################
 
 import logging
+import subprocess
 import urllib2
 import xml.dom.minidom
 
@@ -31,6 +32,14 @@ from .errors import *
 logger = logging.getLogger("ddns.providers")
 logger.propagate = 1
 
+_providers = {}
+
+def get():
+       """
+               Returns a dict with all automatically registered providers.
+       """
+       return _providers.copy()
+
 class DDNSProvider(object):
        # A short string that uniquely identifies
        # this provider.
@@ -48,6 +57,24 @@ class DDNSProvider(object):
 
        DEFAULT_SETTINGS = {}
 
+       # Automatically register all providers.
+       class __metaclass__(type):
+               def __init__(provider, name, bases, dict):
+                       type.__init__(provider, name, bases, dict)
+
+                       # The main class from which is inherited is not registered
+                       # as a provider.
+                       if name == "DDNSProvider":
+                               return
+
+                       if not all((provider.handle, provider.name, provider.website)):
+                               raise DDNSError(_("Provider is not properly configured"))
+
+                       assert not _providers.has_key(provider.handle), \
+                               "Provider '%s' has already been registered" % provider.handle
+
+                       _providers[provider.handle] = provider
+
        def __init__(self, core, **settings):
                self.core = core
 
@@ -227,6 +254,72 @@ class DDNSProviderAllInkl(DDNSProvider):
                raise DDNSUpdateError
 
 
+class DDNSProviderBindNsupdate(DDNSProvider):
+       handle  = "nsupdate"
+       name    = "BIND nsupdate utility"
+       website = "http://en.wikipedia.org/wiki/Nsupdate"
+
+       DEFAULT_TTL = 60
+
+       def update(self):
+               scriptlet = self.__make_scriptlet()
+
+               # -v enables TCP hence we transfer keys and other data that may
+               # exceed the size of one packet.
+               # -t sets the timeout
+               command = ["nsupdate", "-v", "-t", "60"]
+
+               p = subprocess.Popen(command, shell=True,
+                       stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE,
+               )
+               stdout, stderr = p.communicate(scriptlet)
+
+               if p.returncode == 0:
+                       return
+
+               raise DDNSError("nsupdate terminated with error code: %s\n  %s" % (p.returncode, stderr))
+
+       def __make_scriptlet(self):
+               scriptlet = []
+
+               # Set a different server the update is sent to.
+               server = self.get("server", None)
+               if server:
+                       scriptlet.append("server %s" % server)
+
+               key = self.get("key", None)
+               if key:
+                       secret = self.get("secret")
+
+                       scriptlet.append("key %s %s" % (key, secret))
+
+               ttl = self.get("ttl", self.DEFAULT_TTL)
+
+               # Perform an update for each supported protocol.
+               for rrtype, proto in (("AAAA", "ipv6"), ("A", "ipv4")):
+                       address = self.get_address(proto)
+                       if not address:
+                               continue
+
+                       scriptlet.append("update delete %s. %s" % (self.hostname, rrtype))
+                       scriptlet.append("update add %s. %s %s %s" % \
+                               (self.hostname, ttl, rrtype, address))
+
+               # Send the actions to the server.
+               scriptlet.append("send")
+               scriptlet.append("quit")
+
+               logger.debug(_("Scriptlet:"))
+               for line in scriptlet:
+                       # Masquerade the line with the secret key.
+                       if line.startswith("key"):
+                               line = "key **** ****"
+
+                       logger.debug("  %s" % line)
+
+               return "\n".join(scriptlet)
+
+
 class DDNSProviderDHS(DDNSProvider):
        handle    = "dhs.org"
        name      = "DHS International"
@@ -436,6 +529,10 @@ class DDNSProviderFreeDNSAfraidOrg(DDNSProvider):
                # Send update to the server.
                response = self.send_request(url, data=data)
 
+               # Get the full response message.
+               output = response.read()
+
+               # Handle success messages.
                if output.startswith("Updated") or "has not changed" in output:
                        return