#! /usr/bin/env python # -*- coding: iso8859-15 -*- import socket import sys, re import psycopg2 sys.path.append('/usr/scripts/gestion/') from affich_tools import tableau def stats(ip_crans=[], ip_ext=[], show=['ip_crans', 'ip_ext', 'port_crans', 'port_ext'], upload_mini=0, show_limit=10, begin_time=24, end_time=0, show_download=False,resolve_dns=True): """ Retourne une chaine de caratères formatée avec le tableau de statistiques d'upload de l'ip fourni ip_crans : ips des machines Cr@ns chaine de caratère si il a qu'une machine liste si il y a plusieurs machines ip_ext : ips des machines extérieures chaine de caratère si il a qu'une machine liste si il y a plusieurs machines show : liste des champs à afficher parmi : ip_crans, ip_ext, port_crans, port_ext upload_mini : n'affiche que les lignes avec plus d'upload que la valeur donnée show_limit : nombre max de lignes à afficher begin_time : date de départ d'analyse (en heure avant maintenant) end_time : date de fin d'analyse (en heure avant maintenant) show_download: trie par rapport au download plutôt que l'upload """ if type(ip_crans) == str: ip_crans = [ip_crans] if type(ip_ext) == str: ip_ext = [ip_ext] # variables pour la requete et l'affichage ########################################## select = [] largeur = [] titre = [] format = [] alignement = [] if 'ip_crans' in show and len(ip_crans)!=1: select.append('ip_crans') largeur.append(13) titre.append('machine crans') format.append('s') alignement.append('c') if 'ip_ext' in show : select.append('ip_ext') largeur.append('*') titre.append('machine ext') format.append('s') alignement.append('c') if 'port_ext' in show : select.append('port_ext') largeur.append(10) titre.append('port ext') format.append('s') alignement.append('d') if 'port_crans' in show : select.append('port_crans') largeur.append(10) titre.append('port crans') format.append('s') alignement.append('d') select += ['sum(download) as download','sum(upload) as upload'] largeur += [10,10] format += ['o','o'] alignement += ['d','d'] if show_download: sort_by = 'download' titre += ['*download*','upload'] else: sort_by = 'upload' titre += ['download','*upload*'] # requete dans la base ###################### ip_crans = ' OR '.join([ "ip_crans='%s'"%x for x in ip_crans ]) if not ip_crans: ip_crans='true' ip_ext = ' OR '.join([ "ip_ext='%s'"%x for x in ip_ext ]) if not ip_ext: ip_ext='true' requete = """ SELECT * FROM ( ( SELECT %(select)s FROM upload WHERE (%(ip_crans)s) AND (%(ip_ext)s) AND (date > timestamp 'now' - interval '%(begin_time)d hours') AND (date < timestamp 'now' - interval '%(end_time)d hours') GROUP BY %(show)s ) UNION ( SELECT %(select)s FROM upload6 WHERE (%(ip_crans)s) AND (%(ip_ext)s) AND (date > timestamp 'now' - interval '%(begin_time)d hours') AND (date < timestamp 'now' - interval '%(end_time)d hours') GROUP BY %(show)s ) ) AS resultat_intemediaire WHERE %(sort_by)s >= '%(sort_mini)d' ORDER BY %(sort_by)s DESC LIMIT %(show_limit)d;""" % { 'select': ','.join(select), 'ip_crans': ip_crans, 'ip_ext': ip_ext, 'begin_time': begin_time, 'end_time': end_time, 'show': ','.join(show), 'sort_by': sort_by, 'sort_mini': upload_mini*1024*1024, 'show_limit': show_limit } pgsql = psycopg2.connect(database="filtrage", user="crans") curseur = pgsql.cursor() curseur.execute(requete) results = curseur.fetchall() # on transforme tout en chaine results = [ [ str(x) for x in line ] for line in results ] # on modifie les ip en noms de machine et les ports en noms def nom_de_machine (ip) : if not resolve_dns: return ip try: return socket.gethostbyaddr(ip)[0] except: return ip port_to_service = {} for service,port in [re.split('[ \t]+', x.strip().replace('/tcp','').replace('/udp',''))[:2] for x in open('/etc/services').readlines() if x[0] not in ['\n','#']]: port_to_service[port]=service for champ in select: if champ == 'ip_ext': col = select.index(champ) results = [x[:col] + [nom_de_machine(x[col])] + x[col+1:] for x in results] elif champ == 'ip_crans': col = select.index(champ) results = [x[:col] + [nom_de_machine(x[col]).split('.')[0]] + x[col+1:] for x in results] elif 'port' in champ: col = select.index(champ) results = [x[:col] + [port_to_service.get(x[col],x[col])] + x[col+1:] for x in results] return tableau(results, titre=titre, largeur=largeur, alignement=alignement, format=format) if __name__ == '__main__' : help = """Statistiques d'upload d'une machine du crans usage: analyse.py [option]... Option fait partie des options suivantes : -d ou --show-download trier par download plutôt que par upload --ip-crans [ip] ip de la machine crans --ip-ext [ip] ip de la machine extérieure --show [champ] champs à afficher (parmi ip_crans, ip_ext, port_crans, port_ext) --upload-mini [n Mo] upload mini des lignes à afficher --show-limit [n] nombre maximum de lignes à afficher --begin-time [n heures] heure de départ de l'analyse (en heures depuis maintenant) --end-time [n heures] heure de fin de l'analyse (en heures depuis maintenant) -n Ne pas résoudre les adresses ip Exemple : sudo /usr/scripts/surveillance/analyse.py bilou.crans.org""" # import des modules import getopt # aide ###### if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv)==1: print help sys.exit(0) # parsage des arguments ####################### try : opts, args = getopt.getopt(sys.argv[1:], 'dn', ['show-download', 'ip-crans=', 'ip-ext=', 'show=', 'upload-mini=', 'begin-time=', 'end-time=', 'show-limit=']) except getopt.GetoptError,message : print help sys.exit(4) # affichage des stats de download ################################# show_download = False for key,value in opts: if key == '-d' or key == '--show-download': show_download = True if show_download: print "Statistiques de download" else: print "Statistiques d'upload" # recherche de la machine crans ############################### ip_crans = [] ip_crans_nom = [] for key,value in opts : if key == '--ip-crans' : try : ip_crans.append(socket.gethostbyaddr(value)[2][0]) ip_crans_nom.append(socket.gethostbyaddr(value)[0]) except socket.gaierror : print "Hôte %s inconnu" % value sys.exit(5) except socket.herror: print "Hôte %s inconnu" % value ip_crans.append(value) if len(ip_crans_nom)==1: print ' depuis la machine %s' % ip_crans_nom[0] elif ip_crans_nom: print ' depuis les machines %s' % ', '.join(ip_crans_nom) # recherche de la machine ext ############################# ip_ext = [] ip_ext_nom = [] for key,value in opts : if key == '--ip-ext' : # recherche de l'ip de la machine extérieur try: ip_ext.append(socket.gethostbyaddr(value)[2][0]) except socket.herror: ip_ext.append(value) except socket.gaierror : print "Hôte %s inconnu" % value sys.exit(5) # recherche du nom d'hote try : ip_ext_nom.append(socket.gethostbyaddr(value)[0]) except socket.herror: ip_ext_nom.append(ip_ext[-1]) except socket.gaierror : ip_ext_nom.append(ip_ext[-1]) if len(ip_ext_nom)==1: print ' vers la machine extérieure %s' % ip_ext_nom[0] elif ip_ext_nom: print ' vers les machines extérieures %s' % ', '.join(ip_ext_nom) # limite d'affichage #################### show = [x[1] for x in opts if x[0] == '--show' and x[1] in ['ip_crans', 'ip_ext', 'port_crans', 'port_ext']] if not show : show = ['ip_crans', 'ip_ext', 'port_crans', 'port_ext'] else : print ' affichage de %s' % ', '.join(show) # upload mini à afficher ######################## upload_mini = 0 for key,value in opts : if key == '--upload-mini' : try : upload_mini = int(value) except : print 'L\'upload mini doit être un entier (en MO)' sys.exit(4) break if upload_mini: print ' pour les traffics supérieurs à %d Mo' % upload_mini # nombre limite d'enregristrements ################################## limit = 10 for key,value in opts : if key == '--show-limit' : try : limit = int(value) print ' affichage des %d premiers résultats' % limit except : print 'Le nombre limite n\'est pas un entier' sys.exit(3) break # Résolution dns ################ resolve_dns = '-n' not in [key for (key,value) in opts] # début de l'analyse #################### begin_time = 24 for key,value in opts : if key == '--begin-time' : try : begin_time = int(value) except : print 'Le nombre d\'heures doit être un entier' sys.exit(4) break # fin de l'analyse ################## end_time = 0 for key,value in opts : if key == '--end-time' : try : end_time = int(value) except : print 'Le nombre d\'heures doit être un entier' sys.exit(4) break if begin_time != 24 or end_time: print (' entre il y a %d heure(s) et il y a %d heure(s)' % (begin_time,end_time)) # affichage du résultat ####################### print stats(ip_crans, ip_ext, show, upload_mini, limit, begin_time, end_time, show_download,resolve_dns)