Mercurial > libervia-backend
comparison src/plugins/plugin_misc_ip.py @ 1566:ec3848916ee8
plugin ip: implemented XEP-0279 for external ip retrieval + fixed bad exception handling
author | Goffi <goffi@goffi.org> |
---|---|
date | Sun, 08 Nov 2015 14:44:30 +0100 |
parents | eb8aae35085b |
children | d5f59ba166fe |
comparison
equal
deleted
inserted
replaced
1565:d86685c0c019 | 1566:ec3848916ee8 |
---|---|
26 from twisted.internet import defer | 26 from twisted.internet import defer |
27 from twisted.internet import reactor | 27 from twisted.internet import reactor |
28 from twisted.internet import protocol | 28 from twisted.internet import protocol |
29 from twisted.internet import endpoints | 29 from twisted.internet import endpoints |
30 from twisted.internet import error as internet_error | 30 from twisted.internet import error as internet_error |
31 from zope.interface import implements | |
32 from wokkel import disco, iwokkel | |
33 from twisted.words.protocols.jabber.xmlstream import XMPPHandler | |
31 import urlparse | 34 import urlparse |
32 try: | 35 try: |
33 import netifaces | 36 import netifaces |
34 except ImportError: | 37 except ImportError: |
35 log.warning(u"netifaces is not available, it help discovering IPs, you can install it on https://pypi.python.org/pypi/netifaces") | 38 log.warning(u"netifaces is not available, it help discovering IPs, you can install it on https://pypi.python.org/pypi/netifaces") |
38 | 41 |
39 PLUGIN_INFO = { | 42 PLUGIN_INFO = { |
40 "name": "IP discovery", | 43 "name": "IP discovery", |
41 "import_name": "IP", | 44 "import_name": "IP", |
42 "type": C.PLUG_TYPE_MISC, | 45 "type": C.PLUG_TYPE_MISC, |
46 "protocols": ["XEP-0279"], | |
43 "recommendations": ["NAT-PORT"], | 47 "recommendations": ["NAT-PORT"], |
44 "main": "IPPlugin", | 48 "main": "IPPlugin", |
45 "handler": "no", | 49 "handler": "yes", |
46 "description": _("""This plugin help to discover our external IP address.""") | 50 "description": _("""This plugin help to discover our external IP address.""") |
47 } | 51 } |
48 | 52 |
49 GET_IP_PAGE = "http://www.goffi.org/sat_tools/get_ip.php" # This page must only return external IP of the requester | 53 GET_IP_PAGE = "http://www.goffi.org/sat_tools/get_ip.php" # This page must only return external IP of the requester |
50 GET_IP_LABEL = D_(u"Allow external get IP") | 54 GET_IP_LABEL = D_(u"Allow external get IP") |
60 Do you agree to do this request ? | 64 Do you agree to do this request ? |
61 """).format( | 65 """).format( |
62 page = GET_IP_PAGE, | 66 page = GET_IP_PAGE, |
63 domain = urlparse.urlparse(GET_IP_PAGE).netloc, | 67 domain = urlparse.urlparse(GET_IP_PAGE).netloc, |
64 app_name = C.APP_NAME) | 68 app_name = C.APP_NAME) |
69 NS_IP_CHECK = "urn:xmpp:sic:1" | |
65 | 70 |
66 PARAMS = """ | 71 PARAMS = """ |
67 <params> | 72 <params> |
68 <general> | 73 <general> |
69 <category name="{category}"> | 74 <category name="{category}"> |
75 | 80 |
76 | 81 |
77 class IPPlugin(object): | 82 class IPPlugin(object): |
78 # TODO: refresh IP if a new connection is detected | 83 # TODO: refresh IP if a new connection is detected |
79 # TODO: manage IPv6 when implemented in SàT | 84 # TODO: manage IPv6 when implemented in SàT |
80 # TODO: implement XEP-0279 | |
81 | 85 |
82 def __init__(self, host): | 86 def __init__(self, host): |
83 log.info(_("plugin IP discovery initialization")) | 87 log.info(_("plugin IP discovery initialization")) |
84 self.host = host | 88 self.host = host |
85 host.memory.updateParams(PARAMS) | 89 host.memory.updateParams(PARAMS) |
93 | 97 |
94 # XXX: cache is kept until SàT is restarted | 98 # XXX: cache is kept until SàT is restarted |
95 # if IP may have changed, use self.refreshIP | 99 # if IP may have changed, use self.refreshIP |
96 self._external_ip_cache = None | 100 self._external_ip_cache = None |
97 self._local_ip_cache = None | 101 self._local_ip_cache = None |
102 | |
103 def getHandler(self, profile): | |
104 return IPPlugin_handler() | |
98 | 105 |
99 def refreshIP(self): | 106 def refreshIP(self): |
100 # FIXME: use a trigger instead ? | 107 # FIXME: use a trigger instead ? |
101 self._external_ip_cache = None | 108 self._external_ip_cache = None |
102 self._local_ip_cache = None | 109 self._local_ip_cache = None |
171 return local_ip | 178 return local_ip |
172 | 179 |
173 d = endpoints.connectProtocol(point, protocol.Protocol()) | 180 d = endpoints.connectProtocol(point, protocol.Protocol()) |
174 d.addCallback(gotConnection) | 181 d.addCallback(gotConnection) |
175 return d | 182 return d |
176 | |
177 | 183 |
178 @defer.inlineCallbacks | 184 @defer.inlineCallbacks |
179 def getLocalIPs(self, profile): | 185 def getLocalIPs(self, profile): |
180 """Try do discover local area network IPs | 186 """Try do discover local area network IPs |
181 | 187 |
226 if not allow_get_ip: | 232 if not allow_get_ip: |
227 defer.returnValue(addresses) | 233 defer.returnValue(addresses) |
228 | 234 |
229 try: | 235 try: |
230 ip_tuple = yield self._getIPFromExternal(GET_IP_PAGE) | 236 ip_tuple = yield self._getIPFromExternal(GET_IP_PAGE) |
231 except Exception as internet_error.DNSLookupError: | 237 except (internet_error.DNSLookupError, internet_error.TimeoutError): |
232 log.warning(u"Can't access Domain Name System") | 238 log.warning(u"Can't access Domain Name System") |
233 defer.returnValue(addresses) | 239 defer.returnValue(addresses) |
234 self._insertFirst(addresses, ip_tuple.local) | 240 self._insertFirst(addresses, ip_tuple.local) |
235 defer.returnValue(addresses) | 241 defer.returnValue(addresses) |
236 | 242 |
237 | |
238 @defer.inlineCallbacks | 243 @defer.inlineCallbacks |
239 def getExternalIP(self, profile): | 244 def getExternalIP(self, profile): |
240 """Try to discover external IP | 245 """Try to discover external IP |
241 | 246 |
242 @param profile: %(doc_profile)s | 247 @param profile: %(doc_profile)s |
243 @return (deferred): external IP address or None if it can't be discovered | 248 @return (deferred): external IP address or None if it can't be discovered |
244 """ | 249 """ |
245 if self._external_ip_cache is not None: | 250 if self._external_ip_cache is not None: |
246 defer.returnValue(self._external_ip_cache) | 251 defer.returnValue(self._external_ip_cache) |
247 | 252 |
248 # we first try with NAT-Port | 253 # we first try with XEP-0279 |
254 if self.host.hasFeature(NS_IP_CHECK, profile=profile): | |
255 log.debug(u"Server IP Check available, we use it to retrieve our IP") | |
256 client = self.host.getClient(profile) | |
257 iq_elt = client.IQ("get") | |
258 iq_elt.addElement((NS_IP_CHECK, 'address')) | |
259 result_elt = yield iq_elt.send() | |
260 try: | |
261 address_elt = result_elt.elements(NS_IP_CHECK, 'address').next() | |
262 ip_elt = address_elt.elements(NS_IP_CHECK,'ip').next() | |
263 except StopIteration: | |
264 log.warning(u"Server returned invalid result on XEP-0279 request, we ignore it") | |
265 else: | |
266 # FIXME: server IP may not be the same as external IP (server can be on local machine or network) | |
267 # IP should be checked to see if we have a local one, and rejected in this case | |
268 external_ip = str(ip_elt) | |
269 log.debug(u"External IP found: {}".format(external_ip)) | |
270 self._external_ip_cache = external_ip | |
271 defer.returnValue(self._external_ip_cache) | |
272 | |
273 # then with NAT-Port | |
249 if self._nat is not None: | 274 if self._nat is not None: |
250 nat_ip = yield self._nat.getIP() | 275 nat_ip = yield self._nat.getIP() |
251 if nat_ip is not None: | 276 if nat_ip is not None: |
252 self._external_ip_cache = nat_ip | 277 self._external_ip_cache = nat_ip |
253 defer.returnValue(nat_ip) | 278 defer.returnValue(nat_ip) |
254 | 279 |
255 # then by requesting external website | 280 # and finally by requesting external website |
256 allow_get_ip = yield self._externalAllowed(profile) | 281 allow_get_ip = yield self._externalAllowed(profile) |
257 try: | 282 try: |
258 ip = (yield webclient.getPage(GET_IP_PAGE)) if allow_get_ip else None | 283 ip = (yield webclient.getPage(GET_IP_PAGE)) if allow_get_ip else None |
259 except internet_error.DNSLookupError: | 284 except (internet_error.DNSLookupError, internet_error.TimeoutError): |
260 log.warning(u"Can't access Domain Name System") | 285 log.warning(u"Can't access Domain Name System") |
261 ip = None | 286 ip = None |
262 else: | 287 else: |
263 self._external_ip_cache = ip | 288 self._external_ip_cache = ip |
264 defer.returnValue(ip) | 289 defer.returnValue(ip) |
290 | |
291 | |
292 class IPPlugin_handler(XMPPHandler): | |
293 implements(iwokkel.IDisco) | |
294 | |
295 def getDiscoInfo(self, requestor, target, nodeIdentifier=''): | |
296 return [disco.DiscoFeature(NS_IP_CHECK)] | |
297 | |
298 def getDiscoItems(self, requestor, target, nodeIdentifier=''): | |
299 return [] |