Mercurial > dnsbl
diff src/context.cpp @ 153:8d7c439bb6fa
add auto whitelisting
author | carl |
---|---|
date | Sat, 07 Jul 2007 16:10:39 -0700 |
parents | c7fc218686f5 |
children | 89ce226e5383 |
line wrap: on
line diff
--- a/src/context.cpp Sat Jul 07 10:26:31 2007 -0700 +++ b/src/context.cpp Sat Jul 07 16:10:39 2007 -0700 @@ -21,6 +21,7 @@ static char* context_version="$Id$"; +char *token_autowhite; char *token_black; char *token_content; char *token_context; @@ -63,10 +64,16 @@ #endif char myhostname[HOST_NAME_MAX+1]; +pthread_mutex_t verifier_mutex; // protect the verifier map verify_map verifiers; + +pthread_mutex_t whitelister_mutex; // protect the +whitelister_map whitelisters; + string_set all_strings; // owns all the strings, only modified by the config loader thread const int maxlen = 1000; // used for snprintf buffers -const int maxage = 120; // smtp verify sockets older than this are ancient +const int maxsmtp_age = 120;// smtp verify sockets older than this are ancient +const int maxauto_age = 600;// auto whitelister delay before flushing to file extern int NULL_SOCKET; const time_t ERROR_SMTP_SOCKET_TIME = 600; // number of seconds between attempts to open a socket to an smtp server @@ -243,6 +250,9 @@ #endif +//////////////////////////////////////////////// +// smtp verifier so backup mx machines can see the valid users +// VERIFY::VERIFY(char *h) { host = h; last_err = 0; @@ -261,7 +271,7 @@ else { conn = connections.front(); time_t now = time(NULL); - if ((now - conn->get_stamp()) > maxage) { + if ((now - conn->get_stamp()) > maxsmtp_age) { // this connection is ancient, remove it connections.pop_front(); } @@ -372,6 +382,140 @@ } +//////////////////////////////////////////////// +// setup a new smtp verify host +// +VERIFYP add_verify_host(char *host); +VERIFYP add_verify_host(char *host) { + VERIFYP rc = NULL; + pthread_mutex_lock(&verifier_mutex); + verify_map::iterator i = verifiers.find(host); + if (i == verifiers.end()) { + rc = new VERIFY(host); + verifiers[host] = rc; + } + else rc = (*i).second; + pthread_mutex_unlock(&verifier_mutex); + return rc; +} + + +//////////////////////////////////////////////// +// thread to check for verify hosts with old sockets that we can close +// +void* verify_closer(void *arg) { + while (true) { + sleep(maxsmtp_age); + pthread_mutex_lock(&verifier_mutex); + for (verify_map::iterator i=verifiers.begin(); i!=verifiers.end(); i++) { + VERIFYP v = (*i).second; + v->closer(); + } + pthread_mutex_unlock(&verifier_mutex); + } + return NULL; +} + + +//////////////////////////////////////////////// +// automatic whitelister +// +WHITELISTER::WHITELISTER(char *f, int d) { + fn = f; + days = d; + pthread_mutex_init(&mutex, 0); + need = false; +} + + +void WHITELISTER::writer() { + pthread_mutex_lock(&mutex); + time_t limit = time(NULL) - days*86400; + for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end();) { + time_t when = (*i).second; + if (when < limit) { + autowhite_sent::iterator j = i; + j++; + rcpts.erase(i); + i = j; + need = true; + } + else i++; + } + if (need) { + // dump the file + ofstream os; + os.open(fn); + if (!os.fail()) { + for (autowhite_sent::iterator i=rcpts.begin(); i!=rcpts.end(); i++) { + char *who = (*i).first; + int when = (*i).second; + os << who << " " << when << endl; + } + } + os.close(); + } + pthread_mutex_unlock(&mutex); +} + + +void WHITELISTER::sent(char *to) { + pthread_mutex_lock(&mutex); + need = true; + rcpts[to] = time(NULL); + pthread_mutex_unlock(&mutex); +} + + +bool WHITELISTER::is_white(char *from) { + bool rc = false; + pthread_mutex_lock(&mutex); + autowhite_sent::iterator i = rcpts.find(from); + if (i != rcpts.end()) { + time_t when = (*i).second; + time_t now = time(NULL); + rc = (when+(days*8640) > now); + } + pthread_mutex_unlock(&mutex); + return rc; +} + + +//////////////////////////////////////////////// +// setup a new auto whitelister file +// +WHITELISTERP add_whitelister_file(char *fn, int days); +WHITELISTERP add_whitelister_file(char *fn, int days) { + WHITELISTERP rc = NULL; + pthread_mutex_lock(&whitelister_mutex); + whitelister_map::iterator i = whitelisters.find(fn); + if (i == whitelisters.end()) { + rc = new WHITELISTER(fn, days); + whitelisters[fn] = rc; + } + else rc = (*i).second; + pthread_mutex_unlock(&whitelister_mutex); + return rc; +} + + +//////////////////////////////////////////////// +// thread to check for whitelister hosts with old sockets that we can close +// +void* whitelister_writer(void *arg) { + while (true) { + sleep(maxauto_age); + pthread_mutex_lock(&whitelister_mutex); + for (whitelister_map::iterator i=whitelisters.begin(); i!=whitelisters.end(); i++) { + WHITELISTERP v = (*i).second; + v->writer(); + } + pthread_mutex_unlock(&whitelister_mutex); + } + return NULL; +} + + DNSBL::DNSBL(char *n, char *s, char *m) { name = n; suffix = s; @@ -474,6 +618,9 @@ parent = parent_; name = name_; verify_host = NULL; + verifier = NULL; + autowhite_file = NULL; + whitelister = NULL; env_from_default = (parent) ? token_inherit : token_unknown; content_filtering = (parent) ? parent->content_filtering : false; content_suffix = NULL; @@ -531,22 +678,22 @@ VERIFYP CONTEXT::find_verify(char *to) { - if (verify_host && (verify_host != token_myhostname) && cover_env_to(to)) { - verify_map::iterator i = verifiers.find(verify_host); - if (i == verifiers.end()) { - if (debug_syslog) { - char buf[maxlen]; - snprintf(buf, maxlen, "cannot find struc for %s", verify_host); - my_syslog(buf); - } + if (verifier && (verify_host != token_myhostname) && cover_env_to(to)) + return verifier; + else if (parent) + return parent->find_verify(to); + else return NULL; } - VERIFYP v = (*i).second; + - return v; - } - else if (parent) return parent->find_verify(to); - else return NULL; +WHITELISTERP CONTEXT::find_autowhite(char *to) { + if (whitelister && cover_env_to(to)) + return whitelister; + else if (parent) + return parent->find_autowhite(to); + else + return NULL; } @@ -558,6 +705,7 @@ char *CONTEXT::find_from(char *from) { + if (whitelister && whitelister->is_white(from)) return token_white; char *rc = env_from_default; string_map::iterator i = env_from.find(from); if (i != env_from.end()) rc = (*i).second; // found user@domain key @@ -775,6 +923,10 @@ printf("%s verify %s; \n", indent, verify_host); } + if (autowhite_file && whitelister) { + printf("%s autowhite %d %s; \n", indent, whitelister->get_days(), autowhite_file); + } + for (context_map::iterator i=children.begin(); i!=children.end(); i++) { CONTEXTP c = (*i).second; c->dump(false, level+1); @@ -1100,7 +1252,20 @@ char *host = tok.next(); if (!tsa(tok, token_semi)) return false; me.set_verify(host); - add_verify_host(host); + me.set_verifier(add_verify_host(host)); + return true; +} + + +//////////////////////////////////////////////// +// +bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me); +bool parse_autowhite(TOKEN &tok, CONFIG &dc, CONTEXT &me) { + int days = tok.nextint(); + char *fn = tok.next(); + if (!tsa(tok, token_semi)) return false; + me.set_autowhite(fn); + me.set_whitelister(add_whitelister_file(fn, days)); return true; } @@ -1233,6 +1398,9 @@ else if (have == token_verify) { if (!parse_verify(tok, dc, *con)) return false; } + else if (have == token_autowhite) { + if (!parse_autowhite(tok, dc, *con)) return false; + } else if (have == token_envfrom) { if (!parse_envfrom(tok, dc, *con)) return false; } @@ -1286,36 +1454,10 @@ //////////////////////////////////////////////// -// setup a new smtp verify host -// -void add_verify_host(char *host) { - verify_map::iterator i = verifiers.find(host); - if (i == verifiers.end()) { - VERIFYP v = new VERIFY(host); - verifiers[host] = v; - } -} - - -//////////////////////////////////////////////// -// thread to check for verify hosts with old sockets that we can close -// -void* verify_closer(void *arg) { - while (true) { - sleep(maxage); - for (verify_map::iterator i=verifiers.begin(); i!=verifiers.end(); i++) { - VERIFYP v = (*i).second; - v->closer(); - } - } - return NULL; -} - - -//////////////////////////////////////////////// // init the tokens // void token_init() { + token_autowhite = register_string("autowhite"); token_black = register_string("black"); token_cctld = register_string("cctld"); token_content = register_string("content");