517 lines
16 KiB
Python
Executable file
517 lines
16 KiB
Python
Executable file
#!/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
|
||
|
||
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)
|