X-Git-Url: http://git.madism.org/?a=blobdiff_plain;f=postlicyd%2Fiplist.c;h=b37d64bddcd0d509838b31f3b2b5bd5f3a9094a1;hb=56eeb7d73ed0c82f2a8165b6aba525af73c58f73;hp=5337dca0d77e92709cd138dfb8ac0ab684529e17;hpb=f840e396bc900fe05ad159e1ab06e5df63679ea3;p=apps%2Fpfixtools.git diff --git a/postlicyd/iplist.c b/postlicyd/iplist.c index 5337dca..b37d64b 100644 --- a/postlicyd/iplist.c +++ b/postlicyd/iplist.c @@ -43,6 +43,7 @@ #include "str.h" #include "file.h" #include "array.h" +#include "resources.h" #include "rbl.h" #define IPv4_BITS 5 @@ -62,10 +63,25 @@ enum { }; struct rbldb_t { - A(uint16_t) ips[1 << 16]; + char *filename; + A(uint16_t) *ips; }; ARRAY(rbldb_t) +typedef struct rbldb_resource_t { + time_t mtime; + off_t size; + A(uint16_t) ips[1 << 16]; +} rbldb_resource_t; + +static void rbldb_resource_wipe(rbldb_resource_t *res) +{ + for (int i = 0 ; i < 1 << 16 ; ++i) { + array_wipe(res->ips[i]); + } + p_delete(&res); +} + static int get_o(const char *s, const char **out) { int res = 0; @@ -129,6 +145,25 @@ rbldb_t *rbldb_create(const char *file, bool lock) return NULL; } + rbldb_resource_t *res = resource_get("iplist", file); + if (res == NULL) { + debug("No resource found"); + res = p_new(rbldb_resource_t, 1); + resource_set("iplist", file, res, (resource_destructor_t)rbldb_resource_wipe); + } + + db = p_new(rbldb_t, 1); + db->filename = m_strdup(file); + db->ips = res->ips; + if (map.st.st_size == res->size && map.st.st_mtime == res->mtime) { + info("rbl %s up to date", file); + file_map_close(&map); + return db; + } + debug("mtime %d/%d, size %d/%d", (int)map.st.st_mtime, (int)res->mtime, (int)map.st.st_size, (int)res->size); + res->size = map.st.st_size; + res->mtime = map.st.st_mtime; + p = map.map; end = map.end; while (end > p && end[-1] != '\n') { @@ -139,7 +174,6 @@ rbldb_t *rbldb_create(const char *file, bool lock) file); } - db = p_new(rbldb_t, 1); while (p < end) { uint32_t ip; @@ -149,7 +183,7 @@ rbldb_t *rbldb_create(const char *file, bool lock) if (parse_ipv4(p, &p, &ip) < 0) { p = (char *)memchr(p, '\n', end - p) + 1; } else { - array_add(db->ips[ip >> 16], ip & 0xffff); + array_add(res->ips[ip >> 16], ip & 0xffff); ++ips; } } @@ -158,14 +192,14 @@ rbldb_t *rbldb_create(const char *file, bool lock) /* Lookup may perform serveral I/O, so avoid swap. */ for (int i = 0 ; i < 1 << 16 ; ++i) { - array_adjust(db->ips[i]); - if (lock && !array_lock(db->ips[i])) { + array_adjust(res->ips[i]); + if (lock && !array_lock(res->ips[i])) { UNIXERR("mlock"); } - if (db->ips[i].len) { + if (res->ips[i].len) { # define QSORT_TYPE uint16_t -# define QSORT_BASE db->ips[i].data -# define QSORT_NELT db->ips[i].len +# define QSORT_BASE res->ips[i].data +# define QSORT_NELT res->ips[i].len # define QSORT_LT(a,b) *a < *b # include "qsort.c" } @@ -177,9 +211,9 @@ rbldb_t *rbldb_create(const char *file, bool lock) static void rbldb_wipe(rbldb_t *db) { - for (int i = 0 ; i < 1 << 16 ; ++i) { - array_wipe(db->ips[i]); - } + resource_release("iplist", db->filename); + p_delete(&db->filename); + db->ips = NULL; } void rbldb_delete(rbldb_t **db) @@ -225,7 +259,7 @@ bool rbldb_ipv4_lookup(const rbldb_t *db, uint32_t ip) #include "filter.h" -typedef struct rbl_filter_t { +typedef struct iplist_filter_t { PA(rbldb_t) rbls; A(int) weights; A(char) hosts; @@ -234,14 +268,23 @@ typedef struct rbl_filter_t { int32_t hard_threshold; int32_t soft_threshold; -} rbl_filter_t; +} iplist_filter_t; + +typedef struct iplist_async_data_t { + A(rbl_result_t) results; + int awaited; + uint32_t sum; + bool error; +} iplist_async_data_t; -static rbl_filter_t *rbl_filter_new(void) +static filter_type_t filter_type = FTK_UNKNOWN; + +static iplist_filter_t *iplist_filter_new(void) { - return p_new(rbl_filter_t, 1); + return p_new(iplist_filter_t, 1); } -static void rbl_filter_delete(rbl_filter_t **rbl) +static void iplist_filter_delete(iplist_filter_t **rbl) { if (*rbl) { array_deep_wipe((*rbl)->rbls, rbldb_delete); @@ -254,14 +297,14 @@ static void rbl_filter_delete(rbl_filter_t **rbl) } -static bool rbl_filter_constructor(filter_t *filter) +static bool iplist_filter_constructor(filter_t *filter) { - rbl_filter_t *data = rbl_filter_new(); + iplist_filter_t *data = iplist_filter_new(); #define PARSE_CHECK(Expr, Str, ...) \ if (!(Expr)) { \ err(Str, ##__VA_ARGS__); \ - rbl_filter_delete(&data); \ + iplist_filter_delete(&data); \ return false; \ } @@ -299,7 +342,7 @@ static bool rbl_filter_constructor(filter_t *filter) lock = false; } else { PARSE_CHECK(false, "illegal locking state %.*s", - p - current, current); + (int)(p - current), current); } break; @@ -307,7 +350,7 @@ static bool rbl_filter_constructor(filter_t *filter) weight = strtol(current, &next, 10); PARSE_CHECK(next == p && weight >= 0 && weight <= 1024, "illegal weight value %.*s", - (p - current), current); + (int)(p - current), current); break; case 2: @@ -342,7 +385,7 @@ static bool rbl_filter_constructor(filter_t *filter) weight = strtol(current, &next, 10); PARSE_CHECK(next == p && weight >= 0 && weight <= 1024, "illegal weight value %.*s", - (p - current), current); + (int)(p - current), current); break; case 1: @@ -384,22 +427,73 @@ static bool rbl_filter_constructor(filter_t *filter) return true; } -static void rbl_filter_destructor(filter_t *filter) +static void iplist_filter_destructor(filter_t *filter) { - rbl_filter_t *data = filter->data; - rbl_filter_delete(&data); + iplist_filter_t *data = filter->data; + iplist_filter_delete(&data); filter->data = data; } -static filter_result_t rbl_filter(const filter_t *filter, const query_t *query) +static void iplist_filter_async(rbl_result_t *result, void *arg) +{ + filter_context_t *context = arg; + const filter_t *filter = context->current_filter; + const iplist_filter_t *data = filter->data; + iplist_async_data_t *async = context->contexts[filter_type]; + + + if (*result != RBL_ERROR) { + async->error = false; + } + --async->awaited; + + debug("got asynchronous request result for filter %s, rbl %d, still awaiting %d answers", + filter->name, (int)(result - array_ptr(async->results, 0)), async->awaited); + + if (async->awaited == 0) { + filter_result_t res = HTK_FAIL; + if (async->error) { + res = HTK_ERROR; + } else { + for (uint32_t i = 0 ; i < array_len(data->host_offsets) ; ++i) { + int weight = array_elt(data->host_weights, i); + + switch (array_elt(async->results, i)) { + case RBL_ASYNC: + crit("no more awaited answer but result is ASYNC"); + abort(); + case RBL_FOUND: + async->sum += weight; + break; + default: + break; + } + } + if (async->sum >= (uint32_t)data->hard_threshold) { + res = HTK_HARD_MATCH; + } else if (async->sum >= (uint32_t)data->soft_threshold) { + res = HTK_SOFT_MATCH; + } + } + debug("answering to filter %s", filter->name); + filter_post_async_result(context, res); + } +} + +static filter_result_t iplist_filter(const filter_t *filter, const query_t *query, + filter_context_t *context) { uint32_t ip; int32_t sum = 0; const char *end = NULL; - const rbl_filter_t *data = filter->data; + const iplist_filter_t *data = filter->data; bool error = true; if (parse_ipv4(query->client_address, &end, &ip) != 0) { + if (strchr(query->client_address, ':')) { + /* iplist only works on IPv4 */ + return HTK_FAIL; + } warn("invalid client address: %s, expected ipv4", query->client_address); return HTK_ERROR; @@ -415,24 +509,22 @@ static filter_result_t rbl_filter(const filter_t *filter, const query_t *query) } error = false; } - for (uint32_t i = 0 ; i < data->host_offsets.len ; ++i) { - const char *rbl = array_ptr(data->hosts, array_elt(data->host_offsets, i)); - int weight = array_elt(data->host_weights, i); - switch (rbl_check(rbl, ip)) { - case RBL_FOUND: - error = false; - sum += weight; - if (sum >= data->hard_threshold) { - return HTK_HARD_MATCH; + if (array_len(data->host_offsets) > 0) { + iplist_async_data_t* async = context->contexts[filter_type]; + array_ensure_exact_capacity(async->results, array_len(data->host_offsets)); + async->sum = sum; + async->awaited = 0; + for (uint32_t i = 0 ; i < data->host_offsets.len ; ++i) { + const char *rbl = array_ptr(data->hosts, array_elt(data->host_offsets, i)); + if (rbl_check(rbl, ip, array_ptr(async->results, i), + iplist_filter_async, context)) { + error = false; + ++async->awaited; } - break; - case RBL_NOTFOUND: - error = false; - break; - case RBL_ERROR: - warn("rbl %s unavailable", rbl); - break; } + debug("filter %s awaiting %d asynchronous queries", filter->name, async->awaited); + async->error = error; + return HTK_ASYNC; } if (error) { err("filter %s: all the rbl returned an error", filter->name); @@ -447,25 +539,40 @@ static filter_result_t rbl_filter(const filter_t *filter, const query_t *query) } } -static int rbl_init(void) +static void *iplist_context_constructor(void) +{ + return p_new(iplist_async_data_t, 1); +} + +static void iplist_context_destructor(void *data) +{ + iplist_async_data_t *ctx = data; + array_wipe(ctx->results); + p_delete(&ctx); +} + +static int iplist_init(void) { - filter_type_t type = filter_register("iplist", rbl_filter_constructor, - rbl_filter_destructor, rbl_filter); + filter_type = filter_register("iplist", iplist_filter_constructor, + iplist_filter_destructor, iplist_filter, + iplist_context_constructor, + iplist_context_destructor); /* Hooks. */ - (void)filter_hook_register(type, "abort"); - (void)filter_hook_register(type, "error"); - (void)filter_hook_register(type, "fail"); - (void)filter_hook_register(type, "hard_match"); - (void)filter_hook_register(type, "soft_match"); + (void)filter_hook_register(filter_type, "abort"); + (void)filter_hook_register(filter_type, "error"); + (void)filter_hook_register(filter_type, "fail"); + (void)filter_hook_register(filter_type, "hard_match"); + (void)filter_hook_register(filter_type, "soft_match"); + (void)filter_hook_register(filter_type, "async"); /* Parameters. */ - (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(filter_type, "file"); + (void)filter_param_register(filter_type, "rbldns"); + (void)filter_param_register(filter_type, "dns"); + (void)filter_param_register(filter_type, "hard_threshold"); + (void)filter_param_register(filter_type, "soft_threshold"); return 0; } -module_init(rbl_init); +module_init(iplist_init);