From 51a152e44e648b4817473ef03aecf1c10c1f323e Mon Sep 17 00:00:00 2001 From: Peter Surda Date: Sat, 21 Nov 2015 00:39:23 +0100 Subject: [PATCH] Cleanup UPnP --- src/upnp.py | 78 ++++++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 37 deletions(-) diff --git a/src/upnp.py b/src/upnp.py index d0ec5b01..b3ce48f1 100644 --- a/src/upnp.py +++ b/src/upnp.py @@ -7,7 +7,6 @@ from struct import unpack, pack import shared routers = [] -recurDepth = 0 def searchRouter(): from debug import logger @@ -133,6 +132,20 @@ class Router: if service.childNodes[0].data.find('WANIPConnection') > 0: self.path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data + # get local IP + s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + try: + logger.debug("Connecting to %s:%i", self.address, self.routerPath.port) + s.connect ((self.address, self.routerPath.port)) + except: + pass + self.localAddress = s.getsockname()[0] + logger.debug("Local IP: %s", self.localAddress) + try: + s.close() + except: + pass + def AddPortMapping(self, externalPort, internalPort, internalClient, protocol, description, leaseDuration = 0, enabled = 1): resp = self.soapRequest('WANIPConnection:1', 'AddPortMapping', [ ('NewExternalPort', str(externalPort)), @@ -143,6 +156,7 @@ class Router: ('NewPortMappingDescription', str(description)), ('NewLeaseDuration', str(leaseDuration)) ]) + self.extPort = externalPort return resp def DeletePortMapping(self, externalPort, protocol): @@ -160,6 +174,7 @@ class Router: def soapRequest(self, service, action, arguments=[]): from xml.dom.minidom import parseString + from debug import logger conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port) conn.request( 'POST', @@ -174,52 +189,41 @@ class Router: dom = parseString(resp) errinfo = dom.getElementsByTagName('errorDescription') if len(errinfo) > 0: + logger.error("UPnP error: %s", resp) raise UPnPError(errinfo[0].childNodes[0].data) return resp +def createPortMappingInternal(router): + from debug import logger + + for i in range(0, 50): + try: + routerIP, = unpack('>I', socket.inet_aton(router.address)) + localIP = router.localAddress + localPort = shared.config.getint('bitmessagesettings', 'port') + if i == 0: + extPort = localPort # try same port first + else: + extPort = randint(32767, 65535) + logger.debug("Requesting UPnP mapping for %s:%i on external port %i", localIP, localPort, extPort) + router.AddPortMapping(extPort, localPort, localIP, 'TCP', 'BitMessage') + logger.info("Successfully established UPnP mapping for %s:%i on external port %i", localIP, localPort, extPort) + shared.extPort = extPort + break + except UPnPError: + logger.debug("UPnP error: ", exc_info=True) def createPortMapping(): from debug import logger global routers - global recurDepth - - if recurDepth > 50: - logger.error("Too many failures requesting UPnP port mapping, giving up.") - return - + routers = searchRouter() - localIPs = socket.gethostbyname_ex(socket.gethostname())[2] logger.debug("Found %i UPnP routers", len(routers)) - for i in range(len(localIPs)): - localIPs[i], = unpack('>I', socket.inet_aton(localIPs[i])) - try: - #add port mapping for each router - for router in routers: - routerIP, = unpack('>I', socket.inet_aton(router.address)) - localIP = None - minDiff = 0xFFFFFFFF - #find nearest localIP as clientIP to specified router - for IP in localIPs: - if IP ^ routerIP < minDiff: - minDiff = IP ^ routerIP - localIP = IP - - localIP = socket.inet_ntoa(pack('>I', localIP)) - localPort = shared.config.getint('bitmessagesettings', 'port') - if recurDepth == 0: - extPort = localPort # try same port first - else: - extPort = str(randint(32767, 65535)) - logger.debug("Requesting UPnP mapping on external port %i", extPort) - router.AddPortMapping(extPort, localPort, localIP, 'TCP', 'BitMessage') - logger.info("Successfully established UPnP mapping on external port %i", extPort) - shared.extPort = extPort - except UPnPError: - recurDepth += 1 - createPortMapping() - recurDepth -= 1 + for router in routers: + createPortMappingInternal(router) def deletePortMapping(): for router in routers: - router.DeletePortMapping(shared.extPort, 'TCP') + if hasattr(router, "extPort"): + router.DeletePortMapping(router.extPort, 'TCP')