From: Florent Bruneau Date: Sun, 5 Oct 2008 15:26:38 +0000 (+0200) Subject: Add DNS support for strlist filters (i.e. rhbl). X-Git-Url: http://git.madism.org/?p=apps%2Fpfixtools.git;a=commitdiff_plain;h=8d29aaadbe12876d2b36ba65217013f60cb1f6cc Add DNS support for strlist filters (i.e. rhbl). Signed-off-by: Florent Bruneau --- diff --git a/example/postlicyd.conf b/example/postlicyd.conf index 12d8ff5..57c5966 100644 --- a/example/postlicyd.conf +++ b/example/postlicyd.conf @@ -72,6 +72,9 @@ # score of the IP # - rbldns: (no)?lock:weight:filename # this is an alias for file. +# - dns: weight:hostname +# use a rbl via DNS resolution with the given weight. If a DNS lookup error occurs +# the IP is considered as beeing "not found". # - soft_threshold: score (default: 1) # minimum score to match the soft_match return value # - hard_threshold: score (default: 1) @@ -79,6 +82,7 @@ # Return value: # The score of a query is the sum of the weight of the blacklist it matched. # - If the IP can not be parsed, returns error +# - If no rbl was available (no file and all dns down), returns error. # - If the score is strictly greater >= than hard_threshold, returns hard_match # - If the score is strictly greater >= than soft_threshold, returns soft_match # - Else, returns fail @@ -125,6 +129,10 @@ spamhaus_and_abuseat { # * names beginning with '*' are sorted as 'domains' and are matched as suffix # * names starting with an alphanumirical character are sorted as 'hostnames' and are # process via exact matching. +# - dns: weight:hostname +# use a rhbl via DNS resolution with the given weight. If a DNS lookup error occurs +# the hostname is considered as beeing "not found". This can only be used with "hostnames" +# typed fields. # - soft_threshold: score (default: 1) # minimum score to match the soft_match return value # - hard_threshold: score (default: 1) @@ -140,6 +148,7 @@ spamhaus_and_abuseat { # No space is allowed in this parameter. # Return value: # The score of a query is the sum of the weight of the list it matched. +# - If no rhbl was available (no file and all dns down), returns error. # - If the score is strictly greater >= than hard_threshold, returns hard_match # - If the score is strictly greater >= than soft_threshold, returns soft_match # - Else, returns fail diff --git a/postlicyd/strlist.c b/postlicyd/strlist.c index c2704f1..2f17f90 100644 --- a/postlicyd/strlist.c +++ b/postlicyd/strlist.c @@ -37,6 +37,7 @@ #include "trie.h" #include "file.h" #include "str.h" +#include "rbl.h" #include "policy_tokens.h" typedef struct strlist_config_t { @@ -45,6 +46,10 @@ typedef struct strlist_config_t { A(bool) reverses; A(bool) partiales; + A(char) hosts; + A(int) host_offsets; + A(int) host_weights; + int soft_threshold; int hard_threshold; @@ -72,6 +77,9 @@ static void strlist_config_delete(strlist_config_t **config) array_wipe((*config)->weights); array_wipe((*config)->reverses); array_wipe((*config)->partiales); + array_wipe((*config)->hosts); + array_wipe((*config)->host_offsets); + array_wipe((*config)->host_weights); p_delete(config); } } @@ -387,6 +395,39 @@ static bool strlist_filter_constructor(filter_t *filter) } } break; + /* dns parameter. + * weight:hostname. + * define a RBL to use through DNS resolution. + */ + case ATK_DNS: { + int weight = 0; + const char *current = param->value; + const char *p = m_strchrnul(param->value, ':'); + char *next = NULL; + for (int i = 0 ; i < 2 ; ++i) { + PARSE_CHECK(i == 1 || *p, + "host parameter must contains a weight option"); + switch (i) { + case 0: + weight = strtol(current, &next, 10); + PARSE_CHECK(next == p && weight >= 0 && weight <= 1024, + "illegal weight value %.*s", + (p - current), current); + break; + + case 1: + array_add(config->host_offsets, array_len(config->hosts)); + array_append(config->hosts, current, strlen(current) + 1); + array_add(config->host_weights, weight); + break; + } + if (i != 1) { + current = p + 1; + p = m_strchrnul(current, ':'); + } + } + } break; + /* hard_threshold parameter is an integer. * If the matching score is greater or equal than this threshold, * the hook "hard_match" is called. @@ -465,6 +506,9 @@ static filter_result_t strlist_filter(const filter_t *filter, const query_t *que char normal[BUFSIZ]; const strlist_config_t *config = filter->data; int sum = 0; + bool error = true; + + if (config->is_email && ((config->match_sender && query->state < SMTP_MAIL) || (config->match_recipient && query->state != SMTP_RCPT))) { @@ -492,19 +536,58 @@ static filter_result_t strlist_filter(const filter_t *filter, const query_t *que return HTK_HARD_MATCH; \ } \ } \ + error = false; \ + } \ + } +#define DNS(Flag, Field) \ + if (config->match_ ## Flag) { \ + const int len = m_strlen(query->Field); \ + strlist_copy(normal, query->Field, len, false); \ + for (uint32_t i = 0 ; len > 0 && i < config->tries.len ; ++i) { \ + const char *rbl = array_ptr(config->hosts, \ + array_elt(config->host_offsets, i));\ + const int weight = array_elt(config->host_weights, i); \ + switch (rhbl_check(normal, rbl)) { \ + case RBL_FOUND: \ + error = false; \ + sum += weight; \ + if (sum >= config->hard_threshold) { \ + return HTK_HARD_MATCH; \ + } \ + break; \ + case RBL_NOTFOUND: \ + error = false; \ + break; \ + case RBL_ERROR: \ + warn("rbl %s unavailable", rbl); \ + break; \ + } \ } \ } + if (config->is_email) { LOOKUP(sender, sender); LOOKUP(recipient, recipient); + DNS(sender, sender); + DNS(recipient, recipient); } else if (config->is_hostname) { LOOKUP(helo, helo_name); LOOKUP(client, client_name); LOOKUP(reverse, reverse_client_name); LOOKUP(recipient, recipient_domain); LOOKUP(sender, sender_domain); + DNS(helo, helo_name); + DNS(client, client_name); + DNS(reverse, reverse_client_name); + DNS(recipient, recipient_domain); + DNS(sender, sender_domain); } +#undef DNS #undef LOOKUP + if (error) { + err("filter %s: all the rbls returned an error", filter->name); + return HTK_ERROR; + } if (sum >= config->hard_threshold) { return HTK_HARD_MATCH; } else if (sum >= config->soft_threshold) { @@ -530,6 +613,7 @@ static int strlist_init(void) */ (void)filter_param_register(type, "file"); (void)filter_param_register(type, "rbldns"); + (void)filter_param_register(type, "dns"); (void)filter_param_register(type, "hard_threshold"); (void)filter_param_register(type, "soft_threshold"); (void)filter_param_register(type, "fields");