Es hat jetzt doch einen Moment gedauert ...
Gräfin Klara hat geschrieben:
Hier habe ich für dich eine Sammlung von Werkzeugen zusammengestellt, die du benötigen wirst.
Danke. Du wirst sie im zweiten Skript wiederfinden.
Hier das Skript, das die Mails durchsieht und die Header-Daten extrahiert.
Code: Alles auswählen
#!/bin/bash
# ----------------------------------------------------------------------
# emtr-smd.sh
# scan mail directories
# ist Teil von emtr - e-mail trace route
# muss auf die Mail-Verzeichnisse lesend zugreifen können
# z. B. cyrus organisiert sich in /var/spool/imap ...
#
# bei ca. 170.000 Mails: Laufzeit ca. 15 Minuten, ca. 220MB Daten
#
# siehe hierzu
# https://linux-club.de/forum/viewtopic.php?f=86&t=123337
#
# ----------------------------------------------------------------------
init ()
{
# IMAP Verzeichnis
MailDir="/var/spool/imap"
# Ausgabedatei
FileOut="/irgend/ein/Verzeichnis/scan.txt"
# Zeile, um die einzelnen Header in $FileOut voneinander zu trennen
Trennzeile="### Nachricht Nr:"
# lösche den vorherigen Scan
rm $FileOut
# Zähler für verarbeitete Nachrichten
a=0
}
readImapHeaders ()
{
# lese alle Nachrichten in den Mail-Verzeichnissen
# in und unter $MailDir und extrahiere die Header-Daten mit formail
# schreibe das Ergebnis in die Datei $FileOut
# ----------------------------------------------------------------------
# ein einfaches
#
# for message in `find "$MailDir" -type f`
# do
# formail -zX "Message-ID:" -zX "From:" -zX "To:" -zX "Subject:" -zX "Date:" -zX "Received:" < "$message" >> $FileOut
# done
#
# geht nicht, da in den Pfadnamen Leerzeichen vorkommen können
#
# siehe https://askubuntu.com/questions/343727/filenames-with-spaces-breaking-for-loop-find-command
# ----------------------------------------------------------------------
find "$MailDir" -type f -print0 |
while IFS= read -r -d '' message
do
# Unsinn wegfiltern
if [[ "$message" != *"Trash"* ]] && [[ "$message" != *"/cyrus."* ]]
then
a=`expr $a + 1`
echo $Trennzeile" "$a" Pfad: "$message >> $FileOut
formail -zX "Message-ID:" -zX "From:" -zX "To:" -zX "Subject:" -zX "Date:" -zX "Received:" < "$message" >> $FileOut
fi
done
}
init
readImapHeaders
Die vom Skript erzeugte Datei (im Beispiel scan.txt) enthält die gewünschten E-Mail-Header-Informationen - aber noch nicht in aufbereiteter Form.
Die Aufbereitung der Daten erfolgt mit dem zweiten Skript, das die Daten aus der Ausgabedatei des ersten Skripts (hier scan.txt) in eine fixe Struktur bringt und damit besser auswertbar macht.
Code: Alles auswählen
#!/bin/bash
# ----------------------------------------------------------------------
# emtr-mkdb.sh
# e-mail trace route - make database
#
# - ist Teil von emtr - e-mail trace route
# - muss auf die Ausgabedatei des Skrips emtr-smd.sh lesend zugreifen können
# - stellt ausgewählte Felder der E-Mail-Header-Daten in einem einheitlichen
# Format als csv-Datei zur späteren vereinfachten Auswertung zur Verfügung.
#
# liest $EmtrScan (Text-Datei)
# schreibt $EmtrDB (csv-Datei)
#
#
# siehe hierzu
# https://linux-club.de/forum/viewtopic.php?f=86&t=123337
#
# gehört zu emtr.sh und emtr-smd.sh
# ------------------------------------------------
BaseDir="/das/Programm/Verzeichnis/"
EmtrScan="scan.txt"
EmtrDB="emtr-db.csv"
Trennzeile="### Nachricht Nr:"
init ()
{
# wechsele ins Programmverzeichnis
cd $BaseDir
# lösche alte DB
rm $EmtrDB
# EMail-Zähler
msg=0
# Zeilenzähler
i=0
# Hops-Zähler
hop=0
# Programmstart
Start=1
# Limit zur Begrenzung der verarbeiteten Header-Sets (beim Testen)
# Limit=0 -> kein Limit
Limit=50
# Arrays
typeset -a arrTS
typeset -a arrFromURL
typeset -a arrFromIP
typeset -a arrByURL
typeset -a arrByIP
# Variablen
MessageID="MessageID"
Sender="Sender"
Empfaenger="Empfaenger"
Subj="Subj"
Date="Date"
}
processArrays ()
{
# Arrays in Datei schreiben
echo "\""$MessageID"\";\"HDR\";\""$Date"\";\""$Sender"\";\""$Empfaenger"\";\""$Subj"\";\""$Path"\";\"" >> $EmtrDB
while [ $hop -ge 1 ] ;
do
echo "\""$MessageID"\";\"HOP\";\""$hop"\";\""${arrTS[$hop]}"\";\""${arrFromURL[$hop]}"\";\""${arrFromIP[$hop]}"\";\""${arrByURL[$hop]}"\";\""${arrByIP[$hop]}"\";\"" >> $EmtrDB
hop=`expr $hop - 1`
done
# Arrays löschen
unset arrTS
unset arrFromURL
unset arrFromIP
unset arrByURL
unset arrByIP
# Variablen löschen
unset Path
unset MessageID
unset Sender
unset Empfaenger
unset Subj
unset Date
}
mkdb ()
{
while IFS= read -r Line
do
#
# Vorarbeiten bei neuem Nachrichten-Header
# --------------------------------------------------------------
# falls es der Beginn eines neuen Headers ist,
if [[ "$Line" == *"$Trennzeile"* ]]
then
# dann verarbeite den vorherigen. Es sei denn,
# das Programm läuft gerade erst los ($Start= 1)
if [[ $Start -eq 0 ]]
then
processArrays
# falls ein Limit gesetzt ist, stoppe das Skript entsprechend
if [[ $Limit -gt 0 ]] && [[ $msg -eq $Limit ]]
then
echo "Abbruch, Limit erreicht."
exit
fi
fi
# Nachrichtenzähler +1
msg=`expr $msg + 1`
# Zeilenzähler auf 0
i=0
# Hop-Zähler auf 0
hop=0
# Pfad zur Nachricht
s="/" # Suchsstring, der Pfad beginnt mit "/"
x=${Line#*$s} # Rest ab erstem Auftauchen des Suchstrings
p=$(( ${#Line} - ${#x} - ${#s} )) # Position für Rest incl. Suchstring
Path=${Line:$p} # Rest incl. Suchstring, -> der Pfad
fi
i=`expr $i + 1`
# wenn Hop gefunden (wenn "Received" in der Zeile steht),
# erhöhe Anzahl um 1
# $hop dient als Index der Arrays
if [[ "$Line" == *"Received:"* ]]
then
hop=`expr $hop + 1`
fi
#
# ab hier erfolgt die Verarbeitung der Zeilen
# bis zum nächsten Nachrichten-Header
# --------------------------------------------------------------
# suche Zeitstempel
unset TS
# erkannt wird
# 15 Feb 2017 08:06:06 +0100
TS=`echo $Line | grep -E -o "\b([MTWFSonuedriat]{3}), (3[0-1]|2[0-9]|1[0-2]|0[1-9]) [JFMASOND][anebrpyulgpctov]{2} ([12][0-9]{3}) ([01][0-9]|2[0-4]):([0-5][0-9]):([0-5][0-9]) [+-][0-9]{4}?\b"`
# noch nicht erkannt werden:
# 15 Feb 2017 07:06:06 UT
# 15 Feb 2017 08:06:06 +0100 (CET)
if [[ -n $TS ]]
then
arrTS[$hop]=$TS
fi
# suche "from" Server-URL und -IP
unset Furl
Furl=`echo $Line | grep -P -o "from (localhost|\K[0-9a-z\-\.]+\.[0-9a-z\-\.]+ )"`
if [[ -n $Furl ]]
then
arrFromURL[$hop]=$Furl
unset Fip
Fip=`echo $Line | grep -E -o "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"`
if [[ -n $Fip ]]
then
arrFromIP[$hop]=$Fip
fi
fi
# suche "by" Server-URL und -IP
unset Burl
Burl=`echo $Line | grep -P -o "by \K[0-9a-z\-\.]+\.[0-9a-z\-\.]+ "`
if [[ -n $Burl ]]
then
arrByURL[$hop]=$Burl
unset Bip
Bip=`echo $Line | grep -E -o "[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}"`
if [[ -n $Bip ]]
then
arrByIP[$hop]=$Bip
fi
fi
# lese formail-Felder
if [[ "$Line" == *"Message-ID:"* ]]
then
MessageID=${Line:12}
MessageID=${MessageID%?} # ^M am Stringende entfernen
fi
if [[ "$Line" == *"From:"* ]]
then
Sender=`echo $Line | grep -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b"`
fi
if [[ "$Line" == *"To:"* ]]
then
Empfaenger=`echo $Line | grep -E -o "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b"`
fi
if [[ "$Line" == *"Subject:"* ]]
then
Subj=${Line:9}
Subj=${Subj%?} # ^M am Stringende entfernen
fi
if [[ "$Line" == *"Date:"* ]]
then
Date=${Line:6}
Date=${Date%?} # ^M am Stringende entfernen
fi
# ab hier sind wir nicht mehr am Programmstart. Die Sonderbehandlung des
# ersten Durchlaufs kann entfallen
Start=0
done < "$EmtrScan"
}
init
if [[ $Limit -gt 0 ]]
then
echo "Limit gesetzt, Abbruch nach "$Limit" Headern."
fi
mkdb
Schwierigkeiten gibt es noch bei der Erkennung der unterschiedlichen Formate der Zeitstempel, genauer, der Zeitzonenangaben.
Code: Alles auswählen
das geht:
15 Feb 2017 08:06:06 +0100
noch nicht erkannt werden:
15 Feb 2017 07:06:06 UT
15 Feb 2017 08:06:06 +0100 (CET)
Die Laufzeiten will ich noch berechnen und die Anreicherung mit Geo-Daten fehlt auch noch.
Keine Idee habe ich für folgenden Punkt: für jeden Hop wird auch der jeweilige "Service" angegeben, der den Hop erzeugt hat. Das sind Ausdrücke oder Teile davon, die in runden Klammern stehen. Leider gibt es aber noch viele andere Elemente, die auch in runden Klammern stehen, so dass ich das nicht als Kriterium heranziehen kann.
Beispiele für diese "Services" wären:
Code: Alles auswählen
([unix socket])
(Cyrus v2.4.18)
(Postfix)
(amavisd-new, port 10024)
(fetchmail-6.3.26)
(Exim 4.85_2)
(TLSv1.2:DHE-RSA-AES128-SHA:128)
...
Es wird ...
Anmerkungen und Kritik sind hochwillkommen.
Danke und Gruß,
Radiergummi