]>
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
525 "myipv6" : self
.get_address("ipv6"),
531 class DDNSProviderEasyDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
532 handle
= "easydns.com"
534 website
= "http://www.easydns.com/"
535 protocols
= ("ipv4",)
537 # There is only some basic documentation provided by the vendor,
538 # also searching the web gain very poor results.
539 # http://mediawiki.easydns.com/index.php/Dynamic_DNS
541 url
= "http://api.cp.easydns.com/dyn/tomato.php"
544 class DDNSProviderEnomCom(DDNSResponseParserXML
, DDNSProvider
):
547 website
= "http://www.enom.com/"
549 # There are very detailed information about how to send an update request and
551 # http://www.enom.com/APICommandCatalog/
553 url
= "https://dynamic.name-services.com/interface.asp"
557 "command" : "setdnshost",
558 "responsetype" : "xml",
559 "address" : self
.get_address("ipv4"),
560 "domainpassword" : self
.password
,
561 "zone" : self
.hostname
564 # Send update to the server.
565 response
= self
.send_request(self
.url
, data
=data
)
567 # Get the full response message.
568 output
= response
.read()
570 # Handle success messages.
571 if self
.get_xml_tag_value(output
, "ErrCount") == "0":
574 # Handle error codes.
575 errorcode
= self
.get_xml_tag_value(output
, "ResponseNumber")
577 if errorcode
== "304155":
578 raise DDNSAuthenticationError
579 elif errorcode
== "304153":
580 raise DDNSRequestError(_("Domain not found."))
582 # If we got here, some other update error happened.
583 raise DDNSUpdateError
586 class DDNSProviderEntryDNS(DDNSProvider
):
587 handle
= "entrydns.net"
589 website
= "http://entrydns.net/"
590 protocols
= ("ipv4",)
592 # Some very tiny details about their so called "Simple API" can be found
593 # here: https://entrydns.net/help
594 url
= "https://entrydns.net/records/modify"
598 "ip" : self
.get_address("ipv4")
601 # Add auth token to the update url.
602 url
= "%s/%s" % (self
.url
, self
.token
)
604 # Send update to the server.
606 response
= self
.send_request(url
, method
="PUT", data
=data
)
609 except urllib2
.HTTPError
, e
:
611 raise DDNSAuthenticationError
614 raise DDNSRequestError(_("An invalid IP address was submitted"))
618 # Handle success messages.
619 if response
.code
== 200:
622 # If we got here, some other update error happened.
623 raise DDNSUpdateError
626 class DDNSProviderFreeDNSAfraidOrg(DDNSProvider
):
627 handle
= "freedns.afraid.org"
628 name
= "freedns.afraid.org"
629 website
= "http://freedns.afraid.org/"
631 # No information about the request or response could be found on the vendor
632 # page. All used values have been collected by testing.
633 url
= "https://freedns.afraid.org/dynamic/update.php"
637 return self
.get("proto")
640 address
= self
.get_address(self
.proto
)
646 # Add auth token to the update url.
647 url
= "%s?%s" % (self
.url
, self
.token
)
649 # Send update to the server.
650 response
= self
.send_request(url
, data
=data
)
652 # Get the full response message.
653 output
= response
.read()
655 # Handle success messages.
656 if output
.startswith("Updated") or "has not changed" in output
:
659 # Handle error codes.
660 if output
== "ERROR: Unable to locate this record":
661 raise DDNSAuthenticationError
662 elif "is an invalid IP address" in output
:
663 raise DDNSRequestError(_("Invalid IP address has been sent."))
665 # If we got here, some other update error happened.
666 raise DDNSUpdateError
669 class DDNSProviderLightningWireLabs(DDNSProvider
):
670 handle
= "dns.lightningwirelabs.com"
671 name
= "Lightning Wire Labs DNS Service"
672 website
= "http://dns.lightningwirelabs.com/"
674 # Information about the format of the HTTPS request is to be found
675 # https://dns.lightningwirelabs.com/knowledge-base/api/ddns
677 url
= "https://dns.lightningwirelabs.com/update"
681 "hostname" : self
.hostname
,
682 "address6" : self
.get_address("ipv6", "-"),
683 "address4" : self
.get_address("ipv4", "-"),
686 # Check if a token has been set.
688 data
["token"] = self
.token
690 # Check for username and password.
691 elif self
.username
and self
.password
:
693 "username" : self
.username
,
694 "password" : self
.password
,
697 # Raise an error if no auth details are given.
699 raise DDNSConfigurationError
701 # Send update to the server.
702 response
= self
.send_request(self
.url
, data
=data
)
704 # Handle success messages.
705 if response
.code
== 200:
708 # If we got here, some other update error happened.
709 raise DDNSUpdateError
712 class DDNSProviderNamecheap(DDNSResponseParserXML
, DDNSProvider
):
713 handle
= "namecheap.com"
715 website
= "http://namecheap.com"
716 protocols
= ("ipv4",)
718 # Information about the format of the HTTP request is to be found
719 # https://www.namecheap.com/support/knowledgebase/article.aspx/9249/0/nc-dynamic-dns-to-dyndns-adapter
720 # https://community.namecheap.com/forums/viewtopic.php?f=6&t=6772
722 url
= "https://dynamicdns.park-your-domain.com/update"
725 # Namecheap requires the hostname splitted into a host and domain part.
726 host
, domain
= self
.hostname
.split(".", 1)
729 "ip" : self
.get_address("ipv4"),
730 "password" : self
.password
,
735 # Send update to the server.
736 response
= self
.send_request(self
.url
, data
=data
)
738 # Get the full response message.
739 output
= response
.read()
741 # Handle success messages.
742 if self
.get_xml_tag_value(output
, "IP") == self
.get_address("ipv4"):
745 # Handle error codes.
746 errorcode
= self
.get_xml_tag_value(output
, "ResponseNumber")
748 if errorcode
== "304156":
749 raise DDNSAuthenticationError
750 elif errorcode
== "316153":
751 raise DDNSRequestError(_("Domain not found."))
752 elif errorcode
== "316154":
753 raise DDNSRequestError(_("Domain not active."))
754 elif errorcode
in ("380098", "380099"):
755 raise DDNSInternalServerError
757 # If we got here, some other update error happened.
758 raise DDNSUpdateError
761 class DDNSProviderNOIP(DDNSProtocolDynDNS2
, DDNSProvider
):
764 website
= "http://www.no-ip.com/"
765 protocols
= ("ipv4",)
767 # Information about the format of the HTTP request is to be found
768 # here: http://www.no-ip.com/integrate/request and
769 # here: http://www.no-ip.com/integrate/response
771 url
= "http://dynupdate.no-ip.com/nic/update"
773 def _prepare_request_data(self
):
775 "hostname" : self
.hostname
,
776 "address" : self
.get_address("ipv4"),
782 class DDNSProviderNsupdateINFO(DDNSProtocolDynDNS2
, DDNSProvider
):
783 handle
= "nsupdate.info"
784 name
= "nsupdate.info"
785 website
= "http://www.nsupdate.info/"
786 protocols
= ("ipv6", "ipv4",)
788 # Information about the format of the HTTP request can be found
789 # after login on the provider user intrface and here:
790 # http://nsupdateinfo.readthedocs.org/en/latest/user.html
792 # Nsupdate.info uses the hostname as user part for the HTTP basic auth,
793 # and for the password a so called secret.
796 return self
.get("hostname")
800 return self
.get("secret")
804 return self
.get("proto")
808 # The update URL is different by the used protocol.
809 if self
.proto
== "ipv4":
810 return "https://ipv4.nsupdate.info/nic/update"
811 elif self
.proto
== "ipv6":
812 return "https://ipv6.nsupdate.info/nic/update"
814 raise DDNSUpdateError(_("Invalid protocol has been given"))
816 def _prepare_request_data(self
):
818 "myip" : self
.get_address(self
.proto
),
824 class DDNSProviderOpenDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
825 handle
= "opendns.com"
827 website
= "http://www.opendns.com"
829 # Detailed information about the update request and possible
830 # response codes can be obtained from here:
831 # https://support.opendns.com/entries/23891440
833 url
= "https://updates.opendns.com/nic/update"
837 return self
.get("proto")
839 def _prepare_request_data(self
):
841 "hostname" : self
.hostname
,
842 "myip" : self
.get_address(self
.proto
)
848 class DDNSProviderOVH(DDNSProtocolDynDNS2
, DDNSProvider
):
851 website
= "http://www.ovh.com/"
852 protocols
= ("ipv4",)
854 # OVH only provides very limited information about how to
855 # update a DynDNS host. They only provide the update url
856 # on the their german subpage.
858 # http://hilfe.ovh.de/DomainDynHost
860 url
= "https://www.ovh.com/nic/update"
862 def _prepare_request_data(self
):
863 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
871 class DDNSProviderRegfish(DDNSProvider
):
872 handle
= "regfish.com"
873 name
= "Regfish GmbH"
874 website
= "http://www.regfish.com/"
876 # A full documentation to the providers api can be found here
877 # but is only available in german.
878 # https://www.regfish.de/domains/dyndns/dokumentation
880 url
= "https://dyndns.regfish.de/"
884 "fqdn" : self
.hostname
,
887 # Check if we update an IPv6 address.
888 address6
= self
.get_address("ipv6")
890 data
["ipv6"] = address6
892 # Check if we update an IPv4 address.
893 address4
= self
.get_address("ipv4")
895 data
["ipv4"] = address4
897 # Raise an error if none address is given.
898 if not data
.has_key("ipv6") and not data
.has_key("ipv4"):
899 raise DDNSConfigurationError
901 # Check if a token has been set.
903 data
["token"] = self
.token
905 # Raise an error if no token and no useranem and password
907 elif not self
.username
and not self
.password
:
908 raise DDNSConfigurationError(_("No Auth details specified."))
910 # HTTP Basic Auth is only allowed if no token is used.
912 # Send update to the server.
913 response
= self
.send_request(self
.url
, data
=data
)
915 # Send update to the server.
916 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
919 # Get the full response message.
920 output
= response
.read()
922 # Handle success messages.
923 if "100" in output
or "101" in output
:
926 # Handle error codes.
927 if "401" or "402" in output
:
928 raise DDNSAuthenticationError
929 elif "408" in output
:
930 raise DDNSRequestError(_("Invalid IPv4 address has been sent."))
931 elif "409" in output
:
932 raise DDNSRequestError(_("Invalid IPv6 address has been sent."))
933 elif "412" in output
:
934 raise DDNSRequestError(_("No valid FQDN was given."))
935 elif "414" in output
:
936 raise DDNSInternalServerError
938 # If we got here, some other update error happened.
939 raise DDNSUpdateError
942 class DDNSProviderSelfhost(DDNSProtocolDynDNS2
, DDNSProvider
):
943 handle
= "selfhost.de"
945 website
= "http://www.selfhost.de/"
946 protocols
= ("ipv4",)
948 url
= "https://carol.selfhost.de/nic/update"
950 def _prepare_request_data(self
):
951 data
= DDNSProtocolDynDNS2
._prepare_request_data(self
)
959 class DDNSProviderSPDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
962 website
= "http://spdns.org/"
963 protocols
= ("ipv4",)
965 # Detailed information about request and response codes are provided
966 # by the vendor. They are using almost the same mechanism and status
967 # codes as dyndns.org so we can inherit all those stuff.
969 # http://wiki.securepoint.de/index.php/SPDNS_FAQ
970 # http://wiki.securepoint.de/index.php/SPDNS_Update-Tokens
972 url
= "https://update.spdns.de/nic/update"
975 class DDNSProviderStrato(DDNSProtocolDynDNS2
, DDNSProvider
):
976 handle
= "strato.com"
978 website
= "http:/www.strato.com/"
979 protocols
= ("ipv4",)
981 # Information about the request and response can be obtained here:
982 # http://www.strato-faq.de/article/671/So-einfach-richten-Sie-DynDNS-f%C3%BCr-Ihre-Domains-ein.html
984 url
= "https://dyndns.strato.com/nic/update"
987 class DDNSProviderTwoDNS(DDNSProtocolDynDNS2
, DDNSProvider
):
990 website
= "http://www.twodns.de"
991 protocols
= ("ipv4",)
993 # Detailed information about the request can be found here
994 # http://twodns.de/en/faqs
995 # http://twodns.de/en/api
997 url
= "https://update.twodns.de/update"
999 def _prepare_request_data(self
):
1001 "ip" : self
.get_address("ipv4"),
1002 "hostname" : self
.hostname
1008 class DDNSProviderUdmedia(DDNSProtocolDynDNS2
, DDNSProvider
):
1009 handle
= "udmedia.de"
1010 name
= "Udmedia GmbH"
1011 website
= "http://www.udmedia.de"
1012 protocols
= ("ipv4",)
1014 # Information about the request can be found here
1015 # http://www.udmedia.de/faq/content/47/288/de/wie-lege-ich-einen-dyndns_eintrag-an.html
1017 url
= "https://www.udmedia.de/nic/update"
1020 class DDNSProviderVariomedia(DDNSProtocolDynDNS2
, DDNSProvider
):
1021 handle
= "variomedia.de"
1023 website
= "http://www.variomedia.de/"
1024 protocols
= ("ipv6", "ipv4",)
1026 # Detailed information about the request can be found here
1027 # https://dyndns.variomedia.de/
1029 url
= "https://dyndns.variomedia.de/nic/update"
1033 return self
.get("proto")
1035 def _prepare_request_data(self
):
1037 "hostname" : self
.hostname
,
1038 "myip" : self
.get_address(self
.proto
)
1044 class DDNSProviderZoneedit(DDNSProtocolDynDNS2
, DDNSProvider
):
1045 handle
= "zoneedit.com"
1047 website
= "http://www.zoneedit.com"
1048 protocols
= ("ipv4",)
1050 # Detailed information about the request and the response codes can be
1052 # http://www.zoneedit.com/doc/api/other.html
1053 # http://www.zoneedit.com/faq.html
1055 url
= "https://dynamic.zoneedit.com/auth/dynamic.html"
1059 return self
.get("proto")
1063 "dnsto" : self
.get_address(self
.proto
),
1064 "host" : self
.hostname
1067 # Send update to the server.
1068 response
= self
.send_request(self
.url
, username
=self
.username
, password
=self
.password
,
1071 # Get the full response message.
1072 output
= response
.read()
1074 # Handle success messages.
1075 if output
.startswith("<SUCCESS"):
1078 # Handle error codes.
1079 if output
.startswith("invalid login"):
1080 raise DDNSAuthenticationError
1081 elif output
.startswith("<ERROR CODE=\"704\""):
1082 raise DDNSRequestError(_("No valid FQDN was given."))
1083 elif output
.startswith("<ERROR CODE=\"702\""):
1084 raise DDNSInternalServerError
1086 # If we got here, some other update error happened.
1087 raise DDNSUpdateError