[Mac_prise] Modification du wrapper, logging + mail dans analyzer, et mise en place de reperage
* Le wrapper n'envoie plus de mails * Analyzer envoie ses mails lui-même, avec en pièce jointe le contenu du logging. * Analyzer n'envoit rien si les tableaux sont vide, sauf si hargneux, et sur une demi heure * Création de mac_prise_reperage, dont le but est de lister les macs inconnues d'une chambre sur une plage de 24h (script exécuté par cron toutes les heures), et de compter le nombre de minutes pendant lesquelles elles ont été présentes. Si la somme des compteurs pour une chambre dépasse une quantité dans config, on envoie un mail. Pas de logging ici, tout est "limpide". Il faudra bien définir la variable de config sus-citée. * Modification de config, on rajoute les deux variables pour mac_prise_reperage.py
This commit is contained in:
parent
b37a0137e2
commit
777ba5cd9c
4 changed files with 197 additions and 24 deletions
|
@ -332,6 +332,16 @@ puissions corriger le problème.
|
||||||
Les membres actifs du Crans""" % email.Header.make_header([("Déménagement non déclaré", "utf8")])
|
Les membres actifs du Crans""" % email.Header.make_header([("Déménagement non déclaré", "utf8")])
|
||||||
|
|
||||||
class mac_prise:
|
class mac_prise:
|
||||||
|
# Pour spammer, mettre à true.
|
||||||
|
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
|
||||||
|
|
||||||
|
# Titre...
|
||||||
|
titre_mac_inconnue = u"Repérage de macs potentiellement non désirées dans les chambres suivantes."
|
||||||
|
|
||||||
# Pour la recherche dans postgres
|
# Pour la recherche dans postgres
|
||||||
delay = { 'instant': '2 min',
|
delay = { 'instant': '2 min',
|
||||||
'heuristique': '30 min',
|
'heuristique': '30 min',
|
||||||
|
|
|
@ -5,6 +5,7 @@ import psycopg2
|
||||||
import psycopg2.extras
|
import psycopg2.extras
|
||||||
import sys
|
import sys
|
||||||
import smtplib
|
import smtplib
|
||||||
|
import time
|
||||||
|
|
||||||
sys.path.append('/usr/scripts/gestion')
|
sys.path.append('/usr/scripts/gestion')
|
||||||
from config import mac_prise
|
from config import mac_prise
|
||||||
|
@ -67,11 +68,16 @@ def genere_comptage(duree, groupe, associes):
|
||||||
for entry in fetched:
|
for entry in fetched:
|
||||||
# Si c'est la chambre d'un membre actif ou d'un club, on droppe.
|
# Si c'est la chambre d'un membre actif ou d'un club, on droppe.
|
||||||
if groupe == 'chambre':
|
if groupe == 'chambre':
|
||||||
if entry[groupe] in chambres_ma + chambres_clubs:
|
if entry[groupe] in chambres_ma:
|
||||||
|
Logs.append(u"Chambre dropée, car appartenant à un membre actif : %s\n\n" % entry[groupe])
|
||||||
|
continue
|
||||||
|
elif entry[groupe] in chambres_clubs:
|
||||||
|
Logs.append(u"Chambre dropée, car appartenant à un club : %s\n\n" % entry[groupe])
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Sinon, on vérifie si le local est bien rempli.
|
# Sinon, on vérifie si le local est bien rempli.
|
||||||
if entry['nb_'+associes+'s_distinctes'] >= mac_prise.tres_suspect[duree][groupe]:
|
if entry['nb_'+associes+'s_distinctes'] >= mac_prise.tres_suspect[duree][groupe]:
|
||||||
|
Logs.append(u"Recherche par %s, entrée très suspecte : %s -> %s \n" % (groupe, entry[groupe], entry[associes+'s']))
|
||||||
liste_associes = entry[associes+'s'].split(', ')
|
liste_associes = entry[associes+'s'].split(', ')
|
||||||
|
|
||||||
# On retire les machines associées à l'adhérent possédant la chambre
|
# On retire les machines associées à l'adhérent possédant la chambre
|
||||||
|
@ -79,18 +85,21 @@ def genere_comptage(duree, groupe, associes):
|
||||||
for i in liste_associes:
|
for i in liste_associes:
|
||||||
try:
|
try:
|
||||||
proprio_associe = ldap.search('macAddress=%s' % i)[0].proprio()
|
proprio_associe = ldap.search('macAddress=%s' % i)[0].proprio()
|
||||||
if str(proprio_associe['chbre']).lower() == entry[groupe]:
|
if str(proprio_associe['chbre'][0]).lower() == entry[groupe]:
|
||||||
liste_associes.remove(i)
|
liste_associes.remove(i)
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if len(liste_associes) < mac_prise.tres_suspect[duree][groupe]:
|
if len(liste_associes) < mac_prise.tres_suspect[duree][groupe]:
|
||||||
|
Logs.append(u"Entrée rejetée : la plupart des %s appartiennent au propriétaire de la %s\n\n" % (associes, groupe))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# Toujours un problème ? On ajoute au dico
|
# Toujours un problème ? On ajoute au dico
|
||||||
|
Logs.append(u"Entrée ajoutée au tableau %s pour la recherche par %s.\n\n" % (duree, groupe))
|
||||||
pb_comptage_tres_suspect[entry[groupe]] = liste_associes
|
pb_comptage_tres_suspect[entry[groupe]] = liste_associes
|
||||||
|
|
||||||
# Même chose avec un seuil plus faible
|
# Même chose avec un seuil plus faible
|
||||||
elif entry['nb_'+associes+'s_distinctes'] >= mac_prise.suspect[duree][groupe]:
|
elif entry['nb_'+associes+'s_distinctes'] >= mac_prise.suspect[duree][groupe]:
|
||||||
|
Logs.append(u"Recherche par %s, entrée suspecte : %s -> %s \n" % (groupe, entry[groupe], entry[associes+'s']))
|
||||||
liste_associes = entry[associes+'s'].split(', ')
|
liste_associes = entry[associes+'s'].split(', ')
|
||||||
|
|
||||||
if groupe == 'chambre':
|
if groupe == 'chambre':
|
||||||
|
@ -102,14 +111,16 @@ def genere_comptage(duree, groupe, associes):
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
if len(liste_associes) < mac_prise.suspect[duree][groupe]:
|
if len(liste_associes) < mac_prise.suspect[duree][groupe]:
|
||||||
|
Logs.append(u"Entrée rejetée : la plupart des %s appartiennent au propriétaire de la %s\n\n" % (associes, groupe))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
# On calcul la "probabilité" qu'un truc ne soit pas clair concernant la chambre/mac
|
# On calcul 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']))
|
rapport = lin(entry['nb_'+associes+'s'], entry['nb_dates_distinctes'], float(entry['nb_'+associes+'s_distinctes']))
|
||||||
if rapport >= mac_prise.rapport_suspect[duree][groupe]:
|
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])
|
pb_comptage_suspect[entry[groupe]] = (liste_associes, rapport, mac_prise.rapport_suspect[duree][groupe])
|
||||||
else:
|
else:
|
||||||
pass
|
Logs.append(u"Entrée rejetée du tableau %s pour la recherche par %s, car rapport inférieur au seuil.\n\n" % (duree, groupe))
|
||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -148,10 +159,14 @@ def genere_comptage(duree, groupe, associes):
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
output = u"Détection de spoof potentiel\n\n\n"
|
output = u"Détection de spoof potentiel\n\n\n"
|
||||||
coupure = len(output)
|
coupure = len(output)
|
||||||
|
|
||||||
|
Logs = [u"Logs du script mac_prise_analyzer\n\n\n"]
|
||||||
|
|
||||||
output += genere_comptage('instant', 'mac', 'chambre')
|
output += genere_comptage('instant', 'mac', 'chambre')
|
||||||
output += genere_comptage('heuristique', 'mac', 'chambre')
|
output += genere_comptage('heuristique', 'mac', 'chambre')
|
||||||
output += genere_comptage('journalier', 'mac', 'chambre')
|
output += genere_comptage('journalier', 'mac', 'chambre')
|
||||||
|
@ -159,7 +174,45 @@ if __name__ == '__main__':
|
||||||
output += genere_comptage('heuristique', 'chambre', 'mac')
|
output += genere_comptage('heuristique', 'chambre', 'mac')
|
||||||
output += genere_comptage('journalier', 'chambre', 'mac')
|
output += genere_comptage('journalier', 'chambre', 'mac')
|
||||||
|
|
||||||
if len(output) == coupure:
|
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)
|
sys.exit(0)
|
||||||
|
|
||||||
print output.encode('utf-8')
|
message = """From: %(from)s
|
||||||
|
To: %(to)s
|
||||||
|
Subject: %(subject)s
|
||||||
|
Content-Type: multipart/mixed; boundary="_424234545aaff-ffca234efff-556adceff5646_"
|
||||||
|
|
||||||
|
--_424234545aaff-ffca234efff-556adceff5646_
|
||||||
|
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"
|
||||||
|
|
||||||
|
%(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),
|
||||||
|
}
|
||||||
|
|
||||||
|
mail = smtplib.SMTP('localhost')
|
||||||
|
mailfrom = 'spoof-watcher@crans.org'
|
||||||
|
mailto = 'test@lists.crans.org'
|
||||||
|
mail.sendmail(mailfrom, mailto, corps.encode('utf-8'))
|
||||||
|
|
125
surveillance/mac_prises/mac_prise_reperage.py
Executable file
125
surveillance/mac_prises/mac_prise_reperage.py
Executable file
|
@ -0,0 +1,125 @@
|
||||||
|
#!/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
|
||||||
|
|
||||||
|
ldap = lc_ldap.lc_ldap_admin()
|
||||||
|
|
||||||
|
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 date, chambre, mac FROM correspondance WHERE date >= timestamp 'now' - interval '24 hours' ORDER BY chambre ASC;"
|
||||||
|
cur.execute(requete)
|
||||||
|
fetched = cur.fetchall()
|
||||||
|
liste_parsee = {}
|
||||||
|
|
||||||
|
for entry in fetched:
|
||||||
|
if liste_parsee.has_key(entry['chambre']):
|
||||||
|
if liste_parsee[entry['chambre']].has_key(entry['mac']):
|
||||||
|
liste_parsee[entry['chambre']][entry['mac']] += 1
|
||||||
|
else:
|
||||||
|
liste_parsee[entry['chambre']][entry['mac']] = 1
|
||||||
|
else:
|
||||||
|
liste_parsee[entry['chambre']] = {}
|
||||||
|
liste_parsee[entry['chambre']][entry['mac']] = 1
|
||||||
|
|
||||||
|
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'))
|
|
@ -9,19 +9,4 @@ SWITCHS=$(/usr/bin/host -l adm.crans.org sable.adm.crans.org | /usr/bin/awk '/^b
|
||||||
# Lancement du listage des macs en parallèle
|
# Lancement du listage des macs en parallèle
|
||||||
python $SCRIPT $SWITCHS
|
python $SCRIPT $SWITCHS
|
||||||
|
|
||||||
CORPS=$(python $ANALYZER)
|
python $ANALYZER
|
||||||
LENGTH=$(echo $CORPS | wc -c)
|
|
||||||
if [ $LENGTH -ge 10 ]; then
|
|
||||||
(
|
|
||||||
cat <<EOF
|
|
||||||
To: test@lists.crans.org
|
|
||||||
From: Spoofing watcher <spoof-watcher@crans.org>
|
|
||||||
Subject: Analyse du spoofing
|
|
||||||
Content-Type: text/plain; charset="UTF-8"
|
|
||||||
|
|
||||||
${CORPS}
|
|
||||||
--
|
|
||||||
Script d'analyse en test
|
|
||||||
EOF
|
|
||||||
) | /usr/sbin/sendmail -t
|
|
||||||
fi;
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue