140 lines
4.4 KiB
Python
140 lines
4.4 KiB
Python
import datetime, encodings.idna, os, porttools, 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)
|
|
|