#! /usr/bin/env python
# -*- encoding: utf-8 -*-

"""
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
import psycopg2
sys.path.append('/usr/scripts/gestion')
sys.path.append('/usr/scripts/surveillance')
import config.virus
import smtplib
import socket
import time, random, hashlib
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()

def ipv4or6(addr):
    if ':' in addr:
        return "IPv6"
    else:
        return "IPv4"

# Liste des IP des serveurs
ips_serveurs = []
ips_proxys = []
for m in AssociationCrans().machines():
    if m.nom() in [u'charybde.crans.org', u'sable.crans.org']:
        ips_proxys.extend([m.ip(), str(m.ipv6())])
    else:
        ips_serveurs.extend([m.ip(), str(m.ipv6())])

##############################
# Ouverture des connexions : #
##############################

pgsql = psycopg2.connect(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
)

UNION

(SELECT 
    ip_crans, sum(upload) AS somme, sum(download) 
FROM
    (
        SELECT DISTINCT * FROM 
        (
            SELECT 
                upload6.date, mac_ip.mac AS ip_crans, upload6.ip_ext, upload6.id, upload6.port_crans, upload6.port_ext, upload6.download, upload6.upload
            FROM mac_ip,upload6 
            WHERE 
                upload6.ip_crans = mac_ip.ip 
                AND upload6.date > mac_ip.date 
                AND upload6.date - interval '1 day' < mac_ip.date 
                AND upload6.date > timestamp 'now' - interval '1 day'
                AND upload6.date < 'now'
                AND NOT EXISTS
                (
                    SELECT 1
                    FROM exemptes
                    WHERE upload6.ip_crans <<= exemptes.ip_crans
                    AND upload6.ip_ext <<= exemptes.ip_dest
                )
        ) AS upload
    ) AS upload
GROUP BY
    ip_crans
)
ORDER BY somme DESC"""
curseur.execute(requete)
data_upload = curseur.fetchall()

liste_upload = tableau(data = [ (l[1], l[2], ipv4or6(str(l[0])), socket.getfqdn(str(l[0])))
                                for l in data_upload
                                if int(l[1]) > 100*1024*1024
                                and l[0] not in (ips_serveurs + ips_proxys)],
                       titre = ['upload', 'download', 'proto', 'machine'],
                       largeur = [10, 10, 10, 40],
                       format = ['o', 'o', 's', 's'],
                       alignement = ['d', 'd', 'c', 'c']).encode('utf-8')

# 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
)
UNION
(SELECT ip_crans, sum(upload) AS somme, sum(download)
FROM upload6
WHERE
  date > timestamp 'now' - interval '1 day'
  AND EXISTS (
    SELECT 1
    FROM exemptes
    WHERE
      upload6.ip_crans = exemptes.ip_crans
      -- AND upload6.ip_ext <<= exemptes.ip_dest
  )
GROUP BY ip_crans
)
ORDER BY somme DESC"""
curseur.execute(requete)
liste_exemptes = tableau(data = [[l[1], l[2], ipv4or6(str(l[0])), socket.getfqdn(str(l[0]))]
                            for l in curseur.fetchall()],
                         titre = ['upload', 'download', 'proto', 'machine'],
                         largeur = [10, 10, 10, 30],
                         format = ['o', 'o', 's', 's'],
                         alignement = ['d', 'd', 'c', 'c']).encode('utf-8')

# Upload des serveurs :
#######################
liste_serveurs = []
for l in data_upload:
    if l[0] in (ips_serveurs + ips_proxys) and l[1] + l[2] > 10*1024*1024:
        liste_serveurs.append([l[1], l[2], ipv4or6(str(l[0])), socket.getfqdn(l[0])])
#    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

liste_serveurs = tableau(data = liste_serveurs,
                         titre = ['upload', 'download', 'proto', 'serveur'],
                         largeur = [10, 10, 10, 30],
                         format = ['o', 'o', 's', 's'],
                         alignement = ['d', 'd', 'c', 'c']).encode('utf-8')


# statistiques des gros uploads depuis les serveurs
###################################################
# Liste des IP des serveurs
gros_uploads_des_serveurs = stats(ip_crans=ips_serveurs,
    show=['ip_crans', 'ip_ext'], upload_mini=50,
    show_limit=100).encode('utf-8')

############################
# 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)

UNION

(SELECT COUNT(*), ip_ext
FROM upload6
WHERE
  id=-1
GROUP BY ip_ext
)"""
curseur.execute(requete)

liste_etherunk = tableau(data = [[l[0], socket.getfqdn(str(l[1]))]
                            for l in curseur.fetchall()],
                         titre = ['nombre','ip'],
                         largeur = [10, 30],
                         alignement = ['d','c']).encode('utf-8')


# 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 = socket.getfqdn(IP)
    liste_virus.append(["%s" % (str(hostname))])

liste_virus = tableau(liste_virus,
    titre=['machine'], largeur=[30]).encode('utf-8')

# 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 = socket.getfqdn(IP)
    liste_virus2.append([hostname, compteur])
liste_virus2 = tableau(data = liste_virus2,
                       titre = ['machine', 'nombre'],
                       largeur = [30, 12],
                       alignement = ['c', 'd']).encode('utf-8')


# 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 = socket.getfqdn(IP)
    liste_virus3.append([hostname, compteur])
liste_virus3 = tableau(data = liste_virus3,
                       titre = ['machine', 'nombre'],
                       largeur = [30, 12],
                       alignement = ['c', 'd']).encode('utf-8')


#############
# Message : #
#############

expediteur = "disconnect@crans.org"
destinataire = "disconnect@crans.org"
message = """From: %(From)s
To: %(To)s
Subject: Statistiques des =?utf-8?q?derni=C3=A8res?= 24h
X-Mailer: /usr/scripts/surveillance/statistiques.py
Message-Id: <%(uuid)s1@crans.org>
Content-Type: text/plain; charset="utf-8"

*Gros uploads des serveurs* (charybde 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

*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 = hashlib.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_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)
