diff 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
line wrap: on
line diff
--- a/src/plugins/plugin_misc_ip.py	Fri Nov 06 17:09:45 2015 +0100
+++ b/src/plugins/plugin_misc_ip.py	Sun Nov 08 14:44:30 2015 +0100
@@ -28,6 +28,9 @@
 from twisted.internet import protocol
 from twisted.internet import endpoints
 from twisted.internet import error as internet_error
+from zope.interface import implements
+from wokkel import disco, iwokkel
+from twisted.words.protocols.jabber.xmlstream import XMPPHandler
 import urlparse
 try:
     import netifaces
@@ -40,9 +43,10 @@
     "name": "IP discovery",
     "import_name": "IP",
     "type": C.PLUG_TYPE_MISC,
+    "protocols": ["XEP-0279"],
     "recommendations": ["NAT-PORT"],
     "main": "IPPlugin",
-    "handler": "no",
+    "handler": "yes",
     "description": _("""This plugin help to discover our external IP address.""")
 }
 
@@ -62,6 +66,7 @@
     page = GET_IP_PAGE,
     domain = urlparse.urlparse(GET_IP_PAGE).netloc,
     app_name = C.APP_NAME)
+NS_IP_CHECK = "urn:xmpp:sic:1"
 
 PARAMS = """
     <params>
@@ -77,7 +82,6 @@
 class IPPlugin(object):
     # TODO: refresh IP if a new connection is detected
     # TODO: manage IPv6 when implemented in SàT
-    # TODO: implement XEP-0279
 
     def __init__(self, host):
         log.info(_("plugin IP discovery initialization"))
@@ -96,6 +100,9 @@
         self._external_ip_cache = None
         self._local_ip_cache = None
 
+    def getHandler(self, profile):
+        return IPPlugin_handler()
+
     def refreshIP(self):
         # FIXME: use a trigger instead ?
         self._external_ip_cache = None
@@ -174,7 +181,6 @@
         d.addCallback(gotConnection)
         return d
 
-
     @defer.inlineCallbacks
     def getLocalIPs(self, profile):
         """Try do discover local area network IPs
@@ -228,13 +234,12 @@
 
         try:
             ip_tuple = yield self._getIPFromExternal(GET_IP_PAGE)
-        except Exception as internet_error.DNSLookupError:
+        except (internet_error.DNSLookupError, internet_error.TimeoutError):
             log.warning(u"Can't access Domain Name System")
             defer.returnValue(addresses)
         self._insertFirst(addresses, ip_tuple.local)
         defer.returnValue(addresses)
 
-
     @defer.inlineCallbacks
     def getExternalIP(self, profile):
         """Try to discover external IP
@@ -245,20 +250,50 @@
         if self._external_ip_cache is not None:
             defer.returnValue(self._external_ip_cache)
 
-        # we first try with NAT-Port
+        # we first try with XEP-0279
+        if self.host.hasFeature(NS_IP_CHECK, profile=profile):
+            log.debug(u"Server IP Check available, we use it to retrieve our IP")
+            client = self.host.getClient(profile)
+            iq_elt = client.IQ("get")
+            iq_elt.addElement((NS_IP_CHECK, 'address'))
+            result_elt = yield iq_elt.send()
+            try:
+                address_elt = result_elt.elements(NS_IP_CHECK, 'address').next()
+                ip_elt = address_elt.elements(NS_IP_CHECK,'ip').next()
+            except StopIteration:
+                log.warning(u"Server returned invalid result on XEP-0279 request, we ignore it")
+            else:
+                # FIXME: server IP may not be the same as external IP (server can be on local machine or network)
+                #        IP should be checked to see if we have a local one, and rejected in this case
+                external_ip = str(ip_elt)
+                log.debug(u"External IP found: {}".format(external_ip))
+                self._external_ip_cache = external_ip
+                defer.returnValue(self._external_ip_cache)
+
+        # then with NAT-Port
         if self._nat is not None:
             nat_ip = yield self._nat.getIP()
             if nat_ip is not None:
                 self._external_ip_cache = nat_ip
                 defer.returnValue(nat_ip)
 
-        # then by requesting external website
+        # and finally by requesting external website
         allow_get_ip = yield self._externalAllowed(profile)
         try:
             ip = (yield webclient.getPage(GET_IP_PAGE)) if allow_get_ip else None
-        except internet_error.DNSLookupError:
+        except (internet_error.DNSLookupError, internet_error.TimeoutError):
             log.warning(u"Can't access Domain Name System")
             ip = None
         else:
             self._external_ip_cache = ip
         defer.returnValue(ip)
+
+
+class IPPlugin_handler(XMPPHandler):
+    implements(iwokkel.IDisco)
+
+    def getDiscoInfo(self, requestor, target, nodeIdentifier=''):
+        return [disco.DiscoFeature(NS_IP_CHECK)]
+
+    def getDiscoItems(self, requestor, target, nodeIdentifier=''):
+        return []