Basic support for async filters.
[apps/pfixtools.git] / postlicyd / iplist.c
index 256c360..867f88b 100644 (file)
@@ -62,7 +62,7 @@ enum {
 };
 
 struct rbldb_t {
-    A(uint32_t) ips;
+    A(uint16_t) ips[1 << 16];
 };
 ARRAY(rbldb_t)
 
@@ -123,6 +123,7 @@ rbldb_t *rbldb_create(const char *file, bool lock)
     rbldb_t *db;
     file_map_t map;
     const char *p, *end;
+    uint32_t ips = 0;
 
     if (!file_map_open(&map, file, false)) {
         return NULL;
@@ -148,33 +149,37 @@ 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);
+            array_add(db->ips[ip >> 16], ip & 0xffff);
+            ++ips;
         }
     }
     file_map_close(&map);
 
     /* Lookup may perform serveral I/O, so avoid swap.
      */
-    array_adjust(db->ips);
-    if (lock && !array_lock(db->ips)) {
-        UNIXERR("mlock");
-    }
-
-    if (db->ips.len) {
-#       define QSORT_TYPE uint32_t
-#       define QSORT_BASE db->ips.data
-#       define QSORT_NELT db->ips.len
+    for (int i = 0 ; i < 1 << 16 ; ++i) {
+        array_adjust(db->ips[i]);
+        if (lock && !array_lock(db->ips[i])) {
+            UNIXERR("mlock");
+        }
+        if (db->ips[i].len) {
+#       define QSORT_TYPE uint16_t
+#       define QSORT_BASE db->ips[i].data
+#       define QSORT_NELT db->ips[i].len
 #       define QSORT_LT(a,b) *a < *b
 #       include "qsort.c"
+        }
     }
 
-    info("rbl %s loaded, %d IPs", file, db->ips.len);
+    info("rbl %s loaded, %d IPs", file, ips);
     return db;
 }
 
 static void rbldb_wipe(rbldb_t *db)
 {
-    array_wipe(db->ips);
+    for (int i = 0 ; i < 1 << 16 ; ++i) {
+        array_wipe(db->ips[i]);
+    }
 }
 
 void rbldb_delete(rbldb_t **db)
@@ -187,20 +192,26 @@ void rbldb_delete(rbldb_t **db)
 
 uint32_t rbldb_stats(const rbldb_t *rbl)
 {
-    return rbl->ips.len;
+    uint32_t ips = 0;
+    for (int i = 0 ; i < 1 << 16 ; ++i) {
+        ips += array_len(rbl->ips[i]);
+    }
+    return ips;
 }
 
 bool rbldb_ipv4_lookup(const rbldb_t *db, uint32_t ip)
 {
-    int l = 0, r = db->ips.len;
+    const uint16_t hip = ip >> 16;
+    const uint16_t lip = ip & 0xffff;
+    int l = 0, r = db->ips[hip].len;
 
     while (l < r) {
         int i = (r + l) / 2;
 
-        if (array_elt(db->ips, i) == ip)
+        if (array_elt(db->ips[hip], i) == lip)
             return true;
 
-        if (ip < array_elt(db->ips, i)) {
+        if (lip < array_elt(db->ips[hip], i)) {
             r = i;
         } else {
             l = i + 1;
@@ -268,7 +279,7 @@ static bool rbl_filter_constructor(filter_t *filter)
            *  the file pointed by filename MUST be a valid ip list issued from
            *  the rsync (or equivalent) service of a (r)bl.
            */
-          case ATK_FILE: {
+          case ATK_FILE: case ATK_RBLDNS: {
             bool lock = false;
             int  weight = 0;
             rbldb_t *rbl = NULL;
@@ -288,7 +299,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;
 
@@ -296,7 +307,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:
@@ -314,11 +325,11 @@ static bool rbl_filter_constructor(filter_t *filter)
             }
           } break;
 
-          /* host parameter.
+          /* dns parameter.
            *  weight:hostname.
            * define a RBL to use through DNS resolution.
            */
-          case ATK_HOST: {
+          case ATK_DNS: {
             int  weight = 0;
             const char *current = param->value;
             const char *p = m_strchrnul(param->value, ':');
@@ -331,7 +342,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:
@@ -367,7 +378,7 @@ static bool rbl_filter_constructor(filter_t *filter)
         }
     }}
 
-    PARSE_CHECK(data->rbls.len
+    PARSE_CHECK(data->rbls.len || data->host_offsets.len,
                 "no file parameter in the filter %s", filter->name);
     filter->data = data;
     return true;
@@ -380,7 +391,8 @@ static void rbl_filter_destructor(filter_t *filter)
     filter->data = data;
 }
 
-static filter_result_t rbl_filter(const filter_t *filter, const query_t *query)
+static filter_result_t rbl_filter(const filter_t *filter, const query_t *query,
+                                  filter_context_t *context)
 {
     uint32_t ip;
     int32_t sum = 0;
@@ -439,7 +451,8 @@ static filter_result_t rbl_filter(const filter_t *filter, const query_t *query)
 static int rbl_init(void)
 {
     filter_type_t type =  filter_register("iplist", rbl_filter_constructor,
-                                          rbl_filter_destructor, rbl_filter);
+                                          rbl_filter_destructor, rbl_filter,
+                                          NULL, NULL);
     /* Hooks.
      */
     (void)filter_hook_register(type, "abort");
@@ -447,11 +460,13 @@ static int rbl_init(void)
     (void)filter_hook_register(type, "fail");
     (void)filter_hook_register(type, "hard_match");
     (void)filter_hook_register(type, "soft_match");
+    (void)filter_hook_register(type, "async");
 
     /* Parameters.
      */
     (void)filter_param_register(type, "file");
-    (void)filter_param_register(type, "host");
+    (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");
     return 0;