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

# Source Code for Module Products.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, unused, 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, unused, 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, unused=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