Cleanup UPnP

This commit is contained in:
Peter Šurda 2015-11-21 00:39:23 +01:00
parent b93308d7ab
commit 51a152e44e
Signed by untrusted user: PeterSurda
GPG Key ID: 0C5F50C0B5F37D87

View File

@ -7,7 +7,6 @@ from struct import unpack, pack
import shared import shared
routers = [] routers = []
recurDepth = 0
def searchRouter(): def searchRouter():
from debug import logger from debug import logger
@ -133,6 +132,20 @@ class Router:
if service.childNodes[0].data.find('WANIPConnection') > 0: if service.childNodes[0].data.find('WANIPConnection') > 0:
self.path = service.parentNode.getElementsByTagName('controlURL')[0].childNodes[0].data 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): def AddPortMapping(self, externalPort, internalPort, internalClient, protocol, description, leaseDuration = 0, enabled = 1):
resp = self.soapRequest('WANIPConnection:1', 'AddPortMapping', [ resp = self.soapRequest('WANIPConnection:1', 'AddPortMapping', [
('NewExternalPort', str(externalPort)), ('NewExternalPort', str(externalPort)),
@ -143,6 +156,7 @@ class Router:
('NewPortMappingDescription', str(description)), ('NewPortMappingDescription', str(description)),
('NewLeaseDuration', str(leaseDuration)) ('NewLeaseDuration', str(leaseDuration))
]) ])
self.extPort = externalPort
return resp return resp
def DeletePortMapping(self, externalPort, protocol): def DeletePortMapping(self, externalPort, protocol):
@ -160,6 +174,7 @@ class Router:
def soapRequest(self, service, action, arguments=[]): def soapRequest(self, service, action, arguments=[]):
from xml.dom.minidom import parseString from xml.dom.minidom import parseString
from debug import logger
conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port) conn = httplib.HTTPConnection(self.routerPath.hostname, self.routerPath.port)
conn.request( conn.request(
'POST', 'POST',
@ -174,52 +189,41 @@ class Router:
dom = parseString(resp) dom = parseString(resp)
errinfo = dom.getElementsByTagName('errorDescription') errinfo = dom.getElementsByTagName('errorDescription')
if len(errinfo) > 0: if len(errinfo) > 0:
logger.error("UPnP error: %s", resp)
raise UPnPError(errinfo[0].childNodes[0].data) raise UPnPError(errinfo[0].childNodes[0].data)
return resp 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(): def createPortMapping():
from debug import logger from debug import logger
global routers global routers
global recurDepth
if recurDepth > 50:
logger.error("Too many failures requesting UPnP port mapping, giving up.")
return
routers = searchRouter() routers = searchRouter()
localIPs = socket.gethostbyname_ex(socket.gethostname())[2]
logger.debug("Found %i UPnP routers", len(routers)) 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: for router in routers:
routerIP, = unpack('>I', socket.inet_aton(router.address)) createPortMappingInternal(router)
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
def deletePortMapping(): def deletePortMapping():
for router in routers: for router in routers:
router.DeletePortMapping(shared.extPort, 'TCP') if hasattr(router, "extPort"):
router.DeletePortMapping(router.extPort, 'TCP')