import datetime, encodings.idna, os, porttools, servertools.dbconn, setuptools, socket, socketserver, ssltools, sys, syslog, threading SYSLOG = 0 STDOUT = 1 STDDEB = 2 # STDOUT + Debug SILENT = 9 # Quiet mode SSL = 0 PORT = 1 logging = STDOUT try: exec("logging = " + setuptools.getSetting("Log", "sink")) except: pass def logger(message, prio=syslog.LOG_INFO, sink=logging): if sink in (STDOUT, STDDEB): if prio not in (syslog.LOG_NOTICE, syslog.LOG_INFO, syslog.LOG_DEBUG): print(message) sys.stderr.write(message) elif prio != syslog.LOG_DEBUG or sink == STDDEB: print(message) elif sink == SYSLOG: syslog.openlog("KumiStatusServer", syslog.LOG_PID) syslog.syslog(prio, message) elif sink != SILENT: try: sys.stderr.write("Unknown logging level %s, assuming STDOUT from now on." % str(sink)) except: pass logging = STDOUT logger(message, prio, logging) def listIncluded(host, section): if not setuptools.getListSetting("Server", "ignorelist"): for i in setuptools.getListSetting("SSL" if section == SSL else "Ports", "hosts"): if encodings.idna.ToASCII(i[0].lower()).decode("UTF-8") == encodings.idna.ToASCII(host.lower()).decode("UTF-8"): return True return False return True class TCPHandler(socketserver.StreamRequestHandler): def readString(self): return self.rfile.readline().strip() def sendString(self, string): self.request.sendall((string + "\n").encode('utf8')) def requestHandler(self, request): pass def worker(self, message): content = message.split() command = content[0].lower() try: if command == "hi": try: return "HI: Kumi Status v0.8.15 (KSP) at %s" % setuptools.getSetting("Server", "host") or socket.gethostname() except Exception as e: print(e) elif command in ("heartbeat", "hb", "ping"): return "OK: Still here? Wow." elif command in ("stat", "status"): return "UA: Not currently implemented." elif command in ("ssl", "tls"): try: host = encodings.idna.ToASCII(str(content[1])).decode("UTF-8") try: port = int(content[2]) except IndexError: port = 443 if listIncluded(host, SSL): expiry = ssltools.getRemoteExpiry(host, port) if expiry > datetime.datetime.now(): dm = "%s certificate is valid until: %s" % (content[1], expiry) try: delta = int(content[3]) except: delta = 0 if expiry < datetime.datetime.now() + datetime.timedelta(days=delta): return "AL: %s" % dm return "OK: %s" % dm else: return "AL: %s certificate has expired on: %s" % (content[1], expiry) else: return "NM: %s is not being monitored!" % content[1] except Exception as e: print(e) return "ER: Could not verify SSL certificate on %s:%i. Is the server down?" % (content[1], int(content[2])) elif command == "port": host = encodings.idna.ToASCII(str(content[1])).decode("UTF-8") port = int(content[2]) if listIncluded(host, PORT): if porttools.isPortOpen(host, port): return "OK: Port %i is open on %s." % (port, content[1]) else: return "ER: Port %i is not open on %s." % (port, content[1]) else: return "NM: %s is not being monitored!" % content[1] elif command in ("req", "request"): return "NI: Requesting monitoring is not yet implemented." elif command == "help": return "UA: Not currently implemented." else: return "IM: Unknown command %s." % command except TypeError as e: return "IM: Invalid values passed to %s. Try HELP %s." % (command, command) except IndexError as e: return "IM: Invalid values passed to %s. Try HELP %s." % (command, command) def handle(self): remote = self.client_address[0] + ":" + str(self.client_address[1]) logger("New connection from %s." % remote, syslog.LOG_INFO) self.sendString(self.worker("hi")) while True: message = self.readString().decode('utf8') if not message: logger("Connection from %s closed." % remote, syslog.LOG_DEBUG) break logger("%s said: %s" % (remote, message)) response = self.worker(message) if response: self.sendString(response) logger("Sent to %s: %s" % (remote, response), syslog.LOG_DEBUG) class TCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): pass def shutdown(reboot = False, status = 0): if reboot: args = sys.argv[:] args.insert(0, sys.executable) try: os.execv(sys.executable, args) except: logger("Restart failed. Shutting down.") exit(status)