nouvelle gnration :
- comptage de l'upload par adhrent/club* - simplifications de certaines boucles - envoie d'un mail disconnect et gnration du ps en cas de rcidive pour le moment, ce script n'est pas en production, il est en cours d'essai et est lanc par un de mes cron (c'est pour ca que j'avais besoin des droits pgsql) je le met ici au cas ou xabi des trucs corriger dedans darcs-hash:20051214224552-4ec08-869316b2b9c8855dbf5ffdd15ad689682217b1c1.gz
This commit is contained in:
parent
9b43a65b02
commit
cd8ee4dbac
1 changed files with 470 additions and 0 deletions
470
surveillance/deconnexion-ng.py
Executable file
470
surveillance/deconnexion-ng.py
Executable file
|
@ -0,0 +1,470 @@
|
|||
#! /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'")
|
||||
|
||||
################################################################################
|
||||
# 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()
|
Loading…
Add table
Add a link
Reference in a new issue