Fix the copyright and licensing stuff.
[apps/pfixtools.git] / common / rbl.c
index 11ed464..237b6ff 100644 (file)
 /*     products derived from this software without specific prior written     */
 /*     permission.                                                            */
 /*                                                                            */
-/*  THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND   */
-/*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE     */
-/*  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR        */
-/*  PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS    */
-/*  BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR    */
-/*  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF      */
-/*  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS  */
-/*  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN   */
-/*  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)   */
-/*  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF    */
-/*  THE POSSIBILITY OF SUCH DAMAGE.                                           */
+/*  THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS ``AS IS'' AND ANY EXPRESS   */
+/*  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED         */
+/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE    */
+/*  DISCLAIMED.  IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY         */
+/*  DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        */
+/*  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS   */
+/*  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)     */
+/*  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,       */
+/*  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN  */
+/*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
+/*  POSSIBILITY OF SUCH DAMAGE.                                               */
+/*                                                                            */
+/*   Copyright (c) 2006-2008 the Authors                                      */
+/*   see AUTHORS and source files for details                                 */
 /******************************************************************************/
 
 /*
  * Copyright © 2008 Florent Bruneau
  */
 
+#include <unbound.h>
 #include <netdb.h>
+#include "array.h"
+#include "server.h"
 #include "rbl.h"
 
-static inline rbl_result_t rbl_dns_check(const char *hostname)
+
+typedef struct rbl_context_t {
+    rbl_result_t *result;
+    rbl_result_callback_t call;
+    void *data;
+} rbl_context_t;
+ARRAY(rbl_context_t);
+
+static struct ub_ctx *ctx = NULL;
+static client_t *async_event = NULL;
+static PA(rbl_context_t) ctx_pool = ARRAY_INIT;
+
+static rbl_context_t *rbl_context_new(void)
+{
+    return p_new(rbl_context_t, 1);
+}
+
+static void rbl_context_delete(rbl_context_t **context)
+{
+    if (*context) {
+        p_delete(context);
+    }
+}
+
+static void rbl_context_wipe(rbl_context_t *context)
 {
-    struct hostent *host = gethostbyname(hostname);
-    if (host != NULL) {
-        return RBL_FOUND;
+    p_clear(context, 1);
+}
+
+static rbl_context_t *rbl_context_acquire(void)
+{
+    if (array_len(ctx_pool) > 0) {
+        return array_pop_last(ctx_pool);
     } else {
-        if (h_errno == HOST_NOT_FOUND) {
-            return RBL_NOTFOUND;
+        return rbl_context_new();
+    }
+}
+
+static void rbl_context_release(rbl_context_t *context)
+{
+    rbl_context_wipe(context);
+    array_add(ctx_pool, context);
+}
+
+static void rbl_exit(void)
+{
+    if (ctx != NULL) {
+        ub_ctx_delete(ctx);
+        ctx = NULL;
+    }
+    if (async_event != NULL) {
+        client_release(async_event);
+        async_event = NULL;
+    }
+    array_deep_wipe(ctx_pool, rbl_context_delete);
+}
+module_exit(rbl_exit);
+
+static void rbl_callback(void *arg, int err, struct ub_result *result)
+{
+    rbl_context_t *context = arg;
+    if (err != 0) {
+        debug("asynchronous request led to an error");
+        *context->result = RBL_ERROR;
+    } else if (result->nxdomain) {
+        debug("asynchronous request done, %s NOT FOUND", result->qname);
+        *context->result = RBL_NOTFOUND;
+    } else {
+        debug("asynchronous request done, %s FOUND", result->qname);
+        *context->result = RBL_FOUND;
+    }
+    if (context->call != NULL) {
+        context->call(context->result, context->data);
+    }
+    ub_resolve_free(result);
+    rbl_context_release(context);
+}
+
+static int rbl_handler(client_t *event, void *config)
+{
+    int retval = 0;
+    debug("rbl_handler called: ub_fd triggered");
+    client_io_none(event);
+    if ((retval = ub_process(ctx)) != 0) {
+        err("error in DNS resolution: %s", ub_strerror(retval));
+    }
+    client_io_ro(event);
+    return 0;
+}
+
+static inline bool rbl_dns_check(const char *hostname, rbl_result_t *result,
+                                 rbl_result_callback_t callback, void *data)
+{
+    if (ctx == NULL) {
+        ctx = ub_ctx_create();
+        ub_ctx_async(ctx, true);
+        if ((async_event = client_register(ub_fd(ctx), rbl_handler, NULL)) == NULL) {
+            crit("cannot register asynchronous DNS event handler");
+            abort();
         }
-        return RBL_ERROR;
+    }
+    rbl_context_t *context = rbl_context_acquire();
+    context->result = result;
+    context->call   = callback;
+    context->data   = data;
+    debug("running dns resolution on %s", hostname);
+    if (ub_resolve_async(ctx, (char*)hostname, 1, 1, context, rbl_callback, NULL) == 0) {
+        *result = RBL_ASYNC;
+        return true;
+    } else {
+        *result = RBL_ERROR;
+        rbl_context_release(context);
+        return false;
     }
 }
 
-rbl_result_t rbl_check(const char *rbl, uint32_t ip)
+bool rbl_check(const char *rbl, uint32_t ip, rbl_result_t *result,
+               rbl_result_callback_t callback, void *data)
 {
     char host[257];
-    snprintf(host, 257, "%d.%d.%d.%d.%s",
-             ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff,
-             rbl);
-    return rbl_dns_check(host);
+    int len;
+
+    len = snprintf(host, 257, "%d.%d.%d.%d.%s.",
+                   ip & 0xff, (ip >> 8) & 0xff, (ip >> 16) & 0xff, (ip >> 24) & 0xff,
+                   rbl);
+    if (len >= (int)sizeof(host))
+        return RBL_ERROR;
+    if (host[len - 2] == '.')
+        host[len - 1] = '\0';
+    return rbl_dns_check(host, result, callback, data);
 }
 
-rbl_result_t rhbl_check(const char *rhbl, const char *hostname)
+bool rhbl_check(const char *rhbl, const char *hostname, rbl_result_t *result,
+                rbl_result_callback_t callback, void *data)
 {
     char host[257];
-    snprintf(host, 257, "%s.%s", hostname, rhbl);
-    return rbl_dns_check(host);
+    int len;
+
+    len = snprintf(host, 257, "%s.%s.", hostname, rhbl);
+    if (len >= (int)sizeof(host))
+        return RBL_ERROR;
+    if (host[len - 2] == '.')
+        host[len - 1] = '\0';
+    return rbl_dns_check(host, result, callback, data);
 }