]>
git.ipfire.org Git - people/ms/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
== "aduse":
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."))
228 # If we got here, some other update error happened.
229 raise DDNSUpdateError(_("Server response: %s") % output
)
232 class DDNSResponseParserXML(object):
234 This class provides a parser for XML responses which
235 will be sent by various providers. This class uses the python
236 shipped XML minidom module to walk through the XML tree and return
240 def get_xml_tag_value(self
, document
, content
):
241 # Send input to the parser.
242 xmldoc
= xml
.dom
.minidom
.parseString(document
)
244 # Get XML elements by the given content.
245 element
= xmldoc
.getElementsByTagName(content
)
247 # If no element has been found, we directly can return None.
251 # Only get the first child from an element, even there are more than one.
252 firstchild
= element
[0].firstChild
254 # Get the value of the child.
255 value
= firstchild
.nodeValue
261 class DDNSProviderAllInkl(DDNSProvider
):
262 handle
= "all-inkl.com"
263 name
= "All-inkl.com"
264 website
= "http://all-inkl.com/"
265 protocols
= ("ipv4",)
267 # There are only information provided by the vendor how to
268 # perform an update on a FRITZ Box. Grab requried informations
270 # http://all-inkl.goetze.it/v01/ddns-mit-einfachen-mitteln/
272 url
= "http://dyndns.kasserver.com"
275 # There is no additional data required so we directly can
277 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
)
279 # Get the full response message.
280 output
= response
.read()
282 # Handle success messages.
283 if output
.startswith("good") or output
.startswith("nochg"):
286 # If we got here, some other update error happened.
287 raise DDNSUpdateError
290 class DDNSProviderBindNsupdate(DDNSProvider
):
292 name
= "BIND nsupdate utility"
293 website
= "http://en.wikipedia.org/wiki/Nsupdate"
298 scriptlet
= self
.__make
_scriptlet
()
300 # -v enables TCP hence we transfer keys and other data that may
301 # exceed the size of one packet.
302 # -t sets the timeout
303 command
= ["nsupdate", "-v", "-t", "60"]
305 p
= subprocess
.Popen(command
, shell
=True,
306 stdin
=subprocess
.PIPE
, stdout
=subprocess
.PIPE
, stderr
=subprocess
.PIPE
,
308 stdout
, stderr
= p
.communicate(scriptlet
)
310 if p
.returncode
== 0:
313 raise DDNSError("nsupdate terminated with error code: %s\n %s" % (p
.returncode
, stderr
))
315 def __make_scriptlet(self
):
318 # Set a different server the update is sent to.
319 server
= self
.get("server", None)
321 scriptlet
.append("server %s" % server
)
323 # Set the DNS zone the host should be added to.
324 zone
= self
.get("zone", None)
326 scriptlet
.append("zone %s" % zone
)
328 key
= self
.get("key", None)
330 secret
= self
.get("secret")
332 scriptlet
.append("key %s %s" % (key
, secret
))
334 ttl
= self
.get("ttl", self
.DEFAULT_TTL
)
336 # Perform an update for each supported protocol.
337 for rrtype
, proto
in (("AAAA", "ipv6"), ("A", "ipv4")):
338 address
= self
.get_address(proto
)
342 scriptlet
.append("update delete %s. %s" % (self
.hostname
, rrtype
))
343 scriptlet
.append("update add %s. %s %s %s" % \
344 (self
.hostname
, ttl
, rrtype
, address
))
346 # Send the actions to the server.
347 scriptlet
.append("send")
348 scriptlet
.append("quit")
350 logger
.debug(_("Scriptlet:"))
351 for line
in scriptlet
:
352 # Masquerade the line with the secret key.
353 if line
.startswith("key"):
354 line
= "key **** ****"
356 logger
.debug(" %s" % line
)
358 return "\n".join(scriptlet
)
361 class DDNSProviderDHS(DDNSProvider
):
363 name
= "DHS International"
364 website
= "http://dhs.org/"
365 protocols
= ("ipv4",)
367 # No information about the used update api provided on webpage,
368 # grabed from source code of ez-ipudate.
370 url
= "http://members.dhs.org/nic/hosts"
374 "domain" : self
.hostname
,
375 "ip" : self
.get_address("ipv4"),
377 "hostcmdstage" : "2",
381 # Send update to the server.
382 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
385 # Handle success messages.
386 if response
.code
== 200:
389 # If we got here, some other update error happened.
390 raise DDNSUpdateError
393 class DDNSProviderDNSpark(DDNSProvider
):
394 handle
= "dnspark.com"
396 website
= "http://dnspark.com/"
397 protocols
= ("ipv4",)
399 # Informations to the used api can be found here:
400 # https://dnspark.zendesk.com/entries/31229348-Dynamic-DNS-API-Documentation
402 url
= "https://control.dnspark.com/api/dynamic/update.php"
406 "domain" : self
.hostname
,
407 "ip" : self
.get_address("ipv4"),
410 # Send update to the server.
411 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
414 # Get the full response message.
415 output
= response
.read()
417 # Handle success messages.
418 if output
.startswith("ok") or output
.startswith("nochange"):
421 # Handle error codes.
422 if output
== "unauth":
423 raise DDNSAuthenticationError
424 elif output
== "abuse":
426 elif output
== "blocked":
427 raise DDNSBlockedError
428 elif output
== "nofqdn":
429 raise DDNSRequestError(_("No valid FQDN was given."))
430 elif output
== "nohost":
431 raise DDNSRequestError(_("Invalid hostname specified."))
432 elif output
== "notdyn":
433 raise DDNSRequestError(_("Hostname not marked as a dynamic host."))
434 elif output
== "invalid":
435 raise DDNSRequestError(_("Invalid IP address has been sent."))
437 # If we got here, some other update error happened.
438 raise DDNSUpdateError
441 class DDNSProviderDtDNS(DDNSProvider
):
444 website
= "http://dtdns.com/"
445 protocols
= ("ipv4",)
447 # Information about the format of the HTTPS request is to be found
448 # http://www.dtdns.com/dtsite/updatespec
450 url
= "https://www.dtdns.com/api/autodns.cfm"
454 "ip" : self
.get_address("ipv4"),
455 "id" : self
.hostname
,
459 # Send update to the server.
460 response
= self
.send_request(self
.url
, data
=data
)
462 # Get the full response message.
463 output
= response
.read()
465 # Remove all leading and trailing whitespace.
466 output
= output
.strip()
468 # Handle success messages.
469 if "now points to" in output
:
472 # Handle error codes.
473 if output
== "No hostname to update was supplied.":
474 raise DDNSRequestError(_("No hostname specified."))
476 elif output
== "The hostname you supplied is not valid.":
477 raise DDNSRequestError(_("Invalid hostname specified."))
479 elif output
== "The password you supplied is not valid.":
480 raise DDNSAuthenticationError
482 elif output
== "Administration has disabled this account.":
483 raise DDNSRequestError(_("Account has been disabled."))
485 elif output
== "Illegal character in IP.":
486 raise DDNSRequestError(_("Invalid IP address has been sent."))
488 elif output
== "Too many failed requests.":
489 raise DDNSRequestError(_("Too many failed requests."))
491 # If we got here, some other update error happened.
492 raise DDNSUpdateError
495 class DDNSProviderDynDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
496 handle
= "dyndns.org"
498 website
= "http://dyn.com/dns/"
499 protocols
= ("ipv4",)
501 # Information about the format of the request is to be found
502 # http://http://dyn.com/support/developers/api/perform-update/
503 # http://dyn.com/support/developers/api/return-codes/
505 url
= "https://members.dyndns.org/nic/update"
508 class DDNSProviderDynU(DDNSProtocolDynDNS2
, DDNSProvider
):
511 website
= "http://dynu.com/"
512 protocols
= ("ipv6", "ipv4",)
514 # Detailed information about the request and response codes
515 # are available on the providers webpage.
516 # http://dynu.com/Default.aspx?page=dnsapi
518 url
= "https://api.dynu.com/nic/update"
520 def _prepare_request_data(self
):
521 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
523 # This one supports IPv6
524 myipv6
= self
.get_address("ipv6")
526 # Add update information if we have an IPv6 address.
528 data
["myipv6"] = myipv6
533 class DDNSProviderEasyDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
534 handle
= "easydns.com"
536 website
= "http://www.easydns.com/"
537 protocols
= ("ipv4",)
539 # There is only some basic documentation provided by the vendor,
540 # also searching the web gain very poor results.
541 # http://mediawiki.easydns.com/index.php/Dynamic_DNS
543 url
= "http://api.cp.easydns.com/dyn/tomato.php"
546 class DDNSProviderDomopoli(DDNSProtocolDynDNS2
, DDNSProvider
):
547 handle
= "domopoli.de"
549 website
= "http://domopoli.de/"
550 protocols
= ("ipv4",)
552 # https://www.domopoli.de/?page=howto#DynDns_start
554 url
= "http://dyndns.domopoli.de/nic/update"
557 class DDNSProviderEnomCom(DDNSResponseParserXML
, DDNSProvider
):
560 website
= "http://www.enom.com/"
562 # There are very detailed information about how to send an update request and
564 # http://www.enom.com/APICommandCatalog/
566 url
= "https://dynamic.name-services.com/interface.asp"
570 "command" : "setdnshost",
571 "responsetype" : "xml",
572 "address" : self
.get_address("ipv4"),
573 "domainpassword" : self
.password
,
574 "zone" : self
.hostname
577 # Send update to the server.
578 response
= self
.send_request(self
.url
, data
=data
)
580 # Get the full response message.
581 output
= response
.read()
583 # Handle success messages.
584 if self
.get_xml_tag_value(output
, "ErrCount") == "0":
587 # Handle error codes.
588 errorcode
= self
.get_xml_tag_value(output
, "ResponseNumber")
590 if errorcode
== "304155":
591 raise DDNSAuthenticationError
592 elif errorcode
== "304153":
593 raise DDNSRequestError(_("Domain not found."))
595 # If we got here, some other update error happened.
596 raise DDNSUpdateError
599 class DDNSProviderEntryDNS(DDNSProvider
):
600 handle
= "entrydns.net"
602 website
= "http://entrydns.net/"
603 protocols
= ("ipv4",)
605 # Some very tiny details about their so called "Simple API" can be found
606 # here: https://entrydns.net/help
607 url
= "https://entrydns.net/records/modify"
611 "ip" : self
.get_address("ipv4")
614 # Add auth token to the update url.
615 url
= "%s/%s" % (self
.url
, self
.token
)
617 # Send update to the server.
619 response
= self
.send_request(url
, data
=data
)
622 except urllib2
.HTTPError
, e
:
624 raise DDNSAuthenticationError
627 raise DDNSRequestError(_("An invalid IP address was submitted"))
631 # Handle success messages.
632 if response
.code
== 200:
635 # If we got here, some other update error happened.
636 raise DDNSUpdateError
639 class DDNSProviderFreeDNSAfraidOrg(DDNSProvider
):
640 handle
= "freedns.afraid.org"
641 name
= "freedns.afraid.org"
642 website
= "http://freedns.afraid.org/"
644 # No information about the request or response could be found on the vendor
645 # page. All used values have been collected by testing.
646 url
= "https://freedns.afraid.org/dynamic/update.php"
650 return self
.get("proto")
653 address
= self
.get_address(self
.proto
)
659 # Add auth token to the update url.
660 url
= "%s?%s" % (self
.url
, self
.token
)
662 # Send update to the server.
663 response
= self
.send_request(url
, data
=data
)
665 # Get the full response message.
666 output
= response
.read()
668 # Handle success messages.
669 if output
.startswith("Updated") or "has not changed" in output
:
672 # Handle error codes.
673 if output
== "ERROR: Unable to locate this record":
674 raise DDNSAuthenticationError
675 elif "is an invalid IP address" in output
:
676 raise DDNSRequestError(_("Invalid IP address has been sent."))
678 # If we got here, some other update error happened.
679 raise DDNSUpdateError
682 class DDNSProviderLightningWireLabs(DDNSProvider
):
683 handle
= "dns.lightningwirelabs.com"
684 name
= "Lightning Wire Labs DNS Service"
685 website
= "http://dns.lightningwirelabs.com/"
687 # Information about the format of the HTTPS request is to be found
688 # https://dns.lightningwirelabs.com/knowledge-base/api/ddns
690 url
= "https://dns.lightningwirelabs.com/update"
694 "hostname" : self
.hostname
,
695 "address6" : self
.get_address("ipv6", "-"),
696 "address4" : self
.get_address("ipv4", "-"),
699 # Check if a token has been set.
701 data
["token"] = self
.token
703 # Check for username and password.
704 elif self
.username
and self
.password
:
706 "username" : self
.username
,
707 "password" : self
.password
,
710 # Raise an error if no auth details are given.
712 raise DDNSConfigurationError
714 # Send update to the server.
715 response
= self
.send_request(self
.url
, data
=data
)
717 # Handle success messages.
718 if response
.code
== 200:
721 # If we got here, some other update error happened.
722 raise DDNSUpdateError
725 class DDNSProviderNamecheap(DDNSResponseParserXML
, DDNSProvider
):
726 handle
= "namecheap.com"
728 website
= "http://namecheap.com"
729 protocols
= ("ipv4",)
731 # Information about the format of the HTTP request is to be found
732 # https://www.namecheap.com/support/knowledgebase/article.aspx/9249/0/nc-dynamic-dns-to-dyndns-adapter
733 # https://community.namecheap.com/forums/viewtopic.php?f=6&t=6772
735 url
= "https://dynamicdns.park-your-domain.com/update"
738 # Namecheap requires the hostname splitted into a host and domain part.
739 host
, domain
= self
.hostname
.split(".", 1)
742 "ip" : self
.get_address("ipv4"),
743 "password" : self
.password
,
748 # Send update to the server.
749 response
= self
.send_request(self
.url
, data
=data
)
751 # Get the full response message.
752 output
= response
.read()
754 # Handle success messages.
755 if self
.get_xml_tag_value(output
, "IP") == self
.get_address("ipv4"):
758 # Handle error codes.
759 errorcode
= self
.get_xml_tag_value(output
, "ResponseNumber")
761 if errorcode
== "304156":
762 raise DDNSAuthenticationError
763 elif errorcode
== "316153":
764 raise DDNSRequestError(_("Domain not found."))
765 elif errorcode
== "316154":
766 raise DDNSRequestError(_("Domain not active."))
767 elif errorcode
in ("380098", "380099"):
768 raise DDNSInternalServerError
770 # If we got here, some other update error happened.
771 raise DDNSUpdateError
774 class DDNSProviderNOIP(DDNSProtocolDynDNS2
, DDNSProvider
):
777 website
= "http://www.no-ip.com/"
778 protocols
= ("ipv4",)
780 # Information about the format of the HTTP request is to be found
781 # here: http://www.no-ip.com/integrate/request and
782 # here: http://www.no-ip.com/integrate/response
784 url
= "http://dynupdate.no-ip.com/nic/update"
786 def _prepare_request_data(self
):
788 "hostname" : self
.hostname
,
789 "address" : self
.get_address("ipv4"),
795 class DDNSProviderNsupdateINFO(DDNSProtocolDynDNS2
, DDNSProvider
):
796 handle
= "nsupdate.info"
797 name
= "nsupdate.info"
798 website
= "http://www.nsupdate.info/"
799 protocols
= ("ipv6", "ipv4",)
801 # Information about the format of the HTTP request can be found
802 # after login on the provider user intrface and here:
803 # http://nsupdateinfo.readthedocs.org/en/latest/user.html
805 # Nsupdate.info uses the hostname as user part for the HTTP basic auth,
806 # and for the password a so called secret.
809 return self
.get("hostname")
813 return self
.get("secret")
817 return self
.get("proto")
821 # The update URL is different by the used protocol.
822 if self
.proto
== "ipv4":
823 return "https://ipv4.nsupdate.info/nic/update"
824 elif self
.proto
== "ipv6":
825 return "https://ipv6.nsupdate.info/nic/update"
827 raise DDNSUpdateError(_("Invalid protocol has been given"))
829 def _prepare_request_data(self
):
831 "myip" : self
.get_address(self
.proto
),
837 class DDNSProviderOpenDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
838 handle
= "opendns.com"
840 website
= "http://www.opendns.com"
842 # Detailed information about the update request and possible
843 # response codes can be obtained from here:
844 # https://support.opendns.com/entries/23891440
846 url
= "https://updates.opendns.com/nic/update"
850 return self
.get("proto")
852 def _prepare_request_data(self
):
854 "hostname" : self
.hostname
,
855 "myip" : self
.get_address(self
.proto
)
861 class DDNSProviderOVH(DDNSProtocolDynDNS2
, DDNSProvider
):
864 website
= "http://www.ovh.com/"
865 protocols
= ("ipv4",)
867 # OVH only provides very limited information about how to
868 # update a DynDNS host. They only provide the update url
869 # on the their german subpage.
871 # http://hilfe.ovh.de/DomainDynHost
873 url
= "https://www.ovh.com/nic/update"
875 def _prepare_request_data(self
):
876 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
884 class DDNSProviderRegfish(DDNSProvider
):
885 handle
= "regfish.com"
886 name
= "Regfish GmbH"
887 website
= "http://www.regfish.com/"
889 # A full documentation to the providers api can be found here
890 # but is only available in german.
891 # https://www.regfish.de/domains/dyndns/dokumentation
893 url
= "https://dyndns.regfish.de/"
897 "fqdn" : self
.hostname
,
900 # Check if we update an IPv6 address.
901 address6
= self
.get_address("ipv6")
903 data
["ipv6"] = address6
905 # Check if we update an IPv4 address.
906 address4
= self
.get_address("ipv4")
908 data
["ipv4"] = address4
910 # Raise an error if none address is given.
911 if not data
.has_key("ipv6") and not data
.has_key("ipv4"):
912 raise DDNSConfigurationError
914 # Check if a token has been set.
916 data
["token"] = self
.token
918 # Raise an error if no token and no useranem and password
920 elif not self
.username
and not self
.password
:
921 raise DDNSConfigurationError(_("No Auth details specified."))
923 # HTTP Basic Auth is only allowed if no token is used.
925 # Send update to the server.
926 response
= self
.send_request(self
.url
, data
=data
)
928 # Send update to the server.
929 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
932 # Get the full response message.
933 output
= response
.read()
935 # Handle success messages.
936 if "100" in output
or "101" in output
:
939 # Handle error codes.
940 if "401" or "402" in output
:
941 raise DDNSAuthenticationError
942 elif "408" in output
:
943 raise DDNSRequestError(_("Invalid IPv4 address has been sent."))
944 elif "409" in output
:
945 raise DDNSRequestError(_("Invalid IPv6 address has been sent."))
946 elif "412" in output
:
947 raise DDNSRequestError(_("No valid FQDN was given."))
948 elif "414" in output
:
949 raise DDNSInternalServerError
951 # If we got here, some other update error happened.
952 raise DDNSUpdateError
955 class DDNSProviderSelfhost(DDNSProtocolDynDNS2
, DDNSProvider
):
956 handle
= "selfhost.de"
958 website
= "http://www.selfhost.de/"
959 protocols
= ("ipv4",)
961 url
= "https://carol.selfhost.de/nic/update"
963 def _prepare_request_data(self
):
964 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
972 class DDNSProviderSPDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
975 website
= "http://spdns.org/"
976 protocols
= ("ipv4",)
978 # Detailed information about request and response codes are provided
979 # by the vendor. They are using almost the same mechanism and status
980 # codes as dyndns.org so we can inherit all those stuff.
982 # http://wiki.securepoint.de/index.php/SPDNS_FAQ
983 # http://wiki.securepoint.de/index.php/SPDNS_Update-Tokens
985 url
= "https://update.spdns.de/nic/update"
988 class DDNSProviderStrato(DDNSProtocolDynDNS2
, DDNSProvider
):
989 handle
= "strato.com"
991 website
= "http:/www.strato.com/"
992 protocols
= ("ipv4",)
994 # Information about the request and response can be obtained here:
995 # http://www.strato-faq.de/article/671/So-einfach-richten-Sie-DynDNS-f%C3%BCr-Ihre-Domains-ein.html
997 url
= "https://dyndns.strato.com/nic/update"
1000 class DDNSProviderTwoDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
1001 handle
= "twodns.de"
1003 website
= "http://www.twodns.de"
1004 protocols
= ("ipv4",)
1006 # Detailed information about the request can be found here
1007 # http://twodns.de/en/faqs
1008 # http://twodns.de/en/api
1010 url
= "https://update.twodns.de/update"
1012 def _prepare_request_data(self
):
1014 "ip" : self
.get_address("ipv4"),
1015 "hostname" : self
.hostname
1021 class DDNSProviderUdmedia(DDNSProtocolDynDNS2
, DDNSProvider
):
1022 handle
= "udmedia.de"
1023 name
= "Udmedia GmbH"
1024 website
= "http://www.udmedia.de"
1025 protocols
= ("ipv4",)
1027 # Information about the request can be found here
1028 # http://www.udmedia.de/faq/content/47/288/de/wie-lege-ich-einen-dyndns_eintrag-an.html
1030 url
= "https://www.udmedia.de/nic/update"
1033 class DDNSProviderVariomedia(DDNSProtocolDynDNS2
, DDNSProvider
):
1034 handle
= "variomedia.de"
1036 website
= "http://www.variomedia.de/"
1037 protocols
= ("ipv6", "ipv4",)
1039 # Detailed information about the request can be found here
1040 # https://dyndns.variomedia.de/
1042 url
= "https://dyndns.variomedia.de/nic/update"
1046 return self
.get("proto")
1048 def _prepare_request_data(self
):
1050 "hostname" : self
.hostname
,
1051 "myip" : self
.get_address(self
.proto
)
1057 class DDNSProviderZoneedit(DDNSProtocolDynDNS2
, DDNSProvider
):
1058 handle
= "zoneedit.com"
1060 website
= "http://www.zoneedit.com"
1061 protocols
= ("ipv4",)
1063 # Detailed information about the request and the response codes can be
1065 # http://www.zoneedit.com/doc/api/other.html
1066 # http://www.zoneedit.com/faq.html
1068 url
= "https://dynamic.zoneedit.com/auth/dynamic.html"
1072 return self
.get("proto")
1076 "dnsto" : self
.get_address(self
.proto
),
1077 "host" : self
.hostname
1080 # Send update to the server.
1081 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
1084 # Get the full response message.
1085 output
= response
.read()
1087 # Handle success messages.
1088 if output
.startswith("<SUCCESS"):
1091 # Handle error codes.
1092 if output
.startswith("invalid login"):
1093 raise DDNSAuthenticationError
1094 elif output
.startswith("<ERROR CODE=\"704\""):
1095 raise DDNSRequestError(_("No valid FQDN was given."))
1096 elif output
.startswith("<ERROR CODE=\"702\""):
1097 raise DDNSInternalServerError
1099 # If we got here, some other update error happened.
1100 raise DDNSUpdateError