[mac_prises] On envoie plus qu'un email par jour, qui contient un résumé qualitatif, et des détails en pièce jointe.
This commit is contained in:
parent
46bf7e47d6
commit
0e84b5e02d
6 changed files with 199 additions and 231 deletions
|
@ -8,45 +8,32 @@ hargneux = True
|
|||
|
||||
#: Si pour une chambre donnée, il y a plus de 300 entrées filaires
|
||||
#: n'appartenant pas à l'adhérent propriétaire de la mac, on prévient.
|
||||
max_inconnues_par_jour = 300
|
||||
max_inconnues_par_jour = 480
|
||||
|
||||
#: Titre utilisé dans le corps du message
|
||||
titre_mac_inconnue = u"Repérage de macs potentiellement non désirées dans les chambres suivantes."
|
||||
|
||||
#: Pour la recherche dans postgres
|
||||
delay = { 'instant': '2 min',
|
||||
'heuristique': '30 min',
|
||||
delay = { 'instantanne': '2 min',
|
||||
'moyen': '30 min',
|
||||
'journalier': '1 day',
|
||||
}
|
||||
|
||||
#: Contient trois dictionnaire. Le paramètre mac signifie "combien de chambres doivent voir la même mac pour que ça soit suspect"
|
||||
#: Le paramètre chambre signifie "combien de macs doivent traverser une même chambre pour que ça soit suspect"
|
||||
suspect = { 'instant':{'mac': 2, 'chambre': 2},
|
||||
'heuristique':{'mac': 2, 'chambre': 2},
|
||||
'journalier':{'mac': 2, 'chambre': 2},
|
||||
suspect = { 'instantanne':2,
|
||||
'moyen':2,
|
||||
'journalier':2,
|
||||
}
|
||||
|
||||
#: Contient trois dictionnaire. Le paramètre mac signifie "combien de chambres doivent voir la même mac pour que ça soit très suspect"
|
||||
#: Le paramètre chambre signifie "combien de macs doivent traverser une même chambre pour que ça soit très suspect"
|
||||
tres_suspect = { 'instant':{'mac': 3, 'chambre': 3},
|
||||
'heuristique':{'mac': 3, 'chambre': 3},
|
||||
'journalier':{'mac': 3, 'chambre': 3},
|
||||
}
|
||||
|
||||
#: Le point central des analyses.
|
||||
rapport_suspect = { 'instant':{'mac': 0.51, 'chambre': 0.51},
|
||||
'heuristique':{'mac': 0.4, 'chambre': 0.55},
|
||||
'journalier':{'mac': 0.2, 'chambre': 0.58},
|
||||
rapport_suspect = { 'instantanne':0.51,
|
||||
'moyen':0.4,
|
||||
'journalier':0.2,
|
||||
}
|
||||
|
||||
#: Titre des paragraphes suspects
|
||||
titre_suspect = { 'instant':{'mac': u"Macs se baladant un peu trop entre les chambres (instantanné)", 'chambre': u"Chambres avec un peu trop de macs (instantanné)"},
|
||||
'heuristique':{'mac': u"Macs se baladant un peu trop entre les chambres (délai moyen)", 'chambre': u"Chambres avec un peu trop de macs (délai moyen)"},
|
||||
'journalier':{'mac': u"Macs s'étant peut-être un peu trop baladées aujourd'hui", 'chambre': u"Chambres avec un peu trop de macs sur un jour"},
|
||||
titre_suspect = { 'instantanne':u"Macs se baladant un peu trop entre les chambres (instantanneanné)",
|
||||
'moyen':u"Macs se baladant un peu trop entre les chambres (délai moyen)",
|
||||
'journalier':u"Macs s'étant peut-être un peu trop baladées aujourd'hui",
|
||||
}
|
||||
|
||||
#: Titre des paragraphes très suspects
|
||||
titre_tres_suspect = { 'instant':{'mac': u"/!\ Spoof potentiel des macs suivantes dans les chambres ci-après (instantanné)", 'chambre': u"/!\ Les chambres ci-après contiennent étrangement trop de macs inconnues ! (instantanné)"},
|
||||
'heuristique':{'mac': u"/!\ Spoof potentiel des macs suivantes dans les chambres ci-après (délai moyen)", 'chambre': u"/!\ Les chambres ci-après contiennent étrangement trop de macs inconnues ! (délai moyen)"},
|
||||
'journalier':{'mac': u"/!\ Spoof probable des macs suivantes dans les chambres ci-après aujourd'hui !!", 'chambre': u"/!\ Les chambres suivantes contiennent trop de macs inconnues (sur un jour)"},
|
||||
}
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
# -*- coding: utf8 -*-
|
||||
#
|
||||
#
|
||||
# PEB - 01/04/2012
|
||||
# PEB - 01/04/2012 -> now()
|
||||
#
|
||||
|
||||
import os, sys, re
|
||||
import os, sys
|
||||
import sys
|
||||
import re
|
||||
from commands import getstatusoutput
|
||||
|
||||
import time
|
||||
|
||||
|
||||
# nécessite apparemment que l'objet conn soit bien créé lors de l'exec
|
||||
# de annuaires_pg, il faut être root (ou dans je ne sais quel groupe)
|
||||
|
@ -103,14 +103,7 @@ def __exec(cmd):
|
|||
|
||||
if __name__ == '__main__':
|
||||
switchs = sys.argv[1:]
|
||||
date = time.strftime('%F %T')
|
||||
for switch in switchs:
|
||||
macs = liste_chambres_macs(switch)
|
||||
|
||||
print macs
|
||||
|
||||
# fichier =
|
||||
# for chambre in macs.keys():
|
||||
# for mac in macs[chambre]:
|
||||
#
|
||||
# curseur.execute(requete, (date, chambre, mac))
|
||||
|
|
|
@ -12,9 +12,14 @@ from config import mac_prise
|
|||
from affich_tools import tableau
|
||||
sys.path.append('/usr/scripts/lc_ldap')
|
||||
import lc_ldap
|
||||
import collections
|
||||
|
||||
ldap = lc_ldap.lc_ldap_local()
|
||||
|
||||
conn = psycopg2.connect(user='crans', database='mac_prises')
|
||||
conn.set_session(autocommit = True)
|
||||
cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor)
|
||||
|
||||
membres_actifs = ldap.search('(|(droits=Cableur)(droits=Nounou)(droits=Apprenti)(droits=Bureau))')
|
||||
chambres_ma = []
|
||||
for membre_actif in membres_actifs:
|
||||
|
@ -31,20 +36,12 @@ for club in clubs:
|
|||
except:
|
||||
pass
|
||||
|
||||
conn = psycopg2.connect(user='crans', database='mac_prises')
|
||||
conn.set_session(autocommit = True)
|
||||
cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor)
|
||||
|
||||
requete = "SELECT * FROM signales WHERE date >= timestamp 'now' - interval '1 day';"
|
||||
cur.execute(requete)
|
||||
signales = cur.fetchall()
|
||||
|
||||
longueur = { 'mac': (24, 3),
|
||||
'chambre': (10, 7),
|
||||
}
|
||||
titres = { 'mac':(u'mac', u'chambres'),
|
||||
'chambre': (u'chambre', u'macs'),
|
||||
}
|
||||
longueur = (24, 7)
|
||||
titres = (u'mac', u'chambres')
|
||||
alignements = ('c', 'c')
|
||||
|
||||
def lin(x, y, z):
|
||||
|
@ -53,87 +50,168 @@ def lin(x, y, z):
|
|||
"""
|
||||
return (float(x)/float(y)-1.0)/(float(z)-1.0)
|
||||
|
||||
def genere_comptage(duree, groupe, associes):
|
||||
def genere_comptage(duree):
|
||||
"""
|
||||
Grosse fonction de hack pour ne pas écrire six fois le même formatage de sortie bidon.
|
||||
Prend en argument :
|
||||
|
||||
* duree, qui peut valoir 'instant', 'heuristique', ou 'journalier', permet d'importer
|
||||
les variables de config qui vont bien
|
||||
* groupe, qui précise selon quoi on groupe (mac ou chambre)
|
||||
* associes, qui contient l'autre champ
|
||||
"""
|
||||
global date
|
||||
global Logs
|
||||
pb_comptage_suspect = {}
|
||||
output = ""
|
||||
requete = "SELECT array_to_string(array_agg(DISTINCT date), ', ') AS dates , %(groupe)s, array_to_string(array_agg(DISTINCT %(associes)s), ', ') AS %(associes)ss, COUNT(DISTINCT %(associes)s) AS nb_%(associes)ss_distinctes, COUNT(%(associes)s) AS nb_%(associes)ss, COUNT(DISTINCT date) as nb_dates_distinctes, COUNT(DISTINCT %(groupe)s) as nb_%(groupe)ss_distinctes FROM correspondance WHERE date >= timestamp 'now' - interval '%(delay)s' GROUP BY %(groupe)s;" % { 'groupe': groupe, 'associes': associes, 'delay': mac_prise.delay[duree] }
|
||||
requete = "SELECT array_to_string(array_agg(DISTINCT date), ', ') AS dates , mac, array_to_string(array_agg(DISTINCT chambre), ', ') AS chambres, COUNT(DISTINCT chambre) AS nb_chambres_distinctes, COUNT(chambre) AS nb_chambres, COUNT(DISTINCT date) as nb_dates_distinctes, COUNT(DISTINCT mac) as nb_macs_distinctes FROM correspondance WHERE date >= timestamp 'now' - interval '%(delay)s' GROUP BY mac;" % {'delay': mac_prise.delay[duree]}
|
||||
cur.execute(requete)
|
||||
fetched = cur.fetchall()
|
||||
|
||||
for entry in fetched:
|
||||
|
||||
if groupe == "mac":
|
||||
machines = ldap.search('(macAddress=%s)' % entry[groupe])
|
||||
if len(machines) > 0:
|
||||
if isinstance(machines[0], lc_ldap.machineWifi):
|
||||
continue
|
||||
else:
|
||||
machines = ldap.search('(macAddress=%s)' % entry['mac'])
|
||||
if len(machines) > 0:
|
||||
if isinstance(machines[0], lc_ldap.machineWifi):
|
||||
continue
|
||||
else:
|
||||
continue
|
||||
|
||||
if entry['nb_'+associes+'s_distinctes'] >= mac_prise.suspect[duree][groupe]:
|
||||
Logs.append(u"Recherche par %s, entrée suspecte : %s -> %s : %s distinctes sur %s dates distinctes\n" % (groupe, entry[groupe], entry[associes+'s'], entry['nb_'+associes+'s'], entry['nb_dates_distinctes']))
|
||||
liste_associes = entry[associes+'s'].split(', ')
|
||||
if entry['nb_chambres_distinctes'] >= mac_prise.suspect[duree]:
|
||||
Logs.append(u"Recherche par %s, entrée suspecte : %s -> %s : %s distinctes sur %s dates distinctes\n" % ('mac', entry['mac'], entry['chambres'], entry['nb_chambres'], entry['nb_dates_distinctes']))
|
||||
liste_chambres = entry['chambres'].split(', ')
|
||||
|
||||
# On calcule la "probabilité" qu'un truc ne soit pas clair concernant la chambre/mac
|
||||
rapport = lin(entry['nb_'+associes+'s'], entry['nb_dates_distinctes'], float(entry['nb_'+associes+'s_distinctes']))
|
||||
if rapport >= mac_prise.rapport_suspect[duree][groupe]:
|
||||
Logs.append(u"Entrée ajoutée au tableau %s pour la recherche par %s, car rapport supérieur au seuil.\n\n" % (duree, groupe))
|
||||
pb_comptage_suspect[entry[groupe]] = (liste_associes, rapport, mac_prise.rapport_suspect[duree][groupe])
|
||||
rapport = lin(entry['nb_chambres'], entry['nb_dates_distinctes'], float(entry['nb_chambres_distinctes']))
|
||||
if rapport >= mac_prise.rapport_suspect[duree]:
|
||||
Logs.append(u"Entrée ajoutée au tableau %s, car rapport supérieur au seuil.\n\n" % (duree))
|
||||
pb_comptage_suspect[entry['mac']] = (liste_chambres, rapport, mac_prise.rapport_suspect[duree])
|
||||
else:
|
||||
Logs.append(u"Entrée rejetée du tableau %s pour la recherche par %s, car rapport inférieur au seuil : (%s).\n\n" % (duree, groupe, rapport))
|
||||
Logs.append(u"Entrée rejetée du tableau %s, car rapport inférieur au seuil : (%s).\n\n" % (duree, rapport))
|
||||
else:
|
||||
pass
|
||||
|
||||
if len(pb_comptage_suspect) > 0:
|
||||
output += mac_prise.titre_suspect[duree][groupe] + "\n"
|
||||
for clef, valeur in pb_comptage_suspect.items():
|
||||
requete = "INSERT INTO spotted (mac, type, chambre, date, rapport, seuil) VALUES(%s, %s, %s, %s, %s, %s);"
|
||||
cur.execute(requete, (clef, duree, ", ".join(valeur[0]), date, valeur[1], valeur[2]))
|
||||
return None
|
||||
|
||||
# On prend la longueur de la plus longue valeur, on s'assure que cette longueur fait celle de la légende, plus un entier de marge
|
||||
longueur_max = max([len(", ".join(a[0])) for a in pb_comptage_suspect.values()] + [longueur[associes][1]]) + 4
|
||||
largeurs = (longueur[groupe][0], longueur_max, 11, 9)
|
||||
titre = (titres[groupe][0], titres[groupe][1], "rapport", "seuil")
|
||||
alignement = (alignements[0], alignements[1], 'c', 'c')
|
||||
def summary():
|
||||
"""
|
||||
Fonction résumant les entrées "spotted" des dernières 24h
|
||||
"""
|
||||
|
||||
output = u""
|
||||
Logs = u""
|
||||
|
||||
requete = "SELECT * FROM spotted WHERE date >= timestamp 'now' - interval '1 day' ORDER BY date ASC;"
|
||||
cur.execute(requete)
|
||||
fetched = cur.fetchall()
|
||||
liste_triee = collections.defaultdict(dict)
|
||||
|
||||
for entry in fetched:
|
||||
chbres = entry['chambre'].split(', ')
|
||||
chbres.sort()
|
||||
chbres = tuple(chbres)
|
||||
if liste_triee[entry['mac']].has_key(entry['type']):
|
||||
if liste_triee[entry['mac']][entry['type']].has_key(chbres):
|
||||
liste_triee[entry['mac']][entry['type']][chbres].append((entry['date'], entry['rapport'], entry['seuil']))
|
||||
else:
|
||||
liste_triee[entry['mac']][entry['type']][chbres] = []
|
||||
else:
|
||||
liste_triee[entry['mac']][entry['type']] = {}
|
||||
|
||||
for mac, ltype in liste_triee.items():
|
||||
data = []
|
||||
output += u"Il y a eu une activité suspecte concernant la mac %s :\n\n" % mac
|
||||
Logs += u"Activité pour %s :\n" % mac
|
||||
for dtype, dataset in ltype.items():
|
||||
number = 0
|
||||
chambres = set()
|
||||
for chbres, dataframe in dataset.items():
|
||||
chambres.update(chbres)
|
||||
number += len(dataframe)
|
||||
data += [[dtype, ", ".join(list(chbres)), donnee[0], donnee[1], donnee[2]] for donnee in dataframe]
|
||||
output += u'Sur le relevé %s, la mac est apparue %s fois. Elle est apparue dans les chambres suivantes : %s.\n' % (dtype, number, ", ".join(list(chambres)))
|
||||
output += u'Consulter les logs (en PJ) pour plus d\'informations.\n\n'
|
||||
maxlen = max([len(a[1]) for a in data]) + 4
|
||||
titres = (u'relevé', u'chambres', u'date', u'rapport', u'seuil')
|
||||
alignements = ('c', 'c', 'c', 'c', 'c')
|
||||
largeurs = (12, maxlen, 20, 10, 10)
|
||||
Logs += tableau(data, titres, largeurs, alignements)
|
||||
Logs += u"\n\n"
|
||||
|
||||
return output, Logs
|
||||
|
||||
def reperage_mac_inconnue():
|
||||
"""
|
||||
Fonction de repérage d'une mac qui ne devrait pas être
|
||||
dans telle chambre, sur une plage de 24h, suivant un
|
||||
paramètre de config pour le nombre d'occurrences.
|
||||
"""
|
||||
|
||||
output = u""
|
||||
probleme = {}
|
||||
requete = "SELECT chambre, mac, COUNT(mac) as nb_min FROM correspondance WHERE date >= timestamp 'now' - interval '24 hours' GROUP BY chambre, mac ORDER BY chambre ASC;"
|
||||
cur.execute(requete)
|
||||
fetched = cur.fetchall()
|
||||
liste_parsee = collections.defaultdict(dict)
|
||||
|
||||
for entry in fetched:
|
||||
liste_parsee[entry['chambre']][entry['mac']] = int(entry['nb_min'])
|
||||
|
||||
for chambre in liste_parsee.keys():
|
||||
if chambre in chambres_ma + chambres_clubs:
|
||||
continue
|
||||
|
||||
for mac in liste_parsee[chambre].keys():
|
||||
try:
|
||||
proprio_associe = ldap.search('macAddress=%s' % mac)[0].proprio()
|
||||
if str(proprio_associe['chbre'][0]).lower() == chambre.lower():
|
||||
garbage = liste_parsee[chambre].pop(mac)
|
||||
except:
|
||||
pass
|
||||
number = sum(liste_parsee[chambre].values())
|
||||
|
||||
if number >= mac_prise.max_inconnues_par_jour:
|
||||
probleme[chambre] = (liste_parsee[chambre].keys(), number)
|
||||
|
||||
if len(probleme) > 0:
|
||||
output += mac_prise.titre_mac_inconnue+"\n"
|
||||
|
||||
longueur_max = max([len(", ".join(a[0])) for a in probleme.values()] + [len("macs")]) + 2
|
||||
largeurs = (len('chambre') + 2, longueur_max, len('compteur') + 2, len('seuil') + 2)
|
||||
|
||||
data = []
|
||||
clefs = pb_comptage_suspect.keys()
|
||||
clefs = probleme.keys()
|
||||
clefs.sort()
|
||||
for clef in clefs:
|
||||
data.append([clef, ", ".join(pb_comptage_suspect[clef][0]), pb_comptage_suspect[clef][1], pb_comptage_suspect[clef][2]])
|
||||
data.append([clef, ", ".join(probleme[clef][0]), probleme[clef][1], mac_prise.max_inconnues_par_jour])
|
||||
|
||||
output += tableau(data, titre, largeurs, alignement)
|
||||
output += tableau(data, ('chambre', 'macs', 'compteur', 'seuil'), largeurs, ('c', 'c', 'c', 'c'))
|
||||
output += u"\n\n\n"
|
||||
|
||||
return output
|
||||
|
||||
if __name__ == '__main__':
|
||||
output = u"Détection de spoof potentiel\n\n\n"
|
||||
coupure = len(output)
|
||||
date = time.strftime('%F %T')
|
||||
if len(sys.argv) >= 2:
|
||||
output = u''
|
||||
Logs = u''
|
||||
if '--summary' in sys.argv or 'summary' in sys.argv:
|
||||
# On envoie le résumé
|
||||
output += u' *Résumé des apparitions de mac dans plusieurs chambres*\n\n'
|
||||
texte, Logs = summary()
|
||||
output += texte
|
||||
output += u"\n\n"
|
||||
if '--reperage' in sys.argv or 'reperage' in sys.argv:
|
||||
# On envoie le repérage
|
||||
output += u' *Repérage de spoof potentiel par comptage*\n\n'
|
||||
output += reperage_mac_inconnue()
|
||||
|
||||
Logs = [u"Logs du script mac_prise_analyzer\n\n\n"]
|
||||
|
||||
output += genere_comptage('instant', 'mac', 'chambre')
|
||||
output += genere_comptage('heuristique', 'mac', 'chambre')
|
||||
output += genere_comptage('journalier', 'mac', 'chambre')
|
||||
|
||||
if time.localtime().tm_min % 30 == 0 and mac_prise.hargneux:
|
||||
hargneux = True
|
||||
else:
|
||||
hargneux = False
|
||||
|
||||
if len(output) == coupure and not hargneux:
|
||||
sys.exit(0)
|
||||
|
||||
message = """From: %(from)s
|
||||
Logs = Logs.encode('UTF-8')
|
||||
output = output.encode('UTF-8')
|
||||
message = """From: %(from)s
|
||||
To: %(to)s
|
||||
Subject: %(subject)s
|
||||
Subject: Résumé quotidien : mac_prises.
|
||||
Content-Type: multipart/mixed; boundary="_424234545aaff-ffca234efff-556adceff5646_"
|
||||
|
||||
--_424234545aaff-ffca234efff-556adceff5646_
|
||||
|
@ -141,9 +219,6 @@ Content-Type: text/plain; charset="UTF-8"
|
|||
|
||||
%(contenu)s
|
||||
|
||||
--
|
||||
Script d'analyse mac_prise (en test)
|
||||
|
||||
--_424234545aaff-ffca234efff-556adceff5646_
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
Content-Disposition: attachment; filename="logs_analyse"
|
||||
|
@ -151,17 +226,46 @@ Content-Disposition: attachment; filename="logs_analyse"
|
|||
%(logs)s
|
||||
|
||||
--_424234545aaff-ffca234efff-556adceff5646_--
|
||||
|
||||
"""
|
||||
|
||||
corps = message % { 'from': 'Spoofing watcher <spoof-watcher@crans.org>',
|
||||
'to': 'test@lists.crans.org',
|
||||
'subject': 'Analyse du spoofing',
|
||||
'contenu': output,
|
||||
'logs': "".join(Logs),
|
||||
}
|
||||
corps = message % { 'from': 'Spoofing watcher <spoof-watcher@crans.org>',
|
||||
'to': 'test@lists.crans.org',
|
||||
'subject': 'Résumé journalier ',
|
||||
'contenu': output,
|
||||
'logs': Logs,
|
||||
}
|
||||
|
||||
mail = smtplib.SMTP('localhost')
|
||||
mailfrom = 'spoof-watcher@crans.org'
|
||||
mailto = 'test@lists.crans.org'
|
||||
mail.sendmail(mailfrom, mailto, corps.encode('utf-8'))
|
||||
mail = smtplib.SMTP('localhost')
|
||||
mailfrom = 'spoof-watcher@crans.org'
|
||||
mailto = 'test@lists.crans.org'
|
||||
mail.sendmail(mailfrom, mailto, corps)
|
||||
else:
|
||||
Logs = [u"Logs du script mac_prise_analyzer\n\n\n"]
|
||||
genere_comptage('instantanne')
|
||||
genere_comptage('moyen')
|
||||
genere_comptage('journalier')
|
||||
|
||||
if time.localtime().tm_min % 30 == 0 and mac_prise.hargneux:
|
||||
hargneux = True
|
||||
else:
|
||||
hargneux = False
|
||||
|
||||
if hargneux:
|
||||
message = """From: %(from)s
|
||||
To: %(to)s
|
||||
Subject: %(subject)s
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
|
||||
%(logs)s
|
||||
"""
|
||||
|
||||
corps = message % { 'from': 'Spoofing watcher <spoof-watcher@crans.org>',
|
||||
'to': 'test@lists.crans.org',
|
||||
'subject': 'Logs de mac_prises_analyzer',
|
||||
'logs': "".join(Logs),
|
||||
}
|
||||
|
||||
mail = smtplib.SMTP('localhost')
|
||||
mailfrom = 'spoof-watcher@crans.org'
|
||||
mailto = 'test@lists.crans.org'
|
||||
mail.sendmail(mailfrom, mailto, corps.encode('utf-8'))
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#!/bin/sh
|
||||
|
||||
psql -U crans mac_prises -c "DELETE FROM correspondance WHERE date <= timestamp 'now' - interval '2 days';" 1>/dev/null
|
6
surveillance/mac_prises/mac_prise_daily.sh
Executable file
6
surveillance/mac_prises/mac_prise_daily.sh
Executable file
|
@ -0,0 +1,6 @@
|
|||
#!/bin/sh
|
||||
|
||||
SUMMARY='/usr/scripts/surveillance/mac_prises/mac_prises_analyzer.py --summary --reperage'
|
||||
|
||||
psql -U crans mac_prises -c "DELETE FROM correspondance WHERE date <= timestamp 'now' - interval '2 days';" 1>/dev/null
|
||||
psql -U crans mac_prises -c "DELETE FROM spotted WHERE date <= timestamp 'now' - interval '2 days';" 1>/dev/null
|
|
@ -1,119 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf8 -*-
|
||||
|
||||
import psycopg2
|
||||
import psycopg2.extras
|
||||
import sys
|
||||
import smtplib
|
||||
|
||||
sys.path.append('/usr/scripts/gestion')
|
||||
from config import mac_prise
|
||||
from affich_tools import tableau
|
||||
sys.path.append('/usr/scripts/lc_ldap')
|
||||
import lc_ldap
|
||||
import collections
|
||||
|
||||
ldap = lc_ldap.lc_ldap_local()
|
||||
|
||||
membres_actifs = ldap.search('(|(droits=Cableur)(droits=Nounou)(droits=Apprenti)(droits=Bureau))')
|
||||
chambres_ma = []
|
||||
for membre_actif in membres_actifs:
|
||||
try:
|
||||
chambres_ma.append(str(membre_actif['chbre'][0]).lower())
|
||||
except:
|
||||
pass
|
||||
|
||||
clubs = ldap.search('cid=*')
|
||||
chambres_clubs = []
|
||||
for club in clubs:
|
||||
try:
|
||||
chambres_clubs.append(str(club['chbre'][0]).lower())
|
||||
except:
|
||||
pass
|
||||
|
||||
conn = psycopg2.connect(user='crans', database='mac_prises')
|
||||
cur = conn.cursor(cursor_factory = psycopg2.extras.DictCursor)
|
||||
|
||||
def reperage_mac_inconnue():
|
||||
"""
|
||||
Fonction de repérage d'une mac qui ne devrait pas être
|
||||
dans telle chambre, sur une plage de 24h, suivant un
|
||||
paramètre de config pour le nombre d'occurrences.
|
||||
|
||||
Sans doute le truc le plus important, sera en tête du mail
|
||||
"""
|
||||
|
||||
output = u""
|
||||
probleme = {}
|
||||
requete = "SELECT chambre, mac, COUNT(mac) as nb_min FROM correspondance WHERE date >= timestamp 'now' - interval '24 hours' GROUP BY chambre, mac ORDER BY chambre ASC;"
|
||||
cur.execute(requete)
|
||||
fetched = cur.fetchall()
|
||||
liste_parsee = collections.defaultdict(dict)
|
||||
|
||||
for entry in fetched:
|
||||
liste_parsee[entry['chambre']][entry['mac']] = int(entry['nb_min'])
|
||||
|
||||
for chambre in liste_parsee.keys():
|
||||
if chambre in chambres_ma + chambres_clubs:
|
||||
continue
|
||||
|
||||
for mac in liste_parsee[chambre].keys():
|
||||
try:
|
||||
proprio_associe = ldap.search('macAddress=%s' % mac)[0].proprio()
|
||||
if str(proprio_associe['chbre'][0]).lower() == chambre.lower():
|
||||
garbage = liste_parsee[chambre].pop(mac)
|
||||
except:
|
||||
pass
|
||||
number = sum(liste_parsee[chambre].values())
|
||||
|
||||
if number >= mac_prise.max_inconnues_par_jour:
|
||||
probleme[chambre] = (liste_parsee[chambre].keys(), number)
|
||||
|
||||
if len(probleme) > 0:
|
||||
output += mac_prise.titre_mac_inconnue+"\n"
|
||||
|
||||
longueur_max = max([len(", ".join(a[0])) for a in probleme.values()] + [len("macs")]) + 2
|
||||
largeurs = (len('chambre') + 2, longueur_max, len('compteur') + 2, len('seuil') + 2)
|
||||
|
||||
data = []
|
||||
clefs = probleme.keys()
|
||||
clefs.sort()
|
||||
for clef in clefs:
|
||||
data.append([clef, ", ".join(probleme[clef][0]), probleme[clef][1], mac_prise.max_inconnues_par_jour])
|
||||
|
||||
output += tableau(data, ('chambre', 'macs', 'compteur', 'seuil'), largeurs, ('c', 'c', 'c', 'c'))
|
||||
output += u"\n\n\n"
|
||||
|
||||
return output
|
||||
|
||||
if __name__ == '__main__':
|
||||
output = u'Repérage de spoof potentiel par comptage'
|
||||
coupure = len(output)
|
||||
|
||||
output += reperage_mac_inconnue()
|
||||
|
||||
if len(output) == coupure and not mac_prise.hargneux:
|
||||
sys.exit(0)
|
||||
|
||||
message = """From: %(from)s
|
||||
To: %(to)s
|
||||
Subject: %(subject)s
|
||||
Content-Type: text/plain; charset="UTF-8"
|
||||
|
||||
%(contenu)s
|
||||
|
||||
--
|
||||
Script d'analyse mac_prise (en test)
|
||||
|
||||
"""
|
||||
|
||||
corps = message % { 'from': 'Spoofing watcher <spoof-watcher@crans.org>',
|
||||
'to': 'test@lists.crans.org',
|
||||
'subject': 'Analyse horaire du spoofing',
|
||||
'contenu': output,
|
||||
}
|
||||
|
||||
mail = smtplib.SMTP('localhost')
|
||||
mailfrom = 'spoof-watcher@crans.org'
|
||||
mailto = 'test@lists.crans.org'
|
||||
mail.sendmail(mailfrom, mailto, corps.encode('utf-8'))
|
Loading…
Add table
Add a link
Reference in a new issue