264 lines
7.9 KiB
Python
264 lines
7.9 KiB
Python
#!/usr/bin/env python3
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import requests
|
|
|
|
try:
|
|
from settings import *
|
|
except ImportError:
|
|
print("Loading of settings failed. Please check your settings (copy settings.py.default to settings.py)")
|
|
sys.exit(2)
|
|
|
|
# lsof output columns statics
|
|
FILE = HOST = 8
|
|
DEVICE = 3
|
|
TYPE = 4
|
|
PID = 1
|
|
|
|
|
|
def telegram_send(s):
|
|
context = {
|
|
'chat_id': TELEGRAM_CHAT_ID,
|
|
'text': s,
|
|
'parse_mode': 'HTML',
|
|
'disable_notification': True
|
|
}
|
|
r = requests.post("https://api.telegram.org/bot{}/sendMessage".format(TELEGRAM_BOT_KEY), data=context)
|
|
with open("/tmp/spitfire_smbspy_result.txt", 'w', encoding='utf=8') as f:
|
|
f.write("Result: {}, Text: {}".format(r.status_code, r.text))
|
|
|
|
###
|
|
# SMBD monitoring
|
|
###
|
|
|
|
smb_data = {}
|
|
smbd_output = ""
|
|
smb_result = ""
|
|
smb_users = 0
|
|
smb_active = 0
|
|
smb_files = 0
|
|
|
|
try:
|
|
smbd_output = subprocess.check_output([SUDO, "lsof", "-c", "/^"+SMBD+"$/", "-Pcnt"], stderr=subprocess.DEVNULL).decode().split("\n")
|
|
except subprocess.CalledProcessError as e:
|
|
# Error running process.
|
|
pass
|
|
|
|
conns = list(y.split() for y in filter(
|
|
lambda x: ("IPv4" in x or "IPv6" in x) and HOSTNAME in x and "smbd" in x, smbd_output
|
|
))
|
|
for conn in conns:
|
|
try:
|
|
pid = conn[PID]
|
|
except IndexError:
|
|
pid = "-1"
|
|
|
|
try:
|
|
hoststr = conn[HOST]
|
|
try:
|
|
host = hoststr.split("->")[1].split(":")[0]
|
|
except IndexError:
|
|
host = hoststr
|
|
except IndexError:
|
|
host = "Unknown"
|
|
smb_data[pid] = {'host': host, 'pid': pid, 'dirs': set(), 'files': set()}
|
|
|
|
# All lines which are in the base dir and which is a directory or a regular file
|
|
files = list(y.split() for y in filter(
|
|
lambda x: BASE_DIR in x and (("DIR" in x and "cwd" not in x) or "REG" in x), smbd_output
|
|
))
|
|
|
|
for file in files:
|
|
pid = file[PID]
|
|
entry = " ".join(file[FILE:])
|
|
if file[TYPE] == "DIR":
|
|
smb_data[pid]['dirs'].add(entry)
|
|
else:
|
|
smb_data[pid]['files'].add(entry)
|
|
|
|
# Reformat data to index on host instead of PID
|
|
host_data = {}
|
|
for data in smb_data.values():
|
|
host = data['host']
|
|
if host not in host_data.keys():
|
|
host_data[host] = {'pids': [data['pid']], 'dirs': set(data['dirs']), 'files': set(data['files'])}
|
|
else:
|
|
host_data[host]['pids'].append(data['pid'])
|
|
host_data[host]['dirs'].union(data['dirs'])
|
|
host_data[host]['files'].union(data['files'])
|
|
|
|
# Filter dirs to remove any dirs that are parents of another entry in the list (not useful)
|
|
for host, data in host_data.items():
|
|
olddirs = sorted(list(data['dirs']))
|
|
newdirs = []
|
|
for d in olddirs:
|
|
if not any(d in x for x in olddirs if d != x):
|
|
newdirs.append(d)
|
|
data['dirs'] = newdirs
|
|
|
|
for host in sorted(host_data.keys()):
|
|
data = host_data[host]
|
|
flen = len(data['files'])
|
|
dlen = len(data['dirs'])
|
|
plen = len(data['pids'])
|
|
smb_users += 1
|
|
amounts = ["{} connection(s)".format(plen)]
|
|
if dlen > 0:
|
|
amounts.append("{} dir(s)".format(dlen))
|
|
if flen > 0:
|
|
smb_active += 1
|
|
smb_files += flen
|
|
amounts.append("{} file(s)".format(flen))
|
|
if dlen == 0 and flen == 0:
|
|
amounts.append("Nothing")
|
|
smb_result += "- {}: <i>{} open</i>\n".format(host, ", ".join(amounts))
|
|
if flen > 0:
|
|
for f in sorted(data['files']):
|
|
smb_result += " - {}\n".format(f)
|
|
# elif dlen > 0:
|
|
# for d in sorted(data['dirs']):
|
|
# smb_result += " <i>- {}</i>\n".format(d)
|
|
|
|
|
|
###
|
|
# HTTP Monitoring
|
|
###
|
|
|
|
http_data = {}
|
|
http_output = ""
|
|
http_result = ""
|
|
http_users = 0
|
|
http_files = 0
|
|
|
|
try:
|
|
http_output = subprocess.check_output([SUDO, "lsof", "-c", "/^"+APACHE+"$/", "-Pcnt"], stderr=subprocess.DEVNULL).decode().split("\n")
|
|
except subprocess.CalledProcessError as e:
|
|
# Error running process.
|
|
pass
|
|
|
|
conns = list(y.split() for y in filter(
|
|
lambda x: ("IPv4" in x or "IPv6" in x) and HOSTNAME in x and "apache2" in x, http_output
|
|
))
|
|
for conn in conns:
|
|
try:
|
|
pid = conn[PID]
|
|
except IndexError:
|
|
pid = "-1"
|
|
|
|
try:
|
|
hoststr = conn[HOST]
|
|
try:
|
|
host = hoststr.split("->")[1].split(":")[0]
|
|
except IndexError:
|
|
host = hoststr
|
|
except IndexError:
|
|
host = "Unknown"
|
|
http_data[pid] = {'host': host, 'pid': pid, 'files': set()}
|
|
|
|
# All lines which are in the base dir and which is a directory or a regular file
|
|
files = list(y.split() for y in filter(lambda x: BASE_DIR in x and "REG" in x, http_output))
|
|
|
|
for file in files:
|
|
pid = file[PID]
|
|
entry = " ".join(file[FILE:])
|
|
http_data[pid]['files'].add(entry)
|
|
|
|
# Reformat data to index on host instead of PID
|
|
http_host_data = {}
|
|
for data in http_data.values():
|
|
host = data['host']
|
|
if host not in http_host_data.keys():
|
|
http_host_data[host] = {'pids': [data['pid']], 'files': set(data['files'])}
|
|
else:
|
|
http_host_data[host]['pids'].append(data['pid'])
|
|
http_host_data[host]['files'].union(data['files'])
|
|
|
|
for host in sorted(http_host_data.keys()):
|
|
data = http_host_data[host]
|
|
flen = len(data['files'])
|
|
plen = len(data['pids'])
|
|
http_users += 1
|
|
amounts = ["{} connection(s)".format(plen)]
|
|
if flen > 0:
|
|
http_files += flen
|
|
amounts.append("{} file(s)".format(flen))
|
|
if flen == 0:
|
|
amounts.append("Nothing")
|
|
http_result += "- {}: <i>{} open</i>\n".format(host, ", ".join(amounts))
|
|
if flen > 0:
|
|
for f in sorted(data['files']):
|
|
http_result += " - {}\n".format(f)
|
|
|
|
# Construct final telegram string
|
|
final_result = ""
|
|
if smb_result != "":
|
|
final_result += "<b>{} SMB</b> has <b>{}</b> file(s) opened by " \
|
|
"<b>{}</b> user(s) (<b>{}</b> active users).\n".format(
|
|
SERVER_NAME, smb_files, smb_users, smb_active
|
|
)
|
|
final_result += smb_result
|
|
else:
|
|
final_result += "<b>{} SMB</b> has no open files or command failure.\n".format(SERVER_NAME)
|
|
|
|
if http_result != "":
|
|
final_result += "<b>{} HTTP</b> has <b>{}</b> active transfer(s) by <b>{}</b> user(s).\n".format(
|
|
SERVER_NAME, http_files, http_users
|
|
)
|
|
final_result += http_result
|
|
else:
|
|
final_result += "<b>{} HTTP</b> has no open files or command failure.".format(SERVER_NAME)
|
|
|
|
# Report to Telegram if changed
|
|
if os.path.isfile("/tmp/spitfire_smbspy_status.txt"):
|
|
with open('/tmp/spitfire_smbspy_status.txt', 'r', encoding='utf-8') as f:
|
|
old_str = "".join(f.readlines())
|
|
else:
|
|
old_str = ""
|
|
|
|
if old_str != final_result:
|
|
with open('/tmp/spitfire_smbspy_status.txt', 'w', encoding='utf=8') as f:
|
|
f.write(final_result)
|
|
telegram_send(final_result)
|
|
|
|
# Copy results to SpitfireSeries
|
|
import shutil, stat
|
|
try:
|
|
shutil.copyfile("/tmp/spitfire_smbspy_status.txt", "/var/www/spitfireseries/spitfire_smbspy_status.txt")
|
|
os.chmod("/var/www/spitfireseries/spitfire_smbspy_status.txt", 0o666)
|
|
except Exception as e:
|
|
import syslog
|
|
syslog.syslog("Could not copy SMB status to SpitfireSeries: {}".format(e))
|
|
|
|
# Report to Nagios
|
|
limits = {
|
|
'users': [10, 20],
|
|
'files': [20, 50]
|
|
}
|
|
|
|
if smb_active + http_users >= limits['users'][1] or smb_files + http_files >= limits['files'][1]:
|
|
status = "CRITICAL"
|
|
return_code = 2
|
|
elif smb_active + http_users >= limits['users'][0] or smb_files + http_files >= limits['files'][0]:
|
|
status = "WARNING"
|
|
return_code = 1
|
|
else:
|
|
status = "OK"
|
|
return_code = 0
|
|
|
|
# Construct final monitoring string
|
|
monitoring_result = "{}: ".format(status)
|
|
if smb_result != "":
|
|
monitoring_result += "{} files opened on SMB ({}/{} users), ".format(smb_files, smb_active, smb_users)
|
|
else:
|
|
monitoring_result += "SMB no open files or failure, ".format(SERVER_NAME)
|
|
|
|
if http_result != "":
|
|
monitoring_result += "{} active HTTP transfers ({} users).".format(http_files, http_users)
|
|
else:
|
|
monitoring_result += "HTTP no open files or failure.".format(SERVER_NAME)
|
|
|
|
# Print monitoring string and exit with proper exit code
|
|
print(monitoring_result)
|
|
sys.exit(return_code)
|