scripts/surveillance/analyse2.py
2015-01-27 17:52:00 +01:00

521 lines
16 KiB
Python
Executable file
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash /usr/scripts/python.sh
# -*- encoding: utf-8 -*-
import socket
import sys
import re
import psycopg2
import psycopg2.extras
import gestion.affichage as affichage
import lc_ldap.shortcuts
import argparse
import time
import gestion.config as config
import subprocess
if socket.gethostname() != 'odlyd':
print "Va sur odlyd"
sys.exit(1)
ldap = lc_ldap.shortcuts.lc_ldap_readonly()
encoding = "UTF-8"
def get_stats(args):
output = pretty_header(args) + "\n"
output += u"Période considérée : du %s au %s.\n" % (args.begin, args.end)
output += u"Attention, l'upload total et le download total sont calculés sur les %s plus grosses entrées." % (args.limit)
if not args.fichier:
print output.encode(encoding)
output = u""
else:
output += u"\n"
pgsql = psycopg2.connect(database='filtrage', user='crans')
pgsql.set_session(autocommit=True)
curseur = pgsql.cursor(cursor_factory=psycopg2.extras.DictCursor)
ip_requete = """
WITH
machines_sans_doublon
AS
(
SELECT DISTINCT ON(mac_addr)
*
FROM
machines
)
SELECT
SUM(upload) as tot_upload,
SUM(download) as tot_download,
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
FROM (
(
SELECT
sum(bytes) as upload,
'0' as download,
mac_src as mac,
ip_src as ip_crans,
ip_dst as ip_ext,
port_src as port_crans,
port_dst as port_ext
FROM
upload
INNER JOIN
machines_sans_doublon
ON
machines_sans_doublon.mac_addr = upload.mac_src
WHERE
ip_src=%(pg_value)s
AND NOT
ip_dst <<= inet%(ipv6_local)s
AND NOT
ip_dst <<= inet%(plage_ens)s
AND NOT
ip_dst <<= inet%(appt)s
AND NOT
ip_dst <<= inet%(plage_adm)s
AND NOT
ip_dst <<= inet%(plage_ipv6)s
AND
stamp_inserted >= %(begin)s
AND
stamp_inserted <= %(end)s
GROUP BY
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
)
UNION
(
SELECT
'0' as upload,
sum(bytes) as download,
mac_dst as mac,
ip_dst as ip_crans,
ip_src as ip_ext,
port_dst as port_crans,
port_src as port_ext
FROM
upload
INNER JOIN
machines_sans_doublon
ON
machines_sans_doublon.mac_addr = upload.mac_dst
WHERE
ip_dst=%(pg_value)s
AND NOT
ip_src <<= inet%(ipv6_local)s
AND NOT
ip_src <<= inet%(plage_ens)s
AND NOT
ip_src <<= inet%(appt)s
AND NOT
ip_src <<= inet%(plage_adm)s
AND NOT
ip_src <<= inet%(plage_ipv6)s
AND
stamp_inserted >= %(begin)s
AND
stamp_inserted <= %(end)s
GROUP BY
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
)
)
AS
famille
GROUP BY
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
"""
mac_requete = """
WITH
machines_sans_doublon
AS
(
SELECT DISTINCT ON(mac_addr)
*
FROM
machines
)
SELECT
SUM(upload) as tot_upload,
SUM(download) as tot_download,
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
FROM (
(
SELECT
sum(bytes) as upload,
'0' as download,
mac_src as mac,
ip_src as ip_crans,
ip_dst as ip_ext,
port_src as port_crans,
port_dst as port_ext
FROM
upload
INNER JOIN
machines_sans_doublon
ON
machines_sans_doublon.mac_addr = upload.mac_src
WHERE
mac_src=macaddr%(pg_value)s
AND NOT
ip_src <<= inet%(ipv6_local)s
AND NOT
ip_dst <<= inet%(ipv6_local)s
AND NOT
ip_dst <<= inet%(plage_ens)s
AND NOT
ip_dst <<= inet%(appt)s
AND NOT
ip_dst <<= inet%(plage_adm)s
AND NOT
ip_dst <<= inet%(plage_ipv6)s
AND
stamp_inserted >= %(begin)s
AND
stamp_inserted <= %(end)s
GROUP BY
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
)
UNION
(
SELECT
'0' as upload,
sum(bytes) as download,
mac_dst as mac,
ip_dst as ip_crans,
ip_src as ip_ext,
port_dst as port_crans,
port_src as port_ext
FROM
upload
INNER JOIN
machines_sans_doublon
ON
machines_sans_doublon.mac_addr = upload.mac_dst
WHERE
mac_dst=macaddr%(pg_value)s
AND NOT
ip_src <<= inet%(ipv6_local)s
AND NOT
ip_dst <<= inet%(ipv6_local)s
AND NOT
ip_src <<= inet%(plage_ens)s
AND NOT
ip_src <<= inet%(appt)s
AND NOT
ip_src <<= inet%(plage_adm)s
AND NOT
ip_src <<= inet%(plage_ipv6)s
AND
stamp_inserted >= %(begin)s
AND
stamp_inserted <= %(end)s
GROUP BY
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
)
)
AS
famille
GROUP BY
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
"""
adh_requete = """
WITH
machines_sans_doublon
AS
(
SELECT DISTINCT ON(mac_addr)
*
FROM
machines
)
SELECT
SUM(upload) as tot_upload,
SUM(download) as tot_download,
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
FROM (
(
SELECT
sum(bytes) as upload,
'0' as download,
mac_src as mac,
ip_src as ip_crans,
ip_dst as ip_ext,
port_src as port_crans,
port_dst as port_ext
FROM
upload
INNER JOIN
machines_sans_doublon
ON
machines_sans_doublon.mac_addr = upload.mac_src
WHERE
machines_sans_doublon.type=%(pg_filter)s
AND
machines_sans_doublon.id=%(pg_value)s
AND NOT
ip_src <<= inet%(ipv6_local)s
AND NOT
ip_dst <<= inet%(ipv6_local)s
AND NOT
ip_dst <<= inet%(plage_ens)s
AND NOT
ip_dst <<= inet%(appt)s
AND NOT
ip_dst <<= inet%(plage_adm)s
AND NOT
ip_dst <<= inet%(plage_ipv6)s
AND
stamp_inserted >= %(begin)s
AND
stamp_inserted <= %(end)s
GROUP BY
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
)
UNION
(
SELECT
'0' as upload,
sum(bytes) as download,
mac_dst as mac,
ip_dst as ip_crans,
ip_src as ip_ext,
port_dst as port_crans,
port_src as port_ext
FROM
upload
INNER JOIN
machines_sans_doublon
ON
machines_sans_doublon.mac_addr = upload.mac_dst
WHERE
machines_sans_doublon.type=%(pg_filter)s
AND
machines_sans_doublon.id=%(pg_value)s
AND NOT
ip_src <<= inet%(ipv6_local)s
AND NOT
ip_dst <<= inet%(ipv6_local)s
AND NOT
ip_src <<= inet%(plage_ens)s
AND NOT
ip_src <<= inet%(appt)s
AND NOT
ip_src <<= inet%(plage_adm)s
AND NOT
ip_src <<= inet%(plage_ipv6)s
AND
stamp_inserted >= %(begin)s
AND
stamp_inserted <= %(end)s
GROUP BY
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
)
)
AS
famille
GROUP BY
mac,
ip_crans,
ip_ext,
port_crans,
port_ext
"""
if args.download:
mac_requete += "ORDER BY tot_download DESC"
ip_requete += "ORDER BY tot_download DESC"
adh_requete += "ORDER BY tot_download DESC"
down_color = "rouge"
up_color = "vert"
else:
mac_requete += "ORDER BY tot_upload DESC"
ip_requete += "ORDER BY tot_upload DESC"
adh_requete += "ORDER BY tot_upload DESC"
down_color = "vert"
up_color = "rouge"
mac_requete += " LIMIT %s" % (args.limit)
ip_requete += " LIMIT %s" % (args.limit)
adh_requete += " LIMIT %s" % (args.limit)
fill_in_dict = { "begin" : args.begin,
"end" : args.end,
"plage_ens" : config.plage_ens,
"ipv6_local" : 'fe80::/8',
"plage_ipv6" : config.prefix['subnet'][0],
"appt" : config.NETs['personnel-ens'][0],
"plage_adm" : config.NETs['adm'][0],
}
if args.aid:
pg_filter = "adherent"
pg_value = int(args.aid)
fill_in_dict.update({'pg_filter' : pg_filter, 'pg_value' : pg_value})
curseur.execute(adh_requete, fill_in_dict)
elif args.cid:
pg_filter = "adherent"
pg_value = int(args.cid)
fill_in_dict.update({'pg_filter' : pg_filter, 'pg_value' : pg_value})
curseur.execute(adh_requete, fill_in_dict)
elif args.ip:
print "Attention, les statistiques par IP sont une mauvaise idée depuis que les extensions de vie privée IPv6 sont actives."
pg_value = args.ip
fill_in_dict.update({'pg_value' : pg_value})
curseur.execute(ip_requete, fill_in_dict)
elif args.mac:
pg_value = args.mac
fill_in_dict.update({'pg_value' : pg_value})
curseur.execute(mac_requete, fill_in_dict)
else:
pg_value = ldap.search(u"(host=%s)" % (args.data))[0]['macAddress'][0].value
if pg_value == '<automatique>':
print "MAC de la machine %s fixée à %s, problème. :o" % (args.data, pg_value)
fill_in_dict.update({'pg_value' : pg_value})
curseur.execute(mac_requete, fill_in_dict)
if args.debug:
print "Query executed :\n%s" % (curseur.query,)
stats = curseur.fetchall()
peuplade_ip = {}
def convert_ip(ip):
host = peuplade_ip.get(ip, [])
if host:
return host
else:
peuplade_ip[ip] = socket.getfqdn(ip)
return peuplade_ip[ip]
if args.dns:
convert = lambda ip:convert_ip(ip)
else:
convert = lambda ip:ip
if not args.fichier or args.couleur:
styles = (None, None, None, None, down_color, up_color)
else:
styles = None
entete = [u"Ip_crans", u"Ip_ext", u"Port_crans", u"Port_ext", unicode("Download (Mio)"), unicode("Upload (Mio)")]
longueur = [30, '*', 10, 8, 14, 14]
format = ('s', 's', 's', 's', 'o', 'o')
data = [[unicode(convert(ligne['ip_crans'])), unicode(convert(ligne['ip_ext'])), unicode(ligne['port_crans']), unicode(ligne['port_ext']), unicode(ligne["tot_download"]), unicode(ligne["tot_upload"])] for ligne in stats]
final_data = affichage.tableau(data, titre=entete, largeur=longueur, styles=styles, format=format, width=125)
output += u"Upload total : %s Mio, download total : %s Mio\n" % (sum([int(ligne["tot_upload"]) for ligne in stats])/1024/1024, sum([int(ligne["tot_download"]) for ligne in stats])/1024/1024)
output += final_data
if not args.fichier:
print output.encode(encoding)
else:
with open(args.fichier, 'w') as fichier:
fichier.write(output.encode(encoding))
def pretty_header(args):
if args.aid:
adh = ldap.search(u"(aid=%s)" % (args.aid))[0]
prenom = unicode(adh['prenom'][0])
nom = unicode(adh['nom'][0])
good_sentence = u"Statistiques d'upload de %s %s" % (prenom, nom)
elif args.cid:
club = ldap.search(u"(cid=%s)" % (args.cid))[0]
prenom = "club"
nom = unicode(club['nom'][0])
good_sentence = u"Statistiques d'upload du %s %s" % (prenom, nom)
elif args.ip:
machine = ldap.search(u"(|(ipHostNumber=%(val)s)(ip6HostNumber=%(val)s))" % {'val' : args.ip})[0]
nom = unicode(machine['host'][0])
good_sentence = u"Statistiques d'upload de la machine %s" % (nom)
elif args.mac:
machine = ldap.search(u"(macAddress=%s)" % (args.mac))[0]
nom = unicode(machine['host'][0])
good_sentence = u"Statistiques d'upload de la machine %s" % (nom)
else:
machine = ldap.search(u"(host=%s)" % (args.data))[0]
nom = unicode(machine['host'][0])
good_sentence = u"Statistiques d'upload de la machine %s" % (nom)
if not args.fichier or args.couleur:
return affichage.style(good_sentence, 'gras')
return good_sentence
def self_call(args):
args = ["/usr/scripts/surveillance/analyse2.py"] + args
subprocess.Popen(args, stdout=subprocess.PIPE)
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Script d'analyse d'échange de données entre un truc et un autre.", add_help=False)
meg = parser.add_mutually_exclusive_group()
meg.add_argument("-a", "--aid", help="Rechercher tout l'upload d'un adhérent. Il ne faut pas renseigner data si on utilise cette option.", action="store", type=int)
parser.add_argument("-b", "--begin", help="Date de début, dans un format \"AAAA/MM/JJ HH:MM:SS\"", type=str, action="store")
meg.add_argument("-c", "--cid", help="Rechercher tout l'upload d'un club. Il ne faut pas renseigner data si on utilise cette option.", action="store", type=int)
parser.add_argument("-C", "--couleur", help="Force la présence des couleurs et styles, y compris avec -f.", action="store_true")
parser.add_argument("-d", "--download", help="Trier par download décroissant", action="store_true")
parser.add_argument("-D", "--debug", help="Afficher des sorties de debug", action="store_true")
parser.add_argument("-e", "--end", help="Date de fin, dans un format \"AAAA/MM/JJTHH:MM:SS\"", type=str, action="store")
parser.add_argument("-f", "--fichier", help="Sauvegarder le résultat de la recherche dans le fichier FILE. Désactive les fonctions de style (couleur...)", type=str, action="store")
parser.add_argument("-h", "--help", help="Affiche cette aide et quitte.", action="store_true")
meg.add_argument("-i", "--ip", help="Filtrer sur l'ip fournie. Format IPv4 ou IPv6. Il ne faut pas renseigner data si on utilise cette option.", action="store", type=str)
parser.add_argument("-l", "--limit", help="Limiter le nombre de résultats.", action="store", type=int)
meg.add_argument("-m", "--mac", help="Filtrer sur la mac fournie. Format \"aa:bb:cc:dd:ee:ff\". Il ne faut pas renseigner data si on utilise cette option.", action="store", type=str)
parser.add_argument("-w", "--dns", help="Forcer la résolution dns des IP lorsque c'est possible. Attention, c'est gourmand en temps.", action="store_true")
meg.add_argument("data", help="La donnée suivant laquelle rechercher. Si pas d'autre option, doit être renseigné à un nom de machine.", type=str, nargs='?')
args = parser.parse_args()
now = time.time()
if args.help:
parser.print_help()
sys.exit(0)
if not (args.data or args.aid or args.cid or args.ip or args.mac):
print "Il faut fournir un nom de machine, ou autre."
parser.print_help()
sys.exit(7)
if not args.begin:
args.begin = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(now - 86400))
if not args.end:
args.end = time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(now))
if not args.download:
args.download = False
if not args.limit:
args.limit = 1000
get_stats(args)