X-Git-Url: http://git.madism.org/?a=blobdiff_plain;f=postlicyd%2Fgreylist.c;h=b2ea86cd9bee5d1ba3dab2c253e463edb67b7bde;hb=8cecbefa8f63c37cf7a8e9932eea137edcdd5773;hp=53bcf3319ebca5fe2be4b61cf8c4b55b74cb2c6b;hpb=7723ba1a23042c5bd6a920feabd93d3d373c9d55;p=apps%2Fpfixtools.git diff --git a/postlicyd/greylist.c b/postlicyd/greylist.c index 53bcf33..b2ea86c 100644 --- a/postlicyd/greylist.c +++ b/postlicyd/greylist.c @@ -41,6 +41,8 @@ typedef struct greylist_config_t { unsigned lookup_by_host : 1; + unsigned no_sender : 1; + unsigned no_recipient : 1; int delay; int retry_window; int client_awl; @@ -51,6 +53,8 @@ typedef struct greylist_config_t { } greylist_config_t; #define GREYLIST_INIT { .lookup_by_host = false, \ + .no_sender = false, \ + .no_recipient = false, \ .delay = 300, \ .retry_window = 2 * 24 * 3600, \ .client_awl = 5, \ @@ -101,7 +105,6 @@ static TCBDB *greylist_db_get(const greylist_config_t *config, char tmppath[PATH_MAX]; snprintf(tmppath, PATH_MAX, "%s.tmp", path); - syslog(LOG_INFO, "database cleanup started"); awl_db = tcbdbnew(); if (tcbdbopen(awl_db, path, BDBOREADER)) { tmp_db = tcbdbnew(); @@ -132,13 +135,13 @@ static TCBDB *greylist_db_get(const greylist_config_t *config, tcbdbcurdel(cur); tcbdbsync(tmp_db); } else { - syslog(LOG_ERR, "cannot run database cleanup: can't open destination database: %s", - tcbdberrmsg(tcbdbecode(awl_db))); + warn("cannot run database cleanup: can't open destination database: %s", + tcbdberrmsg(tcbdbecode(awl_db))); } tcbdbdel(tmp_db); } else { int ecode = tcbdbecode(awl_db); - syslog(LOG_ERR, "can not open database: %s", tcbdberrmsg(ecode)); + warn("can not open database: %s", tcbdberrmsg(ecode)); trashable = ecode != TCENOPERM && ecode != TCEOPEN && ecode != TCENOFILE && ecode != TCESUCCESS; } tcbdbdel(awl_db); @@ -146,10 +149,10 @@ static TCBDB *greylist_db_get(const greylist_config_t *config, /** Cleanup successful, replace the old database with the new one. */ if (trashable) { - syslog(LOG_INFO, "database cleanup finished: database was corrupted, create a new one"); + info("database cleanup finished: database was corrupted, create a new one"); unlink(path); } else if (replace) { - syslog(LOG_INFO, "database cleanup finished: before %u entries, after %d entries", + info("database cleanup finished: before %u entries, after %d entries", old_count, new_count); unlink(path); if (rename(tmppath, path) != 0) { @@ -157,7 +160,8 @@ static TCBDB *greylist_db_get(const greylist_config_t *config, return NULL; } } else { - syslog(LOG_INFO, "database cleanup finished: nothing to do, %u entries", new_count); + unlink(tmppath); + info("database cleanup finished: nothing to do, %u entries", new_count); } } @@ -165,7 +169,7 @@ static TCBDB *greylist_db_get(const greylist_config_t *config, */ awl_db = tcbdbnew(); if (!tcbdbopen(awl_db, path, BDBOWRITER | BDBOCREAT)) { - syslog(LOG_ERR, "can not open database: %s", tcbdberrmsg(tcbdbecode(awl_db))); + err("can not open database: %s", tcbdberrmsg(tcbdbecode(awl_db))); tcbdbdel(awl_db); return NULL; } @@ -180,7 +184,7 @@ static bool greylist_initialize(greylist_config_t *config, if (config->client_awl) { snprintf(path, sizeof(path), "%s/%swhitelist.db", directory, prefix); - syslog(LOG_INFO, "loading auto-whitelist database"); + info("loading auto-whitelist database"); config->awl_db = greylist_db_get(config, path, true, sizeof(struct awl_entry), (db_entry_checker_t)(greylist_check_awlentry)); @@ -190,7 +194,7 @@ static bool greylist_initialize(greylist_config_t *config, } snprintf(path, sizeof(path), "%s/%sgreylist.db", directory, prefix); - syslog(LOG_INFO, "loading greylist database"); + info("loading greylist database"); config->obj_db = greylist_db_get(config, path, true, sizeof(struct obj_entry), (db_entry_checker_t)(greylist_check_object)); @@ -296,6 +300,8 @@ static bool try_greylist(const greylist_config_t *config, #define INCR_AWL \ aent.count++; \ aent.last = now; \ + debug("whitelist entry for %.*s updated, count %d", \ + c_addrlen, c_addr, aent.count); \ tcbdbput(config->awl_db, c_addr, c_addrlen, &aent, \ sizeof(aent)); @@ -314,23 +320,27 @@ static bool try_greylist(const greylist_config_t *config, res = tcbdbget3(config->awl_db, c_addr, c_addrlen, &len); if (res && len == sizeof(aent)) { memcpy(&aent, res, len); + debug("client %.*s has a whitelist entry, count is %d", + c_addrlen, c_addr, aent.count); } if (!greylist_check_awlentry(config, &aent, now)) { aent.count = 0; aent.last = 0; + debug("client %.*s whitelist entry too old", + c_addrlen, c_addr); } /* Whitelist if count is enough. */ if (aent.count >= config->client_awl) { + debug("client %.*s whitelisted", c_addrlen, c_addr); if (now < aent.last + 3600) { INCR_AWL } /* OK. */ - //syslog(LOG_INFO, "client whitelisted"); return true; } } @@ -339,13 +349,14 @@ static bool try_greylist(const greylist_config_t *config, */ klen = snprintf(key, sizeof(key), "%s/%s/%s", c_net(config, c_addr, c_name, cnet, sizeof(cnet)), - sender_normalize(sender, sbuf, sizeof(sbuf)), rcpt); + config->no_sender ? "" : sender_normalize(sender, sbuf, sizeof(sbuf)), + config->no_recipient ? "" : rcpt); klen = MIN(klen, ssizeof(key) - 1); res = tcbdbget3(config->obj_db, key, klen, &len); if (res && len == sizeof(oent)) { memcpy(&oent, res, len); - greylist_check_object(config, &oent, now); + debug("found a greylist entry for %.*s", klen, key); } /* Discard stored first-seen if it is the first retrial and @@ -353,6 +364,11 @@ static bool try_greylist(const greylist_config_t *config, */ if (!greylist_check_object(config, &oent, now)) { oent.first = now; + debug("invalid retry for %.*s: %s", klen, key, + (config->max_age > 0 && now - oent.last > config->max_age) ? + "too old entry" + : (oent.last - oent.first < config->delay ? + "retry too early" : "retry too late" )); } /* Update. @@ -368,19 +384,18 @@ static bool try_greylist(const greylist_config_t *config, * - client whitelisted already ? -> update last-seen timestamp. */ if (oent.first + config->delay < now) { + debug("valid retry for %.*s", klen, key); if (config->client_awl) { INCR_AWL } /* OK */ - //syslog(LOG_INFO, "client whitelisted"); return true; } /* DUNNO */ - //syslog(LOG_INFO, "client greylisted"); return false; } @@ -413,7 +428,7 @@ static bool greylist_filter_constructor(filter_t *filter) #define PARSE_CHECK(Expr, Str, ...) \ if (!(Expr)) { \ - syslog(LOG_ERR, Str, ##__VA_ARGS__); \ + err(Str, ##__VA_ARGS__); \ greylist_config_delete(&config); \ return false; \ } @@ -423,6 +438,8 @@ static bool greylist_filter_constructor(filter_t *filter) FILTER_PARAM_PARSE_STRING(PATH, path); FILTER_PARAM_PARSE_STRING(PREFIX, prefix); FILTER_PARAM_PARSE_BOOLEAN(LOOKUP_BY_HOST, config->lookup_by_host); + FILTER_PARAM_PARSE_BOOLEAN(NO_SENDER, config->no_sender); + FILTER_PARAM_PARSE_BOOLEAN(NO_RECIPIENT, config->no_recipient); FILTER_PARAM_PARSE_INT(RETRY_WINDOW, config->retry_window); FILTER_PARAM_PARSE_INT(CLIENT_AWL, config->client_awl); FILTER_PARAM_PARSE_INT(DELAY, config->delay); @@ -448,11 +465,16 @@ static void greylist_filter_destructor(filter_t *filter) } static filter_result_t greylist_filter(const filter_t *filter, - const query_t *query) + const query_t *query, + filter_context_t *context) { const greylist_config_t *config = filter->data; - if (query->state != SMTP_RCPT) { - syslog(LOG_WARNING, "greylisting only works as smtpd_recipient_restrictions"); + if (!config->no_recipient && query->state != SMTP_RCPT) { + warn("greylisting on recipient only works as smtpd_recipient_restrictions"); + return HTK_ABORT; + } + if (!config->no_sender && query->state < SMTP_MAIL) { + warn("greylisting on sender must be performed after (or at) MAIL TO"); return HTK_ABORT; } @@ -465,7 +487,7 @@ static int greylist_init(void) { filter_type_t type = filter_register("greylist", greylist_filter_constructor, greylist_filter_destructor, - greylist_filter); + greylist_filter, NULL, NULL); /* Hooks. */ (void)filter_hook_register(type, "abort"); @@ -476,6 +498,8 @@ static int greylist_init(void) /* Parameters. */ (void)filter_param_register(type, "lookup_by_host"); + (void)filter_param_register(type, "no_sender"); + (void)filter_param_register(type, "no_recipient"); (void)filter_param_register(type, "delay"); (void)filter_param_register(type, "retry_window"); (void)filter_param_register(type, "client_awl");