]>
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
.info(_("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 key
= self
.get("key", None)
325 secret
= self
.get("secret")
327 scriptlet
.append("key %s %s" % (key
, secret
))
329 ttl
= self
.get("ttl", self
.DEFAULT_TTL
)
331 # Perform an update for each supported protocol.
332 for rrtype
, proto
in (("AAAA", "ipv6"), ("A", "ipv4")):
333 address
= self
.get_address(proto
)
337 scriptlet
.append("update delete %s. %s" % (self
.hostname
, rrtype
))
338 scriptlet
.append("update add %s. %s %s %s" % \
339 (self
.hostname
, ttl
, rrtype
, address
))
341 # Send the actions to the server.
342 scriptlet
.append("send")
343 scriptlet
.append("quit")
345 logger
.debug(_("Scriptlet:"))
346 for line
in scriptlet
:
347 # Masquerade the line with the secret key.
348 if line
.startswith("key"):
349 line
= "key **** ****"
351 logger
.debug(" %s" % line
)
353 return "\n".join(scriptlet
)
356 class DDNSProviderDHS(DDNSProvider
):
358 name
= "DHS International"
359 website
= "http://dhs.org/"
360 protocols
= ("ipv4",)
362 # No information about the used update api provided on webpage,
363 # grabed from source code of ez-ipudate.
365 url
= "http://members.dhs.org/nic/hosts"
369 "domain" : self
.hostname
,
370 "ip" : self
.get_address("ipv4"),
372 "hostcmdstage" : "2",
376 # Send update to the server.
377 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
380 # Handle success messages.
381 if response
.code
== 200:
384 # If we got here, some other update error happened.
385 raise DDNSUpdateError
388 class DDNSProviderDNSpark(DDNSProvider
):
389 handle
= "dnspark.com"
391 website
= "http://dnspark.com/"
392 protocols
= ("ipv4",)
394 # Informations to the used api can be found here:
395 # https://dnspark.zendesk.com/entries/31229348-Dynamic-DNS-API-Documentation
397 url
= "https://control.dnspark.com/api/dynamic/update.php"
401 "domain" : self
.hostname
,
402 "ip" : self
.get_address("ipv4"),
405 # Send update to the server.
406 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
409 # Get the full response message.
410 output
= response
.read()
412 # Handle success messages.
413 if output
.startswith("ok") or output
.startswith("nochange"):
416 # Handle error codes.
417 if output
== "unauth":
418 raise DDNSAuthenticationError
419 elif output
== "abuse":
421 elif output
== "blocked":
422 raise DDNSBlockedError
423 elif output
== "nofqdn":
424 raise DDNSRequestError(_("No valid FQDN was given."))
425 elif output
== "nohost":
426 raise DDNSRequestError(_("Invalid hostname specified."))
427 elif output
== "notdyn":
428 raise DDNSRequestError(_("Hostname not marked as a dynamic host."))
429 elif output
== "invalid":
430 raise DDNSRequestError(_("Invalid IP address has been sent."))
432 # If we got here, some other update error happened.
433 raise DDNSUpdateError
436 class DDNSProviderDtDNS(DDNSProvider
):
439 website
= "http://dtdns.com/"
440 protocols
= ("ipv4",)
442 # Information about the format of the HTTPS request is to be found
443 # http://www.dtdns.com/dtsite/updatespec
445 url
= "https://www.dtdns.com/api/autodns.cfm"
449 "ip" : self
.get_address("ipv4"),
450 "id" : self
.hostname
,
454 # Send update to the server.
455 response
= self
.send_request(self
.url
, data
=data
)
457 # Get the full response message.
458 output
= response
.read()
460 # Remove all leading and trailing whitespace.
461 output
= output
.strip()
463 # Handle success messages.
464 if "now points to" in output
:
467 # Handle error codes.
468 if output
== "No hostname to update was supplied.":
469 raise DDNSRequestError(_("No hostname specified."))
471 elif output
== "The hostname you supplied is not valid.":
472 raise DDNSRequestError(_("Invalid hostname specified."))
474 elif output
== "The password you supplied is not valid.":
475 raise DDNSAuthenticationError
477 elif output
== "Administration has disabled this account.":
478 raise DDNSRequestError(_("Account has been disabled."))
480 elif output
== "Illegal character in IP.":
481 raise DDNSRequestError(_("Invalid IP address has been sent."))
483 elif output
== "Too many failed requests.":
484 raise DDNSRequestError(_("Too many failed requests."))
486 # If we got here, some other update error happened.
487 raise DDNSUpdateError
490 class DDNSProviderDynDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
491 handle
= "dyndns.org"
493 website
= "http://dyn.com/dns/"
494 protocols
= ("ipv4",)
496 # Information about the format of the request is to be found
497 # http://http://dyn.com/support/developers/api/perform-update/
498 # http://dyn.com/support/developers/api/return-codes/
500 url
= "https://members.dyndns.org/nic/update"
503 class DDNSProviderDynU(DDNSProtocolDynDNS2
, DDNSProvider
):
506 website
= "http://dynu.com/"
507 protocols
= ("ipv6", "ipv4",)
509 # Detailed information about the request and response codes
510 # are available on the providers webpage.
511 # http://dynu.com/Default.aspx?page=dnsapi
513 url
= "https://api.dynu.com/nic/update"
515 def _prepare_request_data(self
):
516 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
518 # This one supports IPv6
519 myipv6
= self
.get_address("ipv6")
521 # Add update information if we have an IPv6 address.
523 data
["myipv6"] = myipv6
528 class DDNSProviderEasyDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
529 handle
= "easydns.com"
531 website
= "http://www.easydns.com/"
532 protocols
= ("ipv4",)
534 # There is only some basic documentation provided by the vendor,
535 # also searching the web gain very poor results.
536 # http://mediawiki.easydns.com/index.php/Dynamic_DNS
538 url
= "http://api.cp.easydns.com/dyn/tomato.php"
541 class DDNSProviderEnomCom(DDNSResponseParserXML
, DDNSProvider
):
544 website
= "http://www.enom.com/"
546 # There are very detailed information about how to send an update request and
548 # http://www.enom.com/APICommandCatalog/
550 url
= "https://dynamic.name-services.com/interface.asp"
554 "command" : "setdnshost",
555 "responsetype" : "xml",
556 "address" : self
.get_address("ipv4"),
557 "domainpassword" : self
.password
,
558 "zone" : self
.hostname
561 # Send update to the server.
562 response
= self
.send_request(self
.url
, data
=data
)
564 # Get the full response message.
565 output
= response
.read()
567 # Handle success messages.
568 if self
.get_xml_tag_value(output
, "ErrCount") == "0":
571 # Handle error codes.
572 errorcode
= self
.get_xml_tag_value(output
, "ResponseNumber")
574 if errorcode
== "304155":
575 raise DDNSAuthenticationError
576 elif errorcode
== "304153":
577 raise DDNSRequestError(_("Domain not found."))
579 # If we got here, some other update error happened.
580 raise DDNSUpdateError
583 class DDNSProviderEntryDNS(DDNSProvider
):
584 handle
= "entrydns.net"
586 website
= "http://entrydns.net/"
587 protocols
= ("ipv4",)
589 # Some very tiny details about their so called "Simple API" can be found
590 # here: https://entrydns.net/help
591 url
= "https://entrydns.net/records/modify"
595 "ip" : self
.get_address("ipv4")
598 # Add auth token to the update url.
599 url
= "%s/%s" % (self
.url
, self
.token
)
601 # Send update to the server.
603 response
= self
.send_request(url
, data
=data
)
606 except urllib2
.HTTPError
, e
:
608 raise DDNSAuthenticationError
611 raise DDNSRequestError(_("An invalid IP address was submitted"))
615 # Handle success messages.
616 if response
.code
== 200:
619 # If we got here, some other update error happened.
620 raise DDNSUpdateError
623 class DDNSProviderFreeDNSAfraidOrg(DDNSProvider
):
624 handle
= "freedns.afraid.org"
625 name
= "freedns.afraid.org"
626 website
= "http://freedns.afraid.org/"
628 # No information about the request or response could be found on the vendor
629 # page. All used values have been collected by testing.
630 url
= "https://freedns.afraid.org/dynamic/update.php"
634 return self
.get("proto")
637 address
= self
.get_address(self
.proto
)
643 # Add auth token to the update url.
644 url
= "%s?%s" % (self
.url
, self
.token
)
646 # Send update to the server.
647 response
= self
.send_request(url
, data
=data
)
649 # Get the full response message.
650 output
= response
.read()
652 # Handle success messages.
653 if output
.startswith("Updated") or "has not changed" in output
:
656 # Handle error codes.
657 if output
== "ERROR: Unable to locate this record":
658 raise DDNSAuthenticationError
659 elif "is an invalid IP address" in output
:
660 raise DDNSRequestError(_("Invalid IP address has been sent."))
662 # If we got here, some other update error happened.
663 raise DDNSUpdateError
666 class DDNSProviderLightningWireLabs(DDNSProvider
):
667 handle
= "dns.lightningwirelabs.com"
668 name
= "Lightning Wire Labs DNS Service"
669 website
= "http://dns.lightningwirelabs.com/"
671 # Information about the format of the HTTPS request is to be found
672 # https://dns.lightningwirelabs.com/knowledge-base/api/ddns
674 url
= "https://dns.lightningwirelabs.com/update"
678 "hostname" : self
.hostname
,
679 "address6" : self
.get_address("ipv6", "-"),
680 "address4" : self
.get_address("ipv4", "-"),
683 # Check if a token has been set.
685 data
["token"] = self
.token
687 # Check for username and password.
688 elif self
.username
and self
.password
:
690 "username" : self
.username
,
691 "password" : self
.password
,
694 # Raise an error if no auth details are given.
696 raise DDNSConfigurationError
698 # Send update to the server.
699 response
= self
.send_request(self
.url
, data
=data
)
701 # Handle success messages.
702 if response
.code
== 200:
705 # If we got here, some other update error happened.
706 raise DDNSUpdateError
709 class DDNSProviderNamecheap(DDNSResponseParserXML
, DDNSProvider
):
710 handle
= "namecheap.com"
712 website
= "http://namecheap.com"
713 protocols
= ("ipv4",)
715 # Information about the format of the HTTP request is to be found
716 # https://www.namecheap.com/support/knowledgebase/article.aspx/9249/0/nc-dynamic-dns-to-dyndns-adapter
717 # https://community.namecheap.com/forums/viewtopic.php?f=6&t=6772
719 url
= "https://dynamicdns.park-your-domain.com/update"
722 # Namecheap requires the hostname splitted into a host and domain part.
723 host
, domain
= self
.hostname
.split(".", 1)
726 "ip" : self
.get_address("ipv4"),
727 "password" : self
.password
,
732 # Send update to the server.
733 response
= self
.send_request(self
.url
, data
=data
)
735 # Get the full response message.
736 output
= response
.read()
738 # Handle success messages.
739 if self
.get_xml_tag_value(output
, "IP") == self
.get_address("ipv4"):
742 # Handle error codes.
743 errorcode
= self
.get_xml_tag_value(output
, "ResponseNumber")
745 if errorcode
== "304156":
746 raise DDNSAuthenticationError
747 elif errorcode
== "316153":
748 raise DDNSRequestError(_("Domain not found."))
749 elif errorcode
== "316154":
750 raise DDNSRequestError(_("Domain not active."))
751 elif errorcode
in ("380098", "380099"):
752 raise DDNSInternalServerError
754 # If we got here, some other update error happened.
755 raise DDNSUpdateError
758 class DDNSProviderNOIP(DDNSProtocolDynDNS2
, DDNSProvider
):
761 website
= "http://www.no-ip.com/"
762 protocols
= ("ipv4",)
764 # Information about the format of the HTTP request is to be found
765 # here: http://www.no-ip.com/integrate/request and
766 # here: http://www.no-ip.com/integrate/response
768 url
= "http://dynupdate.no-ip.com/nic/update"
770 def _prepare_request_data(self
):
772 "hostname" : self
.hostname
,
773 "address" : self
.get_address("ipv4"),
779 class DDNSProviderNsupdateINFO(DDNSProtocolDynDNS2
, DDNSProvider
):
780 handle
= "nsupdate.info"
781 name
= "nsupdate.info"
782 website
= "http://www.nsupdate.info/"
783 protocols
= ("ipv6", "ipv4",)
785 # Information about the format of the HTTP request can be found
786 # after login on the provider user intrface and here:
787 # http://nsupdateinfo.readthedocs.org/en/latest/user.html
789 # Nsupdate.info uses the hostname as user part for the HTTP basic auth,
790 # and for the password a so called secret.
793 return self
.get("hostname")
797 return self
.get("secret")
801 return self
.get("proto")
805 # The update URL is different by the used protocol.
806 if self
.proto
== "ipv4":
807 return "https://ipv4.nsupdate.info/nic/update"
808 elif self
.proto
== "ipv6":
809 return "https://ipv6.nsupdate.info/nic/update"
811 raise DDNSUpdateError(_("Invalid protocol has been given"))
813 def _prepare_request_data(self
):
815 "myip" : self
.get_address(self
.proto
),
821 class DDNSProviderOpenDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
822 handle
= "opendns.com"
824 website
= "http://www.opendns.com"
826 # Detailed information about the update request and possible
827 # response codes can be obtained from here:
828 # https://support.opendns.com/entries/23891440
830 url
= "https://updates.opendns.com/nic/update"
834 return self
.get("proto")
836 def _prepare_request_data(self
):
838 "hostname" : self
.hostname
,
839 "myip" : self
.get_address(self
.proto
)
845 class DDNSProviderOVH(DDNSProtocolDynDNS2
, DDNSProvider
):
848 website
= "http://www.ovh.com/"
849 protocols
= ("ipv4",)
851 # OVH only provides very limited information about how to
852 # update a DynDNS host. They only provide the update url
853 # on the their german subpage.
855 # http://hilfe.ovh.de/DomainDynHost
857 url
= "https://www.ovh.com/nic/update"
859 def _prepare_request_data(self
):
860 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
868 class DDNSProviderRegfish(DDNSProvider
):
869 handle
= "regfish.com"
870 name
= "Regfish GmbH"
871 website
= "http://www.regfish.com/"
873 # A full documentation to the providers api can be found here
874 # but is only available in german.
875 # https://www.regfish.de/domains/dyndns/dokumentation
877 url
= "https://dyndns.regfish.de/"
881 "fqdn" : self
.hostname
,
884 # Check if we update an IPv6 address.
885 address6
= self
.get_address("ipv6")
887 data
["ipv6"] = address6
889 # Check if we update an IPv4 address.
890 address4
= self
.get_address("ipv4")
892 data
["ipv4"] = address4
894 # Raise an error if none address is given.
895 if not data
.has_key("ipv6") and not data
.has_key("ipv4"):
896 raise DDNSConfigurationError
898 # Check if a token has been set.
900 data
["token"] = self
.token
902 # Raise an error if no token and no useranem and password
904 elif not self
.username
and not self
.password
:
905 raise DDNSConfigurationError(_("No Auth details specified."))
907 # HTTP Basic Auth is only allowed if no token is used.
909 # Send update to the server.
910 response
= self
.send_request(self
.url
, data
=data
)
912 # Send update to the server.
913 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
916 # Get the full response message.
917 output
= response
.read()
919 # Handle success messages.
920 if "100" in output
or "101" in output
:
923 # Handle error codes.
924 if "401" or "402" in output
:
925 raise DDNSAuthenticationError
926 elif "408" in output
:
927 raise DDNSRequestError(_("Invalid IPv4 address has been sent."))
928 elif "409" in output
:
929 raise DDNSRequestError(_("Invalid IPv6 address has been sent."))
930 elif "412" in output
:
931 raise DDNSRequestError(_("No valid FQDN was given."))
932 elif "414" in output
:
933 raise DDNSInternalServerError
935 # If we got here, some other update error happened.
936 raise DDNSUpdateError
939 class DDNSProviderSelfhost(DDNSProtocolDynDNS2
, DDNSProvider
):
940 handle
= "selfhost.de"
942 website
= "http://www.selfhost.de/"
943 protocols
= ("ipv4",)
945 url
= "https://carol.selfhost.de/nic/update"
947 def _prepare_request_data(self
):
948 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
956 class DDNSProviderSPDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
959 website
= "http://spdns.org/"
960 protocols
= ("ipv4",)
962 # Detailed information about request and response codes are provided
963 # by the vendor. They are using almost the same mechanism and status
964 # codes as dyndns.org so we can inherit all those stuff.
966 # http://wiki.securepoint.de/index.php/SPDNS_FAQ
967 # http://wiki.securepoint.de/index.php/SPDNS_Update-Tokens
969 url
= "https://update.spdns.de/nic/update"
972 class DDNSProviderStrato(DDNSProtocolDynDNS2
, DDNSProvider
):
973 handle
= "strato.com"
975 website
= "http:/www.strato.com/"
976 protocols
= ("ipv4",)
978 # Information about the request and response can be obtained here:
979 # http://www.strato-faq.de/article/671/So-einfach-richten-Sie-DynDNS-f%C3%BCr-Ihre-Domains-ein.html
981 url
= "https://dyndns.strato.com/nic/update"
984 class DDNSProviderTwoDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
987 website
= "http://www.twodns.de"
988 protocols
= ("ipv4",)
990 # Detailed information about the request can be found here
991 # http://twodns.de/en/faqs
992 # http://twodns.de/en/api
994 url
= "https://update.twodns.de/update"
996 def _prepare_request_data(self
):
998 "ip" : self
.get_address("ipv4"),
999 "hostname" : self
.hostname
1005 class DDNSProviderUdmedia(DDNSProtocolDynDNS2
, DDNSProvider
):
1006 handle
= "udmedia.de"
1007 name
= "Udmedia GmbH"
1008 website
= "http://www.udmedia.de"
1009 protocols
= ("ipv4",)
1011 # Information about the request can be found here
1012 # http://www.udmedia.de/faq/content/47/288/de/wie-lege-ich-einen-dyndns_eintrag-an.html
1014 url
= "https://www.udmedia.de/nic/update"
1017 class DDNSProviderVariomedia(DDNSProtocolDynDNS2
, DDNSProvider
):
1018 handle
= "variomedia.de"
1020 website
= "http://www.variomedia.de/"
1021 protocols
= ("ipv6", "ipv4",)
1023 # Detailed information about the request can be found here
1024 # https://dyndns.variomedia.de/
1026 url
= "https://dyndns.variomedia.de/nic/update"
1030 return self
.get("proto")
1032 def _prepare_request_data(self
):
1034 "hostname" : self
.hostname
,
1035 "myip" : self
.get_address(self
.proto
)
1041 class DDNSProviderZoneedit(DDNSProtocolDynDNS2
, DDNSProvider
):
1042 handle
= "zoneedit.com"
1044 website
= "http://www.zoneedit.com"
1045 protocols
= ("ipv4",)
1047 # Detailed information about the request and the response codes can be
1049 # http://www.zoneedit.com/doc/api/other.html
1050 # http://www.zoneedit.com/faq.html
1052 url
= "https://dynamic.zoneedit.com/auth/dynamic.html"
1056 return self
.get("proto")
1060 "dnsto" : self
.get_address(self
.proto
),
1061 "host" : self
.hostname
1064 # Send update to the server.
1065 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
1068 # Get the full response message.
1069 output
= response
.read()
1071 # Handle success messages.
1072 if output
.startswith("<SUCCESS"):
1075 # Handle error codes.
1076 if output
.startswith("invalid login"):
1077 raise DDNSAuthenticationError
1078 elif output
.startswith("<ERROR CODE=\"704\""):
1079 raise DDNSRequestError(_("No valid FQDN was given."))
1080 elif output
.startswith("<ERROR CODE=\"702\""):
1081 raise DDNSInternalServerError
1083 # If we got here, some other update error happened.
1084 raise DDNSUpdateError