Package Products :: Package ZenUtils :: Module PortScan
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenUtils.PortScan

  1  ############################################################################## 
  2  #  
  3  # Copyright (C) Zenoss, Inc. 2007, all rights reserved. 
  4  #  
  5  # This content is made available according to terms specified in 
  6  # License.zenoss under the directory where your Zenoss product is installed. 
  7  #  
  8  ############################################################################## 
  9   
 10   
 11  import logging 
 12   
 13  from twisted.internet import defer 
 14  from twisted.internet import reactor 
 15  from twisted.internet.protocol import Protocol 
 16  from twisted.internet.protocol import ClientFactory 
 17  from twisted.internet.protocol import ReconnectingClientFactory 
 18  from twisted.internet.error import ConnectBindError 
 19   
 20  log = logging.getLogger("zen.Portscanner") 
 21   
22 -class ScanProtocol(Protocol):
23
24 - def connectionMade(self):
25 self.factory.deferred.callback("success") 26 self.transport.loseConnection()
27
28 -class ScanFactory(ClientFactory):
29 30 protocol = ScanProtocol 31
32 - def __init__(self):
33 self.deferred = defer.Deferred()
34
35 - def clientConnectionFailed(self, unused, reason):
36 self.deferred.errback(reason) 37 self.deferred = None
38
39 - def clientConnectionLost(self, connector, reason):
40 pass
41
42 -class ReconnectingScanFactory(ReconnectingClientFactory):
43 44 protocol = ScanProtocol 45
46 - def __init__(self):
47 self.deferred = defer.Deferred()
48
49 - def clientConnectionFailed(self, connector, reason):
50 self.deferred.errback(reason) 51 if reason.type == ConnectBindError: 52 self.connector = connector 53 self.retry()
54
55 -class Scanner(object):
56 ''' 57 '''
58 - def __init__(self, hosts, portRange=(1, 10000), portList=[], 59 queueCount=50, timeout=30):
60 if isinstance(hosts, list): 61 self.hosts = hosts 62 else: 63 self.hosts = [hosts] 64 self.portRange = (portRange[0], portRange[1] + 1) 65 self.portList = portList 66 self.queueCount = queueCount 67 self.timeout = timeout 68 self.data = { 69 'success': {}, 70 'failure': {}, 71 }
72
73 - def prepare(self):
74 ''' 75 The use of DeferredSemaphore() here allows us to control the 76 number of deferreds (and therefore connections) created at once, 77 thus providing a way for systems to use the script efficiently. 78 ''' 79 80 dl = [] 81 semaphore = defer.DeferredSemaphore(self.queueCount) 82 if self.portList: 83 ports = self.portList 84 else: 85 ports = range(*self.portRange) 86 for host in self.hosts: 87 for port in ports: 88 d = semaphore.run(self.doFactory, host, port) 89 dl.append(d) 90 dl = defer.DeferredList(dl, consumeErrors=True) 91 return dl
92
93 - def run(self):
94 d = self.prepare() 95 d.addCallback(self.finishRun) 96 reactor.run()
97
98 - def doFactory(self, host, port):
99 factory = ScanFactory() 100 reactor.connectTCP(host, port, factory, timeout=self.timeout) 101 d = factory.deferred 102 d.addCallback(self.recordConnection, host, port) 103 d.addErrback(self.recordFailure, host, port) 104 return d
105
106 - def recordConnection(self, unused, host, port):
107 hostData = self.data['success'].setdefault(host, []) 108 log.debug('Connected to %s:%d' % (host, port)) 109 hostData.append(port)
110
111 - def recordFailure(self, failure, host, port):
112 hostData = self.data['failure'].setdefault(host, []) 113 data = (port, failure.getErrorMessage()) 114 log.debug('Failed to connect to %s:%d -- %s' (host, port, data[1])) 115 hostData.append(data)
116
117 - def finishRun(self, unused=None):
118 reactor.stop() 119 self.printResults()
120
121 - def printResults(self):
122 print "Open Ports:" 123 for host, ports in self.getSuccesses().items(): 124 print "Host: %s" % host 125 for port in ports: 126 print "\topen port: %i" % port 127 errors = {} 128 for host, portAndError in self.getFailures().items(): 129 for port, error in portAndError: 130 errors.setdefault(error, 0) 131 errors[error] += 1 132 print "\nErrors encountered, and their counts:" 133 for error, count in errors.items(): 134 print "\t%s -- %i" % (error, count)
135
136 - def getSuccesses(self):
137 return self.data['success']
138
139 - def getFailures(self):
140 return self.data['failure']
141