]> git.ipfire.org Git - oddments/ddns.git/blame - src/ddns/providers.py
Handle HTTP errors as early as possible.
[oddments/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):
3b16fdb1
SS
193 # There is no additional data required so we directly can
194 # send our request.
536e87d1 195 response = self.send_request(self.url, username=self.username, password=self.password)
3b16fdb1
SS
196
197 # Get the full response message.
198 output = response.read()
199
200 # Handle success messages.
201 if output.startswith("good") or output.startswith("nochg"):
202 return
203
204 # If we got here, some other update error happened.
205 raise DDNSUpdateError
206
207
f3cf1f70
SS
208class DDNSProviderDHS(DDNSProvider):
209 INFO = {
210 "handle" : "dhs.org",
211 "name" : "DHS International",
212 "website" : "http://dhs.org/",
213 "protocols" : ["ipv4",]
214 }
215
216 # No information about the used update api provided on webpage,
217 # grabed from source code of ez-ipudate.
218 url = "http://members.dhs.org/nic/hosts"
219
5f402f36 220 def update(self):
f3cf1f70
SS
221 data = {
222 "domain" : self.hostname,
223 "ip" : self.get_address("ipv4"),
224 "hostcmd" : "edit",
225 "hostcmdstage" : "2",
226 "type" : "4",
227 }
228
229 # Send update to the server.
175c9b80 230 response = self.send_request(self.url, username=self.username, password=self.password,
f3cf1f70
SS
231 data=data)
232
233 # Handle success messages.
234 if response.code == 200:
235 return
236
f3cf1f70
SS
237 # If we got here, some other update error happened.
238 raise DDNSUpdateError
239
240
39301272
SS
241class DDNSProviderDNSpark(DDNSProvider):
242 INFO = {
243 "handle" : "dnspark.com",
244 "name" : "DNS Park",
245 "website" : "http://dnspark.com/",
246 "protocols" : ["ipv4",]
247 }
248
249 # Informations to the used api can be found here:
250 # https://dnspark.zendesk.com/entries/31229348-Dynamic-DNS-API-Documentation
251 url = "https://control.dnspark.com/api/dynamic/update.php"
252
5f402f36 253 def update(self):
39301272
SS
254 data = {
255 "domain" : self.hostname,
256 "ip" : self.get_address("ipv4"),
257 }
258
259 # Send update to the server.
175c9b80 260 response = self.send_request(self.url, username=self.username, password=self.password,
39301272
SS
261 data=data)
262
263 # Get the full response message.
264 output = response.read()
265
266 # Handle success messages.
267 if output.startswith("ok") or output.startswith("nochange"):
268 return
269
270 # Handle error codes.
271 if output == "unauth":
272 raise DDNSAuthenticationError
273 elif output == "abuse":
274 raise DDNSAbuseError
275 elif output == "blocked":
276 raise DDNSBlockedError
277 elif output == "nofqdn":
278 raise DDNSRequestError(_("No valid FQDN was given."))
279 elif output == "nohost":
280 raise DDNSRequestError(_("Invalid hostname specified."))
281 elif output == "notdyn":
282 raise DDNSRequestError(_("Hostname not marked as a dynamic host."))
283 elif output == "invalid":
284 raise DDNSRequestError(_("Invalid IP address has been sent."))
285
286 # If we got here, some other update error happened.
287 raise DDNSUpdateError
288
43b2cd59
SS
289
290class DDNSProviderDtDNS(DDNSProvider):
291 INFO = {
292 "handle" : "dtdns.com",
293 "name" : "DtDNS",
294 "website" : "http://dtdns.com/",
295 "protocols" : ["ipv4",]
296 }
297
298 # Information about the format of the HTTPS request is to be found
299 # http://www.dtdns.com/dtsite/updatespec
300 url = "https://www.dtdns.com/api/autodns.cfm"
301
43b2cd59
SS
302 def update(self):
303 data = {
304 "ip" : self.get_address("ipv4"),
305 "id" : self.hostname,
306 "pw" : self.password
307 }
308
309 # Send update to the server.
310 response = self.send_request(self.url, data=data)
311
312 # Get the full response message.
313 output = response.read()
314
315 # Remove all leading and trailing whitespace.
316 output = output.strip()
317
318 # Handle success messages.
319 if "now points to" in output:
320 return
321
322 # Handle error codes.
323 if output == "No hostname to update was supplied.":
324 raise DDNSRequestError(_("No hostname specified."))
325
326 elif output == "The hostname you supplied is not valid.":
327 raise DDNSRequestError(_("Invalid hostname specified."))
328
329 elif output == "The password you supplied is not valid.":
330 raise DDNSAuthenticationError
331
332 elif output == "Administration has disabled this account.":
333 raise DDNSRequestError(_("Account has been disabled."))
334
335 elif output == "Illegal character in IP.":
336 raise DDNSRequestError(_("Invalid IP address has been sent."))
337
338 elif output == "Too many failed requests.":
339 raise DDNSRequestError(_("Too many failed requests."))
340
341 # If we got here, some other update error happened.
342 raise DDNSUpdateError
343
344
bfed6701
SS
345class DDNSProviderDynDNS(DDNSProvider):
346 INFO = {
347 "handle" : "dyndns.org",
348 "name" : "Dyn",
349 "website" : "http://dyn.com/dns/",
350 "protocols" : ["ipv4",]
351 }
352
353 # Information about the format of the request is to be found
354 # http://http://dyn.com/support/developers/api/perform-update/
355 # http://dyn.com/support/developers/api/return-codes/
356 url = "https://members.dyndns.org/nic/update"
357
88f39629 358 def _prepare_request_data(self):
bfed6701
SS
359 data = {
360 "hostname" : self.hostname,
361 "myip" : self.get_address("ipv4"),
362 }
363
88f39629
SS
364 return data
365
366 def update(self):
367 data = self._prepare_request_data()
368
bfed6701 369 # Send update to the server.
88f39629
SS
370 response = self.send_request(self.url, data=data,
371 username=self.username, password=self.password)
bfed6701
SS
372
373 # Get the full response message.
374 output = response.read()
375
376 # Handle success messages.
377 if output.startswith("good") or output.startswith("nochg"):
378 return
379
380 # Handle error codes.
381 if output == "badauth":
382 raise DDNSAuthenticationError
383 elif output == "aduse":
384 raise DDNSAbuseError
385 elif output == "notfqdn":
386 raise DDNSRequestError(_("No valid FQDN was given."))
387 elif output == "nohost":
388 raise DDNSRequestError(_("Specified host does not exist."))
389 elif output == "911":
390 raise DDNSInternalServerError
391 elif output == "dnserr":
392 raise DDNSInternalServerError(_("DNS error encountered."))
393
394 # If we got here, some other update error happened.
0271a97f 395 raise DDNSUpdateError(_("Server response: %s") % output)
bfed6701
SS
396
397
3a8407fa
SS
398class DDNSProviderDynU(DDNSProviderDynDNS):
399 INFO = {
400 "handle" : "dynu.com",
401 "name" : "Dynu",
402 "website" : "http://dynu.com/",
403 "protocols" : ["ipv6", "ipv4",]
404 }
405
406
407 # Detailed information about the request and response codes
408 # are available on the providers webpage.
409 # http://dynu.com/Default.aspx?page=dnsapi
410
411 url = "https://api.dynu.com/nic/update"
412
413 def _prepare_request_data(self):
54d3efc8
MT
414 data = DDNSProviderDynDNS._prepare_request_data(self)
415
416 # This one supports IPv6
417 data.update({
3a8407fa 418 "myipv6" : self.get_address("ipv6"),
54d3efc8
MT
419 })
420
421 return data
3a8407fa
SS
422
423
ee071271
SS
424class DDNSProviderEasyDNS(DDNSProviderDynDNS):
425 INFO = {
426 "handle" : "easydns.com",
427 "name" : "EasyDNS",
428 "website" : "http://www.easydns.com/",
429 "protocols" : ["ipv4",]
430 }
431
432 # There is only some basic documentation provided by the vendor,
433 # also searching the web gain very poor results.
434 # http://mediawiki.easydns.com/index.php/Dynamic_DNS
435
436 url = "http://api.cp.easydns.com/dyn/tomato.php"
437
438
aa21a4c6
SS
439class DDNSProviderFreeDNSAfraidOrg(DDNSProvider):
440 INFO = {
441 "handle" : "freedns.afraid.org",
442 "name" : "freedns.afraid.org",
443 "website" : "http://freedns.afraid.org/",
444 "protocols" : ["ipv6", "ipv4",]
445 }
446
447 # No information about the request or response could be found on the vendor
448 # page. All used values have been collected by testing.
449 url = "https://freedns.afraid.org/dynamic/update.php"
450
451 @property
452 def proto(self):
453 return self.get("proto")
454
455 def update(self):
456 address = self.get_address(self.proto)
457
458 data = {
459 "address" : address,
460 }
461
462 # Add auth token to the update url.
463 url = "%s?%s" % (self.url, self.token)
464
465 # Send update to the server.
466 response = self.send_request(url, data=data)
467
aa21a4c6
SS
468 if output.startswith("Updated") or "has not changed" in output:
469 return
470
471 # Handle error codes.
472 if output == "ERROR: Unable to locate this record":
473 raise DDNSAuthenticationError
474 elif "is an invalid IP address" in output:
475 raise DDNSRequestError(_("Invalid IP address has been sent."))
476
aa21a4c6 477
a08c1b72
SS
478class DDNSProviderLightningWireLabs(DDNSProvider):
479 INFO = {
480 "handle" : "dns.lightningwirelabs.com",
481 "name" : "Lightning Wire Labs",
482 "website" : "http://dns.lightningwirelabs.com/",
483 "protocols" : ["ipv6", "ipv4",]
484 }
485
486 # Information about the format of the HTTPS request is to be found
487 # https://dns.lightningwirelabs.com/knowledge-base/api/ddns
488 url = "https://dns.lightningwirelabs.com/update"
489
5f402f36 490 def update(self):
a08c1b72
SS
491 data = {
492 "hostname" : self.hostname,
493 }
494
495 # Check if we update an IPv6 address.
496 address6 = self.get_address("ipv6")
497 if address6:
498 data["address6"] = address6
499
500 # Check if we update an IPv4 address.
501 address4 = self.get_address("ipv4")
502 if address4:
503 data["address4"] = address4
504
505 # Raise an error if none address is given.
506 if not data.has_key("address6") and not data.has_key("address4"):
507 raise DDNSConfigurationError
508
509 # Check if a token has been set.
510 if self.token:
511 data["token"] = self.token
512
513 # Check for username and password.
514 elif self.username and self.password:
515 data.update({
516 "username" : self.username,
517 "password" : self.password,
518 })
519
520 # Raise an error if no auth details are given.
521 else:
522 raise DDNSConfigurationError
523
524 # Send update to the server.
cb455540 525 response = self.send_request(self.url, data=data)
a08c1b72
SS
526
527 # Handle success messages.
528 if response.code == 200:
529 return
530
a08c1b72
SS
531 # If we got here, some other update error happened.
532 raise DDNSUpdateError
533
534
d1cd57eb
SS
535class DDNSProviderNamecheap(DDNSProvider):
536 INFO = {
537 "handle" : "namecheap.com",
538 "name" : "Namecheap",
539 "website" : "http://namecheap.com",
540 "protocols" : ["ipv4",]
541 }
542
543 # Information about the format of the HTTP request is to be found
544 # https://www.namecheap.com/support/knowledgebase/article.aspx/9249/0/nc-dynamic-dns-to-dyndns-adapter
545 # https://community.namecheap.com/forums/viewtopic.php?f=6&t=6772
546
547 url = "https://dynamicdns.park-your-domain.com/update"
548
549 def parse_xml(self, document, content):
550 # Send input to the parser.
551 xmldoc = xml.dom.minidom.parseString(document)
552
553 # Get XML elements by the given content.
554 element = xmldoc.getElementsByTagName(content)
555
556 # If no element has been found, we directly can return None.
557 if not element:
558 return None
559
560 # Only get the first child from an element, even there are more than one.
561 firstchild = element[0].firstChild
562
563 # Get the value of the child.
564 value = firstchild.nodeValue
565
566 # Return the value.
567 return value
568
569 def update(self):
570 # Namecheap requires the hostname splitted into a host and domain part.
571 host, domain = self.hostname.split(".", 1)
572
573 data = {
574 "ip" : self.get_address("ipv4"),
575 "password" : self.password,
576 "host" : host,
577 "domain" : domain
578 }
579
580 # Send update to the server.
581 response = self.send_request(self.url, data=data)
582
583 # Get the full response message.
584 output = response.read()
585
586 # Handle success messages.
587 if self.parse_xml(output, "IP") == self.get_address("ipv4"):
588 return
589
590 # Handle error codes.
591 errorcode = self.parse_xml(output, "ResponseNumber")
592
593 if errorcode == "304156":
594 raise DDNSAuthenticationError
595 elif errorcode == "316153":
596 raise DDNSRequestError(_("Domain not found."))
597 elif errorcode == "316154":
598 raise DDNSRequestError(_("Domain not active."))
599 elif errorcode in ("380098", "380099"):
600 raise DDNSInternalServerError
601
602 # If we got here, some other update error happened.
603 raise DDNSUpdateError
604
605
88f39629 606class DDNSProviderNOIP(DDNSProviderDynDNS):
f22ab085
MT
607 INFO = {
608 "handle" : "no-ip.com",
609 "name" : "No-IP",
610 "website" : "http://www.no-ip.com/",
611 "protocols" : ["ipv4",]
612 }
613
614 # Information about the format of the HTTP request is to be found
615 # here: http://www.no-ip.com/integrate/request and
616 # here: http://www.no-ip.com/integrate/response
617
88f39629 618 url = "http://dynupdate.no-ip.com/nic/update"
2de06f59 619
88f39629 620 def _prepare_request_data(self):
2de06f59
MT
621 data = {
622 "hostname" : self.hostname,
f22ab085
MT
623 "address" : self.get_address("ipv4"),
624 }
625
88f39629 626 return data
f22ab085
MT
627
628
a508bda6
SS
629class DDNSProviderOVH(DDNSProviderDynDNS):
630 INFO = {
631 "handle" : "ovh.com",
632 "name" : "OVH",
633 "website" : "http://www.ovh.com/",
634 "protocols" : ["ipv4",]
635 }
636
637 # OVH only provides very limited information about how to
638 # update a DynDNS host. They only provide the update url
639 # on the their german subpage.
640 #
641 # http://hilfe.ovh.de/DomainDynHost
642
643 url = "https://www.ovh.com/nic/update"
644
645 def _prepare_request_data(self):
54d3efc8
MT
646 data = DDNSProviderDynDNS._prepare_request_data(self)
647 data.update({
648 "system" : "dyndns",
649 })
650
651 return data
a508bda6
SS
652
653
ef33455e
SS
654class DDNSProviderRegfish(DDNSProvider):
655 INFO = {
656 "handle" : "regfish.com",
657 "name" : "Regfish GmbH",
658 "website" : "http://www.regfish.com/",
659 "protocols" : ["ipv6", "ipv4",]
660 }
661
662 # A full documentation to the providers api can be found here
663 # but is only available in german.
664 # https://www.regfish.de/domains/dyndns/dokumentation
665
666 url = "https://dyndns.regfish.de/"
667
668 def update(self):
669 data = {
670 "fqdn" : self.hostname,
671 }
672
673 # Check if we update an IPv6 address.
674 address6 = self.get_address("ipv6")
675 if address6:
676 data["ipv6"] = address6
677
678 # Check if we update an IPv4 address.
679 address4 = self.get_address("ipv4")
680 if address4:
681 data["ipv4"] = address4
682
683 # Raise an error if none address is given.
684 if not data.has_key("ipv6") and not data.has_key("ipv4"):
685 raise DDNSConfigurationError
686
687 # Check if a token has been set.
688 if self.token:
689 data["token"] = self.token
690
691 # Raise an error if no token and no useranem and password
692 # are given.
693 elif not self.username and not self.password:
694 raise DDNSConfigurationError(_("No Auth details specified."))
695
696 # HTTP Basic Auth is only allowed if no token is used.
697 if self.token:
698 # Send update to the server.
699 response = self.send_request(self.url, data=data)
700 else:
701 # Send update to the server.
702 response = self.send_request(self.url, username=self.username, password=self.password,
703 data=data)
704
705 # Get the full response message.
706 output = response.read()
707
708 # Handle success messages.
709 if "100" in output or "101" in output:
710 return
711
712 # Handle error codes.
713 if "401" or "402" in output:
714 raise DDNSAuthenticationError
715 elif "408" in output:
716 raise DDNSRequestError(_("Invalid IPv4 address has been sent."))
717 elif "409" in output:
718 raise DDNSRequestError(_("Invalid IPv6 address has been sent."))
719 elif "412" in output:
720 raise DDNSRequestError(_("No valid FQDN was given."))
721 elif "414" in output:
722 raise DDNSInternalServerError
723
724 # If we got here, some other update error happened.
725 raise DDNSUpdateError
726
727
04db1862 728class DDNSProviderSelfhost(DDNSProviderDynDNS):
f22ab085
MT
729 INFO = {
730 "handle" : "selfhost.de",
731 "name" : "Selfhost.de",
732 "website" : "http://www.selfhost.de/",
733 "protocols" : ["ipv4",],
734 }
735
04db1862 736 url = "https://carol.selfhost.de/nic/update"
f22ab085 737
04db1862
MT
738 def _prepare_request_data(self):
739 data = DDNSProviderDynDNS._prepare_request_data(self)
740 data.update({
741 "hostname" : "1",
742 })
f22ab085 743
04db1862 744 return data
b09b1545
SS
745
746
747class DDNSProviderSPDNS(DDNSProviderDynDNS):
748 INFO = {
749 "handle" : "spdns.org",
750 "name" : "SPDNS",
751 "website" : "http://spdns.org/",
752 "protocols" : ["ipv4",]
753 }
754
755 # Detailed information about request and response codes are provided
756 # by the vendor. They are using almost the same mechanism and status
757 # codes as dyndns.org so we can inherit all those stuff.
758 #
759 # http://wiki.securepoint.de/index.php/SPDNS_FAQ
760 # http://wiki.securepoint.de/index.php/SPDNS_Update-Tokens
761
762 url = "https://update.spdns.de/nic/update"
4ec90b93
MT
763
764
7488825c
SS
765class DDNSProviderStrato(DDNSProviderDynDNS):
766 INFO = {
767 "handle" : "strato.com",
768 "name" : "Strato AG",
769 "website" : "http:/www.strato.com/",
770 "protocols" : ["ipv4",]
771 }
772
773 # Information about the request and response can be obtained here:
774 # http://www.strato-faq.de/article/671/So-einfach-richten-Sie-DynDNS-f%C3%BCr-Ihre-Domains-ein.html
775
776 url = "https://dyndns.strato.com/nic/update"
777
778
a6183090
SS
779class DDNSProviderTwoDNS(DDNSProviderDynDNS):
780 INFO = {
781 "handle" : "twodns.de",
782 "name" : "TwoDNS",
783 "website" : "http://www.twodns.de",
784 "protocols" : ["ipv4",]
785 }
786
787 # Detailed information about the request can be found here
788 # http://twodns.de/en/faqs
789 # http://twodns.de/en/api
790
791 url = "https://update.twodns.de/update"
792
793 def _prepare_request_data(self):
794 data = {
795 "ip" : self.get_address("ipv4"),
796 "hostname" : self.hostname
797 }
798
799 return data
800
801
03bdd188
SS
802class DDNSProviderUdmedia(DDNSProviderDynDNS):
803 INFO = {
804 "handle" : "udmedia.de",
805 "name" : "Udmedia GmbH",
806 "website" : "http://www.udmedia.de",
807 "protocols" : ["ipv4",]
808 }
809
810 # Information about the request can be found here
811 # http://www.udmedia.de/faq/content/47/288/de/wie-lege-ich-einen-dyndns_eintrag-an.html
812
813 url = "https://www.udmedia.de/nic/update"
814
815
c8c7ca8f
SS
816class DDNSProviderVariomedia(DDNSProviderDynDNS):
817 INFO = {
818 "handle" : "variomedia.de",
819 "name" : "Variomedia",
820 "website" : "http://www.variomedia.de/",
821 "protocols" : ["ipv6", "ipv4",]
822 }
823
824 # Detailed information about the request can be found here
825 # https://dyndns.variomedia.de/
826
827 url = "https://dyndns.variomedia.de/nic/update"
828
829 @property
830 def proto(self):
831 return self.get("proto")
832
833 def _prepare_request_data(self):
834 data = {
835 "hostname" : self.hostname,
836 "myip" : self.get_address(self.proto)
837 }
54d3efc8
MT
838
839 return data
98fbe467
SS
840
841
842class DDNSProviderZoneedit(DDNSProvider):
843 INFO = {
844 "handle" : "zoneedit.com",
845 "name" : "Zoneedit",
846 "website" : "http://www.zoneedit.com",
847 "protocols" : ["ipv6", "ipv4",]
848 }
849
850 # Detailed information about the request and the response codes can be
851 # obtained here:
852 # http://www.zoneedit.com/doc/api/other.html
853 # http://www.zoneedit.com/faq.html
854
855 url = "https://dynamic.zoneedit.com/auth/dynamic.html"
856
857 @property
858 def proto(self):
859 return self.get("proto")
860
861 def update(self):
862 data = {
863 "dnsto" : self.get_address(self.proto),
864 "host" : self.hostname
865 }
866
867 # Send update to the server.
868 response = self.send_request(self.url, username=self.username, password=self.password,
869 data=data)
870
871 # Get the full response message.
872 output = response.read()
873
874 # Handle success messages.
875 if output.startswith("<SUCCESS"):
876 return
877
878 # Handle error codes.
879 if output.startswith("invalid login"):
880 raise DDNSAuthenticationError
881 elif output.startswith("<ERROR CODE=\"704\""):
882 raise DDNSRequestError(_("No valid FQDN was given."))
883 elif output.startswith("<ERROR CODE=\"702\""):
884 raise DDNSInternalServerError
885
886 # If we got here, some other update error happened.
887 raise DDNSUpdateError