Hi all, i thought i would share my implementation of exim greylisting for cpanel. What it essentially does is initially defer all received messages to and from any unique sender / recipient combination for 15 minutes, if the sender re-tries after that the message is accepted and any further messages are accepted immediately for a period of 36 days. Whenever any further messages are received the greylist also refreshes that 36 day timeout so regular correspondence between two parties should remain unmolested after the first 15 minute greylisting.
Instructions are as follows and if anyone has any questions, bugs or other concerns please respond to this thread.
- Firstly create a mysql database called 'greylist';
- Create a mysql user and password with access to that database from the server(s) you're going to be running your exim services (i used username 'greylist' password 'greylist').
- Create the tables in database as follows:
Code:CREATE TABLE `relaytofrom` ( `id` bigint(20) NOT NULL auto_increment, `relay_ip` varchar(16) default NULL, `mail_from` varchar(255) default NULL, `rcpt_to` varchar(255) default NULL, `block_expires` datetime NOT NULL default '0000-00-00 00:00:00', `record_expires` datetime NOT NULL default '0000-00-00 00:00:00', `blocked_count` bigint(20) NOT NULL default '0', `passed_count` bigint(20) NOT NULL default '0', `aborted_count` bigint(20) NOT NULL default '0', `origin_type` enum('MANUAL','AUTO') NOT NULL default 'MANUAL', `create_time` datetime NOT NULL default '0000-00-00 00:00:00', `last_update` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `rcpt_to` (`rcpt_to`), KEY `mail_from` (`mail_from`), KEY `relay_ip` (`relay_ip`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 CREATE TABLE `spam_records` ( `relay_ip` varchar(16) default NULL, `mail_from` varchar(255) default NULL, `rcpt_to` varchar(255) default NULL, `blocked_count` bigint(20) NOT NULL default '0', `passed_count` bigint(20) NOT NULL default '0', `last_update` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP ) ENGINE=MyISAM DEFAULT CHARSET=latin1- Copy your '/etc/exim.pl' to /etc/exim_greylist.pl
- Edit your exim_greylist.pl file and look for this section:
This should be near to the top of the file, insert this under it changing the mysql connection variables as required:Code:my $hasmd5 = 0; eval { require Digest::Perl::MD5; $hasmd5 = 1; };
Code:use DBI; sub greylist() { my $lp = Exim::expand_string('$local_part'); my $sender_addr = Exim::expand_string('$sender_address'); my $host = Exim::expand_string('$sender_host_address'); # put your mysql connect options here my $mydb = "greylist"; my $myhost = "localhost"; my $myuser = "greylist"; my $mypasswd = "greylist"; if(checkrelayhost($host)==1) { return "yes"; } else { my $date = localtime; my $LOGFILE = "/var/log/exim_greylist"; open(FILE, ">>$LOGFILE"); my $isp= DBI->connect("DBI:mysql:$mydb:$myhost", "$myuser", "$mypasswd") || print FILE "$date Can't connect\n"; $lp =~ s/\'/\\\'/g; $sender_addr =~ s/\'/\\\'/g; $host =~ s/\'/\\\'/g; my $query = "select UNIX_TIMESTAMP(block_expires)-UNIX_TIMESTAMP() from greylist.relaytofrom where rcpt_to='$lp' and mail_from='$sender_addr'"; $sth = $isp->prepare($query) || print FILE "$query\n"; $sth->execute || print FILE "$query\n"; my @status_array = $sth->fetchrow_array; $sth->finish; unless (@status_array) { $query = "insert into greylist.relaytofrom values (NULL, '$host', '$sender_addr', '$lp', DATE_ADD(NOW(), INTERVAL 15 MINUTE), DATE_ADD(NOW(), INTERVAL 36 DAY), 1, 0, 0, 'AUTO', NOW(), NULL)"; $sth = $isp->prepare($query) || print FILE "$query\n"; $sth->execute || print FILE "$query [".$sth->errstr()."]\n"; close(FILE); $isp->disconnect; return 1; } else { if ($status_array[0]>0) { $query = "update greylist.relaytofrom set blocked_count=blocked_count+1 where rcpt_to='$lp' and mail_from='$sender_addr' and relay_ip='$host'"; $sth = $isp->prepare($query) || print FILE "$query\n"; $sth->execute || print FILE "$query\n"; close(FILE); $isp->disconnect; return 1; } else { $query = "update greylist.relaytofrom set passed_count=passed_count+1, record_expires=DATE_ADD(NOW(), INTERVAL 36 DAY) where rcpt_to='$lp' and mail_from='$sender_addr' and relay_ip='$host'"; $sth = $isp->prepare($query) || print FILE "$query\n"; $sth->execute || print FILE "$query\n"; } } close(FILE); $isp->disconnect; return "yes"; } }- Create a file called /etc/clear_greylist and paste the following in:
Code:#!/usr/bin/perl -w use strict; use DBI; my $date = localtime; my $LOGFILE = "/var/log/exim_greylist"; my $i = 0; my $host = ""; my $mail_from = ""; my $rcpt_to = ""; my $block = ""; my $pass = ""; # put your mysql connect options here my $mydb = "greylist"; my $myhost = "localhost"; my $myuser = "greylist"; my $mypasswd = "greylist"; open(FILE, ">>$LOGFILE"); my $isp= DBI->connect("DBI:mysql:$mydb:$myhost", "$myuser", "$mypasswd") || print FILE "$date Can't connect\n"; my $query = "select relay_ip, mail_from, rcpt_to, blocked_count, passed_count from greylist.relaytofrom where (passed_count=0 and (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(block_expires)) > 28850) or (UNIX_TIMESTAMP() - UNIX_TIMESTAMP(record_e xpires) > 0) "; my $sth = $isp->prepare($query) || print FILE "$query - Can't prepare retrieving dates"; $sth->execute || print FILE "$query - Can't execute retrieving dates"; my $lines = $sth->fetchall_arrayref || &error("Can't fetch all period data"); $sth->finish; foreach $i (0 .. $#{$lines}) { $host = $lines->[$i][0]; $mail_from = $lines->[$i][1]; $rcpt_to = $lines->[$i][2]; $block = $lines->[$i][3]; $pass = $lines->[$i][4]; $host =~ s/\'/\\\'/g; $mail_from =~ s/\'/\\\'/g; $rcpt_to =~ s/\'/\\\'/g; $block =~ s/\'/\\\'/g; $pass =~ s/\'/\\\'/g; $query = "insert into greylist.spam_records values ('$host', '$mail_from', '$rcpt_to', $block, $pass, NULL)"; $sth = $isp->prepare($query) || print FILE "$query - Can't prepare inserting triplet\n"; $sth->execute || print FILE "$query - Can't execute inserting triplet [".$sth->errstr()."]\n"; $query = "delete from greylist.relaytofrom where rcpt_to='$rcpt_to' and mail_from='$mail_from' and relay_ip='$host'"; $sth = $isp->prepare($query) || print FILE "$query - Can't prepare retrieving dates"; $sth->execute || print FILE "$query - Can't execute retrieving dates"; } $isp->disconnect; close(FILE);- Save and exit and chmod 755 this file.
- Enter something along these lines into your crontab to run this script at midnight every night:
Code:0 0 * * * /etc/clear_greylist.pl- Go to WHM/Exim Configuration Editor/Advanced Editor and enter the following into the top box:
Code:perl_startup = do '/etc/exim_greylist.pl'- Enter the following into your ACL's section under "#if it gets here it isn't mailman":
Code:warn set acl_m0 = ${perl{greylist}} defer message = Greylisted for 15 minutes, please try again later log_message = Greylisted for 15 minutes, please try again later !hosts = +relay_hosts !authenticated = * condition = ${if eq{$acl_m0}{1}{1}}- Save and immediately check your /var/log/exim/mainlog or /var/log/exim_mainlog (system depending) and you should start to see this message pop up:
Code:Greylisted for 15 minutes, please try again later- If anything breaks simply remove the ACL's section that you added and post a message in this thread and i'll see what i can do to help, i've been running it without problems for ~2 years now.
- Final note is that the greylist time can be adjusted by editing the messages in the ACL's area and editing the following line in /etc/exim_greylist.pl
Code:$query = "insert into greylist.relaytofrom values (NULL, '$host', '$sender_addr', '$lp', DATE_ADD(NOW(), INTERVAL 15 MINUTE), DATE_ADD(NOW(), INTERVAL 36 DAY), 1, 0, 0, 'AUTO', NOW(), NULL)";



LinkBack URL
About LinkBacks
Reply With Quote









