]> git.ipfire.org Git - ddns.git/blame - src/ddns/providers.py
dyndns: Show unhandled server responses in exception.
[ddns.git] / src / ddns / providers.py
CommitLineData
f22ab085 1#!/usr/bin/python
3fdcb9d1
MT
2###############################################################################
3# #
4# ddns - A dynamic DNS client for IPFire #
5# Copyright (C) 2012 IPFire development team #
6# #
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. #
11# #
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. #
16# #
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/>. #
19# #
20###############################################################################
f22ab085 21
7399fc5b 22import logging
3b16fdb1 23import urllib2
d1cd57eb 24import xml.dom.minidom
7399fc5b
MT
25
26from i18n import _
27
f22ab085
MT
28# Import all possible exception types.
29from .errors import *
30
7399fc5b
MT
31logger = logging.getLogger("ddns.providers")
32logger.propagate = 1
33
f22ab085
MT
34class DDNSProvider(object):
35 INFO = {
36 # A short string that uniquely identifies
37 # this provider.
38 "handle" : None,
39
40 # The full name of the provider.
41 "name" : None,
42
43 # A weburl to the homepage of the provider.
44 # (Where to register a new account?)
45 "website" : None,
46
47 # A list of supported protocols.
48 "protocols" : ["ipv6", "ipv4"],
49 }
50
51 DEFAULT_SETTINGS = {}
52
53 def __init__(self, core, **settings):
54 self.core = core
55
56 # Copy a set of default settings and
57 # update them by those from the configuration file.
58 self.settings = self.DEFAULT_SETTINGS.copy()
59 self.settings.update(settings)
60
61 def __repr__(self):
62 return "<DDNS Provider %s (%s)>" % (self.name, self.handle)
63
64 def __cmp__(self, other):
65 return cmp(self.hostname, other.hostname)
66
67 @property
68 def name(self):
69 """
70 Returns the name of the provider.
71 """
72 return self.INFO.get("name")
73
74 @property
75 def website(self):
76 """
77 Returns the website URL of the provider
78 or None if that is not available.
79 """
80 return self.INFO.get("website", None)
81
82 @property
83 def handle(self):
84 """
85 Returns the handle of this provider.
86 """
87 return self.INFO.get("handle")
88
89 def get(self, key, default=None):
90 """
91 Get a setting from the settings dictionary.
92 """
93 return self.settings.get(key, default)
94
95 @property
96 def hostname(self):
97 """
98 Fast access to the hostname.
99 """
100 return self.get("hostname")
101
102 @property
103 def username(self):
104 """
105 Fast access to the username.
106 """
107 return self.get("username")
108
109 @property
110 def password(self):
111 """
112 Fast access to the password.
113 """
114 return self.get("password")
115
7399fc5b
MT
116 @property
117 def protocols(self):
118 return self.INFO.get("protocols")
119
46687828
SS
120 @property
121 def token(self):
122 """
123 Fast access to the token.
124 """
125 return self.get("token")
126
9da3e685
MT
127 def __call__(self, force=False):
128 if force:
129 logger.info(_("Updating %s forced") % self.hostname)
130
7399fc5b 131 # Check if we actually need to update this host.
9da3e685 132 elif self.is_uptodate(self.protocols):
7399fc5b
MT
133 logger.info(_("%s is already up to date") % self.hostname)
134 return
135
136 # Execute the update.
5f402f36
MT
137 self.update()
138
139 def update(self):
f22ab085
MT
140 raise NotImplementedError
141
7399fc5b
MT
142 def is_uptodate(self, protos):
143 """
144 Returns True if this host is already up to date
145 and does not need to change the IP address on the
146 name server.
147 """
148 for proto in protos:
149 addresses = self.core.system.resolve(self.hostname, proto)
150
151 current_address = self.get_address(proto)
152
38d81db4
MT
153 # If no addresses for the given protocol exist, we
154 # are fine...
155 if current_address is None and not addresses:
156 continue
157
7399fc5b
MT
158 if not current_address in addresses:
159 return False
160
161 return True
162
f22ab085
MT
163 def send_request(self, *args, **kwargs):
164 """
165 Proxy connection to the send request
166 method.
167 """
168 return self.core.system.send_request(*args, **kwargs)
169
170 def get_address(self, proto):
171 """
172 Proxy method to get the current IP address.
173 """
174 return self.core.system.get_address(proto)
175
176
3b16fdb1
SS
177class DDNSProviderAllInkl(DDNSProvider):
178 INFO = {
179 "handle" : "all-inkl.com",
180 "name" : "All-inkl.com",
181 "website" : "http://all-inkl.com/",
182 "protocols" : ["ipv4",]
183 }
184
185 # There are only information provided by the vendor how to
186 # perform an update on a FRITZ Box. Grab requried informations
187 # from the net.
188 # http://all-inkl.goetze.it/v01/ddns-mit-einfachen-mitteln/
189
190 url = "http://dyndns.kasserver.com"
191
192 def update(self):
193
194 # There is no additional data required so we directly can
195 # send our request.
196 try:
197 # Send request to the server.
198 response = self.send_request(self.url, username=self.username, password=self.password)
199
200 # Handle 401 HTTP Header (Authentication Error)
201 except urllib2.HTTPError, e:
202 if e.code == 401:
203 raise DDNSAuthenticationError
204
205 raise
206
207 # Get the full response message.
208 output = response.read()
209
210 # Handle success messages.
211 if output.startswith("good") or output.startswith("nochg"):
212 return
213
214 # If we got here, some other update error happened.
215 raise DDNSUpdateError
216
217
f3cf1f70
SS
218class DDNSProviderDHS(DDNSProvider):
219 INFO = {
220 "handle" : "dhs.org",
221 "name" : "DHS International",
222 "website" : "http://dhs.org/",
223 "protocols" : ["ipv4",]
224 }
225
226 # No information about the used update api provided on webpage,
227 # grabed from source code of ez-ipudate.
228 url = "http://members.dhs.org/nic/hosts"
229
5f402f36 230 def update(self):
f3cf1f70
SS
231 data = {
232 "domain" : self.hostname,
233 "ip" : self.get_address("ipv4"),
234 "hostcmd" : "edit",
235 "hostcmdstage" : "2",
236 "type" : "4",
237 }
238
239 # Send update to the server.
175c9b80 240 response = self.send_request(self.url, username=self.username, password=self.password,
f3cf1f70
SS
241 data=data)
242
243 # Handle success messages.
244 if response.code == 200:
245 return
246
247 # Handle error codes.
4caed6ed 248 elif response.code == 401:
f3cf1f70
SS
249 raise DDNSAuthenticationError
250
251 # If we got here, some other update error happened.
252 raise DDNSUpdateError
253
254
39301272
SS
255class DDNSProviderDNSpark(DDNSProvider):
256 INFO = {
257 "handle" : "dnspark.com",
258 "name" : "DNS Park",
259 "website" : "http://dnspark.com/",
260 "protocols" : ["ipv4",]
261 }
262
263 # Informations to the used api can be found here:
264 # https://dnspark.zendesk.com/entries/31229348-Dynamic-DNS-API-Documentation
265 url = "https://control.dnspark.com/api/dynamic/update.php"
266
5f402f36 267 def update(self):
39301272
SS
268 data = {
269 "domain" : self.hostname,
270 "ip" : self.get_address("ipv4"),
271 }
272
273 # Send update to the server.
175c9b80 274 response = self.send_request(self.url, username=self.username, password=self.password,
39301272
SS
275 data=data)
276
277 # Get the full response message.
278 output = response.read()
279
280 # Handle success messages.
281 if output.startswith("ok") or output.startswith("nochange"):
282 return
283
284 # Handle error codes.
285 if output == "unauth":
286 raise DDNSAuthenticationError
287 elif output == "abuse":
288 raise DDNSAbuseError
289 elif output == "blocked":
290 raise DDNSBlockedError
291 elif output == "nofqdn":
292 raise DDNSRequestError(_("No valid FQDN was given."))
293 elif output == "nohost":
294 raise DDNSRequestError(_("Invalid hostname specified."))
295 elif output == "notdyn":
296 raise DDNSRequestError(_("Hostname not marked as a dynamic host."))
297 elif output == "invalid":
298 raise DDNSRequestError(_("Invalid IP address has been sent."))
299
300 # If we got here, some other update error happened.
301 raise DDNSUpdateError
302
43b2cd59
SS
303
304class DDNSProviderDtDNS(DDNSProvider):
305 INFO = {
306 "handle" : "dtdns.com",
307 "name" : "DtDNS",
308 "website" : "http://dtdns.com/",
309 "protocols" : ["ipv4",]
310 }
311
312 # Information about the format of the HTTPS request is to be found
313 # http://www.dtdns.com/dtsite/updatespec
314 url = "https://www.dtdns.com/api/autodns.cfm"
315
43b2cd59
SS
316 def update(self):
317 data = {
318 "ip" : self.get_address("ipv4"),
319 "id" : self.hostname,
320 "pw" : self.password
321 }
322
323 # Send update to the server.
324 response = self.send_request(self.url, data=data)
325
326 # Get the full response message.
327 output = response.read()
328
329 # Remove all leading and trailing whitespace.
330 output = output.strip()
331
332 # Handle success messages.
333 if "now points to" in output:
334 return
335
336 # Handle error codes.
337 if output == "No hostname to update was supplied.":
338 raise DDNSRequestError(_("No hostname specified."))
339
340 elif output == "The hostname you supplied is not valid.":
341 raise DDNSRequestError(_("Invalid hostname specified."))
342
343 elif output == "The password you supplied is not valid.":
344 raise DDNSAuthenticationError
345
346 elif output == "Administration has disabled this account.":
347 raise DDNSRequestError(_("Account has been disabled."))
348
349 elif output == "Illegal character in IP.":
350 raise DDNSRequestError(_("Invalid IP address has been sent."))
351
352 elif output == "Too many failed requests.":
353 raise DDNSRequestError(_("Too many failed requests."))
354
355 # If we got here, some other update error happened.
356 raise DDNSUpdateError
357
358
bfed6701
SS
359class DDNSProviderDynDNS(DDNSProvider):
360 INFO = {
361 "handle" : "dyndns.org",
362 "name" : "Dyn",
363 "website" : "http://dyn.com/dns/",
364 "protocols" : ["ipv4",]
365 }
366
367 # Information about the format of the request is to be found
368 # http://http://dyn.com/support/developers/api/perform-update/
369 # http://dyn.com/support/developers/api/return-codes/
370 url = "https://members.dyndns.org/nic/update"
371
88f39629 372 def _prepare_request_data(self):
bfed6701
SS
373 data = {
374 "hostname" : self.hostname,
375 "myip" : self.get_address("ipv4"),
376 }
377
88f39629
SS
378 return data
379
380 def update(self):
381 data = self._prepare_request_data()
382
bfed6701 383 # Send update to the server.
88f39629
SS
384 response = self.send_request(self.url, data=data,
385 username=self.username, password=self.password)
bfed6701
SS
386
387 # Get the full response message.
388 output = response.read()
389
390 # Handle success messages.
391 if output.startswith("good") or output.startswith("nochg"):
392 return
393
394 # Handle error codes.
395 if output == "badauth":
396 raise DDNSAuthenticationError
397 elif output == "aduse":
398 raise DDNSAbuseError
399 elif output == "notfqdn":
400 raise DDNSRequestError(_("No valid FQDN was given."))
401 elif output == "nohost":
402 raise DDNSRequestError(_("Specified host does not exist."))
403 elif output == "911":
404 raise DDNSInternalServerError
405 elif output == "dnserr":
406 raise DDNSInternalServerError(_("DNS error encountered."))
407
408 # If we got here, some other update error happened.
0271a97f 409 raise DDNSUpdateError(_("Server response: %s") % output)
bfed6701
SS
410
411
3a8407fa
SS
412class DDNSProviderDynU(DDNSProviderDynDNS):
413 INFO = {
414 "handle" : "dynu.com",
415 "name" : "Dynu",
416 "website" : "http://dynu.com/",
417 "protocols" : ["ipv6", "ipv4",]
418 }
419
420
421 # Detailed information about the request and response codes
422 # are available on the providers webpage.
423 # http://dynu.com/Default.aspx?page=dnsapi
424
425 url = "https://api.dynu.com/nic/update"
426
427 def _prepare_request_data(self):
54d3efc8
MT
428 data = DDNSProviderDynDNS._prepare_request_data(self)
429
430 # This one supports IPv6
431 data.update({
3a8407fa 432 "myipv6" : self.get_address("ipv6"),
54d3efc8
MT
433 })
434
435 return data
3a8407fa
SS
436
437
ee071271
SS
438class DDNSProviderEasyDNS(DDNSProviderDynDNS):
439 INFO = {
440 "handle" : "easydns.com",
441 "name" : "EasyDNS",
442 "website" : "http://www.easydns.com/",
443 "protocols" : ["ipv4",]
444 }
445
446 # There is only some basic documentation provided by the vendor,
447 # also searching the web gain very poor results.
448 # http://mediawiki.easydns.com/index.php/Dynamic_DNS
449
450 url = "http://api.cp.easydns.com/dyn/tomato.php"
451
452
aa21a4c6
SS
453class DDNSProviderFreeDNSAfraidOrg(DDNSProvider):
454 INFO = {
455 "handle" : "freedns.afraid.org",
456 "name" : "freedns.afraid.org",
457 "website" : "http://freedns.afraid.org/",
458 "protocols" : ["ipv6", "ipv4",]
459 }
460
461 # No information about the request or response could be found on the vendor
462 # page. All used values have been collected by testing.
463 url = "https://freedns.afraid.org/dynamic/update.php"
464
465 @property
466 def proto(self):
467 return self.get("proto")
468
469 def update(self):
470 address = self.get_address(self.proto)
471
472 data = {
473 "address" : address,
474 }
475
476 # Add auth token to the update url.
477 url = "%s?%s" % (self.url, self.token)
478
479 # Send update to the server.
480 response = self.send_request(url, data=data)
481
aa21a4c6
SS
482 if output.startswith("Updated") or "has not changed" in output:
483 return
484
485 # Handle error codes.
486 if output == "ERROR: Unable to locate this record":
487 raise DDNSAuthenticationError
488 elif "is an invalid IP address" in output:
489 raise DDNSRequestError(_("Invalid IP address has been sent."))
490
aa21a4c6 491
a08c1b72
SS
492class DDNSProviderLightningWireLabs(DDNSProvider):
493 INFO = {
494 "handle" : "dns.lightningwirelabs.com",
495 "name" : "Lightning Wire Labs",
496 "website" : "http://dns.lightningwirelabs.com/",
497 "protocols" : ["ipv6", "ipv4",]
498 }
499
500 # Information about the format of the HTTPS request is to be found
501 # https://dns.lightningwirelabs.com/knowledge-base/api/ddns
502 url = "https://dns.lightningwirelabs.com/update"
503
5f402f36 504 def update(self):
a08c1b72
SS
505 data = {
506 "hostname" : self.hostname,
507 }
508
509 # Check if we update an IPv6 address.
510 address6 = self.get_address("ipv6")
511 if address6:
512 data["address6"] = address6
513
514 # Check if we update an IPv4 address.
515 address4 = self.get_address("ipv4")
516 if address4:
517 data["address4"] = address4
518
519 # Raise an error if none address is given.
520 if not data.has_key("address6") and not data.has_key("address4"):
521 raise DDNSConfigurationError
522
523 # Check if a token has been set.
524 if self.token:
525 data["token"] = self.token
526
527 # Check for username and password.
528 elif self.username and self.password:
529 data.update({
530 "username" : self.username,
531 "password" : self.password,
532 })
533
534 # Raise an error if no auth details are given.
535 else:
536 raise DDNSConfigurationError
537
538 # Send update to the server.
cb455540 539 response = self.send_request(self.url, data=data)
a08c1b72
SS
540
541 # Handle success messages.
542 if response.code == 200:
543 return
544
545 # Handle error codes.
2e5ad318 546 if response.code == 403:
a08c1b72 547 raise DDNSAuthenticationError
2e5ad318 548 elif response.code == 400:
a08c1b72
SS
549 raise DDNSRequestError
550
551 # If we got here, some other update error happened.
552 raise DDNSUpdateError
553
554
d1cd57eb
SS
555class DDNSProviderNamecheap(DDNSProvider):
556 INFO = {
557 "handle" : "namecheap.com",
558 "name" : "Namecheap",
559 "website" : "http://namecheap.com",
560 "protocols" : ["ipv4",]
561 }
562
563 # Information about the format of the HTTP request is to be found
564 # https://www.namecheap.com/support/knowledgebase/article.aspx/9249/0/nc-dynamic-dns-to-dyndns-adapter
565 # https://community.namecheap.com/forums/viewtopic.php?f=6&t=6772
566
567 url = "https://dynamicdns.park-your-domain.com/update"
568
569 def parse_xml(self, document, content):
570 # Send input to the parser.
571 xmldoc = xml.dom.minidom.parseString(document)
572
573 # Get XML elements by the given content.
574 element = xmldoc.getElementsByTagName(content)
575
576 # If no element has been found, we directly can return None.
577 if not element:
578 return None
579
580 # Only get the first child from an element, even there are more than one.
581 firstchild = element[0].firstChild
582
583 # Get the value of the child.
584 value = firstchild.nodeValue
585
586 # Return the value.
587 return value
588
589 def update(self):
590 # Namecheap requires the hostname splitted into a host and domain part.
591 host, domain = self.hostname.split(".", 1)
592
593 data = {
594 "ip" : self.get_address("ipv4"),
595 "password" : self.password,
596 "host" : host,
597 "domain" : domain
598 }
599
600 # Send update to the server.
601 response = self.send_request(self.url, data=data)
602
603 # Get the full response message.
604 output = response.read()
605
606 # Handle success messages.
607 if self.parse_xml(output, "IP") == self.get_address("ipv4"):
608 return
609
610 # Handle error codes.
611 errorcode = self.parse_xml(output, "ResponseNumber")
612
613 if errorcode == "304156":
614 raise DDNSAuthenticationError
615 elif errorcode == "316153":
616 raise DDNSRequestError(_("Domain not found."))
617 elif errorcode == "316154":
618 raise DDNSRequestError(_("Domain not active."))
619 elif errorcode in ("380098", "380099"):
620 raise DDNSInternalServerError
621
622 # If we got here, some other update error happened.
623 raise DDNSUpdateError
624
625
88f39629 626class DDNSProviderNOIP(DDNSProviderDynDNS):
f22ab085
MT
627 INFO = {
628 "handle" : "no-ip.com",
629 "name" : "No-IP",
630 "website" : "http://www.no-ip.com/",
631 "protocols" : ["ipv4",]
632 }
633
634 # Information about the format of the HTTP request is to be found
635 # here: http://www.no-ip.com/integrate/request and
636 # here: http://www.no-ip.com/integrate/response
637
88f39629 638 url = "http://dynupdate.no-ip.com/nic/update"
2de06f59 639
88f39629 640 def _prepare_request_data(self):
2de06f59
MT
641 data = {
642 "hostname" : self.hostname,
f22ab085
MT
643 "address" : self.get_address("ipv4"),
644 }
645
88f39629 646 return data
f22ab085
MT
647
648
a508bda6
SS
649class DDNSProviderOVH(DDNSProviderDynDNS):
650 INFO = {
651 "handle" : "ovh.com",
652 "name" : "OVH",
653 "website" : "http://www.ovh.com/",
654 "protocols" : ["ipv4",]
655 }
656
657 # OVH only provides very limited information about how to
658 # update a DynDNS host. They only provide the update url
659 # on the their german subpage.
660 #
661 # http://hilfe.ovh.de/DomainDynHost
662
663 url = "https://www.ovh.com/nic/update"
664
665 def _prepare_request_data(self):
54d3efc8
MT
666 data = DDNSProviderDynDNS._prepare_request_data(self)
667 data.update({
668 "system" : "dyndns",
669 })
670
671 return data
a508bda6
SS
672
673
ef33455e
SS
674class DDNSProviderRegfish(DDNSProvider):
675 INFO = {
676 "handle" : "regfish.com",
677 "name" : "Regfish GmbH",
678 "website" : "http://www.regfish.com/",
679 "protocols" : ["ipv6", "ipv4",]
680 }
681
682 # A full documentation to the providers api can be found here
683 # but is only available in german.
684 # https://www.regfish.de/domains/dyndns/dokumentation
685
686 url = "https://dyndns.regfish.de/"
687
688 def update(self):
689 data = {
690 "fqdn" : self.hostname,
691 }
692
693 # Check if we update an IPv6 address.
694 address6 = self.get_address("ipv6")
695 if address6:
696 data["ipv6"] = address6
697
698 # Check if we update an IPv4 address.
699 address4 = self.get_address("ipv4")
700 if address4:
701 data["ipv4"] = address4
702
703 # Raise an error if none address is given.
704 if not data.has_key("ipv6") and not data.has_key("ipv4"):
705 raise DDNSConfigurationError
706
707 # Check if a token has been set.
708 if self.token:
709 data["token"] = self.token
710
711 # Raise an error if no token and no useranem and password
712 # are given.
713 elif not self.username and not self.password:
714 raise DDNSConfigurationError(_("No Auth details specified."))
715
716 # HTTP Basic Auth is only allowed if no token is used.
717 if self.token:
718 # Send update to the server.
719 response = self.send_request(self.url, data=data)
720 else:
721 # Send update to the server.
722 response = self.send_request(self.url, username=self.username, password=self.password,
723 data=data)
724
725 # Get the full response message.
726 output = response.read()
727
728 # Handle success messages.
729 if "100" in output or "101" in output:
730 return
731
732 # Handle error codes.
733 if "401" or "402" in output:
734 raise DDNSAuthenticationError
735 elif "408" in output:
736 raise DDNSRequestError(_("Invalid IPv4 address has been sent."))
737 elif "409" in output:
738 raise DDNSRequestError(_("Invalid IPv6 address has been sent."))
739 elif "412" in output:
740 raise DDNSRequestError(_("No valid FQDN was given."))
741 elif "414" in output:
742 raise DDNSInternalServerError
743
744 # If we got here, some other update error happened.
745 raise DDNSUpdateError
746
747
f22ab085
MT
748class DDNSProviderSelfhost(DDNSProvider):
749 INFO = {
750 "handle" : "selfhost.de",
751 "name" : "Selfhost.de",
752 "website" : "http://www.selfhost.de/",
753 "protocols" : ["ipv4",],
754 }
755
2de06f59 756 url = "https://carol.selfhost.de/update"
f22ab085 757
5f402f36 758 def update(self):
2de06f59
MT
759 data = {
760 "username" : self.username,
761 "password" : self.password,
762 "textmodi" : "1",
763 }
f22ab085 764
2de06f59 765 response = self.send_request(self.url, data=data)
f22ab085
MT
766
767 match = re.search("status=20(0|4)", response.read())
768 if not match:
769 raise DDNSUpdateError
b09b1545
SS
770
771
772class DDNSProviderSPDNS(DDNSProviderDynDNS):
773 INFO = {
774 "handle" : "spdns.org",
775 "name" : "SPDNS",
776 "website" : "http://spdns.org/",
777 "protocols" : ["ipv4",]
778 }
779
780 # Detailed information about request and response codes are provided
781 # by the vendor. They are using almost the same mechanism and status
782 # codes as dyndns.org so we can inherit all those stuff.
783 #
784 # http://wiki.securepoint.de/index.php/SPDNS_FAQ
785 # http://wiki.securepoint.de/index.php/SPDNS_Update-Tokens
786
787 url = "https://update.spdns.de/nic/update"
4ec90b93
MT
788
789
7488825c
SS
790class DDNSProviderStrato(DDNSProviderDynDNS):
791 INFO = {
792 "handle" : "strato.com",
793 "name" : "Strato AG",
794 "website" : "http:/www.strato.com/",
795 "protocols" : ["ipv4",]
796 }
797
798 # Information about the request and response can be obtained here:
799 # http://www.strato-faq.de/article/671/So-einfach-richten-Sie-DynDNS-f%C3%BCr-Ihre-Domains-ein.html
800
801 url = "https://dyndns.strato.com/nic/update"
802
803
a6183090
SS
804class DDNSProviderTwoDNS(DDNSProviderDynDNS):
805 INFO = {
806 "handle" : "twodns.de",
807 "name" : "TwoDNS",
808 "website" : "http://www.twodns.de",
809 "protocols" : ["ipv4",]
810 }
811
812 # Detailed information about the request can be found here
813 # http://twodns.de/en/faqs
814 # http://twodns.de/en/api
815
816 url = "https://update.twodns.de/update"
817
818 def _prepare_request_data(self):
819 data = {
820 "ip" : self.get_address("ipv4"),
821 "hostname" : self.hostname
822 }
823
824 return data
825
826
03bdd188
SS
827class DDNSProviderUdmedia(DDNSProviderDynDNS):
828 INFO = {
829 "handle" : "udmedia.de",
830 "name" : "Udmedia GmbH",
831 "website" : "http://www.udmedia.de",
832 "protocols" : ["ipv4",]
833 }
834
835 # Information about the request can be found here
836 # http://www.udmedia.de/faq/content/47/288/de/wie-lege-ich-einen-dyndns_eintrag-an.html
837
838 url = "https://www.udmedia.de/nic/update"
839
840
c8c7ca8f
SS
841class DDNSProviderVariomedia(DDNSProviderDynDNS):
842 INFO = {
843 "handle" : "variomedia.de",
844 "name" : "Variomedia",
845 "website" : "http://www.variomedia.de/",
846 "protocols" : ["ipv6", "ipv4",]
847 }
848
849 # Detailed information about the request can be found here
850 # https://dyndns.variomedia.de/
851
852 url = "https://dyndns.variomedia.de/nic/update"
853
854 @property
855 def proto(self):
856 return self.get("proto")
857
858 def _prepare_request_data(self):
859 data = {
860 "hostname" : self.hostname,
861 "myip" : self.get_address(self.proto)
862 }
54d3efc8
MT
863
864 return data
98fbe467
SS
865
866
867class DDNSProviderZoneedit(DDNSProvider):
868 INFO = {
869 "handle" : "zoneedit.com",
870 "name" : "Zoneedit",
871 "website" : "http://www.zoneedit.com",
872 "protocols" : ["ipv6", "ipv4",]
873 }
874
875 # Detailed information about the request and the response codes can be
876 # obtained here:
877 # http://www.zoneedit.com/doc/api/other.html
878 # http://www.zoneedit.com/faq.html
879
880 url = "https://dynamic.zoneedit.com/auth/dynamic.html"
881
882 @property
883 def proto(self):
884 return self.get("proto")
885
886 def update(self):
887 data = {
888 "dnsto" : self.get_address(self.proto),
889 "host" : self.hostname
890 }
891
892 # Send update to the server.
893 response = self.send_request(self.url, username=self.username, password=self.password,
894 data=data)
895
896 # Get the full response message.
897 output = response.read()
898
899 # Handle success messages.
900 if output.startswith("<SUCCESS"):
901 return
902
903 # Handle error codes.
904 if output.startswith("invalid login"):
905 raise DDNSAuthenticationError
906 elif output.startswith("<ERROR CODE=\"704\""):
907 raise DDNSRequestError(_("No valid FQDN was given."))
908 elif output.startswith("<ERROR CODE=\"702\""):
909 raise DDNSInternalServerError
910
911 # If we got here, some other update error happened.
912 raise DDNSUpdateError