diff --git a/surveillance/deconnexion.py b/surveillance/deconnexion.py index 58c387af..fc8399b8 100755 --- a/surveillance/deconnexion.py +++ b/surveillance/deconnexion.py @@ -12,10 +12,9 @@ Copyright (C) Xavier Pessoles, Licence : GPL v2 """ - -########################### -# Import des commmandes : # -########################### +################################################################################ +# Import des commandes # +################################################################################ import commands import sys @@ -25,6 +24,8 @@ 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') # Quelques fonctions #################### @@ -45,7 +46,6 @@ def machine_online(machine) : # 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 : ############### @@ -60,101 +60,121 @@ mail = smtplib.SMTP('localhost') # ldap ldap = crans_ldap() +################################################################################ +# Vérification de l'upload # +################################################################################ -########################################### -# Vérification de l'upload et du download # -########################################### - -requete_template = "SELECT ip_crans,round(sum(upload)/1024/1024) AS total FROM %(table)s WHERE upload>download AND date>timestamp 'now' - interval '23 hours 50 minutes' AND date<'now' AND NOT EXISTS ( SELECT 1 FROM exemptes WHERE %(table)s.ip_crans<<=exemptes.ip_crans and %(table)s.ip_ext<<=exemptes.ip_dest) GROUP BY ip_crans ORDER BY total desc" - -# table générale d'upload -requete = requete_template % {'table':'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_general = curseur.fetchall() - -# table temporaire d'upload -requete = requete_template % {'table':'dump'} -curseur.execute(requete) -uploadeurs_dump = curseur.fetchall() - -# concaténation des résultats -uploadeurs = {} -for i in uploadeurs_general + uploadeurs_dump: - if i[0] in uploadeurs: - uploadeurs[i[0]]+=float(i[1]) - else: - uploadeurs[i[0]]=float(i[1]) -uploadeurs=uploadeurs.items() +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'" +requete = "SELECT type,id FROM avertis_upload_hard where date>timestamp 'now' - interval '1 day'" curseur.execute(requete) -avertish = [ x[0] for x in curseur.fetchall() ] +avertis_hard = curseur.fetchall() # Avertis soft -requete = "SELECT ip_crans FROM avertis_upload where soft='1' " +requete = "SELECT type,id FROM avertis_upload_soft where date>timestamp 'now' - interval '1 day'" curseur.execute(requete) -avertiss = [ x[0] for x in curseur.fetchall() ] +avertis_soft = curseur.fetchall() # Vérification : ################ -for IP, elupload in uploadeurs: - - # On regarde si c'est de l'upload hard +for elupload, eltype, elid in uploadeurs: if elupload >= upload.hard : - - # L'adhérent a t il été averti ? - ################################ - if str(IP) in avertish: + # L'adhérent a t il été blacklisté ? + #################################### + if [eltype,elid] in avertis_hard: continue - - # Objets LDAP - ############# - machine = ldap.search('ipHostNumber=%s' % IP,'w')['machine'] - if not machine: - print 'IP non trouvée (%s)'%IP - continue - machine=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: + # 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 - ########################################### - inscription = "INSERT INTO avertis_upload (ip_crans,date,hard) VALUES ('%s','now','1')" % IP - curseur.execute(inscription) - + # On inscrit l'instance dans la table des avertis_hard + ###################################################### + curseur.execute("INSERT INTO avertis_upload_hard (type,id,date) VALUES ('%s','%d','now')"%(eltype,elid)) + # On sanctionne ############### -# nb_decos = len([ x for x in e.blacklist() if mktime(strptime(x.split(',')[0],'%d/%m/%Y %H:%M')) > mktime(localtime())-30*24*60*60 and x.split(',')[2]=='autodisc' ]) -# if nbdec >= 2: -# pass - #bl=proprio.blacklist() - #for x in bl: - # if mktime(strptime(x.split(',')[0],'%d/%m/%Y %H:%M')) > mktime(localtime())-30*24*60*60 and x.split(',')[2]=='autodisc' : - # liste+=x - # message="""From: %(From)s - # To: %(To)s - # Subject: Upload Massif - # - # La machine a dépassé trois fois les limites d'upload durant le dernier mois : - # %(liste)s - # -- - # deconnexion.py - # """ - # corps = message %{'From':upload.expediteur, - # 'To':upload.expediteur, - # 'liste':liste} 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]) @@ -162,127 +182,160 @@ for IP, elupload in uploadeurs: # 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 = 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) - + mail.sendmail(upload.expediteur,proprio.email(),corps) + # On envoie un mail à disconnect ################################ if upload.disconnect_mail_hard : - corps = upload.deconnexion % { 'From': upload.expediteur, 'To': upload.expediteur, 'upload': elupload, 'hostname': hostname } + 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) - - # Est ce de l'upload soft ? + + # 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: + + # 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 - # L'adhérent a-t-il déjà été averti ? - ##################################### - if str(IP) in avertiss: + # Objets LDAP + ############# + if eltype == 'club': + proprio=ldap.search('cid=%d'%elid)['club'] + elif eltype == 'adherent': + proprio=ldap.search('aid=%d'%elid)['adherent'] + else: continue - - # On récupère les informations de LDAP - ###################################### - machine = ldap.search('ipHostNumber=%s' % IP,'w')['machine'] - if not machine: - print 'IP non trouvée (%s)'%IP + + if len(proprio)!=1: + print 'Proprio non trouvé (%s) %d'%(eltype, elid) continue + proprio=proprio[0] - machine=machine[0] - hostname = machine.nom() - proprio = machine.proprietaire().email() + # 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 envoie un mail à l'adhérent + # On envoie un mail a l'adhérent ################################ - corps = upload.softmessage % { 'From': upload.expediteur, 'To': proprio, 'upload': elupload, 'hostname':hostname } + 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) + mail.sendmail(upload.expediteur,proprio.email(),corps) # On envoie un mail à disconnect ################################ - if upload.disconnect_mail_soft: - corps = upload.avertissement % { 'From': upload.expediteur, 'To': upload.expediteur, 'upload': elupload, 'hostname': hostname} + 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 inscrit l'ip dans la table des avertis - ########################################### - inscription = "INSERT INTO avertis_upload (ip_crans,date,soft) VALUES ('%s','now','1')" % IP - print inscription - 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) +# 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'") - -############################################### -# Détection de l'existence de virus ou de P2P # -############################################### - -# VIRUS -######## +################################################################################ +# 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) -veroles = curseur.fetchall() +infectes = curseur.fetchall() # Recuperation des infectes pour ne pas les reblacklister requete = "SELECT ip_crans FROM avertis_virus" curseur.execute(requete) -infectes = curseur.fetchall() +infectes_old = curseur.fetchall() -for ip, nombre in veroles: +for ip, nombre in infectes: - # si le type dépasse le seuil, on le blacklist - if nombre < virus.virus or [ip] 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 + # inscription dans la table des infectes requete="INSERT INTO avertis_virus (ip_crans,date) VALUES ('%s','now')" % ip curseur.execute(requete) - print "Deconnexion virus : %s" % hostname - # 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() - -# Flood -######## +################################################################################ +# 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) -veroles = curseur.fetchall() +infectes = curseur.fetchall() # Recuperation des infectes pour ne pas les reblacklister requete = "SELECT ip_crans FROM avertis_virus" curseur.execute(requete) -infectes = curseur.fetchall() +infectes_old = curseur.fetchall() -for ip, nombre in veroles: +for ip, nombre in infectes: - # si le type dépasse le seuil, on le blacklist - if nombre < virus.flood or [ip] 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 @@ -290,19 +343,19 @@ for ip, nombre in veroles: hostname = machine.nom() proprio = machine.proprietaire() blacklist = proprio.blacklist() - - # Inscription dans la table des infectes + + # inscription dans la table des infectes requete="INSERT INTO avertis_virus (ip_crans,date) VALUES ('%s','now')" % ip curseur.execute(requete) - print "Deconnexion flood : %s" % hostname - # 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() @@ -342,17 +395,15 @@ for IP in infectes : if ',-,virus,%s'%hostname in ligne: liste=ligne.split(',') argument=[liste[0],'now',liste[2],liste[3]] - print argument,IP index = bl.index(ligne) proprio.blacklist((index,argument)) proprio.save() requete="DELETE FROM avertis_virus where ip_crans='%s'"%IP curseur.execute(requete) - print "Reconnexion %s" %hostname - -# Gestion du P2P : -################## +################################################################################ +# 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 @@ -384,9 +435,9 @@ for ip, id_p2p, nombre in fraudeurs : 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) + #mail.sendmail(upload.expediteur,upload.expediteur,corps) - # Inscription dans la base des avertis + # inscription dans la base des avertis requete="INSERT INTO avertis_p2p (ip_crans,date,protocole) VALUES ('%s','now','%s')" % (ip, protocole) curseur.execute(requete) @@ -397,7 +448,3 @@ for ip, id_p2p, nombre in fraudeurs : # 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() -