#!/usr/bin/perl # $Id: maillog_search,v 1.3 2007/01/29 16:24:36 hutch Exp $ use strict; use warnings; use File::Copy; use File::Temp qw/ tempfile tempdir /; use Getopt::Long; use PerlIO::gzip; # For command-line arguments my @cmd_arg_from; my $cmd_arg_from; my @cmd_arg_to; my $cmd_arg_to; my @cmd_arg_both; my $cmd_arg_both; my @cmd_arg_relay; my $cmd_arg_relay; my $match; my $count_only; my $queue_id_order; my $chronological_order; my $output_file; my $count = 0; GetOptions( "from=s" => \@cmd_arg_from, "to=s" => \@cmd_arg_to, "both=s" => \@cmd_arg_both, "relay=s" => \@cmd_arg_relay, "match!" => \$match, "count-only" => \$count_only, "queue-id-order" => \$queue_id_order, "chronological_order" => \$chronological_order, "output-file:s" => \$output_file); if (! @ARGV) { &print_usage; exit 1; } sub print_usage { (my $basename = $0) =~ s!^.*/!!; print "Usage: $basename [OPTION]... [FILE]...\n"; print "\nMandatory options:\n"; printf "%-21s %-s\n", "--from", "search envelope sender address"; printf "%-21s %-s\n", "--to", "search envelope recipient address(es)"; printf "%-21s %-s\n", "--both", "search envelope sender and envelope recipient address(es)"; printf "%-21s %-s\n", "--relay", "search relay IP"; printf "%-21s %-s\n", "[FILE]...", "one or more maillogs in plaintext or gzip format"; print "\nDefault options:\n"; printf "%-21s %-s\n", "--match", "return all log information with the same queue ID"; printf "%-21s %-s\n", "--chronological-order", "return information in chronological order"; print "\nNon-default options:\n"; printf "%-21s %-s\n", "--no-match", "only loop through the maillog(s) once"; printf "%-21s %-s\n", "--queue-id-order", "return information sorted by queue ID"; printf "%-21s %-s\n", "--output-file", "save results to a file"; printf "%-21s %-s\n", "--count-only", "return only the number of matches"; exit 1 } $cmd_arg_from = join "|", @cmd_arg_from; $cmd_arg_to = join "|", @cmd_arg_to; $cmd_arg_both = join "|", @cmd_arg_both; $cmd_arg_relay = join "|", @cmd_arg_relay; my ($fh, $filename) = tempfile(); open TMPFILE, ">$filename" or die "Error opening $filename: $!"; # Defaults $match = 1 if (! defined $match); $chronological_order = 1 if (! defined $queue_id_order); if ($output_file) { open OUTPUT_FILE, ">$output_file" or die "Cannot open $output_file: $!"; } sub open_maillog { my $maillog = $_[0]; if ( $maillog =~ /\.gz/i ) { open MAILLOG, "<:gzip", "$maillog" or warn "Error opening $maillog: $!"; } else { open MAILLOG, "<$maillog" or warn "Error opening $maillog: $!"; } } foreach my $maillog(@ARGV) { my %find_queue_id; &open_maillog($maillog); # "--match" -- Create a list of queue IDs # "--no-match -- Print the line while() { chomp; if ($cmd_arg_both) { # Find messages from or to $cmd_arg_both if (( /\s(\w{14}):\s(from|to)=?,\s/ ) || ( /\s(\w{14}):\sruleset=check_(mail|rcpt),\sarg1=<(.*?)>,\s/ )) { my $queue_id = $1; my $from_or_to = $3; if ($from_or_to =~ /$cmd_arg_both/i) { $count++; $find_queue_id{$queue_id} = 1 if ($match); if ((! $match) && (! $count_only)) { print TMPFILE "$_\n"; } } } } if (($cmd_arg_from) && (! $cmd_arg_both)) { if (( /\s(\w{14}):\sfrom=?,\s/ ) || ( /\s(\w{14}):\sruleset=check_mail,\sarg1=<(.*?)>,\s/ )) { my $queue_id = $1; my $from = $2; if ($from =~ /$cmd_arg_from/i) { # Only increment $count if we are not searching from and to $count++; $find_queue_id{$queue_id} = 1 if ($match); if ((! $match) && (! $count_only)) { print TMPFILE "$_\n"; } } } } # Don't bother gathering this list of queue IDs if "from" and "to" # were specified on the command line. if (($cmd_arg_to) && (! $cmd_arg_both)) { if (( /\s(\w{14}):\sto=?,\s/ ) || ( /\s(\w{14}):\sruleset=check_rcpt,\sarg1=<(.*?)>,\s/ )) { my $queue_id = $1; my $to = $2; if ($to =~ /$cmd_arg_to/i) { $count++; $find_queue_id{$queue_id} = 1 if ($match); if ((! $match) && (! $count_only)) { print TMPFILE "$_\n"; } } } } if ($cmd_arg_relay) { # Return relay= information with a queue ID # check_mail and check_rcpt include a queue ID # Also catch "k1G8Ombr014697: localhost [127.0.0.1] did not issue" messages if ((/\s(\w{14}):\s.*,\srelay=(.*?)\]/) || ( /\s(\w{14}):\s(.*?)did not issue/)) { my $queue_id = $1; my $relay = $2; if ($relay =~ /$cmd_arg_relay/i) { $count++; $find_queue_id{$queue_id} = 1 if ($match); if ((! $match) && (! $count_only)) { print TMPFILE "$_\n"; } } } # Return relay= information without a queue ID # check_relay, tls_server, STARTTLS do not have a queue ID # , relay=hostname, # , relay=hostname [IP_address]$ # , relay=hostname [IP_address], if ((/,\srelay=(.*?)(\]|,)/) && (! /\s\w{14}:\s/ )) { my $relay = $1; if ($relay =~ /$cmd_arg_relay/i) { print TMPFILE "$_\n" if (! $count_only); } } } } close MAILLOG; if (($match) && (! $count_only)) { open_maillog($maillog); while() { chomp; if (/\s(\w{14}):/) { my $queue_id = $1; if ($find_queue_id{$queue_id}) { print TMPFILE "$_\n"; } } } } } close TMPFILE; if (! $count_only) { if ($chronological_order) { my $first_line = 1; foreach (`sort $filename`) { chomp; if ($output_file) { if (! $first_line) { print OUTPUT_FILE "\n$_\n"; } else { print OUTPUT_FILE "$_\n"; } } else { if (! $first_line) { print "\n$_\n"; } else { print "$_\n"; } } $first_line = 0; } } elsif ($queue_id_order) { my %seen_queue_id; my $first_line = 1; foreach (`sort -k 9 $filename | uniq`) { chomp; if (/\s(\w{14}):/) { my $queue_id = $1; if ($seen_queue_id{$queue_id}) { if ($output_file) { print OUTPUT_FILE "$_\n"; } else { print "$_\n"; } } else { $seen_queue_id{$queue_id} = 1; if (! $first_line) { if ($output_file) { print OUTPUT_FILE "\n$_\n"; } else { print "\n$_\n"; } } } } $first_line = 0; } } } else { print "$count\n"; }