scripts/surveillance/deconnexion.py
chove e8eaa290a2 petit bug pour les clubs, on ne pouvait pas envoyer de mail, maintenant le
mail est envoy au responsable du club

darcs-hash:20051219125630-4ec08-ce6699695c74503456cb284cd2acfa6f1ada351d.gz
2005-12-19 13:56:30 +01:00

403 lines
14 KiB
Python
Executable file

#! /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 commmandes : #
###########################
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 *
# 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 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'}
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()
# 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 = [ x[0] for x in curseur.fetchall() ]
# Avertis soft
requete = "SELECT ip_crans FROM avertis_upload where soft='1' "
curseur.execute(requete)
avertiss = [ x[0] for x in curseur.fetchall() ]
# Vérification :
################
for IP, elupload in uploadeurs:
# On regarde si c'est de l'upload hard
if elupload >= upload.hard :
# L'adhérent a t il été averti ?
################################
if str(IP) in avertish:
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:
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
###############
# 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])
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)
# 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 str(IP) in avertiss:
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
continue
machine=machine[0]
hostname = machine.nom()
proprio = machine.proprietaire().email()
# On envoie un mail à l'adhérent
################################
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_soft:
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
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)
###############################################
# Détection de l'existence de virus ou de P2P #
###############################################
# 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()
# Recuperation des infectes pour ne pas les reblacklister
requete = "SELECT ip_crans FROM avertis_virus"
curseur.execute(requete)
infectes = curseur.fetchall()
for ip, nombre in veroles:
# si le type dépasse le seuil, on le blacklist
if nombre < virus.virus or [ip] in infectes :
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)
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 :
proprio.blacklist(( index[0] , ['now','-','virus',hostname] ))
proprio.save()
else :
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 %s and date > timestamp 'now' - interval '1 hour' GROUP BY ip_src" % ip_src_in_crans
curseur.execute(requete)
veroles = curseur.fetchall()
# Recuperation des infectes pour ne pas les reblacklister
requete = "SELECT ip_crans FROM avertis_virus"
curseur.execute(requete)
infectes = curseur.fetchall()
for ip, nombre in veroles:
# si le type dépasse le seuil, on le blacklist
if nombre < virus.flood or [ip] in infectes :
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)
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 :
proprio.blacklist(( index[0] , ['now','-','virus',hostname] ))
proprio.save()
else :
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]]
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 :
##################
# 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()
# fermeture des connections
mail.quit()