20
20
#-------------------------------------------------------
21
21
use vars qw/ $REVISION $VERSION /;
22
$REVISION='$Revision: 1.22 $'; $REVISION =~ /\s(.*)\s/; $REVISION=$1;
23
$VERSION="1.1 (build $REVISION)";
22
$REVISION='$Revision: 1.31 $'; $REVISION =~ /\s(.*)\s/; $REVISION=$1;
23
$VERSION="1.2 (build $REVISION)";
26
26
$DIR $PROG $Extension
28
28
%mail %qmaildelivery
30
$mode $year $lastmon $Debug
35
$NBOFENTRYFOFLUSH=8192; # Nb or records for flush of %entry (Must be a power of 2)
36
$NBOFENTRYFOFLUSH=16384; # Nb or records for flush of %entry (Must be a power of 2)
36
37
$MailType=''; # Mail server family (postfix, sendmail, qmail)
39
54
#-------------------------------------------------------
115
130
# Clean day and month
116
131
$day=sprintf("%02d",$day);
117
if ($month eq 'Jan') { $month = "01"; }
118
if ($month eq 'Feb') { $month = "02"; }
119
if ($month eq 'Mar') { $month = "03"; }
120
if ($month eq 'Apr') { $month = "04"; }
121
if ($month eq 'May') { $month = "05"; }
122
if ($month eq 'Jun') { $month = "06"; }
123
if ($month eq 'Jul') { $month = "07"; }
124
if ($month eq 'Aug') { $month = "08"; }
125
if ($month eq 'Sep') { $month = "09"; }
126
if ($month eq 'Oct') { $month = "10"; }
127
if ($month eq 'Nov') { $month = "11"; }
128
if ($month eq 'Dec') { $month = "12"; }
132
$month=sprintf("%02d",$MonthNum{$month}||$month);
131
135
$from=&CleanEmail($from);
234
249
elsif (/: client=/) {
235
250
$MailType||='postfix';
236
my ($id,$relay_s)=m/\w+\s+\d+\s+\d+:\d+:\d+\s+[\w\-]+\s+(?:sendmail|postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[\d+\]:\s+(.*?):\s+client=(.*)/;
252
# postfix: Jan 01 07:27:32 apollon.com postfix/smtpd[1684]: 2BC793B8A4: client=remt30.cluster1.abcde.net[209.225.8.40]
253
my ($id,$relay_s)=m/\w+\s+\d+\s+\d+:\d+:\d+\s+[\w\-\.\@]+\s+(?:sendmail|postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[\d+\]:\s+(.*?):\s+client=(.*)/;
238
255
$mail{$id}{'relay_s'}=$relay_s;
239
256
debug("For id=$id, found host sender on a 'client' line: $mail{$id}{'relay_s'}");
245
262
elsif (/: reject/) {
246
263
$MailType||='postfix';
248
# postfix: Jan 01 04:19:04 apollon postfix/smtpd[26553]: 1954F3B8A4: reject: RCPT from unknown[80.245.33.2]: 450 <partenaires@chiensderace.com>: User unknown in local recipient table; from=<httpd@fozzy2.dpi-europe.fr> to=<partenaires@chiensderace.com> proto=ESMTP helo=<fozzy2.dpi-europe.fr>
249
# postfix: Jan 01 04:26:39 halley postfix/smtpd[9245]: reject: RCPT from unknown[203.156.32.33]: 554 <charitha99@yahoo.com>: Recipient address rejected: Relay access denied; from=<1126448365@aol.com> to=<charitha99@yahoo.com>
250
my ($mon,$day,$time,$id,$code,$from,$to)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[\d+\]:\s+(.*?):\s+(.*)\s+from=([^\s,]*)\s+to=([^\s,]*)/;
251
$mailid=($id eq 'reject'?'999':$id); # id not provided in log, we take '999'
252
# $code='reject: RCPT from c66.191.66.89.dul.mn.charter.com[66.191.66.89]: 450 <partenaires@chiensderace.com>: User unknown in local recipient table;'
253
# or 'reject: RCPT from unknown[203.156.32.33]: 554 <charitha99@yahoo.com>: Recipient address rejected: Relay access denied;'
265
# postfix ?.? : Jan 01 12:00:00 halley postfix/smtpd[9245]: reject: RCPT from unknown[203.156.32.33]: 554 <userx@yahoo.com>: Recipient address rejected: Relay access denied; from=<sender@aol.com> to=<userx@yahoo.com>
266
# postfix 2.1+: Jan 01 12:00:00 localhost postfix/smtpd[11120]: NOQUEUE: reject: RCPT from unknown[62.205.124.145]: 450 Client host rejected: cannot find your hostname, [62.205.124.145]; from=<sender@msn.com> to=<usery@yahoo.com> proto=ESMTP helo=<xxx.com>
267
# postfix ?.? : Jan 01 12:00:00 apollon postfix/smtpd[26553]: 1954F3B8A4: reject: RCPT from unknown[80.245.33.2]: 450 <usery@yahoo.com>: User unknown in local recipient table; from=<sender@msn.com> to=<usery@yahoo.com> proto=ESMTP helo=<xxx.com>
268
my ($mon,$day,$time,$id,$code,$from,$to)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-\.\@]+\s+(?:postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[\d+\]:\s+(.*?):\s+(.*)\s+from=([^\s,]*)\s+to=([^\s,]*)/;
269
# postfix: Jan 01 14:10:16 juni postfix/smtpd[2568]: C34ED1432B: reject: RCPT from relay2.tp2rc.edu.tw[163.28.32.177]: 450 <linda@trieger.org>: User unknown in local recipient table; from=<> proto=ESMTP helo=<rmail.nccu.edu.tw>
270
if (! $mon) { ($mon,$day,$time,$id,$code,$from)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-\.\@]+\s+(?:postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[\d+\]:\s+(.*?):\s+(.*)\s+from=([^\s,]*)/; }
271
$mailid=($id eq 'reject' || $id eq 'NOQUEUE'?'999':$id); # id not provided in log, we take '999'
273
# $code='reject: RCPT from unknown[203.156.32.33]: 554 <userx@yahoo.com>: Recipient address rejected: Relay access denied;'
274
# or 'reject: RCPT from unknown[62.205.124.145]: 450 Client host rejected: cannot find your hostname, [62.205.124.145]; from=<sender@msn.com> to=<usery@yahoo.com> proto=ESMTP helo=<xxx.com>'
275
# or 'reject: RCPT from unknown[80.245.33.2]: 450 <usery@yahoo.com>: User unknown in local recipient table;'
255
276
if ($code =~ /\s+(\d\d\d)\s+/) { $mail{$mailid}{'code'}=$1; }
256
277
else { $mail{$mailid}{'code'}=999; } # Unkown error
257
if (! $mail{$mailid}{'relay_s'} && $code =~ /from\s+([^\s]+)\s+/) {
278
if (! $mail{$mailid}{'relay_s'} && $code =~ /from\s+([^\s]+)\s+/) {
258
279
$mail{$mailid}{'relay_s'}=&trim($1);
260
281
$mail{$mailid}{'from'}=&trim($from);
261
$mail{$mailid}{'to'}=&trim($to);
283
$mail{$mailid}{'to'}=&trim($to);
285
elsif ($code =~ /<(.*)>/) {
286
$mail{$mailid}{'to'}=&trim($1);
288
$mail{$mailid}{'year'}=$year; ### <CJK>###
262
289
$mail{$mailid}{'mon'}=$mon;
263
290
$mail{$mailid}{'day'}=$day;
264
291
$mail{$mailid}{'time'}=$time;
273
300
$MailType||='postfix';
275
302
# postfix: Sep 9 18:24:23 halley postfix/local[22003]: 12C6413EC9: to=<etavidian@partenor.com>, relay=local, delay=0, status=bounced (unknown user: "etavidian")
276
my ($mon,$day,$time,$id,$to,$relay_r)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[\d+\]:\s+(.*?):\s+to=([^\s,]*)[\s,]+relay=([^\s,]*)/;
303
my ($mon,$day,$time,$id,$to,$relay_r)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-\.\@]+\s+(?:postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[\d+\]:\s+(.*?):\s+to=([^\s,]*)[\s,]+relay=([^\s,]*)/;
277
304
$mailid=($id eq 'reject'?'999':$id); # id not provided in log, we take '999'
279
306
$mail{$mailid}{'code'}=999; # Unkown error (bounced)
280
307
$mail{$mailid}{'to'}=&trim($to);
281
308
$mail{$mailid}{'relay_r'}=&trim($relay_r);
309
$mail{$mailid}{'year'}=$year; ### <CJK>###
282
310
$mail{$mailid}{'mon'}=$mon;
283
311
$mail{$mailid}{'day'}=$day;
284
312
$mail{$mailid}{'time'}=$time;
299
327
# sendmail: Jan 10 07:37:48 smtp sendmail[32440]: ruleset=check_relay, arg1=[211.228.26.114], arg2=211.228.26.114, relay=[211.228.26.114], reject=554 5.7.1 Rejected 211.228.26.114 found in dnsbl.sorbs.net
300
328
# sendmail: Jan 10 07:37:08 smtp sendmail[32439]: ruleset=check_relay, arg1=235.Red-213-97-175.pooles.rima-tde.net, arg2=213.97.175.235, relay=235.Red-213-97-175.pooles.rima-tde.net [213.97.175.235], reject=550 5.7.1 Mail from 213.97.175.235 refused. Rejected for bad WHOIS info on IP of your SMTP server - see http://www.rfc-ignorant.org/
301
329
# sendmail: Jan 10 17:15:42 smtp sendmail[12770]: ruleset=check_relay, arg1=[63.218.84.21], arg2=63.218.84.21, relay=[63.218.84.21], reject=553 5.3.0 Rejected - see http://spamhaus.org/
302
my ($mon,$day,$time,$id,$ruleset,$arg,$relay_s,$code)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:sendmail|sm-mta)\[\d+\][:\s]*(.*?):\sruleset=(\w+),\s+arg1=(.*),\s+relay=(.*),\s+(reject=.*)/;
330
my ($mon,$day,$time,$id,$ruleset,$arg,$relay_s,$code)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-\.\@]+\s+(?:sendmail|sm-mta)\[\d+\][:\s]*(.*?):\sruleset=(\w+),\s+arg1=(.*),\s+relay=(.*),\s+(reject=.*)/;
303
331
# sendmail: Jan 10 18:00:34 smtp sendmail[5759]: i04Axx2c005759: Milter: data, reject=511 Virus found in email!
304
if (! $mon) { ($mon,$day,$time,$id,$ruleset,$code)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:sendmail|sm-mta)\[\d+\]:\s+(.*?):\s\w+:\s(\w+),\s+(reject=.*)/; }
332
if (! $mon) { ($mon,$day,$time,$id,$ruleset,$code)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-\.\@]+\s+(?:sendmail|sm-mta)\[\d+\]:\s+(.*?):\s\w+:\s(\w+),\s+(reject=.*)/; }
305
333
$mailid=(! $id && $mon?'999':$id); # id not provided in log, we take '999'
307
335
if ($ruleset eq 'check_mail') { $mail{$mailid}{'from'}=$arg; }
312
340
# $code='reject=550 5.7.1 <amber3624@netzero.net>... Relaying denied'
313
341
if ($code =~ /=(\d\d\d)\s+/) { $mail{$mailid}{'code'}=$1; }
314
342
else { $mail{$mailid}{'code'}=999; } # Unkown error
343
$mail{$mailid}{'year'}=$year; ### <CJK>###
315
344
$mail{$mailid}{'mon'}=$mon;
316
345
$mail{$mailid}{'day'}=$day;
317
346
$mail{$mailid}{'time'}=$time;
329
358
# Matched outgoing sendmail/postfix message
331
my ($mon,$day,$time,$id,$to,$from)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:sm-mta|sendmail(?:-out|)|postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[.*?\]:\s+([^:]*):\s+to=(.*?)[,\s]+ctladdr=([^\,\s]*)/;
360
my ($mon,$day,$time,$id,$to,$fromorto)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-\.\@]+\s+(?:sm-mta|sendmail(?:-out|)|postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[.*?\]:\s+([^:]*):\s+to=(.*?)[,\s]+ctladdr=([^\,\s]*)/;
333
362
if (m/\s+relay=([^\s,]*)[\s,]/) { $mail{$id}{'relay_r'}=$1; }
334
363
elsif (m/\s+mailer=local/) { $mail{$id}{'relay_r'}='localhost'; }
337
366
elsif (/, stat\=Local\s+configuration/) { $mail{$id}{'code'}=451; }
338
367
elsif (/, stat\=Deferred:\s+(\d*)/) { $mail{$id}{'code'}=$1; }
339
368
else { $mail{$id}{'code'}=999; }
369
$mail{$mailid}{'year'}=$year; ### <CJK>###
340
370
$mail{$id}{'mon'}=$mon;
341
371
$mail{$id}{'day'}=$day;
342
372
$mail{$id}{'time'}=$time;
343
$mail{$id}{'to'}=&trim($to);
344
$mail{$id}{'from'}=&trim($from);
373
if (&trim($to)=~/^|/) {
374
# In particular case of mails are sent to a pipe, the ctladdr contains the to
375
$mail{$id}{'to'}=&trim($fromorto);
378
$mail{$id}{'to'}=&trim($to);
379
$mail{$id}{'from'}=&trim($fromorto);
345
381
if (! defined($mail{$id}{'size'})) { $mail{$id}{'size'}='?'; }
346
382
debug("For id=$id, found a sendmail outgoing message: to=$mail{$id}{'to'} from=$mail{$id}{'from'} size=$mail{$id}{'size'} relay_r=".($mail{$id}{'relay_r'}||''));
352
388
elsif (/info msg .* from/) {
353
389
# Example: Sep 14 09:58:09 gandalf qmail: 1063526289.292776 info msg 270182: bytes 10712 from <john@john.do> qp 54945 uid 82
354
390
$MailType||='qmail';
355
#my ($id,$size,$from)=m/(\d+)(?:\.\d+)? info msg \d+: bytes (\d+) from <(.*)>/;
356
my ($id,$size,$from)=m/\d+(?:\.\d+)? info msg (\d+): bytes (\d+) from <(.*)>/;
391
#my ($id,$size,$from)=m/info msg \d+: bytes (\d+) from <(.*)>/;
392
my ($id,$size,$from)=m/info msg (\d+): bytes (\d+) from <(.*)>/;
358
394
delete $mail{$mailid}; # If 'info msg' found, we start a new mail. This is to protect from wrong file
359
395
if (! $mail{$id}{'from'} || $mail{$id}{'from'} ne '<>') { $mail{$id}{'from'}=$from; } # TODO ???
369
405
# sm-mta: Jul 28 06:55:13 androneda sm-mta[28877]: h6SDtCtg028877: from=<xxx@mysite.net>, size=2556, class=0, nrcpts=1, msgid=<w1$kqj-9-o2m45@0h2i38.4.m0.5u>, proto=ESMTP, daemon=MTA, relay=smtp.easydns.com [205.210.42.50]
370
406
# postfix: Jul 3 15:32:26 apollon postfix/qmgr[13860]: 08FB63B8A4: from=<nobody@ns3744.ovh.net>, size=3302, nrcpt=1 (queue active)
371
407
# postfix: Sep 24 14:45:15 wideboy postfix/qmgr[22331]: 7E0E6196: from=<xxx@hotmail.com>, size=1141 (queue active)
372
my ($id,$from,$size)=m/\w+\s+\d+\s+\d+:\d+:\d+\s+[\w\-]+\s+(?:sm-mta|sendmail(?:-in|)|postfix\/qmgr|postfix\/nqmgr)\[\d+\]:\s+(.*?):\s+from=(.*?),\s+size=(\d+)/;
408
my ($id,$from,$size)=m/\w+\s+\d+\s+\d+:\d+:\d+\s+[\w\-\.\@]+\s+(?:sm-mta|sendmail(?:-in|)|postfix\/qmgr|postfix\/nqmgr)\[\d+\]:\s+(.*?):\s+from=(.*?),\s+size=(\d+)/;
374
410
if (! $mail{$id}{'code'}) { $mail{$id}{'code'}=1; } # If not already defined, we define it
375
411
if (! $mail{$id}{'from'} || $mail{$id}{'from'} ne '<>') { $mail{$id}{'from'}=$from; }
382
418
# Matched exchange message
384
elsif (/^([^\t]+)\t([^\t]+)\t[^\t]+\t([^\t]+)\t([^\t]+)\t([^\t]+)\t[^\t]+\t([^\t]+)\t([^\t]+)\t([^\t]+)\t[^\t]+\t[^\t]+\t([^\t]+)\t[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+\t([^\t]+)/) {
385
# date hour GMT ip_s relay_s partner relay_r ip_r to code id size from
420
elsif (/^([^\t]+)\t([^\t]+)\t[^\t]+\t([^\t]+)\t([^\t]+)\t([^\t]+)\t[^\t]+\t([^\t]+)\t([^\t]+)\t([^\t]+)\t[^\t]+\t[^\t]+\t([^\t]+)\t[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+\t[^\t]+\t([^\t]+)\t([^\t]+)/) {
421
# date hour GMT ip_s relay_s partner relay_r ip_r to code id size subject from
386
422
# Example: 2003-8-12 0:58:14 GMT 66.218.66.69 n14.grp.scd.yahoo.com - PACKRAT 192.168.1.2 christina@pirnie.org 1019 bh9e3f+5qvo@eGroups.com 0 0 4281 1 2003-8-12 0:58:14 GMT 0 Version: 6.0.3790.0 - [SRESafeHaven] Re: More Baby Stuff jtluvs2cq@wmconnect.com -
387
423
$MailType||='exchange';
397
my $from=$10; $from =~ s/\s/%20/g;
433
my $subject=&trim($10);
434
my $from=$11; $from =~ s/\s/%20/g;
435
$id=sprintf("%s_%s_%s",$id,$from,$to);
398
436
# Check if record is significant record
400
# Code 1031=end outbound transfer
401
if ($code == 1031) { # This is outbound mail
403
#my $savrelay_s=$relay_s;
404
#$relay_s=$relay_r; $relay_r=$savrelay_s;
409
# Code 1023=SMTP local delivery
410
if ($code == 1023) { # This is inbound ???
439
# Code 1031=SMTP End Outbound Transfer
440
if ($code == 1031) { # This is for external bound mails
442
my $savrelay_s=$relay_s;
443
$relay_s=$relay_r; $relay_r=$savrelay_s;
448
# Code 1028=SMTP Store Driver: Message Delivered Locally to Store
449
if ($code == 1028) { # This is for local bound mails
453
# Code 1030=SMTP: Non-Delivered Report (NDR) Generated
454
if ($code == 1030) { # This is for errors.
459
if ($ok && !$mail{$id}{'code'} ) {
416
461
if ($date =~ /(\d+)-(\d+)-(\d+)/) {
417
462
$mail{$id}{'year'}=sprintf("%02s",$1);
421
466
if ($time =~ /^(\d+):(\d+):(\d+)/) {
422
467
$mail{$id}{'time'}=sprintf("%02s:%02s:%02s",$1,$2,$3);
469
if ( $from eq '<>' && $subject =~ /^Delivery\s+Status/) {
470
$from='postmaster@localhost';
424
472
$mail{$id}{'from'}=$from;
425
473
$mail{$id}{'to'}=$to;
426
474
$mail{$id}{'code'}=$code;
435
# Matched sendmail/postfix "to" message
483
# Matched sendmail or postfix "to" message
437
485
elsif (/: to=.*stat(us)?=sent/i) {
438
my ($mon,$day,$time,$id,$to)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-]+\s+(?:sm-mta|sendmail(?:-out|)|postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[.*?\]:\s+(.*?):\s+to=(.*?),/;
487
# postfix: Jan 01 07:27:38 apollon postfix/local[1689]: 2BC793B8A4: to=<jo@jo.com>, orig_to=<webmaster@toto.com>, relay=local, delay=6, status=sent ("|/usr/bin/procmail")
488
my ($mon,$day,$time,$id,$to)=m/(\w+)\s+(\d+)\s+(\d+:\d+:\d+)\s+[\w\-\.\@]+\s+(?:sm-mta|sendmail(?:-out|)|postfix\/(?:local|lmtp|smtpd|smtp|virtual|pipe))\[.*?\]:\s+(.*?):\s+to=(.*?),/;
440
490
$mail{$id}{'code'}='1';
441
491
if (m/\s+relay=([^\s,]*)[\s,]/) { $mail{$id}{'relay_r'}=$1; }