Hello all,
for some days now i've been looking into the best way to make
greylisting work with qmail-ldap. I've come to the conclusion that the
more common ways around where to use an rblsmtpd drop in replacement
program, that would greylist by incoming ip address.
It doesn't take much to come to the conclusion that such approach is far
from perfect since it takes a test condition to the three IP, MAIL FROM
and RCPT TO triplets to have a solid ground for greylisting.
Looking around a bit longer i was able to find a page which could
provide a starting ground for the solution.
http://www.digitaleveryware.com/projects/greylisting/ had, in theory, a
solution for qmail. I noticed then that there was already a patch for
netqmail that would benefit from the digitaleveryware solution. Although
the patch didn't apply cleanly, i was able to identify the differences
and port it to qmail-ldap. I also took the chance to add support for
on-the-fly enabling by using the GREYLIST env var in the tcpserver rules
file.
More detailed information is available in the README.greylist file which
is part of the patch.
I've been running this solution for a couple of days now and it seems
very stable and fast. I had a reduction of Spam messages in the order of
80% since, and that at the level of SMTP talk, wasting almost no
resources, and sparing my content filter solution which is working,
after, using the ALTQUEUE enhancement.
Also i'd like to take a chance to say that it would be rather nice if
this, or something similar, would go into the mainstream qmail-ldap patch.
If anyone uses this patch, please let me know how did it work for you.
Cheers!
Hugo Monteiro.
--
ci.fct.unl.pt:~# cat .signature
Hugo Monteiro
Email : hugo.monteiro@fct.unl.pt
Telefone : +351 212948300 Ext.15307
Centro de Informática
Faculdade de Ciências e Tecnologia da
Universidade Nova de Lisboa
Quinta da Torre 2829-516 Caparica Portugal
Telefone: +351 212948596 Fax: +351 212948548
www.ci.fct.unl.pt apoio@fct.unl.pt
ci.fct.unl.pt:~# _
diff -u -N -r qmail-ldap-1.03-20060201/dbdef.sql
qmail-ldap-1.03-20060201-greylist-0.3/dbdef.sql
--- qmail-ldap-1.03-20060201/dbdef.sql 1970-01-01 01:00:00.000000000 +0100
+++ qmail-ldap-1.03-20060201-greylist-0.3/dbdef.sql 2007-01-22
10:44:24.307885032 +0000
@@ -0,0 +1,73 @@
+
+#######################################################################
+# Database definitions
+#######################################################################
+
+# Using Mysql 3.23.2 or later (required for NULLs allowed in indexed fields
+
+CREATE DATABASE relaydelay;
+grant select,insert,update,delete on relaydelay.* to milter@"localhost"
identified by 'milter';
+
+USE relaydelay;
+
+# NOTE: We allow nulls in the 3 "triplet" fields for manual white/black
listing. A null indicates that that field
+# should not be considered when looking for a match. Automatic entries will
always have all three populated.
+# Note: Since we index the triplet fields, and allow them to be null, this
requires at least Mysql 3.23.2 and MYISAM
+# tables.
+create table relaytofrom # Stores settings for each [relay, to, from]
triplet
+(
+ id bigint NOT NULL auto_increment, #
unique triplet id
+ relay_ip char(16), #
sending relay in IPV4 ascii dotted quad notation
+ mail_from varchar(255), #
ascii address of sender
+ rcpt_to varchar(255), # the
recipient address.
+ block_expires datetime NOT NULL, # the
time that an initial block will/did expire
+ record_expires datetime NOT NULL, # the
date after which this record is ignored
+
+ blocked_count bigint default 0 NOT NULL, # num
of blocked attempts to deliver
+ passed_count bigint default 0 NOT NULL, # num
of passed attempts we have allowed
+ aborted_count bigint default 0 NOT NULL, # num
of attempts we have passed, but were later aborted
+ origin_type enum("MANUAL","AUTO") NOT NULL, #
indicates the origin of this record (auto, or manual)
+ create_time datetime NOT NULL, #
timestamp of creation time of this record
+ last_update timestamp NOT NULL, #
timestamp of last change to this record (automatic)
+
+ primary key(id),
+ key(relay_ip),
+ key(mail_from(20)), # To
keep the index size down, only index first 20 chars
+ key(rcpt_to(20))
+);
+
+create table dns_name # Stores the reverse dns name lookup for records
+(
+ relay_ip varchar(18) NOT NULL,
+ relay_name varchar(255) NOT NULL, # dns
name, stored in reversed character order (for index)
+ last_update timestamp NOT NULL, #
timestamp of last change to this record (automatic)
+ primary key(relay_ip),
+ key(relay_name(20))
+);
+
+# This table is not used yet, possibly never will be
+create table mail_log # Stores a record for every mail delivery attempt
+(
+ id bigint NOT NULL auto_increment, #
unique log entry id
+ relay_ip varchar(16) NOT NULL, #
sending relay in IPV4 ascii dotted quad notation
+ relay_name varchar(255), #
sending relay dns name
+ dns_mismatch bool NOT NULL, # true
if does not match, false if matches or no dns
+ mail_from varchar(255) NOT NULL, # the
mail from: address
+ rcpt_to varchar(255) NOT NULL, # the
rcpt to: address
+ rcpt_host varchar(80) NOT NULL, # the
id (hostname) of the host that generated this row
+ create_time datetime NOT NULL, #
timestamp of inserted time, since no updates
+
+ primary key(id),
+ key(relay_ip),
+ key(mail_from(20)),
+ key(rcpt_to(20))
+);
+
+# Example wildcard whitelists for subnets
+insert into relaytofrom values (0,"127.0.0.1" ,NULL,NULL,"0000-00-00
00:00:00","9999-12-31 23:59:59",0,0,0,"MANUAL",NOW(),NOW());
+insert into relaytofrom values (0,"192.168" ,NULL,NULL,"0000-00-00
00:00:00","9999-12-31 23:59:59",0,0,0,"MANUAL",NOW(),NOW());
+
+# Example wildcard whitelist entry for a recieved domain or subdomain
+insert into relaytofrom values (0,NULL,NULL,"sub.domain.com","0000-00-00
00:00:00","9999-12-31 23:59:59",0,0,0,"MANUAL",NOW(),NOW());
+
+
diff -u -N -r qmail-ldap-1.03-20060201/FILES
qmail-ldap-1.03-20060201-greylist-0.3/FILES
--- qmail-ldap-1.03-20060201/FILES 2007-01-21 01:39:36.000000000 +0000
+++ qmail-ldap-1.03-20060201-greylist-0.3/FILES 2007-01-20 20:09:23.000000000
+0000
@@ -426,6 +426,10 @@
tcp-environ.5
constmap.h
constmap.c
+local_scan.c
+qmail-envelope-scanner.c
+dbdef.sql
+local_scan.h
EXTTODO
Makefile.cdb
POPBEFORESMTP
diff -u -N -r qmail-ldap-1.03-20060201/greylist-cleanup.pl
qmail-ldap-1.03-20060201-greylist-0.3/greylist-cleanup.pl
--- qmail-ldap-1.03-20060201/greylist-cleanup.pl 1970-01-01
01:00:00.000000000 +0100
+++ qmail-ldap-1.03-20060201-greylist-0.3/greylist-cleanup.pl 2007-01-21
19:07:39.000000000 +0000
@@ -0,0 +1,20 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use constant DBD => 'DBI:mysql:relaydelay:localhost:3306';
+use constant DBUSER => 'milter';
+use constant DBPASS => 'milter';
+
+use DBI;
+
+system ("cat /dev/null > /tmp/greylist_dbg.txt");
+
+my $dbh = DBI->connect(DBD,DBUSER,DBPASS) or die "can't connect to db ",
$DBI::errstr, ":$!";
+
+$dbh->do("DELETE FROM relaytofrom WHERE record_expires < NOW() - INTERVAL 1
HOUR AND origin_type = 'AUTO'");
+$dbh->do("OPTIMIZE TABLE relaytofrom");
+
+$dbh->disconnect;
+
+exit;
diff -u -N -r qmail-ldap-1.03-20060201/greylist-whitelist.pl
qmail-ldap-1.03-20060201-greylist-0.3/greylist-whitelist.pl
--- qmail-ldap-1.03-20060201/greylist-whitelist.pl 1970-01-01
01:00:00.000000000 +0100
+++ qmail-ldap-1.03-20060201-greylist-0.3/greylist-whitelist.pl 2007-01-21
20:10:48.000000000 +0000
@@ -0,0 +1,20 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use constant DBD => 'DBI:mysql:relaydelay:localhost:3306';
+use constant DBUSER => 'milter';
+use constant DBPASS => 'milter';
+
+use DBI;
+
+system ("cat /dev/null > /tmp/greylist_dbg.txt");
+
+my $dbh = DBI->connect(DBD,DBUSER,DBPASS) or die "can't connect to db ",
$DBI::errstr, ":$!";
+
+$dbh->do("INSERT INTO relaytofrom values (NULL, '$ARGV[0]',NULL,NULL,
'0000-00-00 00:00:00', '9999-12-31 23:59:59', 0, 0, 0, 'MANUAL', NOW(),
NOW())");
+$dbh->do("OPTIMIZE TABLE relaytofrom");
+
+$dbh->disconnect;
+
+exit;
diff -u -N -r qmail-ldap-1.03-20060201/hier.c
qmail-ldap-1.03-20060201-greylist-0.3/hier.c
--- qmail-ldap-1.03-20060201/hier.c 2007-01-21 01:39:36.000000000 +0000
+++ qmail-ldap-1.03-20060201-greylist-0.3/hier.c 2007-01-21
23:18:01.000000000 +0000
@@ -214,6 +214,13 @@
c(auto_qmail,"bin","qmail-qmqpd",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qmail-qmtpd",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qmail-smtpd",auto_uido,auto_gidq,0755);
+#ifdef GREYLIST
+ c(auto_qmail,"bin","qmail-envelope-scanner",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"doc","greylist-whitelist.pl",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"doc","greylist-cleanup.pl",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"doc","README.greylist",auto_uido,auto_gidq,0644);
+ c(auto_qmail,"doc","dbdef.sql",auto_uido,auto_gidq,0644);
+#endif
c(auto_qmail,"bin","sendmail",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","tcp-env",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qreceipt",auto_uido,auto_gidq,0755);
diff -u -N -r qmail-ldap-1.03-20060201/install-big.c
qmail-ldap-1.03-20060201-greylist-0.3/install-big.c
--- qmail-ldap-1.03-20060201/install-big.c 2007-01-21 01:39:36.000000000
+0000
+++ qmail-ldap-1.03-20060201-greylist-0.3/install-big.c 2007-01-21
23:18:58.000000000 +0000
@@ -214,6 +214,13 @@
c(auto_qmail,"bin","qmail-qmqpd",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qmail-qmtpd",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qmail-smtpd",auto_uido,auto_gidq,0755);
+#ifdef GREYLIST
+ c(auto_qmail,"bin","qmail-envelope-scanner",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"doc","greylist-whitelist.pl",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"doc","greylist-cleanup.pl",auto_uido,auto_gidq,0755);
+ c(auto_qmail,"doc","README.greylist",auto_uido,auto_gidq,0644);
+ c(auto_qmail,"doc","dbdef.sql",auto_uido,auto_gidq,0644);
+#endif
c(auto_qmail,"bin","sendmail",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","tcp-env",auto_uido,auto_gidq,0755);
c(auto_qmail,"bin","qreceipt",auto_uido,auto_gidq,0755);
diff -u -N -r qmail-ldap-1.03-20060201/local_scan.c
qmail-ldap-1.03-20060201-greylist-0.3/local_scan.c
--- qmail-ldap-1.03-20060201/local_scan.c 1970-01-01 01:00:00.000000000
+0100
+++ qmail-ldap-1.03-20060201-greylist-0.3/local_scan.c 2007-01-21
18:25:35.000000000 +0000
@@ -0,0 +1,287 @@
+/**************
+ * Copyright (c) mjd@digitaleveryware.com 2003
+ * GPL Licensed see http://www.gnu.org/licenses/gpl.html
+ * Version 0.04: I don't even have it in cvs yet
+ * ChangeHistory:
+ * Version 0.04: support for qmail
+ * Version 0.03: added whitelisting by incoming domain address
+ * Version 0.02: added relay_ip matching by /24 subnet
+ *************/
+
+#include "local_scan.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <mysql.h>
+
+/************************/
+#define DEFAULT_MYSQLHOST "localhost"
+#define DEFAULT_MYSQLUSER "milter"
+#define DEFAULT_MYSQLPASS "milter"
+#define DEFAULT_MYSQLDB "relaydelay"
+#define DEFAULT_BLOCK_EXPIRE 55 /* minutes until email is accepted */
+#define DEFAULT_RECORD_EXPIRE 500 /* minutes until record expires */
+#define DEFAULT_RECORD_EXPIRE_GOOD 36 /* days until record expires after
accepting email */
+#define DEFAULT_LOCAL_SCAN_DEBUG 0 /* set to 1 to enable debugging */
+
+/*************************/
+
+#define SQLCMDSIZE 1024
+
+char *mysqlhost, *mysqluser, *mysqlpass, *mysqldb;
+int block_expire, record_expire, record_expire_good, local_scan_debug;
+
+int mysql_query_wrapper(MYSQL *mysql, char *sqltext)
+{
+ int result;
+
+ result = mysql_query(mysql,sqltext);
+ if(local_scan_debug == 1) fprintf(stderr,"local_scan: SQL: ret=%d
|%s|\n",result,sqltext);
+ return result;
+}
+
+void AddOrClause(char *subquery,char *in_ipaddr)
+{
+ int loop;
+ char *ptr;
+ char ipaddr[256];
+
+
+ strncpy(ipaddr, in_ipaddr, sizeof(ipaddr));
+ for (loop = 0; loop < 4; loop++) {
+ if (loop)
+ strcat(subquery, " OR ");
+ strcat(subquery , "relay_ip = '" );
+ strcat(subquery ,ipaddr);
+ strcat(subquery , "'");
+ ptr = strrchr(ipaddr,'.'); // strip off the last octet
+ if(ptr)
+ *ptr = '\0';
+ }
+}
+
+/* returns TRUE FALSE if record exists in database */
+int checkWhiteListIP( MYSQL *mysql, int *action)
+{
+ MYSQL_RES *myres;
+ MYSQL_ROW myrow;
+
+ char sql[SQLCMDSIZE], sid[32];
+ int white, black,exists = FALSE;
+
+ /* check for whitelisted sender ip address */
+ sprintf(sql, "SELECT id, block_expires > NOW(), block_expires < NOW()
FROM relaytofrom WHERE record_expires > NOW() AND mail_from IS NULL AND
rcpt_to IS NULL AND (");
+ AddOrClause(sql, sender_host_address);
+ strcat(sql, ") ORDER BY length(relay_ip)");
+ //#ifdef local_scan_debug
+ // fprintf(stderr,"local_scan: check whitelist: %s\n",sql);
+ //#endif
+ if(!mysql_query_wrapper(mysql,sql)) {
+ myres = mysql_store_result(mysql);
+ while ((myrow = mysql_fetch_row(myres)) != NULL) {
+ exists = TRUE;
+ strncpy(sid,myrow[0],sizeof(sid));
+ black = atoi(myrow[1]);
+ white = atoi(myrow[2]);
+ }
+ mysql_free_result(myres); // free memory used by result
+ }
+ if (exists && white) {
+ if(local_scan_debug == 1) fprintf(stderr,"local_scan: %s -> xxx (%s)
Whitelist IP Accept id = %s \n",sender_address, sender_host_address,sid);
+ *action = LOCAL_SCAN_ACCEPT;
+ }
+ else if (exists && black) {
+ if(local_scan_debug == 1) fprintf(stderr,"local_scan: %s -> xxx (%s)
Blacklist IP Permanent Reject id = %s \n",sender_address,
sender_host_address,sid);
+ *action = LOCAL_SCAN_REJECT;
+ }
+
+ return exists;
+}
+
+
+/* returns TRUE FALSE if record exists in database */
+int checkWhiteListDomain( MYSQL *mysql, int *action, int i)
+{
+ MYSQL_RES *myres;
+ MYSQL_ROW myrow;
+
+ char sql[SQLCMDSIZE], sid[32], *indomain;
+ int white, black,exists = FALSE;
+
+ indomain = strrchr(recipients_list[i].address,'@');
+ if(indomain != NULL) {
+ indomain++; /* skip the '@' char */
+
+ /* check for whitelisted receiver domain address */
+ sprintf(sql, "SELECT id, block_expires > NOW(), block_expires < NOW() FROM
relaytofrom WHERE record_expires > NOW() AND mail_from IS NULL AND relay_ip IS
NULL AND rcpt_to = '%s'",indomain);
+ if(!mysql_query_wrapper(mysql,sql)) {
+ myres = mysql_store_result(mysql);
+ while ((myrow = mysql_fetch_row(myres)) != NULL) {
+ exists = TRUE;
+ strncpy(sid,myrow[0],sizeof(sid));
+ black = atoi(myrow[1]);
+ white = atoi(myrow[2]);
+ }
+ mysql_free_result(myres); // free memory used by result
+ }
+ if (exists && white) {
+ if(local_scan_debug == 1) fprintf(stderr,"local_scan: %s -> %s (%s)
Whitelist Domain Accept id = %s \n",sender_address,
recipients_list[i].address, sender_host_address,sid);
+ *action = LOCAL_SCAN_ACCEPT;
+ }
+ else if (exists && black) {
+ if(local_scan_debug == 1) fprintf(stderr,"local_scan: %s -> xxx (%s)
Blacklist Domain Permanent Reject id = %s \n",sender_address,
sender_host_address,sid);
+ *action = LOCAL_SCAN_REJECT;
+ }
+ }
+ return exists;
+}
+
+void buildLookupSql(char *sql, int recipIndex)
+{
+ char hostip[32];
+ char *ptr;
+
+ if (FALSE) {
+ /* this first sprintf does an exact match on ipaddr */
+ sprintf(sql,"SELECT id, NOW() > block_expires FROM relaytofrom WHERE
record_expires > NOW() AND mail_from = '%s' AND rcpt_to = '%s' AND relay_ip
= '%s' order by block_expires desc",sender_address,
recipients_list[recipIndex].address,sender_host_address);
+ }
+ else {
+ /* this second version matches anything in the same /24 subnet */
+ sprintf(sql,"SELECT id, NOW() > block_expires FROM relaytofrom WHERE
record_expires > NOW() AND mail_from = '%s' AND rcpt_to = '%s' AND relay_ip
like '",sender_address, recipients_list[recipIndex].address);
+ strcpy(hostip,sender_host_address);
+ /* now remove the last octet and add a '%' */
+ ptr = strrchr(hostip,'.'); // strip off the last octet
+ if(ptr)
+ *ptr = '\0';
+ strcat(sql,hostip);
+ strcat(sql, "%' order by block_expires desc");
+ }
+}
+
+
+int checkGreylist( MYSQL *mysql, int *action, int i)
+{
+ MYSQL_RES *myres;
+ MYSQL_ROW myrow;
+
+ char sql[SQLCMDSIZE], sid[32];
+ int notexpired, exists = FALSE;
+
+ // lookup to see if record exists
+ buildLookupSql(sql,i);
+ if(!mysql_query_wrapper(mysql,sql)) {
+ myres = mysql_store_result(mysql);
+ while ((myrow = mysql_fetch_row(myres)) != NULL) {
+ exists = TRUE;
+ strncpy(sid,myrow[0],sizeof(sid));
+ notexpired = atoi(myrow[1]);
+ //fprintf(stderr,"local_scan: id = %s expire = %d\n",sid,notexpired);
+ }
+ mysql_free_result(myres); // free memory used by result
+ // if it exists and is not record expired and the block_expired passes
+ if (exists && notexpired) {
+ // update expire time to 36 days, and pass count
+ sprintf(sql,"update relaytofrom set record_expires = NOW() + INTERVAL %d
DAY, passed_count = passed_count + 1 where id ='%s'",record_expire_good,sid);
+ mysql_query_wrapper(mysql, sql);
+ if(local_scan_debug == 1) fprintf(stderr,"local_scan: %s -> %s (%s)
Exists Accept id = %s expire =
%d\n",sender_address,recipients_list[i].address,
sender_host_address,sid,notexpired);
+ *action = LOCAL_SCAN_ACCEPT;
+ }
+ else if ( exists && ! notexpired) {
+ // update fail count
+ sprintf(sql,"update relaytofrom set blocked_count = blocked_count + 1
where id = %s",sid);
+ mysql_query_wrapper(mysql, sql);
+ if(local_scan_debug == 1) fprintf(stderr,"local_scan: %s -> %s (%s)
Exists Block id = %s expire = %d\n",sender_address,recipients_list[i].address,
sender_host_address,sid,notexpired);
+ *action = LOCAL_SCAN_TEMPREJECT;
+ }
+ else /* doesn't exist */ {
+ // it doesn't exist make and entry
+ sprintf(sql,"insert into relaytofrom values (0,'%s','%s','%s',NOW() +
INTERVAL %d MINUTE,NOW() + INTERVAL %d
MINUTE,1,0,0,'AUTO',NOW(),NOW())",sender_host_address,sender_address,
recipients_list[i].address,block_expire,record_expire);
+ mysql_query_wrapper(mysql,sql);
+ if(local_scan_debug == 1) fprintf(stderr,"local_scan: %s -> %s (%s)
Doesn't Exists Block\n",sender_address,recipients_list[i].address,
sender_host_address);
+ *action = LOCAL_SCAN_TEMPREJECT;
+ }
+ }
+}
+
+void get_config(void) {
+
+ char *t;
+
+ mysqlhost = getenv("MYSQLHOST");
+ if (!mysqlhost) {
+ mysqlhost = malloc(strlen(DEFAULT_MYSQLHOST)+1);
+ strcpy(mysqlhost, DEFAULT_MYSQLHOST);
+ }
+ mysqluser = getenv("MYSQLUSER");
+ if (!mysqluser) {
+ mysqluser = malloc(strlen(DEFAULT_MYSQLUSER)+1);
+ strcpy(mysqluser, DEFAULT_MYSQLUSER);
+ }
+ mysqlpass = getenv("MYSQLPASS");
+ if (!mysqlpass) {
+ mysqlpass = malloc(strlen(DEFAULT_MYSQLPASS)+1);
+ strcpy(mysqlpass, DEFAULT_MYSQLPASS);
+ }
+ mysqldb = getenv("MYSQLDB");
+ if (!mysqldb) {
+ mysqldb = malloc(strlen(DEFAULT_MYSQLDB)+1);
+ strcpy(mysqldb, DEFAULT_MYSQLDB);
+ }
+ t = getenv("BLOCK_EXPIRE");
+ if (t) {
+ block_expire = atoi(t);
+ } else {
+ block_expire = DEFAULT_BLOCK_EXPIRE;
+ }
+ t = getenv("RECORD_EXPIRE");
+ if (t) {
+ record_expire = atoi(t);
+ } else {
+ record_expire = DEFAULT_RECORD_EXPIRE;
+ }
+ t = getenv("RECORD_EXPIRE_GOOD");
+ if (t) {
+ record_expire_good = atoi(t);
+ } else {
+ record_expire_good = DEFAULT_RECORD_EXPIRE_GOOD;
+ }
+ t = getenv("LOCAL_SCAN_DEBUG");
+ if (t) {
+ local_scan_debug = atoi(t);
+ } else {
+ local_scan_debug = DEFAULT_LOCAL_SCAN_DEBUG;
+ }
+}
+
+int local_scan(int fd, uschar **return_text)
+{
+ MYSQL *mysql = NULL;
+ int i, ret = LOCAL_SCAN_ACCEPT;
+
+ get_config();
+
+ if(local_scan_debug == 1) fprintf(stderr,"local_scan: protocol = %s %s
\n",received_protocol,sender_address);
+
+
+ fd = fd; /* Keep picky compilers happy */
+ return_text = return_text; /* Keep picky compilers happy
*/
+ mysql = mysql_init(NULL);
+ if (mysql && strcmp(received_protocol,"local") ) {
+ if
(mysql_real_connect(mysql,mysqlhost,mysqluser,mysqlpass,mysqldb,0,NULL,0)) {
+ if ( !checkWhiteListIP( mysql, &ret )) { /* check for whitelisted
sender ip address */
+ for(i= 0 ; i < recipients_count; i++ ) {
+ if(strlen(sender_host_address) + strlen(sender_address) +
+ strlen(recipients_list[i].address) < SQLCMDSIZE - 200) { /* check
to avoid buffer overflows */
+ if(!checkWhiteListDomain( mysql, &ret,i ))
+ checkGreylist(mysql, &ret,i);
+ }
+ }
+ }
+ }
+ }
+ if(mysql) mysql_close(mysql);
+ if(local_scan_debug == 1) fprintf(stderr, "--------\n");
+ return ret;
+}
+
+/* End of local_scan.c */
diff -u -N -r qmail-ldap-1.03-20060201/local_scan.h
qmail-ldap-1.03-20060201-greylist-0.3/local_scan.h
--- qmail-ldap-1.03-20060201/local_scan.h 1970-01-01 01:00:00.000000000
+0100
+++ qmail-ldap-1.03-20060201-greylist-0.3/local_scan.h 2007-01-21
15:52:06.000000000 +0000
@@ -0,0 +1,38 @@
+/**************
+ * Copyright (c) mjd@digitaleveryware.com 2003
+ * GPL Licensed see http://www.gnu.org/licenses/gpl.html
+ * Version 0.04: I don't even have it in cvs yet
+ * ChangeHistory:
+ * Version 0.04: support for qmail
+ * Version 0.03: added whitelisting by incoming domain address
+ * Version 0.02: added relay_ip matching by /24 subnet
+ *************/
+
+#ifndef __GREYLIST_H__
+#define __GREYLIST_H__
+
+#define FALSE 0
+#define TRUE 1
+#define uschar char
+
+#define LOCAL_SCAN_ACCEPT 0
+#define LOCAL_SCAN_REJECT 100
+#define LOCAL_SCAN_TEMPREJECT 101
+#define SOMETHING_BAD 102
+
+struct recipients_list {
+ char *address;
+};
+
+
+int local_scan(int fd, uschar **return_text);
+
+/* globals used by exim */
+
+extern int recipients_count;
+extern char *received_protocol;
+extern char *sender_host_address;
+extern char *sender_address;
+extern struct recipients_list recipients_list[];
+
+#endif
diff -u -N -r qmail-ldap-1.03-20060201/Makefile
qmail-ldap-1.03-20060201-greylist-0.3/Makefile
--- qmail-ldap-1.03-20060201/Makefile 2007-01-21 17:03:42.000000000 +0000
+++ qmail-ldap-1.03-20060201-greylist-0.3/Makefile 2007-01-21
23:22:28.000000000 +0000
@@ -19,6 +19,7 @@
# -DQMQP_COMPRESS to use the QMQP on the fly compression (for clusters)
# -DQUOTATRASH to include the Trash in the quota calculation (normaly it is
not)
# -DSMTPEXECCHECK to enable smtp DOS/Windows executable detection
+# -DGREYLIST to enable greylisting support
#LDAPFLAGS=-DQLDAP_CLUSTER -DEXTERNAL_TODO -DDASH_EXT -DDATA_COMPRESS
-DQMQP_COMPRESS -DSMTPEXECCHECK
# Perhaps you have different ldap libraries, change them here
@@ -71,6 +72,10 @@
#SHADOWOPTS=-DPW_SHADOW
# To use shadow passwords under Solaris, uncomment the SHADOWOPTS line.
+# Greylist support
+MYSQLINCLUDES=-I/usr/include/mysql
+MYSQLLIBS=-L/usr/lib -lmysqlclient
+
# to enable the possibility to log and debug imap and pop uncoment the
# next line
DEBUG=-DDEBUG
@@ -1041,7 +1046,7 @@
predate datemail mailsubj qmail-upq qmail-showctl qmail-newu \
qmail-pw2u qmail-qread qmail-qstat qmail-tcpto qmail-tcpok \
qmail-pop3d qmail-popup qmail-qmqpc qmail-qmqpd qmail-qmtpd \
-qmail-smtpd sendmail tcp-env qmail-newmrh config config-fast dnscname \
+qmail-smtpd qmail-envelope-scanner sendmail tcp-env qmail-newmrh config
config-fast dnscname \
dnsptr dnsip dnsmxip dnsfq hostname ipmeprint qreceipt qsmhook qbiff \
forward preline condredirect bouncesaying except maildirmake \
maildir2mbox maildirwatch qail elq pinq idedit install-big \
@@ -2071,6 +2076,18 @@
error.a fs.a auto_qmail.o dns.o str.a auto_break.o \
`cat dns.lib` `cat socket.lib` $(TLSLIBS) $(ZLIB)
+qmail-envelope-scanner: \
+load qmail-envelope-scanner.o local_scan.o
+ ./load qmail-envelope-scanner -lz -lm local_scan.o $(MYSQLLIBS)
+
+qmail-envelope-scanner.o: \
+compile qmail-envelope-scanner.c local_scan.h
+ ./compile qmail-envelope-scanner.c
+
+local_scan.o: \
+compile local_scan.c local_scan.h
+ ./compile $(MYSQLINCLUDES) local_scan.c
+
qmail-smtpd.0: \
qmail-smtpd.8
nroff -man qmail-smtpd.8 > qmail-smtpd.0
@@ -2362,7 +2379,7 @@
qmail-lspawn.c qmail-newmrh.c qmail-newu.c qmail-pop3d.c \
qmail-popup.c qmail-pw2u.c qmail-qmqpc.c qmail-qmqpd.c qmail-qmtpd.c \
qmail-qread.c qmail-qstat.sh qmail-queue.c qmail-remote.c \
-qmail-rspawn.c qmail-send.c qmail-showctl.c qmail-smtpd.c \
+qmail-rspawn.c qmail-send.c qmail-showctl.c qmail-smtpd.c
qmail-envelope-scanner.c \
qmail-start.c qmail-tcpok.c qmail-tcpto.c spawn.c dnscname.c dnsfq.c \
dnsip.c dnsmxip.c dnsptr.c hostname.c ipmeprint.c tcp-env.c \
sendmail.c qreceipt.c qsmhook.c qbiff.c forward.c preline.c predate.c \
diff -u -N -r qmail-ldap-1.03-20060201/qmail-envelope-scanner.c
qmail-ldap-1.03-20060201-greylist-0.3/qmail-envelope-scanner.c
--- qmail-ldap-1.03-20060201/qmail-envelope-scanner.c 1970-01-01
01:00:00.000000000 +0100
+++ qmail-ldap-1.03-20060201-greylist-0.3/qmail-envelope-scanner.c
2007-01-21 16:06:25.000000000 +0000
@@ -0,0 +1,34 @@
+/**************
+ * Copyright (c) mjd@digitaleveryware.com 2003
+ * GPL Licensed see http://www.gnu.org/licenses/gpl.html
+ * Version 0.04: I don't even have it in cvs yet
+ * ChangeHistory:
+ * Version 0.04: support for qmail
+ * Version 0.03: added whitelisting by incoming domain address
+ * Version 0.02: added relay_ip matching by /24 subnet
+ *************/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "local_scan.h"
+
+
+char *received_protocol;
+char *sender_host_address;
+char *sender_address;
+struct recipients_list recipients_list[1];
+int recipients_count = 1;
+
+int main(int argv, char *argc[])
+{
+ received_protocol = "notneeded4qmail";
+ sender_host_address = getenv("TCPREMOTEIP");
+ recipients_list[0].address = argc[2];
+ sender_address = argc[1];
+
+ if (argv == 3 && sender_host_address != NULL)
+ return local_scan(1,NULL);
+ else
+ return SOMETHING_BAD;
+}
+
diff -u -N -r qmail-ldap-1.03-20060201/qmail-smtpd.c
qmail-ldap-1.03-20060201-greylist-0.3/qmail-smtpd.c
--- qmail-ldap-1.03-20060201/qmail-smtpd.c 2007-01-21 01:39:36.000000000
+0000
+++ qmail-ldap-1.03-20060201-greylist-0.3/qmail-smtpd.c 2007-01-21
15:16:23.000000000 +0000
@@ -22,6 +22,10 @@
#include "env.h"
#include "now.h"
#include "exit.h"
+#ifdef GREYLIST
+ #include "fork.h"
+ #include "wait.h"
+#endif
#include "rcpthosts.h"
#include "rbl.h"
#include "timeoutread.h"
@@ -165,6 +169,10 @@
void err_qqt(void) { out("451 qqt failure (#4.3.0)\r\n"); }
void err_dns(void) { out("421 DNS temporary failure at return MX check, try
again later (#4.3.0)\r\n"); }
void err_soft(char *s) { out("451 "); out(s); out("\r\n");
logline2(1,"temporary verify error: ", s); }
+#ifdef GREYLIST
+void err_tempfail() { out("421 temporary envelope failure (#4.3.0)\r\n"); }
+void err_permfail() { out("553 sorry, permanent envelope failure
(#5.7.1)\r\n"); }
+#endif
void err_bmf(void) { out("553 sorry, your mail was administratively denied.
(#5.7.1)\r\n"); }
void err_bmfunknown(void) { out("553 sorry, your mail from a host [");
out(remoteip); out("] without valid reverse DNS was administratively denied
(#5.7.1)\r\n"); }
void err_maxrcpt(void) { out("553 sorry, too many recipients (#5.7.1)\r\n"); }
@@ -831,7 +839,39 @@
return 0;
}
+#ifdef GREYLIST
+int envelope_scanner()
+{
+ int child;
+ int wstat;
+ char *envelope_scannerarg[] = { "bin/qmail-envelope-scanner", mailfrom.s,
addr.s, 0 };
+
+ switch(child = vfork()) {
+ case -1:
+ return 1;
+ case 0:
+ execv(*envelope_scannerarg,envelope_scannerarg);
+ _exit(111);
+ }
+ wait_pid(&wstat,child);
+ if (wait_crashed(wstat)) {
+ return 1;
+ }
+
+ switch(wait_exitcode(wstat)) {
+ case 101:
+ err_tempfail();
+ return 0;
+ case 100:
+ err_permfail();
+ return 0;
+ default:
+ return 1;
+ }
+}
+#endif
+
void smtp_helo(char *arg)
{
smtp_line("250 ");
@@ -1134,6 +1174,10 @@
if (errdisconnect) err_quit();
return;
}
+#ifdef GREYLIST
+ if (env_get("GREYLIST"))
+ if (!envelope_scanner()) return;
+#endif
}
++rcptcount;
diff -u -N -r qmail-ldap-1.03-20060201/README.greylist
qmail-ldap-1.03-20060201-greylist-0.3/README.greylist
--- qmail-ldap-1.03-20060201/README.greylist 1970-01-01 01:00:00.000000000
+0100
+++ qmail-ldap-1.03-20060201-greylist-0.3/README.greylist 2007-01-21
23:28:05.000000000 +0000
@@ -0,0 +1,46 @@
+AKNOWLEDGEMENTS:
+
+The greylist support added is based on mjd@digitaleveryware.com greylisting
+software available at http://www.digitaleveryware.com/projects/greylisting/.
+
+Integration with qmail-ldap was almost entirely ripped off from the netqmail
+greylist patch for the same digitaleveryware software, done by Joshua Megerman
+(josh@honorablemenschen.com) and Bill Shupp (hostmaster@shupp.org).
+
+Besides the qmail-ldap integration itself, it was added the -DGREYLIST option
to
+LDAPFLAGS so that the code can be activated/deactivated at compile time.
+Support for greylist checking depending on the existance of GREYLIST env var
was
+also added. That way greylisting can be activated only for the desired sources,
+in the tcpserver rules way.
+
+Compilation with greylist support depends on the existence of mysql development
+libraries. Check the MYSQL* build variables on the Makefile.
+
+
+ON MYSQL FAILURE:
+
+If mysql isn't running, the relaydelay database doesn't exist or the username
or
+password fails, greylisting will be disabled and messages will be accepted
+according to qmail-ldap defined rules.
+
+
+WHITELISTING:
+
+Although there's the possibility to whitelist by omiting the GREYLIST env var
+on the tcpserver rules cdb, for a certain netblock, there's also the
possibility to
+do so by inserting records into the relaydelay database. There's a small perl
script
+(greylist-whitelist.pl) bundled to aid with such task.
+
+Ex:
+ /var/qmail/doc/greylist-whitelist.pl 1.2.3.4
+
+
+DATABASE MAINTENANCE:
+
+Database maintenance, i.e. deletion of expired records, has to be done
separatly.
+I've bundled a perl script (greylist-cleanup.pl) formerly submitted by Gerard
Earley
+to the QMR mailing list.
+It's advised that you preform such maintenance once a day, peharps setting up
a cronjob.
+
+Ex:
+ 0 0 * * * root /usr/local/bin/greylist-cleanup.pl
diff -u -N -r qmail-ldap-1.03-20060201/TARGETS
qmail-ldap-1.03-20060201-greylist-0.3/TARGETS
--- qmail-ldap-1.03-20060201/TARGETS 2007-01-21 01:39:36.000000000 +0000
+++ qmail-ldap-1.03-20060201-greylist-0.3/TARGETS 2007-01-20
20:12:13.000000000 +0000
@@ -381,6 +381,9 @@
man
setup
check
+local_scan.o
+qmail-envelope-scanner.o
+qmail-envelope-scanner
auth_imap
Makefile.cdb-p
auth_imap.o
|