############################### ############################### ### ### ### README ### ### ### ############################### ############################### Umap v0.7 By Daniel Garcia formatez@toor.do Dependencies ------- Not much is needed, just Python > 2.6 and Python SoapPy. Executing ------- Umap works with a curses interface. Here are the arguments used by the program. -h: Help -c: Curses mode (Don't recommend NOT using curses) -v: Verbose output -p: Port / Port range (Internal Scanning) -l: List of IP blocks -i: Target IP -s: SOCKSv4 Proxy mode -b: IP SOCKS should bind to. -t: Number of maximum threads Here are some common ways to use Umap: (SOCKSv4 Proxy mode) - is the location of a filename containing an IP per line for scanning, it will automatically scan the whole class C block if specified on the list. If specified by the -i argument you can specify single ip's. On curses use the 'd' and 'u' keys to move around the iplist for the selection of positive hosts found, 'e' to execute upnp commands and 'q' to quit. ./umap.py -c -s -l -t 254 (Scanning internal network mode) - Scans an IP looking for available IGD control points, if it finds one it attempts to map internal hosts for scanning. ./umap.py -c -i (Scanning internal network mode) - Same as above but only scans ports specified in ./umap.py -c -i -p ############################### ############################### ### ### ### list ### ### ### ############################### ############################### # Format: x.x.x.x(per line) # Will scan the whole Class C block for each IP listed # example: 1.2.3.4 ############################### ############################### ### ### ### umap.py ### ### ### ############################### ############################### #!/usr/bin/python # Umap v0.7 (UPNP Map) # formatez@toor.do (Daniel Garcia) # http://www.toor.do/ # # UPNP NAT Hole puncher/Scanner # -------------------------------- # This program attempts to # 1) Scan open TCP ports on the hosts behind a UPNP enabled Internet Gateway Device(IGD) NAT. # 2) Add port forward using open WAN control points # 3) Act as a SOCKS v4 using port forwarding from open WAN control points # # # For more information on the subject: # http://www.upnp-hacks.org/ # http://www.gnucitizen.org/ # http://www.sourcesec.com/2008/11/07/miranda-upnp-administration-tool/ # # # # Code docs/comments coming soon. #import sys import os import socket, SocketServer import urllib2 import getopt import xml.dom.minidom as minidom import threading import Queue import random import time import uscan, usocks, upnpscan, uctui import curses from SOAPpy import * # The format for the XML descriptor locations is 'XML location | TCP Port | Type' knownLocations = ['/upnp/IGD.xml|80|0', '/allxml/|5431|1', '/devicedesc.xml|80|2', '/IGatewayDeviceDescDoc|2869|3', '/igd.xml|80|4', '/gatedesc.xml|49152|5', '/rootDesc.xml|5000|6'] # Default scanned ports commonPorts = ['21','22','23','80','137','138','139','443','445','8080'] # Uscan queue queue = Queue.Queue() # IP List upnpList = [] # Mappings list mapList = [] threadList = [] def main(): socks = 0 max_threads = 16 upnp_type = False verbose = False cursesMode = False portLow = 0 portHigh = 0 ip = '' file = '' bindIP = '' portList = [] selectedIP = 0 current_ip = 0 mapDict = {} selectedIPXML = {} headers = { 'USER-AGENT':'Umap/0.7', 'CONTENT-TYPE':'text/xml; charset="utf-8"' } try: opts, args = getopt.getopt(sys.argv[1:], "hcvst:i:p:l:b:", ["help", "curses", "verbose", "socks", "threads=", "ip=", "port=", "list=", "bind="]) except getopt.GetoptError, err: print str(err) sys.exit(2) if len(opts) == 0: print "No arguments specified" printhelp() sys.exit(2) for o,a in opts: if o == "-h": printhelp() sys.exit(2) if o == "-v": verbose = 1 if o == "-c": cursesMode = 1 if o == "-i": ip = a if o == "-p": if ',' in a: for port in a.split(','): if port.isdigit(): portList.append(port) else: print "[E] Wrong port number" elif '-' in a: (portLow, portHigh) = a.split('-') if portLow.isdigit() and portHigh.isdigit(): portLow = int(portLow) portHigh = int(portHigh) while portLow <= portHigh: portList.append(portLow) portLow += 1 else: if a.isdigit: portList.append(a) else: print "[E] Wrong port number" sys.exit() if o == "-t": if a.isdigit() and int(a) < 255: max_threads = a else: print "Error in threads" sys.exit() if o == "-s": socks = 1 if o == "-b": bindIP = a if not a: print "Error in bind IP" sys.exit() if o == "-l": if os.path.exists(a): file = a else: print "File doesn't exist!" sys.exit() if len(portList) == 0: for port in commonPorts: portList.append(port) if not ip and not socks: print "[E] Either target IP or socks option must be specified" sys.exit() if socks and (not file and not ip): print "[E] Must specify IP block list file or IP target" sys.exit() if ip and not socks: if cursesMode: scr = uctui.uCTUI(0, selectedIP, selectedIPXML, upnpList, mapList) scr.mainScreen.nodelay(1) scr.printMessage("Trying "+ip) scr.draw() upnpScan = upnpscan.UPNPScan(ip, upnpList, scr, selectedIPXML) upnpScan.setDaemon(True) upnpScan.start() upnpScan.join() if len(upnpList) == 0: scr.printMessage("[E] Couldn't find a match") else: splitUPnP = upnpList[0].split('|') location = splitUPnP[3]+"|"+splitUPnP[4]+"|"+splitUPnP[5] scanned = upnpScan.getInfo(location, ip, 1) guessIP() try: while True: if(threading.activeCount() < max_threads): current_ip = queue.get() if cursesMode: umap = uscan.Uscan(ip, current_ip, scanned, queue, verbose, portList, mapList, scr) else: umap = uscan.Uscan(ip, current_ip, scanned, queue, verbose, portList, mapList) umap.setDaemon(True) umap.start() if umap.stopIt.isSet(): break time.sleep(0.5) scr.draw() input = scr.mainScreen.getch() if input == ord('q'): scr.exitCurse() break except KeyboardInterrupt: scr.printMEssage("Caught interrupt! waiting for threads and exiting") umap.stopIt.set() umap.join() scr.exitCurse() if socks and (file or ip): scr = uctui.uCTUI(1, selectedIP, selectedIPXML, upnpList, mapList) if file: ipListfh = open(file, 'r') ipList = ipListfh.readlines() for line in ipList: c = 1 if line.find('#') != -1: continue splitIP = line.split('.') if len(splitIP) == 4: while c < 255: ip = str(splitIP[0])+"."+str(splitIP[1])+"."+str(splitIP[2])+"."+str(c) if c == 1: dip = ip.split('.') scr.printMessage("Adding block: "+ip) queue.put(ip) c += 1 else: scr.printMessage("[E]Error in format!") if ip: scr.printMessage("Adding: "+ip) queue.put(ip) try: socksServer = usocks.UsocksServer((bindIP, 1081), usocks.UsocksHandle) except: print "Error binding" sys.exit(0) socksServer.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) socksThread = threading.Thread(target=socksServer.serve_forever) socksThread.setDaemon(True) socksThread.start() totalCount = 0 try: while True: if not queue.empty(): current_ip = queue.get() upnpScan = upnpscan.UPNPScan(current_ip, upnpList, scr, selectedIPXML) scr.mainScreen.nodelay(1) time.sleep(0.5) scr.draw() input = scr.mainScreen.getch() lenUPnP = len(upnpList) scan = () if lenUPnP > 0 and selectedIP < lenUPnP and len(scr.selectedIPXML) == 0: splitUPnP = upnpList[scr.selectedIP].split('|') location = splitUPnP[3]+"|"+splitUPnP[4]+"|"+splitUPnP[5] scan = upnpScan.getInfo(location, upnpList[scr.selectedIP].split('|')[0], 1) if input == ord('q'): socksServer.shutdown() socksThread.join() scr.exitCurse() break if input == ord('r'): scr.mainScreen.refresh() if input == ord('e'): if lenUPnP == 0: scr.printMessage("No positive matches") return False scr.mainScreen.nodelay(0) scr.drawExecute() scr.mainScreen.nodelay(1) if input == ord('u') and selectedIP >= 0: scr.cursorUp() splitUPnP = upnpList[scr.selectedIP].split('|') location = splitUPnP[3]+"|"+splitUPnP[4]+"|"+splitUPnP[5] scr.selectedIPXML = {} mapDict = {} if input == ord('d') and selectedIP < lenUPnP: scr.cursorDown() splitUPnP = upnpList[scr.selectedIP].split('|') location = splitUPnP[3]+"|"+splitUPnP[4]+"|"+splitUPnP[5] scr.selectedIPXML = {} mapDict = {} socksServer.scan = scan socksServer.IPlist = upnpList socksServer.map = mapDict socksServer.scr = scr socksServer.selectedIP = selectedIP if(threading.activeCount() < int(max_threads)): totalCount += 1 if queue.empty() and current_ip == 0: continue else: scr.printMessage("Scanning("+str(threading.activeCount())+","+str(totalCount)+"): "+current_ip) upnpScan.setDaemon(True) upnpScan.start() threadList.append(upnpScan) current_ip = 0 else: for t in threadList: t.join() if upnpScan.stopIt.isSet(): break except KeyboardInterrupt: scr.printMessage("Caught interrupt! waiting for threads and exiting") upnpScan.stopIt.set() upnpScan.join() scr.exitCurse() def guessIP(): # TODO # Best guess of IP (10.0.0.0) ipGuess = '10.0.0.1' # ipGuess = base.split('://')[1].split(':')[0] (a,b,c,d) = ipGuess.split('.') d = int(d) originald = d d = 1 while d < 255: if d == originald: d += 1 continue d += 1 ipGuess = a+'.'+b+'.'+c+'.'+str(d) queue.put(ipGuess) def printhelp(): print "------------" print "Umap v0.7" print "By FormateZ" print "formatez@toor.do" print "------------" print "-h: Help" print "-b: Bind IP of SOCKS" print "-c: Curses mode" print "-v: Verbose output" print "-p: Port / Port range (Internal Scanning)" print "-l: File with list of IP's to be scanned" print "-i: Target IP" print "-s: SOCKSv4 Proxy mode" print "-t: Number of maximum threads" if __name__ == '__main__': main() ############################### ############################### ### ### ### upnpscan.py ### ### ### ############################### ############################### #!/usr/bin/python import urllib2 import asyncore import threading, random, socket import random from SOAPpy import * import xml.dom.minidom as minidom import sys import time # Much thanks to Dan Kaminsky for supplying most of these description XML's knownLocations = ['/upnp/IGD.xml|80|0', '/DeviceDescription.xml|80|1', '/allxml/|5431|2', '/devicedesc.xml|80|3', '/IGatewayDeviceDescDoc|2869|4', '/igd.xml|80|5', '/gatedesc.xml|49152|6', '/rootDesc.xml|5000|7', '/RootDevice.XML|50718|9', '/UPNP_rootDesc.xml|5819|10', '/rtdevdsc.xml|1900|11', '/gateway.xml|49152|12', '/rootDesc.xml|5555|13', '/upnp/igdrootdesc.xml|80|14', '/x_internetgatewaydevice.xml|80|15', '/desc.xml|80|16', '/DeviceDescrption.xml|9007|17', '/Public_UPNP_gatedesc.xml|80|18', '/gen-desc.xml|4004|19', '/__rootDevice|30888|20', '/gateconnSCPD.xml|80|21', '/RootDevice.xml|8008|22', '/device.xml|51004|23', '/upnp/service/descrip.xml|80|24', '/rootDesc.xml|8200|25', '/DeviceDescription.xml|62802|26', '/rootDesc.xml|65535|27', '/rootDesc.xml|8588|29', '/InternetGatewayDevice.xml|2800|30', '/UPNP_rootDesc.xml|5819|31', '/InternetGatewayDevice.xml|1780|32', '/RootDevice.xml|64340|33', '/igddesc.xml|49000|34', '/RootDevice.xml|34137|35'] class UPNPScan(threading.Thread, asyncore.dispatcher): def __init__(self, ip, upnpList, scr, selectedIPXML): threading.Thread.__init__ (self) asyncore.dispatcher.__init__(self) self.stopIt = threading.Event() self.ip = ip self.upnpList = upnpList self.selectedIPXML = selectedIPXML self.scr = scr def run(self): headers = { 'USER-AGENT':'Umap/0.7', 'CONTENT-TYPE':'text/xml; charset="utf-8"' } for location in knownLocations: data = False (link, port, upnpType) = location.split('|') requestLocation = "http://%s:%s%s" % (self.ip, port, link) try: socket.setdefaulttimeout(6) request = urllib2.Request(requestLocation, None) response = urllib2.urlopen(request) headers = response.info() data = response.read() except Exception, err: continue if data and data.find('xml') != -1: upnp_type = location self.scr.printMessage("[*] Positive match "+requestLocation) self.soapInfo = self.getInfo(location, self.ip, 0) try: self.upnpList.append(str(self.ip)+"|"+str(self.soapInfo[2])+"|"+str(port)+"|"+str(location)+"|"+str(self.soapInfo[1])+"|"+str(self.soapInfo[0])+"|"+str(self.soapInfo[6])) except: continue break def getInfo(self, location, ip, paint): st = time.time() (link, port, upnpType) = location.split('|') requestLocation = "http://%s:%s%s" % (ip, port, link) on = 0 out = {} newXml = '' location = '' data = '' base = '' tags = ['URLBase', 'friendlyName', 'modelDescription', 'modelName', 'modelNumber', 'serialNumber', 'UDN'] try: request = urllib2.Request(requestLocation, None) response = urllib2.urlopen(request) headers = response.info() xmlData = response.read() except Exception, err: return False ed = time.time() for line in xmlData.split('\n'): if '"+self.ip+":"+str(port)) s.close() except Exception, err: open = 0 s.close() if self.verbose: self.scr.printMessage("Closed port "+str(err)) if not open: endpoint = "http://%s:%s%s" % (self.uip, self.port, self.soapInfo[2]) namespace = self.soapInfo[0] soapaction = namespace+"#DeletePortMapping" server = SOAPProxy(endpoint, namespace) try: self.scr.printMessage("Deleting: "+str(thisport)) server._sa(soapaction).DeletePortMapping(NewRemoteHost="", NewExternalPort=thisport, NewProtocol="TCP") except Exception, err: self.scr.printMessage("[E] Error deleting port "+str(thisport)) ############################### ############################### ### ### ### usocks.py ### ### ### ############################### ############################### #!/usr/bin/python import thread import SocketServer, socket import struct import sys import random import string from SOAPpy import * from time import time class UsocksHandle(SocketServer.BaseRequestHandler): def pipe(self,src,dest): while 1: try: r = src.recv(4096) except Exception as e: self.server.scr.printMessage("Receive "+str(e)) src.close() dest.close() break if not r: src.close() dest.close() break try: dest.send(r) except Exception as e: self.server.scr.printMessage("Send "+str(e)) src.close() dest.close() break def handle(self): outData = [] inData = [] selectedIP = self.server.scr.selectedIP positive = self.server.IPlist mapDict = self.server.map scr = self.server.scr sys.stdout = open("/dev/null") sys.stderr = open("/dev/null") socksFormat = '!BBH4s' socksResponseOK = struct.pack('!BBHI',0,0x5a,0,0) socksFail = struct.pack('!BBHI',0,0x5b,0,0) while 1: initialData = self.request.recv(struct.calcsize(socksFormat)) if not initialData: scr.printMessage("Dropped request") break (socks_ver,command,target_port,target_addr) = struct.unpack(socksFormat,initialData) (target_addr_int,) = struct.unpack('!I',target_addr) target_addr = socket.inet_ntoa(target_addr) if len(positive) == 0: scr.printMessage("[E] Can't processs request without positive matches") self.request.send(socksFail) self.request.close() continue if command == 1: port = target_port ip = target_addr lenPositives = len(positive) scr.printMessage("Processing("+str(selectedIP)+"): "+ip+" from "+str(self.client_address[0])) rhost = positive[selectedIP].split('|')[0] rendpoint = positive[selectedIP].split('|')[1] rendpointport = positive[selectedIP].split('|')[2] serviceType = positive[selectedIP].split('|')[7] self.rhost = rhost rport = random.randint(10000,20000) self.rport = rport # # TODO if mapDict.has_key(ip+':'+str(port)): thisMap = mapDict[ip+':'+str(port)].split(':') rhost = thisMap[0] rport = thisMap[1] self.rhost = rhost self.rport = rport scr.printMessage("Already mapped "+rhost+":"+rport) else: endpoint = "http://"+rhost+":"+str(rendpointport)+rendpoint scr.printMessage("Trying to add: "+str(rhost)+":"+str(rport)+"|"+str(ip)+":"+str(port)) namespace = serviceType server = SOAPProxy(endpoint, namespace) soapaction = serviceType+"#AddPortMapping" try: server._sa(soapaction).AddPortMapping(NewRemoteHost="", NewExternalPort=rport, NewProtocol="TCP", NewInternalPort=port, NewInternalClient=ip, NewEnabled=1, NewPortMappingDescription=7, NewLeaseDuration=0) mapDict[ip+":"+str(port)] = rhost+":"+str(rport)+":"+str(int(time())) except Exception, err: scr.printMessage("Exception adding "+str(err)+rendpoint) self.request.send(socksFail) self.request.close() continue if mapDict.has_key(ip+':'+str(port)): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect((rhost, int(rport))) except: scr.printMessage("Couldn't connect to mapped port") self.request.send(socksFail) self.request.close() continue else: mapDict[ip+':'+str(port)] = rhost+':'+str(rport)+':'+str(time()) sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.setdefaulttimeout(20) try: sock.connect((rhost, int(rport))) except: scr.printMessage("Couldn't connect to mapped port") self.request.send(socksFail) self.request.close() continue self.request.send(socksResponseOK) thread.start_new_thread(self.pipe,(self.request,sock)) thread.start_new_thread(self.pipe,(sock,self.request)) if mapDict.has_key(ip+':'+str(port)): current = time() if (int(current) - int(mapDict[ip+':'+str(port)].split(':')[2])) > 60: scr.printMessage("Closing up "+self.rhost+" "+str(self.rport)) endpoint = "http://"+self.rhost+"/upnp/control/igd/wanpppcInternet" soapaction = serviceType+"#DeletePortMapping" try: server = SOAPProxy(endpoint, namespace) server._sa(soapaction).DeletePortMapping(NewRemoteHost="", NewExternalPort=self.rport, NewProtocol="TCP") del mapDict[ip+':'+str(port)] except: scr.printMessage("Exception deleting") pass class UsocksServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer): pass ############################### ############################### ### ### ### uctui.py ### ### ### ############################### ############################### #!/usr/bin/python import curses import collections import copy import xml.dom.minidom as minidom import urllib2 from SOAPpy import * UPnPActions = ['SetConnectionType', 'GetConnectionTypeInfo', 'ConfigureConnection', 'RequestConnection', 'RequestTermination', 'ForceTermination', 'SetAutoDisconnectTime', 'SetIdleDisconnectTime', 'SetWarnDisconnectDelay', 'GetStatusInfo', 'GetLinkLayerMaxBitRates', 'GetPPPEncryptionProtocol', 'GetPPPCompressionProtocol', 'GetPPPAuthenticationProtocol', 'GetUserName', 'GetPassword', 'GetAutoDisconnectTime', 'GetIdleDisconnectTime', 'GetWarnDisconnectDelay', 'GetNATRSIPStatus', 'GetGenericPortMappingEntry', 'GetSpecificPortMappingEntry', 'AddPortMapping', 'DeletePortMapping', 'GetExternalIPAddress'] class uCTUI(): def __init__(self, type, selectedIP, selectedIPXML, upnpList, mapList): self.type = type self.scan = '' self.mapList = mapList self.upnpList = upnpList self.selectedIPXML = selectedIPXML self.messagesQueue = collections.deque() self.positiveQueue = collections.deque() self.cursorPos = 0 self.selectedIP = selectedIP self.qSize = 0 self.mainScreen = curses.initscr() self.mainMax = self.mainScreen.getmaxyx() self.mainScreen.clear() self.mainScreen.subwin(self.mainMax[0], self.mainMax[1], 0, 0) self.messagesLimit = self.mainMax[1] self.mainScreen.box() curses.noecho() curses.cbreak() self.mainScreen.refresh() def draw(self): start = 0 if self.type == 1: self.positiveWindow = curses.newwin(20,20,1,1) self.positiveWindow.box() self.positiveWindow.addstr(0,1,"Positive IP's",curses.A_REVERSE) self.positiveWindow.refresh() self.detailWindow = curses.newwin(20,self.mainMax[1]-25,1,22) self.detailWindow.box() if len(self.upnpList) > 0: dselectedIP = self.upnpList[self.selectedIP].split('|')[0] dselectedService = self.upnpList[self.selectedIP].split('|')[7].split(':')[3] dselectedTiming = self.upnpList[self.selectedIP].split('|')[8].split('.')[0] else: dselectedIP = '' dselectedService = '' dselectedTiming = '-' self.detailWindow.addstr(0,1,"UPnP Details - |Selected IP: "+dselectedIP+" |Total positives: "+str(len(self.upnpList))+" |Service: "+dselectedService+" |Timing: "+dselectedTiming+"ms",curses.A_REVERSE) dcount = 1 for k in self.selectedIPXML: if dcount < 20: self.detailWindow.addstr(dcount,1,str(k)+": "+str(self.selectedIPXML[k])) dcount = dcount + 1 self.detailWindow.refresh() self.messagesWindow = curses.newwin(self.mainMax[0]-22, self.mainMax[1]-4, 21, 1) self.messagesWindow.box() self.messagesWindow.addstr(0,1,"Messages",curses.A_REVERSE) self.messagesWindow.refresh() count = 1 if self.selectedIP >= range(19,254,19)[0]: start = self.selectedIP end = self.selectedIP+19 elif self.selectedIP >= range(19,254,19)[1]: start = self.selectedIP end = self.selectedIP+19 for positive in self.upnpList: if count < start+1: count += 1 continue if self.selectedIP < start+19 and start > 18 and count < end: self.positiveWindow.addstr(count-start,1,str(count-start)+"-"+positive.split('|')[0]) count = count + 1 if self.selectedIP == count-1: self.positiveWindow.addstr(count-start,1,str(count-start)+"+"+positive.split('|')[0],curses.A_REVERSE) count = count + 1 continue if count < 19 and start == 0: self.positiveWindow.addstr(count,1,str(count)+"-"+positive.split('|')[0]) count = count + 1 self.positiveWindow.refresh() else: self.mappingWindow = curses.newwin(20,47,1,1) self.mappingWindow.box() self.mappingWindow.addstr(0,1,"Mappings",curses.A_REVERSE) mcount = 1 for map in self.mapList: if mcount < 20: self.mappingWindow.addstr(mcount,1,str(map)) mcount = mcount + 1 self.mappingWindow.refresh() self.detailWindow = curses.newwin(20,self.mainMax[1]-52,1,48) self.detailWindow.box() self.detailWindow.addstr(0,1,"UPnP Details",curses.A_REVERSE) dcount = 1 for k in self.selectedIPXML: if dcount < 20: self.detailWindow.addstr(dcount,1,str(k)+": "+str(self.selectedIPXML[k])) dcount = dcount + 1 self.detailWindow.refresh() it = self.mainMax[0]-22 self.messagesWindow = curses.newwin(self.mainMax[0]-22, self.mainMax[1]-4, 21, 1) self.messagesWindow.box() self.messagesWindow.addstr(0,1,"Messages",curses.A_REVERSE) self.messagesWindow.refresh() count = 1 for map in self.mapList: if count < 20: self.mappingWindow.addstr(count,1,str(count)+"-"+map) count = count + 1 qCopy = copy.deepcopy(self.messagesQueue) count = 1 for message in qCopy: self.messagesWindow.addstr(count,1,str(message)) count = count + 1 self.messagesWindow.refresh() def drawExecute(self): actionNumber = {} actionList = [] argumentDict = {} stateVars = {} inputArgs = {} if len(self.upnpList) == 0: return False self.executeWindow = curses.newwin(40,self.mainMax[1]-25,3,5) self.executeWindow.box() self.executeWindow.refresh() try: nowIP = self.upnpList[self.selectedIP].split('|')[0] nowPort = self.upnpList[self.selectedIP].split('|')[2] nowXML = self.upnpList[self.selectedIP].split('|')[6] scpd = "http://"+nowIP+":"+nowPort+nowXML request = urllib2.Request(scpd, None) response = urllib2.urlopen(request) headers = response.info() xmlData = response.read() except Exception, err: return False xmlRoot = minidom.parseString(xmlData) for stateVar in xmlRoot.getElementsByTagName('stateVariable'): stateVarName = stateVar.getElementsByTagName('name')[0].childNodes[0].data stateVarType = stateVar.getElementsByTagName('dataType')[0].childNodes[0].data stateVars[str(stateVarName)] = str(stateVarType) for action in xmlRoot.getElementsByTagName('action'): actionName = action.getElementsByTagName('name')[0].childNodes[0].data actionList.append(str(actionName)) argumentDict[actionName] = '' for argument in action.getElementsByTagName('argument'): lenAction = len(actionList) nowArg = argument.getElementsByTagName('name')[0].childNodes[0].data relatedVar = argument.getElementsByTagName('relatedStateVariable')[0].childNodes[0].data direction = argument.getElementsByTagName('direction')[0].childNodes[0].data if argumentDict[actionName] == '': argumentDict[actionName] = nowArg+":"+stateVars[relatedVar]+":"+direction else: argumentDict[actionName] = argumentDict[actionName]+"|"+nowArg+":"+stateVars[relatedVar]+":"+direction count = 1 for action in actionList: strCount = str(count) self.executeWindow.addstr(count,1,strCount+"-"+str(action)) actionNumber[strCount] = str(action) count = count + 1 for action in UPnPActions: strCount = str(count) if action in actionList: continue self.executeWindow.addstr(count,1,strCount+"-"+str(action),curses.A_BOLD) actionNumber[strCount] = str(action) count = count + 1 self.executeWindow.refresh() selection = self.executeWindow.getstr() if not selection.isdigit() or int(selection) > count: self.mainScreen.clear() self.mainScreen.refresh() self.printMessage("Error in selection") return False try: nowAction = actionNumber.get(selection) if argumentDict.has_key(nowAction): nowArgs = argumentDict[nowAction].split('|') else: nowArgs = '' for nowArg in nowArgs: nowArg = nowArg.split(':') if nowArg[2] == 'out': continue self.executeWindow.clear() self.executeWindow.refresh() curses.echo() self.executeWindow.addstr(1,1,"Insert("+str(nowArg[1])+") "+str(nowArg[0])+":") input = self.executeWindow.getstr() curses.noecho() inputArgs[str(nowArg[0])] = str(input)+"|"+str(nowArg[1]) self.executeWindow.refresh() except Exception, err: self.printMessage("Error in selection "+str(err)) return False sendParms = self.upnpList[self.selectedIP].split('|') if selection == '99': soapRequest = self.sendSoap(sendParms[1], sendParms[0], sendParms[2], sendParms[7], "GetPPPAuthenticationProtocol", inputArgs) else: soapRequest = self.sendSoap(sendParms[1], sendParms[0], sendParms[2], sendParms[7], actionNumber.get(selection), inputArgs) newXML = '' if not soapRequest or 'faultString' in soapRequest: self.printMessage("Error in UPnP Request") return False try: for s in soapRequest: newXML += s+'\n' xmlResponse = minidom.parseString(newXML) ecount = 1 self.executeWindow.clear() self.executeWindow.refresh() if argumentDict.has_key(nowAction): nowArgs = argumentDict[nowAction].split('|') for nowArg in nowArgs: nowArg = nowArg.split(':') if nowArg[2] == 'in': continue responseValue = xmlResponse.getElementsByTagName(nowArg[0])[0].childNodes[0].data if not responseValue: continue self.executeWindow.addstr(ecount,1,nowArg[0]+": "+responseValue) ecount = ecount + 1 else: nowArgs = '' for r in xmlResponse.getElementsByTagName('s:Body'): outerBody = r.childNodes[1] inner = outerBody.childNodes[1].toxml() if not inner: continue self.executeWindow.addstr(ecount,1,inner) self.executeWindow.addstr(ecount+5,1,"Press any key to continue") self.executeWindow.refresh() self.executeWindow.getch() except Exception, err: self.printMessage("Exception: "+str(err)) return False del self.executeWindow self.mainScreen.clear() self.mainScreen.refresh() def sendSoap(self, control, ip, port, device, action, inputArgs = ''): body = [] bodyStr = '\n' if len(inputArgs) > 0: for k,v in inputArgs.iteritems(): splitv = v.split('|') try: body.append("<"+k+" xsi:type=\"xsd:"+splitv[1]+"\">"+splitv[0]+"") except Exception, err: self.printMessage("Exception "+str(v)) for b in body: bodyStr = bodyStr+str(b)+"\n" bodyStr = bodyStr+"" payload = """ """+bodyStr+""" \r\n\r\n """ head = """POST """+control+""" HTTP/1.0\r Host: """+ip+"""\r User-agent: Umap v0.5 UPnP/1.1 None\r Content-type: text/xml; charset="UTF-8"\r Content-length: """+str(len(payload))+"""\r SOAPAction: """+'"'+device+'#'+action+'"'+"""\r \r\n""" sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: sock.connect((ip, int(port))) except Exception, err: self.printMessage("Error connecting for SOAP request") return False sock.send(head+payload) soapRcvStr = '' while 1: try: soapRcv = sock.recv(2048) except Exception, err: self.printMessage("Error receiving "+str(err)) return False if not soapRcv: break soapRcvStr += soapRcv sock.close f = 0 response = [] for s in soapRcvStr.split('\n'): if '