[arpwatch] ajout d'un serveur d'envoi
Celui-ci écoute au travers d'une socket unix. Il permet ainsi de garder une connexion ldap (et pg et cie) en permanence ouverte. Ce qui accélère le traitement des rapports de arpwatch. Pour utiliser ce server, report.py (ancien arpwatch_sendmail.py) tente de se connecter à cette socket et envoie le mail lui-même en cas d'échec. On rajoute également un initscript pour arpwatch_sendmail_server. Il n'est pas parfait et si vous aimez pas, feel free to edit.
This commit is contained in:
parent
37c5a6836e
commit
c068df708d
6 changed files with 226 additions and 68 deletions
6
surveillance/arpwatch/common.py
Normal file
6
surveillance/arpwatch/common.py
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#-*- coding: utf-8 -*-
|
||||||
|
PIDFILE = '/var/run/arpwatch_sendmail.pid'
|
||||||
|
USER='arpwatch'
|
||||||
|
GROUP='adm'
|
||||||
|
SOCKET_FILE='/var/run/arpwatch_sendmail.sock'
|
49
surveillance/arpwatch/initscript
Executable file
49
surveillance/arpwatch/initscript
Executable file
|
@ -0,0 +1,49 @@
|
||||||
|
#! /bin/sh
|
||||||
|
### BEGIN INIT INFO
|
||||||
|
# Provides: arpwatch_sendmail
|
||||||
|
# Required-Start: $remote_fs
|
||||||
|
# Required-Stop: $remote_fs
|
||||||
|
# Default-Start: 2 3 4 5
|
||||||
|
# Default-Stop: 0 1 6
|
||||||
|
# Short-Description: arpwatch_sendmail
|
||||||
|
# Description: Report mail d'arpwatch
|
||||||
|
### END INIT INFO
|
||||||
|
|
||||||
|
NAME=arpwatch_sendmail
|
||||||
|
PIDF=/var/run/$NAME.pid
|
||||||
|
PATH=/usr/scripts/surveillance/arpwatch
|
||||||
|
ARGS=root@crans.org
|
||||||
|
BIN="/usr/bin/python $PATH/sendmail_server.py"
|
||||||
|
DESCR="Script d'envoi de mails arpwatch"
|
||||||
|
|
||||||
|
. /lib/lsb/init-functions
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
case "$1" in
|
||||||
|
start)
|
||||||
|
echo -n "Démarrage de $NAME"
|
||||||
|
/sbin/start-stop-daemon --start --quiet --pidfile $PIDF --exec $BIN $ARGS
|
||||||
|
echo "."
|
||||||
|
;;
|
||||||
|
stop)
|
||||||
|
echo -n "Arrêt de $NAME"
|
||||||
|
/sbin/start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile $PIDF
|
||||||
|
echo "."
|
||||||
|
;;
|
||||||
|
|
||||||
|
restart)
|
||||||
|
echo -n "Redémarrage (arrêt) de $NAME"
|
||||||
|
/sbin/start-stop-daemon --stop --quiet --oknodo --retry 30 --pidfile $PIDF
|
||||||
|
/bin/sleep 1
|
||||||
|
echo -n "Redémarrage (démarrage) de $NAME"
|
||||||
|
/sbin/start-stop-daemon --start --quiet --pidfile $PIDF --exec $BIN $ARGS
|
||||||
|
echo "."
|
||||||
|
;;
|
||||||
|
|
||||||
|
*)
|
||||||
|
echo "Usage: /etc/init.d/$NAME {start|stop|restart}"
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
|
||||||
|
exit 0
|
96
surveillance/arpwatch/report.py
Executable file
96
surveillance/arpwatch/report.py
Executable file
|
@ -0,0 +1,96 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# Ajout d'un whos et d'un tracage aux mails d'arpwatch
|
||||||
|
# Auteurs : Stéphane Glondu, Cyril Cohen, Daniel STAN, Valentin Samir
|
||||||
|
# Licence : GPLv2
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import sys, os, re
|
||||||
|
import socket
|
||||||
|
|
||||||
|
import common
|
||||||
|
|
||||||
|
sys.path.append('/usr/scripts')
|
||||||
|
from gestion.tools.locate_mac import trace_machine, format_mac, info_machine
|
||||||
|
from gestion.config import NETs
|
||||||
|
from gestion.iptools import AddrInNets
|
||||||
|
from utils.sendmail import sendmail
|
||||||
|
|
||||||
|
# On récupère les destinataires dans les arguments (très ad hoc)
|
||||||
|
recipients = [ mail for mail in sys.argv[1:] if '@' in mail ]
|
||||||
|
if not recipients:
|
||||||
|
print("Pas de mail fourni: affichage sur stdout.",
|
||||||
|
file=sys.stderr)
|
||||||
|
|
||||||
|
find_mac = re.compile(r'[0-9A-Fa-f]{1,2}(?::[0-9A-Fa-f]{1,2}){5}')
|
||||||
|
find_ip = re.compile(r'[0-9]{1,3}(?:\.[0-9]{1,3}){3}')
|
||||||
|
arpwatched_net = NETs['all'] + NETs['adm'] + NETs['accueil'] + NETs['isolement'] + NETs['personnel-ens'] + NETs['evenementiel']
|
||||||
|
|
||||||
|
def get_machine(unformated_mac):
|
||||||
|
"""Renvoie les informations sur la machine à partir de sa mac"""
|
||||||
|
mac = format_mac(unformated_mac)
|
||||||
|
return u"\n" + info_machine(mac) + u"\n" + trace_machine(mac)
|
||||||
|
|
||||||
|
def get_subject(headers_list):
|
||||||
|
for line in headers_list:
|
||||||
|
if line.lower().startswith('subject:'):
|
||||||
|
return line[9:].strip()
|
||||||
|
return None
|
||||||
|
|
||||||
|
def report(texte, fallback=False):
|
||||||
|
"""Envoi d'un rapport"""
|
||||||
|
textes = texte.splitlines(True)
|
||||||
|
try:
|
||||||
|
i = textes.index('\n')
|
||||||
|
except ValueError:
|
||||||
|
print("wrong formatted mail", file=sys.stderr)
|
||||||
|
return
|
||||||
|
|
||||||
|
headers = textes[:i]
|
||||||
|
textes = textes[(i+1):]
|
||||||
|
|
||||||
|
# Extrait le sujet
|
||||||
|
subject = get_subject(headers)
|
||||||
|
|
||||||
|
# Cherche les IP dans le corps
|
||||||
|
try:
|
||||||
|
ip = set(find_ip.findall(texte)).pop()
|
||||||
|
except KeyError:
|
||||||
|
ip = None
|
||||||
|
# On complète le message
|
||||||
|
if u'flip flop' in subject and ip is not None and AddrInNets(ip, arpwatched_net):
|
||||||
|
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)))
|
||||||
|
if fallback:
|
||||||
|
textes.append(u'\nAttention, arpwatch/sendmail_server.py inactif !\n')
|
||||||
|
textes.append(u'\n-- \narpwatch_sendmail.py\n')
|
||||||
|
|
||||||
|
out = ''.join(textes)
|
||||||
|
if recipients:
|
||||||
|
sendmail(u"arpwatch@crans.org", recipients, subject, out,
|
||||||
|
more_headers = {
|
||||||
|
'X-Mailer': __file__,
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
print(out)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
data = sys.stdin.read()
|
||||||
|
# On essaye d'envoyer le mail à la socket de sendmail_server
|
||||||
|
# et au pire, on envoie nous-même le mail
|
||||||
|
try:
|
||||||
|
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
||||||
|
s.connect(common.SOCKET_FILE)
|
||||||
|
s.send(data)
|
||||||
|
s.close()
|
||||||
|
except socket.error:
|
||||||
|
report(data, fallback=True)
|
75
surveillance/arpwatch/sendmail_server.py
Executable file
75
surveillance/arpwatch/sendmail_server.py
Executable file
|
@ -0,0 +1,75 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Serveur sendmail d'arpwatch.
|
||||||
|
Permet de ne charger qu'une fois le module report (et donc lc_ldap
|
||||||
|
et cie)
|
||||||
|
Ceci écoute sur une socket unix les rapports arpwatch (via report.py)
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import SocketServer
|
||||||
|
import sys, os, pwd, grp
|
||||||
|
import common
|
||||||
|
|
||||||
|
class Handler(SocketServer.StreamRequestHandler):
|
||||||
|
"""Gestion d'une requête"""
|
||||||
|
def handle(self):
|
||||||
|
self.server.reporter.report(self.request.recv(1024))
|
||||||
|
|
||||||
|
class MyServer(SocketServer.UnixStreamServer):
|
||||||
|
"""Un server, avec une instance du module report"""
|
||||||
|
reporter = None
|
||||||
|
|
||||||
|
def run():
|
||||||
|
"""Serveur permanent"""
|
||||||
|
import report
|
||||||
|
|
||||||
|
try:
|
||||||
|
os.remove(common.SOCKET_FILE)
|
||||||
|
print("Removed old socket", file=sys.stderr)
|
||||||
|
except OSError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# La socket ne doit pas être accessible pour tous: on garde adm
|
||||||
|
os.umask(007)
|
||||||
|
os.setgid(grp.getgrnam(common.GROUP).gr_gid)
|
||||||
|
|
||||||
|
serv = SocketServer.UnixStreamServer(common.SOCKET_FILE, Handler)
|
||||||
|
serv.reporter = report
|
||||||
|
|
||||||
|
serv.serve_forever()
|
||||||
|
|
||||||
|
# fork en arrière plan + pidfile
|
||||||
|
if __name__ == "__main__":
|
||||||
|
# do the UNIX double-fork magic, see Stevens' "Advanced
|
||||||
|
# Programming in the UNIX Environment" for details (ISBN 0201563177)
|
||||||
|
try:
|
||||||
|
pid = os.fork()
|
||||||
|
if pid > 0:
|
||||||
|
# exit first parent
|
||||||
|
sys.exit(0)
|
||||||
|
except OSError, e:
|
||||||
|
print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# decouple from parent environment
|
||||||
|
os.chdir("/") #don't prevent unmounting....
|
||||||
|
os.setsid()
|
||||||
|
os.umask(0)
|
||||||
|
|
||||||
|
# do second fork
|
||||||
|
try:
|
||||||
|
pid = os.fork()
|
||||||
|
if pid > 0:
|
||||||
|
# exit from second parent, print eventual PID before
|
||||||
|
#print "Daemon PID %d" % pid
|
||||||
|
open(common.PIDFILE, 'w').write("%d" % pid)
|
||||||
|
sys.exit(0)
|
||||||
|
except OSError, e:
|
||||||
|
print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# start the daemon main loop
|
||||||
|
run()
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
#!/bin/sh
|
|
||||||
|
|
||||||
#execution avec des droits suffisants
|
|
||||||
LANG=fr_FR.UTF-8 sudo -u 'arpwatch' /usr/scripts/surveillance/arpwatch_sendmail.py $*
|
|
|
@ -1,64 +0,0 @@
|
||||||
#! /usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# 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')
|
|
||||||
sys.path.append('/usr/scripts/gestion/tools')
|
|
||||||
from locate_mac import trace_machine, format_mac, info_machine
|
|
||||||
from config import NETs
|
|
||||||
from iptools import AddrInNets
|
|
||||||
|
|
||||||
find_mac = re.compile(r'[0-9A-Fa-f]{1,2}(?::[0-9A-Fa-f]{1,2}){5}')
|
|
||||||
find_ip = re.compile(r'[0-9]{1,3}(?:\.[0-9]{1,3}){3}')
|
|
||||||
arpwatched_net = NETs['all'] + NETs['adm'] + NETs['accueil'] + NETs['isolement'] + NETs['personnel-ens'] + NETs['evenementiel']
|
|
||||||
|
|
||||||
|
|
||||||
def get_machine(unformated_mac):
|
|
||||||
mac = format_mac(unformated_mac)
|
|
||||||
return u"\n" + info_machine(mac) + u"\n" + trace_machine(mac)
|
|
||||||
|
|
||||||
def get_subject(headers_list):
|
|
||||||
for line in headers_list:
|
|
||||||
if line.lower().startswith('subject:'):
|
|
||||||
return line
|
|
||||||
return None
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
texte = sys.stdin.read() #.decode('ISO-8859-15')
|
|
||||||
textes = texte.splitlines(True)
|
|
||||||
i = textes.index(u'\n')
|
|
||||||
subject = get_subject(textes[:i])
|
|
||||||
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',
|
|
||||||
]
|
|
||||||
|
|
||||||
# On récupère les destinataires dans les arguments (très ad hoc)
|
|
||||||
recipients = sys.argv[2].split(',')
|
|
||||||
|
|
||||||
try : ip = set(find_ip.findall(texte)).pop()
|
|
||||||
except KeyError: ip = None
|
|
||||||
# On complète le message
|
|
||||||
if 'flip flop' in subject and ip is not None and AddrInNets(ip, arpwatched_net):
|
|
||||||
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')
|
|
||||||
|
|
||||||
smtp = smtplib.SMTP()
|
|
||||||
smtp.connect()
|
|
||||||
smtp.sendmail("arpwatch@crans.org", recipients, u''.join(textes).encode('UTF-8'))
|
|
||||||
smtp.quit()
|
|
Loading…
Add table
Add a link
Reference in a new issue