X-Git-Url: http://git.madism.org/?a=blobdiff_plain;f=greylist.c;h=e556883c266e94bfaa5d354f76d51baef6fb55a9;hb=6a736221313a18d611bc5e2c49f4fa8b354390f2;hp=9f4895aa485bb14e0e14dcf95cc65396f620973c;hpb=cf48fad99532b7590b8bfea416532a7a84910bdf;p=apps%2Fpfixtools.git diff --git a/greylist.c b/greylist.c index 9f4895a..e556883 100644 --- a/greylist.c +++ b/greylist.c @@ -35,19 +35,17 @@ #include +#include "common.h" #include "greylist.h" #include "str.h" -static struct { - int do_awl; - int awl_count; - bool lookup_by_host; - - int delay; - int retry_window; - - TCBDB *awl_db, *obj_db; -} cfg; +struct greylist_cfg greylist_cfg = { + .lookup_by_host = false, + .delay = 300, + .retry_window = 2 * 24 * 2600, + .client_awl = 5, +}; +static TCBDB *awl_db, *obj_db; struct awl_entry { int32_t count; @@ -59,6 +57,50 @@ struct obj_entry { time_t last; }; +int greylist_initialize(const char *directory, const char *prefix) +{ + char path[PATH_MAX]; + + if (greylist_cfg.client_awl) { + snprintf(path, sizeof(path), "%s/%swhitelist.db", directory, prefix); + awl_db = tcbdbnew(); + if (!tcbdbopen(awl_db, path, BDBOWRITER | BDBOCREAT)) { + tcbdbdel(awl_db); + awl_db = NULL; + } + return -1; + } + + snprintf(path, sizeof(path), "%s/%sgreylist.db", directory, prefix); + obj_db = tcbdbnew(); + if (!tcbdbopen(obj_db, path, BDBOWRITER | BDBOCREAT)) { + tcbdbdel(obj_db); + obj_db = NULL; + if (awl_db) { + tcbdbdel(awl_db); + awl_db = NULL; + } + return -1; + } + + return 0; +} + +static void greylist_shutdown(void) +{ + if (awl_db) { + tcbdbsync(awl_db); + tcbdbdel(awl_db); + awl_db = NULL; + } + if (obj_db) { + tcbdbsync(obj_db); + tcbdbdel(obj_db); + obj_db = NULL; + } +} +module_exit(greylist_shutdown); + const char *sender_normalize(const char *sender, char *buf, int len) { const char *at = strchr(sender, '@'); @@ -100,7 +142,7 @@ c_net(const char *c_addr, const char *c_name, char *cnet, int cnetlen) char ip2[4], ip3[4]; const char *dot, *p; - if (cfg.lookup_by_host) + if (greylist_cfg.lookup_by_host) return c_addr; if (!(dot = strchr(c_addr, '.'))) @@ -130,6 +172,11 @@ c_net(const char *c_addr, const char *c_name, char *cnet, int cnetlen) bool try_greylist(const char *sender, const char *c_addr, const char *c_name, const char *rcpt) { +#define INCR_AWL \ + aent.count++; \ + aent.last = now; \ + tcbdbput(awl_db, c_addr, c_addrlen, &aent, sizeof(aent)); + char sbuf[BUFSIZ], cnet[64], key[BUFSIZ]; const void *res; @@ -139,44 +186,70 @@ bool try_greylist(const char *sender, const char *c_addr, int len, klen, c_addrlen = strlen(c_addr); - - if (cfg.do_awl) { - res = tcbdbget3(cfg.awl_db, c_addr, c_addrlen, &len); + /* Auto whitelist clients. + */ + if (greylist_cfg.client_awl) { + res = tcbdbget3(awl_db, c_addr, c_addrlen, &len); if (res && len == sizeof(aent)) { memcpy(&aent, res, len); } - if (aent.count > cfg.awl_count) { - if (now < aent.last + 3600) - goto incr_aent; + + /* Whitelist if count is enough. + */ + if (aent.count > greylist_cfg.client_awl) { + if (now < aent.last + 3600) { + INCR_AWL + } + + /* OK. + */ return true; } } + /* Lookup. + */ klen = snprintf(key, sizeof(key), "%s/%s/%s", c_net(c_addr, c_name, cnet, sizeof(cnet)), sender_normalize(sender, sbuf, sizeof(sbuf)), rcpt); klen = MIN(klen, ssizeof(key) - 1); - res = tcbdbget3(cfg.obj_db, key, klen, &len); + res = tcbdbget3(obj_db, key, klen, &len); if (res && len == sizeof(oent)) { memcpy(&oent, res, len); } - if (oent.last - oent.first < cfg.delay - && now - oent.first > cfg.retry_window) - { + /* Discard stored first-seen if it is the first retrial and + * it is beyong the retry window. + */ + if (oent.last - oent.first < greylist_cfg.delay + && now - oent.first > greylist_cfg.retry_window) { oent.first = now; } + + /* Update. + */ oent.last = now; - tcbdbput(cfg.obj_db, key, klen, &oent, sizeof(oent)); - if (oent.first + cfg.delay < now) { - if (cfg.do_awl) { - incr_aent: - aent.count++; - aent.last = now; - tcbdbput(cfg.awl_db, c_addr, c_addrlen, &aent, sizeof(aent)); + tcbdbput(obj_db, key, klen, &oent, sizeof(oent)); + + /* Auto whitelist clients: + * algorithm: + * - on successful entry in the greylist db of a triplet: + * - client not whitelisted yet ? -> increase count + * -> withelist if count > limit + * - client whitelisted already ? -> update last-seen timestamp. + */ + if (oent.first + greylist_cfg.delay < now) { + if (greylist_cfg.client_awl) { + INCR_AWL } + + /* OK + */ return true; } + + /* DUNNO + */ return false; }