scripts/surveillance/deconnexion.py
chove b3bf892ad6 on analyse que sur 23 heures 50, car dans le cas de Fred, tout tait dans la
meme  connection, compt hier dans la table dump et aujourd'hui dans la
table upload...
dans le firewall on ferme les connections ouvertes ?

darcs-hash:20051207201327-4ec08-4a0f213a7e2db5c7422513afa36e1f105f6b50a3.gz
2005-12-07 21:13:27 +01:00

386 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
###############
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().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_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()