[scripts] Going to utf-8

This commit is contained in:
Pierre-Elliott Bécue 2013-05-04 19:19:36 +02:00
parent c4a19a88ed
commit a1bf0a4547
54 changed files with 676 additions and 573 deletions

View file

@ -1,4 +1,4 @@
#!/bin/sh
#execution avec des droits suffisants
LANG=fr_FR@euro sudo -u 'arpwatch' /usr/scripts/surveillance/arpwatch_sendmail.py $*
LANG=fr_FR.UTF-8 sudo -u 'arpwatch' /usr/scripts/surveillance/arpwatch_sendmail.py $*

View file

@ -1,49 +1,149 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# Ajout d'un whos et d'un tracage aux mails d'arpwatch
# Auteurs : Stéphane Glondu, Cyril Cohen
# Licence : GPLv2
import sys, os, re, smtplib
from commands import getstatusoutput
sys.path.append('/usr/scripts/gestion/tools')
from locate_mac import trace_machine, format_mac, info_machine
find_mac = re.compile(r'[0-9A-Fa-f]{1,2}(?::[0-9A-Fa-f]{1,2}){5}')
# -*- encoding: utf-8 -*-
def get_machine(unformated_mac):
mac = format_mac(unformated_mac)
return u"\n" + info_machine(mac) + u"\n" + trace_machine(mac)
###########################
# Import des commmandes : #
###########################
import commands
import os
# import pg # Import des commandes de postgres
import sys
sys.path.append('/usr/scripts/gestion')
import iptools
import psycopg2
import re
sys.path.append('/usr/script/surveillance')
import strptime
# Définition de constantes :
############################
reseau = ["138.231.136.0/21", "138.231.148.0/22"]
# Ouverture de la base de données :
###################################
pgsql = psycopg2.connect(host='pgsql.adm.crans.org', database='filtrage', user='crans')
# Ancienne méthode pour faire de l'autocommit.
# Sous wheezy, il faudra remplacer par pgsql.set_session(autocommit=True) !!!
pgsql.set_isolation_level(0)
curseur = pgsql.cursor()
if __name__ == "__main__":
texte = sys.stdin.read() #.decode('ISO-8859-15')
textes = texte.splitlines(True)
i = textes.index(u'\n')
textes[i-1:i-1] = [
u'MIME-Version: 1.0\n',
u'Content-Type: text/plain; charset=UTF-8\n',
u'Content-Transfer-Encoding: 8bit\n',
]
###########################################
# Récupération des tables de protocoles : #
###########################################
# On récupère les destinataires dans les arguments (très ad hoc)
recipients = sys.argv[2].split(',')
# On complète le message
try:
macs = find_mac.findall(texte)
for mac in macs:
textes.append(get_machine(mac))
except:
# En cas d'exception, on envoie le traceback
import traceback
textes.append(u'\n')
textes.append(u''.join(traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback)))
textes.append('\n-- \narpwatch_sendmail.py\n')
requete = "SELECT nom,id_p2p from protocole_p2p"
curseur.execute(requete)
curseur.fetchall
tableau = curseur.fetchall()
protocole_p2p = {}
for cellule in tableau:
protocole_p2p[cellule[0]]=cellule[1]
smtp = smtplib.SMTP()
smtp.connect()
smtp.sendmail("arpwatch@crans.org", recipients, u''.join(textes).encode('UTF-8'))
smtp.quit()
requete = "SELECT nom,id from protocole"
curseur.execute(requete)
curseur.fetchall
tableau = curseur.fetchall()
protocole = {}
for cellule in tableau:
protocole[cellule[0]]=cellule[1]
##############################################################
# Parser ler log du firewall: /var/log/firewall/filtre.log : #
##############################################################
# Définition des motifs des comparaisons :
##########################################
motif_p2p = re.compile("^(.*) komaz .* IPP2P=([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*")
motif_virus = re.compile("^(.*) komaz .* Virus:([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*")
motif_flood = re.compile("^(.*) komaz .* Flood:([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*")
# On récupère en continu les log du firewall:
#############################################
filtre = os.popen("tail -F /var/log/firewall/filtre.log 2> /dev/null")
# On matche les log du firewall avec les motifs :
#################################################
for log in filtre:
resultat_p2p = motif_p2p.match(log)
resultat_virus = motif_virus.match(log)
resultat_flood = motif_flood.match(log)
if resultat_p2p :
try:
ip_src = resultat_p2p.group(3)
verif = iptools.AddrInNets (ip_src,reseau)
except ValueError:
continue #IP malformee
if verif :
try:
date = resultat_p2p.group(1)
id_p2p = int(protocole_p2p[resultat_p2p.group(2)])
ip_src = resultat_p2p.group(3)
ip_dest = resultat_p2p.group(4)
proto = int(protocole[resultat_p2p.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_p2p.group(6))
port_dest = int(resultat_p2p.group(7))
date=strptime.syslog2pgsql(date)
except ValueError, KeyError:
continue #mal parse
# On remplit la base :
######################
requete = "INSERT INTO p2p (date,ip_src,ip_dest,id_p2p,id,port_src,port_dest) VALUES ('%s','%s','%s',%d,%d,%d,%d)" % (date,ip_src,ip_dest,id_p2p,proto,port_src,port_dest)
curseur.execute(requete)
# On teste si le log contient des virus
########################################
elif resultat_virus :
try:
ip_src = resultat_virus.group(3)
verif = iptools.AddrInNets (ip_src,reseau)
except ValueError:
continue
if verif :
try:
date = resultat_virus.group(1)
ip_src = resultat_virus.group(3)
ip_dest = resultat_virus.group(4)
proto = int(protocole[resultat_virus.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_virus.group(6))
port_dest = int(resultat_virus.group(7))
# On remplit la base :
######################
date=strptime.syslog2pgsql(date)
except ValueError, KeyError:
continue
requete = "INSERT INTO virus (date,ip_src,ip_dest,id,port_src,port_dest) VALUES ('%s','%s','%s',%d,%d,%d)" % (date,ip_src,ip_dest,proto,port_src,port_dest)
curseur.execute(requete)
elif resultat_flood :
try:
ip_src = resultat_flood.group(3)
verif = iptools.AddrInNets (ip_src,reseau)
except ValueError:
continue
if verif :
try:
date = resultat_flood.group(1)
ip_src = resultat_flood.group(3)
ip_dest = resultat_flood.group(4)
proto = int(protocole[resultat_flood.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_flood.group(6))
port_dest = int(resultat_flood.group(7))
# On remplit la base :
######################
date=strptime.syslog2pgsql(date)
except ValueError, KeyError:
continue
requete = "INSERT INTO flood (date,ip_src,ip_dest,id,port_src,port_dest) VALUES ('%s','%s','%s',%d,%d,%d)" % (date,ip_src,ip_dest,proto,port_src,port_dest)
curseur.execute(requete)

View file

@ -1,9 +1,9 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
"""DESCRIPTION
Ce script repère les comptes inactifs en parsant les logs de dernière
connexion de sshd et dovecot, et en lisant et mettant à jour les champs
Ce script repère les comptes inactifs en parsant les logs de dernière
connexion de sshd et dovecot, et en lisant et mettant à jour les champs
derniereConnexion dans la base LDAP.
UTILISATION
@ -12,7 +12,7 @@ UTILISATION
ACTIONS POSSIBLES
%(acts)s"""
# Copyright (C) 2006 Stéphane Glondu
# Copyright (C) 2006 Stéphane Glondu
# Licence : GPLv2
@ -41,8 +41,8 @@ openlog('comptes_inactifs')
def nb_mails_non_lus(login):
"""
Renvoie le nombre de mails non lus de login, ou None si impossible à
déterminer.
Renvoie le nombre de mails non lus de login, ou None si impossible à
déterminer.
"""
try:
maildir = '/var/mail/%s/new' % login
@ -56,8 +56,8 @@ def nb_mails_non_lus(login):
class ComptesInactifs(object):
# liste d'expressions régulières qui seront testées sur les lignes de log
# le premier groupe doit correspondre à la date, le second au login
# liste d'expressions régulières qui seront testées sur les lignes de log
# le premier groupe doit correspondre à la date, le second au login
re = [re.compile(r'^(\w+\s+\d+\s+\d+:\d+:\d+).*(?:'
r'dovecot.*Login: user=<|'
r'sshd.*Accepted.*for '
@ -70,7 +70,7 @@ class ComptesInactifs(object):
self.dic = {}
def search(self, query, mode=''):
""" CransLdap.search allégé """
""" CransLdap.search allégé """
query = '(&(objectClass=cransAccount)(objectClass=adherent)(%s))' % query
result = db.conn.search_s(db.base_dn, db.scope['adherent'], query)
result = [db.make(x, mode) for x in result]
@ -79,13 +79,13 @@ class ComptesInactifs(object):
def commit_to_ldap(self):
"""
Sauvegarde du dico dans la base LDAP.
Renvoie le nombre d'entrées mises à jour.
Renvoie le nombre d'entrées mises à jour.
"""
total = 0
for (login, timestamp) in self.dic.items():
a = self.search('uid=%s' % login, 'w')
if not a:
# Probablement un adhérent récemment parti
# Probablement un adhérent récemment parti
continue
a = a[0]
if a._modifiable == 'w':
@ -93,7 +93,7 @@ class ComptesInactifs(object):
if a.modifs: total += 1
a.save()
else:
# on loggue on espérant que les logs seront réinjectés
# on loggue on espérant que les logs seront réinjectés
# plus tard
syslog("LDAP(lock): derniereConnexion=<%s>, login=<%s>" %
(strftime("%b %d %H:%M:%S", localtime(timestamp)), login))
@ -101,7 +101,7 @@ class ComptesInactifs(object):
def update(self, login, timestamp):
"""
Met à jour l'entrée correspondant au login donné.
Met à jour l'entrée correspondant au login donné.
"""
dic = self.dic
timestamp = int(timestamp)
@ -110,8 +110,8 @@ class ComptesInactifs(object):
def update_from_syslog(self, loglines):
"""
Met à jour le dico avec les lignes de syslog données.
Renvoie le nombre de lignes traitées.
Met à jour le dico avec les lignes de syslog données.
Renvoie le nombre de lignes traitées.
"""
annee = localtime(time())[0]
now = time() + 600
@ -124,8 +124,8 @@ class ComptesInactifs(object):
date = list(strptime(m.group(1), "%b %d %H:%M:%S"))
date[0] = annee
t = mktime(date)
# les lignes de syslog n'indiquent pas l'année
# on suppose qu'une date dans le futur est en fait l'année dernière
# les lignes de syslog n'indiquent pas l'année
# on suppose qu'une date dans le futur est en fait l'année dernière
if t > now:
date[0] = annee - 1
t = mktime(date)
@ -135,21 +135,21 @@ class ComptesInactifs(object):
def do_log(self):
"""
Lit des lignes de log sur l'entrée std et met à jour la base LDAP.
Lit des lignes de log sur l'entrée std et met à jour la base LDAP.
"""
parsed_lines = self.update_from_syslog(sys.stdin)
updated_entries = self.commit_to_ldap()
syslog("%(parsed_lines)s ligne(s) traitée(s)" % locals())
syslog("%(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP" % locals())
syslog("%(parsed_lines)s ligne(s) traitée(s)" % locals())
syslog("%(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP" % locals())
if parsed_lines == 0 or updated_entries == 0:
sys.stderr.write("""Erreur lors de la mise à jour de la base LDAP :
%(parsed_lines)s ligne(s) traitée(s)
%(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP
sys.stderr.write("""Erreur lors de la mise à jour de la base LDAP :
%(parsed_lines)s ligne(s) traitée(s)
%(updated_entries)s entrée(s) mise(s) à jour dans la base LDAP
""" % locals())
def do_dump(self):
"""
Affiche la liste des dernières connexions, triées par date.
Affiche la liste des dernières connexions, triées par date.
"""
liste = self.search('derniereConnexion=*')
liste = [(x.derniereConnexion(), x.compte()) for x in liste]
@ -157,15 +157,15 @@ class ComptesInactifs(object):
liste = [(x[1], strftime('%d/%m/%Y %H:%M', localtime(x[0])))
for x in liste]
cprint(tableau(liste,
titre = (u'Login', u'Dernière connexion'),
titre = (u'Login', u'Dernière connexion'),
largeur = (20, 20)))
cprint(u"Total : %d" % len(liste))
def get_idle_accounts(self, since=32*24*3600):
"""
Renvoie la liste des objets Adherent de ceux qui ne se sont pas
connectés depuis since secondes, par défaut un mois (32 jours,
pour être sûr).
connectés depuis since secondes, par défaut un mois (32 jours,
pour être sûr).
"""
limit = int(time()) - since
liste = self.search("derniereConnexion<=%d" % limit)
@ -176,20 +176,20 @@ class ComptesInactifs(object):
def do_summary(self):
"""
Envoie à disconnect un résume des comptes inactifs depuis plus d'un
Envoie à disconnect un résume des comptes inactifs depuis plus d'un
mois.
"""
modele = u"""*Membres inscrits ne s'étant pas connectés depuis plus d'un mois*
modele = u"""*Membres inscrits ne s'étant pas connectés depuis plus d'un mois*
%(inscrits)s
Total : %(inscrits_total)d
*Anciens membres ne s'étant pas connectés depuis plus d'un mois*
*Anciens membres ne s'étant pas connectés depuis plus d'un mois*
%(anciens)s
Total : %(anciens_total)d
Légende :
Légende :
- F : existence d'un .forward
- M : existence de mails non lus
@ -219,7 +219,7 @@ comptes_inactifs.py
else:
anciens.append(ligne)
titres = (u'aid', u'Login', u'Nom', u'Dernière connexion', u'F', u'M')
titres = (u'aid', u'Login', u'Nom', u'Dernière connexion', u'F', u'M')
largeurs = (6, 15, 20, 20, 1, 1)
alignements = ('d', 'g', 'c', 'c', 'c', 'c')
@ -237,9 +237,9 @@ comptes_inactifs.py
def do_spam(self):
"""
Envoie un mail explicatif aux possesseurs de compte inactif
(doit être exécuté en tant que root).
(doit être exécuté en tant que root).
"""
# Nombre de personnes concernées, en expansant de droite à gauche :
# Nombre de personnes concernées, en expansant de droite à gauche :
# inscrit/ancien, avec/sans procmail, avec/sans mail non lu
# Voir aussi template_path
stats = [0, 0, 0, 0, 0, 0, 0, 0]
@ -262,7 +262,7 @@ comptes_inactifs.py
if not os.path.isfile('/home/%s/.forward' % login): i += 2
# a-il-des mails non lus ?
if not mail: i += 1
# on incrémente
# on incrémente
stats[i] += 1
if i == 1:
# on laisse tranquilles les membres inscrits sans mails non
@ -303,7 +303,7 @@ comptes_inactifs.py
""" % total
send_email(mail_sender,
mail_report,
u"Récapitulatif des comptes inactifs",
u"Récapitulatif des comptes inactifs",
recapitulatif,
server = smtp,
debug = debug)

View file

@ -1,4 +1,4 @@
Encoding: iso-8859-15
Encoding: utf-8
Subject: [CRANS] Compte inactif depuis plus d'un mois
Bonjour %(nom)s,

View file

@ -1,4 +1,4 @@
Encoding: iso-8859-15
Encoding: utf-8
Subject: [CRANS] Compte inactif depuis plus d'un mois
Bonjour %(nom)s,

View file

@ -1,4 +1,4 @@
Encoding: iso-8859-15
Encoding: utf-8
Subject: [CRANS] Compte inactif depuis plus d'un mois
Bonjour %(nom)s,

View file

@ -1,4 +1,4 @@
Encoding: iso-8859-15
Encoding: utf-8
Subject: [CRANS] Compte inactif depuis plus d'un mois
Bonjour %(nom)s,

View file

@ -1,4 +1,4 @@
Encoding: iso-8859-15
Encoding: utf-8
Subject: [CRANS] Compte inactif depuis plus d'un mois
Bonjour %(nom)s,

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
"""
Script de déconnection automatique des machines du crans pour les raisons :

View file

@ -1,7 +1,7 @@
#! /usr/bin/env python
# -*- encoding: iso-8859-15 -*-
# -*- encoding: utf-8 -*-
# Utilisation de scappy pour détecter un DHCP pirate.
# Utilisation de scappy pour détecter un DHCP pirate.
# $Id: dhcp-detect.py,v 1.3 2006/12/11 23:31:39 glondu Exp $
import sys, os
@ -25,23 +25,23 @@ PIDFILE = "/var/run/dhcp-detect.pid"
# dhcp-server attendu
DHCPSERVER = '138.231.136.9'
# Interface à surveiller
# Interface à surveiller
INTERFACE = "crans"
# Adresse MAC
mac = os.popen(r"ifconfig | grep '^%s' | awk '{print $(NF)}'" % INTERFACE).readline().strip()
# Paquet à envoyer pour détecter un DHCP (il a été capturé pour avoir la bonne tête)
# Paquet à envoyer pour détecter un DHCP (il a été capturé pour avoir la bonne tête)
tosend = Ether("\xff\xff\xff\xff\xff\xff\x00\x80\xc8\xc9\xab\x01\x08\x00E\x10\x01H\x00\x00\x00\x00@\x11y\x96\x00\x00\x00\x00\xff\xff\xff\xff\x00D\x00C\x014\x9aA\x01\x01\x06\x00\xb2\x87\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x80\xc8\xc9\xab\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00c\x82Sc5\x01\x012\x04R\xe1'67\x07\x01\x1c\x02\x03\x0f\x06\x0c\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
# On met à jour ce paquet
# On met à jour ce paquet
tosend.getlayer(Ether).src = mac
tosend.getlayer(IP).chksum = None
tosend.getlayer(UDP).chksum = None
tosend.getlayer(BOOTP).chaddr = ''.join(map(lambda x: chr(int(x,16)),mac.split(":")+['0']*10))
tosend = Ether(tosend.build())
# Tableau associatif "mac" - "mailé pour la dernière fois"
# Tableau associatif "mac" - "mailé pour la dernière fois"
dejavu = {}
@ -88,7 +88,7 @@ def mail(paquet):
print "Envoi d'un mail...",
msg = u"""Boujour,
Un DHCP pirate a été découvert sur le réseau. Voici quelques renseignements mineurs à son sujet :
Un DHCP pirate a été découvert sur le réseau. Voici quelques renseignements mineurs à son sujet :
Son adresse Ethernet : %s
Son adresse IP : %s
@ -99,7 +99,7 @@ Un DHCP pirate a
msg += u"\n"
msg += info_machine(mac_pirate)
msg += u"""
Merci de votre attention et à bientôt.
Merci de votre attention et à bientôt.
--
dhcp-detect.py
@ -111,10 +111,10 @@ dhcp-detect.py
print "ok"
# Réception d'une réponse
# Réception d'une réponse
def recoit(paquet):
# On affiche
print "Réception de : ", paquet.summary()
print "Réception de : ", paquet.summary()
# On verifie que c'est bien ce qu'on attend
if paquet.getlayer(Ether).dst.upper() == globals()['mac'] and paquet.haslayer(BOOTP) and paquet.getlayer(BOOTP).op == 2 and paquet.getlayer(IP).src != DHCPSERVER:
# DHCP pirate ?
@ -140,7 +140,7 @@ def get():
if __name__ == "__main__":
# On quitte les éventuelles instances démonisées en cours
# On quitte les éventuelles instances démonisées en cours
try:
pid = int(file(PIDFILE).read().strip())
os.kill(pid, 15)
@ -150,12 +150,12 @@ if __name__ == "__main__":
createDaemon()
file(PIDFILE, "w").write("%d\n" % os.getpid())
else:
print "Le paquet suivant va être envoyé à intervalles réguliers pour tester la présence de DHCP pirates :"
print "Le paquet suivant va être envoyé à intervalles réguliers pour tester la présence de DHCP pirates :"
print tosend.summary()
openlog("dhcp-detect", LOG_PID)
syslog("Démarrage de dhcp-detect")
# On démarre le thread qui envoie régulièrement le paquet...
syslog("Démarrage de dhcp-detect")
# On démarre le thread qui envoie régulièrement le paquet...
Thread(target=send, name="send").start()
# ...et celui qui sniffe régulièrement la réponse
# ...et celui qui sniffe régulièrement la réponse
Thread(target=get, name="get").start()

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python
# -*- encoding: iso-8859-15 -*-
# -*- encoding: utf-8 -*-
###########################
@ -17,21 +17,21 @@ import re
sys.path.append('/usr/script/surveillance')
import strptime
# Définition de constantes :
# Définition de constantes :
############################
reseau = ["138.231.136.0/21", "138.231.148.0/22"]
# Ouverture de la base de données :
# Ouverture de la base de données :
###################################
pgsql = psycopg2.connect(host='pgsql.adm.crans.org', database='filtrage', user='crans')
# Ancienne méthode pour faire de l'autocommit.
# Ancienne méthode pour faire de l'autocommit.
# Sous wheezy, il faudra remplacer par pgsql.set_session(autocommit=True) !!!
pgsql.set_isolation_level(0)
curseur = pgsql.cursor()
###########################################
# Récupération des tables de protocoles : #
# Récupération des tables de protocoles : #
###########################################
requete = "SELECT nom,id_p2p from protocole_p2p"
@ -56,7 +56,7 @@ for cellule in tableau:
# Parser ler log du firewall: /var/log/firewall/filtre.log : #
##############################################################
# Définition des motifs des comparaisons :
# Définition des motifs des comparaisons :
##########################################
motif_p2p = re.compile("^(.*) komaz .* IPP2P=([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*")
@ -65,7 +65,7 @@ motif_virus = re.compile("^(.*) komaz .* Virus:([^ ]*).* SRC=([^ ]*).* DST=([^ ]
motif_flood = re.compile("^(.*) komaz .* Flood:([^ ]*).* SRC=([^ ]*).* DST=([^ ]*).* PROTO=([^ ]*).* SPT=([^ ]*).* DPT=([^ ]*).*")
# On récupère en continu les log du firewall:
# On récupère en continu les log du firewall:
#############################################
filtre = os.popen("tail -F /var/log/firewall/filtre.log 2> /dev/null")
@ -89,7 +89,7 @@ for log in filtre:
id_p2p = int(protocole_p2p[resultat_p2p.group(2)])
ip_src = resultat_p2p.group(3)
ip_dest = resultat_p2p.group(4)
proto = int(protocole[resultat_p2p.group(5)]) #C'est à dire id pour la base
proto = int(protocole[resultat_p2p.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_p2p.group(6))
port_dest = int(resultat_p2p.group(7))
date=strptime.syslog2pgsql(date)
@ -114,7 +114,7 @@ for log in filtre:
date = resultat_virus.group(1)
ip_src = resultat_virus.group(3)
ip_dest = resultat_virus.group(4)
proto = int(protocole[resultat_virus.group(5)]) #C'est à dire id pour la base
proto = int(protocole[resultat_virus.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_virus.group(6))
port_dest = int(resultat_virus.group(7))
# On remplit la base :
@ -136,7 +136,7 @@ for log in filtre:
date = resultat_flood.group(1)
ip_src = resultat_flood.group(3)
ip_dest = resultat_flood.group(4)
proto = int(protocole[resultat_flood.group(5)]) #C'est à dire id pour la base
proto = int(protocole[resultat_flood.group(5)]) #C'est à dire id pour la base
port_src = int(resultat_flood.group(6))
port_dest = int(resultat_flood.group(7))

View file

@ -1,5 +1,5 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
###########################
# Import des commmandes : #

View file

@ -1,13 +1,13 @@
#! /usr/bin/env python
# -*- coding: iso-8859-15 -*-
# -*- coding: utf-8 -*-
###############################################################################
# parse_auth_log.py : Détecte les problèmes d'authentifications
# parse_auth_log.py : Détecte les problèmes d'authentifications
###############################################################################
# The authors of this code are
# Jérémie Dimino <dimino@crans.org>
# Jérémie Dimino <dimino@crans.org>
#
# Copyright (C) 2006 Jérémie Dimino
# Copyright (C) 2006 Jérémie Dimino
# All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
@ -40,7 +40,7 @@ prise_chbre = {}
aujourdhui = datetime.date.today()
def trouve_chambre(bat, prise):
""" Trouve la chambre associée à une prise """
""" Trouve la chambre associée à une prise """
if prise in ('????', 'EXT', 'CRA'):
return prise
@ -59,7 +59,7 @@ def trouve_chambre(bat, prise):
def trouve_prise(chbre):
""" Trouve la prise associée à une chambre """
""" Trouve la prise associée à une chambre """
if chbre in ('EXT', '????', 'CRA'):
return chbre
@ -72,7 +72,7 @@ def trouve_prise(chbre):
def __calcul_max(table):
""" Calcule les différents maxima (voir parse_auth_log pour plus de détails) """
""" Calcule les différents maxima (voir parse_auth_log pour plus de détails) """
nb_m = 0
nb_p = 0
@ -93,7 +93,7 @@ def __calcul_max(table):
def __ajoute_ligne(errs, ligne, prise, mac, info=None):
""" Ajoute une ligne dans le dico pour la prise et la mac donnée """
""" Ajoute une ligne dans le dico pour la prise et la mac donnée """
erreur_prise = errs.get(prise)
if not erreur_prise:
@ -108,29 +108,29 @@ def __ajoute_ligne(errs, ligne, prise, mac, info=None):
erreur_mac['lignes'].append(ligne)
# Correspondance 'noms de mois' -> n°
# Correspondance 'noms de mois' -> n°
__mois_num = { 'Jan': 1, 'Feb': 2, 'Mar': 3, 'Apr': 4, 'May': 5, 'Jun': 6,
'Jul': 7, 'Aug': 8, 'Sep': 9, 'Oct': 10, 'Nov': 11, 'Dec': 12 }
def parse_auth_log(fichier_log='/var/log/freeradius/radius_auth.log', jour=None):
""" Retourne la liste des problèmes de connexions: retourne deux dicos, la première étant pour les macs qui n'ont pas été trouvées dans la base et la seconde pour les connexions qui ont eu lieu à partir d'une mauvaise prise
""" Retourne la liste des problèmes de connexions: retourne deux dicos, la première étant pour les macs qui n'ont pas été trouvées dans la base et la seconde pour les connexions qui ont eu lieu à partir d'une mauvaise prise
les deux dictionnaires ont la structure suivante:
- nombre_mac_max: nombre maximal d'erreurs trouvées pour une mac
- nombre_prise_max: nombre maximal d'erreurs trouvées pour une prise
- prises: dico associant à une prise la listes des erreurs à partir de cette prise:
- nombre_mac_max: nombre maximal d'erreurs trouvées pour une mac
- nombre_prise_max: nombre maximal d'erreurs trouvées pour une prise
- prises: dico associant à une prise la listes des erreurs à partir de cette prise:
- nombre: nombre total d'erreurs survenues sur la prise
- nombre_max: nombre maximal d'erreurs trouvéss pour une mac
- macs: dico associant à une mac la liste des erreurs à partir de cette mac
- nombre_max: nombre maximal d'erreurs trouvéss pour une mac
- macs: dico associant à une mac la liste des erreurs à partir de cette mac
- nombre: le nombre d'erreurs survenues pour cette mac sur cette prise
- lignes: la liste des lignes du fichier de logs la mac apparaît sur cette prise
- info: informations sur le propriétaire (vaut None pour la première table)
- lignes: la liste des lignes du fichier de logs la mac apparaît sur cette prise
- info: informations sur le propriétaire (vaut None pour la première table)
- machine: la machine en question
- prise: la prise de sa chambre
- chambre: sa chambre
- prop: le propriétaire
- prop: le propriétaire
Si jour est spécifié (de type datetime.date), toutes les connexions avant cette dates seront ignorées.
Si jour est spécifié (de type datetime.date), toutes les connexions avant cette dates seront ignorées.
"""
try:
@ -139,13 +139,13 @@ Si jour est sp
cprint(u"Impossible d'ouvrir le fichier %s" % fichier_log, 'rouge')
sys.exit(1)
# Les macs non trouvées
# Les macs non trouvées
errs_inconnue = {}
# Les pc connectés sur la mauvaise prise
# Les pc connectés sur la mauvaise prise
errs_prise = {}
# Les recherches déjà effectuées sur les macs
# Les recherches déjà effectuées sur les macs
mac_machine = {}
annee = None
@ -161,12 +161,12 @@ Si jour est sp
if annee == None:
if nouveau_mois > aujourdhui.month:
# Là on suppose qu'il s'agit de l'année dernière
# Là on suppose qu'il s'agit de l'année dernière
annee = aujourdhui.year - 1
else:
annee = aujourdhui.year
elif mois > nouveau_mois:
# Là on suppose qu'on est passé à l'année suivante
# Là on suppose qu'on est passé à l'année suivante
annee += 1
mois = nouveau_mois
@ -213,7 +213,7 @@ Si jour est sp
def affiche_erreurs(errs, message, min_mac=1, min_prise=1):
""" Affiche les infos contenues dans un dico renvoyé par parse_auth_log """
""" Affiche les infos contenues dans un dico renvoyé par parse_auth_log """
if errs['nombre_mac_max'] >= min_mac and errs['nombre_prise_max'] >= min_prise:
@ -248,35 +248,35 @@ def __usage(err=''):
def __param_entier(opt, val):
""" Récupère un entier passé en ligne de commande """
""" Récupère un entier passé en ligne de commande """
try:
return int(val)
except:
__usage(u'La valeur du paramètre %s est incorecte (doit être un entier positif)' % opt)
__usage(u'La valeur du paramètre %s est incorecte (doit être un entier positif)' % opt)
def __aide():
""" Aide """
cprint(u"""Usage: %s [OPTIONS]
Parse les logs d'authentifications et affiche les erreurs trouvées (macs inconnues ou connexion d'une machine sur une prise autre que celle du propriétaire).
Parse les logs d'authentifications et affiche les erreurs trouvées (macs inconnues ou connexion d'une machine sur une prise autre que celle du propriétaire).
Options:
-h, --help affiche cette aide
-l, --log <fichier> fichier de log à parser (par défaut: /var/log/freeradius/radius_auth.log)
-m, --min-mac <nombre> nombre minimal d'occurrences d'une mac sur une prise pour qu'elle soit reportée
-n, --min-prise <nombre> nombre minimal d'erreurs sur une prise pour qu'elle soit reportée
-l, --log <fichier> fichier de log à parser (par défaut: /var/log/freeradius/radius_auth.log)
-m, --min-mac <nombre> nombre minimal d'occurrences d'une mac sur une prise pour qu'elle soit reportée
-n, --min-prise <nombre> nombre minimal d'erreurs sur une prise pour qu'elle soit reportée
-i, --inconnue n'affiche que les erreurs de mac inconnues
-p, --prise n'affiche que les connexions sur une prise autre que celle du propriétaire
-p, --prise n'affiche que les connexions sur une prise autre que celle du propriétaire
-d, --date <date> ignorer totalement les lignes avant cette date
<date> peut être:
<date> peut être:
- une date absolue sous la forme AAAAMMJJ
- une date relative à aujourd'hui sous la forme +<nombre de jour>
Par exemple pour ne considérer que les deux dernier jours: +2
- une date relative à aujourd'hui sous la forme +<nombre de jour>
Par exemple pour ne considérer que les deux dernier jours: +2
Rapporter toutes anomalies à <dimino@crans.org>.""" % sys.argv[0].split('/')[-1].split('.')[0])
Rapporter toutes anomalies à <dimino@crans.org>.""" % sys.argv[0].split('/')[-1].split('.')[0])
sys.exit(0)
@ -288,7 +288,7 @@ if __name__ == '__main__':
# Info que l'on veut afficher
aff_inconnue = True
aff_prise = True
# Date de départ
# Date de départ
jour = None
import getopt, time
@ -318,7 +318,7 @@ if __name__ == '__main__':
try:
jour = datetime.date(*(time.strptime(val, "%Y%m%d")[0:3]))
except:
__usage(u'La valeur du paramètre %s est incorecte (doit être de la forme AAAAMMJJ)' % opt)
__usage(u'La valeur du paramètre %s est incorecte (doit être de la forme AAAAMMJJ)' % opt)
else:
cprint(u'Option inconnue: %s' % opt, 'rouge')
__usage()
@ -328,7 +328,7 @@ if __name__ == '__main__':
errs_inconnue, errs_prise = parse_auth_log(fichier_log, jour)
if aff_inconnue:
affiche_erreurs(errs_inconnue, u"Pour les connexions suivantes la mac n'a pas été trouvée dans la base:", min_mac, min_prise)
affiche_erreurs(errs_inconnue, u"Pour les connexions suivantes la mac n'a pas été trouvée dans la base:", min_mac, min_prise)
if aff_prise:
affiche_erreurs(errs_prise, u"Les connexions suivantes ont eu lieu sur une prise autre que celle du proriétaire:", min_mac, min_prise)
affiche_erreurs(errs_prise, u"Les connexions suivantes ont eu lieu sur une prise autre que celle du proriétaire:", min_mac, min_prise)

View file

@ -1,11 +1,11 @@
#! /usr/bin/env python
# -*- encoding: iso-8859-15 -*-
# -*- encoding: utf-8 -*-
"""
Script d'envoi des statistiques des déconnections
et du trafic de la journée à disconnect@
Script d'envoi des statistiques des déconnections
et du trafic de la journée à disconnect@
Copyright (C) Xavier Pessoles - Étienne Chové - Michel Blockelet
Copyright (C) Xavier Pessoles - Étienne Chové - Michel Blockelet
Licence : GPLv2
"""
@ -111,9 +111,9 @@ liste_upload = tableau(data = [ (l[1], l[2], ipv4or6(str(l[0])), socket.getfqdn(
titre = ['upload', 'download', 'proto', 'machine'],
largeur = [10, 10, 10, 40],
format = ['o', 'o', 's', 's'],
alignement = ['d', 'd', 'c', 'c']).encode('iso-8859-15')
alignement = ['d', 'd', 'c', 'c']).encode('utf-8')
# Trafic exempté :
# Trafic exempté :
##################
requete = """(SELECT ip_crans, sum(upload) AS somme, sum(download)
FROM upload
@ -149,7 +149,7 @@ liste_exemptes = tableau(data = [[l[1], l[2], ipv4or6(str(l[0])), socket.getfqdn
titre = ['upload', 'download', 'proto', 'machine'],
largeur = [10, 10, 10, 30],
format = ['o', 'o', 's', 's'],
alignement = ['d', 'd', 'c', 'c']).encode('iso-8859-15')
alignement = ['d', 'd', 'c', 'c']).encode('utf-8')
# Upload des serveurs :
#######################
@ -170,7 +170,7 @@ 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('iso-8859-15')
alignement = ['d', 'd', 'c', 'c']).encode('utf-8')
# statistiques des gros uploads depuis les serveurs
@ -178,7 +178,7 @@ liste_serveurs = tableau(data = liste_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('iso-8859-15')
show_limit=100).encode('utf-8')
############################
# Statistiques virus/p2p : #
@ -206,10 +206,10 @@ 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('iso-8859-15')
alignement = ['d','c']).encode('utf-8')
# Machines actuellement déconnectées :
# Machines actuellement déconnectées :
######################################
requete = "SELECT DISTINCT ip_crans FROM avertis_virus"
curseur.execute(requete)
@ -220,9 +220,9 @@ for IP in infections:
liste_virus.append(["%s" % (str(hostname))])
liste_virus = tableau(liste_virus,
titre=['machine'], largeur=[30]).encode('iso-8859-15')
titre=['machine'], largeur=[30]).encode('utf-8')
# Machines ayant fait des attaques virus dans la journée :
# 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'
@ -237,10 +237,10 @@ for IP, compteur in curseur.fetchall():
liste_virus2 = tableau(data = liste_virus2,
titre = ['machine', 'nombre'],
largeur = [30, 12],
alignement = ['c', 'd']).encode('iso-8859-15')
alignement = ['c', 'd']).encode('utf-8')
# Machines ayant fait de attaques flood dans la journée :
# 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'
@ -255,7 +255,7 @@ for IP, compteur in curseur.fetchall():
liste_virus3 = tableau(data = liste_virus3,
titre = ['machine', 'nombre'],
largeur = [30, 12],
alignement = ['c', 'd']).encode('iso-8859-15')
alignement = ['c', 'd']).encode('utf-8')
#############
@ -266,11 +266,11 @@ 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
Subject: Statistiques des =?utf-8?q?derni=C3=A8res?= 24h
Message-Id: <%(uuid)s1@crans.org>
Content-Type: text/plain; charset="iso-8859-15"
Content-Type: text/plain; charset="utf-8"
*Gros uploads des serveurs* (charybde et sable sont exemptés totalement)
*Gros uploads des serveurs* (charybde et sable sont exemptés totalement)
%(gros_uploads_des_serveurs)s
@ -282,23 +282,23 @@ Content-Type: text/plain; charset="iso-8859-15"
%(liste_etherunk)s
*Machines actuellement déconnectées pour virus*
*Machines actuellement déconnectées pour virus*
%(liste_virus)s
*Machines ayant commis des attaques virales dans la journée*
*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*
*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)
*Statistiques de trafic des adhérents* (tout le trafic)
%(liste_upload)s
*Statistiques de trafic des adhérents exemptés* (juste le trafic exempté)
*Statistiques de trafic des adhérents exemptés* (juste le trafic exempté)
%(liste_exemptes)s