Edit File by line
/home/barbar84/public_h.../wp-conte.../plugins/sujqvwi/ExeBy/smexe_ro.../opt/sharedra...
File: msp.pl
#!/usr/local/cpanel/3rdparty/bin/perl
[0] Fix | Delete
package MSP;
[1] Fix | Delete
[2] Fix | Delete
use strict;
[3] Fix | Delete
use warnings;
[4] Fix | Delete
[5] Fix | Delete
use Getopt::Long;
[6] Fix | Delete
use Cpanel::AdvConfig::dovecot ();
[7] Fix | Delete
use Cpanel::FileUtils::Dir ();
[8] Fix | Delete
use Cpanel::IONice ();
[9] Fix | Delete
use Cpanel::IO ();
[10] Fix | Delete
use Term::ANSIColor qw{:constants};
[11] Fix | Delete
[12] Fix | Delete
# Variables
[13] Fix | Delete
our $VERSION = '2.1';
[14] Fix | Delete
[15] Fix | Delete
$Term::ANSIColor::AUTORESET = 1;
[16] Fix | Delete
[17] Fix | Delete
our $LOGDIR = q{/var/log/};
[18] Fix | Delete
our $CPANEL_CONFIG_FILE = q{/var/cpanel/cpanel.config};
[19] Fix | Delete
our $EXIM_LOCALOPTS_FILE = q{/etc/exim.conf.localopts};
[20] Fix | Delete
our $DOVECOT_CONF = q{/var/cpanel/conf/dovecot/main};
[21] Fix | Delete
[22] Fix | Delete
our $EXIM_MAINLOG = q{exim_mainlog};
[23] Fix | Delete
our $MAILLOG = q{maillog};
[24] Fix | Delete
[25] Fix | Delete
our @RBLS = qw{ b.barracudacentral.org
[26] Fix | Delete
bl.spamcop.net
[27] Fix | Delete
dnsbl.sorbs.net
[28] Fix | Delete
spam.dnsbl.sorbs.net
[29] Fix | Delete
ips.backscatterer.org
[30] Fix | Delete
zen.spamhaus.org
[31] Fix | Delete
};
[32] Fix | Delete
[33] Fix | Delete
# Initialize
[34] Fix | Delete
our $LIMIT = 10;
[35] Fix | Delete
our $THRESHOLD = 1;
[36] Fix | Delete
our $ROTATED_LIMIT = 5; # I've seen users with hundreds of rotated logs before, we should safeguard to prevent msp from working against unreasonably large data set
[37] Fix | Delete
our $OPT_TIMEOUT;
[38] Fix | Delete
[39] Fix | Delete
# Options
[40] Fix | Delete
my %opts;
[41] Fix | Delete
my ( $all, $auth, $conf, $forwards, $help, $limit, $logdir, $queue, @rbl, $rbllist, $rotated, $rude, $threshold, $verbose );
[42] Fix | Delete
GetOptions(
[43] Fix | Delete
\%opts,
[44] Fix | Delete
'all',
[45] Fix | Delete
'auth',
[46] Fix | Delete
'forwards',
[47] Fix | Delete
'help',
[48] Fix | Delete
'conf',
[49] Fix | Delete
'limit=i{1}',
[50] Fix | Delete
'logdir=s{1}',
[51] Fix | Delete
'maillog',
[52] Fix | Delete
'queue',
[53] Fix | Delete
'rbl=s',
[54] Fix | Delete
'rbllist',
[55] Fix | Delete
'rotated',
[56] Fix | Delete
'rude',
[57] Fix | Delete
'threshold=i{1}',
[58] Fix | Delete
'verbose'
[59] Fix | Delete
) or die("Please see --help\n");
[60] Fix | Delete
[61] Fix | Delete
# Make this a modulino
[62] Fix | Delete
__PACKAGE__->main(@ARGV) unless caller();
[63] Fix | Delete
1;
[64] Fix | Delete
[65] Fix | Delete
sub print_help {
[66] Fix | Delete
print BOLD BRIGHT_BLUE ON_BLACK "[MSP-$VERSION] ";
[67] Fix | Delete
print BOLD WHITE ON_BLACK "Mail Status Probe: Mail authentication statistics and configuration checker\n";
[68] Fix | Delete
print "Usage: ./msp.pl --auth --rotated --rude\n";
[69] Fix | Delete
print " ./msp.pl --conf --rbl [all|bl.spamcop.net,zen.spamhaus.org]\n\n";
[70] Fix | Delete
printf( "\t%-15s %s\n", "--help", "print this help message");
[71] Fix | Delete
# printf( "\t%-15s %s\n", "--all", "run all checks");
[72] Fix | Delete
printf( "\t%-15s %s\n", "--auth", "print mail authentication statistics");
[73] Fix | Delete
printf( "\t%-15s %s\n", "--conf", "print mail configuration info (e.g. require_secure_auth, smtpmailgidonly, etc.)");
[74] Fix | Delete
# printf( "\t%-15s %s\n", "--forwards", "print forward relay statistics");
[75] Fix | Delete
# printf( "\t%-15s %s\n", "--ignore", "ignore common statistics (e.g. cwd=/var/spool/exim)");
[76] Fix | Delete
printf( "\t%-15s %s\n", "--limit", "limit statistics checks to n results (defaults to 10, set to 0 for no limit)");
[77] Fix | Delete
printf( "\t%-15s %s\n", "--logdir", "specify an alternative logging directory, (defaults to /var/log)");
[78] Fix | Delete
printf( "\t%-15s %s\n", "--maillog", "check maillog for common errors");
[79] Fix | Delete
printf( "\t%-15s %s\n", "--queue", "print exim queue length");
[80] Fix | Delete
# printf( "\t%-15s %s\n", "--quiet", "only print alarming information or statistics (requires --threshold)");
[81] Fix | Delete
printf( "\t%-15s %s\n", "--rbl", "check IP's against provided blacklists(comma delimited)");
[82] Fix | Delete
printf( "\t%-15s %s\n", "--rbllist", "list available RBL's");
[83] Fix | Delete
printf( "\t%-15s %s\n", "--rotated", "check rotated exim logs");
[84] Fix | Delete
printf( "\t%-15s %s\n", "--rude", "forgo nice/ionice settings");
[85] Fix | Delete
printf( "\t%-15s %s\n", "--threshold", "limit statistics output to n threshold(defaults to 1)");
[86] Fix | Delete
printf( "\t%-15s %s\n", "--verbose", "display all information");
[87] Fix | Delete
print "\n";
[88] Fix | Delete
exit;
[89] Fix | Delete
}
[90] Fix | Delete
[91] Fix | Delete
sub main {
[92] Fix | Delete
die "MSP must be run as root\n" if ( $< != 0 );
[93] Fix | Delete
[94] Fix | Delete
print_help() if ( (!%opts) || ($opts{help}) );
[95] Fix | Delete
[96] Fix | Delete
conf_check() if ($opts{conf});
[97] Fix | Delete
[98] Fix | Delete
print_exim_queue() if ($opts{queue});
[99] Fix | Delete
[100] Fix | Delete
auth_check() if ($opts{auth});
[101] Fix | Delete
[102] Fix | Delete
maillog_check() if ($opts{maillog});
[103] Fix | Delete
[104] Fix | Delete
rbl_list() if ($opts{rbllist});
[105] Fix | Delete
[106] Fix | Delete
rbl_check($opts{rbl}) if ($opts{rbl});
[107] Fix | Delete
return;
[108] Fix | Delete
}
[109] Fix | Delete
[110] Fix | Delete
sub conf_check {
[111] Fix | Delete
# Check Tweak Settings
[112] Fix | Delete
print_bold_white("Checking Tweak Settings...\n");
[113] Fix | Delete
print "--------------------------\n";
[114] Fix | Delete
my %cpconf = get_conf( $CPANEL_CONFIG_FILE );
[115] Fix | Delete
if ( $cpconf{'smtpmailgidonly'} ne 1 ) {
[116] Fix | Delete
print_warn("Restrict outgoing SMTP to root, exim, and mailman (FKA SMTP Tweak) is disabled!\n");
[117] Fix | Delete
} elsif ( $opts{verbose} ) {
[118] Fix | Delete
print_info("Restrict outgoing SMTP to root, exim, and mailman (FKA SMTP Tweak) is enabled\n");
[119] Fix | Delete
}
[120] Fix | Delete
if ( $cpconf{'nobodyspam'} ne 1 ) {
[121] Fix | Delete
print_warn("Prevent “nobody” from sending mail is disabled!\n");
[122] Fix | Delete
} elsif ( $opts{verbose} ) {
[123] Fix | Delete
print_info("Prevent “nobody” from sending mail is enabled\n");
[124] Fix | Delete
}
[125] Fix | Delete
if ( $cpconf{'popbeforesmtp'} ne 0 ) {
[126] Fix | Delete
print_warn("Pop-before-SMTP is enabled!\n");
[127] Fix | Delete
} elsif ( $opts{verbose} ) {
[128] Fix | Delete
print_info("Pop-before-SMTP is disabled\n");
[129] Fix | Delete
}
[130] Fix | Delete
if ( $cpconf{'domainowner_mail_pass'} ne 0 ) {
[131] Fix | Delete
print_warn("Mail authentication via domain owner password is enabled!\n");
[132] Fix | Delete
} elsif ( $opts{verbose} ) {
[133] Fix | Delete
print_info("Mail authentication via domain owner password is disabled\n");
[134] Fix | Delete
}
[135] Fix | Delete
print "\n";
[136] Fix | Delete
[137] Fix | Delete
# Check Exim Configuration
[138] Fix | Delete
print_bold_white("Checking Exim Configuration...\n");
[139] Fix | Delete
print "------------------------------\n";
[140] Fix | Delete
my %exim_localopts_conf = get_conf( $EXIM_LOCALOPTS_FILE );
[141] Fix | Delete
if ( $exim_localopts_conf{'allowweakciphers'} ne 0 ) {
[142] Fix | Delete
print_warn("Allow weak SSL/TLS ciphers is enabled!\n");
[143] Fix | Delete
} elsif ( $opts{verbose} ) {
[144] Fix | Delete
print_info("Allow weak SSL/TLS ciphers is disabled\n");
[145] Fix | Delete
}
[146] Fix | Delete
if ( $exim_localopts_conf{'require_secure_auth'} ne 1 ) {
[147] Fix | Delete
print_warn("Require clients to connect with SSL or issue the STARTTLS is disabled!\n");
[148] Fix | Delete
} elsif ( $opts{verbose} ) {
[149] Fix | Delete
print_info("Require clients to connect with SSL or issue the STARTTLS is enabled\n");
[150] Fix | Delete
}
[151] Fix | Delete
if ( $exim_localopts_conf{'systemfilter'} ne q{/etc/cpanel_exim_system_filter} ) {
[152] Fix | Delete
print_warn("Custom System Filter File in use: $exim_localopts_conf{'systemfilter'}\n");
[153] Fix | Delete
} elsif ( $opts{verbose} ) {
[154] Fix | Delete
print_info("System Filter File is set to the default path: $exim_localopts_conf{'systemfilter'}\n");
[155] Fix | Delete
}
[156] Fix | Delete
print "\n";
[157] Fix | Delete
[158] Fix | Delete
# Check Dovecot Configuration
[159] Fix | Delete
print_bold_white("Checking Dovecot Configuration...\n");
[160] Fix | Delete
print "---------------------------------\n";
[161] Fix | Delete
my $dovecot = Cpanel::AdvConfig::dovecot::get_config();
[162] Fix | Delete
if ( $dovecot->{'protocols'} !~ m/imap/ ) {
[163] Fix | Delete
print_warn("IMAP Protocol is disabled!\n");
[164] Fix | Delete
}
[165] Fix | Delete
if ( $dovecot->{'disable_plaintext_auth'} !~ m/no/ ) {
[166] Fix | Delete
print_warn("Allow Plaintext Authentication is enabled!\n");
[167] Fix | Delete
} elsif ( $opts{verbose} ) {
[168] Fix | Delete
print_info("Allow Plaintext Authentication is disabled\n");
[169] Fix | Delete
}
[170] Fix | Delete
print "\n";
[171] Fix | Delete
return;
[172] Fix | Delete
}
[173] Fix | Delete
[174] Fix | Delete
[175] Fix | Delete
sub auth_check {
[176] Fix | Delete
my @logfiles;
[177] Fix | Delete
my @auth_password_hits;
[178] Fix | Delete
my @auth_sendmail_hits;
[179] Fix | Delete
my @auth_local_user_hits;
[180] Fix | Delete
my @subject_hits;
[181] Fix | Delete
my $logcount = 0;
[182] Fix | Delete
[183] Fix | Delete
# Exim regex search strings
[184] Fix | Delete
my $auth_password_regex = qr{\sA=dovecot_(login|plain):([^\s]+)\s};
[185] Fix | Delete
my $auth_sendmail_regex = qr{\scwd=([^\s]+)\s};
[186] Fix | Delete
my $auth_local_user_regex = qr{\sU=([^\s]+)\s.*B=authenticated_local_user};
[187] Fix | Delete
my $subject_regex = qr{\s<=\s.*T="([^"]+)"\s};
[188] Fix | Delete
[189] Fix | Delete
print_bold_white("Checking Mail Authentication statistics...\n");
[190] Fix | Delete
print "------------------------------------------\n";
[191] Fix | Delete
[192] Fix | Delete
# Set logdir, ensure trailing slash, and bail if the provided logdir doesn't exist:
[193] Fix | Delete
my $logdir = ($opts{logdir}) ? ($opts{logdir}) : $LOGDIR;
[194] Fix | Delete
$logdir =~ s@/*$@/@;
[195] Fix | Delete
[196] Fix | Delete
if (!-d $logdir) {
[197] Fix | Delete
print_warn("$opts{logdir}: No such file or directory. Skipping spam check...\n\n");
[198] Fix | Delete
return;
[199] Fix | Delete
}
[200] Fix | Delete
[201] Fix | Delete
# Collect log files
[202] Fix | Delete
for my $file ( grep { m/^exim_mainlog/ } @{ Cpanel::FileUtils::Dir::get_directory_nodes($logdir) } ) {
[203] Fix | Delete
if ( $opts{rotated} ) {
[204] Fix | Delete
if ( ( $file =~ m/mainlog-/ ) && ( $logcount ne $ROTATED_LIMIT ) ) {
[205] Fix | Delete
push @logfiles, $file;
[206] Fix | Delete
$logcount++;
[207] Fix | Delete
}
[208] Fix | Delete
}
[209] Fix | Delete
push @logfiles, $file if ( $file =~ m/mainlog$/ );
[210] Fix | Delete
}
[211] Fix | Delete
print_warn("Safeguard triggered... --rotated is limited to $ROTATED_LIMIT logs\n") if ( $logcount eq $ROTATED_LIMIT );
[212] Fix | Delete
[213] Fix | Delete
# Bail if we can't find any logs
[214] Fix | Delete
return print_warn("Bailing, no exim logs found...\n\n") if (!@logfiles);
[215] Fix | Delete
[216] Fix | Delete
# Set ionice
[217] Fix | Delete
my %cpconf = get_conf( $CPANEL_CONFIG_FILE );
[218] Fix | Delete
if ( ( !$opts{rude} ) && ( Cpanel::IONice::ionice( 'best-effort', exists $cpconf{'ionice_import_exim_data'} ? $cpconf{'ionice_import_exim_data'} : 6 ) ) ) {
[219] Fix | Delete
print("Setting I/O priority to reduce system load: " . Cpanel::IONice::get_ionice() . "\n\n");
[220] Fix | Delete
setpriority( 0, 0, 19 );
[221] Fix | Delete
}
[222] Fix | Delete
[223] Fix | Delete
my $fh;
[224] Fix | Delete
lOG: for my $log ( @logfiles ) {
[225] Fix | Delete
if ( $log =~ /[.]gz$/ ) {
[226] Fix | Delete
my @cmd = ( qw{ gunzip -c -f }, $logdir . $log );
[227] Fix | Delete
if ( !open $fh, '-|', @cmd ) {
[228] Fix | Delete
print_warn("Skipping $logdir/$log: Cannot open pipe to read stdout from command '@{ [ join ' ', @cmd ] }' : $!\n");
[229] Fix | Delete
next LOG;
[230] Fix | Delete
}
[231] Fix | Delete
} else {
[232] Fix | Delete
if ( !open $fh, '<', $logdir . $log ) {
[233] Fix | Delete
print_warn("Skipping $logdir/$log: Cannot open for reading $!\n");
[234] Fix | Delete
next LOG;
[235] Fix | Delete
}
[236] Fix | Delete
}
[237] Fix | Delete
while ( my $block = Cpanel::IO::read_bytes_to_end_of_line( $fh, 65_535 ) ) {
[238] Fix | Delete
foreach my $line ( split( m{\n}, $block ) ) {
[239] Fix | Delete
push @auth_password_hits, $2 if ($line =~ $auth_password_regex);
[240] Fix | Delete
push @auth_sendmail_hits, $1 if ($line =~ $auth_sendmail_regex);
[241] Fix | Delete
push @auth_local_user_hits, $1 if ($line =~ $auth_local_user_regex);
[242] Fix | Delete
push @subject_hits, $1 if ($line =~ $subject_regex);
[243] Fix | Delete
}
[244] Fix | Delete
}
[245] Fix | Delete
close($fh);
[246] Fix | Delete
}
[247] Fix | Delete
[248] Fix | Delete
# Print info
[249] Fix | Delete
print_bold_white("Emails sent via Password Authentication:\n");
[250] Fix | Delete
if (@auth_password_hits) {
[251] Fix | Delete
sort_uniq(@auth_password_hits);
[252] Fix | Delete
} else {
[253] Fix | Delete
print "None\n";
[254] Fix | Delete
}
[255] Fix | Delete
print "\n";
[256] Fix | Delete
print_bold_white("Directories where email was sent via sendmail/script:\n");
[257] Fix | Delete
if (@auth_sendmail_hits) {
[258] Fix | Delete
sort_uniq(@auth_sendmail_hits);
[259] Fix | Delete
} else {
[260] Fix | Delete
print "None\n";
[261] Fix | Delete
}
[262] Fix | Delete
print "\n";
[263] Fix | Delete
print_bold_white("Users who sent mail via local SMTP:\n");
[264] Fix | Delete
if (@auth_local_user_hits) {
[265] Fix | Delete
sort_uniq(@auth_local_user_hits);
[266] Fix | Delete
} else {
[267] Fix | Delete
print "None\n";
[268] Fix | Delete
}
[269] Fix | Delete
print "\n";
[270] Fix | Delete
print_bold_white("Subjects by commonality:\n");
[271] Fix | Delete
sort_uniq(@subject_hits);
[272] Fix | Delete
print "\n";
[273] Fix | Delete
[274] Fix | Delete
return;
[275] Fix | Delete
}
[276] Fix | Delete
[277] Fix | Delete
sub print_exim_queue {
[278] Fix | Delete
# Print exim queue length
[279] Fix | Delete
print_bold_white("Exim Queue: ");
[280] Fix | Delete
my $queue = get_exim_queue();
[281] Fix | Delete
if ($queue >= 1000) {
[282] Fix | Delete
print_bold_red("$queue\n");
[283] Fix | Delete
} else {
[284] Fix | Delete
print_bold_green("$queue\n");
[285] Fix | Delete
}
[286] Fix | Delete
return;
[287] Fix | Delete
}
[288] Fix | Delete
[289] Fix | Delete
sub get_exim_queue {
[290] Fix | Delete
my $queue = timed_run_trap_stderr( 10, 'exim', '-bpc');
[291] Fix | Delete
return $queue;
[292] Fix | Delete
}
[293] Fix | Delete
[294] Fix | Delete
sub rbl_check {
[295] Fix | Delete
my $rbls = shift;
[296] Fix | Delete
my @rbls = split( /,/, $rbls);
[297] Fix | Delete
my @ips;
[298] Fix | Delete
[299] Fix | Delete
# Fetch IP's... should we only check mailips? this is more thorough...
[300] Fix | Delete
# could ignore local through bogon regex?
[301] Fix | Delete
return unless my $ips = get_ips();
[302] Fix | Delete
[303] Fix | Delete
# Uncomment the following for testing positive hits
[304] Fix | Delete
# push @$ips, qw{ 127.0.0.2 };
[305] Fix | Delete
[306] Fix | Delete
# In cPanel 11.84, we switched to the libunbound resolver
[307] Fix | Delete
my ($cp_numeric_version, $cp_original_version) = get_cpanel_version();
[308] Fix | Delete
my $libunbound = (version_compare($cp_numeric_version, qw( < 11.84))) ? 0 : 1;
[309] Fix | Delete
[310] Fix | Delete
# If "all" is found in the --rbl arg, ignore rest, use default rbl list
[311] Fix | Delete
# maybe we should append so that user can specify all and ones which are not included in the list?
[312] Fix | Delete
@rbls = @RBLS if (grep { /\ball\b/i } @rbls);
[313] Fix | Delete
print_bold_white("Checking IP's against RBL's...\n");
[314] Fix | Delete
print "------------------------------\n";
[315] Fix | Delete
[316] Fix | Delete
foreach my $ip (@$ips) {
[317] Fix | Delete
print "$ip:\n";
[318] Fix | Delete
my $ip_rev = join('.', reverse split('\.', $ip));
[319] Fix | Delete
foreach my $rbl (@rbls) {
[320] Fix | Delete
printf("\t%-25s ", $rbl);
[321] Fix | Delete
[322] Fix | Delete
my $result;
[323] Fix | Delete
if ($libunbound) {
[324] Fix | Delete
$result = dns_query("$ip_rev.$rbl", 'A')->[0] || 0;
[325] Fix | Delete
} else {
[326] Fix | Delete
# This uses libunbound, which will return an aref, but we can always expect just one result here
[327] Fix | Delete
$result = dns_query_pre_84("$ip_rev.$rbl", 'A') || 0;
[328] Fix | Delete
}
[329] Fix | Delete
[330] Fix | Delete
if ( $result =~ /\A 127\.0\.0\./xms ) {
[331] Fix | Delete
print_bold_red("LISTED\n");
[332] Fix | Delete
} else {
[333] Fix | Delete
print_bold_green("GOOD\n");
[334] Fix | Delete
}
[335] Fix | Delete
}
[336] Fix | Delete
print "\n";
[337] Fix | Delete
}
[338] Fix | Delete
[339] Fix | Delete
return;
[340] Fix | Delete
}
[341] Fix | Delete
[342] Fix | Delete
sub rbl_list {
[343] Fix | Delete
print_bold_white("Available RBL's:\n");
[344] Fix | Delete
print "----------------\n";
[345] Fix | Delete
[346] Fix | Delete
foreach my $rbl (@RBLS) {
[347] Fix | Delete
print "$rbl\n";
[348] Fix | Delete
}
[349] Fix | Delete
print "\n";
[350] Fix | Delete
return;
[351] Fix | Delete
}
[352] Fix | Delete
[353] Fix | Delete
sub maillog_check {
[354] Fix | Delete
my @logfiles;
[355] Fix | Delete
my $logcount = 0;
[356] Fix | Delete
[357] Fix | Delete
# General
[358] Fix | Delete
my @out_of_memory;
[359] Fix | Delete
my $out_of_memory_regex = qr{lmtp\(([\w\.@]+)\): Fatal: \S+: Out of memory};
[360] Fix | Delete
[361] Fix | Delete
my $time_backwards = 0;
[362] Fix | Delete
my $time_backwards_regex = qr{Fatal: Time just moved backwards by \d+ \w+\. This might cause a lot of problems, so I'll just kill myself now};
[363] Fix | Delete
[364] Fix | Delete
# Quota errors
[365] Fix | Delete
my @quota_failed;
[366] Fix | Delete
my $quotactl_failed_regex = qr{quota-fs: (quotactl\(Q_X?GETQUOTA, [\w/]+\) failed: .+)};
[367] Fix | Delete
my $ioctl_failed_regex = qr{quota-fs: (ioctl\([\w/]+, Q_QUOTACTL\) failed: .+)};
[368] Fix | Delete
my $invalid_nfs_regex = qr{quota-fs: (.+ is not a valid NFS device path)};
[369] Fix | Delete
my $unrespponsive_rpc_regex = qr{quota-fs: (could not contact RPC service on .+)};
[370] Fix | Delete
my $rquota_remote_regex = qr{quota-fs: (remote( ext)? rquota call failed: .+)};
[371] Fix | Delete
my $rquota_eacces_regex = qr{quota-fs: (permission denied to( ext)? rquota service)};
[372] Fix | Delete
my $rquota_compile_regex = qr{quota-fs: (rquota not compiled with group support)};
[373] Fix | Delete
my $dovecot_compile_regex = qr{quota-fs: (Dovecot was compiled with Linux quota .+)};
[374] Fix | Delete
my $unrec_code_regex = qr{quota-fs: (unrecognized status code .+)};
[375] Fix | Delete
[376] Fix | Delete
# Spamd error
[377] Fix | Delete
my $pyzor_timeout = 0;
[378] Fix | Delete
my $pyzor_timeout_regex = qr{Timeout: Did not receive a response from the pyzor server public\.pyzor\.org};
[379] Fix | Delete
[380] Fix | Delete
my $pyzor_unreachable = 0;
[381] Fix | Delete
my $pyzor_unreachable_regex = qr{pyzor: check failed: Cannot connect to public.pyzor.org:24441: IO::Socket::INET: connect: Network is unreachable};
[382] Fix | Delete
[383] Fix | Delete
print_bold_white("Checking Maillog for common errors...\n");
[384] Fix | Delete
print "-----------------------------------------\n";
[385] Fix | Delete
[386] Fix | Delete
# Set logdir, ensure trailing slash, and bail if the provided logdir doesn't exist:
[387] Fix | Delete
my $logdir = ($opts{logdir}) ? ($opts{logdir}) : $LOGDIR;
[388] Fix | Delete
$logdir =~ s@/*$@/@;
[389] Fix | Delete
[390] Fix | Delete
if (!-d $logdir) {
[391] Fix | Delete
print_warn("$opts{logdir}: No such file or directory. Skipping spam check...\n\n");
[392] Fix | Delete
return;
[393] Fix | Delete
}
[394] Fix | Delete
[395] Fix | Delete
# Collect log files
[396] Fix | Delete
for my $file ( grep { m/^maillog/ } @{ Cpanel::FileUtils::Dir::get_directory_nodes($logdir) } ) {
[397] Fix | Delete
if ( $opts{rotated} ) {
[398] Fix | Delete
if ( ( $file =~ m/maillog-/ ) && ( $logcount ne $ROTATED_LIMIT ) ) {
[399] Fix | Delete
push @logfiles, $file;
[400] Fix | Delete
$logcount++;
[401] Fix | Delete
}
[402] Fix | Delete
}
[403] Fix | Delete
push @logfiles, $file if ( $file =~ m/maillog$/ );
[404] Fix | Delete
}
[405] Fix | Delete
print_warn("Safeguard triggered... --rotated is limited to $ROTATED_LIMIT logs\n") if ( $logcount eq $ROTATED_LIMIT );
[406] Fix | Delete
[407] Fix | Delete
# Bail if we can't find any logs
[408] Fix | Delete
return print_warn("Bailing, no maillog found...\n\n") if (!@logfiles);
[409] Fix | Delete
[410] Fix | Delete
# Set ionice
[411] Fix | Delete
my %cpconf = get_conf( $CPANEL_CONFIG_FILE );
[412] Fix | Delete
if ( ( !$opts{rude} ) && ( Cpanel::IONice::ionice( 'best-effort', exists $cpconf{'ionice_import_exim_data'} ? $cpconf{'ionice_import_exim_data'} : 6 ) ) ) {
[413] Fix | Delete
print("Setting I/O priority to reduce system load: " . Cpanel::IONice::get_ionice() . "\n\n");
[414] Fix | Delete
setpriority( 0, 0, 19 );
[415] Fix | Delete
}
[416] Fix | Delete
[417] Fix | Delete
my $fh;
[418] Fix | Delete
lOG: for my $log ( @logfiles ) {
[419] Fix | Delete
if ( $log =~ /[.]gz$/ ) {
[420] Fix | Delete
my @cmd = ( qw{ gunzip -c -f }, $logdir . $log );
[421] Fix | Delete
if ( !open $fh, '-|', @cmd ) {
[422] Fix | Delete
print_warn("Skipping $logdir/$log: Cannot open pipe to read stdout from command '@{ [ join ' ', @cmd ] }' : $!\n");
[423] Fix | Delete
next LOG;
[424] Fix | Delete
}
[425] Fix | Delete
} else {
[426] Fix | Delete
if ( !open $fh, '<', $logdir . $log ) {
[427] Fix | Delete
print_warn("Skipping $logdir/$log: Cannot open for reading $!\n");
[428] Fix | Delete
next LOG;
[429] Fix | Delete
}
[430] Fix | Delete
}
[431] Fix | Delete
while ( my $block = Cpanel::IO::read_bytes_to_end_of_line( $fh, 65_535 ) ) {
[432] Fix | Delete
foreach my $line ( split( m{\n}, $block ) ) {
[433] Fix | Delete
push @out_of_memory, $1 if ($line =~ $out_of_memory_regex);
[434] Fix | Delete
push @quota_failed, $1 if ($line =~ $quotactl_failed_regex);
[435] Fix | Delete
++$pyzor_timeout if ($line =~ $pyzor_timeout_regex);
[436] Fix | Delete
}
[437] Fix | Delete
}
[438] Fix | Delete
close($fh);
[439] Fix | Delete
}
[440] Fix | Delete
[441] Fix | Delete
# Print info
[442] Fix | Delete
print_bold_white("LMTP quota issues:\n");
[443] Fix | Delete
if (@quota_failed) {
[444] Fix | Delete
sort_uniq(@quota_failed);
[445] Fix | Delete
} else {
[446] Fix | Delete
print "None\n";
[447] Fix | Delete
}
[448] Fix | Delete
print "\n";
[449] Fix | Delete
print_bold_white("Email accounts triggering LMTP Out of memory:\n");
[450] Fix | Delete
if (@out_of_memory) {
[451] Fix | Delete
sort_uniq(@out_of_memory);
[452] Fix | Delete
} else {
[453] Fix | Delete
print "None\n";
[454] Fix | Delete
}
[455] Fix | Delete
print "\n";
[456] Fix | Delete
print_bold_white("Timeouts to public.pyzor.org:24441:\n");
[457] Fix | Delete
if ($pyzor_timeout ne 0) {
[458] Fix | Delete
print "Pyzor timed out $pyzor_timeout times\n";
[459] Fix | Delete
} else {
[460] Fix | Delete
print "None\n";
[461] Fix | Delete
}
[462] Fix | Delete
print "\n";
[463] Fix | Delete
[464] Fix | Delete
return;
[465] Fix | Delete
}
[466] Fix | Delete
[467] Fix | Delete
sub version_compare {
[468] Fix | Delete
# example: return if version_compare($ver_string, qw( >= 1.2.3.3 ));
[469] Fix | Delete
# Must be no more than four version numbers separated by periods and/or underscores.
[470] Fix | Delete
my ( $ver1, $mode, $ver2 ) = @_;
[471] Fix | Delete
return if ( !defined($ver1) || ( $ver1 =~ /[^\._0-9]/ ) );
[472] Fix | Delete
return if ( !defined($ver2) || ( $ver2 =~ /[^\._0-9]/ ) );
[473] Fix | Delete
[474] Fix | Delete
# Shamelessly copied the comparison logic out of Cpanel::Version::Compare
[475] Fix | Delete
my %modes = (
[476] Fix | Delete
'>' => sub {
[477] Fix | Delete
return if $_[0] eq $_[1];
[478] Fix | Delete
return _version_cmp(@_) > 0;
[479] Fix | Delete
},
[480] Fix | Delete
'<' => sub {
[481] Fix | Delete
return if $_[0] eq $_[1];
[482] Fix | Delete
return _version_cmp(@_) < 0;
[483] Fix | Delete
},
[484] Fix | Delete
'==' => sub { return $_[0] eq $_[1] || _version_cmp(@_) == 0; },
[485] Fix | Delete
'!=' => sub { return $_[0] ne $_[1] && _version_cmp(@_) != 0; },
[486] Fix | Delete
'>=' => sub {
[487] Fix | Delete
return 1 if $_[0] eq $_[1];
[488] Fix | Delete
return _version_cmp(@_) >= 0;
[489] Fix | Delete
},
[490] Fix | Delete
'<=' => sub {
[491] Fix | Delete
return 1 if $_[0] eq $_[1];
[492] Fix | Delete
return _version_cmp(@_) <= 0;
[493] Fix | Delete
}
[494] Fix | Delete
);
[495] Fix | Delete
return if ( !exists $modes{$mode} );
[496] Fix | Delete
return $modes{$mode}->( $ver1, $ver2 );
[497] Fix | Delete
}
[498] Fix | Delete
[499] Fix | Delete
12
It is recommended that you Edit text format, this type of Fix handles quite a lot in one request
Function