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

Source Code for Module ZenUtils.PortScan

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