diff --git a/surveillance/deconnexion-ng.py b/surveillance/deconnexion-ng.py deleted file mode 100755 index 271f760d..00000000 --- a/surveillance/deconnexion-ng.py +++ /dev/null @@ -1,472 +0,0 @@ -#! /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, Étienne Chové, Vincent Bernat -Licence : GPL v2 -""" - -################################################################################ -# Import des commandes # -################################################################################ - -import commands -import sys -from pyPgSQL import PgSQL -sys.path.append('/usr/scripts/gestion') -from config import upload, virus, p2p, NETs -import smtplib -from ldap_crans import crans_ldap, crans, invite, base_classes_crans -from time import * -import locale -locale.setlocale(locale.LC_TIME,'fr_FR') - -debug = '--debug' in sys.argv - -# Quelques fonctions -#################### - -def machine_online(machine) : - """ - Retourne True si la machine est connectée au réseau et False si elle ne l'est pas - """ - # les wifi sont toujours online - if machine.ipsec() : - return True - # 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() - -################################################################################ -# Vérification de l'upload # -################################################################################ - -# upload par entité (adhérent/club/machine crans) -requete = """SELECT - sum(total), type, id -FROM - ( - SELECT - sum(total) AS total, ip_crans - FROM - ( - ( -- upload terminé par ip - SELECT - 'upload',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 - ) - UNION - ( -- upload en cours par ip - SELECT - 'dump', round(sum(upload)/1024/1024) AS total, ip_crans - FROM - dump AS 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 - ) - ) - AS - total - GROUP BY - ip_crans - ) -AS - total -INNER JOIN - machines -ON - total.ip_crans = machines.ip -GROUP BY - type, id -;""" -curseur.execute(requete) -uploadeurs = curseur.fetchall() - -# Table des avertis -################### - -# Avertis hard -requete = "SELECT type,id FROM avertis_upload_hard where date>timestamp 'now' - interval '1 day'" -curseur.execute(requete) -avertis_hard = curseur.fetchall() - -# Avertis soft -requete = "SELECT type,id FROM avertis_upload_soft where date>timestamp 'now' - interval '1 day'" -curseur.execute(requete) -avertis_soft = curseur.fetchall() - -#uploadeurs.append([1000,'adherent',367]) - -# Vérification : -################ - -for elupload, eltype, elid in uploadeurs: - if elupload >= upload.hard : - # L'adhérent a t il été blacklisté ? - #################################### - if [eltype,elid] in avertis_hard: - continue - - # Propriétaire issu de LDAP - ########################### - if eltype == 'club': - proprio=ldap.search('cid=%d'%elid,'w')['club'] - elif eltype == 'adherent': - proprio=ldap.search('aid=%d'%elid,'w')['adherent'] - else: - continue - - if len(proprio)!=1: - print 'Erreur : Proprio non trouvé (%s) %d'%(eltype, elid) - continue - proprio=proprio[0] - - # On inscrit l'ip dans la table des avertis_hard - ################################################ - curseur.execute("INSERT INTO avertis_upload_hard (type,id,date) VALUES ('%s','%d','now')"%(eltype,elid)) - - # on s'arrete ici pour le debug - if debug: - print 'Sanction de %s pour upload (%dMo)'%(proprio.Nom(),elupload) - - # 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_mail = proprio.email() - corps = upload.message_soft % {'from':upload.expediteur, 'to':proprio_mail, 'upload':elupload, 'proprio':proprio.Nom()} - corps = corps.encode('iso 8859-15') - #mail.sendmail(upload.expediteur,proprio,corps) - - # On envoie un mail à disconnect - ################################ - if upload.disconnect_mail_hard : - corps = upload.message_disconnect_hard % {'from':upload.expediteur, 'to':upload.expediteur, 'upload':elupload, 'proprio':proprio.Nom()} - corps = corps.encode('iso 8859-15') - #mail.sendmail(upload.expediteur,upload.expediteur,corps) - - # Vérification du nombre de déconnections - ######################################### - nb_decos = len([ x for x in proprio.blacklist() if mktime(strptime(x.split(',')[0],'%d/%m/%Y %H:%M')) > mktime(localtime())-30*24*60*60 and x.split(',')[2]=='autodisc' ]) - if nb_decos >= 3: - if debug: - print 'Recidiviste !!!' - - # dossier de génération du pdf - dossier = '/usr/scripts/surveillance/fiche_deconnection/' - - # base pour le dossier de destination - fichier = strftime('%Y-%m-%d-%H-%M') + '-' + proprio.Nom().lower().replace(' ','-') - - # création du fichier tex - template = file(dossier + 'deconnexion_upload.tex').read() - template = template.replace('~prenom~',proprio.prenom().encode('iso8859-15')) - template = template.replace('~nom~',proprio.nom().encode('iso8859-15')) - template = template.replace('~chambre~',proprio.chbre().encode('iso8859-15')) - template = template.replace('~mail~',proprio.email().encode('iso8859-15')) - template = template.replace('~debut~',proprio.prenom().encode('iso8859-15')) - template = template.replace('~fin~',proprio.prenom().encode('iso8859-15')) - historique = [ bl.encode('iso-8859-15').split(',') for bl in proprio.blacklist() if bl.split(',')[2]=='autodisc' ] # filtrage des autodisc - historique = [ (strftime('%A %d %B %Y',strptime(bl[0],'%d/%m/%Y %H:%M')), bl[-1].split(' ')[-2]) for bl in historique ] # transfomation en tupple (date, upload) - historique = [ '%s & %s & Mo'%(bl[0],bl[1]) for bl in historique ] # tranformation en ligne - historique = '\\\\\n'.join(historique) # assemblage des lignes - template = template.replace('~historique~', historique) - - file(dossier+fichier+'.tex','w').write(template) - - # compilation - commands.getstatusoutput('PATH="/bin:/usr/bin" cd %(dossier)s && latex %(base)s.tex && dvips %(base)s.ps && rm -f %(base)s.dvi %(base)s.aux %(base)s.log %(base)s.tex'%{'dossier':dossier,'base':fichier}) - - # envoie du mail à disconnect - corps = upload.message_disconnect_multi % {'from':upload.expediteur, 'to':upload.expediteur, 'nbdeco':nb_decos, 'proprio':proprio.Nom(), 'ps':dossier+fichier+'.ps'} - corps = corps.encode('iso 8859-15') - mail.sendmail(upload.expediteur,upload.expediteur,corps) - - elif elupload >= upload.soft : - # L'adhérent a t il été averti - ############################## - if [eltype,elid] in avertis_soft: - continue - - # Objets LDAP - ############# - if eltype == 'club': - proprio=ldap.search('cid=%d'%elid)['club'] - elif eltype == 'adherent': - proprio=ldap.search('aid=%d'%elid)['adherent'] - else: - continue - - if len(proprio)!=1: - print 'Proprio non trouvé (%s) %d'%(eltype, elid) - continue - proprio=proprio[0] - - # On inscrit l'ip dans la table des avertis soft - ################################################ - curseur.execute("INSERT INTO avertis_upload_soft (type,id,date) VALUES ('%s','%d','now')"%(eltype,elid)) - - # on s'arrete ici pour le debug - if debug: - print 'Upload soft de %s (%dMo)'%(proprio.Nom(),elupload) - continue - - # On envoie un mail a l'adhérent - ################################ - if debug: print 'Avertissement de %s pour upload'%proprio.Nom() - proprio_mail = proprio.mail() - if '@' not in proprio_mail : - proprio_mail += '@crans.org' - corps = upload.message_soft % {'from':upload.expediteur, 'to':proprio_mail, 'upload':elupload, 'proprio':proprio.Nom()} - corps = corps.encode('iso 8859-15') - #mail.sendmail(upload.expediteur,proprio,corps) - - # On envoie un mail à disconnect - ################################ - if upload.disconnect_mail_soft : - corps = upload.message_disconnect_soft % {'from':upload.expediteur, 'to':upload.expediteur, 'upload':elupload, 'proprio':proprio.Nom()} - corps = corps.encode('iso 8859-15') - #mail.sendmail(upload.expediteur,upload.expediteur,corps) - -# On supprime les vieux avertisements -curseur.execute("DELETE FROM avertis_upload_hard WHERE date < timestamp 'now' - interval '1 day'") -curseur.execute("DELETE FROM avertis_upload_soft WHERE date < timestamp 'now' - interval '1 day'") - -sys.exit(0) - -################################################################################ -# Détection de l'existence de virus # -################################################################################ - -# Dans le table virus on sélectionne les ip_src qui appartiennent au reseau -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) -infectes = curseur.fetchall() - -# Recuperation des infectes pour ne pas les reblacklister -requete = "SELECT ip_crans FROM avertis_virus" -curseur.execute(requete) -infectes_old = curseur.fetchall() - -for ip, nombre in infectes: - - # si on est en dessous du seuil, on laisse passer - if nombre < virus.virus: - continue - - # si on est déja avertis, on laisse passer - if [ip] in infectes_old: - continue - - # lecture des infos de ldap - machine = ldap.search('ipHostNumber=%s' % ip,'w' )['machine'][0] - hostname = machine.nom() - proprio = machine.proprietaire() - blacklist = proprio.blacklist() - - # inscription dans la table des infectes - requete="INSERT INTO avertis_virus (ip_crans,date) VALUES ('%s','now')" % ip - curseur.execute(requete) - - # on récupère les index des lignes de bl ou il y a marqué virus - index = [blacklist.index(x) for x in blacklist if 'virus' in x ] - if index : - # adhérent déja blacklisté - proprio.blacklist(( index[0] , ['now','-','virus',hostname] )) - proprio.save() - else : - # adhérent non blacklisté - proprio.blacklist(['now','-','virus',hostname]) - proprio.save() - -################################################################################ -# Détection des virus qui floodent # -################################################################################ - -# Dans le table virus on sélectionne les ip_src qui appartiennent au reseau -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) -infectes = curseur.fetchall() - -# Recuperation des infectes pour ne pas les reblacklister -requete = "SELECT ip_crans FROM avertis_virus" -curseur.execute(requete) -infectes_old = curseur.fetchall() - -for ip, nombre in infectes: - - # si on est en dessous du seuil, on laisse passer - if nombre < virus.flood: - continue - - # si on est déja avertis, on laisse passer - if [ip] in infectes_old : - continue - - # lecture des infos de ldap - machine = ldap.search('ipHostNumber=%s' % ip,'w' )['machine'][0] - hostname = machine.nom() - proprio = machine.proprietaire() - blacklist = proprio.blacklist() - - # inscription dans la table des infectes - requete="INSERT INTO avertis_virus (ip_crans,date) VALUES ('%s','now')" % ip - curseur.execute(requete) - - # on récupère les index des lignes de bl ou il y a marqué virus - index = [blacklist.index(x) for x in blacklist if 'virus' in x ] - if index : - # adhérent déja blacklisté - proprio.blacklist(( index[0] , ['now','-','virus',hostname] )) - proprio.save() - else : - # adhérent non blacklisté - proprio.blacklist(['now','-','virus',hostname]) - proprio.save() - - -# 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 = [ 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 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 - #if machine_online(machine) : - proprio = machine.proprietaire() - bl = proprio.blacklist() - hostname = machine.nom() - # On stoppe la sanction pour une ligne existante de la blackliste - # En prenant en compte le fait que d'autres lignes de blackliste - # ont pu s'ajouter. - for ligne in bl: - if ',-,virus,%s'%hostname in ligne: - liste=ligne.split(',') - argument=[liste[0],'now',liste[2],liste[3]] - index = bl.index(ligne) - proprio.blacklist((index,argument)) - proprio.save() - requete="DELETE FROM avertis_virus where ip_crans='%s'"%IP - curseur.execute(requete) - -################################################################################ -# Gestion du peer to peer # -################################################################################ - -# 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) -fraudeurs = curseur.fetchall() - -# Recuperation des infectes pour ne pas les reblacklister -requete = "SELECT ip_crans,protocole FROM avertis_p2p WHERE date > timestamp 'now' - interval '1 day'" -curseur.execute(requete) -avertisp2p = curseur.fetchall() - -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 - if p2p.disconnect_mail : - 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()