]>
git.ipfire.org Git - 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 ###############################################################################
26 # Import all possible exception types.
29 logger
= logging
.getLogger("ddns.providers")
32 class DDNSProvider(object):
34 # A short string that uniquely identifies
38 # The full name of the provider.
41 # A weburl to the homepage of the provider.
42 # (Where to register a new account?)
45 # A list of supported protocols.
46 "protocols" : ["ipv6", "ipv4"],
51 def __init__(self
, core
, **settings
):
54 # Copy a set of default settings and
55 # update them by those from the configuration file.
56 self
.settings
= self
.DEFAULT_SETTINGS
.copy()
57 self
.settings
.update(settings
)
60 return "<DDNS Provider %s (%s)>" % (self
.name
, self
.handle
)
62 def __cmp__(self
, other
):
63 return cmp(self
.hostname
, other
.hostname
)
68 Returns the name of the provider.
70 return self
.INFO
.get("name")
75 Returns the website URL of the provider
76 or None if that is not available.
78 return self
.INFO
.get("website", None)
83 Returns the handle of this provider.
85 return self
.INFO
.get("handle")
87 def get(self
, key
, default
=None):
89 Get a setting from the settings dictionary.
91 return self
.settings
.get(key
, default
)
96 Fast access to the hostname.
98 return self
.get("hostname")
103 Fast access to the username.
105 return self
.get("username")
110 Fast access to the password.
112 return self
.get("password")
116 return self
.INFO
.get("protocols")
118 def __call__(self
, force
=False):
120 logger
.info(_("Updating %s forced") % self
.hostname
)
122 # Check if we actually need to update this host.
123 elif self
.is_uptodate(self
.protocols
):
124 logger
.info(_("%s is already up to date") % self
.hostname
)
127 # Execute the update.
131 raise NotImplementedError
133 def is_uptodate(self
, protos
):
135 Returns True if this host is already up to date
136 and does not need to change the IP address on the
140 addresses
= self
.core
.system
.resolve(self
.hostname
, proto
)
142 current_address
= self
.get_address(proto
)
144 if not current_address
in addresses
:
149 def send_request(self
, *args
, **kwargs
):
151 Proxy connection to the send request
154 return self
.core
.system
.send_request(*args
, **kwargs
)
156 def get_address(self
, proto
):
158 Proxy method to get the current IP address.
160 return self
.core
.system
.get_address(proto
)
163 class DDNSProviderDHS(DDNSProvider
):
165 "handle" : "dhs.org",
166 "name" : "DHS International",
167 "website" : "http://dhs.org/",
168 "protocols" : ["ipv4",]
171 # No information about the used update api provided on webpage,
172 # grabed from source code of ez-ipudate.
173 url
= "http://members.dhs.org/nic/hosts"
177 "username" : self
.username
,
178 "password" : self
.password
,
182 "domain" : self
.hostname
,
183 "ip" : self
.get_address("ipv4"),
185 "hostcmdstage" : "2",
189 # Send update to the server.
190 response
= self
.send_request(url
, username
=self
.username
, password
=self
.password
,
193 # Handle success messages.
194 if response
.code
== 200:
197 # Handle error codes.
198 elif response
.code
== 401:
199 raise DDNSAuthenticationError
201 # If we got here, some other update error happened.
202 raise DDNSUpdateError
205 class DDNSProviderDNSpark(DDNSProvider
):
207 "handle" : "dnspark.com",
209 "website" : "http://dnspark.com/",
210 "protocols" : ["ipv4",]
213 # Informations to the used api can be found here:
214 # https://dnspark.zendesk.com/entries/31229348-Dynamic-DNS-API-Documentation
215 url
= "https://control.dnspark.com/api/dynamic/update.php"
219 "username" : self
.username
,
220 "password" : self
.password
,
224 "domain" : self
.hostname
,
225 "ip" : self
.get_address("ipv4"),
228 # Send update to the server.
229 response
= self
.send_request(url
, username
=self
.username
, password
=self
.password
,
232 # Get the full response message.
233 output
= response
.read()
235 # Handle success messages.
236 if output
.startswith("ok") or output
.startswith("nochange"):
239 # Handle error codes.
240 if output
== "unauth":
241 raise DDNSAuthenticationError
242 elif output
== "abuse":
244 elif output
== "blocked":
245 raise DDNSBlockedError
246 elif output
== "nofqdn":
247 raise DDNSRequestError(_("No valid FQDN was given."))
248 elif output
== "nohost":
249 raise DDNSRequestError(_("Invalid hostname specified."))
250 elif output
== "notdyn":
251 raise DDNSRequestError(_("Hostname not marked as a dynamic host."))
252 elif output
== "invalid":
253 raise DDNSRequestError(_("Invalid IP address has been sent."))
255 # If we got here, some other update error happened.
256 raise DDNSUpdateError
259 class DDNSProviderLightningWireLabs(DDNSProvider
):
261 "handle" : "dns.lightningwirelabs.com",
262 "name" : "Lightning Wire Labs",
263 "website" : "http://dns.lightningwirelabs.com/",
264 "protocols" : ["ipv6", "ipv4",]
267 # Information about the format of the HTTPS request is to be found
268 # https://dns.lightningwirelabs.com/knowledge-base/api/ddns
269 url
= "https://dns.lightningwirelabs.com/update"
274 Fast access to the token.
276 return self
.get("token")
280 "hostname" : self
.hostname
,
283 # Check if we update an IPv6 address.
284 address6
= self
.get_address("ipv6")
286 data
["address6"] = address6
288 # Check if we update an IPv4 address.
289 address4
= self
.get_address("ipv4")
291 data
["address4"] = address4
293 # Raise an error if none address is given.
294 if not data
.has_key("address6") and not data
.has_key("address4"):
295 raise DDNSConfigurationError
297 # Check if a token has been set.
299 data
["token"] = self
.token
301 # Check for username and password.
302 elif self
.username
and self
.password
:
304 "username" : self
.username
,
305 "password" : self
.password
,
308 # Raise an error if no auth details are given.
310 raise DDNSConfigurationError
312 # Send update to the server.
313 response
= self
.send_request(self
.url
, data
=data
)
315 # Handle success messages.
316 if response
.code
== 200:
319 # Handle error codes.
320 if response
.code
== 403:
321 raise DDNSAuthenticationError
322 elif response
.code
== 400:
323 raise DDNSRequestError
325 # If we got here, some other update error happened.
326 raise DDNSUpdateError
329 class DDNSProviderNOIP(DDNSProvider
):
331 "handle" : "no-ip.com",
333 "website" : "http://www.no-ip.com/",
334 "protocols" : ["ipv4",]
337 # Information about the format of the HTTP request is to be found
338 # here: http://www.no-ip.com/integrate/request and
339 # here: http://www.no-ip.com/integrate/response
341 url
= "http://%(username)s:%(password)s@dynupdate.no-ip.com/nic/update"
345 "username" : self
.username
,
346 "password" : self
.password
,
350 "hostname" : self
.hostname
,
351 "address" : self
.get_address("ipv4"),
354 # Send update to the server.
355 response
= self
.send_request(url
, data
=data
)
357 # Get the full response message.
358 output
= response
.read()
360 # Handle success messages.
361 if output
.startswith("good") or output
.startswith("nochg"):
364 # Handle error codes.
365 if output
== "badauth":
366 raise DDNSAuthenticationError
367 elif output
== "aduse":
369 elif output
== "911":
370 raise DDNSInternalServerError
372 # If we got here, some other update error happened.
373 raise DDNSUpdateError
376 class DDNSProviderSelfhost(DDNSProvider
):
378 "handle" : "selfhost.de",
379 "name" : "Selfhost.de",
380 "website" : "http://www.selfhost.de/",
381 "protocols" : ["ipv4",],
384 url
= "https://carol.selfhost.de/update"
388 "username" : self
.username
,
389 "password" : self
.password
,
393 response
= self
.send_request(self
.url
, data
=data
)
395 match
= re
.search("status=20(0|4)", response
.read())
397 raise DDNSUpdateError