From 84688a05a4430daf8dedf80bce35286aff4f4b1c Mon Sep 17 00:00:00 2001 From: John Denker Date: Thu, 19 Jul 2012 17:24:43 -0700 Subject: bare beginnings of a greylisting system --- tools/filters.conf | 1 + tools/greylist.c | 89 +++++++++++++++++++++++++++++++++++++++++- tools/hi-q.c | 111 +++++++++++++++++++++++++++++------------------------ 3 files changed, 149 insertions(+), 52 deletions(-) (limited to 'tools') diff --git a/tools/filters.conf b/tools/filters.conf index 8bc2efe..641b792 100644 --- a/tools/filters.conf +++ b/tools/filters.conf @@ -1,4 +1,5 @@ # configuration file for hi-q black /var/qmail/bin/skrewt +gray /var/qmail/bin/greylist black /usr/local/bin/spamc -Y 0 -s 1000000 qq /var/qmail/bin/qmail-queue diff --git a/tools/greylist.c b/tools/greylist.c index fa7d701..8adac05 100644 --- a/tools/greylist.c +++ b/tools/greylist.c @@ -1,5 +1,92 @@ +#include /* for exit(), getenv() */ +#include +#include +#include /* for stat() */ +#include /* for stat() */ +#include /* for stat() */ +#include /* for perror */ +#include /* for ENOENT */ +#include /* for ofstream() */ +#include /* for creat() */ +using namespace std; -int main(){ +const int sa_good = 0; +const int bug_bait_grey = 1; +// qmail_queue and spamc have similar interpretations here: +const int sa_syserr = 71; + +pid_t mypid; +string progname; + +void dump(const string var){ + char* str = getenv(var.c_str()); + cerr << progname + << "[" << mypid << "] " + << var; + if (str) cerr << " is set to '" << str << "'" << endl; + else cerr << " is not set." << endl; +} + +const string dirname("/var/qmail/greylist"); + + // int stat(const char *path, struct stat *buf); + // int fstat(int fd, struct stat *buf); + // int lstat(const char *path, struct stat *buf); + +int main(int argc, char** argv){ + mypid = getpid(); + progname = argv[0]; +// dump("TCPREMOTEIP"); +// dump("TCPREMOTEHOST"); + + char* ipvar = getenv("TCPREMOTEIP"); + if (!ipvar) { + cerr << progname << ": TCPREMOTEIP not set???" << endl; + exit(sa_syserr); + } + string ipbase = ipvar; + +// see if our directory exists: + struct stat dirstat; + int rslt = stat(dirname.c_str(), &dirstat); + if (rslt != 0){ + if (errno != ENOENT) { + cerr << progname << ": stat failed for '" + << dirname << "' : "; + perror(0); + } + rslt = mkdir(dirname.c_str(), 0755); + if (rslt != 0) { + cerr << progname + << "uid " << getuid() + << ": mkdir failed for '" + << dirname << "' : "; + perror(0); + exit(sa_syserr); + } + } + + string ipname = dirname + "/" + ipbase; + struct stat ipstat; + rslt = stat(ipname.c_str(), &ipstat); + if (rslt != 0){ + if (errno != ENOENT) { + cerr << progname << ": stat failed for '" + << ipname << "' : "; + perror(0); + } + ofstream foo; + int fd = creat(ipname.c_str(), 0644); + if (fd < 0){ + cerr << progname << ": create failed for '" + << ipname << "' : "; + perror(0); + } + close(fd); + return(bug_bait_grey); + } else { + cerr << "file exists: " << ipname << endl; + } return 0; } diff --git a/tools/hi-q.c b/tools/hi-q.c index 2ddc448..21724a1 100644 --- a/tools/hi-q.c +++ b/tools/hi-q.c @@ -11,7 +11,7 @@ #include #include /* for exit(), getenv() */ -#include +#include /* for perror */ #include #include /* for fork(), wait() */ #include @@ -29,6 +29,7 @@ using namespace std; // error exit codes, mostly as stated in qmail.c const int ex_good = 0; const int ex_spam = 21; +const int ex_grey = 70; const int ex_syserr = 71; const int ex_comerr = 74; @@ -139,7 +140,7 @@ int xclose(int arg){ extern char** environ; -typedef enum {gray, black, qq, fail} moder; +typedef enum {grey, black, qq, fail} moder; class jobber{ public: @@ -161,8 +162,8 @@ public: void setmode(const string _mode) { if (0) {} - else if (_mode == "gray") mode = gray; - else if (_mode == "grey") mode = gray; // variant spelling + else if (_mode == "gray") mode = grey; + else if (_mode == "grey") mode = grey; // variant spelling else if (_mode == "black") mode = black; else if (_mode == "qq") mode = qq; else { @@ -175,8 +176,8 @@ public: int main(int argc, char** argv) { progname = *argv; mypid = getpid(); - dump("TCPREMOTEIP"); - dump("TCPREMOTEHOST"); +// dump("TCPREMOTEIP"); +// dump("TCPREMOTEHOST"); int verbose(0); int kidstatus; @@ -270,41 +271,44 @@ int main(int argc, char** argv) { // to close it and dup() something useful onto it. map iiofpid; - for (unsigned int ii=0; ii < nkids; ii++){ /* loop starting all kids */ - int datapipe[2]; - int kid_end; + for (unsigned int ii=0; ii < nkids; ii++){ /* loop starting all kids */ //xx fprintf(stderr, "Top of loop %d loose: %d\n", ii, loose_end); - if (loose_end) { - close(0); - dup2(loose_end, 0); - close(loose_end); - } + int kid_end; + if (filter[ii].mode != grey){ + int datapipe[2]; -// Create a pipe, which will be used to connect -// this child's fd1 to the next child's fd0 ... -// except for the last kid, which reads both fd0 and fd1, -// while writing nothing. + if (loose_end) { + close(0); + dup2(loose_end, 0); + close(loose_end); + } - rslt = pipe(datapipe); - if (rslt < 0) { - fprintf(stderr, "hi-q: could not create datapipe: "); - perror(0); - panic(ex_syserr); - } + // Create a pipe, which will be used to connect + // this child's fd1 to the next child's fd0 ... + // except for the last kid, which reads both fd0 and fd1, + // while writing nothing. -//xx fprintf(stderr, "pipe: %d %d\n", datapipe[0], datapipe[1]); + rslt = pipe(datapipe); + if (rslt < 0) { + fprintf(stderr, "hi-q: could not create datapipe: "); + perror(0); + panic(ex_syserr); + } -// For N-1 kids, the loose end feeds forward. -// It will be written by this kid and read by the next kid. -// For the last kid, the loose end connects to hi-q. -// It will be written by hi-q and read by the last kid. + //xx fprintf(stderr, "pipe: %d %d\n", datapipe[0], datapipe[1]); - int lastkid = (ii == nkids-1); -#define flip(a,b) (lastkid ? b : a) - loose_end = datapipe[flip(rEnd, wEnd)]; - kid_end = datapipe[flip(wEnd, rEnd)]; + // For N-1 kids, the loose end feeds forward. + // It will be written by this kid and read by the next kid. + // For the last kid, the loose end connects to hi-q. + // It will be written by hi-q and read by the last kid. + + int lastkid = (ii == nkids-1); + #define flip(a,b) (lastkid ? b : a) + loose_end = datapipe[flip(rEnd, wEnd)]; + kid_end = datapipe[flip(wEnd, rEnd)]; + } kidpid[ii] = fork(); if (kidpid[ii] == -1) { @@ -358,24 +362,23 @@ int main(int argc, char** argv) { } } -// Now that we are through creating pipes, we don't -// need to continue blocking fd1: - close(1); - - close(loose_end); // the reading end is none of this kid's business - // except last kid: writing end + if (filter[ii].mode != grey){ + close(loose_end); // the reading end is none of this kid's business + // except last kid: writing end + + // Note this does an implicit close on the previously-open fd1: + rslt = dup2(kid_end, 1); // the writing end is stdout for this kid + // except last kid: nonstandard input + if (rslt < 0) { + fprintf(stderr, "hi-q: kid %d: dup2(%d,1) failed: ", ii, kid_end); + perror(0); + exit(ex_syserr); + } - rslt = dup2(kid_end, 1); // the writing end is stdout for this kid - // except last kid: nonstandard input - if (rslt < 0) { - fprintf(stderr, "hi-q: kid %d: dup2(%d,1) failed: ", ii, kid_end); - perror(0); - exit(ex_syserr); + close(kid_end); // use fd1 instead now + // OK, at this point this kid is set up to read fd0 and write fd1 + // (except last kid reads fd1 as well as fd0). } - - close(kid_end); // use fd1 instead now - // OK, at this point this kid is set up to read fd0 and write fd1 - // (except last kid reads fd1 as well as fd0). //// probe_fd(); int ntok = filter[ii].cmd.size(); @@ -499,14 +502,20 @@ int main(int argc, char** argv) { if (best_blame) { string short_name(""); int kidno(iiofpid[argbest_blame]); + string exword = "spam"; + int excode = ex_spam; + if (filter[kidno].mode == grey) { + exword = "greylisting"; + excode = ex_grey; + } if (WIFEXITED(best_blame)) { int sts = WEXITSTATUS(best_blame); if (sts == 1) { cerr << "hi-q says: kid[" << kidno << "]" << " pid " << argbest_blame << " i.e. '" << filter[kidno].cmd[0] << "'" - << " reports spam." << endl; - panic(ex_spam); + << " reports " << exword << endl; + panic(excode); } if (sts != 0) { cerr << "hi-q says: kid " << argbest_blame -- cgit v1.2.3