EE, What are the chances of including this patch in the basic simscan-toaster?
While I'm inclined to believe that greylisting is best implemented at the firewall, what are the drawbacks to having it in the toaster? -------- Original Message -------- Subject: [simscan] [PATCH] Updated greylisting patch for simscan 1.2 Date: Mon, 13 Nov 2006 20:10:55 +0100 From: Florian G. Pflug <[EMAIL PROTECTED]> Reply-To: [EMAIL PROTECTED] To: [EMAIL PROTECTED] Hi I've updates the greylisting patch to simscan 1.2 It now uses log_message log initial blocking, and the first successfull attempt by a sender. greetings, Florian Pflug !DSPAM:4558c2c627411592547952! -- -Eric 'shubes'
diff -Naur simscan-1.2/configure.in simscan-1.2.greylist/configure.in --- simscan-1.2/configure.in 2005-09-30 23:15:47.000000000 +0200 +++ simscan-1.2.greylist/configure.in 2006-11-12 13:12:45.000000000 +0100 @@ -282,6 +282,25 @@ #---------------------------------------------------------------------- +AC_ARG_ENABLE(greylist, [ --enable-greylist=y|n Turn on greylisting. default no.], + ENABLE_GREYLIST="$enableval", + [ + ENABLE_GREYLIST=no + ] ) +case $ENABLE_GREYLIST in +1*|y*|Y*) + ENABLE_GREYLIST=1 + AC_DEFINE_UNQUOTED([ENABLE_GREYLIST], $ENABLE_GREYLIST, [enable greylisting]) + ;; +*) + ENABLE_GREYLIST=0 + ;; +esac + +AC_SUBST(ENABLE_GREYLIST) + +#---------------------------------------------------------------------- + AC_MSG_CHECKING(whether we can locate the qmail directory) qmaildir="" for f in /var/qmail @@ -796,4 +815,14 @@ ;; esac +case $ENABLE_GREYLIST in + 1*|y*|Y*) + echo " greylisting = ON" + ;; + + *) + echo " greylisting = OFF" + ;; +esac + echo "" diff -Naur simscan-1.2/Makefile.am simscan-1.2.greylist/Makefile.am --- simscan-1.2/Makefile.am 2004-11-04 16:27:45.000000000 +0100 +++ simscan-1.2.greylist/Makefile.am 2006-11-12 13:12:45.000000000 +0100 @@ -17,9 +17,11 @@ $(INSTALL) simscan @qmaildir@/bin/simscan $(INSTALL) simscanmk @qmaildir@/bin/simscanmk $(INSTALL) -m 750 -d @workdir@ + test "@ENABLE_GREYLIST@" = "1" && $(INSTALL) -m 2750 -d @workdir@/scanner + test "@ENABLE_GREYLIST@" = "1" && $(INSTALL) -m 2750 -d @workdir@/greylist strip @qmaildir@/bin/simscan strip @qmaildir@/bin/simscanmk - chown @ENABLE_USER@ @workdir@ @qmaildir@/bin/simscan + chown -R @ENABLE_USER@ @workdir@ @qmaildir@/bin/simscan chmod 4711 @qmaildir@/bin/simscan AUTOMAKE_OPTIONS = foreign no-dependencies diff -Naur simscan-1.2/simscan.c simscan-1.2.greylist/simscan.c --- simscan-1.2/simscan.c 2005-10-05 23:12:42.000000000 +0200 +++ simscan-1.2.greylist/simscan.c 2006-11-12 13:26:32.000000000 +0100 @@ -19,6 +19,8 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <time.h> +#include <utime.h> #include <sys/types.h> #include <sys/wait.h> #include <sys/stat.h> @@ -68,7 +70,6 @@ 91 Envelope format error. */ - #ifdef QUARANTINEDIR void quarantine_msg(char *message_name); #endif @@ -85,6 +86,11 @@ char message_name[BUFFER_SIZE]; char workdir[BUFFER_SIZE]; char unique_ext[BUFFER_SIZE]; +#ifdef ENABLE_GREYLIST +char greylist_initial[BUFFER_SIZE]; +char greylist_allowed[BUFFER_SIZE]; +char greylist_dir[BUFFER_SIZE]; +#endif void format_dir(char *workdir); void exit_clean(int error_code); @@ -123,8 +129,9 @@ int PerDomainSpam; int PerDomainTrophie; int PerDomainSpamPassthru; -int MaxDomains; -char Domains[MAXDOMAINS][MAXDOMLEN]; +#ifdef ENABLE_GREYLIST +int PerDomainGreylist; +#endif void set_per_domain(); void init_per_domain(); @@ -187,7 +194,7 @@ #endif struct timeval start,stop; -double utime; +double delta; #define SECS(tv) (tv.tv_sec + tv.tv_usec / 1000000.0) /* write a received line */ @@ -208,6 +215,27 @@ void log_message( char *state, char *subject, int spam ); +#ifdef ENABLE_GREYLIST +/* + * Timing for greylisting. + * + * Algorithm: When a sender with a source ip for which no record yet exists + * connects, his delivery will fail with a temporary error. + * All following delivery attempts by that sender will fail with + * a temporary error too, until GREYLIST_MIN_DELAY seconds after + * his _first_ attempt. + * Delivery attempts started between GREYLIST_MIN_DELAY and + * GREYLIST_MAX_DELAY seconds after the first delivery attempt + * will succeed, and cause all future mails from that sender to + * be accepted immediatly. + */ +#define GREYLIST_MIN_DELAY 60 +#define GREYLIST_MAX_DELAY 36*3600 + +void format_greylist(char* greylist_dir, char* greylist_initial, char* greylist_allowed); +int check_greylist(); +#endif + int main(int argc, char **argv) { #ifdef HAS_ULIMIT_NPROC @@ -255,9 +283,23 @@ /* format the new directory name */ format_dir(workdir); + + /* format greylist names */ +#ifdef ENABLE_GREYLIST + format_greylist(greylist_dir, greylist_initial, greylist_allowed); +#endif if ( DebugFlag > 0 ) { +#ifdef ENABLE_GREYLIST + fprintf(stderr, + "simscan: starting: work dir: %s, greylistdir: %s, sourceip: %s\n", + workdir, + greylist_dir, + getenv("TCPREMOTEIP") + ); +#else fprintf(stderr, "simscan: starting: work dir: %s\n", workdir); +#endif } /* create the working directory, allow group access too */ @@ -269,6 +311,17 @@ _exit(EXIT_400); } +#ifdef ENABLE_GREYLIST + /* create the working directory, allow group access too */ + if ( (mkdir(greylist_dir, 0750) == -1) && (errno != EEXIST) ) { + if ( DebugFlag > 0 ) { + fprintf(stderr, "simscan: error making graylist dir, exit 400, errno: %d\n", + errno); + } + _exit(EXIT_400); + } +#endif + /* change to the new working directory */ if ( chdir(workdir) != 0 ) { if ( DebugFlag > 0 ) { @@ -361,6 +414,31 @@ set_per_domain(); #endif +#ifdef ENABLE_GREYLIST + switch ( check_greylist() ) { + case -2: + if ( DebugFlag > 0 ) { fprintf(stderr, "simscan: greylisting disabled\n"); } + break; + case 1: + log_message("GREYLIST DELAYED", "-", 0); +#ifdef ENABLE_CUSTOM_SMTP_REJECT + snprintf(RejectMsg,sizeof(RejectMsg), + "ZFirst connection from %s. Just retry, and you mail will be accepted", + getenv("TCPREMOTEIP") ); + write(4,RejectMsg, strlen(RejectMsg)); + exit_clean(EXIT_MSG); +#else + exit_clean(EXIT_400); +#endif + break; + case 2: + log_message("GREYLIST ACCEPTED", "-", 0); + break; + default: + break; + } +#endif + #ifdef ENABLE_REGEX /* check for regexs to block */ if ( check_regex() == 2 ) { @@ -608,10 +686,10 @@ #ifdef ENABLE_RECEIVED gettimeofday(&stop,(struct timezone *) 0); - utime=SECS(stop)-SECS(start); + delta=SECS(stop)-SECS(start); snprintf(buffer,sizeof(buffer), "Received: by simscan %s ppid: %d, pid: %d, t: %3.4fs\n scanners:%s\n", - VERSION,getppid(),getpid(),utime, + VERSION,getppid(),getpid(),delta, strlen(runned_scanners) > 0 ? runned_scanners : "none"); if ( write(pim[1], buffer,strlen(buffer)) == -1 ) { if ( DebugFlag > 0 ) { @@ -1082,10 +1160,36 @@ snprintf(unique_ext, sizeof(unique_ext),"%ld.%ld.%ld", mytime.tv_sec, mytime.tv_usec, (long int)getpid()); +#ifdef ENABLE_GREYLIST snprintf(workdir,BUFFER_SIZE, "%s/%s", WORKDIR, unique_ext); +#else + snprintf(workdir,BUFFER_SIZE, "%s/scanner/%s", WORKDIR, unique_ext); +#endif } +#ifdef ENABLE_GREYLIST +/* + * create path to state file for TCPREMOTEIP + */ +void format_greylist(char* greylist_dir, char* greylist_initial, char* greylist_allowed) +{ + char h=0, *ip=getenv("TCPREMOTEIP") ; + int i, l=strlen(ip) ; + + /* Compute hash */ + for(i=0; i < l; i++) + h = ip[i] ^ ( + ((h & 0xf0)>>4) | + ((h & 0x0f)<<4) + ) ; + + snprintf(greylist_dir,BUFFER_SIZE, "%s/greylist/%02hhx", WORKDIR, h); + snprintf(greylist_initial,BUFFER_SIZE, "%s/greylist/%02hhx/%s.initial", WORKDIR, h, ip); + snprintf(greylist_allowed,BUFFER_SIZE, "%s/greylist/%02hhx/%s.allowed", WORKDIR, h, ip); +} +#endif + /* * From vpopmail source * recursively remove a directory and all it's files @@ -1377,6 +1481,7 @@ PerDomainSpam = 0; PerDomainTrophie = 0; PerDomainSpamPassthru = 0; + PerDomainGreylist = 0; per_domain_lookup(""); } @@ -1469,6 +1574,15 @@ } if ( DebugFlag > 1 ) fprintf(stderr, "simscan: spampassthru = %s/%d\n", val,PerDomainSpamPassthru); #endif +#ifdef ENABLE_GREYLIST + } else if ( strcasecmp(parm,"greylist") == 0 ) { + if ( DebugFlag > 1 ) fprintf(stderr, "simscan: greylist = %s\n", val); + if ( strcasecmp(val, "yes") == 0 ) { + PerDomainGreylist = 1; + } else if ( strcasecmp(val, "no") == 0 ) { + PerDomainGreylist = 0; + } +#endif } else { if ( DebugFlag > 1 ) fprintf(stderr, "simscan: unimplemented flag %s = %s\n", parm, val); } @@ -1635,6 +1749,61 @@ #endif +#ifdef ENABLE_GREYLIST +int check_greylist () { + struct stat statbuf ; + double elapsed ; + FILE* fh ; + + /* Always allow authenticated senders */ + if (getenv("RELAYCLIENT")) { + log_message("RELAYCLIENT", "-", 0); + return 0; + } + +#ifdef ENABLE_PER_DOMAIN + if ( PerDomainGreylist == 0 ) return(-2); +#endif + + /* Is the sender allowed to send? */ + if (lstat(greylist_allowed, &statbuf) == 0) { + utime(greylist_allowed, NULL); + return 0; + } + + /* Have we ever seen him? */ + if (lstat(greylist_initial, &statbuf) != 0) { + /* Here for the first time. */ + if ( (fh = fopen(greylist_initial, "w")) == NULL) { + fprintf(stderr, "simscan: could not create: %s\n", greylist_initial); + exit_clean(EXIT_400); + } + fclose(fh); + return 1; + } + + elapsed = difftime(time(NULL), statbuf.st_mtime) ; + if (elapsed < GREYLIST_MIN_DELAY) { + /* Sender needs to be patient */ + return 1; + } + else if (elapsed > GREYLIST_MAX_DELAY) { + /* He's too late. Pretent he's here for the first time. */ + utime(greylist_initial, NULL); + return 1; + } + + /* Sender is at the right place in the right timeframe. */ + if ( (fh = fopen(greylist_allowed, "w")) == NULL) { + fprintf(stderr, "simscan: could not create: %s\n", greylist_allowed); + exit_clean(EXIT_400); + } + fclose(fh); + unlink(greylist_initial); + return 2; +} +#endif + #ifdef ENABLE_REGEX /* check_regex - returns 0 if no match * returns 1 if there was an error matching @@ -1875,17 +2044,17 @@ float reqhits; gettimeofday(&stop,(struct timezone *) 0); - utime=SECS(stop)-SECS(start); + delta=SECS(stop)-SECS(start); if ( spam == 1 ) { if ( PerDomainHits == 1 ) reqhits = PDHits; else reqhits = ReqHits; fprintf(stderr, "simscan:[%d]:%s (%.2f/%.2f):%3.4fs:%s:%s:%s:%s", - getppid(), state, SpamHits,reqhits, utime, subject, + getppid(), state, SpamHits,reqhits, delta, subject, getenv("TCPREMOTEIP"), MailFrom, RcptTo[0]); } else { fprintf(stderr, "simscan:[%d]:%s:%3.4fs:%s:%s:%s:%s", - getppid(),state,utime,subject,getenv("TCPREMOTEIP"),MailFrom,RcptTo[0]); + getppid(),state,delta,subject,getenv("TCPREMOTEIP"),MailFrom,RcptTo[0]); } for(i=1;i<MaxRcptTo;++i) { !DSPAM:4558c2c627411592547952!
--------------------------------------------------------------------- QmailToaster hosted by: VR Hosted <http://www.vr.org> --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]