]>
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
== "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 DDNSProviderEnomCom(DDNSResponseParserXML
, DDNSProvider
):
562 website
= "http://www.enom.com/"
564 # There are very detailed information about how to send an update request and
566 # http://www.enom.com/APICommandCatalog/
568 url
= "https://dynamic.name-services.com/interface.asp"
572 "command" : "setdnshost",
573 "responsetype" : "xml",
574 "address" : self
.get_address("ipv4"),
575 "domainpassword" : self
.password
,
576 "zone" : self
.hostname
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 self
.get_xml_tag_value(output
, "ErrCount") == "0":
589 # Handle error codes.
590 errorcode
= self
.get_xml_tag_value(output
, "ResponseNumber")
592 if errorcode
== "304155":
593 raise DDNSAuthenticationError
594 elif errorcode
== "304153":
595 raise DDNSRequestError(_("Domain not found."))
597 # If we got here, some other update error happened.
598 raise DDNSUpdateError
601 class DDNSProviderEntryDNS(DDNSProvider
):
602 handle
= "entrydns.net"
604 website
= "http://entrydns.net/"
605 protocols
= ("ipv4",)
607 # Some very tiny details about their so called "Simple API" can be found
608 # here: https://entrydns.net/help
609 url
= "https://entrydns.net/records/modify"
613 "ip" : self
.get_address("ipv4")
616 # Add auth token to the update url.
617 url
= "%s/%s" % (self
.url
, self
.token
)
619 # Send update to the server.
621 response
= self
.send_request(url
, data
=data
)
624 except urllib2
.HTTPError
, e
:
626 raise DDNSAuthenticationError
629 raise DDNSRequestError(_("An invalid IP address was submitted"))
633 # Handle success messages.
634 if response
.code
== 200:
637 # If we got here, some other update error happened.
638 raise DDNSUpdateError
641 class DDNSProviderFreeDNSAfraidOrg(DDNSProvider
):
642 handle
= "freedns.afraid.org"
643 name
= "freedns.afraid.org"
644 website
= "http://freedns.afraid.org/"
646 # No information about the request or response could be found on the vendor
647 # page. All used values have been collected by testing.
648 url
= "https://freedns.afraid.org/dynamic/update.php"
652 return self
.get("proto")
655 address
= self
.get_address(self
.proto
)
661 # Add auth token to the update url.
662 url
= "%s?%s" % (self
.url
, self
.token
)
664 # Send update to the server.
665 response
= self
.send_request(url
, data
=data
)
667 # Get the full response message.
668 output
= response
.read()
670 # Handle success messages.
671 if output
.startswith("Updated") or "has not changed" in output
:
674 # Handle error codes.
675 if output
== "ERROR: Unable to locate this record":
676 raise DDNSAuthenticationError
677 elif "is an invalid IP address" in output
:
678 raise DDNSRequestError(_("Invalid IP address has been sent."))
680 # If we got here, some other update error happened.
681 raise DDNSUpdateError
684 class DDNSProviderLightningWireLabs(DDNSProvider
):
685 handle
= "dns.lightningwirelabs.com"
686 name
= "Lightning Wire Labs DNS Service"
687 website
= "http://dns.lightningwirelabs.com/"
689 # Information about the format of the HTTPS request is to be found
690 # https://dns.lightningwirelabs.com/knowledge-base/api/ddns
692 url
= "https://dns.lightningwirelabs.com/update"
696 "hostname" : self
.hostname
,
697 "address6" : self
.get_address("ipv6", "-"),
698 "address4" : self
.get_address("ipv4", "-"),
701 # Check if a token has been set.
703 data
["token"] = self
.token
705 # Check for username and password.
706 elif self
.username
and self
.password
:
708 "username" : self
.username
,
709 "password" : self
.password
,
712 # Raise an error if no auth details are given.
714 raise DDNSConfigurationError
716 # Send update to the server.
717 response
= self
.send_request(self
.url
, data
=data
)
719 # Handle success messages.
720 if response
.code
== 200:
723 # If we got here, some other update error happened.
724 raise DDNSUpdateError
727 class DDNSProviderNamecheap(DDNSResponseParserXML
, DDNSProvider
):
728 handle
= "namecheap.com"
730 website
= "http://namecheap.com"
731 protocols
= ("ipv4",)
733 # Information about the format of the HTTP request is to be found
734 # https://www.namecheap.com/support/knowledgebase/article.aspx/9249/0/nc-dynamic-dns-to-dyndns-adapter
735 # https://community.namecheap.com/forums/viewtopic.php?f=6&t=6772
737 url
= "https://dynamicdns.park-your-domain.com/update"
740 # Namecheap requires the hostname splitted into a host and domain part.
741 host
, domain
= self
.hostname
.split(".", 1)
744 "ip" : self
.get_address("ipv4"),
745 "password" : self
.password
,
750 # Send update to the server.
751 response
= self
.send_request(self
.url
, data
=data
)
753 # Get the full response message.
754 output
= response
.read()
756 # Handle success messages.
757 if self
.get_xml_tag_value(output
, "IP") == self
.get_address("ipv4"):
760 # Handle error codes.
761 errorcode
= self
.get_xml_tag_value(output
, "ResponseNumber")
763 if errorcode
== "304156":
764 raise DDNSAuthenticationError
765 elif errorcode
== "316153":
766 raise DDNSRequestError(_("Domain not found."))
767 elif errorcode
== "316154":
768 raise DDNSRequestError(_("Domain not active."))
769 elif errorcode
in ("380098", "380099"):
770 raise DDNSInternalServerError
772 # If we got here, some other update error happened.
773 raise DDNSUpdateError
776 class DDNSProviderNOIP(DDNSProtocolDynDNS2
, DDNSProvider
):
779 website
= "http://www.no-ip.com/"
780 protocols
= ("ipv4",)
782 # Information about the format of the HTTP request is to be found
783 # here: http://www.no-ip.com/integrate/request and
784 # here: http://www.no-ip.com/integrate/response
786 url
= "http://dynupdate.no-ip.com/nic/update"
788 def _prepare_request_data(self
):
790 "hostname" : self
.hostname
,
791 "address" : self
.get_address("ipv4"),
797 class DDNSProviderNsupdateINFO(DDNSProtocolDynDNS2
, DDNSProvider
):
798 handle
= "nsupdate.info"
799 name
= "nsupdate.info"
800 website
= "http://www.nsupdate.info/"
801 protocols
= ("ipv6", "ipv4",)
803 # Information about the format of the HTTP request can be found
804 # after login on the provider user intrface and here:
805 # http://nsupdateinfo.readthedocs.org/en/latest/user.html
807 # Nsupdate.info uses the hostname as user part for the HTTP basic auth,
808 # and for the password a so called secret.
811 return self
.get("hostname")
815 return self
.get("secret")
819 return self
.get("proto")
823 # The update URL is different by the used protocol.
824 if self
.proto
== "ipv4":
825 return "https://ipv4.nsupdate.info/nic/update"
826 elif self
.proto
== "ipv6":
827 return "https://ipv6.nsupdate.info/nic/update"
829 raise DDNSUpdateError(_("Invalid protocol has been given"))
831 def _prepare_request_data(self
):
833 "myip" : self
.get_address(self
.proto
),
839 class DDNSProviderOpenDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
840 handle
= "opendns.com"
842 website
= "http://www.opendns.com"
844 # Detailed information about the update request and possible
845 # response codes can be obtained from here:
846 # https://support.opendns.com/entries/23891440
848 url
= "https://updates.opendns.com/nic/update"
852 return self
.get("proto")
854 def _prepare_request_data(self
):
856 "hostname" : self
.hostname
,
857 "myip" : self
.get_address(self
.proto
)
863 class DDNSProviderOVH(DDNSProtocolDynDNS2
, DDNSProvider
):
866 website
= "http://www.ovh.com/"
867 protocols
= ("ipv4",)
869 # OVH only provides very limited information about how to
870 # update a DynDNS host. They only provide the update url
871 # on the their german subpage.
873 # http://hilfe.ovh.de/DomainDynHost
875 url
= "https://www.ovh.com/nic/update"
877 def _prepare_request_data(self
):
878 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
886 class DDNSProviderRegfish(DDNSProvider
):
887 handle
= "regfish.com"
888 name
= "Regfish GmbH"
889 website
= "http://www.regfish.com/"
891 # A full documentation to the providers api can be found here
892 # but is only available in german.
893 # https://www.regfish.de/domains/dyndns/dokumentation
895 url
= "https://dyndns.regfish.de/"
899 "fqdn" : self
.hostname
,
902 # Check if we update an IPv6 address.
903 address6
= self
.get_address("ipv6")
905 data
["ipv6"] = address6
907 # Check if we update an IPv4 address.
908 address4
= self
.get_address("ipv4")
910 data
["ipv4"] = address4
912 # Raise an error if none address is given.
913 if not data
.has_key("ipv6") and not data
.has_key("ipv4"):
914 raise DDNSConfigurationError
916 # Check if a token has been set.
918 data
["token"] = self
.token
920 # Raise an error if no token and no useranem and password
922 elif not self
.username
and not self
.password
:
923 raise DDNSConfigurationError(_("No Auth details specified."))
925 # HTTP Basic Auth is only allowed if no token is used.
927 # Send update to the server.
928 response
= self
.send_request(self
.url
, data
=data
)
930 # Send update to the server.
931 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
934 # Get the full response message.
935 output
= response
.read()
937 # Handle success messages.
938 if "100" in output
or "101" in output
:
941 # Handle error codes.
942 if "401" or "402" in output
:
943 raise DDNSAuthenticationError
944 elif "408" in output
:
945 raise DDNSRequestError(_("Invalid IPv4 address has been sent."))
946 elif "409" in output
:
947 raise DDNSRequestError(_("Invalid IPv6 address has been sent."))
948 elif "412" in output
:
949 raise DDNSRequestError(_("No valid FQDN was given."))
950 elif "414" in output
:
951 raise DDNSInternalServerError
953 # If we got here, some other update error happened.
954 raise DDNSUpdateError
957 class DDNSProviderSelfhost(DDNSProtocolDynDNS2
, DDNSProvider
):
958 handle
= "selfhost.de"
960 website
= "http://www.selfhost.de/"
961 protocols
= ("ipv4",)
963 url
= "https://carol.selfhost.de/nic/update"
965 def _prepare_request_data(self
):
966 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
974 class DDNSProviderSPDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
977 website
= "http://spdns.org/"
978 protocols
= ("ipv4",)
980 # Detailed information about request and response codes are provided
981 # by the vendor. They are using almost the same mechanism and status
982 # codes as dyndns.org so we can inherit all those stuff.
984 # http://wiki.securepoint.de/index.php/SPDNS_FAQ
985 # http://wiki.securepoint.de/index.php/SPDNS_Update-Tokens
987 url
= "https://update.spdns.de/nic/update"
990 class DDNSProviderStrato(DDNSProtocolDynDNS2
, DDNSProvider
):
991 handle
= "strato.com"
993 website
= "http:/www.strato.com/"
994 protocols
= ("ipv4",)
996 # Information about the request and response can be obtained here:
997 # http://www.strato-faq.de/article/671/So-einfach-richten-Sie-DynDNS-f%C3%BCr-Ihre-Domains-ein.html
999 url
= "https://dyndns.strato.com/nic/update"
1002 class DDNSProviderTwoDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
1003 handle
= "twodns.de"
1005 website
= "http://www.twodns.de"
1006 protocols
= ("ipv4",)
1008 # Detailed information about the request can be found here
1009 # http://twodns.de/en/faqs
1010 # http://twodns.de/en/api
1012 url
= "https://update.twodns.de/update"
1014 def _prepare_request_data(self
):
1016 "ip" : self
.get_address("ipv4"),
1017 "hostname" : self
.hostname
1023 class DDNSProviderUdmedia(DDNSProtocolDynDNS2
, DDNSProvider
):
1024 handle
= "udmedia.de"
1025 name
= "Udmedia GmbH"
1026 website
= "http://www.udmedia.de"
1027 protocols
= ("ipv4",)
1029 # Information about the request can be found here
1030 # http://www.udmedia.de/faq/content/47/288/de/wie-lege-ich-einen-dyndns_eintrag-an.html
1032 url
= "https://www.udmedia.de/nic/update"
1035 class DDNSProviderVariomedia(DDNSProtocolDynDNS2
, DDNSProvider
):
1036 handle
= "variomedia.de"
1038 website
= "http://www.variomedia.de/"
1039 protocols
= ("ipv6", "ipv4",)
1041 # Detailed information about the request can be found here
1042 # https://dyndns.variomedia.de/
1044 url
= "https://dyndns.variomedia.de/nic/update"
1048 return self
.get("proto")
1050 def _prepare_request_data(self
):
1052 "hostname" : self
.hostname
,
1053 "myip" : self
.get_address(self
.proto
)
1059 class DDNSProviderZoneedit(DDNSProtocolDynDNS2
, DDNSProvider
):
1060 handle
= "zoneedit.com"
1062 website
= "http://www.zoneedit.com"
1063 protocols
= ("ipv4",)
1065 # Detailed information about the request and the response codes can be
1067 # http://www.zoneedit.com/doc/api/other.html
1068 # http://www.zoneedit.com/faq.html
1070 url
= "https://dynamic.zoneedit.com/auth/dynamic.html"
1074 return self
.get("proto")
1078 "dnsto" : self
.get_address(self
.proto
),
1079 "host" : self
.hostname
1082 # Send update to the server.
1083 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
1086 # Get the full response message.
1087 output
= response
.read()
1089 # Handle success messages.
1090 if output
.startswith("<SUCCESS"):
1093 # Handle error codes.
1094 if output
.startswith("invalid login"):
1095 raise DDNSAuthenticationError
1096 elif output
.startswith("<ERROR CODE=\"704\""):
1097 raise DDNSRequestError(_("No valid FQDN was given."))
1098 elif output
.startswith("<ERROR CODE=\"702\""):
1099 raise DDNSInternalServerError
1101 # If we got here, some other update error happened.
1102 raise DDNSUpdateError