def hangup(unused_sig: int, unused_frame: object): """ Handles the SIGHUP signal by re-reading conf files (if available) and resuming execution """ global confFile, collectors # Signal to the threads to stop for collector in collectors: collector.pipe[0].send(True) # Wait for the threads to exit for collector in collectors: collector.join() # Re-read the input file if exists # If it doesn't, print an error and go about your business if not confFile: utils.error(IOError("No input file to read! (input given on stdin)")) else: readConf() for collector in collectors: collector.start() raise ContinueException()
def pingloop(self): """ Runs a loop for collecting ping statistics as specified in the configuration. """ printFunc = self.printJSONPing if self.conf.JSON else self.printPing try: # with multiprocessing.pool.ThreadPool(self.conf.NUMPINGS) as pool, ping.Pinger(self.host, bytes(self.conf.PAYLOAD)) as pinger: # while True: # try: # self.ping(pool, pinger) # except multiprocessing.TimeoutError: # self.result[0] = utils.PingResult(-1, -1, -1, -1, 100.) # printFunc() # time.sleep(self.conf.PING / 1000) with ping.Pinger(self.host, bytes(self.conf.PAYLOAD)) as pinger: while True: try: printFunc(pinger.sendAll(self.conf.NUMPINGS)) except (socket.gaierror, OSError, TimeoutError) as e: utils.error(e) printFunc(utils.PingResult(-1, -1, -1, -1, 100.)) time.sleep(self.conf.PING / 1000) except KeyboardInterrupt: pass
def readConf(): """ Reads a configuration file. Expects a file object, which can be a true file or a pipe such as stdin """ global collectors, confFile, config # Try to open config file if exists, fatal error if file pointed to # Does not/no longer exist(s) if confFile: try: file = open(confFile) except OSError as e: utils.error(FileNotFoundError("Couldn't read input file '%s'"%e), fatal=True) hosts = file.readlines() file.close() # Closing stdin can cause huge problems, esp. for e.g. debuggers else: hosts = sys.stdin.readlines() # You need to clear this, or the monitor will keep querying old hosts. collectors = [] #parse args for i,host in enumerate(hosts): # ignore empty lines if not host.strip(): continue args = host.split() host = args.pop(0) addrinfo = utils.getaddr(host) if not addrinfo: utils.error(Exception("Unable to resolve host ( %s )" % host)) sys.stderr.flush() continue conf = {"HOSTS": {host: addrinfo}} try: for arg, value in [a.upper().split('=') for a in args]: conf[arg] = config[arg](value) except ValueError as e: utils.error(IOError("Error parsing value for %s: %s" % (arg,e)), True) except KeyError as e: utils.error(IOError("Error in config file - unknown option '%s'" % arg), True) collectors.append(Collector(host, i+1, Config(**conf))) if not collectors: utils.error(Exception("No hosts could be parsed!"), fatal=True)
def main() -> int: """ Runs the main routine, returning an exit status indicating successful termination """ global confFile, collectors signal.signal(signal.SIGHUP, hangup) signal.signal(signal.SIGTERM, terminate) # Construct a persistent monitor based on argv if len(sys.argv) > 1: confFile = sys.argv[1] readConf() # Start the collectors for c in collectors: c.start() # The main thread just checks to see that all of the sub-threads are still going, and handles # exceptions. try: while True: try: time.sleep(5) if not collectors or not any(c.is_alive() for c in collectors): return 1 except ContinueException: pass except KeyboardInterrupt: for c in collectors: c.pipe[0].send(True) for c in collectors: c.join() except Exception as e: utils.error(e) return 1 print() # Flush the buffer return 0
def run(self): """ Called when the thread is run """ # Determine output headers now to save time later self.plaintextHdr = self.hostname if self.host[0] != self.hostname: self.plaintextHdr += " " + self.host[0] if self.conf.TIMESTAMP: self.jsonHdr = '{"addr":"%s","name":"%s","timestamp":%%f,%%s}' else: self.jsonHdr = '{"addr":"%s", "name":"%s", %%s}' self.jsonHdr %= (self.host[0], self.hostname) numThreads = sum(int(bool(x)) for x in (self.conf.PING, self.conf.TRACE, self.conf.SCAN)) with multiprocessing.pool.ThreadPool(numThreads) as pool: try: waitables = [] if self.conf.SCAN: waitables.append(pool.apply_async(self.portscanloop, (), error_callback=utils.error)) if self.conf.TRACE: waitables.append(pool.apply_async(self.traceloop, (), error_callback=utils.error)) if self.conf.PING: waitables.append(pool.apply_async(self.pingloop, (), error_callback=utils.error)) for waitable in waitables: waitable.wait() pool.close() pool.join() except KeyboardInterrupt: pass except Exception as e: utils.error("Unknown Error Occurred while polling.") utils.error(e)