diff --git a/surveillance/deconnexion.py b/surveillance/deconnexion.py index ae414838..06598e1f 100755 --- a/surveillance/deconnexion.py +++ b/surveillance/deconnexion.py @@ -1,6 +1,18 @@ #! /usr/bin/env python # -*- coding: iso-8859-15 -*- +""" +Script de déconnection automatique des machines du crans pour les raisons : + - upload + - p2p + - flood + - virus + +Copyright (C) Xavier Pessoles +Licence : ???? +""" + + ########################### # Import des commmandes : # ########################### @@ -9,13 +21,13 @@ import commands import sys from pyPgSQL import PgSQL sys.path.append('/usr/scripts/gestion') -from config import upload, virus, p2p +from config import upload, virus, p2p, NETs import smtplib from ldap_crans import crans_ldap, crans, invite, base_classes_crans from time import * -# quelques fonctions +# Quelques fonctions #################### def machine_online(machine) : @@ -28,11 +40,24 @@ def machine_online(machine) : # arping pour les fixes return not commands.getstatusoutput('/usr/sbin/arping -c 3 %s' % machine.mac())[0] +# Variables utiles +################## + +# création d'une chaine qui ressemble à : (ip_src<<=inet('138.231.136.0/21') or ip_src<<=inet('138.231.148.0/22')) +ip_src_in_crans = '(%s)' % ' or '.join([ "ip_src<<=inet('%s')" % net for net in NETs['all'] ]) + # Connections : ############### + +# pgsql pgsql = PgSQL.connect(host='/var/run/postgresql', database='filtrage', user='crans') pgsql.autocommit = True +curseur = pgsql.cursor() + +# smtp mail = smtplib.SMTP('localhost') + +# ldap ldap = crans_ldap() @@ -40,21 +65,21 @@ ldap = crans_ldap() # Vérification de l'upload et du download # ########################################### -# Déclaration du curseur : -########################## -curseur = pgsql.cursor() - # Table des uploaders : ####################### -requete = "SELECT round(sum(upload)/1024/1024) as total,ip_crans from upload where upload>download and date>timestamp 'now' - interval '1 day' and date<'now' and NOT EXISTS ( select 1 from exemptes where upload.ip_crans<<=exemptes.ip_crans and upload.ip_ext<<=exemptes.ip_dest) group by ip_crans order by total desc" +requete = "SELECT round(sum(upload)/1024/1024) AS total,ip_crans FROM upload WHERE upload>download AND date>timestamp 'now' - interval '1 day' AND date<'now' AND NOT EXISTS ( SELECT 1 FROM exemptes WHERE upload.ip_crans<<=exemptes.ip_crans and upload.ip_ext<<=exemptes.ip_dest) GROUP BY ip_crans ORDER BY total desc" curseur.execute(requete) -table = curseur.fetchall() +uploadeurs= curseur.fetchall() # Table des avertis ################### + +# Avertis hard requete = "SELECT ip_crans FROM avertis_upload where hard='1' and date>timestamp 'now' - interval '1 day'" curseur.execute(requete) avertish = curseur.fetchall() + +# Avertis soft requete = "SELECT ip_crans FROM avertis_upload where soft='1' " curseur.execute(requete) avertiss = curseur.fetchall() @@ -62,93 +87,97 @@ avertiss = curseur.fetchall() # Vérification : ################ -for i in range(0,len(table)) : - elupload = int(table[i][0]) - IP = table[i][1].encode('iso 8859-15') - # On regarde si c'est de l'upload hard - if elupload >= upload.hard : - # L'adhérent a t il été averti ? - if [IP] not in avertish: - machine = ldap.search('ipHostNumber=%s' % IP,'w')['machine'][0] - hostname = machine.nom() - proprio = machine.proprietaire() - aid = machine.id() - if proprio.__class__ != crans and proprio.__class__ != invite: - # On inscrit l'ip dans la table des avertis - ########################################### - inscription = "INSERT INTO avertis_upload (ip_crans,date,hard) VALUES ('%s','now','1')" % IP - curseur.execute(inscription) - # On sanctionne : - ################# - date = time() - #debut = localtime(date+60*60*24*200)#test - debut = localtime(date) - #fin = localtime(date+60*60*24*300)#test - fin = localtime(date+60*60*24) - proprio.blacklist(["%d/%d/%d %d:%d" % (debut[2],debut[1],debut[0],debut[3],debut[4]),"%d/%d/%d %d:%d" % (fin[2],fin[1],fin[0],fin[3],fin[4]),'autodisc',"Déconn auto. %s Mo" % elupload]) - proprio.save() - - # On récupere l'adresse électronique : - ###################################### - proprio = proprio.mail() - if '@' not in proprio : - proprio += '@crans.org' - else: - proprio = 'roots@crans.org' - corps = upload.hardmessage % { 'From': upload.expediteur, - 'To': proprio, - 'upload': elupload, - 'hostname': hostname } - corps = corps.encode('iso 8859-15') - # On envoie un mail a l'adhérent - mail.sendmail(upload.expediteur,proprio,corps) - # On envoie un mail à disconnect - corps = upload.deconnexion % { 'From': upload.expediteur, - 'To': upload.expediteur, - 'upload': elupload, - 'hostname': hostname } - corps = corps.encode('iso 8859-15') - mail.sendmail(upload.expediteur,upload.expediteur,corps) - - - - # Est ce de l'upload soft ? - elif elupload >= upload.soft : - # L'adhérent a-t-il déjà été averti ? - if [IP] not in avertiss: - # On lui envoie un mail et on l'inscrit - machine = ldap.search('ipHostNumber=%s' % IP )['machine'][0] - hostname = machine.nom() - proprio = machine.proprietaire().mail() - if '@' not in proprio : - proprio += '@crans.org' - corps = upload.softmessage % { 'From': upload.expediteur, - 'To': proprio, - 'upload': elupload, - 'hostname':hostname } - corps = corps.encode('iso 8859-15') - mail.sendmail(upload.expediteur,proprio,corps) - - # On envoie un mail à disconnect - corps = upload.avertissement % { 'From': upload.expediteur, - 'To': upload.expediteur, - 'upload': elupload, - 'hostname': hostname} - corps = corps.encode('iso 8859-15') - mail.sendmail(upload.expediteur,upload.expediteur,corps) - # On inscrit l'ip dans la table des avertis - inscription = "INSERT INTO avertis_upload (ip_crans,date,soft) VALUES ('%s','now','1')" % IP - curseur.execute(inscription) +for elupload, IP in uploadeurs : + + # On regarde si c'est de l'upload hard + if elupload >= upload.hard : + + # L'adhérent a t il été averti ? + ################################ + if [IP] in avertish: + continue + + # Objets LDAP + ############# + machine = ldap.search('ipHostNumber=%s' % IP,'w')['machine'][0] + hostname = machine.nom() + proprio = machine.proprietaire() + mid = machine.id() + + # On évite de blacklister les proprios spéciaux + ############################################### + if proprio.__class__ == crans or proprio.__class__ == invite: + continue + + # On inscrit l'ip dans la table des avertis + ########################################### + inscription = "INSERT INTO avertis_upload (ip_crans,date,hard) VALUES ('%s','now','1')" % IP + curseur.execute(inscription) + + # On sanctionne + ############### + debut = localtime(time()) + fin = localtime(time()+60*60*24) + proprio.blacklist(["%d/%d/%d %d:%d" % (debut[2],debut[1],debut[0],debut[3],debut[4]),"%d/%d/%d %d:%d" % (fin[2],fin[1],fin[0],fin[3],fin[4]),'autodisc',"Déconn auto. %s Mo" % elupload]) + proprio.save() + + # On envoie un mail a l'adhérent + ################################ + proprio = proprio.mail() + if '@' not in proprio : + proprio += '@crans.org' + corps = upload.hardmessage % { 'From': upload.expediteur, 'To': proprio, 'upload': elupload, 'hostname': hostname } + corps = corps.encode('iso 8859-15') + mail.sendmail(upload.expediteur,proprio,corps) -# Changement de statut des uploders (Ainsi, les gens ne recoivent des mails qu'une fois et on a en memoire les uplaods) + # On envoie un mail à disconnect + ################################ + if upload.disconnect_mail_hard : + corps = upload.deconnexion % { 'From': upload.expediteur, 'To': upload.expediteur, 'upload': elupload, 'hostname': hostname } + corps = corps.encode('iso 8859-15') + mail.sendmail(upload.expediteur,upload.expediteur,corps) + + # Est ce de l'upload soft ? + elif elupload >= upload.soft : + + # L'adhérent a-t-il déjà été averti ? + ##################################### + if [IP] not in avertiss: + continue + + # On récupère les informations de LDAP + ###################################### + machine = ldap.search('ipHostNumber=%s' % IP )['machine'][0] + hostname = machine.nom() + proprio = machine.proprietaire().mail() + + # On envoie un mail à l'adhérent + ################################ + if '@' not in proprio : + proprio += '@crans.org' + corps = upload.softmessage % { 'From': upload.expediteur, 'To': proprio, 'upload': elupload, 'hostname':hostname } + corps = corps.encode('iso 8859-15') + mail.sendmail(upload.expediteur,proprio,corps) + + # On envoie un mail à disconnect + ################################ + if upload.disconnect_mail_sost: + corps = upload.avertissement % { 'From': upload.expediteur, 'To': upload.expediteur, 'upload': elupload, 'hostname': hostname} + corps = corps.encode('iso 8859-15') + mail.sendmail(upload.expediteur,upload.expediteur,corps) + + # On inscrit l'ip dans la table des avertis + ########################################### + inscription = "INSERT INTO avertis_upload (ip_crans,date,soft) VALUES ('%s','now','1')" % IP + curseur.execute(inscription) + +# Changement de statut des uploders (Ainsi, les gens ne recoivent des mails qu'une fois et on a en memoire les uploads) requete="UPDATE avertis_upload set hard='f' where hard='t' and date < timestamp ' now' - interval '1 day'" curseur.execute(requete) requete="UPDATE avertis_upload set soft='f' where soft='t' and date < timestamp 'now' - interval '1 day'" curseur.execute(requete) - - ############################################### # Détection de l'existence de virus ou de P2P # ############################################### @@ -157,7 +186,7 @@ curseur.execute(requete) ######## # Dans le table virus on sélectionne les ip_src qui appartiennent au reseau -requete = "SELECT ip_src,count(ip_src) FROM virus WHERE (ip_src<<=inet('138.231.136.0/21') or ip_src<<=inet('138.231.148.0/22')) and date > timestamp 'now' - interval '1 hour' group by ip_src" +requete = "SELECT ip_src,count(ip_src) FROM virus WHERE %s and date > timestamp 'now' - interval '1 hour' group by ip_src" % ip_src_in_crans curseur.execute(requete) veroles = curseur.fetchall() @@ -166,11 +195,8 @@ requete = "SELECT ip_crans FROM avertis_virus" curseur.execute(requete) infectes = curseur.fetchall() -for verole in veroles: - - ip=verole[0] - nombre=verole[1] - +for ip, nombre in veroles: + # si le type dépasse le seuil, on le blacklist if nombre < virus.virus or [ip] not in infectes : continue @@ -196,11 +222,12 @@ for verole in veroles: proprio.blacklist(['now','-','virus',hostname]) proprio.save() + # Flood ######## # Dans le table virus on sélectionne les ip_src qui appartiennent au reseau -requete = "SELECT ip_src,count(ip_src) FROM flood WHERE (ip_src<<=inet('138.231.136.0/21') or ip_src<<=inet('138.231.148.0/22')) and date > timestamp 'now' - interval '1 hour' group by ip_src" +requete = "SELECT ip_src,count(ip_src) FROM flood WHERE %s and date > timestamp 'now' - interval '1 hour' GROUP BY ip_src" % ip_src_in_crans curseur.execute(requete) veroles = curseur.fetchall() @@ -209,10 +236,7 @@ requete = "SELECT ip_crans FROM avertis_virus" curseur.execute(requete) infectes = curseur.fetchall() -for verole in veroles: - - ip=verole[0] - nombre=verole[1] +for ip, nombre in veroles: # si le type dépasse le seuil, on le blacklist if nombre < virus.flood or [ip] not in infectes : @@ -239,21 +263,28 @@ for verole in veroles: proprio.blacklist(['now','-','virus',hostname]) proprio.save() -# Reconnexion si le virus a disparu -################################### +# Reconnexion si le virus/flood a disparu +######################################### + +# Dans la table avertis_virus on récupère la liste des infectés requete = "SELECT ip_crans FROM avertis_virus where date < timestamp 'now' - interval '1 hour'" curseur.execute(requete) -infectes = curseur.fetchall() -for i in range(0,len(infectes)): - IP=infectes[i][0] +infectes = [ x[0] for x in curseur.fetchall() ] + +for IP in infectes : + + # Nombre de requets de virus requete1="SELECT COUNT(ip_src) FROM virus where ip_src='%s' and date > timestamp 'now' - interval '1 hour'" % IP curseur.execute(requete1) nb_virus = curseur.fetchall() + + # Nombre de requetes de flood requete2="SELECT COUNT(ip_src) FROM flood where ip_src='%s' and date > timestamp 'now' - interval '1 hour'" % IP curseur.execute(requete2) nb_flood = curseur.fetchall() - # On traite que les IP qui sont descendues en dessoys des seuils + + # On traite que les IP qui sont descendues en dessous des seuils if nb_virus[0][0] < virus.virus and nb_flood[0][0] < virus.flood : machine = ldap.search('ipHostNumber=%s' % IP,'w' )['machine'][0] # si la machine est pas online, on reconnecte @@ -280,55 +311,48 @@ for i in range(0,len(infectes)): # Gestion du P2P : ################## -# Dans le table virus on sélectionne les ip_src qui appartiennent au reseau -requete = "SELECT ip_src,id_p2p FROM p2p WHERE (ip_src<<=inet('138.231.136.0/21') or ip_src<<=inet('138.231.148.0/22')) and date > timestamp 'now' - interval '1 day' order by ip_src" +# Dans le table p2p on sélectionne les ip_src qui appartiennent au reseau +requete = "SELECT ip_src,id_p2p,count(ip_src) FROM p2p WHERE %s AND date > timestamp 'now' - interval '1 day' GROUP BY ip_src,id_p2p ORDER BY ip_src" % ip_src_in_crans curseur.execute(requete) -pair = curseur.fetchall() +fraudeurs = curseur.fetchall() + # Recuperation des infectes pour ne pas les reblacklister -requete = "SELECT ip_crans FROM avertis_p2p WHERE date > timestamp 'now' - interval '1 day'" +requete = "SELECT ip_crans,protocole FROM avertis_p2p WHERE date > timestamp 'now' - interval '1 day'" curseur.execute(requete) avertisp2p = curseur.fetchall() -N=0 -ip1=str('0.0.0.0') -if pair : - ip1=pair[0][0] - for i in range(0,len(pair)): - ip=pair[i][0] - if ip != ip1 : - ip1=ip - N=0 - else : - N=N+1 - if N >= p2p.tag and [ip] not in avertisp2p : - # Recuperation des ref de la machine - machine = ldap.search('ipHostNumber=%s' % ip,'w' )['machine'][0] - hostname = machine.nom() - proprio = machine.proprietaire() - #On récupére le protocole de p2p : - protocole=int(pair[i][1]) - requete="SELECT nom FROM protocole_p2p WHERE id_p2p=%d" % protocole - curseur.execute(requete) - protocole = curseur.fetchall() - protocole=protocole[0][0] - corps = p2p.avertissement % { 'From': upload.expediteur, - 'To': upload.expediteur, - 'protocole': protocole, - 'hostname':hostname} - corps = corps.encode('iso 8859-15') - mail.sendmail(upload.expediteur,upload.expediteur,corps) - #Inscription dans la base des avertis - requete="INSERT INTO avertis_p2p (ip_crans,date,protocole) VALUES ('%s','now','%s')" % (ip1,protocole) - curseur.execute(requete) - requete = "SELECT ip_crans FROM avertis_p2p WHERE date > timestamp 'now' - interval '1 day'" - curseur.execute(requete) - avertisp2p = curseur.fetchall() - # Blacklistage - date = time() - debut = localtime(date) - # 7 jours - fin = localtime(date+60*60*24*7) - # proprio.blacklist(["%d/%d/%d %d:%d" % (debut[2],debut[1],debut[0],debut[3],debut[4]),"%d/%d/%d %d:%d" % (fin[2],fin[1],fin[0],fin[3],fin[4]),'p2p',"P2P (auto)" % protocole]) - # proprio.save() +for ip, id_p2p, nombre in fraudeurs : + + # On récupére le protocole de p2p : + requete="SELECT nom FROM protocole_p2p WHERE id_p2p=%d" % id_p2p + curseur.execute(requete) + protocole = curseur.fetchall()[0][0] + + # On ne prend pas en compte s'il est sous le seuil admis, ou s'il est averti + if nombre <= p2p.tag or [ip, protocole] in avertisp2p : + continue + + # Recuperation des ref de la machine + machine = ldap.search('ipHostNumber=%s' % ip,'w' )['machine'][0] + hostname = machine.nom() + # proprio = machine.proprietaire() + + # Envoie du mail à disconnect + corps = p2p.avertissement % { 'From': upload.expediteur, 'To': upload.expediteur, 'protocole': protocole, 'hostname':hostname} + corps = corps.encode('iso 8859-15') + mail.sendmail(upload.expediteur,upload.expediteur,corps) + + # Inscription dans la base des avertis + requete="INSERT INTO avertis_p2p (ip_crans,date,protocole) VALUES ('%s','now','%s')" % (ip, protocole) + curseur.execute(requete) + + # Blacklistage + # date = time() + # debut = localtime(date) + # 7 jours + # fin = localtime(date+60*60*24*7) + # proprio.blacklist(["%d/%d/%d %d:%d" % (debut[2],debut[1],debut[0],debut[3],debut[4]),"%d/%d/%d %d:%d" % (fin[2],fin[1],fin[0],fin[3],fin[4]),'p2p',"P2P (auto)" % protocole]) + # proprio.save() + +# fermeture des connections mail.quit() -