Cкрипт
findmail.pl и findmail.sh разработан для тассировки письма (поиска) в лог-файле Postfix.
Основные возможности:
-
findmail.sh - bash версия,
findmail.pl - perl версия;
-
Принудительный выбор лог-файла (если не указан, то по умолчанию /var/log/mail);
-
Многоуровневая трассировка письма (например, при наличии коннектора amavisd-new) или принудительный выбор релея;
-
Поиск по дате и e-mail адресу получателя или отправителя.
mail:/home/postadmin # findmail.sh -d "Nov 18 15" -t user@mydomain.com -r all
=============================================================
Фильтрация лога. Это может занять некоторое время... Готово
=============================================================
==============================
Trace mail started with keys:
==============================
type=t
date=Nov 18 15
e-mail=user@mydomain.com
logfile=/var/log/mail-20091119.gz
relay=
------------------
Found mail id's:
------------------
60D39F8F39
0B394F8F5A
E8D1FF8F49
--------------------------------
Trace mail with id: 60D39F8F39
--------------------------------
Nov 18 15:12:12 mail postfix/smtpd[31049]: 60D39F8F39: client=guard.mydomain.local[10.1.1.9]
Nov 18 15:12:12 mail postfix/cleanup[30110]: 60D39F8F39: message-id=<20091118121212.2C6BC1A22AC@guard.mydomain.com>
Nov 18 15:12:12 mail postfix/qmgr[8799]: 60D39F8F39: from=<guard@mydomain.com>, size=1165, nrcpt=1 (queue active)
Nov 18 15:12:13 mail postfix/smtp[30201]: 60D39F8F39: to=<user@mydomain.com>, relay=127.0.0.1[127.0.0.1]:10024, delay=0.8, delays=0.02/0/0/0.77, dsn=2.0.0, status=sent (250 2.0.0 Ok, id=26709-12, from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 0B394F8F5A)
Nov 18 15:12:13 mail postfix/qmgr[8799]: 60D39F8F39: removed
--------------------------------
Trace mail with id: 0B394F8F5A
--------------------------------
Nov 18 15:12:13 mail postfix/smtpd[31068]: 0B394F8F5A: client=localhost[127.0.0.1]
Nov 18 15:12:13 mail postfix/cleanup[30110]: 0B394F8F5A: message-id=<20091118121212.2C6BC1A22AC@guard.mydomain.com>
Nov 18 15:12:13 mail postfix/qmgr[8799]: 0B394F8F5A: from=<guard@mydomain.com>, size=1213, nrcpt=1 (queue active)
Nov 18 15:12:13 mail postfix/smtp[30819]: 0B394F8F5A: to=<user@mydomain.com>, relay=10.1.1.8[10.1.1.8]:25, delay=0.58, delays=0.14/0/0/0.44, dsn=2.6.0, status=sent (250 2.6.0 <20091118121212.2C6BC1A22AC@guard.mydomain.com> Queued mail for delivery)
Nov 18 15:12:13 mail postfix/qmgr[8799]: 0B394F8F5A: removed
--------------------------------
Trace mail with id: E8D1FF8F49
--------------------------------
Nov 18 15:20:01 mail postfix/pickup[31098]: E8D1FF8F49: uid=0 from=<root>
Nov 18 15:20:01 mail postfix/cleanup[308]: E8D1FF8F49: message-id=<20091118122001.E8D1FF8F49@mail.mydomain.com>
Nov 18 15:20:01 mail postfix/qmgr[8799]: E8D1FF8F49: from=<root@mydomain.com>, size=611, nrcpt=1 (queue active)
Nov 18 15:20:02 mail postfix/smtp[336]: E8D1FF8F49: to=<user@mydomain.com>, orig_to=<root>, relay=10.1.1.8[10.1.1.8]:25, delay=0.45, delays=0.12/0/0/0.32, dsn=2.6.0, status=sent (250 2.6.0 <20091118122001.E8D1FF8F49@mail.mydomain.com> Queued mail for delivery)
Nov 18 15:20:02 mail postfix/qmgr[8799]: E8D1FF8F49: removed
======================
Trace time (sec): 18
======================
mail:/home/postadmin #
Пример cкрипта findmail.pl и findmail.sh для трассировки письма по лог-файлам Postfix
(Скачать файл можно будет
здесь. ЗЫ Не тыкать! Жать правой кнопкой: сохранить ссылку как...)
Условия:
Используй: findmail.pl -f|-t e-mail [-d date] [-l logfile] [-r relay]
- -t|-f - поиск по e-mail получателя|отправителя (формат: sample@sample.ru)
- -d - дата (формат:"Mar 10 12:00:00")
- -l - логфайл (формат:/var/log/mail), по умолчанию /var/log/mail
- -r - релей (формат:192.168.1.1|all), по умолчанию 127.0.0.1 (с ключем -f релей игнорируется)
- -h - показать справку
Обязательные параметры: e-mail отправителя или получателя.
Необязательные параметры: дата в формате используемом в лог-файле (например "Mar 10 12:00:00" или "Mar 10 12" и т.д. обязательно в кавычках), логфайл и релей
Пример:
findmail.pl -d "Nov 18 15" -t user@mydomain.com -l /var/log/mail -r all
Текст findmail.pl:
#!/usr/bin/perl -w
#
#Copyright 2010 Konstantin Nadezhdin <w.homenki.ru>
#
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#
use strict;
my($nexts,$ftf,$fd,$fe,$fl,$fltype,$fr,$fn) = ("","","","","/var/log/mail","","all",0);
my($GREP_BIN) = "/usr/bin/grep";
my($tftStr,$OutStr,$Fld,$ID,$IDn,$c_d_expr,$c_d_expr1,$c_d_expr2,$c_d_time,$c_d_time_sek,$ID_COUNT_NOQUEUE);
my($starttime,$worktime) = 0;
my(%ID_COUNT,%c_d_expr,%FILTERED_LOG);
foreach (@ARGV) {
if ($_ eq "-t") {
$nexts = "ft";
} elsif ($_ eq "-f") {
$nexts = "ff";
} elsif ($_ eq "-d") {
$nexts = "fd";
} elsif ($_ eq "-l") {
$nexts = "fl";
} elsif ($_ eq "-r") {
$nexts = "fr";
} elsif ($_ eq "-n") {
$fn = 1;
} elsif ($_ eq "-h") {
die "Используй: -f|-t e-mail [-d date] [-l logfile] [-r relay] [-n] -h
\t-f|-t - поиск по e-mail получателя|отправителя (формат: sample\@sample.ru);
\t-d - дата (формат:\"Mar 10 12:00:00\");
\t-l - логфайл (формат:/var/log/mail), по умолчанию /var/log/mail;
\t-r - релей (формат:192.168.1.1|mx.host.name|all), по умолчанию all (с ключем -f релей игнорируется);
\t-n - только NOQUEUE;
\t-h - показать справку.\n";
} else {
if ($nexts eq "fd") {
($fd = $_) =~ s/ / \?/;
} elsif ($nexts eq "ft") {
$fe = $_; $ftf = "t";
} elsif ($nexts eq "ff") {
$fe = $_; $ftf = "f";
} elsif ($nexts eq "fl") {
$fl = $_;
} elsif ($nexts eq "fr") {
$fr = $_;
}
$nexts = "";
}
}
($fe eq "") && die "Ошибка: e-mail не указан!\n";
if ($fl eq "") {
print "Не указан лог, использую по умолчанию!\n";
$fl = "/var/log/mail";
}
(-e $fl) || die "Ошибка, $fl несуществует или нулевой!\n";
($fltype = $fl) =~ s/^.*\.//;
if ($fltype eq "gz") {
$GREP_BIN="/usr/bin/zgrep";
} elsif ($fltype eq "bz2") {
$GREP_BIN="/usr/bin/bzgrep";
}
if ($fr eq "all" or $ftf eq "f") {
$fr = "";
}
if ($ftf eq "t") {
if ($fn) {
$tftStr = "to=<$fe> proto";
} else {
$tftStr = "to=<$fe>, relay=$fr";
}
} elsif ($ftf eq "f") {
if ($fn) {
$tftStr = "from=<$fe> to=";
} else {
$tftStr = "from=<$fe>, size=";
}
}
$OutStr = " Фильтрация лога. Это может занять некоторое время... ";
echo_for("$OutStr ","=");
print "$OutStr";
$starttime = `date +%s.%N`;
open(LOG,"$GREP_BIN -Ei \"^$fd.* $tftStr\" $fl|") || die "Ошибка $!\n";
while (<LOG>) {
($Fld = (split(/ ?/))[5]) =~ s/:$//;
if ($Fld eq "NOQUEUE") {
$FILTERED_LOG{'NOQUEUE'} .= $_;
$ID_COUNT_NOQUEUE++;
} else {
$ID_COUNT{$Fld}++;
}
}
close(LOG);
$ID = join("|",(keys(%ID_COUNT)));
$ID_COUNT{'NOQUEUE'} = $ID_COUNT_NOQUEUE if (defined($FILTERED_LOG{'NOQUEUE'}));
if ($ID eq "" and ! defined($ID_COUNT{'NOQUEUE'})) { print "Ничего не найдено.\n"; die "$!\n"; }
print "похоже, что-то есть... ";
unless ($ID eq "") {
open(LOG,"$GREP_BIN -Ei \"^$fd.* ($ID):\" $fl|") || die "Ошибка $!\n";
while (<LOG>) {
($Fld = (split(/ ?/))[5]) =~ s/:$//;
if (defined($ID_COUNT{$Fld})) {
$FILTERED_LOG{$Fld} .= $_;
}
}
close(LOG);
}
print "Готово\n";
echo_for("$OutStr ","=");
echo_for2(" Trace mail started with keys:","=");
print "type=$ftf\ndate=$fd\ne-mail=$fe\nlogfile=$fl\nrelay=$fr\n";
foreach (keys(%FILTERED_LOG)) {
$OutStr = " Trace mail with id: $_ ";
echo_for2("$OutStr","-");
print "$FILTERED_LOG{$_}\n";
}
echo_for2(" Traced mail id's: ","-");
foreach (keys(%ID_COUNT)) {
printf("%-10s : %d\n",$_,$ID_COUNT{$_});
}
$worktime = `date -d "-$starttime seconds" "+%s.%N"`;
chomp($worktime);
echo_for2(" Trace time (sec): $worktime ","=");
sub echo_for {
my($a,$b) = @_;
my($strOut) = "";
$strOut = $b x length($a);
print "$strOut\n";
}
sub echo_for2 {
my($a,$b) = @_;
echo_for($a,$b);
print "$a\n";
echo_for($a,$b);
}
Текст findmail.sh:
#!/bin/bash
#
#Copyright 2010 Konstantin Nadezhdin <w.homenki.ru>
#
#This program is free software: you can redistribute it and/or modify
#it under the terms of the GNU General Public License as published by
#the Free Software Foundation, either version 3 of the License, or
#(at your option) any later version.
#
#This program is distributed in the hope that it will be useful,
#but WITHOUT ANY WARRANTY; without even the implied warranty of
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
#GNU General Public License for more details.
#
#You should have received a copy of the GNU General Public License
#along with this program. If not, see <http://www.gnu.org/licenses/>.
#
nexts=""
ftf=""
fd=""
fe=""
fl="/var/log/mail"
fr="127.0.0.1"
for i in "$@"; do
case $i in
-t) nexts="ft";;
-f) nexts="ff";;
-d) nexts="fd";;
-l) nexts="fl";;
-r) nexts="fr";;
-h) echo -e "Используй: $0 (-t e-mail | -f e-mail) -d date [-l logfile] [-r relay]\
\n\t-t|-f - поиск по e-mail получателя|отправителя (формат: sample@sample.ru)\
\n\t-d - дата (формат:\"Mar 10 12:00:00\")\
\n\t-l - логфайл (формат:/var/log/mail), по умолчанию /var/log/mail\
\n\t-r - релей (формат:192.168.1.1|all), по умолчанию 127.0.0.1 (с ключем -f релей игнорируется)\
\n\t-h - показать справку"; exit 0;;
*)
case $nexts in
fd) fd="${i/ / ?}"; nexts="";;
ft) fe="$i"; ftf="t"; nexts="";;
ff) fe="$i"; ftf="f"; nexts="";;
fl) fl="$i"; nexts="";;
fr) fr="$i"; nexts="";;
esac
;;
esac
done
test "$fd" || { echo "Ошибка: дата не указана!"; $0 -h; exit 1; }
test "$fe" || { echo "Ошибка: e-mail не указан!"; $0 -h; exit 1; }
test -s "$fl" || { echo "Логфайл $fl несуществует или нулевой!"; exit 1; }
fltype="${fl##*.}"
case $fltype in
gz) GREP_BIN="/usr/bin/zgrep";;
bz2) GREP_BIN="/usr/bin/bzgrep";;
*) GREP_BIN="/usr/bin/grep";;
esac
test "$fr" = "all" -o "$ftf" = "f" && fr=""
get_logs () {
#c_d=$($GREP_BIN "$1.* postfix/smtpd.* $2: client=" $3)
c_d="$(echo "$3" | grep -E "$1.* postfix/(smtpd.* $2: client|pickup.* $2: uid)=")"
#test "$c_d" = "" && c_d=$($GREP_BIN "$1.* postfix/pickup.* $2: uid=" $3)
test "$c_d" || { echo "Ошибка. Переменная c_d пуста. Попробуй задать другой фильтр."; exit 1; }
#echo "c_d=$c_d"
c_d_expr2="$(echo "$c_d" | awk 'sub(".$","",$3) {print $1" ?"$2" "$3}'). .* $2:"
#echo "c_d_expr2=$c_d_expr2"
c_d_time=$(echo "$c_d" | awk '{print $3}')
#echo "c_d_time=$c_d_time"
c_d_time_sek=$(echo "$c_d_time" | sed "s/.$/\./")
#echo "c_d_time_sek=$c_d_time_sek"
c_d_expr1=$(echo "$c_d" | sed -e "s/ $2: client=/ (connect|disconnect) from /" -e "s/\[/\./g" -e "s/\]/\./g" -e "s/ $c_d_time / $c_d_time_sek /")
#echo "c_d_expr1=$c_d_expr1"
#$GREP_BIN -E "^($c_d_expr1|$c_d_expr2)" $3
echo "$3" | grep -E "^($c_d_expr1|$c_d_expr2)"
}
echo_for () {
lOutStrmax=${#1}
for ((lOutStr=0; lOutStr<lOutStrmax; lOutStr++)); do echo -n "$2"; done
echo ""
}
echo_for2 () {
echo_for "$1" "$2"
echo "$1"
echo_for "$1" "$2"
}
case $ftf in
t) tftStr="to=<$fe>,.* relay=$fr";;
f) tftStr="from=<$fe>,.* size=";;
esac
OutStr=" Фильтрация лога. Это может занять некоторое время... "
echo_for "$OutStr " "="
echo -n "$OutStr"
starttime=$(date +%s.%N)
ID="$($GREP_BIN -E "^$fd.* $tftStr" $fl | awk '{print $6}' | sort -u | sed ':a; s/://g; /$/N; s/\n/ /; ta')"
test "$ID" || { echo -e "Ошибка\n\tФильтр вернул пустой массив (попробуй указать другой фильтр)."; exit 1; }
FILTERED_ID="${ID// /|}"
FILTERED_LOG="$($GREP_BIN -E "^$fd.*($FILTERED_ID):" $fl)"
echo "Готово"
echo_for "$OutStr " "="
echo_for2 " Trace mail started with keys:" "="
echo -e "type=$ftf\ndate=$fd\ne-mail=$fe\nlogfile=$fl\nrelay=$fr"
echo_for2 " Found mail id's: " "-"
echo "$ID" | sed 's/ /\n/g'
for i in $ID
do
#if [ "$mailid1" = "" ]; then
mailidi=$i
#else
#mailidi=$i" "$mailid1
#fi
#echo_for2 " All id's to trace for: $i " "-"
#echo "$mailidi"
OutStr=" Trace mail with id: $i "
for j in $mailidi
do
echo_for2 "$OutStr" "-"
get_logs "$fd" "$j" "$FILTERED_LOG"
done
done
worktime=$(date -d "-$starttime seconds" "+%s.%N")
echo_for2 " Trace time (sec): $worktime " "="
Что нового в этой версии:
Версия 1.3 (Срд Июн 2 2010):
- Переписан на perl;
- Оптимизация bash версии.
Версия 1.2 (Пнд Ноя 30 2009):
- Оптимизирован код для повышения быстродействия, добавлена предварительная фильтрация лога.
Версия 1.1 (Срд Ноя 18 2009):
- Добавлена возможность обрабатывать сжатые логи (gz и bz2);
- Добавлен поиск по адресу отправителя.
Версия 1.0:
- Первый релиз.