summaryrefslogtreecommitdiffstats
path: root/contrib/unbound/libunbound
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/unbound/libunbound')
-rw-r--r--contrib/unbound/libunbound/context.c400
-rw-r--r--contrib/unbound/libunbound/context.h345
-rw-r--r--contrib/unbound/libunbound/libunbound.c1124
-rw-r--r--contrib/unbound/libunbound/libworker.c920
-rw-r--r--contrib/unbound/libunbound/libworker.h170
-rw-r--r--contrib/unbound/libunbound/python/LICENSE28
-rw-r--r--contrib/unbound/libunbound/python/Makefile75
-rw-r--r--contrib/unbound/libunbound/python/doc/_static/readme1
-rw-r--r--contrib/unbound/libunbound/python/doc/conf.py181
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example1a.rst26
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example1b.rst33
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example2.rst41
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example3.rst36
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example4.rst34
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example5.rst29
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example6-1.py27
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example6.rst11
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example7-1.py17
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example7-2.py16
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example7.rst18
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example8-1.py31
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/example8.rst28
-rw-r--r--contrib/unbound/libunbound/python/doc/examples/index.rst14
-rw-r--r--contrib/unbound/libunbound/python/doc/index.rst27
-rw-r--r--contrib/unbound/libunbound/python/doc/install.rst31
-rw-r--r--contrib/unbound/libunbound/python/doc/intro.rst39
-rw-r--r--contrib/unbound/libunbound/python/doc/modules/unbound.rst167
-rw-r--r--contrib/unbound/libunbound/python/examples/async-lookup.py56
-rw-r--r--contrib/unbound/libunbound/python/examples/dns-lookup.py44
-rw-r--r--contrib/unbound/libunbound/python/examples/dnssec-valid.py59
-rw-r--r--contrib/unbound/libunbound/python/examples/dnssec_test.py35
-rw-r--r--contrib/unbound/libunbound/python/examples/example8-1.py61
-rw-r--r--contrib/unbound/libunbound/python/examples/idn-lookup.py62
-rw-r--r--contrib/unbound/libunbound/python/examples/mx-lookup.py53
-rw-r--r--contrib/unbound/libunbound/python/examples/ns-lookup.py47
-rw-r--r--contrib/unbound/libunbound/python/examples/reverse-lookup.py43
-rw-r--r--contrib/unbound/libunbound/python/libunbound.i941
-rw-r--r--contrib/unbound/libunbound/ubsyms.def29
-rw-r--r--contrib/unbound/libunbound/unbound.h556
39 files changed, 5855 insertions, 0 deletions
diff --git a/contrib/unbound/libunbound/context.c b/contrib/unbound/libunbound/context.c
new file mode 100644
index 0000000..f283079
--- /dev/null
+++ b/contrib/unbound/libunbound/context.c
@@ -0,0 +1,400 @@
+/*
+ * libunbound/context.c - validating context for unbound internal use
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+ */
+
+/**
+ * \file
+ *
+ * This file contains the validator context structure.
+ */
+#include "config.h"
+#include "libunbound/context.h"
+#include "util/module.h"
+#include "util/config_file.h"
+#include "util/net_help.h"
+#include "services/modstack.h"
+#include "services/localzone.h"
+#include "services/cache/rrset.h"
+#include "services/cache/infra.h"
+#include "util/data/msgreply.h"
+#include "util/storage/slabhash.h"
+
+int
+context_finalize(struct ub_ctx* ctx)
+{
+ struct config_file* cfg = ctx->env->cfg;
+ verbosity = cfg->verbosity;
+ if(ctx->logfile_override)
+ log_file(ctx->log_out);
+ else log_init(cfg->logfile, cfg->use_syslog, NULL);
+ config_apply(cfg);
+ if(!modstack_setup(&ctx->mods, cfg->module_conf, ctx->env))
+ return UB_INITFAIL;
+ ctx->local_zones = local_zones_create();
+ if(!ctx->local_zones)
+ return UB_NOMEM;
+ if(!local_zones_apply_cfg(ctx->local_zones, cfg))
+ return UB_INITFAIL;
+ if(!ctx->env->msg_cache ||
+ cfg->msg_cache_size != slabhash_get_size(ctx->env->msg_cache) ||
+ cfg->msg_cache_slabs != ctx->env->msg_cache->size) {
+ slabhash_delete(ctx->env->msg_cache);
+ ctx->env->msg_cache = slabhash_create(cfg->msg_cache_slabs,
+ HASH_DEFAULT_STARTARRAY, cfg->msg_cache_size,
+ msgreply_sizefunc, query_info_compare,
+ query_entry_delete, reply_info_delete, NULL);
+ if(!ctx->env->msg_cache)
+ return UB_NOMEM;
+ }
+ ctx->env->rrset_cache = rrset_cache_adjust(ctx->env->rrset_cache,
+ ctx->env->cfg, ctx->env->alloc);
+ if(!ctx->env->rrset_cache)
+ return UB_NOMEM;
+ ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg);
+ if(!ctx->env->infra_cache)
+ return UB_NOMEM;
+ ctx->finalized = 1;
+ return UB_NOERROR;
+}
+
+int context_query_cmp(const void* a, const void* b)
+{
+ if( *(int*)a < *(int*)b )
+ return -1;
+ if( *(int*)a > *(int*)b )
+ return 1;
+ return 0;
+}
+
+void
+context_query_delete(struct ctx_query* q)
+{
+ if(!q) return;
+ ub_resolve_free(q->res);
+ free(q->msg);
+ free(q);
+}
+
+/** How many times to try to find an unused query-id-number for async */
+#define NUM_ID_TRIES 100000
+/** find next useful id number of 0 on error */
+static int
+find_id(struct ub_ctx* ctx, int* id)
+{
+ size_t tries = 0;
+ ctx->next_querynum++;
+ while(rbtree_search(&ctx->queries, &ctx->next_querynum)) {
+ ctx->next_querynum++; /* numerical wraparound is fine */
+ if(tries++ > NUM_ID_TRIES)
+ return 0;
+ }
+ *id = ctx->next_querynum;
+ return 1;
+}
+
+struct ctx_query*
+context_new(struct ub_ctx* ctx, char* name, int rrtype, int rrclass,
+ ub_callback_t cb, void* cbarg)
+{
+ struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
+ if(!q) return NULL;
+ lock_basic_lock(&ctx->cfglock);
+ if(!find_id(ctx, &q->querynum)) {
+ lock_basic_unlock(&ctx->cfglock);
+ free(q);
+ return NULL;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ q->node.key = &q->querynum;
+ q->async = (cb != NULL);
+ q->cb = cb;
+ q->cb_arg = cbarg;
+ q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
+ if(!q->res) {
+ free(q);
+ return NULL;
+ }
+ q->res->qname = strdup(name);
+ if(!q->res->qname) {
+ free(q->res);
+ free(q);
+ return NULL;
+ }
+ q->res->qtype = rrtype;
+ q->res->qclass = rrclass;
+
+ /* add to query list */
+ lock_basic_lock(&ctx->cfglock);
+ if(q->async)
+ ctx->num_async ++;
+ (void)rbtree_insert(&ctx->queries, &q->node);
+ lock_basic_unlock(&ctx->cfglock);
+ return q;
+}
+
+struct alloc_cache*
+context_obtain_alloc(struct ub_ctx* ctx, int locking)
+{
+ struct alloc_cache* a;
+ int tnum = 0;
+ if(locking) {
+ lock_basic_lock(&ctx->cfglock);
+ }
+ a = ctx->alloc_list;
+ if(a)
+ ctx->alloc_list = a->super; /* snip off list */
+ else tnum = ctx->thr_next_num++;
+ if(locking) {
+ lock_basic_unlock(&ctx->cfglock);
+ }
+ if(a) {
+ a->super = &ctx->superalloc;
+ return a;
+ }
+ a = (struct alloc_cache*)calloc(1, sizeof(*a));
+ if(!a)
+ return NULL;
+ alloc_init(a, &ctx->superalloc, tnum);
+ return a;
+}
+
+void
+context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc,
+ int locking)
+{
+ if(!ctx || !alloc)
+ return;
+ if(locking) {
+ lock_basic_lock(&ctx->cfglock);
+ }
+ alloc->super = ctx->alloc_list;
+ ctx->alloc_list = alloc;
+ if(locking) {
+ lock_basic_unlock(&ctx->cfglock);
+ }
+}
+
+uint8_t*
+context_serialize_new_query(struct ctx_query* q, uint32_t* len)
+{
+ /* format for new query is
+ * o uint32 cmd
+ * o uint32 id
+ * o uint32 type
+ * o uint32 class
+ * o rest queryname (string)
+ */
+ uint8_t* p;
+ size_t slen = strlen(q->res->qname) + 1/*end of string*/;
+ *len = sizeof(uint32_t)*4 + slen;
+ p = (uint8_t*)malloc(*len);
+ if(!p) return NULL;
+ ldns_write_uint32(p, UB_LIBCMD_NEWQUERY);
+ ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
+ ldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)q->res->qtype);
+ ldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->res->qclass);
+ memmove(p+4*sizeof(uint32_t), q->res->qname, slen);
+ return p;
+}
+
+struct ctx_query*
+context_deserialize_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
+{
+ struct ctx_query* q = (struct ctx_query*)calloc(1, sizeof(*q));
+ if(!q) return NULL;
+ if(len < 4*sizeof(uint32_t)+1) {
+ free(q);
+ return NULL;
+ }
+ log_assert( ldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
+ q->querynum = (int)ldns_read_uint32(p+sizeof(uint32_t));
+ q->node.key = &q->querynum;
+ q->async = 1;
+ q->res = (struct ub_result*)calloc(1, sizeof(*q->res));
+ if(!q->res) {
+ free(q);
+ return NULL;
+ }
+ q->res->qtype = (int)ldns_read_uint32(p+2*sizeof(uint32_t));
+ q->res->qclass = (int)ldns_read_uint32(p+3*sizeof(uint32_t));
+ q->res->qname = strdup((char*)(p+4*sizeof(uint32_t)));
+ if(!q->res->qname) {
+ free(q->res);
+ free(q);
+ return NULL;
+ }
+
+ /** add to query list */
+ ctx->num_async++;
+ (void)rbtree_insert(&ctx->queries, &q->node);
+ return q;
+}
+
+struct ctx_query*
+context_lookup_new_query(struct ub_ctx* ctx, uint8_t* p, uint32_t len)
+{
+ struct ctx_query* q;
+ int querynum;
+ if(len < 4*sizeof(uint32_t)+1) {
+ return NULL;
+ }
+ log_assert( ldns_read_uint32(p) == UB_LIBCMD_NEWQUERY);
+ querynum = (int)ldns_read_uint32(p+sizeof(uint32_t));
+ q = (struct ctx_query*)rbtree_search(&ctx->queries, &querynum);
+ if(!q) {
+ return NULL;
+ }
+ log_assert(q->async);
+ return q;
+}
+
+uint8_t*
+context_serialize_answer(struct ctx_query* q, int err, ldns_buffer* pkt,
+ uint32_t* len)
+{
+ /* answer format
+ * o uint32 cmd
+ * o uint32 id
+ * o uint32 error_code
+ * o uint32 msg_security
+ * o uint32 length of why_bogus string (+1 for eos); 0 absent.
+ * o why_bogus_string
+ * o the remainder is the answer msg from resolver lookup.
+ * remainder can be length 0.
+ */
+ size_t pkt_len = pkt?ldns_buffer_remaining(pkt):0;
+ size_t wlen = (pkt&&q->res->why_bogus)?strlen(q->res->why_bogus)+1:0;
+ uint8_t* p;
+ *len = sizeof(uint32_t)*5 + pkt_len + wlen;
+ p = (uint8_t*)malloc(*len);
+ if(!p) return NULL;
+ ldns_write_uint32(p, UB_LIBCMD_ANSWER);
+ ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
+ ldns_write_uint32(p+2*sizeof(uint32_t), (uint32_t)err);
+ ldns_write_uint32(p+3*sizeof(uint32_t), (uint32_t)q->msg_security);
+ ldns_write_uint32(p+4*sizeof(uint32_t), (uint32_t)wlen);
+ if(wlen > 0)
+ memmove(p+5*sizeof(uint32_t), q->res->why_bogus, wlen);
+ if(pkt_len > 0)
+ memmove(p+5*sizeof(uint32_t)+wlen,
+ ldns_buffer_begin(pkt), pkt_len);
+ return p;
+}
+
+struct ctx_query*
+context_deserialize_answer(struct ub_ctx* ctx,
+ uint8_t* p, uint32_t len, int* err)
+{
+ struct ctx_query* q = NULL ;
+ int id;
+ size_t wlen;
+ if(len < 5*sizeof(uint32_t)) return NULL;
+ log_assert( ldns_read_uint32(p) == UB_LIBCMD_ANSWER);
+ id = (int)ldns_read_uint32(p+sizeof(uint32_t));
+ q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
+ if(!q) return NULL;
+ *err = (int)ldns_read_uint32(p+2*sizeof(uint32_t));
+ q->msg_security = ldns_read_uint32(p+3*sizeof(uint32_t));
+ wlen = (size_t)ldns_read_uint32(p+4*sizeof(uint32_t));
+ if(len > 5*sizeof(uint32_t) && wlen > 0) {
+ if(len >= 5*sizeof(uint32_t)+wlen)
+ q->res->why_bogus = (char*)memdup(
+ p+5*sizeof(uint32_t), wlen);
+ if(!q->res->why_bogus) {
+ /* pass malloc failure to the user callback */
+ q->msg_len = 0;
+ *err = UB_NOMEM;
+ return q;
+ }
+ q->res->why_bogus[wlen-1] = 0; /* zero terminated for sure */
+ }
+ if(len > 5*sizeof(uint32_t)+wlen) {
+ q->msg_len = len - 5*sizeof(uint32_t) - wlen;
+ q->msg = (uint8_t*)memdup(p+5*sizeof(uint32_t)+wlen,
+ q->msg_len);
+ if(!q->msg) {
+ /* pass malloc failure to the user callback */
+ q->msg_len = 0;
+ *err = UB_NOMEM;
+ return q;
+ }
+ }
+ return q;
+}
+
+uint8_t*
+context_serialize_cancel(struct ctx_query* q, uint32_t* len)
+{
+ /* format of cancel:
+ * o uint32 cmd
+ * o uint32 async-id */
+ uint8_t* p = (uint8_t*)malloc(2*sizeof(uint32_t));
+ if(!p) return NULL;
+ *len = 2*sizeof(uint32_t);
+ ldns_write_uint32(p, UB_LIBCMD_CANCEL);
+ ldns_write_uint32(p+sizeof(uint32_t), (uint32_t)q->querynum);
+ return p;
+}
+
+struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx,
+ uint8_t* p, uint32_t len)
+{
+ struct ctx_query* q;
+ int id;
+ if(len != 2*sizeof(uint32_t)) return NULL;
+ log_assert( ldns_read_uint32(p) == UB_LIBCMD_CANCEL);
+ id = (int)ldns_read_uint32(p+sizeof(uint32_t));
+ q = (struct ctx_query*)rbtree_search(&ctx->queries, &id);
+ return q;
+}
+
+uint8_t*
+context_serialize_quit(uint32_t* len)
+{
+ uint8_t* p = (uint8_t*)malloc(sizeof(uint32_t));
+ if(!p)
+ return NULL;
+ *len = sizeof(uint32_t);
+ ldns_write_uint32(p, UB_LIBCMD_QUIT);
+ return p;
+}
+
+enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len)
+{
+ uint32_t v;
+ if((size_t)len < sizeof(v))
+ return UB_LIBCMD_QUIT;
+ v = ldns_read_uint32(p);
+ return v;
+}
diff --git a/contrib/unbound/libunbound/context.h b/contrib/unbound/libunbound/context.h
new file mode 100644
index 0000000..8898f3e
--- /dev/null
+++ b/contrib/unbound/libunbound/context.h
@@ -0,0 +1,345 @@
+/*
+ * libunbound/context.h - validating context for unbound internal use
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+ */
+
+/**
+ * \file
+ *
+ * This file contains the validator context structure.
+ */
+#ifndef LIBUNBOUND_CONTEXT_H
+#define LIBUNBOUND_CONTEXT_H
+#include "util/locks.h"
+#include "util/alloc.h"
+#include "util/rbtree.h"
+#include "services/modstack.h"
+#include "libunbound/unbound.h"
+#include "util/data/packed_rrset.h"
+struct libworker;
+struct tube;
+
+/**
+ * The context structure
+ *
+ * Contains two pipes for async service
+ * qq : write queries to the async service pid/tid.
+ * rr : read results from the async service pid/tid.
+ */
+struct ub_ctx {
+ /* --- pipes --- */
+ /** mutex on query write pipe */
+ lock_basic_t qqpipe_lock;
+ /** the query write pipe */
+ struct tube* qq_pipe;
+ /** mutex on result read pipe */
+ lock_basic_t rrpipe_lock;
+ /** the result read pipe */
+ struct tube* rr_pipe;
+
+ /* --- shared data --- */
+ /** mutex for access to env.cfg, finalized and dothread */
+ lock_basic_t cfglock;
+ /**
+ * The context has been finalized
+ * This is after config when the first resolve is done.
+ * The modules are inited (module-init()) and shared caches created.
+ */
+ int finalized;
+
+ /** is bg worker created yet ? */
+ int created_bg;
+ /** pid of bg worker process */
+ pid_t bg_pid;
+ /** tid of bg worker thread */
+ ub_thread_t bg_tid;
+
+ /** do threading (instead of forking) for async resolution */
+ int dothread;
+ /** next thread number for new threads */
+ int thr_next_num;
+ /** if logfile is overriden */
+ int logfile_override;
+ /** what logfile to use instead */
+ FILE* log_out;
+ /**
+ * List of alloc-cache-id points per threadnum for notinuse threads.
+ * Simply the entire struct alloc_cache with the 'super' member used
+ * to link a simply linked list. Reset super member to the superalloc
+ * before use.
+ */
+ struct alloc_cache* alloc_list;
+
+ /** shared caches, and so on */
+ struct alloc_cache superalloc;
+ /** module env master value */
+ struct module_env* env;
+ /** module stack */
+ struct module_stack mods;
+ /** local authority zones */
+ struct local_zones* local_zones;
+ /** random state used to seed new random state structures */
+ struct ub_randstate* seed_rnd;
+
+ /** next query number (to try) to use */
+ int next_querynum;
+ /** number of async queries outstanding */
+ size_t num_async;
+ /**
+ * Tree of outstanding queries. Indexed by querynum
+ * Used when results come in for async to lookup.
+ * Used when cancel is done for lookup (and delete).
+ * Used to see if querynum is free for use.
+ * Content of type ctx_query.
+ */
+ rbtree_t queries;
+};
+
+/**
+ * The queries outstanding for the libunbound resolver.
+ * These are outstanding for async resolution.
+ * But also, outstanding for sync resolution by one of the threads that
+ * has joined the threadpool.
+ */
+struct ctx_query {
+ /** node in rbtree, must be first entry, key is ptr to the querynum */
+ struct rbnode_t node;
+ /** query id number, key for node */
+ int querynum;
+ /** was this an async query? */
+ int async;
+ /** was this query cancelled (for bg worker) */
+ int cancelled;
+
+ /** for async query, the callback function */
+ ub_callback_t cb;
+ /** for async query, the callback user arg */
+ void* cb_arg;
+
+ /** answer message, result from resolver lookup. */
+ uint8_t* msg;
+ /** resulting message length. */
+ size_t msg_len;
+ /** validation status on security */
+ enum sec_status msg_security;
+ /** store libworker that is handling this query */
+ struct libworker* w;
+
+ /** result structure, also contains original query, type, class.
+ * malloced ptr ready to hand to the client. */
+ struct ub_result* res;
+};
+
+/**
+ * The error constants
+ */
+enum ub_ctx_err {
+ /** no error */
+ UB_NOERROR = 0,
+ /** socket operation. Set to -1, so that if an error from _fd() is
+ * passed (-1) it gives a socket error. */
+ UB_SOCKET = -1,
+ /** alloc failure */
+ UB_NOMEM = -2,
+ /** syntax error */
+ UB_SYNTAX = -3,
+ /** DNS service failed */
+ UB_SERVFAIL = -4,
+ /** fork() failed */
+ UB_FORKFAIL = -5,
+ /** cfg change after finalize() */
+ UB_AFTERFINAL = -6,
+ /** initialization failed (bad settings) */
+ UB_INITFAIL = -7,
+ /** error in pipe communication with async bg worker */
+ UB_PIPE = -8,
+ /** error reading from file (resolv.conf) */
+ UB_READFILE = -9,
+ /** error async_id does not exist or result already been delivered */
+ UB_NOID = -10
+};
+
+/**
+ * Command codes for libunbound pipe.
+ *
+ * Serialization looks like this:
+ * o length (of remainder) uint32.
+ * o uint32 command code.
+ * o per command format.
+ */
+enum ub_ctx_cmd {
+ /** QUIT */
+ UB_LIBCMD_QUIT = 0,
+ /** New query, sent to bg worker */
+ UB_LIBCMD_NEWQUERY,
+ /** Cancel query, sent to bg worker */
+ UB_LIBCMD_CANCEL,
+ /** Query result, originates from bg worker */
+ UB_LIBCMD_ANSWER
+};
+
+/**
+ * finalize a context.
+ * @param ctx: context to finalize. creates shared data.
+ * @return 0 if OK, or errcode.
+ */
+int context_finalize(struct ub_ctx* ctx);
+
+/** compare two ctx_query elements */
+int context_query_cmp(const void* a, const void* b);
+
+/**
+ * delete context query
+ * @param q: query to delete, including message packet and prealloc result
+ */
+void context_query_delete(struct ctx_query* q);
+
+/**
+ * Create new query in context, add to querynum list.
+ * @param ctx: context
+ * @param name: query name
+ * @param rrtype: type
+ * @param rrclass: class
+ * @param cb: callback for async, or NULL for sync.
+ * @param cbarg: user arg for async queries.
+ * @return new ctx_query or NULL for malloc failure.
+ */
+struct ctx_query* context_new(struct ub_ctx* ctx, char* name, int rrtype,
+ int rrclass, ub_callback_t cb, void* cbarg);
+
+/**
+ * Get a new alloc. Creates a new one or uses a cached one.
+ * @param ctx: context
+ * @param locking: if true, cfglock is locked while getting alloc.
+ * @return an alloc, or NULL on mem error.
+ */
+struct alloc_cache* context_obtain_alloc(struct ub_ctx* ctx, int locking);
+
+/**
+ * Release an alloc. Puts it into the cache.
+ * @param ctx: context
+ * @param locking: if true, cfglock is locked while releasing alloc.
+ * @param alloc: alloc to relinquish.
+ */
+void context_release_alloc(struct ub_ctx* ctx, struct alloc_cache* alloc,
+ int locking);
+
+/**
+ * Serialize a context query that questions data.
+ * This serializes the query name, type, ...
+ * As well as command code 'new_query'.
+ * @param q: context query
+ * @param len: the length of the allocation is returned.
+ * @return: an alloc, or NULL on mem error.
+ */
+uint8_t* context_serialize_new_query(struct ctx_query* q, uint32_t* len);
+
+/**
+ * Serialize a context_query result to hand back to user.
+ * This serializes the query name, type, ..., and result.
+ * As well as command code 'answer'.
+ * @param q: context query
+ * @param err: error code to pass to client.
+ * @param pkt: the packet to add, can be NULL.
+ * @param len: the length of the allocation is returned.
+ * @return: an alloc, or NULL on mem error.
+ */
+uint8_t* context_serialize_answer(struct ctx_query* q, int err,
+ ldns_buffer* pkt, uint32_t* len);
+
+/**
+ * Serialize a query cancellation. Serializes query async id
+ * as well as command code 'cancel'
+ * @param q: context query
+ * @param len: the length of the allocation is returned.
+ * @return: an alloc, or NULL on mem error.
+ */
+uint8_t* context_serialize_cancel(struct ctx_query* q, uint32_t* len);
+
+/**
+ * Serialize a 'quit' command.
+ * @param len: the length of the allocation is returned.
+ * @return: an alloc, or NULL on mem error.
+ */
+uint8_t* context_serialize_quit(uint32_t* len);
+
+/**
+ * Obtain command code from serialized buffer
+ * @param p: buffer serialized.
+ * @param len: length of buffer.
+ * @return command code or QUIT on error.
+ */
+enum ub_ctx_cmd context_serial_getcmd(uint8_t* p, uint32_t len);
+
+/**
+ * Lookup query from new_query buffer.
+ * @param ctx: context
+ * @param p: buffer serialized.
+ * @param len: length of buffer.
+ * @return looked up ctx_query or NULL for malloc failure.
+ */
+struct ctx_query* context_lookup_new_query(struct ub_ctx* ctx,
+ uint8_t* p, uint32_t len);
+
+/**
+ * Deserialize a new_query buffer.
+ * @param ctx: context
+ * @param p: buffer serialized.
+ * @param len: length of buffer.
+ * @return new ctx_query or NULL for malloc failure.
+ */
+struct ctx_query* context_deserialize_new_query(struct ub_ctx* ctx,
+ uint8_t* p, uint32_t len);
+
+/**
+ * Deserialize an answer buffer.
+ * @param ctx: context
+ * @param p: buffer serialized.
+ * @param len: length of buffer.
+ * @param err: error code to be returned to client is passed.
+ * @return ctx_query with answer added or NULL for malloc failure.
+ */
+struct ctx_query* context_deserialize_answer(struct ub_ctx* ctx,
+ uint8_t* p, uint32_t len, int* err);
+
+/**
+ * Deserialize a cancel buffer.
+ * @param ctx: context
+ * @param p: buffer serialized.
+ * @param len: length of buffer.
+ * @return ctx_query to cancel or NULL for failure.
+ */
+struct ctx_query* context_deserialize_cancel(struct ub_ctx* ctx,
+ uint8_t* p, uint32_t len);
+
+#endif /* LIBUNBOUND_CONTEXT_H */
diff --git a/contrib/unbound/libunbound/libunbound.c b/contrib/unbound/libunbound/libunbound.c
new file mode 100644
index 0000000..10d00dd
--- /dev/null
+++ b/contrib/unbound/libunbound/libunbound.c
@@ -0,0 +1,1124 @@
+/*
+ * unbound.c - unbound validating resolver public API implementation
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+ */
+
+/**
+ * \file
+ *
+ * This file contains functions to resolve DNS queries and
+ * validate the answers. Synchonously and asynchronously.
+ *
+ */
+
+/* include the public api first, it should be able to stand alone */
+#include "libunbound/unbound.h"
+#include "config.h"
+#include <ctype.h>
+#include "libunbound/context.h"
+#include "libunbound/libworker.h"
+#include "util/locks.h"
+#include "util/config_file.h"
+#include "util/alloc.h"
+#include "util/module.h"
+#include "util/regional.h"
+#include "util/log.h"
+#include "util/random.h"
+#include "util/net_help.h"
+#include "util/tube.h"
+#include "services/modstack.h"
+#include "services/localzone.h"
+#include "services/cache/infra.h"
+#include "services/cache/rrset.h"
+
+#if defined(UB_ON_WINDOWS) && defined (HAVE_WINDOWS_H)
+#include <windows.h>
+#include <iphlpapi.h>
+#endif /* UB_ON_WINDOWS */
+
+struct ub_ctx*
+ub_ctx_create(void)
+{
+ struct ub_ctx* ctx;
+ unsigned int seed;
+#ifdef USE_WINSOCK
+ int r;
+ WSADATA wsa_data;
+#endif
+
+ log_init(NULL, 0, NULL); /* logs to stderr */
+ log_ident_set("libunbound");
+#ifdef USE_WINSOCK
+ if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) {
+ log_err("could not init winsock. WSAStartup: %s",
+ wsa_strerror(r));
+ return NULL;
+ }
+#endif
+ verbosity = 0; /* errors only */
+ checklock_start();
+ ctx = (struct ub_ctx*)calloc(1, sizeof(*ctx));
+ if(!ctx) {
+ errno = ENOMEM;
+ return NULL;
+ }
+ alloc_init(&ctx->superalloc, NULL, 0);
+ seed = (unsigned int)time(NULL) ^ (unsigned int)getpid();
+ if(!(ctx->seed_rnd = ub_initstate(seed, NULL))) {
+ seed = 0;
+ ub_randfree(ctx->seed_rnd);
+ free(ctx);
+ errno = ENOMEM;
+ return NULL;
+ }
+ seed = 0;
+ if((ctx->qq_pipe = tube_create()) == NULL) {
+ int e = errno;
+ ub_randfree(ctx->seed_rnd);
+ free(ctx);
+ errno = e;
+ return NULL;
+ }
+ if((ctx->rr_pipe = tube_create()) == NULL) {
+ int e = errno;
+ tube_delete(ctx->qq_pipe);
+ ub_randfree(ctx->seed_rnd);
+ free(ctx);
+ errno = e;
+ return NULL;
+ }
+ lock_basic_init(&ctx->qqpipe_lock);
+ lock_basic_init(&ctx->rrpipe_lock);
+ lock_basic_init(&ctx->cfglock);
+ ctx->env = (struct module_env*)calloc(1, sizeof(*ctx->env));
+ if(!ctx->env) {
+ tube_delete(ctx->qq_pipe);
+ tube_delete(ctx->rr_pipe);
+ ub_randfree(ctx->seed_rnd);
+ free(ctx);
+ errno = ENOMEM;
+ return NULL;
+ }
+ ctx->env->cfg = config_create_forlib();
+ if(!ctx->env->cfg) {
+ tube_delete(ctx->qq_pipe);
+ tube_delete(ctx->rr_pipe);
+ free(ctx->env);
+ ub_randfree(ctx->seed_rnd);
+ free(ctx);
+ errno = ENOMEM;
+ return NULL;
+ }
+ ctx->env->alloc = &ctx->superalloc;
+ ctx->env->worker = NULL;
+ ctx->env->need_to_validate = 0;
+ modstack_init(&ctx->mods);
+ rbtree_init(&ctx->queries, &context_query_cmp);
+ return ctx;
+}
+
+/** delete q */
+static void
+delq(rbnode_t* n, void* ATTR_UNUSED(arg))
+{
+ struct ctx_query* q = (struct ctx_query*)n;
+ context_query_delete(q);
+}
+
+void
+ub_ctx_delete(struct ub_ctx* ctx)
+{
+ struct alloc_cache* a, *na;
+ if(!ctx) return;
+ /* stop the bg thread */
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->created_bg) {
+ uint8_t* msg;
+ uint32_t len;
+ uint32_t cmd = UB_LIBCMD_QUIT;
+ lock_basic_unlock(&ctx->cfglock);
+ lock_basic_lock(&ctx->qqpipe_lock);
+ (void)tube_write_msg(ctx->qq_pipe, (uint8_t*)&cmd,
+ (uint32_t)sizeof(cmd), 0);
+ lock_basic_unlock(&ctx->qqpipe_lock);
+ lock_basic_lock(&ctx->rrpipe_lock);
+ while(tube_read_msg(ctx->rr_pipe, &msg, &len, 0)) {
+ /* discard all results except a quit confirm */
+ if(context_serial_getcmd(msg, len) == UB_LIBCMD_QUIT) {
+ free(msg);
+ break;
+ }
+ free(msg);
+ }
+ lock_basic_unlock(&ctx->rrpipe_lock);
+
+ /* if bg worker is a thread, wait for it to exit, so that all
+ * resources are really gone. */
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->dothread) {
+ lock_basic_unlock(&ctx->cfglock);
+ ub_thread_join(ctx->bg_tid);
+ } else {
+ lock_basic_unlock(&ctx->cfglock);
+ }
+ }
+ else {
+ lock_basic_unlock(&ctx->cfglock);
+ }
+
+
+ modstack_desetup(&ctx->mods, ctx->env);
+ a = ctx->alloc_list;
+ while(a) {
+ na = a->super;
+ a->super = &ctx->superalloc;
+ alloc_clear(a);
+ free(a);
+ a = na;
+ }
+ local_zones_delete(ctx->local_zones);
+ lock_basic_destroy(&ctx->qqpipe_lock);
+ lock_basic_destroy(&ctx->rrpipe_lock);
+ lock_basic_destroy(&ctx->cfglock);
+ tube_delete(ctx->qq_pipe);
+ tube_delete(ctx->rr_pipe);
+ if(ctx->env) {
+ slabhash_delete(ctx->env->msg_cache);
+ rrset_cache_delete(ctx->env->rrset_cache);
+ infra_delete(ctx->env->infra_cache);
+ config_delete(ctx->env->cfg);
+ free(ctx->env);
+ }
+ ub_randfree(ctx->seed_rnd);
+ alloc_clear(&ctx->superalloc);
+ traverse_postorder(&ctx->queries, delq, NULL);
+ free(ctx);
+#ifdef USE_WINSOCK
+ WSACleanup();
+#endif
+}
+
+int
+ub_ctx_set_option(struct ub_ctx* ctx, char* opt, char* val)
+{
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_AFTERFINAL;
+ }
+ if(!config_set_option(ctx->env->cfg, opt, val)) {
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_SYNTAX;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int
+ub_ctx_get_option(struct ub_ctx* ctx, char* opt, char** str)
+{
+ int r;
+ lock_basic_lock(&ctx->cfglock);
+ r = config_get_option_collate(ctx->env->cfg, opt, str);
+ lock_basic_unlock(&ctx->cfglock);
+ if(r == 0) r = UB_NOERROR;
+ else if(r == 1) r = UB_SYNTAX;
+ else if(r == 2) r = UB_NOMEM;
+ return r;
+}
+
+int
+ub_ctx_config(struct ub_ctx* ctx, char* fname)
+{
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_AFTERFINAL;
+ }
+ if(!config_read(ctx->env->cfg, fname, NULL)) {
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_SYNTAX;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int
+ub_ctx_add_ta(struct ub_ctx* ctx, char* ta)
+{
+ char* dup = strdup(ta);
+ if(!dup) return UB_NOMEM;
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ free(dup);
+ return UB_AFTERFINAL;
+ }
+ if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) {
+ lock_basic_unlock(&ctx->cfglock);
+ free(dup);
+ return UB_NOMEM;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int
+ub_ctx_add_ta_file(struct ub_ctx* ctx, char* fname)
+{
+ char* dup = strdup(fname);
+ if(!dup) return UB_NOMEM;
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ free(dup);
+ return UB_AFTERFINAL;
+ }
+ if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_file_list, dup)) {
+ lock_basic_unlock(&ctx->cfglock);
+ free(dup);
+ return UB_NOMEM;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int
+ub_ctx_trustedkeys(struct ub_ctx* ctx, char* fname)
+{
+ char* dup = strdup(fname);
+ if(!dup) return UB_NOMEM;
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ free(dup);
+ return UB_AFTERFINAL;
+ }
+ if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) {
+ lock_basic_unlock(&ctx->cfglock);
+ free(dup);
+ return UB_NOMEM;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int
+ub_ctx_debuglevel(struct ub_ctx* ctx, int d)
+{
+ lock_basic_lock(&ctx->cfglock);
+ verbosity = d;
+ ctx->env->cfg->verbosity = d;
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int ub_ctx_debugout(struct ub_ctx* ctx, void* out)
+{
+ lock_basic_lock(&ctx->cfglock);
+ log_file((FILE*)out);
+ ctx->logfile_override = 1;
+ ctx->log_out = out;
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int
+ub_ctx_async(struct ub_ctx* ctx, int dothread)
+{
+#ifdef THREADS_DISABLED
+ if(dothread) /* cannot do threading */
+ return UB_NOERROR;
+#endif
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_AFTERFINAL;
+ }
+ ctx->dothread = dothread;
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int
+ub_poll(struct ub_ctx* ctx)
+{
+ /* no need to hold lock while testing for readability. */
+ return tube_poll(ctx->rr_pipe);
+}
+
+int
+ub_fd(struct ub_ctx* ctx)
+{
+ return tube_read_fd(ctx->rr_pipe);
+}
+
+/** process answer from bg worker */
+static int
+process_answer_detail(struct ub_ctx* ctx, uint8_t* msg, uint32_t len,
+ ub_callback_t* cb, void** cbarg, int* err,
+ struct ub_result** res)
+{
+ struct ctx_query* q;
+ if(context_serial_getcmd(msg, len) != UB_LIBCMD_ANSWER) {
+ log_err("error: bad data from bg worker %d",
+ (int)context_serial_getcmd(msg, len));
+ return 0;
+ }
+
+ lock_basic_lock(&ctx->cfglock);
+ q = context_deserialize_answer(ctx, msg, len, err);
+ if(!q) {
+ lock_basic_unlock(&ctx->cfglock);
+ /* probably simply the lookup that failed, i.e.
+ * response returned before cancel was sent out, so noerror */
+ return 1;
+ }
+ log_assert(q->async);
+
+ /* grab cb while locked */
+ if(q->cancelled) {
+ *cb = NULL;
+ *cbarg = NULL;
+ } else {
+ *cb = q->cb;
+ *cbarg = q->cb_arg;
+ }
+ if(*err) {
+ *res = NULL;
+ ub_resolve_free(q->res);
+ } else {
+ /* parse the message, extract rcode, fill result */
+ ldns_buffer* buf = ldns_buffer_new(q->msg_len);
+ struct regional* region = regional_create();
+ *res = q->res;
+ (*res)->rcode = LDNS_RCODE_SERVFAIL;
+ if(region && buf) {
+ ldns_buffer_clear(buf);
+ ldns_buffer_write(buf, q->msg, q->msg_len);
+ ldns_buffer_flip(buf);
+ libworker_enter_result(*res, buf, region,
+ q->msg_security);
+ }
+ (*res)->answer_packet = q->msg;
+ (*res)->answer_len = (int)q->msg_len;
+ q->msg = NULL;
+ ldns_buffer_free(buf);
+ regional_destroy(region);
+ }
+ q->res = NULL;
+ /* delete the q from list */
+ (void)rbtree_delete(&ctx->queries, q->node.key);
+ ctx->num_async--;
+ context_query_delete(q);
+ lock_basic_unlock(&ctx->cfglock);
+
+ if(*cb) return 2;
+ ub_resolve_free(*res);
+ return 1;
+}
+
+/** process answer from bg worker */
+static int
+process_answer(struct ub_ctx* ctx, uint8_t* msg, uint32_t len)
+{
+ int err;
+ ub_callback_t cb;
+ void* cbarg;
+ struct ub_result* res;
+ int r;
+
+ r = process_answer_detail(ctx, msg, len, &cb, &cbarg, &err, &res);
+
+ /* no locks held while calling callback, so that library is
+ * re-entrant. */
+ if(r == 2)
+ (*cb)(cbarg, err, res);
+
+ return r;
+}
+
+int
+ub_process(struct ub_ctx* ctx)
+{
+ int r;
+ uint8_t* msg;
+ uint32_t len;
+ while(1) {
+ msg = NULL;
+ lock_basic_lock(&ctx->rrpipe_lock);
+ r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1);
+ lock_basic_unlock(&ctx->rrpipe_lock);
+ if(r == 0)
+ return UB_PIPE;
+ else if(r == -1)
+ break;
+ if(!process_answer(ctx, msg, len)) {
+ free(msg);
+ return UB_PIPE;
+ }
+ free(msg);
+ }
+ return UB_NOERROR;
+}
+
+int
+ub_wait(struct ub_ctx* ctx)
+{
+ int err;
+ ub_callback_t cb;
+ void* cbarg;
+ struct ub_result* res;
+ int r;
+ uint8_t* msg;
+ uint32_t len;
+ /* this is basically the same loop as _process(), but with changes.
+ * holds the rrpipe lock and waits with tube_wait */
+ while(1) {
+ lock_basic_lock(&ctx->rrpipe_lock);
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->num_async == 0) {
+ lock_basic_unlock(&ctx->cfglock);
+ lock_basic_unlock(&ctx->rrpipe_lock);
+ break;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+
+ /* keep rrpipe locked, while
+ * o waiting for pipe readable
+ * o parsing message
+ * o possibly decrementing num_async
+ * do callback without lock
+ */
+ r = tube_wait(ctx->rr_pipe);
+ if(r) {
+ r = tube_read_msg(ctx->rr_pipe, &msg, &len, 1);
+ if(r == 0) {
+ lock_basic_unlock(&ctx->rrpipe_lock);
+ return UB_PIPE;
+ }
+ if(r == -1) {
+ lock_basic_unlock(&ctx->rrpipe_lock);
+ continue;
+ }
+ r = process_answer_detail(ctx, msg, len,
+ &cb, &cbarg, &err, &res);
+ lock_basic_unlock(&ctx->rrpipe_lock);
+ free(msg);
+ if(r == 0)
+ return UB_PIPE;
+ if(r == 2)
+ (*cb)(cbarg, err, res);
+ } else {
+ lock_basic_unlock(&ctx->rrpipe_lock);
+ }
+ }
+ return UB_NOERROR;
+}
+
+int
+ub_resolve(struct ub_ctx* ctx, char* name, int rrtype,
+ int rrclass, struct ub_result** result)
+{
+ struct ctx_query* q;
+ int r;
+ *result = NULL;
+
+ lock_basic_lock(&ctx->cfglock);
+ if(!ctx->finalized) {
+ r = context_finalize(ctx);
+ if(r) {
+ lock_basic_unlock(&ctx->cfglock);
+ return r;
+ }
+ }
+ /* create new ctx_query and attempt to add to the list */
+ lock_basic_unlock(&ctx->cfglock);
+ q = context_new(ctx, name, rrtype, rrclass, NULL, NULL);
+ if(!q)
+ return UB_NOMEM;
+ /* become a resolver thread for a bit */
+
+ r = libworker_fg(ctx, q);
+ if(r) {
+ lock_basic_lock(&ctx->cfglock);
+ (void)rbtree_delete(&ctx->queries, q->node.key);
+ context_query_delete(q);
+ lock_basic_unlock(&ctx->cfglock);
+ return r;
+ }
+ q->res->answer_packet = q->msg;
+ q->res->answer_len = (int)q->msg_len;
+ q->msg = NULL;
+ *result = q->res;
+ q->res = NULL;
+
+ lock_basic_lock(&ctx->cfglock);
+ (void)rbtree_delete(&ctx->queries, q->node.key);
+ context_query_delete(q);
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int
+ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype,
+ int rrclass, void* mydata, ub_callback_t callback, int* async_id)
+{
+ struct ctx_query* q;
+ uint8_t* msg = NULL;
+ uint32_t len = 0;
+
+ if(async_id)
+ *async_id = 0;
+ lock_basic_lock(&ctx->cfglock);
+ if(!ctx->finalized) {
+ int r = context_finalize(ctx);
+ if(r) {
+ lock_basic_unlock(&ctx->cfglock);
+ return r;
+ }
+ }
+ if(!ctx->created_bg) {
+ int r;
+ ctx->created_bg = 1;
+ lock_basic_unlock(&ctx->cfglock);
+ r = libworker_bg(ctx);
+ if(r) {
+ lock_basic_lock(&ctx->cfglock);
+ ctx->created_bg = 0;
+ lock_basic_unlock(&ctx->cfglock);
+ return r;
+ }
+ } else {
+ lock_basic_unlock(&ctx->cfglock);
+ }
+
+ /* create new ctx_query and attempt to add to the list */
+ q = context_new(ctx, name, rrtype, rrclass, callback, mydata);
+ if(!q)
+ return UB_NOMEM;
+
+ /* write over pipe to background worker */
+ lock_basic_lock(&ctx->cfglock);
+ msg = context_serialize_new_query(q, &len);
+ if(!msg) {
+ (void)rbtree_delete(&ctx->queries, q->node.key);
+ ctx->num_async--;
+ context_query_delete(q);
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOMEM;
+ }
+ if(async_id)
+ *async_id = q->querynum;
+ lock_basic_unlock(&ctx->cfglock);
+
+ lock_basic_lock(&ctx->qqpipe_lock);
+ if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
+ lock_basic_unlock(&ctx->qqpipe_lock);
+ free(msg);
+ return UB_PIPE;
+ }
+ lock_basic_unlock(&ctx->qqpipe_lock);
+ free(msg);
+ return UB_NOERROR;
+}
+
+int
+ub_cancel(struct ub_ctx* ctx, int async_id)
+{
+ struct ctx_query* q;
+ uint8_t* msg = NULL;
+ uint32_t len = 0;
+ lock_basic_lock(&ctx->cfglock);
+ q = (struct ctx_query*)rbtree_search(&ctx->queries, &async_id);
+ if(!q || !q->async) {
+ /* it is not there, so nothing to do */
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOID;
+ }
+ log_assert(q->async);
+ q->cancelled = 1;
+
+ /* delete it */
+ if(!ctx->dothread) { /* if forked */
+ (void)rbtree_delete(&ctx->queries, q->node.key);
+ ctx->num_async--;
+ msg = context_serialize_cancel(q, &len);
+ context_query_delete(q);
+ lock_basic_unlock(&ctx->cfglock);
+ if(!msg) {
+ return UB_NOMEM;
+ }
+ /* send cancel to background worker */
+ lock_basic_lock(&ctx->qqpipe_lock);
+ if(!tube_write_msg(ctx->qq_pipe, msg, len, 0)) {
+ lock_basic_unlock(&ctx->qqpipe_lock);
+ free(msg);
+ return UB_PIPE;
+ }
+ lock_basic_unlock(&ctx->qqpipe_lock);
+ free(msg);
+ } else {
+ lock_basic_unlock(&ctx->cfglock);
+ }
+ return UB_NOERROR;
+}
+
+void
+ub_resolve_free(struct ub_result* result)
+{
+ char** p;
+ if(!result) return;
+ free(result->qname);
+ if(result->canonname != result->qname)
+ free(result->canonname);
+ if(result->data)
+ for(p = result->data; *p; p++)
+ free(*p);
+ free(result->data);
+ free(result->len);
+ free(result->answer_packet);
+ free(result->why_bogus);
+ free(result);
+}
+
+const char*
+ub_strerror(int err)
+{
+ switch(err) {
+ case UB_NOERROR: return "no error";
+ case UB_SOCKET: return "socket io error";
+ case UB_NOMEM: return "out of memory";
+ case UB_SYNTAX: return "syntax error";
+ case UB_SERVFAIL: return "server failure";
+ case UB_FORKFAIL: return "could not fork";
+ case UB_INITFAIL: return "initialization failure";
+ case UB_AFTERFINAL: return "setting change after finalize";
+ case UB_PIPE: return "error in pipe communication with async";
+ case UB_READFILE: return "error reading file";
+ case UB_NOID: return "error async_id does not exist";
+ default: return "unknown error";
+ }
+}
+
+int
+ub_ctx_set_fwd(struct ub_ctx* ctx, char* addr)
+{
+ struct sockaddr_storage storage;
+ socklen_t stlen;
+ struct config_stub* s;
+ char* dupl;
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ errno=EINVAL;
+ return UB_AFTERFINAL;
+ }
+ if(!addr) {
+ /* disable fwd mode - the root stub should be first. */
+ if(ctx->env->cfg->forwards &&
+ strcmp(ctx->env->cfg->forwards->name, ".") == 0) {
+ s = ctx->env->cfg->forwards;
+ ctx->env->cfg->forwards = s->next;
+ s->next = NULL;
+ config_delstubs(s);
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+
+ /* check syntax for addr */
+ if(!extstrtoaddr(addr, &storage, &stlen)) {
+ errno=EINVAL;
+ return UB_SYNTAX;
+ }
+
+ /* it parses, add root stub in front of list */
+ lock_basic_lock(&ctx->cfglock);
+ if(!ctx->env->cfg->forwards ||
+ strcmp(ctx->env->cfg->forwards->name, ".") != 0) {
+ s = calloc(1, sizeof(*s));
+ if(!s) {
+ lock_basic_unlock(&ctx->cfglock);
+ errno=ENOMEM;
+ return UB_NOMEM;
+ }
+ s->name = strdup(".");
+ if(!s->name) {
+ free(s);
+ lock_basic_unlock(&ctx->cfglock);
+ errno=ENOMEM;
+ return UB_NOMEM;
+ }
+ s->next = ctx->env->cfg->forwards;
+ ctx->env->cfg->forwards = s;
+ } else {
+ log_assert(ctx->env->cfg->forwards);
+ s = ctx->env->cfg->forwards;
+ }
+ dupl = strdup(addr);
+ if(!dupl) {
+ lock_basic_unlock(&ctx->cfglock);
+ errno=ENOMEM;
+ return UB_NOMEM;
+ }
+ if(!cfg_strlist_insert(&s->addrs, dupl)) {
+ free(dupl);
+ lock_basic_unlock(&ctx->cfglock);
+ errno=ENOMEM;
+ return UB_NOMEM;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int
+ub_ctx_resolvconf(struct ub_ctx* ctx, char* fname)
+{
+ FILE* in;
+ int numserv = 0;
+ char buf[1024];
+ char* parse, *addr;
+ int r;
+
+ if(fname == NULL) {
+#if !defined(UB_ON_WINDOWS) || !defined(HAVE_WINDOWS_H)
+ fname = "/etc/resolv.conf";
+#else
+ FIXED_INFO *info;
+ ULONG buflen = sizeof(*info);
+ IP_ADDR_STRING *ptr;
+
+ info = (FIXED_INFO *) malloc(sizeof (FIXED_INFO));
+ if (info == NULL)
+ return UB_READFILE;
+
+ if (GetNetworkParams(info, &buflen) == ERROR_BUFFER_OVERFLOW) {
+ free(info);
+ info = (FIXED_INFO *) malloc(buflen);
+ if (info == NULL)
+ return UB_READFILE;
+ }
+
+ if (GetNetworkParams(info, &buflen) == NO_ERROR) {
+ int retval=0;
+ ptr = &(info->DnsServerList);
+ while (ptr) {
+ numserv++;
+ if((retval=ub_ctx_set_fwd(ctx,
+ ptr->IpAddress.String)!=0)) {
+ free(info);
+ return retval;
+ }
+ ptr = ptr->Next;
+ }
+ free(info);
+ if (numserv==0)
+ return UB_READFILE;
+ return UB_NOERROR;
+ }
+ free(info);
+ return UB_READFILE;
+#endif /* WINDOWS */
+ }
+ in = fopen(fname, "r");
+ if(!in) {
+ /* error in errno! perror(fname) */
+ return UB_READFILE;
+ }
+ while(fgets(buf, (int)sizeof(buf), in)) {
+ buf[sizeof(buf)-1] = 0;
+ parse=buf;
+ while(*parse == ' ' || *parse == '\t')
+ parse++;
+ if(strncmp(parse, "nameserver", 10) == 0) {
+ numserv++;
+ parse += 10; /* skip 'nameserver' */
+ /* skip whitespace */
+ while(*parse == ' ' || *parse == '\t')
+ parse++;
+ addr = parse;
+ /* skip [0-9a-fA-F.:]*, i.e. IP4 and IP6 address */
+ while(isxdigit(*parse) || *parse=='.' || *parse==':')
+ parse++;
+ /* terminate after the address, remove newline */
+ *parse = 0;
+
+ if((r = ub_ctx_set_fwd(ctx, addr)) != UB_NOERROR) {
+ fclose(in);
+ return r;
+ }
+ }
+ }
+ fclose(in);
+ if(numserv == 0) {
+ /* from resolv.conf(5) if none given, use localhost */
+ return ub_ctx_set_fwd(ctx, "127.0.0.1");
+ }
+ return UB_NOERROR;
+}
+
+int
+ub_ctx_hosts(struct ub_ctx* ctx, char* fname)
+{
+ FILE* in;
+ char buf[1024], ldata[1024];
+ char* parse, *addr, *name, *ins;
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ errno=EINVAL;
+ return UB_AFTERFINAL;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ if(fname == NULL) {
+#if defined(UB_ON_WINDOWS) && defined(HAVE_WINDOWS_H)
+ /*
+ * If this is Windows NT/XP/2K it's in
+ * %WINDIR%\system32\drivers\etc\hosts.
+ * If this is Windows 95/98/Me it's in %WINDIR%\hosts.
+ */
+ name = getenv("WINDIR");
+ if (name != NULL) {
+ int retval=0;
+ snprintf(buf, sizeof(buf), "%s%s", name,
+ "\\system32\\drivers\\etc\\hosts");
+ if((retval=ub_ctx_hosts(ctx, buf)) !=0 ) {
+ snprintf(buf, sizeof(buf), "%s%s", name,
+ "\\hosts");
+ retval=ub_ctx_hosts(ctx, buf);
+ }
+ free(name);
+ return retval;
+ }
+ return UB_READFILE;
+#else
+ fname = "/etc/hosts";
+#endif /* WIN32 */
+ }
+ in = fopen(fname, "r");
+ if(!in) {
+ /* error in errno! perror(fname) */
+ return UB_READFILE;
+ }
+ while(fgets(buf, (int)sizeof(buf), in)) {
+ buf[sizeof(buf)-1] = 0;
+ parse=buf;
+ while(*parse == ' ' || *parse == '\t')
+ parse++;
+ if(*parse == '#')
+ continue; /* skip comment */
+ /* format: <addr> spaces <name> spaces <name> ... */
+ addr = parse;
+ /* skip addr */
+ while(isxdigit(*parse) || *parse == '.' || *parse == ':')
+ parse++;
+ if(*parse == '\n' || *parse == 0)
+ continue;
+ if(*parse == '%')
+ continue; /* ignore macOSX fe80::1%lo0 localhost */
+ if(*parse != ' ' && *parse != '\t') {
+ /* must have whitespace after address */
+ fclose(in);
+ errno=EINVAL;
+ return UB_SYNTAX;
+ }
+ *parse++ = 0; /* end delimiter for addr ... */
+ /* go to names and add them */
+ while(*parse) {
+ while(*parse == ' ' || *parse == '\t' || *parse=='\n')
+ parse++;
+ if(*parse == 0 || *parse == '#')
+ break;
+ /* skip name, allows (too) many printable characters */
+ name = parse;
+ while('!' <= *parse && *parse <= '~')
+ parse++;
+ if(*parse)
+ *parse++ = 0; /* end delimiter for name */
+ snprintf(ldata, sizeof(ldata), "%s %s %s",
+ name, str_is_ip6(addr)?"AAAA":"A", addr);
+ ins = strdup(ldata);
+ if(!ins) {
+ /* out of memory */
+ fclose(in);
+ errno=ENOMEM;
+ return UB_NOMEM;
+ }
+ lock_basic_lock(&ctx->cfglock);
+ if(!cfg_strlist_insert(&ctx->env->cfg->local_data,
+ ins)) {
+ lock_basic_unlock(&ctx->cfglock);
+ fclose(in);
+ free(ins);
+ errno=ENOMEM;
+ return UB_NOMEM;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ }
+ }
+ fclose(in);
+ return UB_NOERROR;
+}
+
+/** finalize the context, if not already finalized */
+static int ub_ctx_finalize(struct ub_ctx* ctx)
+{
+ int res = 0;
+ lock_basic_lock(&ctx->cfglock);
+ if (!ctx->finalized) {
+ res = context_finalize(ctx);
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ return res;
+}
+
+/* Print local zones and RR data */
+int ub_ctx_print_local_zones(struct ub_ctx* ctx)
+{
+ int res = ub_ctx_finalize(ctx);
+ if (res) return res;
+
+ local_zones_print(ctx->local_zones);
+
+ return UB_NOERROR;
+}
+
+/* Add a new zone */
+int ub_ctx_zone_add(struct ub_ctx* ctx, char *zone_name, char *zone_type)
+{
+ enum localzone_type t;
+ struct local_zone* z;
+ uint8_t* nm;
+ int nmlabs;
+ size_t nmlen;
+
+ int res = ub_ctx_finalize(ctx);
+ if (res) return res;
+
+ if(!local_zone_str2type(zone_type, &t)) {
+ return UB_SYNTAX;
+ }
+
+ if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) {
+ return UB_SYNTAX;
+ }
+
+ lock_quick_lock(&ctx->local_zones->lock);
+ if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs,
+ LDNS_RR_CLASS_IN))) {
+ /* already present in tree */
+ lock_rw_wrlock(&z->lock);
+ z->type = t; /* update type anyway */
+ lock_rw_unlock(&z->lock);
+ lock_quick_unlock(&ctx->local_zones->lock);
+ free(nm);
+ return UB_NOERROR;
+ }
+ if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs,
+ LDNS_RR_CLASS_IN, t)) {
+ lock_quick_unlock(&ctx->local_zones->lock);
+ return UB_NOMEM;
+ }
+ lock_quick_unlock(&ctx->local_zones->lock);
+ return UB_NOERROR;
+}
+
+/* Remove zone */
+int ub_ctx_zone_remove(struct ub_ctx* ctx, char *zone_name)
+{
+ struct local_zone* z;
+ uint8_t* nm;
+ int nmlabs;
+ size_t nmlen;
+
+ int res = ub_ctx_finalize(ctx);
+ if (res) return res;
+
+ if(!parse_dname(zone_name, &nm, &nmlen, &nmlabs)) {
+ return UB_SYNTAX;
+ }
+
+ lock_quick_lock(&ctx->local_zones->lock);
+ if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs,
+ LDNS_RR_CLASS_IN))) {
+ /* present in tree */
+ local_zones_del_zone(ctx->local_zones, z);
+ }
+ lock_quick_unlock(&ctx->local_zones->lock);
+ free(nm);
+ return UB_NOERROR;
+}
+
+/* Add new RR data */
+int ub_ctx_data_add(struct ub_ctx* ctx, char *data)
+{
+ ldns_buffer* buf;
+ int res = ub_ctx_finalize(ctx);
+ if (res) return res;
+
+ lock_basic_lock(&ctx->cfglock);
+ buf = ldns_buffer_new(ctx->env->cfg->msg_buffer_size);
+ lock_basic_unlock(&ctx->cfglock);
+ if(!buf) return UB_NOMEM;
+
+ res = local_zones_add_RR(ctx->local_zones, data, buf);
+
+ ldns_buffer_free(buf);
+ return (!res) ? UB_NOMEM : UB_NOERROR;
+}
+
+/* Remove RR data */
+int ub_ctx_data_remove(struct ub_ctx* ctx, char *data)
+{
+ uint8_t* nm;
+ int nmlabs;
+ size_t nmlen;
+ int res = ub_ctx_finalize(ctx);
+ if (res) return res;
+
+ if(!parse_dname(data, &nm, &nmlen, &nmlabs))
+ return UB_SYNTAX;
+
+ local_zones_del_data(ctx->local_zones, nm, nmlen, nmlabs,
+ LDNS_RR_CLASS_IN);
+
+ free(nm);
+ return UB_NOERROR;
+}
+
+const char* ub_version(void)
+{
+ return PACKAGE_VERSION;
+}
diff --git a/contrib/unbound/libunbound/libworker.c b/contrib/unbound/libunbound/libworker.c
new file mode 100644
index 0000000..917a910
--- /dev/null
+++ b/contrib/unbound/libunbound/libworker.c
@@ -0,0 +1,920 @@
+/*
+ * libunbound/worker.c - worker thread or process that resolves
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+ */
+
+/**
+ * \file
+ *
+ * This file contains the worker process or thread that performs
+ * the DNS resolving and validation. The worker is called by a procedure
+ * and if in the background continues until exit, if in the foreground
+ * returns from the procedure when done.
+ */
+#include "config.h"
+#include <ldns/dname.h>
+#include <ldns/wire2host.h>
+#include <openssl/ssl.h>
+#include "libunbound/libworker.h"
+#include "libunbound/context.h"
+#include "libunbound/unbound.h"
+#include "services/outside_network.h"
+#include "services/mesh.h"
+#include "services/localzone.h"
+#include "services/cache/rrset.h"
+#include "services/outbound_list.h"
+#include "util/module.h"
+#include "util/regional.h"
+#include "util/random.h"
+#include "util/config_file.h"
+#include "util/netevent.h"
+#include "util/storage/lookup3.h"
+#include "util/storage/slabhash.h"
+#include "util/net_help.h"
+#include "util/data/dname.h"
+#include "util/data/msgreply.h"
+#include "util/data/msgencode.h"
+#include "util/tube.h"
+#include "iterator/iter_fwd.h"
+#include "iterator/iter_hints.h"
+
+/** handle new query command for bg worker */
+static void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
+
+/** delete libworker struct */
+static void
+libworker_delete(struct libworker* w)
+{
+ if(!w) return;
+ if(w->env) {
+ outside_network_quit_prepare(w->back);
+ mesh_delete(w->env->mesh);
+ context_release_alloc(w->ctx, w->env->alloc,
+ !w->is_bg || w->is_bg_thread);
+ ldns_buffer_free(w->env->scratch_buffer);
+ regional_destroy(w->env->scratch);
+ forwards_delete(w->env->fwds);
+ hints_delete(w->env->hints);
+ ub_randfree(w->env->rnd);
+ free(w->env);
+ }
+ SSL_CTX_free(w->sslctx);
+ outside_network_delete(w->back);
+ comm_base_delete(w->base);
+ free(w);
+}
+
+/** setup fresh libworker struct */
+static struct libworker*
+libworker_setup(struct ub_ctx* ctx, int is_bg)
+{
+ unsigned int seed;
+ struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
+ struct config_file* cfg = ctx->env->cfg;
+ int* ports;
+ int numports;
+ if(!w) return NULL;
+ w->is_bg = is_bg;
+ w->ctx = ctx;
+ w->env = (struct module_env*)malloc(sizeof(*w->env));
+ if(!w->env) {
+ free(w);
+ return NULL;
+ }
+ *w->env = *ctx->env;
+ w->env->alloc = context_obtain_alloc(ctx, !w->is_bg || w->is_bg_thread);
+ if(!w->env->alloc) {
+ libworker_delete(w);
+ return NULL;
+ }
+ w->thread_num = w->env->alloc->thread_num;
+ alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w);
+ if(!w->is_bg || w->is_bg_thread) {
+ lock_basic_lock(&ctx->cfglock);
+ }
+ w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
+ w->env->scratch_buffer = ldns_buffer_new(cfg->msg_buffer_size);
+ w->env->fwds = forwards_create();
+ if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) {
+ forwards_delete(w->env->fwds);
+ w->env->fwds = NULL;
+ }
+ w->env->hints = hints_create();
+ if(w->env->hints && !hints_apply_cfg(w->env->hints, cfg)) {
+ hints_delete(w->env->hints);
+ w->env->hints = NULL;
+ }
+ if(cfg->ssl_upstream) {
+ w->sslctx = connect_sslctx_create(NULL, NULL, NULL);
+ if(!w->sslctx) {
+ /* to make the setup fail after unlock */
+ hints_delete(w->env->hints);
+ w->env->hints = NULL;
+ }
+ }
+ if(!w->is_bg || w->is_bg_thread) {
+ lock_basic_unlock(&ctx->cfglock);
+ }
+ if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds ||
+ !w->env->hints) {
+ libworker_delete(w);
+ return NULL;
+ }
+ w->env->worker = (struct worker*)w;
+ w->env->probe_timer = NULL;
+ seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^
+ (((unsigned int)w->thread_num)<<17);
+ seed ^= (unsigned int)w->env->alloc->next_id;
+ if(!w->is_bg || w->is_bg_thread) {
+ lock_basic_lock(&ctx->cfglock);
+ }
+ if(!(w->env->rnd = ub_initstate(seed, ctx->seed_rnd))) {
+ if(!w->is_bg || w->is_bg_thread) {
+ lock_basic_unlock(&ctx->cfglock);
+ }
+ seed = 0;
+ libworker_delete(w);
+ return NULL;
+ }
+ if(!w->is_bg || w->is_bg_thread) {
+ lock_basic_unlock(&ctx->cfglock);
+ }
+ if(1) {
+ /* primitive lockout for threading: if it overwrites another
+ * thread it is like wiping the cache (which is likely empty
+ * at the start) */
+ /* note we are holding the ctx lock in normal threaded
+ * cases so that is solved properly, it is only for many ctx
+ * in different threads that this may clash */
+ static int done_raninit = 0;
+ if(!done_raninit) {
+ done_raninit = 1;
+ hash_set_raninit((uint32_t)ub_random(w->env->rnd));
+ }
+ }
+ seed = 0;
+
+ w->base = comm_base_create(0);
+ if(!w->base) {
+ libworker_delete(w);
+ return NULL;
+ }
+ if(!w->is_bg || w->is_bg_thread) {
+ lock_basic_lock(&ctx->cfglock);
+ }
+ numports = cfg_condense_ports(cfg, &ports);
+ if(numports == 0) {
+ libworker_delete(w);
+ return NULL;
+ }
+ w->back = outside_network_create(w->base, cfg->msg_buffer_size,
+ (size_t)cfg->outgoing_num_ports, cfg->out_ifs,
+ cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
+ cfg->do_tcp?cfg->outgoing_num_tcp:0,
+ w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
+ ports, numports, cfg->unwanted_threshold,
+ &libworker_alloc_cleanup, w, cfg->do_udp, w->sslctx);
+ if(!w->is_bg || w->is_bg_thread) {
+ lock_basic_unlock(&ctx->cfglock);
+ }
+ free(ports);
+ if(!w->back) {
+ libworker_delete(w);
+ return NULL;
+ }
+ w->env->mesh = mesh_create(&ctx->mods, w->env);
+ if(!w->env->mesh) {
+ libworker_delete(w);
+ return NULL;
+ }
+ w->env->send_query = &libworker_send_query;
+ w->env->detach_subs = &mesh_detach_subs;
+ w->env->attach_sub = &mesh_attach_sub;
+ w->env->kill_sub = &mesh_state_delete;
+ w->env->detect_cycle = &mesh_detect_cycle;
+ comm_base_timept(w->base, &w->env->now, &w->env->now_tv);
+ return w;
+}
+
+/** handle cancel command for bg worker */
+static void
+handle_cancel(struct libworker* w, uint8_t* buf, uint32_t len)
+{
+ struct ctx_query* q;
+ if(w->is_bg_thread) {
+ lock_basic_lock(&w->ctx->cfglock);
+ q = context_deserialize_cancel(w->ctx, buf, len);
+ lock_basic_unlock(&w->ctx->cfglock);
+ } else {
+ q = context_deserialize_cancel(w->ctx, buf, len);
+ }
+ if(!q) {
+ /* probably simply lookup failed, i.e. the message had been
+ * processed and answered before the cancel arrived */
+ return;
+ }
+ q->cancelled = 1;
+ free(buf);
+}
+
+/** do control command coming into bg server */
+static void
+libworker_do_cmd(struct libworker* w, uint8_t* msg, uint32_t len)
+{
+ switch(context_serial_getcmd(msg, len)) {
+ default:
+ case UB_LIBCMD_ANSWER:
+ log_err("unknown command for bg worker %d",
+ (int)context_serial_getcmd(msg, len));
+ /* and fall through to quit */
+ case UB_LIBCMD_QUIT:
+ free(msg);
+ comm_base_exit(w->base);
+ break;
+ case UB_LIBCMD_NEWQUERY:
+ handle_newq(w, msg, len);
+ break;
+ case UB_LIBCMD_CANCEL:
+ handle_cancel(w, msg, len);
+ break;
+ }
+}
+
+/** handle control command coming into server */
+void
+libworker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
+ uint8_t* msg, size_t len, int err, void* arg)
+{
+ struct libworker* w = (struct libworker*)arg;
+
+ if(err != 0) {
+ free(msg);
+ /* it is of no use to go on, exit */
+ comm_base_exit(w->base);
+ return;
+ }
+ libworker_do_cmd(w, msg, len); /* also frees the buf */
+}
+
+/** the background thread func */
+static void*
+libworker_dobg(void* arg)
+{
+ /* setup */
+ uint32_t m;
+ struct libworker* w = (struct libworker*)arg;
+ struct ub_ctx* ctx;
+ if(!w) {
+ log_err("libunbound bg worker init failed, nomem");
+ return NULL;
+ }
+ ctx = w->ctx;
+ log_thread_set(&w->thread_num);
+#ifdef THREADS_DISABLED
+ /* we are forked */
+ w->is_bg_thread = 0;
+ /* close non-used parts of the pipes */
+ tube_close_write(ctx->qq_pipe);
+ tube_close_read(ctx->rr_pipe);
+#endif
+ if(!tube_setup_bg_listen(ctx->qq_pipe, w->base,
+ libworker_handle_control_cmd, w)) {
+ log_err("libunbound bg worker init failed, no bglisten");
+ return NULL;
+ }
+ if(!tube_setup_bg_write(ctx->rr_pipe, w->base)) {
+ log_err("libunbound bg worker init failed, no bgwrite");
+ return NULL;
+ }
+
+ /* do the work */
+ comm_base_dispatch(w->base);
+
+ /* cleanup */
+ m = UB_LIBCMD_QUIT;
+ tube_remove_bg_listen(w->ctx->qq_pipe);
+ tube_remove_bg_write(w->ctx->rr_pipe);
+ libworker_delete(w);
+ (void)tube_write_msg(ctx->rr_pipe, (uint8_t*)&m,
+ (uint32_t)sizeof(m), 0);
+#ifdef THREADS_DISABLED
+ /* close pipes from forked process before exit */
+ tube_close_read(ctx->qq_pipe);
+ tube_close_write(ctx->rr_pipe);
+#endif
+ return NULL;
+}
+
+int libworker_bg(struct ub_ctx* ctx)
+{
+ struct libworker* w;
+ /* fork or threadcreate */
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->dothread) {
+ lock_basic_unlock(&ctx->cfglock);
+ w = libworker_setup(ctx, 1);
+ if(!w) return UB_NOMEM;
+ w->is_bg_thread = 1;
+#ifdef ENABLE_LOCK_CHECKS
+ w->thread_num = 1; /* for nicer DEBUG checklocks */
+#endif
+ ub_thread_create(&ctx->bg_tid, libworker_dobg, w);
+ } else {
+ lock_basic_unlock(&ctx->cfglock);
+#ifndef HAVE_FORK
+ /* no fork on windows */
+ return UB_FORKFAIL;
+#else /* HAVE_FORK */
+ switch((ctx->bg_pid=fork())) {
+ case 0:
+ w = libworker_setup(ctx, 1);
+ if(!w) fatal_exit("out of memory");
+ /* close non-used parts of the pipes */
+ tube_close_write(ctx->qq_pipe);
+ tube_close_read(ctx->rr_pipe);
+ (void)libworker_dobg(w);
+ exit(0);
+ break;
+ case -1:
+ return UB_FORKFAIL;
+ default:
+ break;
+ }
+#endif /* HAVE_FORK */
+ }
+ return UB_NOERROR;
+}
+
+/** get msg reply struct (in temp region) */
+static struct reply_info*
+parse_reply(ldns_buffer* pkt, struct regional* region, struct query_info* qi)
+{
+ struct reply_info* rep;
+ struct msg_parse* msg;
+ if(!(msg = regional_alloc(region, sizeof(*msg)))) {
+ return NULL;
+ }
+ memset(msg, 0, sizeof(*msg));
+ ldns_buffer_set_position(pkt, 0);
+ if(parse_packet(pkt, msg, region) != 0)
+ return 0;
+ if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) {
+ return 0;
+ }
+ return rep;
+}
+
+/** insert canonname */
+static int
+fill_canon(struct ub_result* res, uint8_t* s)
+{
+ char buf[255+2];
+ dname_str(s, buf);
+ res->canonname = strdup(buf);
+ return res->canonname != 0;
+}
+
+/** fill data into result */
+static int
+fill_res(struct ub_result* res, struct ub_packed_rrset_key* answer,
+ uint8_t* finalcname, struct query_info* rq)
+{
+ size_t i;
+ struct packed_rrset_data* data;
+ if(!answer) {
+ if(finalcname) {
+ if(!fill_canon(res, finalcname))
+ return 0; /* out of memory */
+ }
+ res->data = (char**)calloc(1, sizeof(char*));
+ res->len = (int*)calloc(1, sizeof(int));
+ return (res->data && res->len);
+ }
+ data = (struct packed_rrset_data*)answer->entry.data;
+ if(query_dname_compare(rq->qname, answer->rk.dname) != 0) {
+ if(!fill_canon(res, answer->rk.dname))
+ return 0; /* out of memory */
+ } else res->canonname = NULL;
+ res->data = (char**)calloc(data->count+1, sizeof(char*));
+ res->len = (int*)calloc(data->count+1, sizeof(int));
+ if(!res->data || !res->len)
+ return 0; /* out of memory */
+ for(i=0; i<data->count; i++) {
+ /* remove rdlength from rdata */
+ res->len[i] = (int)(data->rr_len[i] - 2);
+ res->data[i] = memdup(data->rr_data[i]+2, (size_t)res->len[i]);
+ if(!res->data[i])
+ return 0; /* out of memory */
+ }
+ res->data[data->count] = NULL;
+ res->len[data->count] = 0;
+ return 1;
+}
+
+/** fill result from parsed message, on error fills servfail */
+void
+libworker_enter_result(struct ub_result* res, ldns_buffer* buf,
+ struct regional* temp, enum sec_status msg_security)
+{
+ struct query_info rq;
+ struct reply_info* rep;
+ res->rcode = LDNS_RCODE_SERVFAIL;
+ rep = parse_reply(buf, temp, &rq);
+ if(!rep) {
+ log_err("cannot parse buf");
+ return; /* error parsing buf, or out of memory */
+ }
+ if(!fill_res(res, reply_find_answer_rrset(&rq, rep),
+ reply_find_final_cname_target(&rq, rep), &rq))
+ return; /* out of memory */
+ /* rcode, havedata, nxdomain, secure, bogus */
+ res->rcode = (int)FLAGS_GET_RCODE(rep->flags);
+ if(res->data && res->data[0])
+ res->havedata = 1;
+ if(res->rcode == LDNS_RCODE_NXDOMAIN)
+ res->nxdomain = 1;
+ if(msg_security == sec_status_secure)
+ res->secure = 1;
+ if(msg_security == sec_status_bogus)
+ res->bogus = 1;
+}
+
+/** fillup fg results */
+static void
+libworker_fillup_fg(struct ctx_query* q, int rcode, ldns_buffer* buf,
+ enum sec_status s, char* why_bogus)
+{
+ if(why_bogus)
+ q->res->why_bogus = strdup(why_bogus);
+ if(rcode != 0) {
+ q->res->rcode = rcode;
+ q->msg_security = s;
+ return;
+ }
+
+ q->res->rcode = LDNS_RCODE_SERVFAIL;
+ q->msg_security = 0;
+ q->msg = memdup(ldns_buffer_begin(buf), ldns_buffer_limit(buf));
+ q->msg_len = ldns_buffer_limit(buf);
+ if(!q->msg) {
+ return; /* the error is in the rcode */
+ }
+
+ /* canonname and results */
+ q->msg_security = s;
+ libworker_enter_result(q->res, buf, q->w->env->scratch, s);
+}
+
+void
+libworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s,
+ char* why_bogus)
+{
+ struct ctx_query* q = (struct ctx_query*)arg;
+ /* fg query is done; exit comm base */
+ comm_base_exit(q->w->base);
+
+ libworker_fillup_fg(q, rcode, buf, s, why_bogus);
+}
+
+/** setup qinfo and edns */
+static int
+setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
+ struct query_info* qinfo, struct edns_data* edns)
+{
+ ldns_rdf* rdf;
+ qinfo->qtype = (uint16_t)q->res->qtype;
+ qinfo->qclass = (uint16_t)q->res->qclass;
+ rdf = ldns_dname_new_frm_str(q->res->qname);
+ if(!rdf) {
+ return 0;
+ }
+#ifdef UNBOUND_ALLOC_LITE
+ qinfo->qname = memdup(ldns_rdf_data(rdf), ldns_rdf_size(rdf));
+ qinfo->qname_len = ldns_rdf_size(rdf);
+ ldns_rdf_deep_free(rdf);
+ rdf = 0;
+#else
+ qinfo->qname = ldns_rdf_data(rdf);
+ qinfo->qname_len = ldns_rdf_size(rdf);
+#endif
+ edns->edns_present = 1;
+ edns->ext_rcode = 0;
+ edns->edns_version = 0;
+ edns->bits = EDNS_DO;
+ if(ldns_buffer_capacity(w->back->udp_buff) < 65535)
+ edns->udp_size = (uint16_t)ldns_buffer_capacity(
+ w->back->udp_buff);
+ else edns->udp_size = 65535;
+ ldns_rdf_free(rdf);
+ return 1;
+}
+
+int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
+{
+ struct libworker* w = libworker_setup(ctx, 0);
+ uint16_t qflags, qid;
+ struct query_info qinfo;
+ struct edns_data edns;
+ if(!w)
+ return UB_INITFAIL;
+ if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
+ libworker_delete(w);
+ return UB_SYNTAX;
+ }
+ qid = 0;
+ qflags = BIT_RD;
+ q->w = w;
+ /* see if there is a fixed answer */
+ ldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
+ ldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
+ if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
+ w->back->udp_buff, w->env->scratch)) {
+ regional_free_all(w->env->scratch);
+ libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
+ w->back->udp_buff, sec_status_insecure, NULL);
+ libworker_delete(w);
+ free(qinfo.qname);
+ return UB_NOERROR;
+ }
+ /* process new query */
+ if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
+ w->back->udp_buff, qid, libworker_fg_done_cb, q)) {
+ free(qinfo.qname);
+ return UB_NOMEM;
+ }
+ free(qinfo.qname);
+
+ /* wait for reply */
+ comm_base_dispatch(w->base);
+
+ libworker_delete(w);
+ return UB_NOERROR;
+}
+
+/** add result to the bg worker result queue */
+static void
+add_bg_result(struct libworker* w, struct ctx_query* q, ldns_buffer* pkt,
+ int err, char* reason)
+{
+ uint8_t* msg = NULL;
+ uint32_t len = 0;
+
+ /* serialize and delete unneeded q */
+ if(w->is_bg_thread) {
+ lock_basic_lock(&w->ctx->cfglock);
+ if(reason)
+ q->res->why_bogus = strdup(reason);
+ if(pkt) {
+ q->msg_len = ldns_buffer_remaining(pkt);
+ q->msg = memdup(ldns_buffer_begin(pkt), q->msg_len);
+ if(!q->msg)
+ msg = context_serialize_answer(q, UB_NOMEM,
+ NULL, &len);
+ else msg = context_serialize_answer(q, err,
+ NULL, &len);
+ } else msg = context_serialize_answer(q, err, NULL, &len);
+ lock_basic_unlock(&w->ctx->cfglock);
+ } else {
+ if(reason)
+ q->res->why_bogus = strdup(reason);
+ msg = context_serialize_answer(q, err, pkt, &len);
+ (void)rbtree_delete(&w->ctx->queries, q->node.key);
+ w->ctx->num_async--;
+ context_query_delete(q);
+ }
+
+ if(!msg) {
+ log_err("out of memory for async answer");
+ return;
+ }
+ if(!tube_queue_item(w->ctx->rr_pipe, msg, len)) {
+ log_err("out of memory for async answer");
+ return;
+ }
+}
+
+void
+libworker_bg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s,
+ char* why_bogus)
+{
+ struct ctx_query* q = (struct ctx_query*)arg;
+
+ if(q->cancelled) {
+ if(q->w->is_bg_thread) {
+ /* delete it now */
+ struct ub_ctx* ctx = q->w->ctx;
+ lock_basic_lock(&ctx->cfglock);
+ (void)rbtree_delete(&ctx->queries, q->node.key);
+ ctx->num_async--;
+ context_query_delete(q);
+ lock_basic_unlock(&ctx->cfglock);
+ }
+ /* cancelled, do not give answer */
+ return;
+ }
+ q->msg_security = s;
+ if(rcode != 0) {
+ error_encode(buf, rcode, NULL, 0, BIT_RD, NULL);
+ }
+ add_bg_result(q->w, q, buf, UB_NOERROR, why_bogus);
+}
+
+
+/** handle new query command for bg worker */
+static void
+handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
+{
+ uint16_t qflags, qid;
+ struct query_info qinfo;
+ struct edns_data edns;
+ struct ctx_query* q;
+ if(w->is_bg_thread) {
+ lock_basic_lock(&w->ctx->cfglock);
+ q = context_lookup_new_query(w->ctx, buf, len);
+ lock_basic_unlock(&w->ctx->cfglock);
+ } else {
+ q = context_deserialize_new_query(w->ctx, buf, len);
+ }
+ free(buf);
+ if(!q) {
+ log_err("failed to deserialize newq");
+ return;
+ }
+ if(!setup_qinfo_edns(w, q, &qinfo, &edns)) {
+ add_bg_result(w, q, NULL, UB_SYNTAX, NULL);
+ return;
+ }
+ qid = 0;
+ qflags = BIT_RD;
+ /* see if there is a fixed answer */
+ ldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
+ ldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
+ if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns,
+ w->back->udp_buff, w->env->scratch)) {
+ regional_free_all(w->env->scratch);
+ q->msg_security = sec_status_insecure;
+ add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL);
+ free(qinfo.qname);
+ return;
+ }
+ q->w = w;
+ /* process new query */
+ if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
+ w->back->udp_buff, qid, libworker_bg_done_cb, q)) {
+ add_bg_result(w, q, NULL, UB_NOMEM, NULL);
+ }
+ free(qinfo.qname);
+}
+
+void libworker_alloc_cleanup(void* arg)
+{
+ struct libworker* w = (struct libworker*)arg;
+ slabhash_clear(&w->env->rrset_cache->table);
+ slabhash_clear(w->env->msg_cache);
+}
+
+/** compare outbound entry qstates */
+static int
+outbound_entry_compare(void* a, void* b)
+{
+ struct outbound_entry* e1 = (struct outbound_entry*)a;
+ struct outbound_entry* e2 = (struct outbound_entry*)b;
+ if(e1->qstate == e2->qstate)
+ return 1;
+ return 0;
+}
+
+struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
+ uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
+ int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen, struct module_qstate* q)
+{
+ struct libworker* w = (struct libworker*)q->env->worker;
+ struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
+ q->region, sizeof(*e));
+ if(!e)
+ return NULL;
+ e->qstate = q;
+ e->qsent = outnet_serviced_query(w->back, qname,
+ qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
+ q->env->cfg->tcp_upstream, q->env->cfg->ssl_upstream, addr,
+ addrlen, zone, zonelen, libworker_handle_service_reply, e,
+ w->back->udp_buff, &outbound_entry_compare);
+ if(!e->qsent) {
+ return NULL;
+ }
+ return e;
+}
+
+int
+libworker_handle_reply(struct comm_point* c, void* arg, int error,
+ struct comm_reply* reply_info)
+{
+ struct module_qstate* q = (struct module_qstate*)arg;
+ struct libworker* lw = (struct libworker*)q->env->worker;
+ struct outbound_entry e;
+ e.qstate = q;
+ e.qsent = NULL;
+
+ if(error != 0) {
+ mesh_report_reply(lw->env->mesh, &e, reply_info, error);
+ return 0;
+ }
+ /* sanity check. */
+ if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer))
+ || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) !=
+ LDNS_PACKET_QUERY
+ || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
+ /* error becomes timeout for the module as if this reply
+ * never arrived. */
+ mesh_report_reply(lw->env->mesh, &e, reply_info,
+ NETEVENT_TIMEOUT);
+ return 0;
+ }
+ mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR);
+ return 0;
+}
+
+int
+libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
+ struct comm_reply* reply_info)
+{
+ struct outbound_entry* e = (struct outbound_entry*)arg;
+ struct libworker* lw = (struct libworker*)e->qstate->env->worker;
+
+ if(error != 0) {
+ mesh_report_reply(lw->env->mesh, e, reply_info, error);
+ return 0;
+ }
+ /* sanity check. */
+ if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer))
+ || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) !=
+ LDNS_PACKET_QUERY
+ || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
+ /* error becomes timeout for the module as if this reply
+ * never arrived. */
+ mesh_report_reply(lw->env->mesh, e, reply_info,
+ NETEVENT_TIMEOUT);
+ return 0;
+ }
+ mesh_report_reply(lw->env->mesh, e, reply_info, NETEVENT_NOERROR);
+ return 0;
+}
+
+/* --- fake callbacks for fptr_wlist to work --- */
+void worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube),
+ uint8_t* ATTR_UNUSED(buffer), size_t ATTR_UNUSED(len),
+ int ATTR_UNUSED(error), void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+int worker_handle_request(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(repinfo))
+{
+ log_assert(0);
+ return 0;
+}
+
+int worker_handle_reply(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ log_assert(0);
+ return 0;
+}
+
+int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ log_assert(0);
+ return 0;
+}
+
+int remote_accept_callback(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(repinfo))
+{
+ log_assert(0);
+ return 0;
+}
+
+int remote_control_callback(struct comm_point* ATTR_UNUSED(c),
+ void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
+ struct comm_reply* ATTR_UNUSED(repinfo))
+{
+ log_assert(0);
+ return 0;
+}
+
+void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname),
+ size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
+ uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
+ int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
+ struct sockaddr_storage* ATTR_UNUSED(addr),
+ socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
+{
+ log_assert(0);
+ return 0;
+}
+
+void
+worker_alloc_cleanup(void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+void worker_stat_timer_cb(void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+void worker_probe_timer_cb(void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+void worker_start_accept(void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+void worker_stop_accept(void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+int order_lock_cmp(const void* ATTR_UNUSED(e1), const void* ATTR_UNUSED(e2))
+{
+ log_assert(0);
+ return 0;
+}
+
+int
+codeline_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
+{
+ log_assert(0);
+ return 0;
+}
+
+int replay_var_compare(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
+{
+ log_assert(0);
+ return 0;
+}
+
+void remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+#ifdef UB_ON_WINDOWS
+void
+worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void*
+ ATTR_UNUSED(arg)) {
+ log_assert(0);
+}
+
+void
+wsvc_cron_cb(void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+#endif /* UB_ON_WINDOWS */
diff --git a/contrib/unbound/libunbound/libworker.h b/contrib/unbound/libunbound/libworker.h
new file mode 100644
index 0000000..c3896fc
--- /dev/null
+++ b/contrib/unbound/libunbound/libworker.h
@@ -0,0 +1,170 @@
+/*
+ * libunbound/worker.h - worker thread or process that resolves
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+ */
+
+/**
+ * \file
+ *
+ * This file contains the worker process or thread that performs
+ * the DNS resolving and validation. The worker is called by a procedure
+ * and if in the background continues until exit, if in the foreground
+ * returns from the procedure when done.
+ */
+#ifndef LIBUNBOUND_WORKER_H
+#define LIBUNBOUND_WORKER_H
+#include "util/data/packed_rrset.h"
+struct ub_ctx;
+struct ub_result;
+struct module_env;
+struct comm_base;
+struct outside_network;
+struct ub_randstate;
+struct ctx_query;
+struct outbound_entry;
+struct module_qstate;
+struct comm_point;
+struct comm_reply;
+struct regional;
+struct tube;
+
+/**
+ * The library-worker status structure
+ * Internal to the worker.
+ */
+struct libworker {
+ /** every worker has a unique thread_num. (first in struct) */
+ int thread_num;
+ /** context we are operating under */
+ struct ub_ctx* ctx;
+
+ /** is this the bg worker? */
+ int is_bg;
+ /** is this a bg worker that is threaded (not forked)? */
+ int is_bg_thread;
+
+ /** copy of the module environment with worker local entries. */
+ struct module_env* env;
+ /** the event base this worker works with */
+ struct comm_base* base;
+ /** the backside outside network interface to the auth servers */
+ struct outside_network* back;
+ /** random() table for this worker. */
+ struct ub_randstate* rndstate;
+ /** sslcontext for SSL wrapped DNS over TCP queries */
+ void* sslctx;
+};
+
+/**
+ * Create a background worker
+ * @param ctx: is updated with pid/tid of the background worker.
+ * a new allocation cache is obtained from ctx. It contains the
+ * threadnumber and unique id for further (shared) cache insertions.
+ * @return 0 if OK, else error.
+ * Further communication is done via the pipes in ctx.
+ */
+int libworker_bg(struct ub_ctx* ctx);
+
+/**
+ * Create a foreground worker.
+ * This worker will join the threadpool of resolver threads.
+ * It exits when the query answer has been obtained (or error).
+ * This routine blocks until the worker is finished.
+ * @param ctx: new allocation cache obtained and returned to it.
+ * @param q: query (result is stored in here).
+ * @return 0 if finished OK, else error.
+ */
+int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q);
+
+/** cleanup the cache to remove all rrset IDs from it, arg is libworker */
+void libworker_alloc_cleanup(void* arg);
+
+/**
+ * Worker service routine to send serviced queries to authoritative servers.
+ * @param qname: query name. (host order)
+ * @param qnamelen: length in bytes of qname, including trailing 0.
+ * @param qtype: query type. (host order)
+ * @param qclass: query class. (host order)
+ * @param flags: host order flags word, with opcode and CD bit.
+ * @param dnssec: if set, EDNS record will have DO bit set.
+ * @param want_dnssec: signatures needed.
+ * @param addr: where to.
+ * @param addrlen: length of addr.
+ * @param zone: delegation point name.
+ * @param zonelen: length of zone name wireformat dname.
+ * @param q: wich query state to reactivate upon return.
+ * @return: false on failure (memory or socket related). no query was
+ * sent.
+ */
+struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
+ uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
+ int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen, struct module_qstate* q);
+
+/** process incoming replies from the network */
+int libworker_handle_reply(struct comm_point* c, void* arg, int error,
+ struct comm_reply* reply_info);
+
+/** process incoming serviced query replies from the network */
+int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
+ struct comm_reply* reply_info);
+
+/** handle control command coming into server */
+void libworker_handle_control_cmd(struct tube* tube, uint8_t* msg, size_t len,
+ int err, void* arg);
+
+/** handle opportunity to write result back */
+void libworker_handle_result_write(struct tube* tube, uint8_t* msg, size_t len,
+ int err, void* arg);
+
+/** mesh callback with fg results */
+void libworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf,
+ enum sec_status s, char* why_bogus);
+
+/** mesh callback with bg results */
+void libworker_bg_done_cb(void* arg, int rcode, ldns_buffer* buf,
+ enum sec_status s, char* why_bogus);
+
+/**
+ * fill result from parsed message, on error fills servfail
+ * @param res: is clear at start, filled in at end.
+ * @param buf: contains DNS message.
+ * @param temp: temporary buffer for parse.
+ * @param msg_security: security status of the DNS message.
+ * On error, the res may contain a different status
+ * (out of memory is not secure, not bogus).
+ */
+void libworker_enter_result(struct ub_result* res, ldns_buffer* buf,
+ struct regional* temp, enum sec_status msg_security);
+
+#endif /* LIBUNBOUND_WORKER_H */
diff --git a/contrib/unbound/libunbound/python/LICENSE b/contrib/unbound/libunbound/python/LICENSE
new file mode 100644
index 0000000..7b769d0
--- /dev/null
+++ b/contrib/unbound/libunbound/python/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+ * Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the organization nor the names of its
+ contributors may be used to endorse or promote products derived from this
+ software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
diff --git a/contrib/unbound/libunbound/python/Makefile b/contrib/unbound/libunbound/python/Makefile
new file mode 100644
index 0000000..86ba177
--- /dev/null
+++ b/contrib/unbound/libunbound/python/Makefile
@@ -0,0 +1,75 @@
+#
+# Makefile: compilation of pyUnbound and documentation, testing
+#
+# Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+# Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+#
+# This software is open source.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+# * Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# * Neither the name of the organization nor the names of its
+# contributors may be used to endorse or promote products derived from this
+# software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+
+help:
+ @echo "Please use \`make <target>' where <target> is one of"
+ @echo " testenv to make test environment and run bash "
+ @echo " usefull in case you don't want to install unbound but want to test examples"
+ @echo " doc to make documentation"
+ @echo " clean clean all"
+
+.PHONY: testenv clean doc swig
+
+#_unbound.so: ../../Makefile
+ #$(MAKE) -C ../..
+
+#../../.libs/libunbound.so.0: ../../Makefile
+ #$(MAKE) -C ../..
+
+#../../ldns-src/lib/libldns.so: ../../ldns-src/Makefile
+ #$(MAKE) -C ../../ldns-src
+
+clean:
+ rm -rdf examples/unbound
+ rm -f _unbound.so libunbound_wrap.o
+ $(MAKE) -C ../.. clean
+
+testenv: ../../.libs/libunbound.so.2 ../../ldns-src/lib/libldns.so ../../.libs/_unbound.so
+ rm -rdf examples/unbound
+ cd examples && mkdir unbound && ln -s ../../unbound.py unbound/__init__.py && ln -s ../../_unbound.so unbound/_unbound.so && ln -s ../../../../.libs/libunbound.so.2 unbound/libunbound.so.2 && ln -s ../../../../ldns-src/lib/libldns.so.1 unbound/libldns.so.1 && ls -la
+ cd examples && if test -f ../../../.libs/_unbound.so; then cp ../../../.libs/_unbound.so . ; fi
+ @echo "Run a script by typing ./script_name.py"
+ cd examples && LD_LIBRARY_PATH=unbound bash
+ rm -rdf examples/unbound examples/_unbound.so
+
+doc: ../../.libs/libunbound.so.0 _unbound.so
+ $(MAKE) -C docs html
+
+#for development only
+swig: libunbound.i
+ swig -python -o libunbound_wrap.c -I../.. libunbound.i
+ gcc -c libunbound_wrap.c -O9 -fPIC -I../.. -I/usr/include/python2.5 -I. -o libunbound_wrap.o
+ gcc -shared libunbound_wrap.o -L../../.libs -lunbound -o _unbound.so
+
diff --git a/contrib/unbound/libunbound/python/doc/_static/readme b/contrib/unbound/libunbound/python/doc/_static/readme
new file mode 100644
index 0000000..db676ae
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/_static/readme
@@ -0,0 +1 @@
+this directory exists to pacify sphinx-build.
diff --git a/contrib/unbound/libunbound/python/doc/conf.py b/contrib/unbound/libunbound/python/doc/conf.py
new file mode 100644
index 0000000..97fca21
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/conf.py
@@ -0,0 +1,181 @@
+# -*- coding: utf-8 -*-
+#
+# Unbound documentation build configuration file
+#
+# This file is execfile()d with the current directory set to its containing dir.
+#
+# The contents of this file are pickled, so don't put values in the namespace
+# that aren't pickleable (module imports are okay, they're removed automatically).
+#
+# All configuration values have a default value; values that are commented out
+# serve to show the default value.
+
+import sys, os
+
+# If your extensions are in another directory, add it here. If the directory
+# is relative to the documentation root, use os.path.abspath to make it
+# absolute, like shown here.
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'../')))
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'../../../')))
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__),'../../../.libs/')))
+#print sys.path
+
+# General configuration
+# ---------------------
+
+# Add any Sphinx extension module names here, as strings. They can be extensions
+# coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
+extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest']
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# The suffix of source filenames.
+source_suffix = '.rst'
+
+# The master toctree document.
+master_doc = 'index'
+
+# General substitutions.
+project = 'pyUnbound'
+copyright = '2009, Zdenek Vasicek, Marek Vavrusa'
+
+# The default replacements for |version| and |release|, also used in various
+# other places throughout the built documents.
+#
+# The short X.Y version.
+version = '1.0'
+# The full version, including alpha/beta/rc tags.
+release = '1.0.0'
+
+# There are two options for replacing |today|: either, you set today to some
+# non-false value, then it is used:
+#today = ''
+# Else, today_fmt is used as the format for a strftime call.
+today_fmt = '%B %d, %Y'
+
+# List of documents that shouldn't be included in the build.
+#unused_docs = []
+
+# List of directories, relative to source directories, that shouldn't be searched
+# for source files.
+#exclude_dirs = []
+
+# The reST default role (used for this markup: `text`) to use for all documents.
+#default_role = None
+
+# If true, '()' will be appended to :func: etc. cross-reference text.
+#add_function_parentheses = True
+
+# If true, the current module name will be prepended to all description
+# unit titles (such as .. function::).
+#add_module_names = True
+
+# If true, sectionauthor and moduleauthor directives will be shown in the
+# output. They are ignored by default.
+#show_authors = False
+
+# The name of the Pygments (syntax highlighting) style to use.
+pygments_style = 'sphinx'
+
+
+# Options for HTML output
+# -----------------------
+
+# The style sheet to use for HTML and HTML Help pages. A file of that name
+# must exist either in Sphinx' static/ path, or in one of the custom paths
+# given in html_static_path.
+html_style = 'default.css'
+
+# The name for this set of Sphinx documents. If None, it defaults to
+# "<project> v<release> documentation".
+#html_title = None
+
+# A shorter title for the navigation bar. Default is the same as html_title.
+#html_short_title = None
+
+# The name of an image file (within the static path) to place at the top of
+# the sidebar.
+#html_logo = None
+
+# The name of an image file (within the static path) to use as favicon of the
+# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
+# pixels large.
+#html_favicon = None
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
+
+# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
+# using the given strftime format.
+html_last_updated_fmt = '%b %d, %Y'
+
+# If true, SmartyPants will be used to convert quotes and dashes to
+# typographically correct entities.
+#html_use_smartypants = True
+
+# Custom sidebar templates, maps document names to template names.
+#html_sidebars = {}
+
+# Additional templates that should be rendered to pages, maps page names to
+# template names.
+#html_additional_pages = {}
+
+# If false, no module index is generated.
+html_use_modindex = False
+
+# If false, no index is generated.
+#html_use_index = True
+
+# If true, the index is split into individual pages for each letter.
+#html_split_index = False
+
+# If true, the reST sources are included in the HTML build as _sources/<name>.
+html_copy_source = False
+
+# If true, an OpenSearch description file will be output, and all pages will
+# contain a <link> tag referring to it. The value of this option must be the
+# base URL from which the finished HTML is served.
+#html_use_opensearch = ''
+
+# If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml").
+#html_file_suffix = ''
+
+# Output file base name for HTML help builder.
+htmlhelp_basename = 'Unbounddoc'
+
+
+# Options for LaTeX output
+# ------------------------
+
+# The paper size ('letter' or 'a4').
+#latex_paper_size = 'letter'
+
+# The font size ('10pt', '11pt' or '12pt').
+#latex_font_size = '10pt'
+
+# Grouping the document tree into LaTeX files. List of tuples
+# (source start file, target name, title, author, document class [howto/manual]).
+latex_documents = [
+ ('index', 'Unbound.tex', 'Unbound Documentation',
+ 'Zdenek Vasicek, Marek Vavrusa', 'manual'),
+]
+
+# The name of an image file (relative to this directory) to place at the top of
+# the title page.
+#latex_logo = None
+
+# For "manual" documents, if this is true, then toplevel headings are parts,
+# not chapters.
+#latex_use_parts = False
+
+# Additional stuff for the LaTeX preamble.
+#latex_preamble = ''
+
+# Documents to append as an appendix to all manuals.
+#latex_appendices = []
+
+# If false, no module index is generated.
+#latex_use_modindex = True
diff --git a/contrib/unbound/libunbound/python/doc/examples/example1a.rst b/contrib/unbound/libunbound/python/doc/examples/example1a.rst
new file mode 100644
index 0000000..3c81547
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example1a.rst
@@ -0,0 +1,26 @@
+.. _example_resolve_name:
+
+==============================
+Resolve a name
+==============================
+
+This basic example shows how to create a context and resolve a host address (DNS record of A type).
+
+::
+
+ #!/usr/bin/python
+ import unbound
+
+ ctx = unbound.ub_ctx()
+ ctx.resolvconf("/etc/resolv.conf")
+
+ status, result = ctx.resolve("www.google.com")
+ if status == 0 and result.havedata:
+ print "Result.data:", result.data.address_list
+ elif status != 0:
+ print "Resolve error:", unbound.ub_strerror(status)
+
+In contrast with C API, the source code is more compact while the performance of C implementation is preserved.
+The main advantage is that you need not take care about the deallocation and allocation of context and result structures; pyUnbound module do it automatically for you.
+
+If only domain name is given, the :meth:`unbound.ub_ctx.resolve` looks for A records in IN class.
diff --git a/contrib/unbound/libunbound/python/doc/examples/example1b.rst b/contrib/unbound/libunbound/python/doc/examples/example1b.rst
new file mode 100644
index 0000000..ea1e6f5
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example1b.rst
@@ -0,0 +1,33 @@
+.. _example_reverse_lookup:
+
+==============================
+Reverse DNS lookup
+==============================
+
+Reverse DNS lookup involves determining the hostname associated with a given IP address.
+This example shows how reverse lookup can be done using unbound module.
+
+For the reverse DNS records, the special domain in-addr.arpa is reserved.
+For example, a host name for the IP address 74.125.43.147 can be obtained by issuing a DNS query for the PTR record for address 147.43.125.74.in-addr.arpa.
+
+::
+
+ #!/usr/bin/python
+ import unbound
+
+ ctx = unbound.ub_ctx()
+ ctx.resolvconf("/etc/resolv.conf")
+
+ status, result = ctx.resolve(unbound.reverse("74.125.43.147") + ".in-addr.arpa.", unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN)
+ if status == 0 and result.havedata:
+ print "Result.data:", result.data.domain_list
+ elif status != 0:
+ print "Resolve error:", unbound.ub_strerror(status)
+
+In order to simplify the python code, unbound module contains function which reverses the hostname components.
+This function is defined as follows::
+
+ def reverse(domain):
+ return '.'.join([a for a in domain.split(".")][::-1])
+
+
diff --git a/contrib/unbound/libunbound/python/doc/examples/example2.rst b/contrib/unbound/libunbound/python/doc/examples/example2.rst
new file mode 100644
index 0000000..c009ec1
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example2.rst
@@ -0,0 +1,41 @@
+.. _example_setup_ctx:
+
+==============================
+Lookup from threads
+==============================
+
+This example shows how to use unbound module from a threaded program.
+In this example, three lookup threads are created which work in background.
+Each thread resolves different DNS record.
+
+::
+
+ #!/usr/bin/python
+ from unbound import ub_ctx, RR_TYPE_A, RR_CLASS_IN
+ from threading import Thread
+
+ ctx = ub_ctx()
+ ctx.resolvconf("/etc/resolv.conf")
+
+ class LookupThread(Thread):
+ def __init__(self,ctx, name):
+ Thread.__init__(self)
+ self.ctx = ctx
+ self.name = name
+
+ def run(self):
+ print "Thread lookup started:",self.name
+ status, result = self.ctx.resolve(self.name, RR_TYPE_A, RR_CLASS_IN)
+ if status == 0 and result.havedata:
+ print " Result:",self.name,":", result.data.address_list
+
+ threads = []
+ for name in ["www.fit.vutbr.cz","www.vutbr.cz","www.google.com"]:
+ thread = LookupThread(ctx, name)
+ thread.start()
+ threads.append(thread)
+
+ for thread in threads:
+ thread.join()
+
+
diff --git a/contrib/unbound/libunbound/python/doc/examples/example3.rst b/contrib/unbound/libunbound/python/doc/examples/example3.rst
new file mode 100644
index 0000000..9136033
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example3.rst
@@ -0,0 +1,36 @@
+.. _example_asynch:
+
+==============================
+Asynchronous lookup
+==============================
+
+This example performs the name lookup in the background.
+The main program keeps running while the name is resolved.
+
+::
+
+ #!/usr/bin/python
+ import time
+ import unbound
+
+ ctx = unbound.ub_ctx()
+ ctx.resolvconf("/etc/resolv.conf")
+
+ def call_back(my_data,status,result):
+ print "Call_back:", my_data
+ if status == 0 and result.havedata:
+ print "Result:", result.data.address_list
+ my_data['done_flag'] = True
+
+
+ my_data = {'done_flag':False,'arbitrary':"object"}
+ status, async_id = ctx.resolve_async("www.seznam.cz", my_data, call_back, unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
+
+ while (status == 0) and (not my_data['done_flag']):
+ status = ctx.process()
+ time.sleep(0.1)
+
+ if (status != 0):
+ print "Resolve error:", unbound.ub_strerror(status)
+
+The :meth:`unbound.ub_ctx.resolve_async` method is able to pass on any Python object. In this example, we used a dictionary object `my_data`.
diff --git a/contrib/unbound/libunbound/python/doc/examples/example4.rst b/contrib/unbound/libunbound/python/doc/examples/example4.rst
new file mode 100644
index 0000000..996ef4e
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example4.rst
@@ -0,0 +1,34 @@
+.. _example_examine:
+
+==============================
+DNSSEC validator
+==============================
+
+This example program performs DNSSEC validation of a DNS lookup.
+
+::
+
+ #!/usr/bin/python
+ import os
+ from unbound import ub_ctx,RR_TYPE_A,RR_CLASS_IN
+
+ ctx = ub_ctx()
+ ctx.resolvconf("/etc/resolv.conf")
+ if (os.path.isfile("keys")):
+ ctx.add_ta_file("keys") #read public keys for DNSSEC verification
+
+ status, result = ctx.resolve("www.nic.cz", RR_TYPE_A, RR_CLASS_IN)
+ if status == 0 and result.havedata:
+
+ print "Result:", result.data.address_list
+
+ if result.secure:
+ print "Result is secure"
+ elif result.bogus:
+ print "Result is bogus"
+ else:
+ print "Result is insecure"
+
+More detailed informations can be seen in libUnbound DNSSEC tutorial `here`_.
+
+.. _here: http://www.unbound.net/documentation/libunbound-tutorial-6.html
diff --git a/contrib/unbound/libunbound/python/doc/examples/example5.rst b/contrib/unbound/libunbound/python/doc/examples/example5.rst
new file mode 100644
index 0000000..0a31d9a
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example5.rst
@@ -0,0 +1,29 @@
+.. _example_resolver_only:
+
+==============================
+Resolver only
+==============================
+
+This example program shows how to perform DNS resolution only.
+Unbound contains two basic modules: resolver and validator.
+In case, the validator is not necessary, the validator module can be turned off using "module-config" option.
+This option contains a list of module names separated by the space char. This list determined which modules should be employed and in what order.
+
+::
+
+ #!/usr/bin/python
+ import os
+ from unbound import ub_ctx,RR_TYPE_A,RR_CLASS_IN
+
+ ctx = ub_ctx()
+ ctx.set_option("module-config:","iterator")
+ ctx.resolvconf("/etc/resolv.conf")
+
+ status, result = ctx.resolve("www.google.com", RR_TYPE_A, RR_CLASS_IN)
+ if status == 0 and result.havedata:
+
+ print "Result:", result.data.address_list
+
+.. note::
+ The :meth:`unbound.ub_ctx.set_option` method must be used before the first resolution (i.e. before :meth:`unbound.ub_ctx.resolve` or :meth:`unbound.ub_ctx.resolve_async` call).
+
diff --git a/contrib/unbound/libunbound/python/doc/examples/example6-1.py b/contrib/unbound/libunbound/python/doc/examples/example6-1.py
new file mode 100644
index 0000000..0f40544
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example6-1.py
@@ -0,0 +1,27 @@
+#!/usr/bin/python
+from unbound import ub_ctx,ub_strerror,RR_TYPE_A,RR_CLASS_IN
+
+ctx = ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+status, result = ctx.resolve("test.record.xxx", RR_TYPE_A, RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:", result.data.address_list
+else:
+ print "No record found"
+
+#define new local zone
+status = ctx.zone_add("xxx.","static")
+if (status != 0): print "Error zone_add:",status, ub_strerror(status)
+
+#add RR to the zone
+status = ctx.data_add("test.record.xxx. IN A 1.2.3.4")
+if (status != 0): print "Error data_add:",status, ub_strerror(status)
+
+#lookup for an A record
+status, result = ctx.resolve("test.record.xxx", RR_TYPE_A, RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:", result.data.as_address_list()
+else:
+ print "No record found"
+
diff --git a/contrib/unbound/libunbound/python/doc/examples/example6.rst b/contrib/unbound/libunbound/python/doc/examples/example6.rst
new file mode 100644
index 0000000..478e139
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example6.rst
@@ -0,0 +1,11 @@
+.. _example_localzone:
+
+==============================
+Local zone manipulation
+==============================
+
+This example program shows how to define local zone containing custom DNS records.
+
+.. literalinclude:: example6-1.py
+ :language: python
+
diff --git a/contrib/unbound/libunbound/python/doc/examples/example7-1.py b/contrib/unbound/libunbound/python/doc/examples/example7-1.py
new file mode 100644
index 0000000..802bd1c
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example7-1.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+# vim:fileencoding=utf-8
+#
+# IDN (Internationalized Domain Name) lookup support
+#
+import unbound
+
+ctx = unbound.ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+status, result = ctx.resolve(u"www.háčkyčárky.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.address_list:
+ print " address:%s" % k
+
diff --git a/contrib/unbound/libunbound/python/doc/examples/example7-2.py b/contrib/unbound/libunbound/python/doc/examples/example7-2.py
new file mode 100644
index 0000000..5a41f8d
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example7-2.py
@@ -0,0 +1,16 @@
+#!/usr/bin/python
+# vim:fileencoding=utf-8
+#
+# IDN (Internationalized Domain Name) lookup support (lookup for MX)
+#
+import unbound
+
+ctx = unbound.ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+status, result = ctx.resolve(u"háčkyčárky.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.mx_list_idn:
+ print " priority:%d address:%s" % k
diff --git a/contrib/unbound/libunbound/python/doc/examples/example7.rst b/contrib/unbound/libunbound/python/doc/examples/example7.rst
new file mode 100644
index 0000000..d405021
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example7.rst
@@ -0,0 +1,18 @@
+.. _example_idna:
+
+=================================================
+Internationalized domain name support
+=================================================
+
+Unlike the libUnbound, pyUnbound is able to handle IDN queries.
+
+.. literalinclude:: example7-1.py
+ :language: python
+
+If we use unicode string in :meth:`unbound.ub_ctx.resolve` method, the IDN DNAME conversion (if it is necessary) is performed on background.
+
+.. literalinclude:: example7-2.py
+ :language: python
+
+The :class:`unbound.ub_data` class contains attributes suffix which converts the dname to UTF string. These attributes have the '_idn' suffix.
+Apart from this aproach, two conversion functions exist (:func:`unbound.idn2dname` and :func:`unbound.dname2idn`).
diff --git a/contrib/unbound/libunbound/python/doc/examples/example8-1.py b/contrib/unbound/libunbound/python/doc/examples/example8-1.py
new file mode 100644
index 0000000..7906016
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example8-1.py
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+# vim:fileencoding=utf-8
+#
+# Lookup for MX and NS records
+#
+import unbound
+
+ctx = unbound.ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.mx_list:
+ print " priority:%d address:%s" % k
+
+status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.address_list:
+ print " address:%s" % k
+
+status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_NS, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.domain_list:
+ print " host: %s" % k
+
diff --git a/contrib/unbound/libunbound/python/doc/examples/example8.rst b/contrib/unbound/libunbound/python/doc/examples/example8.rst
new file mode 100644
index 0000000..8cdfcdc
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/example8.rst
@@ -0,0 +1,28 @@
+.. _example_mxlookup:
+
+=================================================
+Lookup for MX and NS records
+=================================================
+
+The pyUnbound extension provides functions which are able to encode RAW RDATA produces by unbound resolver (see :class:`unbound.ub_data`).
+
+.. literalinclude:: example8-1.py
+ :language: python
+
+Previous example produces following output::
+
+ Result:
+ raw data: 00 0F 05 6D 61 69 6C 34 03 6E 69 63 02 63 7A 00;00 14 02 6D 78 05 63 7A 6E 69 63 03 6F 72 67 00;00 0A 04 6D 61 69 6C 03 6E 69 63 02 63 7A 00
+ priority:15 address: mail4.nic.cz.
+ priority:20 address: mx.cznic.org.
+ priority:10 address: mail.nic.cz.
+
+ Result:
+ raw data: D9 1F CD 32
+ address: 217.31.205.50
+
+ Result:
+ raw data: 01 61 02 6E 73 03 6E 69 63 02 63 7A 00;01 65 02 6E 73 03 6E 69 63 02 63 7A 00;01 63 02 6E 73 03 6E 69 63 02 63 7A 00
+ host: a.ns.nic.cz.
+ host: e.ns.nic.cz.
+ host: c.ns.nic.cz.
diff --git a/contrib/unbound/libunbound/python/doc/examples/index.rst b/contrib/unbound/libunbound/python/doc/examples/index.rst
new file mode 100644
index 0000000..c2c9cf4
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/examples/index.rst
@@ -0,0 +1,14 @@
+Examples
+==============================
+
+Here you can find several examples which utilizes the unbound library in Python environment.
+Unbound is a caching validator and resolver and can be linked into an application, as a library where can answer DNS queries for the application.
+This set of examples shows how to use the functions from Python environment.
+
+`Tutorials`
+
+.. toctree::
+ :maxdepth: 1
+ :glob:
+
+ example*
diff --git a/contrib/unbound/libunbound/python/doc/index.rst b/contrib/unbound/libunbound/python/doc/index.rst
new file mode 100644
index 0000000..b42e052
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/index.rst
@@ -0,0 +1,27 @@
+PyUnbound documentation
+=======================================
+
+This project contains an Unbound wrapper providing the thinnest layer over the library possible.
+Everything you can do from the libUnbound C API, you can do from Python, even more.
+
+Contents
+----------
+.. toctree::
+ :maxdepth: 2
+
+ intro.rst
+ install.rst
+ examples/index.rst
+ modules/unbound
+
+Module Documentation
+-----------------------
+
+* Module :mod:`unbound`
+
+Indices and tables
+-------------------
+
+* :ref:`genindex`
+* :ref:`search`
+
diff --git a/contrib/unbound/libunbound/python/doc/install.rst b/contrib/unbound/libunbound/python/doc/install.rst
new file mode 100644
index 0000000..f638ed1
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/install.rst
@@ -0,0 +1,31 @@
+Installation
+===================================
+
+**Prerequisites**
+
+Python 2.4 or higher, SWIG 1.3 or higher, GNU make
+
+**Compiling**
+
+After downloading, you can compile the pyUnbound library by doing::
+
+ > tar -xzf unbound-x.x.x-py.tar.gz
+ > cd unbound-x.x.x
+ > ./configure --with-pyunbound
+ > make
+
+You may want to --with-pythonmodule as well if you want to use python as
+a module in the resolver.
+
+You need GNU make to compile sources; SWIG and Python devel libraries to compile extension module.
+
+
+**Testing**
+
+If the compilation is successfull, you can test the python LDNS extension module by::
+
+ > cd contrib/python
+ > make testenv
+ > ./dns-lookup.py
+
+You may want to make install in the main directory since make testenv is for debugging. In contrib/examples you can find simple applications written in Python using the Unbound extension.
diff --git a/contrib/unbound/libunbound/python/doc/intro.rst b/contrib/unbound/libunbound/python/doc/intro.rst
new file mode 100644
index 0000000..f751f54
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/intro.rst
@@ -0,0 +1,39 @@
+Introduction
+===================================
+
+**Unbound**
+
+ `Unbound`_ is an implementation of a DNS resolver, that performs caching and DNSSEC validation.
+ Together with unbound, the libunbound library is provided.
+ This library can be used to convert hostnames to ip addresses, and back, as well as obtain other information.
+ Since the resolver allows to specify the class and type of a query (A record, NS, MX, ...), this library offers powerful resolving tool.
+ The library also performs public-key validation of results with DNSSEC.
+
+ .. _Unbound: http://www.unbound.net/documentation
+
+**pyUnbound**
+
+ The pyUnbound is an extension module for Python which provides an object-oriented interface to libunbound.
+ It is the first Python module which offers thread-safe caching resolver.
+
+ The interface was designed with the emphasis on the simplicity of use.
+ There are two main classes :class:`unbound.ub_ctx` (a validation and resolution context) and :class:`unbound.ub_result` which contains the validation and resolution results.
+ The objects are thread-safe, and a context can be used in non-threaded as well as threaded environment.
+ Resolution can be performed blocking and non-blocking (i.e. asynchronous).
+ The asynchronous method returns from the call immediately, so that processing can go on, while the results become available later.
+
+**Features**
+ * customizable caching validation resolver for synchronous and asynchronous lookups
+ * easy to use object interface
+ * easy to integrate extension module
+ * designed for thread environment (i.e. thread-safe)
+ * allows define and customize of local zone and its RR's during the operation (i.e. without restart)
+ * includes encoding functions to simplify the results retrieval
+ * Internationalized domain name (`IDN`_) support
+
+ .. _IDN: http://en.wikipedia.org/wiki/Internationalized_domain_name
+
+**Application area**
+ * DNS-based applications performing DNS lookups; the caching resolver can reduce overhead
+ * Applications where the validation of DNS records is required
+ * Great solution for customizable and dynamic DNS-based white/blacklists (spam rejection, connection rejection, ...) using the dynamic local zone manipulation
diff --git a/contrib/unbound/libunbound/python/doc/modules/unbound.rst b/contrib/unbound/libunbound/python/doc/modules/unbound.rst
new file mode 100644
index 0000000..21f4a12
--- /dev/null
+++ b/contrib/unbound/libunbound/python/doc/modules/unbound.rst
@@ -0,0 +1,167 @@
+Unbound module documentation
+================================
+
+.. automodule:: unbound
+
+Class ub_ctx
+--------------
+.. autoclass:: ub_ctx
+ :members:
+ :undoc-members:
+
+ .. automethod:: __init__
+
+Class ub_result
+----------------------
+.. autoclass:: ub_result
+ :members:
+
+ .. attribute:: qname
+
+ The original question, name text string.
+
+ .. attribute:: qtype
+
+ The class asked for.
+
+ .. attribute:: canonname
+
+ Canonical name for the result (the final cname). May be empty if no canonical name exists.
+
+ .. attribute:: answer_packet
+
+ The DNS answer packet. Network formatted. Can contain DNSSEC types.
+
+ .. attribute:: havedata
+
+ If there is any data, this property is true. If false, there was no data (nxdomain may be true, rcode can be set).
+
+ .. attribute:: secure
+
+ True, if the result is validated securely.
+ False, if validation failed or domain queried has no security info.
+
+ It is possible to get a result with no data (havedata is false),
+ and secure is true. This means that the non-existance of the data
+ was cryptographically proven (with signatures).
+
+ .. attribute:: bogus
+
+ If the result was not secure (secure==0), and this result is due to a security failure, bogus is true.
+ This means the data has been actively tampered with, signatures
+ failed, expected signatures were not present, timestamps on
+ signatures were out of date and so on.
+
+ If secure==0 and bogus==0, this can happen if the data is not secure
+ because security is disabled for that domain name.
+ This means the data is from a domain where data is not signed.
+
+ .. attribute:: nxdomain
+
+ If there was no data, and the domain did not exist, this is true.
+ If it is false, and there was no data, then the domain name is purported to exist, but the requested data type is not available.
+
+ .. attribute:: rcode
+
+ DNS RCODE for the result. May contain additional error code if there was no data due to an error.
+ 0 (RCODE_NOERROR) if okay. See predefined `RCODE_` constants.
+
+ RCODE can be represented in display representation form (string) using :attr:`rcode_str` attribute.
+
+Class ub_data
+----------------------
+.. autoclass:: ub_data
+ :members:
+
+Functions
+----------------------
+.. autofunction:: reverse
+.. autofunction:: idn2dname
+.. autofunction:: dname2idn
+
+Predefined constants
+-----------------------
+
+**RCODE**
+ * RCODE_FORMERR = 1
+ * RCODE_NOERROR = 0
+ * RCODE_NOTAUTH = 9
+ * RCODE_NOTIMPL = 4
+ * RCODE_NOTZONE = 10
+ * RCODE_NXDOMAIN = 3
+ * RCODE_NXRRSET = 8
+ * RCODE_REFUSED = 5
+ * RCODE_SERVFAIL = 2
+ * RCODE_YXDOMAIN = 6
+ * RCODE_YXRRSET = 7
+
+**RR_CLASS**
+ * RR_CLASS_ANY = 255
+ * RR_CLASS_CH = 3
+ * RR_CLASS_HS = 4
+ * RR_CLASS_IN = 1
+ * RR_CLASS_NONE = 254
+
+**RR_TYPE**
+ * RR_TYPE_A = 1
+ * RR_TYPE_A6 = 38
+ * RR_TYPE_AAAA = 28
+ * RR_TYPE_AFSDB = 18
+ * RR_TYPE_ANY = 255
+ * RR_TYPE_APL = 42
+ * RR_TYPE_ATMA = 34
+ * RR_TYPE_AXFR = 252
+ * RR_TYPE_CERT = 37
+ * RR_TYPE_CNAME = 5
+ * RR_TYPE_DHCID = 49
+ * RR_TYPE_DLV = 32769
+ * RR_TYPE_DNAME = 39
+ * RR_TYPE_DNSKEY = 48
+ * RR_TYPE_DS = 43
+ * RR_TYPE_EID = 31
+ * RR_TYPE_GID = 102
+ * RR_TYPE_GPOS = 27
+ * RR_TYPE_HINFO = 13
+ * RR_TYPE_IPSECKEY = 45
+ * RR_TYPE_ISDN = 20
+ * RR_TYPE_IXFR = 251
+ * RR_TYPE_KEY = 25
+ * RR_TYPE_KX = 36
+ * RR_TYPE_LOC = 29
+ * RR_TYPE_MAILA = 254
+ * RR_TYPE_MAILB = 253
+ * RR_TYPE_MB = 7
+ * RR_TYPE_MD = 3
+ * RR_TYPE_MF = 4
+ * RR_TYPE_MG = 8
+ * RR_TYPE_MINFO = 14
+ * RR_TYPE_MR = 9
+ * RR_TYPE_MX = 15
+ * RR_TYPE_NAPTR = 35
+ * RR_TYPE_NIMLOC = 32
+ * RR_TYPE_NS = 2
+ * RR_TYPE_NSAP = 22
+ * RR_TYPE_NSAP_PTR = 23
+ * RR_TYPE_NSEC = 47
+ * RR_TYPE_NSEC3 = 50
+ * RR_TYPE_NSEC3PARAMS = 51
+ * RR_TYPE_NULL = 10
+ * RR_TYPE_NXT = 30
+ * RR_TYPE_OPT = 41
+ * RR_TYPE_PTR = 12
+ * RR_TYPE_PX = 26
+ * RR_TYPE_RP = 17
+ * RR_TYPE_RRSIG = 46
+ * RR_TYPE_RT = 21
+ * RR_TYPE_SIG = 24
+ * RR_TYPE_SINK = 40
+ * RR_TYPE_SOA = 6
+ * RR_TYPE_SRV = 33
+ * RR_TYPE_SSHFP = 44
+ * RR_TYPE_TSIG = 250
+ * RR_TYPE_TXT = 16
+ * RR_TYPE_UID = 101
+ * RR_TYPE_UINFO = 100
+ * RR_TYPE_UNSPEC = 103
+ * RR_TYPE_WKS = 11
+ * RR_TYPE_X25 = 19
diff --git a/contrib/unbound/libunbound/python/examples/async-lookup.py b/contrib/unbound/libunbound/python/examples/async-lookup.py
new file mode 100644
index 0000000..52a2d3c
--- /dev/null
+++ b/contrib/unbound/libunbound/python/examples/async-lookup.py
@@ -0,0 +1,56 @@
+#!/usr/bin/python
+'''
+ async-lookup.py : This example shows how to use asynchronous lookups
+
+ Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+
+ Copyright (c) 2008. All rights reserved.
+
+ This software is open source.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+'''
+import unbound
+import time
+
+ctx = unbound.ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+def call_back(my_data,status,result):
+ print "Call_back:", my_data
+ if status == 0 and result.havedata:
+ print "Result:", result.data.address_list
+ my_data['done_flag'] = True
+
+
+my_data = {'done_flag':False,'arbitrary':"object"}
+status, async_id = ctx.resolve_async("www.nic.cz", my_data, call_back, unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
+
+while (status == 0) and (not my_data['done_flag']):
+ status = ctx.process()
+ time.sleep(0.1)
+
+if (status != 0):
+ print "Resolve error:", unbound.ub_strerror(status)
diff --git a/contrib/unbound/libunbound/python/examples/dns-lookup.py b/contrib/unbound/libunbound/python/examples/dns-lookup.py
new file mode 100644
index 0000000..2821ed3
--- /dev/null
+++ b/contrib/unbound/libunbound/python/examples/dns-lookup.py
@@ -0,0 +1,44 @@
+#!/usr/bin/python
+'''
+ dns-lookup.py : This example shows how to resolve IP address
+
+ Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+
+ Copyright (c) 2008. All rights reserved.
+
+ This software is open source.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+'''
+import unbound
+
+ctx = unbound.ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+status, result = ctx.resolve("www.nic.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:", result.data.address_list
+elif status != 0:
+ print "Error:", unbound.ub_strerror(status)
diff --git a/contrib/unbound/libunbound/python/examples/dnssec-valid.py b/contrib/unbound/libunbound/python/examples/dnssec-valid.py
new file mode 100644
index 0000000..3e05ddd
--- /dev/null
+++ b/contrib/unbound/libunbound/python/examples/dnssec-valid.py
@@ -0,0 +1,59 @@
+#!/usr/bin/python
+'''
+ dnssec-valid.py: DNSSEC validation
+
+ Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+
+ Copyright (c) 2008. All rights reserved.
+
+ This software is open source.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+'''
+import os
+from unbound import ub_ctx,RR_TYPE_A,RR_CLASS_IN
+
+ctx = ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+fw = open("dnssec-valid.txt","wb")
+ctx.debugout(fw)
+ctx.debuglevel(2)
+
+if os.path.isfile("keys"):
+ ctx.add_ta_file("keys") #read public keys for DNSSEC verificatio
+
+status, result = ctx.resolve("www.nic.cz", RR_TYPE_A, RR_CLASS_IN)
+if status == 0 and result.havedata:
+
+ print "Result:", result.data.address_list
+
+ if result.secure:
+ print "Result is secure"
+ elif result.bogus:
+ print "Result is bogus"
+ else:
+ print "Result is insecure"
+
diff --git a/contrib/unbound/libunbound/python/examples/dnssec_test.py b/contrib/unbound/libunbound/python/examples/dnssec_test.py
new file mode 100644
index 0000000..138e19b
--- /dev/null
+++ b/contrib/unbound/libunbound/python/examples/dnssec_test.py
@@ -0,0 +1,35 @@
+#!/usr/bin/env python
+from unbound import ub_ctx, RR_TYPE_A, RR_TYPE_RRSIG, RR_TYPE_NSEC, RR_TYPE_NSEC3
+import ldns
+
+def dnssecParse(domain, rrType=RR_TYPE_A):
+ print "Resolving domain", domain
+ s, r = resolver.resolve(domain)
+ print "status: %s, secure: %s, rcode: %s, havedata: %s, answer_len; %s" % (s, r.secure, r.rcode_str, r.havedata, r.answer_len)
+
+ s, pkt = ldns.ldns_wire2pkt(r.packet)
+ if s != 0:
+ raise RuntimeError("Error parsing DNS packet")
+
+ rrsigs = pkt.rr_list_by_type(RR_TYPE_RRSIG, ldns.LDNS_SECTION_ANSWER)
+ print "RRSIGs from answer:", rrsigs
+
+ rrsigs = pkt.rr_list_by_type(RR_TYPE_RRSIG, ldns.LDNS_SECTION_AUTHORITY)
+ print "RRSIGs from authority:", rrsigs
+
+ nsecs = pkt.rr_list_by_type(RR_TYPE_NSEC, ldns.LDNS_SECTION_AUTHORITY)
+ print "NSECs:", nsecs
+
+ nsec3s = pkt.rr_list_by_type(RR_TYPE_NSEC3, ldns.LDNS_SECTION_AUTHORITY)
+ print "NSEC3s:", nsec3s
+
+ print "---"
+
+
+resolver = ub_ctx()
+resolver.add_ta(". IN DS 19036 8 2 49AAC11D7B6F6446702E54A1607371607A1A41855200FD2CE1CDDE32F24E8FB5")
+
+dnssecParse("nic.cz")
+dnssecParse("nonexistent-domain-blablabla.cz")
+dnssecParse("nonexistent-domain-blablabla.root.cz")
+
diff --git a/contrib/unbound/libunbound/python/examples/example8-1.py b/contrib/unbound/libunbound/python/examples/example8-1.py
new file mode 100644
index 0000000..6816da0
--- /dev/null
+++ b/contrib/unbound/libunbound/python/examples/example8-1.py
@@ -0,0 +1,61 @@
+#!/usr/bin/python
+# vim:fileencoding=utf-8
+'''
+ example8-1.py: Example shows how to lookup for MX and NS records
+
+ Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+
+ Copyright (c) 2008. All rights reserved.
+
+ This software is open source.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+'''
+import unbound
+
+ctx = unbound.ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.mx_list:
+ print " priority:%d address:%s" % k
+
+status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.address_list:
+ print " address:%s" % k
+
+status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_NS, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.domain_list:
+ print " host: %s" % k
+
diff --git a/contrib/unbound/libunbound/python/examples/idn-lookup.py b/contrib/unbound/libunbound/python/examples/idn-lookup.py
new file mode 100644
index 0000000..7cfdc9e
--- /dev/null
+++ b/contrib/unbound/libunbound/python/examples/idn-lookup.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python
+# vim:fileencoding=utf-8
+'''
+ idn-lookup.py: IDN (Internationalized Domain Name) lookup support
+
+ Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+
+ Copyright (c) 2008. All rights reserved.
+
+ This software is open source.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+'''
+import unbound
+import locale
+
+ctx = unbound.ub_ctx()
+ctx.set_option("module-config:","iterator") #We don't need validation
+ctx.resolvconf("/etc/resolv.conf")
+
+#The unicode IDN string is automatically converted (if necessary)
+status, result = ctx.resolve(u"www.háčkyčárky.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.address_list:
+ print " address:%s" % k
+
+status, result = ctx.resolve(u"háčkyčárky.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.mx_list_idn:
+ print " priority:%d address:%s" % k
+
+status, result = ctx.resolve(unbound.reverse('217.31.204.66')+'.in-addr.arpa', unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result.data:", result.data
+ for k in result.data.domain_list_idn:
+ print " dname:%s" % k
diff --git a/contrib/unbound/libunbound/python/examples/mx-lookup.py b/contrib/unbound/libunbound/python/examples/mx-lookup.py
new file mode 100644
index 0000000..cdcd1b1
--- /dev/null
+++ b/contrib/unbound/libunbound/python/examples/mx-lookup.py
@@ -0,0 +1,53 @@
+#!/usr/bin/python
+# vim:fileencoding=utf-8
+'''
+ mx-lookup.py: Lookup for MX records
+
+ Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+
+ Copyright (c) 2008. All rights reserved.
+
+ This software is open source.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+'''
+import unbound
+
+ctx = unbound.ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_MX, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.mx_list:
+ print " priority:%d address:%s" % k
+
+status, result = ctx.resolve("nic.cz", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.address_list:
+ print " address:%s" % k
diff --git a/contrib/unbound/libunbound/python/examples/ns-lookup.py b/contrib/unbound/libunbound/python/examples/ns-lookup.py
new file mode 100644
index 0000000..f9eafb2
--- /dev/null
+++ b/contrib/unbound/libunbound/python/examples/ns-lookup.py
@@ -0,0 +1,47 @@
+#!/usr/bin/python
+# vim:fileencoding=utf-8
+'''
+ ns-lookup.py: Example shows how to lookup for NS records
+
+ Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+
+ Copyright (c) 2008. All rights reserved.
+
+ This software is open source.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+'''
+import unbound
+
+ctx = unbound.ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+status, result = ctx.resolve("vutbr.cz", unbound.RR_TYPE_NS, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result:"
+ print " raw data:", result.data
+ for k in result.data.domain_list:
+ print " host: %s" % k
+
diff --git a/contrib/unbound/libunbound/python/examples/reverse-lookup.py b/contrib/unbound/libunbound/python/examples/reverse-lookup.py
new file mode 100644
index 0000000..4d3e0bb
--- /dev/null
+++ b/contrib/unbound/libunbound/python/examples/reverse-lookup.py
@@ -0,0 +1,43 @@
+#!/usr/bin/python
+'''
+ reverse-lookup.py: Example shows how to resolve reverse record
+
+ Authors: Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+
+ Copyright (c) 2008. All rights reserved.
+
+ This software is open source.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+'''
+import unbound
+
+ctx = unbound.ub_ctx()
+ctx.resolvconf("/etc/resolv.conf")
+
+status, result = ctx.resolve(unbound.reverse("74.125.43.147") + ".in-addr.arpa.", unbound.RR_TYPE_PTR, unbound.RR_CLASS_IN)
+if status == 0 and result.havedata:
+ print "Result.data:", result.data, result.data.domain_list
+
diff --git a/contrib/unbound/libunbound/python/libunbound.i b/contrib/unbound/libunbound/python/libunbound.i
new file mode 100644
index 0000000..4f92799
--- /dev/null
+++ b/contrib/unbound/libunbound/python/libunbound.i
@@ -0,0 +1,941 @@
+/*
+ * libounbound.i: pyUnbound module (libunbound wrapper for Python)
+ *
+ * Copyright (c) 2009, Zdenek Vasicek (vasicek AT fit.vutbr.cz)
+ * Marek Vavrusa (xvavru00 AT stud.fit.vutbr.cz)
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the organization nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+ */
+%module unbound
+%{
+ #include <sys/types.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <arpa/inet.h>
+ #include "libunbound/unbound.h"
+%}
+
+%pythoncode %{
+ import encodings.idna
+%}
+
+//%include "doc.i"
+%include "file.i"
+
+%feature("docstring") strerror "Convert error value to a human readable string."
+
+// ================================================================================
+// ub_resolve - perform resolution and validation
+// ================================================================================
+%typemap(in,numinputs=0,noblock=1) (struct ub_result** result)
+{
+ struct ub_result* newubr;
+ $1 = &newubr;
+}
+
+/* result generation */
+%typemap(argout,noblock=1) (struct ub_result** result)
+{
+ if(1) { /* new code block for variable on stack */
+ PyObject* tuple;
+ tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, $result);
+ if (result == 0) {
+ PyTuple_SetItem(tuple, 1, SWIG_NewPointerObj(SWIG_as_voidptr(newubr), SWIGTYPE_p_ub_result, SWIG_POINTER_OWN | 0 ));
+ } else {
+ PyTuple_SetItem(tuple, 1, Py_None);
+ }
+ $result = tuple;
+ }
+}
+
+
+// ================================================================================
+// ub_ctx - validation context
+// ================================================================================
+%nodefaultctor ub_ctx; //no default constructor & destructor
+%nodefaultdtor ub_ctx;
+
+%newobject ub_ctx_create;
+%delobject ub_ctx_delete;
+%rename(_ub_ctx_delete) ub_ctx_delete;
+
+%newobject ub_resolve;
+
+%inline %{
+ void ub_ctx_free_dbg (struct ub_ctx* c) {
+ printf("******** UB_CTX free 0x%lX ************\n", (long unsigned int)c);
+ ub_ctx_delete(c);
+ }
+
+ //RR types
+ enum enum_rr_type
+ {
+ /** a host address */
+ RR_TYPE_A = 1,
+ /** an authoritative name server */
+ RR_TYPE_NS = 2,
+ /** a mail destination (Obsolete - use MX) */
+ RR_TYPE_MD = 3,
+ /** a mail forwarder (Obsolete - use MX) */
+ RR_TYPE_MF = 4,
+ /** the canonical name for an alias */
+ RR_TYPE_CNAME = 5,
+ /** marks the start of a zone of authority */
+ RR_TYPE_SOA = 6,
+ /** a mailbox domain name (EXPERIMENTAL) */
+ RR_TYPE_MB = 7,
+ /** a mail group member (EXPERIMENTAL) */
+ RR_TYPE_MG = 8,
+ /** a mail rename domain name (EXPERIMENTAL) */
+ RR_TYPE_MR = 9,
+ /** a null RR (EXPERIMENTAL) */
+ RR_TYPE_NULL = 10,
+ /** a well known service description */
+ RR_TYPE_WKS = 11,
+ /** a domain name pointer */
+ RR_TYPE_PTR = 12,
+ /** host information */
+ RR_TYPE_HINFO = 13,
+ /** mailbox or mail list information */
+ RR_TYPE_MINFO = 14,
+ /** mail exchange */
+ RR_TYPE_MX = 15,
+ /** text strings */
+ RR_TYPE_TXT = 16,
+ /** RFC1183 */
+ RR_TYPE_RP = 17,
+ /** RFC1183 */
+ RR_TYPE_AFSDB = 18,
+ /** RFC1183 */
+ RR_TYPE_X25 = 19,
+ /** RFC1183 */
+ RR_TYPE_ISDN = 20,
+ /** RFC1183 */
+ RR_TYPE_RT = 21,
+ /** RFC1706 */
+ RR_TYPE_NSAP = 22,
+ /** RFC1348 */
+ RR_TYPE_NSAP_PTR = 23,
+ /** 2535typecode */
+ RR_TYPE_SIG = 24,
+ /** 2535typecode */
+ RR_TYPE_KEY = 25,
+ /** RFC2163 */
+ RR_TYPE_PX = 26,
+ /** RFC1712 */
+ RR_TYPE_GPOS = 27,
+ /** ipv6 address */
+ RR_TYPE_AAAA = 28,
+ /** LOC record RFC1876 */
+ RR_TYPE_LOC = 29,
+ /** 2535typecode */
+ RR_TYPE_NXT = 30,
+ /** draft-ietf-nimrod-dns-01.txt */
+ RR_TYPE_EID = 31,
+ /** draft-ietf-nimrod-dns-01.txt */
+ RR_TYPE_NIMLOC = 32,
+ /** SRV record RFC2782 */
+ RR_TYPE_SRV = 33,
+ /** http://www.jhsoft.com/rfc/af-saa-0069.000.rtf */
+ RR_TYPE_ATMA = 34,
+ /** RFC2915 */
+ RR_TYPE_NAPTR = 35,
+ /** RFC2230 */
+ RR_TYPE_KX = 36,
+ /** RFC2538 */
+ RR_TYPE_CERT = 37,
+ /** RFC2874 */
+ RR_TYPE_A6 = 38,
+ /** RFC2672 */
+ RR_TYPE_DNAME = 39,
+ /** dnsind-kitchen-sink-02.txt */
+ RR_TYPE_SINK = 40,
+ /** Pseudo OPT record... */
+ RR_TYPE_OPT = 41,
+ /** RFC3123 */
+ RR_TYPE_APL = 42,
+ /** draft-ietf-dnsext-delegation */
+ RR_TYPE_DS = 43,
+ /** SSH Key Fingerprint */
+ RR_TYPE_SSHFP = 44,
+ /** draft-richardson-ipseckey-rr-11.txt */
+ RR_TYPE_IPSECKEY = 45,
+ /** draft-ietf-dnsext-dnssec-25 */
+ RR_TYPE_RRSIG = 46,
+ RR_TYPE_NSEC = 47,
+ RR_TYPE_DNSKEY = 48,
+ RR_TYPE_DHCID = 49,
+
+ RR_TYPE_NSEC3 = 50,
+ RR_TYPE_NSEC3PARAMS = 51,
+
+ RR_TYPE_UINFO = 100,
+ RR_TYPE_UID = 101,
+ RR_TYPE_GID = 102,
+ RR_TYPE_UNSPEC = 103,
+
+ RR_TYPE_TSIG = 250,
+ RR_TYPE_IXFR = 251,
+ RR_TYPE_AXFR = 252,
+ /** A request for mailbox-related records (MB, MG or MR) */
+ RR_TYPE_MAILB = 253,
+ /** A request for mail agent RRs (Obsolete - see MX) */
+ RR_TYPE_MAILA = 254,
+ /** any type (wildcard) */
+ RR_TYPE_ANY = 255,
+
+ /* RFC 4431, 5074, DNSSEC Lookaside Validation */
+ RR_TYPE_DLV = 32769,
+ };
+
+ // RR classes
+ enum enum_rr_class
+ {
+ /** the Internet */
+ RR_CLASS_IN = 1,
+ /** Chaos class */
+ RR_CLASS_CH = 3,
+ /** Hesiod (Dyer 87) */
+ RR_CLASS_HS = 4,
+ /** None class, dynamic update */
+ RR_CLASS_NONE = 254,
+ /** Any class */
+ RR_CLASS_ANY = 255,
+ };
+%}
+
+%feature("docstring") ub_ctx "Unbound resolving and validation context.
+
+The validation context is created to hold the resolver status, validation keys and a small cache (containing messages, rrsets, roundtrip times, trusted keys, lameness information).
+
+**Usage**
+
+>>> import unbound
+>>> ctx = unbound.ub_ctx()
+>>> ctx.resolvconf(\"/etc/resolv.conf\")
+>>> status, result = ctx.resolve(\"www.google.com\", unbound.RR_TYPE_A, unbound.RR_CLASS_IN)
+>>> if status==0 and result.havedata:
+>>> print \"Result:\",result.data.address_list
+Result: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104']
+"
+
+%extend ub_ctx
+{
+ %pythoncode %{
+ def __init__(self):
+ """Creates a resolving and validation context.
+
+ An exception is invoked if the process of creation an ub_ctx instance fails.
+ """
+ self.this = _unbound.ub_ctx_create()
+ if not self.this:
+ raise Exception("Fatal error: unbound context initialization failed")
+
+ #__swig_destroy__ = _unbound.ub_ctx_free_dbg
+ __swig_destroy__ = _unbound._ub_ctx_delete
+
+ #UB_CTX_METHODS_#
+ def add_ta(self,ta):
+ """Add a trust anchor to the given context.
+
+ The trust anchor is a string, on one line, that holds a valid DNSKEY or DS RR.
+
+ :param ta:
+ string, with zone-format RR on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_add_ta(self,ta)
+ #parameters: struct ub_ctx *,char *,
+ #retvals: int
+
+ def add_ta_file(self,fname):
+ """Add trust anchors to the given context.
+
+ Pass name of a file with DS and DNSKEY records (like from dig or drill).
+
+ :param fname:
+ filename of file with keyfile with trust anchors.
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_add_ta_file(self,fname)
+ #parameters: struct ub_ctx *,char *,
+ #retvals: int
+
+ def config(self,fname):
+ """setup configuration for the given context.
+
+ :param fname:
+ unbound config file (not all settings applicable). This is a power-users interface that lets you specify all sorts of options. For some specific options, such as adding trust anchors, special routines exist.
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_config(self,fname)
+ #parameters: struct ub_ctx *,char *,
+ #retvals: int
+
+ def debuglevel(self,d):
+ """Set debug verbosity for the context Output is directed to stderr.
+
+ :param d:
+ debug level, 0 is off, 1 is very minimal, 2 is detailed, and 3 is lots.
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_debuglevel(self,d)
+ #parameters: struct ub_ctx *,int,
+ #retvals: int
+
+ def debugout(self,out):
+ """Set debug output (and error output) to the specified stream.
+
+ Pass None to disable. Default is stderr.
+
+ :param out:
+ File stream to log to.
+ :returns: (int) 0 if OK, else error.
+
+ **Usage:**
+
+ In order to log into file, use
+
+ ::
+
+ ctx = unbound.ub_ctx()
+ fw = fopen("debug.log")
+ ctx.debuglevel(3)
+ ctx.debugout(fw)
+
+ Another option is to print the debug informations to stderr output
+
+ ::
+
+ ctx = unbound.ub_ctx()
+ ctx.debuglevel(10)
+ ctx.debugout(sys.stderr)
+ """
+ return _unbound.ub_ctx_debugout(self,out)
+ #parameters: struct ub_ctx *,void *,
+ #retvals: int
+
+ def hosts(self,fname="/etc/hosts"):
+ """Read list of hosts from the filename given.
+
+ Usually "/etc/hosts". These addresses are not flagged as DNSSEC secure when queried for.
+
+ :param fname:
+ file name string. If None "/etc/hosts" is used.
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_hosts(self,fname)
+ #parameters: struct ub_ctx *,char *,
+ #retvals: int
+
+ def print_local_zones(self):
+ """Print the local zones and their content (RR data) to the debug output.
+
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_print_local_zones(self)
+ #parameters: struct ub_ctx *,
+ #retvals: int
+
+ def resolvconf(self,fname="/etc/resolv.conf"):
+ """Read list of nameservers to use from the filename given.
+
+ Usually "/etc/resolv.conf". Uses those nameservers as caching proxies. If they do not support DNSSEC, validation may fail.
+
+ Only nameservers are picked up, the searchdomain, ndots and other settings from resolv.conf(5) are ignored.
+
+ :param fname:
+ file name string. If None "/etc/resolv.conf" is used.
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_resolvconf(self,fname)
+ #parameters: struct ub_ctx *,char *,
+ #retvals: int
+
+ def set_async(self,dothread):
+ """Set a context behaviour for asynchronous action.
+
+ :param dothread:
+ if True, enables threading and a call to :meth:`resolve_async` creates a thread to handle work in the background.
+ If False, a process is forked to handle work in the background.
+ Changes to this setting after :meth:`async` calls have been made have no effect (delete and re-create the context to change).
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_async(self,dothread)
+ #parameters: struct ub_ctx *,int,
+ #retvals: int
+
+ def set_fwd(self,addr):
+ """Set machine to forward DNS queries to, the caching resolver to use.
+
+ IP4 or IP6 address. Forwards all DNS requests to that machine, which is expected to run a recursive resolver. If the is not DNSSEC-capable, validation may fail. Can be called several times, in that case the addresses are used as backup servers.
+
+ To read the list of nameservers from /etc/resolv.conf (from DHCP or so), use the call :meth:`resolvconf`.
+
+ :param addr:
+ address, IP4 or IP6 in string format. If the addr is None, forwarding is disabled.
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_set_fwd(self,addr)
+ #parameters: struct ub_ctx *,char *,
+ #retvals: int
+
+ def set_option(self,opt,val):
+ """Set an option for the context.
+
+ Changes to the options after :meth:`resolve`, :meth:`resolve_async`, :meth:`zone_add`, :meth:`zone_remove`, :meth:`data_add` or :meth:`data_remove` have no effect (you have to delete and re-create the context).
+
+ :param opt:
+ option name from the unbound.conf config file format. (not all settings applicable). The name includes the trailing ':' for example set_option("logfile:", "mylog.txt"); This is a power-users interface that lets you specify all sorts of options. For some specific options, such as adding trust anchors, special routines exist.
+ :param val:
+ value of the option.
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_set_option(self,opt,val)
+ #parameters: struct ub_ctx *,char *,char *,
+ #retvals: int
+
+ def trustedkeys(self,fname):
+ """Add trust anchors to the given context.
+
+ Pass the name of a bind-style config file with trusted-keys{}.
+
+ :param fname:
+ filename of file with bind-style config entries with trust anchors.
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_trustedkeys(self,fname)
+ #parameters: struct ub_ctx *,char *,
+ #retvals: int
+ #_UB_CTX_METHODS#
+
+ def zone_print(self):
+ """Print local zones using debougout"""
+ _unbound.ub_ctx_print_local_zones(self)
+
+ def zone_add(self,zonename,zonetype):
+ """Add new local zone
+
+ :param zonename: zone domain name (e.g. myzone.)
+ :param zonetype: type of the zone ("static",...)
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_zone_add(self,zonename, zonetype)
+ #parameters: struct ub_ctx *,char*, char*
+ #retvals: int
+
+ def zone_remove(self,zonename):
+ """Remove local zone
+
+ If exists, removes local zone with all the RRs.
+
+ :param zonename: zone domain name
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_zone_remove(self,zonename)
+ #parameters: struct ub_ctx *,char*
+ #retvals: int
+
+ def data_add(self,rrdata):
+ """Add new local RR data
+
+ :param rrdata: string, in zone-format on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
+ :returns: (int) 0 if OK, else error.
+
+ **Usage**
+ The local data ...
+
+ ::
+
+ >>> ctx = unbound.ub_ctx()
+ >>> ctx.zone_add("mydomain.net.","static")
+ 0
+ >>> status = ctx.data_add("test.mydomain.net. IN A 192.168.1.1")
+ 0
+ >>> status, result = ctx.resolve("test.mydomain.net")
+ >>> if status==0 and result.havedata:
+ >>> print \"Result:\",result.data.address_list
+ Result: ['192.168.1.1']
+
+ """
+ return _unbound.ub_ctx_data_add(self,rrdata)
+ #parameters: struct ub_ctx *,char*
+ #retvals: int
+
+ def data_remove(self,rrdata):
+ """Remove local RR data
+
+ If exists, remove resource record from local zone
+
+ :param rrdata: string, in zone-format on one line. [domainname] [TTL optional] [type] [class optional] [rdata contents]
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_ctx_data_remove(self,rrdata)
+ #parameters: struct ub_ctx *,char*
+ #retvals: int
+
+ #UB_METHODS_#
+ def cancel(self,async_id):
+ """Cancel an async query in progress.
+
+ Its callback will not be called.
+
+ :param async_id:
+ which query to cancel.
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_cancel(self,async_id)
+ #parameters: struct ub_ctx *,int,
+ #retvals: int
+
+ def get_fd(self):
+ """Get file descriptor.
+
+ Wait for it to become readable, at this point answers are returned from the asynchronous validating resolver. Then call the ub_process to continue processing. This routine works immediately after context creation, the fd does not change.
+
+ :returns: (int) -1 on error, or file descriptor to use select(2) with.
+ """
+ return _unbound.ub_fd(self)
+ #parameters: struct ub_ctx *,
+ #retvals: int
+
+ def poll(self):
+ """Poll a context to see if it has any new results Do not poll in a loop, instead extract the fd below to poll for readiness, and then check, or wait using the wait routine.
+
+ :returns: (int) 0 if nothing to read, or nonzero if a result is available. If nonzero, call ctx_process() to do callbacks.
+ """
+ return _unbound.ub_poll(self)
+ #parameters: struct ub_ctx *,
+ #retvals: int
+
+ def process(self):
+ """Call this routine to continue processing results from the validating resolver (when the fd becomes readable).
+
+ Will perform necessary callbacks.
+
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_process(self)
+ #parameters: struct ub_ctx *,
+ #retvals: int
+
+ def resolve(self,name,rrtype=RR_TYPE_A,rrclass=RR_CLASS_IN):
+ """Perform resolution and validation of the target name.
+
+ :param name:
+ domain name in text format (a string or unicode string). IDN domain name have to be passed as a unicode string.
+ :param rrtype:
+ type of RR in host order (optional argument). Default value is RR_TYPE_A (A class).
+ :param rrclass:
+ class of RR in host order (optional argument). Default value is RR_CLASS_IN (for internet).
+ :returns: * (int) 0 if OK, else error.
+ * (:class:`ub_result`) the result data is returned in a newly allocated result structure. May be None on return, return value is set to an error in that case (out of memory).
+ """
+ if isinstance(name, unicode): #probably IDN
+ return _unbound.ub_resolve(self,idn2dname(name),rrtype,rrclass)
+ else:
+ return _unbound.ub_resolve(self,name,rrtype,rrclass)
+ #parameters: struct ub_ctx *,char *,int,int,
+ #retvals: int,struct ub_result **
+
+ def resolve_async(self,name,mydata,callback,rrtype=RR_TYPE_A,rrclass=RR_CLASS_IN):
+ """Perform resolution and validation of the target name.
+
+ Asynchronous, after a while, the callback will be called with your data and the result.
+ If an error happens during processing, your callback will be called with error set to a nonzero value (and result==None).
+
+ :param name:
+ domain name in text format (a string or unicode string). IDN domain name have to be passed as a unicode string.
+ :param mydata:
+ this data is your own data (you can pass arbitrary python object or None) which are passed on to the callback function.
+ :param callback:
+ call-back function which is called on completion of the resolution.
+ :param rrtype:
+ type of RR in host order (optional argument). Default value is RR_TYPE_A (A class).
+ :param rrclass:
+ class of RR in host order (optional argument). Default value is RR_CLASS_IN (for internet).
+ :returns: * (int) 0 if OK, else error.
+ * (int) async_id, an identifier number is returned for the query as it is in progress. It can be used to cancel the query.
+
+ **Call-back function:**
+ The call-back function looks as the follows::
+
+ def call_back(mydata, status, result):
+ pass
+
+ **Parameters:**
+ * `mydata` - mydata object
+ * `status` - 0 when a result has been found
+ * `result` - the result structure. The result may be None, in that case err is set.
+
+ """
+ if isinstance(name, unicode): #probably IDN
+ return _unbound._ub_resolve_async(self,idn2dname(name),rrtype,rrclass,mydata,callback)
+ else:
+ return _unbound._ub_resolve_async(self,name,rrtype,rrclass,mydata,callback)
+ #parameters: struct ub_ctx *,char *,int,int,void *,ub_callback_t,
+ #retvals: int, int
+
+ def wait(self):
+ """Wait for a context to finish with results.
+
+ Calls after the wait for you. After the wait, there are no more outstanding asynchronous queries.
+
+ :returns: (int) 0 if OK, else error.
+ """
+ return _unbound.ub_wait(self)
+ #parameters: struct ub_ctx *,
+ #retvals: int
+
+ #_UB_METHODS#
+ %}
+}
+
+
+// ================================================================================
+// ub_result - validation and resolution results
+// ================================================================================
+%nodefaultctor ub_result; //no default constructor & destructor
+%nodefaultdtor ub_result;
+
+%delobject ub_resolve_free;
+%rename(_ub_resolve_free) ub_resolve_free;
+
+%inline %{
+ void ub_resolve_free_dbg (struct ub_result* r) {
+ printf("******** UB_RESOLVE free 0x%lX ************\n", (long unsigned int)r);
+ ub_resolve_free(r);
+ }
+%}
+
+%feature("docstring") ub_result "The validation and resolution results."
+
+//ub_result.rcode
+%inline %{
+ enum result_enum_rcode {
+ RCODE_NOERROR = 0,
+ RCODE_FORMERR = 1,
+ RCODE_SERVFAIL = 2,
+ RCODE_NXDOMAIN = 3,
+ RCODE_NOTIMPL = 4,
+ RCODE_REFUSED = 5,
+ RCODE_YXDOMAIN = 6,
+ RCODE_YXRRSET = 7,
+ RCODE_NXRRSET = 8,
+ RCODE_NOTAUTH = 9,
+ RCODE_NOTZONE = 10
+ };
+%}
+
+%pythoncode %{
+ class ub_data:
+ """Class which makes the resolution results accessible"""
+ def __init__(self, data):
+ """Creates ub_data class
+ :param data: a list of the result data in RAW format
+ """
+ if data == None:
+ raise Exception("ub_data init: No data")
+ self.data = data
+
+ def __str__(self):
+ """Represents data as string"""
+ return ';'.join([' '.join(map(lambda x:"%02X" % ord(x),a)) for a in self.data])
+
+ @staticmethod
+ def dname2str(s, ofs=0, maxlen=0):
+ """Parses DNAME and produces a list of labels
+
+ :param ofs: where the conversion should start to parse data
+ :param maxlen: maximum length (0 means parse to the end)
+ :returns: list of labels (string)
+ """
+ if not s:
+ return []
+
+ res = []
+ slen = len(s)
+ if maxlen > 0:
+ slen = min(slen, maxlen)
+
+ idx = ofs
+ while (idx < slen):
+ complen = ord(s[idx])
+ res.append(s[idx+1:idx+1+complen])
+ idx += complen + 1
+
+ return res
+
+ def as_raw_data(self):
+ """Returns a list of RAW strings"""
+ return self.data
+
+ raw = property(as_raw_data, doc="Returns RAW data (a list of binary encoded strings). See :meth:`as_raw_data`")
+
+ def as_mx_list(self):
+ """Represents data as a list of MX records (query for RR_TYPE_MX)
+
+ :returns: list of tuples (priority, dname)
+ """
+ return [(256*ord(rdf[0])+ord(rdf[1]),'.'.join([a for a in self.dname2str(rdf,2)])) for rdf in self.data]
+
+ mx_list = property(as_mx_list, doc="Returns a list of tuples containing priority and domain names. See :meth:`as_mx_list`")
+
+ def as_idn_mx_list(self):
+ """Represents data as a list of MX records (query for RR_TYPE_MX)
+
+ :returns: list of tuples (priority, unicode dname)
+ """
+ return [(256*ord(rdf[0])+ord(rdf[1]),'.'.join([encodings.idna.ToUnicode(a) for a in self.dname2str(rdf,2)])) for rdf in self.data]
+
+ mx_list_idn = property(as_idn_mx_list, doc="Returns a list of tuples containing priority and IDN domain names. See :meth:`as_idn_mx_list`")
+
+ def as_address_list(self):
+ """Represents data as a list of IP addresses (query for RR_TYPE_PTR)
+
+ :returns: list of strings
+ """
+ return ['.'.join(map(lambda x:str(ord(x)),a)) for a in self.data]
+
+ address_list = property(as_address_list, doc="Returns a list of IP addresses. See :meth:`as_address_list`")
+
+ def as_domain_list(self):
+ """Represents data as a list of domain names (query for RR_TYPE_A)
+
+ :returns: list of strings
+ """
+ return map(lambda x:'.'.join(self.dname2str(x)), self.data)
+
+ domain_list = property(as_domain_list, doc="Returns a list of domain names. See :meth:`as_domain_list`")
+
+ def as_idn_domain_list(self):
+ """Represents data as a list of unicode domain names (query for RR_TYPE_A)
+
+ :returns: list of strings
+ """
+ return map(lambda x: '.'.join([encodings.idna.ToUnicode(a) for a in self.dname2str(x)]), self.data)
+
+ domain_list_idn = property(as_idn_domain_list, doc="Returns a list of IDN domain names. See :meth:`as_idn_domain_list`")
+%}
+
+%extend ub_result
+{
+
+ %rename(_data) data;
+
+ PyObject* _ub_result_data(struct ub_result* result) {
+ PyObject *list;
+ int i,cnt;
+ (void)self;
+ if ((result == 0) || (!result->havedata) || (result->data == 0))
+ return Py_None;
+
+ for (cnt=0,i=0;;i++,cnt++)
+ if (result->data[i] == 0)
+ break;
+
+ list = PyList_New(cnt);
+ for (i=0;i<cnt;i++)
+ PyList_SetItem(list, i, PyString_FromStringAndSize(result->data[i],result->len[i]));
+
+ return list;
+ }
+
+ PyObject* _packet() {
+ return PyString_FromStringAndSize($self->answer_packet, $self->answer_len);
+ }
+
+ %pythoncode %{
+ def __init__(self):
+ raise Exception("This class can't be created directly.")
+
+ #__swig_destroy__ = _unbound.ub_resolve_free_dbg
+ __swig_destroy__ = _unbound._ub_resolve_free
+
+ #havedata = property(_unbound.ub_result_havedata_get, _unbound.ub_result_havedata_set, "Havedata property")
+
+ rcode2str = {RCODE_NOERROR:'no error', RCODE_FORMERR:'form error', RCODE_SERVFAIL:'serv fail', RCODE_NXDOMAIN:'nx domain', RCODE_NOTIMPL:'not implemented', RCODE_REFUSED:'refused', RCODE_YXDOMAIN:'yxdomain', RCODE_YXRRSET:'yxrrset', RCODE_NXRRSET:'nxrrset', RCODE_NOTAUTH:'not auth', RCODE_NOTZONE:'not zone'}
+
+ def _get_rcode_str(self):
+ """Returns rcode in display representation form
+
+ :returns: string
+ """
+ return self.rcode2str[self.rcode]
+
+ __swig_getmethods__["rcode_str"] = _get_rcode_str
+ if _newclass:rcode_str = _swig_property(_get_rcode_str)
+
+ def _get_raw_data(self):
+ """Result data, a list of network order DNS rdata items.
+
+ Data are represented as a list of strings. To decode RAW data to the list of IP addresses use :attr:`data` attribute which returns an :class:`ub_data` instance containing conversion function.
+ """
+ return self._ub_result_data(self)
+
+ __swig_getmethods__["rawdata"] = _get_raw_data
+ rawdata = property(_get_raw_data, doc="Returns raw data, a list of rdata items. To decode RAW data use the :attr:`data` attribute which returns an instance of :class:`ub_data` containing the conversion functions.")
+
+ def _get_data(self):
+ if not self.havedata: return None
+ return ub_data(self._ub_result_data(self))
+
+ __swig_getmethods__["data"] = _get_data
+ __swig_getmethods__["packet"] = _packet
+ data = property(_get_data, doc="Returns :class:`ub_data` instance containing various decoding functions or None")
+
+%}
+
+}
+
+%exception ub_resolve
+%{
+ //printf("resolve_start(%lX)\n",(long unsigned int)arg1);
+ Py_BEGIN_ALLOW_THREADS
+ $function
+ Py_END_ALLOW_THREADS
+ //printf("resolve_stop()\n");
+%}
+
+%include "libunbound/unbound.h"
+
+%inline %{
+ //SWIG will see the ub_ctx as a class
+ struct ub_ctx {
+ };
+%}
+
+//ub_ctx_debugout void* parameter correction
+int ub_ctx_debugout(struct ub_ctx* ctx, FILE* out);
+
+// ================================================================================
+// ub_resolve_async - perform asynchronous resolution and validation
+// ================================================================================
+
+%typemap(in,numinputs=0,noblock=1) (int* async_id)
+{
+ int asyncid = -1;
+ $1 = &asyncid;
+}
+
+%apply PyObject* {void* mydata}
+
+/* result generation */
+%typemap(argout,noblock=1) (int* async_id)
+{
+ if(1) { /* new code block for variable on stack */
+ PyObject* tuple;
+ tuple = PyTuple_New(2);
+ PyTuple_SetItem(tuple, 0, $result);
+ PyTuple_SetItem(tuple, 1, SWIG_From_int(asyncid));
+ $result = tuple;
+ }
+}
+
+// Grab a Python function object as a Python object.
+%typemap(in) (PyObject *pyfunc) {
+ if (!PyCallable_Check($input))
+ {
+ PyErr_SetString(PyExc_TypeError, "Need a callable object!");
+ return NULL;
+ }
+ $1 = $input;
+}
+
+// Python callback workaround
+int _ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype, int rrclass, void* mydata, PyObject *pyfunc, int* async_id);
+
+%{
+ struct cb_data {
+ PyObject* data;
+ PyObject* func;
+ };
+
+ static void PythonCallBack(void* iddata, int status, struct ub_result* result)
+ {
+ PyObject *arglist;
+ PyObject *fresult;
+ struct cb_data* id;
+ id = (struct cb_data*) iddata;
+ arglist = Py_BuildValue("(OiO)",id->data,status, SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ub_result, 0 | 0 )); // Build argument list
+ fresult = PyEval_CallObject(id->func,arglist); // Call Python
+ Py_DECREF(id->func);
+ Py_DECREF(id->data);
+ free(id);
+ ub_resolve_free(result); //free ub_result
+ //ub_resolve_free_dbg(result); //free ub_result
+ Py_DECREF(arglist); // Trash arglist
+ Py_XDECREF(fresult);
+ }
+
+ int _ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype, int rrclass, PyObject* mydata, PyObject *pyfunc, int* async_id) {
+ int r;
+ struct cb_data* id;
+ id = (struct cb_data*) malloc(sizeof(struct cb_data));
+ id->data = mydata;
+ id->func = pyfunc;
+
+ r = ub_resolve_async(ctx,name,rrtype,rrclass, (void *) id, PythonCallBack, async_id);
+ Py_INCREF(mydata);
+ Py_INCREF(pyfunc);
+ return r;
+ }
+
+%}
+
+%pythoncode %{
+ ub_resolve_async = _unbound._ub_resolve_async
+
+ def reverse(domain):
+ """Reverse domain name
+
+ Usable for reverse lookups when the IP address should be reversed
+ """
+ return '.'.join([a for a in domain.split(".")][::-1])
+
+ def idn2dname(idnname):
+ """Converts domain name in IDN format to canonic domain name
+
+ :param idnname: (unicode string) IDN name
+ :returns: (string) domain name
+ """
+ return '.'.join([encodings.idna.ToASCII(a) for a in idnname.split('.')])
+
+ def dname2idn(name):
+ """Converts canonic domain name in IDN format to unicode string
+
+ :param name: (string) domain name
+ :returns: (unicode string) domain name
+ """
+ return '.'.join([encodings.idna.ToUnicode(a) for a in name.split('.')])
+
+%}
+
diff --git a/contrib/unbound/libunbound/ubsyms.def b/contrib/unbound/libunbound/ubsyms.def
new file mode 100644
index 0000000..7e3fdd1
--- /dev/null
+++ b/contrib/unbound/libunbound/ubsyms.def
@@ -0,0 +1,29 @@
+ub_ctx_create
+ub_ctx_delete
+ub_ctx_get_option
+ub_ctx_set_option
+ub_ctx_config
+ub_ctx_set_fwd
+ub_ctx_resolvconf
+ub_ctx_hosts
+ub_ctx_add_ta
+ub_ctx_add_ta_file
+ub_ctx_trustedkeys
+ub_ctx_debugout
+ub_ctx_debuglevel
+ub_ctx_async
+ub_poll
+ub_wait
+ub_fd
+ub_process
+ub_resolve
+ub_resolve_async
+ub_cancel
+ub_resolve_free
+ub_strerror
+ub_ctx_print_local_zones
+ub_ctx_zone_add
+ub_ctx_zone_remove
+ub_ctx_data_add
+ub_ctx_data_remove
+ub_version
diff --git a/contrib/unbound/libunbound/unbound.h b/contrib/unbound/libunbound/unbound.h
new file mode 100644
index 0000000..085f9f5
--- /dev/null
+++ b/contrib/unbound/libunbound/unbound.h
@@ -0,0 +1,556 @@
+/*
+ * unbound.h - unbound validating resolver public API
+ *
+ * Copyright (c) 2007, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS 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.
+ */
+
+/**
+ * \file
+ *
+ * This file contains functions to resolve DNS queries and
+ * validate the answers. Synchonously and asynchronously.
+ *
+ * Several ways to use this interface from an application wishing
+ * to perform (validated) DNS lookups.
+ *
+ * All start with
+ * ctx = ub_ctx_create();
+ * err = ub_ctx_add_ta(ctx, "...");
+ * err = ub_ctx_add_ta(ctx, "...");
+ * ... some lookups
+ * ... call ub_ctx_delete(ctx); when you want to stop.
+ *
+ * Application not threaded. Blocking.
+ * int err = ub_resolve(ctx, "www.example.com", ...
+ * if(err) fprintf(stderr, "lookup error: %s\n", ub_strerror(err));
+ * ... use the answer
+ *
+ * Application not threaded. Non-blocking ('asynchronous').
+ * err = ub_resolve_async(ctx, "www.example.com", ... my_callback);
+ * ... application resumes processing ...
+ * ... and when either ub_poll(ctx) is true
+ * ... or when the file descriptor ub_fd(ctx) is readable,
+ * ... or whenever, the app calls ...
+ * ub_process(ctx);
+ * ... if no result is ready, the app resumes processing above,
+ * ... or process() calls my_callback() with results.
+ *
+ * ... if the application has nothing more to do, wait for answer
+ * ub_wait(ctx);
+ *
+ * Application threaded. Blocking.
+ * Blocking, same as above. The current thread does the work.
+ * Multiple threads can use the *same context*, each does work and uses
+ * shared cache data from the context.
+ *
+ * Application threaded. Non-blocking ('asynchronous').
+ * ... setup threaded-asynchronous config option
+ * err = ub_ctx_async(ctx, 1);
+ * ... same as async for non-threaded
+ * ... the callbacks are called in the thread that calls process(ctx)
+ *
+ * If no threading is compiled in, the above async example uses fork(2) to
+ * create a process to perform the work. The forked process exits when the
+ * calling process exits, or ctx_delete() is called.
+ * Otherwise, for asynchronous with threading, a worker thread is created.
+ *
+ * The blocking calls use shared ctx-cache when threaded. Thus
+ * ub_resolve() and ub_resolve_async() && ub_wait() are
+ * not the same. The first makes the current thread do the work, setting
+ * up buffers, etc, to perform the work (but using shared cache data).
+ * The second calls another worker thread (or process) to perform the work.
+ * And no buffers need to be set up, but a context-switch happens.
+ */
+#ifndef _UB_UNBOUND_H
+#define _UB_UNBOUND_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * The validation context is created to hold the resolver status,
+ * validation keys and a small cache (containing messages, rrsets,
+ * roundtrip times, trusted keys, lameness information).
+ *
+ * Its contents are internally defined.
+ */
+struct ub_ctx;
+
+/**
+ * The validation and resolution results.
+ * Allocated by the resolver, and need to be freed by the application
+ * with ub_resolve_free().
+ */
+struct ub_result {
+ /** The original question, name text string. */
+ char* qname;
+ /** the type asked for */
+ int qtype;
+ /** the class asked for */
+ int qclass;
+
+ /**
+ * a list of network order DNS rdata items, terminated with a
+ * NULL pointer, so that data[0] is the first result entry,
+ * data[1] the second, and the last entry is NULL.
+ * If there was no data, data[0] is NULL.
+ */
+ char** data;
+
+ /** the length in bytes of the data items, len[i] for data[i] */
+ int* len;
+
+ /**
+ * canonical name for the result (the final cname).
+ * zero terminated string.
+ * May be NULL if no canonical name exists.
+ */
+ char* canonname;
+
+ /**
+ * DNS RCODE for the result. May contain additional error code if
+ * there was no data due to an error. 0 (NOERROR) if okay.
+ */
+ int rcode;
+
+ /**
+ * The DNS answer packet. Network formatted. Can contain DNSSEC types.
+ */
+ void* answer_packet;
+ /** length of the answer packet in octets. */
+ int answer_len;
+
+ /**
+ * If there is any data, this is true.
+ * If false, there was no data (nxdomain may be true, rcode can be set).
+ */
+ int havedata;
+
+ /**
+ * If there was no data, and the domain did not exist, this is true.
+ * If it is false, and there was no data, then the domain name
+ * is purported to exist, but the requested data type is not available.
+ */
+ int nxdomain;
+
+ /**
+ * True, if the result is validated securely.
+ * False, if validation failed or domain queried has no security info.
+ *
+ * It is possible to get a result with no data (havedata is false),
+ * and secure is true. This means that the non-existance of the data
+ * was cryptographically proven (with signatures).
+ */
+ int secure;
+
+ /**
+ * If the result was not secure (secure==0), and this result is due
+ * to a security failure, bogus is true.
+ * This means the data has been actively tampered with, signatures
+ * failed, expected signatures were not present, timestamps on
+ * signatures were out of date and so on.
+ *
+ * If !secure and !bogus, this can happen if the data is not secure
+ * because security is disabled for that domain name.
+ * This means the data is from a domain where data is not signed.
+ */
+ int bogus;
+
+ /**
+ * If the result is bogus this contains a string (zero terminated)
+ * that describes the failure. There may be other errors as well
+ * as the one described, the description may not be perfectly accurate.
+ * Is NULL if the result is not bogus.
+ */
+ char* why_bogus;
+};
+
+/**
+ * Callback for results of async queries.
+ * The readable function definition looks like:
+ * void my_callback(void* my_arg, int err, struct ub_result* result);
+ * It is called with
+ * void* my_arg: your pointer to a (struct of) data of your choice,
+ * or NULL.
+ * int err: if 0 all is OK, otherwise an error occured and no results
+ * are forthcoming.
+ * struct result: pointer to more detailed result structure.
+ * This structure is allocated on the heap and needs to be
+ * freed with ub_resolve_free(result);
+ */
+typedef void (*ub_callback_t)(void*, int, struct ub_result*);
+
+/**
+ * Create a resolving and validation context.
+ * The information from /etc/resolv.conf and /etc/hosts is not utilised by
+ * default. Use ub_ctx_resolvconf and ub_ctx_hosts to read them.
+ * @return a new context. default initialisation.
+ * returns NULL on error.
+ */
+struct ub_ctx* ub_ctx_create(void);
+
+/**
+ * Destroy a validation context and free all its resources.
+ * Outstanding async queries are killed and callbacks are not called for them.
+ * @param ctx: context to delete.
+ */
+void ub_ctx_delete(struct ub_ctx* ctx);
+
+/**
+ * Set an option for the context.
+ * @param ctx: context.
+ * @param opt: option name from the unbound.conf config file format.
+ * (not all settings applicable). The name includes the trailing ':'
+ * for example ub_ctx_set_option(ctx, "logfile:", "mylog.txt");
+ * This is a power-users interface that lets you specify all sorts
+ * of options.
+ * For some specific options, such as adding trust anchors, special
+ * routines exist.
+ * @param val: value of the option.
+ * @return: 0 if OK, else error.
+ */
+int ub_ctx_set_option(struct ub_ctx* ctx, char* opt, char* val);
+
+/**
+ * Get an option from the context.
+ * @param ctx: context.
+ * @param opt: option name from the unbound.conf config file format.
+ * (not all settings applicable). The name excludes the trailing ':'
+ * for example ub_ctx_get_option(ctx, "logfile", &result);
+ * This is a power-users interface that lets you specify all sorts
+ * of options.
+ * @param str: the string is malloced and returned here. NULL on error.
+ * The caller must free() the string. In cases with multiple
+ * entries (auto-trust-anchor-file), a newline delimited list is
+ * returned in the string.
+ * @return 0 if OK else an error code (malloc failure, syntax error).
+ */
+int ub_ctx_get_option(struct ub_ctx* ctx, char* opt, char** str);
+
+/**
+ * setup configuration for the given context.
+ * @param ctx: context.
+ * @param fname: unbound config file (not all settings applicable).
+ * This is a power-users interface that lets you specify all sorts
+ * of options.
+ * For some specific options, such as adding trust anchors, special
+ * routines exist.
+ * @return: 0 if OK, else error.
+ */
+int ub_ctx_config(struct ub_ctx* ctx, char* fname);
+
+/**
+ * Set machine to forward DNS queries to, the caching resolver to use.
+ * IP4 or IP6 address. Forwards all DNS requests to that machine, which
+ * is expected to run a recursive resolver. If the proxy is not
+ * DNSSEC-capable, validation may fail. Can be called several times, in
+ * that case the addresses are used as backup servers.
+ *
+ * To read the list of nameservers from /etc/resolv.conf (from DHCP or so),
+ * use the call ub_ctx_resolvconf.
+ *
+ * @param ctx: context.
+ * At this time it is only possible to set configuration before the
+ * first resolve is done.
+ * @param addr: address, IP4 or IP6 in string format.
+ * If the addr is NULL, forwarding is disabled.
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_set_fwd(struct ub_ctx* ctx, char* addr);
+
+/**
+ * Read list of nameservers to use from the filename given.
+ * Usually "/etc/resolv.conf". Uses those nameservers as caching proxies.
+ * If they do not support DNSSEC, validation may fail.
+ *
+ * Only nameservers are picked up, the searchdomain, ndots and other
+ * settings from resolv.conf(5) are ignored.
+ *
+ * @param ctx: context.
+ * At this time it is only possible to set configuration before the
+ * first resolve is done.
+ * @param fname: file name string. If NULL "/etc/resolv.conf" is used.
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_resolvconf(struct ub_ctx* ctx, char* fname);
+
+/**
+ * Read list of hosts from the filename given.
+ * Usually "/etc/hosts".
+ * These addresses are not flagged as DNSSEC secure when queried for.
+ *
+ * @param ctx: context.
+ * At this time it is only possible to set configuration before the
+ * first resolve is done.
+ * @param fname: file name string. If NULL "/etc/hosts" is used.
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_hosts(struct ub_ctx* ctx, char* fname);
+
+/**
+ * Add a trust anchor to the given context.
+ * The trust anchor is a string, on one line, that holds a valid DNSKEY or
+ * DS RR.
+ * @param ctx: context.
+ * At this time it is only possible to add trusted keys before the
+ * first resolve is done.
+ * @param ta: string, with zone-format RR on one line.
+ * [domainname] [TTL optional] [type] [class optional] [rdata contents]
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_add_ta(struct ub_ctx* ctx, char* ta);
+
+/**
+ * Add trust anchors to the given context.
+ * Pass name of a file with DS and DNSKEY records (like from dig or drill).
+ * @param ctx: context.
+ * At this time it is only possible to add trusted keys before the
+ * first resolve is done.
+ * @param fname: filename of file with keyfile with trust anchors.
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_add_ta_file(struct ub_ctx* ctx, char* fname);
+
+/**
+ * Add trust anchors to the given context.
+ * Pass the name of a bind-style config file with trusted-keys{}.
+ * @param ctx: context.
+ * At this time it is only possible to add trusted keys before the
+ * first resolve is done.
+ * @param fname: filename of file with bind-style config entries with trust
+ * anchors.
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_trustedkeys(struct ub_ctx* ctx, char* fname);
+
+/**
+ * Set debug output (and error output) to the specified stream.
+ * Pass NULL to disable. Default is stderr.
+ * @param ctx: context.
+ * @param out: FILE* out file stream to log to.
+ * Type void* to avoid stdio dependency of this header file.
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_debugout(struct ub_ctx* ctx, void* out);
+
+/**
+ * Set debug verbosity for the context
+ * Output is directed to stderr.
+ * @param ctx: context.
+ * @param d: debug level, 0 is off, 1 is very minimal, 2 is detailed,
+ * and 3 is lots.
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_debuglevel(struct ub_ctx* ctx, int d);
+
+/**
+ * Set a context behaviour for asynchronous action.
+ * @param ctx: context.
+ * @param dothread: if true, enables threading and a call to resolve_async()
+ * creates a thread to handle work in the background.
+ * If false, a process is forked to handle work in the background.
+ * Changes to this setting after async() calls have been made have
+ * no effect (delete and re-create the context to change).
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_async(struct ub_ctx* ctx, int dothread);
+
+/**
+ * Poll a context to see if it has any new results
+ * Do not poll in a loop, instead extract the fd below to poll for readiness,
+ * and then check, or wait using the wait routine.
+ * @param ctx: context.
+ * @return: 0 if nothing to read, or nonzero if a result is available.
+ * If nonzero, call ctx_process() to do callbacks.
+ */
+int ub_poll(struct ub_ctx* ctx);
+
+/**
+ * Wait for a context to finish with results. Calls ub_process() after
+ * the wait for you. After the wait, there are no more outstanding
+ * asynchronous queries.
+ * @param ctx: context.
+ * @return: 0 if OK, else error.
+ */
+int ub_wait(struct ub_ctx* ctx);
+
+/**
+ * Get file descriptor. Wait for it to become readable, at this point
+ * answers are returned from the asynchronous validating resolver.
+ * Then call the ub_process to continue processing.
+ * This routine works immediately after context creation, the fd
+ * does not change.
+ * @param ctx: context.
+ * @return: -1 on error, or file descriptor to use select(2) with.
+ */
+int ub_fd(struct ub_ctx* ctx);
+
+/**
+ * Call this routine to continue processing results from the validating
+ * resolver (when the fd becomes readable).
+ * Will perform necessary callbacks.
+ * @param ctx: context
+ * @return: 0 if OK, else error.
+ */
+int ub_process(struct ub_ctx* ctx);
+
+/**
+ * Perform resolution and validation of the target name.
+ * @param ctx: context.
+ * The context is finalized, and can no longer accept config changes.
+ * @param name: domain name in text format (a zero terminated text string).
+ * @param rrtype: type of RR in host order, 1 is A (address).
+ * @param rrclass: class of RR in host order, 1 is IN (for internet).
+ * @param result: the result data is returned in a newly allocated result
+ * structure. May be NULL on return, return value is set to an error
+ * in that case (out of memory).
+ * @return 0 if OK, else error.
+ */
+int ub_resolve(struct ub_ctx* ctx, char* name, int rrtype,
+ int rrclass, struct ub_result** result);
+
+/**
+ * Perform resolution and validation of the target name.
+ * Asynchronous, after a while, the callback will be called with your
+ * data and the result.
+ * @param ctx: context.
+ * If no thread or process has been created yet to perform the
+ * work in the background, it is created now.
+ * The context is finalized, and can no longer accept config changes.
+ * @param name: domain name in text format (a string).
+ * @param rrtype: type of RR in host order, 1 is A.
+ * @param rrclass: class of RR in host order, 1 is IN (for internet).
+ * @param mydata: this data is your own data (you can pass NULL),
+ * and is passed on to the callback function.
+ * @param callback: this is called on completion of the resolution.
+ * It is called as:
+ * void callback(void* mydata, int err, struct ub_result* result)
+ * with mydata: the same as passed here, you may pass NULL,
+ * with err: is 0 when a result has been found.
+ * with result: a newly allocated result structure.
+ * The result may be NULL, in that case err is set.
+ *
+ * If an error happens during processing, your callback will be called
+ * with error set to a nonzero value (and result==NULL).
+ * @param async_id: if you pass a non-NULL value, an identifier number is
+ * returned for the query as it is in progress. It can be used to
+ * cancel the query.
+ * @return 0 if OK, else error.
+ */
+int ub_resolve_async(struct ub_ctx* ctx, char* name, int rrtype,
+ int rrclass, void* mydata, ub_callback_t callback, int* async_id);
+
+/**
+ * Cancel an async query in progress.
+ * Its callback will not be called.
+ *
+ * @param ctx: context.
+ * @param async_id: which query to cancel.
+ * @return 0 if OK, else error.
+ * This routine can return an error if the async_id passed does not exist
+ * or has already been delivered. If another thread is processing results
+ * at the same time, the result may be delivered at the same time and the
+ * cancel fails with an error. Also the cancel can fail due to a system
+ * error, no memory or socket failures.
+ */
+int ub_cancel(struct ub_ctx* ctx, int async_id);
+
+/**
+ * Free storage associated with a result structure.
+ * @param result: to free
+ */
+void ub_resolve_free(struct ub_result* result);
+
+/**
+ * Convert error value to a human readable string.
+ * @param err: error code from one of the ub_val* functions.
+ * @return pointer to constant text string, zero terminated.
+ */
+const char* ub_strerror(int err);
+
+/**
+ * Debug routine. Print the local zone information to debug output.
+ * @param ctx: context. Is finalized by the routine.
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_print_local_zones(struct ub_ctx* ctx);
+
+/**
+ * Add a new zone with the zonetype to the local authority info of the
+ * library.
+ * @param ctx: context. Is finalized by the routine.
+ * @param zone_name: name of the zone in text, "example.com"
+ * If it already exists, the type is updated.
+ * @param zone_type: type of the zone (like for unbound.conf) in text.
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_zone_add(struct ub_ctx* ctx, char *zone_name, char *zone_type);
+
+/**
+ * Remove zone from local authority info of the library.
+ * @param ctx: context. Is finalized by the routine.
+ * @param zone_name: name of the zone in text, "example.com"
+ * If it does not exist, nothing happens.
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_zone_remove(struct ub_ctx* ctx, char *zone_name);
+
+/**
+ * Add localdata to the library local authority info.
+ * Similar to local-data config statement.
+ * @param ctx: context. Is finalized by the routine.
+ * @param data: the resource record in text format, for example
+ * "www.example.com IN A 127.0.0.1"
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_data_add(struct ub_ctx* ctx, char *data);
+
+/**
+ * Remove localdata from the library local authority info.
+ * @param ctx: context. Is finalized by the routine.
+ * @param data: the name to delete all data from, like "www.example.com".
+ * @return 0 if OK, else error.
+ */
+int ub_ctx_data_remove(struct ub_ctx* ctx, char *data);
+
+/**
+ * Get a version string from the libunbound implementation.
+ * @return a static constant string with the version number.
+ */
+const char* ub_version(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _UB_UNBOUND_H */
OpenPOWER on IntegriCloud