#! /usr/bin/env python # -*- encoding: iso-8859-15 -*- """ Script d'envoi des statistiques des déconnections et du trafic de la journée à disconnect@ Copyright (C) Xavier Pessoles - Étienne Chové - Michel Blockelet Licence : GPLv2 """ ########################### # Import des commmandes : # ########################### import commands import sys, os from pyPgSQL import PgSQL sys.path.append('/usr/scripts/gestion') sys.path.append('/usr/scripts/surveillance') import config import smtplib import socket import time, random, md5 import netaddr from analyse import stats from affich_tools import tableau from iptools import AddrInNet from ldap_crans import AssociationCrans, crans_ldap CL = crans_ldap() # Fonction retournant l'hote quand c'est possible def gethostname(ip): # Poor man's IPv6 reverse DNS... if ":" in ip: # reconstruction de l'EUI48 à partir de l'EUI64... addr_bits = list(netaddr.IPAddress(ip).bits('')) addr_bits[0:64] = [] addr_bits[24:40] = [] addr_bits[6] = '0' addr_bits = ''.join(addr_bits) mac = ':'.join("%02x" % int(addr_bits[8*i:8*i+8], 2) for i in range(6)) res = CL.search("mac=%s" % mac) noms = sorted(r.nom() for r in res["machineFixe"] + res["machineWifi"] + res["machineCrans"] if r.nom().endswith('crans.org')) if noms: return str(noms[0]) else: return ip else: try: return socket.gethostbyaddr(ip)[0] except: return ip def ipv4or6(addr): if ':' in addr: return "IPv6" else: return "IPv4" # Liste des IP des serveurs serveurs_ips = [x.ip() for x in AssociationCrans().machines() if x.nom() not in [u'sila.crans.org', u'sable.crans.org']] ############################## # Ouverture des connexions : # ############################## pgsql = PgSQL.connect(host='/var/run/postgresql', database='filtrage', user='crans') curseur = pgsql.cursor() ########################### # Statistiques d'upload : # ########################### # Liste des uploads : ##################### requete = """SELECT ip_crans, sum(upload) AS somme, sum(download) FROM upload WHERE date > timestamp 'now' - interval '1 day' 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 somme DESC""" curseur.execute(requete) liste_upload = tableau(data = [ (l[1], l[2], ipv4or6(str(l[0])), gethostname(str(l[0]))) for l in curseur.fetchall() if int(l[1]) > 100*1024*1024 or ':' in l[0]], titre = ['upload', 'download', 'proto', 'machine'], largeur = [10, 10, 10, 40], format = ['o', 'o', 's', 's'], alignement = ['d', 'd', 'c', 'c']).encode('iso-8859-15') # Trafic exempté : ################## requete = """SELECT ip_crans, sum(upload) AS somme, sum(download) FROM upload WHERE date > timestamp 'now' - interval '1 day' AND 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 somme DESC""" curseur.execute(requete) liste_exemptes = tableau(data = [[l[1], l[2], gethostname(str(l[0]))] for l in curseur.fetchall()], titre = ['upload', 'download', 'machine'], largeur = [10, 10, 30], format = ['o', 'o', 's'], alignement = ['d', 'd', 'c']).encode('iso-8859-15') # Upload des serveurs : ####################### liste_serveurs = [] for IP in serveurs_ips: hostname = gethostname(IP) requete = """SELECT sum(upload), sum(download) FROM upload WHERE ip_crans='%s' AND date > timestamp 'now' - interval '1 day' """ % IP curseur.execute(requete) traffic = curseur.fetchone() # On ne compte pas le serveur si le trafic est petit if traffic == [None, None] or traffic[0] + traffic[1] < 10*1024*1024: continue liste_serveurs.append([traffic[0], traffic[1], hostname]) liste_serveurs = tableau(data = liste_serveurs, titre = ['upload','download','serveur'], largeur = [10, 10, 30], format = ['o','o','s'], alignement = ['d','d','c']).encode('iso-8859-15') # statistiques des gros uploads depuis les serveurs ################################################### gros_uploads_des_serveurs = stats(ip_crans=serveurs_ips, show=['ip_crans', 'ip_ext'], upload_mini=50, show_limit=100).encode('iso-8859-15') ############################ # Statistiques virus/p2p : # ############################ # IPs envoyant des paquets de protocole Ethernet inconnu : ######################################################### requete = """SELECT COUNT(*), ip_ext FROM upload WHERE id=-1 GROUP BY ip_ext""" curseur.execute(requete) liste_etherunk = tableau(data = [[l[0], gethostname(str(l[1]))] for l in curseur.fetchall()], titre = ['nombre','ip'], largeur = [10, 30], alignement = ['d','c']).encode('iso-8859-15') # statistiques des gros uploads depuis les serveurs ################################################### gros_uploads_des_serveurs = stats(ip_crans=serveurs_ips, show=['ip_crans', 'ip_ext'], upload_mini=50, show_limit=100).encode('iso-8859-15') # Machines actuellement déconnectées : ###################################### requete = "SELECT DISTINCT ip_crans FROM avertis_virus" curseur.execute(requete) infections = [ x[0] for x in curseur.fetchall() ] liste_virus = [] for IP in infections: hostname = gethostname(IP) liste_virus.append(["%s" % (str(hostname))]) liste_virus = tableau(liste_virus, titre=['machine'], largeur=[30]).encode('iso-8859-15') # Machines ayant fait des attaques virus dans la journée : ########################################################## requete = """SELECT * FROM (SELECT ip_src,count(ip_src) as compteur FROM virus WHERE date > timestamp 'now' - interval '1 day' GROUP BY ip_src ORDER BY compteur DESC) AS tous WHERE tous.compteur>'%s' LIMIT 30""" % config.virus.virus curseur.execute(requete) liste_virus2 = [] for IP, compteur in curseur.fetchall(): hostname = gethostname(IP) liste_virus2.append([hostname, compteur]) liste_virus2 = tableau(data = liste_virus2, titre = ['machine', 'nombre'], largeur = [30, 12], alignement = ['c', 'd']).encode('iso-8859-15') # Machines ayant fait de attaques flood dans la journée : ######################################################### requete = """SELECT * FROM (SELECT ip_src,count(ip_src) as compteur FROM flood WHERE date > timestamp 'now' - interval '1 day' GROUP BY ip_src ORDER BY compteur DESC) AS tous WHERE tous.compteur>'%s' LIMIT 30""" % config.virus.flood curseur.execute(requete) liste_virus3 = [] for IP, compteur in curseur.fetchall(): hostname = gethostname(IP) liste_virus3.append([hostname, compteur]) liste_virus3 = tableau(data = liste_virus3, titre = ['machine', 'nombre'], largeur = [30, 12], alignement = ['c', 'd']).encode('iso-8859-15') # Machines ayant utilisé des protocoles P2P dans la journée : ############################################################# requete = """SELECT ip_src, nom, compteur, max(date) FROM (SELECT ip_src,nom,count(ip_src) as compteur FROM p2p INNER JOIN protocole_p2p ON p2p.id_p2p=protocole_p2p.id_p2p WHERE p2p.date > timestamp 'now' - interval '1 day' GROUP BY ip_src,nom) AS tous LEFT JOIN (SELECT * FROM avertis_p2p WHERE date > timestamp 'now' - interval '1 day') AS avertis ON ip_src=ip_crans WHERE tous.compteur>5 GROUP BY ip_src, nom, compteur ORDER BY 3 DESC""" curseur.execute(requete) liste_p2p = [] for IP, protocole, compteur, blackliste in curseur.fetchall(): hostname = gethostname(IP) # Le champ blackliste contient la date du blacklistage si il a eu lieu if blackliste : liste_p2p.append(['*%s*' % hostname, '*%s*' % protocole, '*%d*' % compteur, '*%d*' % config.p2p.limite[protocole]]) else: liste_p2p.append([hostname, protocole, compteur, config.p2p.limite[protocole]]) liste_p2p = tableau(data = liste_p2p, titre = ['machine', 'protocole', 'nombre', 'limite'], largeur = [32, 14, 10, 8], alignement = ['c', 'c', 'd', 'd']).encode('iso-8859-15') ############# # Message : # ############# expediteur = "disconnect@crans.org" destinataire = "disconnect@crans.org" message = """From: %(From)s To: %(To)s Subject: Statistiques des =?iso-8859-1?Q?derni=E8res?= 24h Message-Id: <%(uuid)s1@crans.org> Content-Type: text/plain; charset="iso-8859-15" *Gros uploads des serveurs* (sila et sable sont exemptés totalement) %(gros_uploads_des_serveurs)s *Statistiques de trafic des serveurs* %(liste_serveurs)s *IPs envoyant des paquets de protocole Ethernet inconnu* %(liste_etherunk)s *Machines actuellement déconnectées pour virus* %(liste_virus)s *Machines ayant commis des attaques virales dans la journée* %(liste_virus2)s *Machines ayant commis des attaques virales de type flood dans la journée* %(liste_virus3)s *Machines ayant utilisé des protocoles P2P durant la journée* %(liste_p2p)s *Statistiques de trafic des adhérents* (tout le trafic) %(liste_upload)s *Statistiques de trafic des adhérents exemptés* (juste le trafic exempté) %(liste_exemptes)s -- statistiques.py """ uuid = md5.md5(str(long(time.time() * 1000)) + str(long(random.random()*100000000000000000L))).hexdigest() corps = message % { 'From': expediteur, 'To': destinataire, 'uuid': uuid, 'gros_uploads_des_serveurs': gros_uploads_des_serveurs, 'liste_etherunk': liste_etherunk, 'liste_serveurs': liste_serveurs, 'liste_upload': liste_upload, 'liste_p2p': liste_p2p, 'liste_virus': liste_virus, 'liste_virus2': liste_virus2, 'liste_virus3': liste_virus3, 'liste_exemptes': liste_exemptes } mail = smtplib.SMTP('localhost') mailaddr = os.getenv('CRANS_EMAIL', 'disconnect@crans.org') mail.sendmail(mailaddr, mailaddr, corps)