]>
git.ipfire.org Git - ddns.git/blob - src/ddns/providers.py
2 ###############################################################################
4 # ddns - A dynamic DNS client for IPFire #
5 # Copyright (C) 2012 IPFire development team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
25 import xml
.dom
.minidom
29 # Import all possible exception types.
32 logger
= logging
.getLogger("ddns.providers")
39 Returns a dict with all automatically registered providers.
41 return _providers
.copy()
43 class DDNSProvider(object):
44 # A short string that uniquely identifies
48 # The full name of the provider.
51 # A weburl to the homepage of the provider.
52 # (Where to register a new account?)
55 # A list of supported protocols.
56 protocols
= ("ipv6", "ipv4")
60 # Automatically register all providers.
61 class __metaclass__(type):
62 def __init__(provider
, name
, bases
, dict):
63 type.__init
__(provider
, name
, bases
, dict)
65 # The main class from which is inherited is not registered
67 if name
== "DDNSProvider":
70 if not all((provider
.handle
, provider
.name
, provider
.website
)):
71 raise DDNSError(_("Provider is not properly configured"))
73 assert not _providers
.has_key(provider
.handle
), \
74 "Provider '%s' has already been registered" % provider
.handle
76 _providers
[provider
.handle
] = provider
78 def __init__(self
, core
, **settings
):
81 # Copy a set of default settings and
82 # update them by those from the configuration file.
83 self
.settings
= self
.DEFAULT_SETTINGS
.copy()
84 self
.settings
.update(settings
)
87 return "<DDNS Provider %s (%s)>" % (self
.name
, self
.handle
)
89 def __cmp__(self
, other
):
90 return cmp(self
.hostname
, other
.hostname
)
92 def get(self
, key
, default
=None):
94 Get a setting from the settings dictionary.
96 return self
.settings
.get(key
, default
)
101 Fast access to the hostname.
103 return self
.get("hostname")
108 Fast access to the username.
110 return self
.get("username")
115 Fast access to the password.
117 return self
.get("password")
122 Fast access to the token.
124 return self
.get("token")
126 def __call__(self
, force
=False):
128 logger
.debug(_("Updating %s forced") % self
.hostname
)
130 # Check if we actually need to update this host.
131 elif self
.is_uptodate(self
.protocols
):
132 logger
.debug(_("The dynamic host %(hostname)s (%(provider)s) is already up to date") % \
133 { "hostname" : self
.hostname
, "provider" : self
.name
})
136 # Execute the update.
139 logger
.info(_("Dynamic DNS update for %(hostname)s (%(provider)s) successful") % \
140 { "hostname" : self
.hostname
, "provider" : self
.name
})
143 raise NotImplementedError
145 def is_uptodate(self
, protos
):
147 Returns True if this host is already up to date
148 and does not need to change the IP address on the
152 addresses
= self
.core
.system
.resolve(self
.hostname
, proto
)
154 current_address
= self
.get_address(proto
)
156 # If no addresses for the given protocol exist, we
158 if current_address
is None and not addresses
:
161 if not current_address
in addresses
:
166 def send_request(self
, *args
, **kwargs
):
168 Proxy connection to the send request
171 return self
.core
.system
.send_request(*args
, **kwargs
)
173 def get_address(self
, proto
, default
=None):
175 Proxy method to get the current IP address.
177 return self
.core
.system
.get_address(proto
) or default
180 class DDNSProtocolDynDNS2(object):
182 This is an abstract class that implements the DynDNS updater
183 protocol version 2. As this is a popular way to update dynamic
184 DNS records, this class is supposed make the provider classes
188 # Information about the format of the request is to be found
189 # http://dyn.com/support/developers/api/perform-update/
190 # http://dyn.com/support/developers/api/return-codes/
192 def _prepare_request_data(self
):
194 "hostname" : self
.hostname
,
195 "myip" : self
.get_address("ipv4"),
201 data
= self
._prepare
_request
_data
()
203 # Send update to the server.
204 response
= self
.send_request(self
.url
, data
=data
,
205 username
=self
.username
, password
=self
.password
)
207 # Get the full response message.
208 output
= response
.read()
210 # Handle success messages.
211 if output
.startswith("good") or output
.startswith("nochg"):
214 # Handle error codes.
215 if output
== "badauth":
216 raise DDNSAuthenticationError
217 elif output
== "abuse":
219 elif output
== "notfqdn":
220 raise DDNSRequestError(_("No valid FQDN was given."))
221 elif output
== "nohost":
222 raise DDNSRequestError(_("Specified host does not exist."))
223 elif output
== "911":
224 raise DDNSInternalServerError
225 elif output
== "dnserr":
226 raise DDNSInternalServerError(_("DNS error encountered."))
227 elif output
== "badagent":
228 raise DDNSBlockedError
230 # If we got here, some other update error happened.
231 raise DDNSUpdateError(_("Server response: %s") % output
)
234 class DDNSResponseParserXML(object):
236 This class provides a parser for XML responses which
237 will be sent by various providers. This class uses the python
238 shipped XML minidom module to walk through the XML tree and return
242 def get_xml_tag_value(self
, document
, content
):
243 # Send input to the parser.
244 xmldoc
= xml
.dom
.minidom
.parseString(document
)
246 # Get XML elements by the given content.
247 element
= xmldoc
.getElementsByTagName(content
)
249 # If no element has been found, we directly can return None.
253 # Only get the first child from an element, even there are more than one.
254 firstchild
= element
[0].firstChild
256 # Get the value of the child.
257 value
= firstchild
.nodeValue
263 class DDNSProviderAllInkl(DDNSProvider
):
264 handle
= "all-inkl.com"
265 name
= "All-inkl.com"
266 website
= "http://all-inkl.com/"
267 protocols
= ("ipv4",)
269 # There are only information provided by the vendor how to
270 # perform an update on a FRITZ Box. Grab requried informations
272 # http://all-inkl.goetze.it/v01/ddns-mit-einfachen-mitteln/
274 url
= "http://dyndns.kasserver.com"
277 # There is no additional data required so we directly can
279 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
)
281 # Get the full response message.
282 output
= response
.read()
284 # Handle success messages.
285 if output
.startswith("good") or output
.startswith("nochg"):
288 # If we got here, some other update error happened.
289 raise DDNSUpdateError
292 class DDNSProviderBindNsupdate(DDNSProvider
):
294 name
= "BIND nsupdate utility"
295 website
= "http://en.wikipedia.org/wiki/Nsupdate"
300 scriptlet
= self
.__make
_scriptlet
()
302 # -v enables TCP hence we transfer keys and other data that may
303 # exceed the size of one packet.
304 # -t sets the timeout
305 command
= ["nsupdate", "-v", "-t", "60"]
307 p
= subprocess
.Popen(command
, shell
=True,
308 stdin
=subprocess
.PIPE
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
,
310 stdout
, stderr
= p
.communicate(scriptlet
)
312 if p
.returncode
== 0:
315 raise DDNSError("nsupdate terminated with error code: %s\n %s" % (p
.returncode
, stderr
))
317 def __make_scriptlet(self
):
320 # Set a different server the update is sent to.
321 server
= self
.get("server", None)
323 scriptlet
.append("server %s" % server
)
325 # Set the DNS zone the host should be added to.
326 zone
= self
.get("zone", None)
328 scriptlet
.append("zone %s" % zone
)
330 key
= self
.get("key", None)
332 secret
= self
.get("secret")
334 scriptlet
.append("key %s %s" % (key
, secret
))
336 ttl
= self
.get("ttl", self
.DEFAULT_TTL
)
338 # Perform an update for each supported protocol.
339 for rrtype
, proto
in (("AAAA", "ipv6"), ("A", "ipv4")):
340 address
= self
.get_address(proto
)
344 scriptlet
.append("update delete %s. %s" % (self
.hostname
, rrtype
))
345 scriptlet
.append("update add %s. %s %s %s" % \
346 (self
.hostname
, ttl
, rrtype
, address
))
348 # Send the actions to the server.
349 scriptlet
.append("send")
350 scriptlet
.append("quit")
352 logger
.debug(_("Scriptlet:"))
353 for line
in scriptlet
:
354 # Masquerade the line with the secret key.
355 if line
.startswith("key"):
356 line
= "key **** ****"
358 logger
.debug(" %s" % line
)
360 return "\n".join(scriptlet
)
363 class DDNSProviderDHS(DDNSProvider
):
365 name
= "DHS International"
366 website
= "http://dhs.org/"
367 protocols
= ("ipv4",)
369 # No information about the used update api provided on webpage,
370 # grabed from source code of ez-ipudate.
372 url
= "http://members.dhs.org/nic/hosts"
376 "domain" : self
.hostname
,
377 "ip" : self
.get_address("ipv4"),
379 "hostcmdstage" : "2",
383 # Send update to the server.
384 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
387 # Handle success messages.
388 if response
.code
== 200:
391 # If we got here, some other update error happened.
392 raise DDNSUpdateError
395 class DDNSProviderDNSpark(DDNSProvider
):
396 handle
= "dnspark.com"
398 website
= "http://dnspark.com/"
399 protocols
= ("ipv4",)
401 # Informations to the used api can be found here:
402 # https://dnspark.zendesk.com/entries/31229348-Dynamic-DNS-API-Documentation
404 url
= "https://control.dnspark.com/api/dynamic/update.php"
408 "domain" : self
.hostname
,
409 "ip" : self
.get_address("ipv4"),
412 # Send update to the server.
413 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
416 # Get the full response message.
417 output
= response
.read()
419 # Handle success messages.
420 if output
.startswith("ok") or output
.startswith("nochange"):
423 # Handle error codes.
424 if output
== "unauth":
425 raise DDNSAuthenticationError
426 elif output
== "abuse":
428 elif output
== "blocked":
429 raise DDNSBlockedError
430 elif output
== "nofqdn":
431 raise DDNSRequestError(_("No valid FQDN was given."))
432 elif output
== "nohost":
433 raise DDNSRequestError(_("Invalid hostname specified."))
434 elif output
== "notdyn":
435 raise DDNSRequestError(_("Hostname not marked as a dynamic host."))
436 elif output
== "invalid":
437 raise DDNSRequestError(_("Invalid IP address has been sent."))
439 # If we got here, some other update error happened.
440 raise DDNSUpdateError
443 class DDNSProviderDtDNS(DDNSProvider
):
446 website
= "http://dtdns.com/"
447 protocols
= ("ipv4",)
449 # Information about the format of the HTTPS request is to be found
450 # http://www.dtdns.com/dtsite/updatespec
452 url
= "https://www.dtdns.com/api/autodns.cfm"
456 "ip" : self
.get_address("ipv4"),
457 "id" : self
.hostname
,
461 # Send update to the server.
462 response
= self
.send_request(self
.url
, data
=data
)
464 # Get the full response message.
465 output
= response
.read()
467 # Remove all leading and trailing whitespace.
468 output
= output
.strip()
470 # Handle success messages.
471 if "now points to" in output
:
474 # Handle error codes.
475 if output
== "No hostname to update was supplied.":
476 raise DDNSRequestError(_("No hostname specified."))
478 elif output
== "The hostname you supplied is not valid.":
479 raise DDNSRequestError(_("Invalid hostname specified."))
481 elif output
== "The password you supplied is not valid.":
482 raise DDNSAuthenticationError
484 elif output
== "Administration has disabled this account.":
485 raise DDNSRequestError(_("Account has been disabled."))
487 elif output
== "Illegal character in IP.":
488 raise DDNSRequestError(_("Invalid IP address has been sent."))
490 elif output
== "Too many failed requests.":
491 raise DDNSRequestError(_("Too many failed requests."))
493 # If we got here, some other update error happened.
494 raise DDNSUpdateError
497 class DDNSProviderDynDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
498 handle
= "dyndns.org"
500 website
= "http://dyn.com/dns/"
501 protocols
= ("ipv4",)
503 # Information about the format of the request is to be found
504 # http://http://dyn.com/support/developers/api/perform-update/
505 # http://dyn.com/support/developers/api/return-codes/
507 url
= "https://members.dyndns.org/nic/update"
510 class DDNSProviderDynU(DDNSProtocolDynDNS2
, DDNSProvider
):
513 website
= "http://dynu.com/"
514 protocols
= ("ipv6", "ipv4",)
516 # Detailed information about the request and response codes
517 # are available on the providers webpage.
518 # http://dynu.com/Default.aspx?page=dnsapi
520 url
= "https://api.dynu.com/nic/update"
522 def _prepare_request_data(self
):
523 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
525 # This one supports IPv6
526 myipv6
= self
.get_address("ipv6")
528 # Add update information if we have an IPv6 address.
530 data
["myipv6"] = myipv6
535 class DDNSProviderEasyDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
536 handle
= "easydns.com"
538 website
= "http://www.easydns.com/"
539 protocols
= ("ipv4",)
541 # There is only some basic documentation provided by the vendor,
542 # also searching the web gain very poor results.
543 # http://mediawiki.easydns.com/index.php/Dynamic_DNS
545 url
= "http://api.cp.easydns.com/dyn/tomato.php"
548 class DDNSProviderDomopoli(DDNSProtocolDynDNS2
, DDNSProvider
):
549 handle
= "domopoli.de"
551 website
= "http://domopoli.de/"
552 protocols
= ("ipv4",)
554 # https://www.domopoli.de/?page=howto#DynDns_start
556 url
= "http://dyndns.domopoli.de/nic/update"
559 class DDNSProviderDynsNet(DDNSProvider
):
562 website
= "http://www.dyns.net/"
563 protocols
= ("ipv4",)
565 # There is very detailed informatio about how to send the update request and
566 # the possible response codes. (Currently we are using the v1.1 proto)
567 # http://www.dyns.net/documentation/technical/protocol/
569 url
= "http://www.dyns.net/postscript011.php"
573 "ip" : self
.get_address("ipv4"),
574 "host" : self
.hostname
,
575 "username" : self
.username
,
576 "password" : self
.password
,
579 # Send update to the server.
580 response
= self
.send_request(self
.url
, data
=data
)
582 # Get the full response message.
583 output
= response
.read()
585 # Handle success messages.
586 if output
.startswith("200"):
589 # Handle error codes.
590 if output
.startswith("400"):
591 raise DDNSRequestError(_("Malformed request has been sent."))
592 elif output
.startswith("401"):
593 raise DDNSAuthenticationError
594 elif output
.startswith("402"):
595 raise DDNSRequestError(_("Too frequent update requests have been sent."))
596 elif output
.startswith("403"):
597 raise DDNSInternalServerError
599 # If we got here, some other update error happened.
600 raise DDNSUpdateError(_("Server response: %s") % output
)
603 class DDNSProviderEnomCom(DDNSResponseParserXML
, DDNSProvider
):
606 website
= "http://www.enom.com/"
608 # There are very detailed information about how to send an update request and
610 # http://www.enom.com/APICommandCatalog/
612 url
= "https://dynamic.name-services.com/interface.asp"
616 "command" : "setdnshost",
617 "responsetype" : "xml",
618 "address" : self
.get_address("ipv4"),
619 "domainpassword" : self
.password
,
620 "zone" : self
.hostname
623 # Send update to the server.
624 response
= self
.send_request(self
.url
, data
=data
)
626 # Get the full response message.
627 output
= response
.read()
629 # Handle success messages.
630 if self
.get_xml_tag_value(output
, "ErrCount") == "0":
633 # Handle error codes.
634 errorcode
= self
.get_xml_tag_value(output
, "ResponseNumber")
636 if errorcode
== "304155":
637 raise DDNSAuthenticationError
638 elif errorcode
== "304153":
639 raise DDNSRequestError(_("Domain not found."))
641 # If we got here, some other update error happened.
642 raise DDNSUpdateError
645 class DDNSProviderEntryDNS(DDNSProvider
):
646 handle
= "entrydns.net"
648 website
= "http://entrydns.net/"
649 protocols
= ("ipv4",)
651 # Some very tiny details about their so called "Simple API" can be found
652 # here: https://entrydns.net/help
653 url
= "https://entrydns.net/records/modify"
657 "ip" : self
.get_address("ipv4")
660 # Add auth token to the update url.
661 url
= "%s/%s" % (self
.url
, self
.token
)
663 # Send update to the server.
665 response
= self
.send_request(url
, data
=data
)
668 except urllib2
.HTTPError
, e
:
670 raise DDNSAuthenticationError
673 raise DDNSRequestError(_("An invalid IP address was submitted"))
677 # Handle success messages.
678 if response
.code
== 200:
681 # If we got here, some other update error happened.
682 raise DDNSUpdateError
685 class DDNSProviderFreeDNSAfraidOrg(DDNSProvider
):
686 handle
= "freedns.afraid.org"
687 name
= "freedns.afraid.org"
688 website
= "http://freedns.afraid.org/"
690 # No information about the request or response could be found on the vendor
691 # page. All used values have been collected by testing.
692 url
= "https://freedns.afraid.org/dynamic/update.php"
696 return self
.get("proto")
699 address
= self
.get_address(self
.proto
)
705 # Add auth token to the update url.
706 url
= "%s?%s" % (self
.url
, self
.token
)
708 # Send update to the server.
709 response
= self
.send_request(url
, data
=data
)
711 # Get the full response message.
712 output
= response
.read()
714 # Handle success messages.
715 if output
.startswith("Updated") or "has not changed" in output
:
718 # Handle error codes.
719 if output
== "ERROR: Unable to locate this record":
720 raise DDNSAuthenticationError
721 elif "is an invalid IP address" in output
:
722 raise DDNSRequestError(_("Invalid IP address has been sent."))
724 # If we got here, some other update error happened.
725 raise DDNSUpdateError
728 class DDNSProviderLightningWireLabs(DDNSProvider
):
729 handle
= "dns.lightningwirelabs.com"
730 name
= "Lightning Wire Labs DNS Service"
731 website
= "http://dns.lightningwirelabs.com/"
733 # Information about the format of the HTTPS request is to be found
734 # https://dns.lightningwirelabs.com/knowledge-base/api/ddns
736 url
= "https://dns.lightningwirelabs.com/update"
740 "hostname" : self
.hostname
,
741 "address6" : self
.get_address("ipv6", "-"),
742 "address4" : self
.get_address("ipv4", "-"),
745 # Check if a token has been set.
747 data
["token"] = self
.token
749 # Check for username and password.
750 elif self
.username
and self
.password
:
752 "username" : self
.username
,
753 "password" : self
.password
,
756 # Raise an error if no auth details are given.
758 raise DDNSConfigurationError
760 # Send update to the server.
761 response
= self
.send_request(self
.url
, data
=data
)
763 # Handle success messages.
764 if response
.code
== 200:
767 # If we got here, some other update error happened.
768 raise DDNSUpdateError
771 class DDNSProviderNamecheap(DDNSResponseParserXML
, DDNSProvider
):
772 handle
= "namecheap.com"
774 website
= "http://namecheap.com"
775 protocols
= ("ipv4",)
777 # Information about the format of the HTTP request is to be found
778 # https://www.namecheap.com/support/knowledgebase/article.aspx/9249/0/nc-dynamic-dns-to-dyndns-adapter
779 # https://community.namecheap.com/forums/viewtopic.php?f=6&t=6772
781 url
= "https://dynamicdns.park-your-domain.com/update"
784 # Namecheap requires the hostname splitted into a host and domain part.
785 host
, domain
= self
.hostname
.split(".", 1)
788 "ip" : self
.get_address("ipv4"),
789 "password" : self
.password
,
794 # Send update to the server.
795 response
= self
.send_request(self
.url
, data
=data
)
797 # Get the full response message.
798 output
= response
.read()
800 # Handle success messages.
801 if self
.get_xml_tag_value(output
, "IP") == self
.get_address("ipv4"):
804 # Handle error codes.
805 errorcode
= self
.get_xml_tag_value(output
, "ResponseNumber")
807 if errorcode
== "304156":
808 raise DDNSAuthenticationError
809 elif errorcode
== "316153":
810 raise DDNSRequestError(_("Domain not found."))
811 elif errorcode
== "316154":
812 raise DDNSRequestError(_("Domain not active."))
813 elif errorcode
in ("380098", "380099"):
814 raise DDNSInternalServerError
816 # If we got here, some other update error happened.
817 raise DDNSUpdateError
820 class DDNSProviderNOIP(DDNSProtocolDynDNS2
, DDNSProvider
):
823 website
= "http://www.no-ip.com/"
824 protocols
= ("ipv4",)
826 # Information about the format of the HTTP request is to be found
827 # here: http://www.no-ip.com/integrate/request and
828 # here: http://www.no-ip.com/integrate/response
830 url
= "http://dynupdate.no-ip.com/nic/update"
832 def _prepare_request_data(self
):
834 "hostname" : self
.hostname
,
835 "address" : self
.get_address("ipv4"),
841 class DDNSProviderNsupdateINFO(DDNSProtocolDynDNS2
, DDNSProvider
):
842 handle
= "nsupdate.info"
843 name
= "nsupdate.info"
844 website
= "http://www.nsupdate.info/"
845 protocols
= ("ipv6", "ipv4",)
847 # Information about the format of the HTTP request can be found
848 # after login on the provider user intrface and here:
849 # http://nsupdateinfo.readthedocs.org/en/latest/user.html
851 # Nsupdate.info uses the hostname as user part for the HTTP basic auth,
852 # and for the password a so called secret.
855 return self
.get("hostname")
859 return self
.get("secret")
863 return self
.get("proto")
867 # The update URL is different by the used protocol.
868 if self
.proto
== "ipv4":
869 return "https://ipv4.nsupdate.info/nic/update"
870 elif self
.proto
== "ipv6":
871 return "https://ipv6.nsupdate.info/nic/update"
873 raise DDNSUpdateError(_("Invalid protocol has been given"))
875 def _prepare_request_data(self
):
877 "myip" : self
.get_address(self
.proto
),
883 class DDNSProviderOpenDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
884 handle
= "opendns.com"
886 website
= "http://www.opendns.com"
888 # Detailed information about the update request and possible
889 # response codes can be obtained from here:
890 # https://support.opendns.com/entries/23891440
892 url
= "https://updates.opendns.com/nic/update"
896 return self
.get("proto")
898 def _prepare_request_data(self
):
900 "hostname" : self
.hostname
,
901 "myip" : self
.get_address(self
.proto
)
907 class DDNSProviderOVH(DDNSProtocolDynDNS2
, DDNSProvider
):
910 website
= "http://www.ovh.com/"
911 protocols
= ("ipv4",)
913 # OVH only provides very limited information about how to
914 # update a DynDNS host. They only provide the update url
915 # on the their german subpage.
917 # http://hilfe.ovh.de/DomainDynHost
919 url
= "https://www.ovh.com/nic/update"
921 def _prepare_request_data(self
):
922 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
930 class DDNSProviderRegfish(DDNSProvider
):
931 handle
= "regfish.com"
932 name
= "Regfish GmbH"
933 website
= "http://www.regfish.com/"
935 # A full documentation to the providers api can be found here
936 # but is only available in german.
937 # https://www.regfish.de/domains/dyndns/dokumentation
939 url
= "https://dyndns.regfish.de/"
943 "fqdn" : self
.hostname
,
946 # Check if we update an IPv6 address.
947 address6
= self
.get_address("ipv6")
949 data
["ipv6"] = address6
951 # Check if we update an IPv4 address.
952 address4
= self
.get_address("ipv4")
954 data
["ipv4"] = address4
956 # Raise an error if none address is given.
957 if not data
.has_key("ipv6") and not data
.has_key("ipv4"):
958 raise DDNSConfigurationError
960 # Check if a token has been set.
962 data
["token"] = self
.token
964 # Raise an error if no token and no useranem and password
966 elif not self
.username
and not self
.password
:
967 raise DDNSConfigurationError(_("No Auth details specified."))
969 # HTTP Basic Auth is only allowed if no token is used.
971 # Send update to the server.
972 response
= self
.send_request(self
.url
, data
=data
)
974 # Send update to the server.
975 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
978 # Get the full response message.
979 output
= response
.read()
981 # Handle success messages.
982 if "100" in output
or "101" in output
:
985 # Handle error codes.
986 if "401" or "402" in output
:
987 raise DDNSAuthenticationError
988 elif "408" in output
:
989 raise DDNSRequestError(_("Invalid IPv4 address has been sent."))
990 elif "409" in output
:
991 raise DDNSRequestError(_("Invalid IPv6 address has been sent."))
992 elif "412" in output
:
993 raise DDNSRequestError(_("No valid FQDN was given."))
994 elif "414" in output
:
995 raise DDNSInternalServerError
997 # If we got here, some other update error happened.
998 raise DDNSUpdateError
1001 class DDNSProviderSelfhost(DDNSProtocolDynDNS2
, DDNSProvider
):
1002 handle
= "selfhost.de"
1003 name
= "Selfhost.de"
1004 website
= "http://www.selfhost.de/"
1005 protocols
= ("ipv4",)
1007 url
= "https://carol.selfhost.de/nic/update"
1009 def _prepare_request_data(self
):
1010 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
1018 class DDNSProviderSPDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
1019 handle
= "spdns.org"
1021 website
= "http://spdns.org/"
1022 protocols
= ("ipv4",)
1024 # Detailed information about request and response codes are provided
1025 # by the vendor. They are using almost the same mechanism and status
1026 # codes as dyndns.org so we can inherit all those stuff.
1028 # http://wiki.securepoint.de/index.php/SPDNS_FAQ
1029 # http://wiki.securepoint.de/index.php/SPDNS_Update-Tokens
1031 url
= "https://update.spdns.de/nic/update"
1034 class DDNSProviderStrato(DDNSProtocolDynDNS2
, DDNSProvider
):
1035 handle
= "strato.com"
1037 website
= "http:/www.strato.com/"
1038 protocols
= ("ipv4",)
1040 # Information about the request and response can be obtained here:
1041 # http://www.strato-faq.de/article/671/So-einfach-richten-Sie-DynDNS-f%C3%BCr-Ihre-Domains-ein.html
1043 url
= "https://dyndns.strato.com/nic/update"
1046 class DDNSProviderTwoDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
1047 handle
= "twodns.de"
1049 website
= "http://www.twodns.de"
1050 protocols
= ("ipv4",)
1052 # Detailed information about the request can be found here
1053 # http://twodns.de/en/faqs
1054 # http://twodns.de/en/api
1056 url
= "https://update.twodns.de/update"
1058 def _prepare_request_data(self
):
1060 "ip" : self
.get_address("ipv4"),
1061 "hostname" : self
.hostname
1067 class DDNSProviderUdmedia(DDNSProtocolDynDNS2
, DDNSProvider
):
1068 handle
= "udmedia.de"
1069 name
= "Udmedia GmbH"
1070 website
= "http://www.udmedia.de"
1071 protocols
= ("ipv4",)
1073 # Information about the request can be found here
1074 # http://www.udmedia.de/faq/content/47/288/de/wie-lege-ich-einen-dyndns_eintrag-an.html
1076 url
= "https://www.udmedia.de/nic/update"
1079 class DDNSProviderVariomedia(DDNSProtocolDynDNS2
, DDNSProvider
):
1080 handle
= "variomedia.de"
1082 website
= "http://www.variomedia.de/"
1083 protocols
= ("ipv6", "ipv4",)
1085 # Detailed information about the request can be found here
1086 # https://dyndns.variomedia.de/
1088 url
= "https://dyndns.variomedia.de/nic/update"
1092 return self
.get("proto")
1094 def _prepare_request_data(self
):
1096 "hostname" : self
.hostname
,
1097 "myip" : self
.get_address(self
.proto
)
1103 class DDNSProviderZoneedit(DDNSProtocolDynDNS2
, DDNSProvider
):
1104 handle
= "zoneedit.com"
1106 website
= "http://www.zoneedit.com"
1107 protocols
= ("ipv4",)
1109 # Detailed information about the request and the response codes can be
1111 # http://www.zoneedit.com/doc/api/other.html
1112 # http://www.zoneedit.com/faq.html
1114 url
= "https://dynamic.zoneedit.com/auth/dynamic.html"
1118 return self
.get("proto")
1122 "dnsto" : self
.get_address(self
.proto
),
1123 "host" : self
.hostname
1126 # Send update to the server.
1127 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
1130 # Get the full response message.
1131 output
= response
.read()
1133 # Handle success messages.
1134 if output
.startswith("<SUCCESS"):
1137 # Handle error codes.
1138 if output
.startswith("invalid login"):
1139 raise DDNSAuthenticationError
1140 elif output
.startswith("<ERROR CODE=\"704\""):
1141 raise DDNSRequestError(_("No valid FQDN was given."))
1142 elif output
.startswith("<ERROR CODE=\"702\""):
1143 raise DDNSInternalServerError
1145 # If we got here, some other update error happened.
1146 raise DDNSUpdateError