From 60ebe6c00a2868e6bb69ef30cf04e5568276808b Mon Sep 17 00:00:00 2001 From: John Denker Date: Fri, 20 Jul 2012 22:18:31 -0700 Subject: implement penaltybox return-code (exit status) also make sure DNS checking doesn't interfere with more basic duties such as keeping the greylist database updated --- tools/greylist.c | 82 +++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 55 insertions(+), 27 deletions(-) (limited to 'tools/greylist.c') diff --git a/tools/greylist.c b/tools/greylist.c index 465a78e..c5c891f 100644 --- a/tools/greylist.c +++ b/tools/greylist.c @@ -31,6 +31,7 @@ const int probation(4*hour); #define foo(name, num) const int ex_ ## name = num #define bar foo(good, 0) ;\ foo(spam, 21) ;\ +foo(penaltybox, 22) ;\ foo(greylisting, 70) ;\ foo(syserr, 71) ;\ foo(comerr, 74) ; @@ -90,9 +91,12 @@ public: int ac_age; string suffix; string progid; + int verbosity; whatsit(const string name, const string _dirname) - : dirname(_dirname), progname(name), mypid(getpid()), mod_age(0), ac_age(0) + : dirname(_dirname), progname(name), mypid(getpid()), + mod_age(0), ac_age(0), + verbosity(0) { gettimeofday(&now, NULL); } @@ -103,9 +107,15 @@ public: void bind(); }; +string basename(const string path){ + size_t where = path.rfind("/"); + if (where != string::npos) return path.substr(1+where); + return path; +} + void whatsit::bind(){ stringstream foo; - foo << progname << suffix + foo << basename(progname) << suffix << "[" << mypid << "]"; progid = foo.str(); } @@ -166,6 +176,7 @@ void scan(const string progid, const string p, const int copies=1){ if (mod_age != ac_age) cout << "!"; } else if (mod_age < minimum_age) { cout << " young"; + if (mod_age != ac_age) cout << "!"; } else if (mod_age == ac_age) { cout << " unused"; } else if (mod_age > maximum_age) { @@ -185,12 +196,15 @@ void scan(const string progid, const string p, const int copies=1){ void whatsit::update(const string msg, const timeval new_mod, const timeval new_ac, const int penalty){ - cerr << progid << ": " - << msg << ": " << ipbase; - if (hostname.length()) cerr << " " << hostname; - cerr << " mod_age: " << time_out(mod_age) - << " ac_age: " << time_out(ac_age) - << endl; + if (verbosity){ + cerr << progid << ": "; + if (penalty) cerr << " penalty+"; + cerr << msg << ": " << ipbase; + if (hostname.length()) cerr << " " << hostname; + cerr << " mod_age: " << time_out(mod_age) + << " ac_age: " << time_out(ac_age) + << endl; + } timeval pen_mod(new_mod); if (penalty) { pen_mod = now; @@ -213,12 +227,17 @@ int main(int _argc, char** _argv){ int scanmode(0); int copies(1); int penalty(0); + int check(0); while (argc > 0) { string arg = argv[0]; argc--; argv++; if (prefix(arg, "-scan")) { scanmode++; } else if (prefix(arg, "-copy")) { copies++; + } else if (prefix(arg, "-verbose")) { + foo.verbosity++; + } else if (prefix(arg, "-check")) { + check++; } else if (prefix(arg, "-penalize") || prefix(arg, "-penalty")) { if (!argc){ @@ -244,7 +263,22 @@ int main(int _argc, char** _argv){ return 0; } - return foo.doit(penalty); + int sts = foo.doit(penalty); + +// perform some extra checks. +// Probably a better design would be to +// a) make more thorough DNS checks, and +// b) move all the DNS checking to a separate module + if (check){ + char* hostvar = getenv("TCPREMOTEHOST"); + if (!hostvar) { + cerr << foo.progid + << " from " << foo.ipbase + << " ... TCPREMOTEHOST not set???" << endl; + exeunt(ex_spam); + } + } + exeunt(sts); } int whatsit::doit(const int penalty){ @@ -254,18 +288,11 @@ int whatsit::doit(const int penalty){ << " TCPREMOTEIP not set???" << endl; // should never happen // although you can make it happen using a weird test-harness - exeunt(ex_syserr); + return(ex_syserr); } ipbase = ipvar; char* hostvar = getenv("TCPREMOTEHOST"); - if (!hostvar) { - cerr << progid - << " from " << ipbase - << " ... TCPREMOTEHOST not set???" << endl; - exeunt(ex_spam); - } else { - hostname = hostvar; - } + if (hostvar) hostname = hostvar; // see if our directory exists: struct stat dirstat; @@ -283,7 +310,7 @@ int whatsit::doit(const int penalty){ << ": mkdir failed for '" << dirname << "' : "; perror(0); - exeunt(ex_syserr); + return(ex_syserr); } } @@ -304,33 +331,34 @@ int whatsit::doit(const int penalty){ perror(0); } close(fd); - update("new customer", now, now); - exeunt(ex_greylisting); + update("new customer", now, now, penalty); + return(ex_greylisting); } -// here if stat succeeded + +// now for really checking the greylist status: mod_age = now.tv_sec - ipstat.st_mtime; ac_age = now.tv_sec - ipstat.st_atime; timeval mod_orig = {ipstat.st_mtime, 0}; if (mod_age < 0) { update("penalty box", mod_orig, now, penalty); - exeunt(ex_spam); + return(ex_penaltybox); } if (mod_age < ac_age){ update("paroled spammer", now, now, penalty); - exeunt(ex_greylisting); + return(ex_greylisting); } if (mod_age < minimum_age) { update("early bird", mod_orig, now, penalty); - exeunt(ex_greylisting); + return(ex_greylisting); } if (mod_age - ac_age < minimum_age // early bird, or completely unused && mod_age > probation) { // did not diligently resubmit update("disprobation", now, now, penalty); - exeunt(ex_greylisting); + return(ex_greylisting); } if (ac_age > maximum_age) { update("too old, starting over", now, now, penalty); - exeunt(ex_greylisting); + return(ex_greylisting); } // if all checks are passed, must be OK: update("returning customer", mod_orig, now, penalty); -- cgit v1.2.3