aboutsummaryrefslogtreecommitdiff
path: root/external/unbound/util
diff options
context:
space:
mode:
authorRiccardo Spagni <ric@spagni.net>2014-10-05 23:44:31 +0200
committerRiccardo Spagni <ric@spagni.net>2014-10-05 23:44:31 +0200
commit9ef094b356b4da7542c3cab898dac7e135b76903 (patch)
tree99b5876712b0b1551fc042fe75447b998e4b0fc1 /external/unbound/util
parentsplit mnemonic printout over 3 lines (diff)
downloadmonero-9ef094b356b4da7542c3cab898dac7e135b76903.tar.xz
added unbound to external deps
Diffstat (limited to 'external/unbound/util')
-rw-r--r--external/unbound/util/alloc.c642
-rw-r--r--external/unbound/util/alloc.h217
-rw-r--r--external/unbound/util/config_file.c1571
-rw-r--r--external/unbound/util/config_file.h704
-rw-r--r--external/unbound/util/configlexer.c4023
-rw-r--r--external/unbound/util/configlexer.lex444
-rw-r--r--external/unbound/util/configparser.c4109
-rw-r--r--external/unbound/util/configparser.h380
-rw-r--r--external/unbound/util/configparser.y1462
-rw-r--r--external/unbound/util/configyyrename.h88
-rw-r--r--external/unbound/util/data/dname.c782
-rw-r--r--external/unbound/util/data/dname.h304
-rw-r--r--external/unbound/util/data/msgencode.c841
-rw-r--r--external/unbound/util/data/msgencode.h131
-rw-r--r--external/unbound/util/data/msgparse.c1022
-rw-r--r--external/unbound/util/data/msgparse.h301
-rw-r--r--external/unbound/util/data/msgreply.c830
-rw-r--r--external/unbound/util/data/msgreply.h438
-rw-r--r--external/unbound/util/data/packed_rrset.c389
-rw-r--r--external/unbound/util/data/packed_rrset.h428
-rw-r--r--external/unbound/util/fptr_wlist.c409
-rw-r--r--external/unbound/util/fptr_wlist.h359
-rw-r--r--external/unbound/util/iana_ports.inc5408
-rw-r--r--external/unbound/util/locks.c264
-rw-r--r--external/unbound/util/locks.h296
-rw-r--r--external/unbound/util/log.c485
-rw-r--r--external/unbound/util/log.h198
-rw-r--r--external/unbound/util/mini_event.c394
-rw-r--r--external/unbound/util/mini_event.h177
-rw-r--r--external/unbound/util/module.c71
-rw-r--r--external/unbound/util/module.h517
-rw-r--r--external/unbound/util/net_help.c804
-rw-r--r--external/unbound/util/net_help.h393
-rw-r--r--external/unbound/util/netevent.c2217
-rw-r--r--external/unbound/util/netevent.h703
-rw-r--r--external/unbound/util/random.c166
-rw-r--r--external/unbound/util/random.h93
-rw-r--r--external/unbound/util/rbtree.c620
-rw-r--r--external/unbound/util/rbtree.h192
-rw-r--r--external/unbound/util/regional.c223
-rw-r--r--external/unbound/util/regional.h150
-rw-r--r--external/unbound/util/rtt.c119
-rw-r--r--external/unbound/util/rtt.h107
-rw-r--r--external/unbound/util/storage/dnstree.c282
-rw-r--r--external/unbound/util/storage/dnstree.h192
-rw-r--r--external/unbound/util/storage/lookup3.c1032
-rw-r--r--external/unbound/util/storage/lookup3.h71
-rw-r--r--external/unbound/util/storage/lruhash.c544
-rw-r--r--external/unbound/util/storage/lruhash.h414
-rw-r--r--external/unbound/util/storage/slabhash.c231
-rw-r--r--external/unbound/util/storage/slabhash.h218
-rw-r--r--external/unbound/util/timehist.c247
-rw-r--r--external/unbound/util/timehist.h134
-rw-r--r--external/unbound/util/tube.c727
-rw-r--r--external/unbound/util/tube.h273
-rw-r--r--external/unbound/util/winsock_event.c696
-rw-r--r--external/unbound/util/winsock_event.h264
57 files changed, 38796 insertions, 0 deletions
diff --git a/external/unbound/util/alloc.c b/external/unbound/util/alloc.c
new file mode 100644
index 000000000..4b81beb4c
--- /dev/null
+++ b/external/unbound/util/alloc.c
@@ -0,0 +1,642 @@
+/*
+ * util/alloc.c - memory allocation service.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 memory allocation functions.
+ */
+
+#include "config.h"
+#include "util/alloc.h"
+#include "util/regional.h"
+#include "util/data/packed_rrset.h"
+#include "util/fptr_wlist.h"
+
+/** custom size of cached regional blocks */
+#define ALLOC_REG_SIZE 16384
+/** number of bits for ID part of uint64, rest for number of threads. */
+#define THRNUM_SHIFT 48 /* for 65k threads, 2^48 rrsets per thr. */
+
+/** setup new special type */
+static void
+alloc_setup_special(alloc_special_t* t)
+{
+ memset(t, 0, sizeof(*t));
+ lock_rw_init(&t->entry.lock);
+ t->entry.key = t;
+}
+
+/** prealloc some entries in the cache. To minimize contention.
+ * Result is 1 lock per alloc_max newly created entries.
+ * @param alloc: the structure to fill up.
+ */
+static void
+prealloc(struct alloc_cache* alloc)
+{
+ alloc_special_t* p;
+ int i;
+ for(i=0; i<ALLOC_SPECIAL_MAX; i++) {
+ if(!(p = (alloc_special_t*)malloc(sizeof(alloc_special_t)))) {
+ log_err("prealloc: out of memory");
+ return;
+ }
+ alloc_setup_special(p);
+ alloc_set_special_next(p, alloc->quar);
+ alloc->quar = p;
+ alloc->num_quar++;
+ }
+}
+
+/** prealloc region blocks */
+static void
+prealloc_blocks(struct alloc_cache* alloc, size_t num)
+{
+ size_t i;
+ struct regional* r;
+ for(i=0; i<num; i++) {
+ r = regional_create_custom(ALLOC_REG_SIZE);
+ if(!r) {
+ log_err("prealloc blocks: out of memory");
+ return;
+ }
+ r->next = (char*)alloc->reg_list;
+ alloc->reg_list = r;
+ alloc->num_reg_blocks ++;
+ }
+}
+
+void
+alloc_init(struct alloc_cache* alloc, struct alloc_cache* super,
+ int thread_num)
+{
+ memset(alloc, 0, sizeof(*alloc));
+ alloc->super = super;
+ alloc->thread_num = thread_num;
+ alloc->next_id = (uint64_t)thread_num; /* in steps, so that type */
+ alloc->next_id <<= THRNUM_SHIFT; /* of *_id is used. */
+ alloc->last_id = 1; /* so no 64bit constants, */
+ alloc->last_id <<= THRNUM_SHIFT; /* or implicit 'int' ops. */
+ alloc->last_id -= 1; /* for compiler portability. */
+ alloc->last_id |= alloc->next_id;
+ alloc->next_id += 1; /* because id=0 is special. */
+ alloc->max_reg_blocks = 100;
+ alloc->num_reg_blocks = 0;
+ alloc->reg_list = NULL;
+ alloc->cleanup = NULL;
+ alloc->cleanup_arg = NULL;
+ if(alloc->super)
+ prealloc_blocks(alloc, alloc->max_reg_blocks);
+ if(!alloc->super) {
+ lock_quick_init(&alloc->lock);
+ lock_protect(&alloc->lock, alloc, sizeof(*alloc));
+ }
+}
+
+void
+alloc_clear(struct alloc_cache* alloc)
+{
+ alloc_special_t* p, *np;
+ struct regional* r, *nr;
+ if(!alloc)
+ return;
+ if(!alloc->super) {
+ lock_quick_destroy(&alloc->lock);
+ }
+ if(alloc->super && alloc->quar) {
+ /* push entire list into super */
+ p = alloc->quar;
+ while(alloc_special_next(p)) /* find last */
+ p = alloc_special_next(p);
+ lock_quick_lock(&alloc->super->lock);
+ alloc_set_special_next(p, alloc->super->quar);
+ alloc->super->quar = alloc->quar;
+ alloc->super->num_quar += alloc->num_quar;
+ lock_quick_unlock(&alloc->super->lock);
+ } else {
+ /* free */
+ p = alloc->quar;
+ while(p) {
+ np = alloc_special_next(p);
+ /* deinit special type */
+ lock_rw_destroy(&p->entry.lock);
+ free(p);
+ p = np;
+ }
+ }
+ alloc->quar = 0;
+ alloc->num_quar = 0;
+ r = alloc->reg_list;
+ while(r) {
+ nr = (struct regional*)r->next;
+ free(r);
+ r = nr;
+ }
+ alloc->reg_list = NULL;
+ alloc->num_reg_blocks = 0;
+}
+
+uint64_t
+alloc_get_id(struct alloc_cache* alloc)
+{
+ uint64_t id = alloc->next_id++;
+ if(id == alloc->last_id) {
+ log_warn("rrset alloc: out of 64bit ids. Clearing cache.");
+ fptr_ok(fptr_whitelist_alloc_cleanup(alloc->cleanup));
+ (*alloc->cleanup)(alloc->cleanup_arg);
+
+ /* start back at first number */ /* like in alloc_init*/
+ alloc->next_id = (uint64_t)alloc->thread_num;
+ alloc->next_id <<= THRNUM_SHIFT; /* in steps for comp. */
+ alloc->next_id += 1; /* portability. */
+ /* and generate new and safe id */
+ id = alloc->next_id++;
+ }
+ return id;
+}
+
+alloc_special_t*
+alloc_special_obtain(struct alloc_cache* alloc)
+{
+ alloc_special_t* p;
+ log_assert(alloc);
+ /* see if in local cache */
+ if(alloc->quar) {
+ p = alloc->quar;
+ alloc->quar = alloc_special_next(p);
+ alloc->num_quar--;
+ p->id = alloc_get_id(alloc);
+ return p;
+ }
+ /* see if in global cache */
+ if(alloc->super) {
+ /* could maybe grab alloc_max/2 entries in one go,
+ * but really, isn't that just as fast as this code? */
+ lock_quick_lock(&alloc->super->lock);
+ if((p = alloc->super->quar)) {
+ alloc->super->quar = alloc_special_next(p);
+ alloc->super->num_quar--;
+ }
+ lock_quick_unlock(&alloc->super->lock);
+ if(p) {
+ p->id = alloc_get_id(alloc);
+ return p;
+ }
+ }
+ /* allocate new */
+ prealloc(alloc);
+ if(!(p = (alloc_special_t*)malloc(sizeof(alloc_special_t)))) {
+ log_err("alloc_special_obtain: out of memory");
+ return NULL;
+ }
+ alloc_setup_special(p);
+ p->id = alloc_get_id(alloc);
+ return p;
+}
+
+/** push mem and some more items to the super */
+static void
+pushintosuper(struct alloc_cache* alloc, alloc_special_t* mem)
+{
+ int i;
+ alloc_special_t *p = alloc->quar;
+ log_assert(p);
+ log_assert(alloc && alloc->super &&
+ alloc->num_quar >= ALLOC_SPECIAL_MAX);
+ /* push ALLOC_SPECIAL_MAX/2 after mem */
+ alloc_set_special_next(mem, alloc->quar);
+ for(i=1; i<ALLOC_SPECIAL_MAX/2; i++) {
+ p = alloc_special_next(p);
+ }
+ alloc->quar = alloc_special_next(p);
+ alloc->num_quar -= ALLOC_SPECIAL_MAX/2;
+
+ /* dump mem+list into the super quar list */
+ lock_quick_lock(&alloc->super->lock);
+ alloc_set_special_next(p, alloc->super->quar);
+ alloc->super->quar = mem;
+ alloc->super->num_quar += ALLOC_SPECIAL_MAX/2 + 1;
+ lock_quick_unlock(&alloc->super->lock);
+ /* so 1 lock per mem+alloc/2 deletes */
+}
+
+void
+alloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem)
+{
+ log_assert(alloc);
+ if(!mem)
+ return;
+ if(!alloc->super) {
+ lock_quick_lock(&alloc->lock); /* superalloc needs locking */
+ }
+
+ alloc_special_clean(mem);
+ if(alloc->super && alloc->num_quar >= ALLOC_SPECIAL_MAX) {
+ /* push it to the super structure */
+ pushintosuper(alloc, mem);
+ return;
+ }
+
+ alloc_set_special_next(mem, alloc->quar);
+ alloc->quar = mem;
+ alloc->num_quar++;
+ if(!alloc->super) {
+ lock_quick_unlock(&alloc->lock);
+ }
+}
+
+void
+alloc_stats(struct alloc_cache* alloc)
+{
+ log_info("%salloc: %d in cache, %d blocks.", alloc->super?"":"sup",
+ (int)alloc->num_quar, (int)alloc->num_reg_blocks);
+}
+
+size_t alloc_get_mem(struct alloc_cache* alloc)
+{
+ alloc_special_t* p;
+ size_t s = sizeof(*alloc);
+ if(!alloc->super) {
+ lock_quick_lock(&alloc->lock); /* superalloc needs locking */
+ }
+ s += sizeof(alloc_special_t) * alloc->num_quar;
+ for(p = alloc->quar; p; p = alloc_special_next(p)) {
+ s += lock_get_mem(&p->entry.lock);
+ }
+ s += alloc->num_reg_blocks * ALLOC_REG_SIZE;
+ if(!alloc->super) {
+ lock_quick_unlock(&alloc->lock);
+ }
+ return s;
+}
+
+struct regional*
+alloc_reg_obtain(struct alloc_cache* alloc)
+{
+ if(alloc->num_reg_blocks > 0) {
+ struct regional* r = alloc->reg_list;
+ alloc->reg_list = (struct regional*)r->next;
+ r->next = NULL;
+ alloc->num_reg_blocks--;
+ return r;
+ }
+ return regional_create_custom(ALLOC_REG_SIZE);
+}
+
+void
+alloc_reg_release(struct alloc_cache* alloc, struct regional* r)
+{
+ if(alloc->num_reg_blocks >= alloc->max_reg_blocks) {
+ regional_destroy(r);
+ return;
+ }
+ if(!r) return;
+ regional_free_all(r);
+ log_assert(r->next == NULL);
+ r->next = (char*)alloc->reg_list;
+ alloc->reg_list = r;
+ alloc->num_reg_blocks++;
+}
+
+void
+alloc_set_id_cleanup(struct alloc_cache* alloc, void (*cleanup)(void*),
+ void* arg)
+{
+ alloc->cleanup = cleanup;
+ alloc->cleanup_arg = arg;
+}
+
+/** global debug value to keep track of total memory mallocs */
+size_t unbound_mem_alloc = 0;
+/** global debug value to keep track of total memory frees */
+size_t unbound_mem_freed = 0;
+#ifdef UNBOUND_ALLOC_STATS
+/** special value to know if the memory is being tracked */
+uint64_t mem_special = (uint64_t)0xfeed43327766abcdLL;
+#ifdef malloc
+#undef malloc
+#endif
+/** malloc with stats */
+void *unbound_stat_malloc(size_t size)
+{
+ void* res;
+ if(size == 0) size = 1;
+ res = malloc(size+16);
+ if(!res) return NULL;
+ unbound_mem_alloc += size;
+ log_info("stat %p=malloc(%u)", res+16, (unsigned)size);
+ memcpy(res, &size, sizeof(size));
+ memcpy(res+8, &mem_special, sizeof(mem_special));
+ return res+16;
+}
+#ifdef calloc
+#undef calloc
+#endif
+/** calloc with stats */
+void *unbound_stat_calloc(size_t nmemb, size_t size)
+{
+ size_t s = (nmemb*size==0)?(size_t)1:nmemb*size;
+ void* res = calloc(1, s+16);
+ if(!res) return NULL;
+ log_info("stat %p=calloc(%u, %u)", res+16, (unsigned)nmemb, (unsigned)size);
+ unbound_mem_alloc += s;
+ memcpy(res, &s, sizeof(s));
+ memcpy(res+8, &mem_special, sizeof(mem_special));
+ return res+16;
+}
+#ifdef free
+#undef free
+#endif
+/** free with stats */
+void unbound_stat_free(void *ptr)
+{
+ size_t s;
+ if(!ptr) return;
+ if(memcmp(ptr-8, &mem_special, sizeof(mem_special)) != 0) {
+ free(ptr);
+ return;
+ }
+ ptr-=16;
+ memcpy(&s, ptr, sizeof(s));
+ log_info("stat free(%p) size %u", ptr+16, (unsigned)s);
+ memset(ptr+8, 0, 8);
+ unbound_mem_freed += s;
+ free(ptr);
+}
+#ifdef realloc
+#undef realloc
+#endif
+/** realloc with stats */
+void *unbound_stat_realloc(void *ptr, size_t size)
+{
+ size_t cursz;
+ void* res;
+ if(!ptr) return unbound_stat_malloc(size);
+ if(memcmp(ptr-8, &mem_special, sizeof(mem_special)) != 0) {
+ return realloc(ptr, size);
+ }
+ if(size==0) {
+ unbound_stat_free(ptr);
+ return NULL;
+ }
+ ptr -= 16;
+ memcpy(&cursz, ptr, sizeof(cursz));
+ if(cursz == size) {
+ /* nothing changes */
+ return ptr;
+ }
+ res = malloc(size+16);
+ if(!res) return NULL;
+ unbound_mem_alloc += size;
+ unbound_mem_freed += cursz;
+ log_info("stat realloc(%p, %u) from %u", ptr+16, (unsigned)size, (unsigned)cursz);
+ if(cursz > size) {
+ memcpy(res+16, ptr+16, size);
+ } else if(size > cursz) {
+ memcpy(res+16, ptr+16, cursz);
+ }
+ memset(ptr+8, 0, 8);
+ free(ptr);
+ memcpy(res, &size, sizeof(size));
+ memcpy(res+8, &mem_special, sizeof(mem_special));
+ return res+16;
+}
+
+/** log to file where alloc was done */
+void *unbound_stat_malloc_log(size_t size, const char* file, int line,
+ const char* func)
+{
+ log_info("%s:%d %s malloc(%u)", file, line, func, (unsigned)size);
+ return unbound_stat_malloc(size);
+}
+
+/** log to file where alloc was done */
+void *unbound_stat_calloc_log(size_t nmemb, size_t size, const char* file,
+ int line, const char* func)
+{
+ log_info("%s:%d %s calloc(%u, %u)", file, line, func,
+ (unsigned) nmemb, (unsigned)size);
+ return unbound_stat_calloc(nmemb, size);
+}
+
+/** log to file where free was done */
+void unbound_stat_free_log(void *ptr, const char* file, int line,
+ const char* func)
+{
+ if(ptr && memcmp(ptr-8, &mem_special, sizeof(mem_special)) == 0) {
+ size_t s;
+ memcpy(&s, ptr-16, sizeof(s));
+ log_info("%s:%d %s free(%p) size %u",
+ file, line, func, ptr, (unsigned)s);
+ } else
+ log_info("%s:%d %s unmatched free(%p)", file, line, func, ptr);
+ unbound_stat_free(ptr);
+}
+
+/** log to file where alloc was done */
+void *unbound_stat_realloc_log(void *ptr, size_t size, const char* file,
+ int line, const char* func)
+{
+ log_info("%s:%d %s realloc(%p, %u)", file, line, func,
+ ptr, (unsigned)size);
+ return unbound_stat_realloc(ptr, size);
+}
+
+#endif /* UNBOUND_ALLOC_STATS */
+#ifdef UNBOUND_ALLOC_LITE
+#undef malloc
+#undef calloc
+#undef free
+#undef realloc
+/** length of prefix and suffix */
+static size_t lite_pad = 16;
+/** prefix value to check */
+static char* lite_pre = "checkfront123456";
+/** suffix value to check */
+static char* lite_post= "checkafter123456";
+
+void *unbound_stat_malloc_lite(size_t size, const char* file, int line,
+ const char* func)
+{
+ /* [prefix .. len .. actual data .. suffix] */
+ void* res = malloc(size+lite_pad*2+sizeof(size_t));
+ if(!res) return NULL;
+ memmove(res, lite_pre, lite_pad);
+ memmove(res+lite_pad, &size, sizeof(size_t));
+ memset(res+lite_pad+sizeof(size_t), 0x1a, size); /* init the memory */
+ memmove(res+lite_pad+size+sizeof(size_t), lite_post, lite_pad);
+ return res+lite_pad+sizeof(size_t);
+}
+
+void *unbound_stat_calloc_lite(size_t nmemb, size_t size, const char* file,
+ int line, const char* func)
+{
+ size_t req = nmemb * size;
+ void* res = malloc(req+lite_pad*2+sizeof(size_t));
+ if(!res) return NULL;
+ memmove(res, lite_pre, lite_pad);
+ memmove(res+lite_pad, &req, sizeof(size_t));
+ memset(res+lite_pad+sizeof(size_t), 0, req);
+ memmove(res+lite_pad+req+sizeof(size_t), lite_post, lite_pad);
+ return res+lite_pad+sizeof(size_t);
+}
+
+void unbound_stat_free_lite(void *ptr, const char* file, int line,
+ const char* func)
+{
+ void* real;
+ size_t orig = 0;
+ if(!ptr) return;
+ real = ptr-lite_pad-sizeof(size_t);
+ if(memcmp(real, lite_pre, lite_pad) != 0) {
+ log_err("free(): prefix failed %s:%d %s", file, line, func);
+ log_hex("prefix here", real, lite_pad);
+ log_hex(" should be", lite_pre, lite_pad);
+ fatal_exit("alloc assertion failed");
+ }
+ memmove(&orig, real+lite_pad, sizeof(size_t));
+ if(memcmp(real+lite_pad+orig+sizeof(size_t), lite_post, lite_pad)!=0){
+ log_err("free(): suffix failed %s:%d %s", file, line, func);
+ log_err("alloc size is %d", (int)orig);
+ log_hex("suffix here", real+lite_pad+orig+sizeof(size_t),
+ lite_pad);
+ log_hex(" should be", lite_post, lite_pad);
+ fatal_exit("alloc assertion failed");
+ }
+ memset(real, 0xdd, orig+lite_pad*2+sizeof(size_t)); /* mark it */
+ free(real);
+}
+
+void *unbound_stat_realloc_lite(void *ptr, size_t size, const char* file,
+ int line, const char* func)
+{
+ /* always free and realloc (no growing) */
+ void* real, *newa;
+ size_t orig = 0;
+ if(!ptr) {
+ /* like malloc() */
+ return unbound_stat_malloc_lite(size, file, line, func);
+ }
+ if(!size) {
+ /* like free() */
+ unbound_stat_free_lite(ptr, file, line, func);
+ return NULL;
+ }
+ /* change allocation size and copy */
+ real = ptr-lite_pad-sizeof(size_t);
+ if(memcmp(real, lite_pre, lite_pad) != 0) {
+ log_err("realloc(): prefix failed %s:%d %s", file, line, func);
+ log_hex("prefix here", real, lite_pad);
+ log_hex(" should be", lite_pre, lite_pad);
+ fatal_exit("alloc assertion failed");
+ }
+ memmove(&orig, real+lite_pad, sizeof(size_t));
+ if(memcmp(real+lite_pad+orig+sizeof(size_t), lite_post, lite_pad)!=0){
+ log_err("realloc(): suffix failed %s:%d %s", file, line, func);
+ log_err("alloc size is %d", (int)orig);
+ log_hex("suffix here", real+lite_pad+orig+sizeof(size_t),
+ lite_pad);
+ log_hex(" should be", lite_post, lite_pad);
+ fatal_exit("alloc assertion failed");
+ }
+ /* new alloc and copy over */
+ newa = unbound_stat_malloc_lite(size, file, line, func);
+ if(!newa)
+ return NULL;
+ if(orig < size)
+ memmove(newa, ptr, orig);
+ else memmove(newa, ptr, size);
+ memset(real, 0xdd, orig+lite_pad*2+sizeof(size_t)); /* mark it */
+ free(real);
+ return newa;
+}
+
+char* unbound_strdup_lite(const char* s, const char* file, int line,
+ const char* func)
+{
+ /* this routine is made to make sure strdup() uses the malloc_lite */
+ size_t l = strlen(s)+1;
+ char* n = (char*)unbound_stat_malloc_lite(l, file, line, func);
+ if(!n) return NULL;
+ memmove(n, s, l);
+ return n;
+}
+
+char* unbound_lite_wrapstr(char* s)
+{
+ char* n = unbound_strdup_lite(s, __FILE__, __LINE__, __func__);
+ free(s);
+ return n;
+}
+
+#undef sldns_pkt2wire
+sldns_status unbound_lite_pkt2wire(uint8_t **dest, const sldns_pkt *p,
+ size_t *size)
+{
+ uint8_t* md = NULL;
+ size_t ms = 0;
+ sldns_status s = sldns_pkt2wire(&md, p, &ms);
+ if(md) {
+ *dest = unbound_stat_malloc_lite(ms, __FILE__, __LINE__,
+ __func__);
+ *size = ms;
+ if(!*dest) { free(md); return LDNS_STATUS_MEM_ERR; }
+ memcpy(*dest, md, ms);
+ free(md);
+ } else {
+ *dest = NULL;
+ *size = 0;
+ }
+ return s;
+}
+
+#undef i2d_DSA_SIG
+int unbound_lite_i2d_DSA_SIG(DSA_SIG* dsasig, unsigned char** sig)
+{
+ unsigned char* n = NULL;
+ int r= i2d_DSA_SIG(dsasig, &n);
+ if(n) {
+ *sig = unbound_stat_malloc_lite((size_t)r, __FILE__, __LINE__,
+ __func__);
+ if(!*sig) return -1;
+ memcpy(*sig, n, (size_t)r);
+ free(n);
+ return r;
+ }
+ *sig = NULL;
+ return r;
+}
+
+#endif /* UNBOUND_ALLOC_LITE */
diff --git a/external/unbound/util/alloc.h b/external/unbound/util/alloc.h
new file mode 100644
index 000000000..ffd605c5d
--- /dev/null
+++ b/external/unbound/util/alloc.h
@@ -0,0 +1,217 @@
+/*
+ * util/alloc.h - memory allocation service.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 memory allocation functions.
+ *
+ * The reasons for this service are:
+ * o Avoid locking costs of getting global lock to call malloc().
+ * o The packed rrset type needs to be kept on special freelists,
+ * so that they are reused for other packet rrset allocations.
+ *
+ */
+
+#ifndef UTIL_ALLOC_H
+#define UTIL_ALLOC_H
+
+#include "util/locks.h"
+struct ub_packed_rrset_key;
+struct regional;
+
+/** The special type, packed rrset. Not allowed to be used for other memory */
+typedef struct ub_packed_rrset_key alloc_special_t;
+/** clean the special type. Pass pointer. */
+#define alloc_special_clean(x) (x)->id = 0;
+/** access next pointer. (in available spot). Pass pointer. */
+#define alloc_special_next(x) ((alloc_special_t*)((x)->entry.overflow_next))
+/** set next pointer. (in available spot). Pass pointers. */
+#define alloc_set_special_next(x, y) \
+ ((x)->entry.overflow_next) = (struct lruhash_entry*)(y);
+
+/** how many blocks to cache locally. */
+#define ALLOC_SPECIAL_MAX 10
+
+/**
+ * Structure that provides allocation. Use one per thread.
+ * The one on top has a NULL super pointer.
+ */
+struct alloc_cache {
+ /** lock, only used for the super. */
+ lock_quick_t lock;
+ /** global allocator above this one. NULL for none (malloc/free) */
+ struct alloc_cache* super;
+ /** singly linked lists of special type. These are free for use. */
+ alloc_special_t* quar;
+ /** number of items in quarantine. */
+ size_t num_quar;
+ /** thread number for id creation */
+ int thread_num;
+ /** next id number to pass out */
+ uint64_t next_id;
+ /** last id number possible */
+ uint64_t last_id;
+ /** what function to call to cleanup when last id is reached */
+ void (*cleanup)(void*);
+ /** user arg for cleanup */
+ void* cleanup_arg;
+
+ /** how many regional blocks to keep back max */
+ size_t max_reg_blocks;
+ /** how many regional blocks are kept now */
+ size_t num_reg_blocks;
+ /** linked list of regional blocks, using regional->next */
+ struct regional* reg_list;
+};
+
+/**
+ * Init alloc (zeroes the struct).
+ * @param alloc: this parameter is allocated by the caller.
+ * @param super: super to use (init that before with super_init).
+ * Pass this argument NULL to init the toplevel alloc structure.
+ * @param thread_num: thread number for id creation of special type.
+ */
+void alloc_init(struct alloc_cache* alloc, struct alloc_cache* super,
+ int thread_num);
+
+/**
+ * Free the alloc. Pushes all the cached items into the super structure.
+ * Or deletes them if alloc->super is NULL.
+ * Does not free the alloc struct itself (it was also allocated by caller).
+ * @param alloc: is almost zeroed on exit (except some stats).
+ */
+void alloc_clear(struct alloc_cache* alloc);
+
+/**
+ * Get a new special_t element.
+ * @param alloc: where to alloc it.
+ * @return: memory block. Will not return NULL (instead fatal_exit).
+ * The block is zeroed.
+ */
+alloc_special_t* alloc_special_obtain(struct alloc_cache* alloc);
+
+/**
+ * Return special_t back to pool.
+ * The block is cleaned up (zeroed) which also invalidates the ID inside.
+ * @param alloc: where to alloc it.
+ * @param mem: block to free.
+ */
+void alloc_special_release(struct alloc_cache* alloc, alloc_special_t* mem);
+
+/**
+ * Set ID number of special type to a fresh new ID number.
+ * In case of ID number overflow, the rrset cache has to be cleared.
+ * @param alloc: the alloc cache
+ * @return: fresh id is returned.
+ */
+uint64_t alloc_get_id(struct alloc_cache* alloc);
+
+/**
+ * Get memory size of alloc cache, alloc structure including special types.
+ * @param alloc: on what alloc.
+ * @return size in bytes.
+ */
+size_t alloc_get_mem(struct alloc_cache* alloc);
+
+/**
+ * Print debug information (statistics).
+ * @param alloc: on what alloc.
+ */
+void alloc_stats(struct alloc_cache* alloc);
+
+/**
+ * Get a new regional for query states
+ * @param alloc: where to alloc it.
+ * @return regional for use or NULL on alloc failure.
+ */
+struct regional* alloc_reg_obtain(struct alloc_cache* alloc);
+
+/**
+ * Put regional for query states back into alloc cache.
+ * @param alloc: where to alloc it.
+ * @param r: regional to put back.
+ */
+void alloc_reg_release(struct alloc_cache* alloc, struct regional* r);
+
+/**
+ * Set cleanup on ID overflow callback function. This should remove all
+ * RRset ID references from the program. Clear the caches.
+ * @param alloc: the alloc
+ * @param cleanup: the callback function, called as cleanup(arg).
+ * @param arg: user argument to callback function.
+ */
+void alloc_set_id_cleanup(struct alloc_cache* alloc, void (*cleanup)(void*),
+ void* arg);
+
+#ifdef UNBOUND_ALLOC_LITE
+# include <ldns/ldns.h>
+# include <ldns/packet.h>
+# ifdef HAVE_OPENSSL_SSL_H
+# include <openssl/ssl.h>
+# endif
+# define malloc(s) unbound_stat_malloc_lite(s, __FILE__, __LINE__, __func__)
+# define calloc(n,s) unbound_stat_calloc_lite(n, s, __FILE__, __LINE__, __func__)
+# define free(p) unbound_stat_free_lite(p, __FILE__, __LINE__, __func__)
+# define realloc(p,s) unbound_stat_realloc_lite(p, s, __FILE__, __LINE__, __func__)
+void *unbound_stat_malloc_lite(size_t size, const char* file, int line,
+ const char* func);
+void *unbound_stat_calloc_lite(size_t nmemb, size_t size, const char* file,
+ int line, const char* func);
+void unbound_stat_free_lite(void *ptr, const char* file, int line,
+ const char* func);
+void *unbound_stat_realloc_lite(void *ptr, size_t size, const char* file,
+ int line, const char* func);
+# ifdef strdup
+# undef strdup
+# endif
+# define strdup(s) unbound_strdup_lite(s, __FILE__, __LINE__, __func__)
+char* unbound_strdup_lite(const char* s, const char* file, int line,
+ const char* func);
+char* unbound_lite_wrapstr(char* s);
+# define sldns_rr2str(rr) unbound_lite_wrapstr(sldns_rr2str(rr))
+# define sldns_rdf2str(rdf) unbound_lite_wrapstr(sldns_rdf2str(rdf))
+# define sldns_rr_type2str(t) unbound_lite_wrapstr(sldns_rr_type2str(t))
+# define sldns_rr_class2str(c) unbound_lite_wrapstr(sldns_rr_class2str(c))
+# define sldns_rr_list2str(r) unbound_lite_wrapstr(sldns_rr_list2str(r))
+# define sldns_pkt2str(p) unbound_lite_wrapstr(sldns_pkt2str(p))
+# define sldns_pkt_rcode2str(r) unbound_lite_wrapstr(sldns_pkt_rcode2str(r))
+# define sldns_pkt2wire(a, r, s) unbound_lite_pkt2wire(a, r, s)
+sldns_status unbound_lite_pkt2wire(uint8_t **dest, const sldns_pkt *p, size_t *size);
+# define i2d_DSA_SIG(d, s) unbound_lite_i2d_DSA_SIG(d, s)
+int unbound_lite_i2d_DSA_SIG(DSA_SIG* dsasig, unsigned char** sig);
+#endif /* UNBOUND_ALLOC_LITE */
+
+#endif /* UTIL_ALLOC_H */
diff --git a/external/unbound/util/config_file.c b/external/unbound/util/config_file.c
new file mode 100644
index 000000000..96ec2f11d
--- /dev/null
+++ b/external/unbound/util/config_file.c
@@ -0,0 +1,1571 @@
+/*
+ * util/config_file.c - reads and stores the config file for unbound.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 for the config file.
+ */
+
+#include "config.h"
+#include <ctype.h>
+#include <stdarg.h>
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include "util/log.h"
+#include "util/configyyrename.h"
+#include "util/config_file.h"
+#include "util/configparser.h"
+#include "util/net_help.h"
+#include "util/data/msgparse.h"
+#include "util/module.h"
+#include "util/regional.h"
+#include "util/fptr_wlist.h"
+#include "util/data/dname.h"
+#include "ldns/wire2str.h"
+#include "ldns/parseutil.h"
+#ifdef HAVE_GLOB_H
+# include <glob.h>
+#endif
+
+/** global config during parsing */
+struct config_parser_state* cfg_parser = 0;
+
+/** init ports possible for use */
+static void init_outgoing_availports(int* array, int num);
+
+struct config_file*
+config_create(void)
+{
+ struct config_file* cfg;
+ cfg = (struct config_file*)calloc(1, sizeof(struct config_file));
+ if(!cfg)
+ return NULL;
+ /* the defaults if no config is present */
+ cfg->verbosity = 1;
+ cfg->stat_interval = 0;
+ cfg->stat_cumulative = 0;
+ cfg->stat_extended = 0;
+ cfg->num_threads = 1;
+ cfg->port = UNBOUND_DNS_PORT;
+ cfg->do_ip4 = 1;
+ cfg->do_ip6 = 1;
+ cfg->do_udp = 1;
+ cfg->do_tcp = 1;
+ cfg->tcp_upstream = 0;
+ cfg->ssl_service_key = NULL;
+ cfg->ssl_service_pem = NULL;
+ cfg->ssl_port = 443;
+ cfg->ssl_upstream = 0;
+ cfg->use_syslog = 1;
+ cfg->log_time_ascii = 0;
+ cfg->log_queries = 0;
+#ifndef USE_WINSOCK
+# ifdef USE_MINI_EVENT
+ /* select max 1024 sockets */
+ cfg->outgoing_num_ports = 960;
+ cfg->num_queries_per_thread = 512;
+# else
+ /* libevent can use many sockets */
+ cfg->outgoing_num_ports = 4096;
+ cfg->num_queries_per_thread = 1024;
+# endif
+ cfg->outgoing_num_tcp = 10;
+ cfg->incoming_num_tcp = 10;
+#else
+ cfg->outgoing_num_ports = 48; /* windows is limited in num fds */
+ cfg->num_queries_per_thread = 24;
+ cfg->outgoing_num_tcp = 2; /* leaves 64-52=12 for: 4if,1stop,thread4 */
+ cfg->incoming_num_tcp = 2;
+#endif
+ cfg->edns_buffer_size = 4096; /* 4k from rfc recommendation */
+ cfg->msg_buffer_size = 65552; /* 64 k + a small margin */
+ cfg->msg_cache_size = 4 * 1024 * 1024;
+ cfg->msg_cache_slabs = 4;
+ cfg->jostle_time = 200;
+ cfg->rrset_cache_size = 4 * 1024 * 1024;
+ cfg->rrset_cache_slabs = 4;
+ cfg->host_ttl = 900;
+ cfg->bogus_ttl = 60;
+ cfg->min_ttl = 0;
+ cfg->max_ttl = 3600 * 24;
+ cfg->prefetch = 0;
+ cfg->prefetch_key = 0;
+ cfg->infra_cache_slabs = 4;
+ cfg->infra_cache_numhosts = 10000;
+ cfg->delay_close = 0;
+ if(!(cfg->outgoing_avail_ports = (int*)calloc(65536, sizeof(int))))
+ goto error_exit;
+ init_outgoing_availports(cfg->outgoing_avail_ports, 65536);
+ if(!(cfg->username = strdup(UB_USERNAME))) goto error_exit;
+#ifdef HAVE_CHROOT
+ if(!(cfg->chrootdir = strdup(CHROOT_DIR))) goto error_exit;
+#endif
+ if(!(cfg->directory = strdup(RUN_DIR))) goto error_exit;
+ if(!(cfg->logfile = strdup(""))) goto error_exit;
+ if(!(cfg->pidfile = strdup(PIDFILE))) goto error_exit;
+ if(!(cfg->target_fetch_policy = strdup("3 2 1 0 0"))) goto error_exit;
+ cfg->donotqueryaddrs = NULL;
+ cfg->donotquery_localhost = 1;
+ cfg->root_hints = NULL;
+ cfg->do_daemonize = 1;
+ cfg->if_automatic = 0;
+ cfg->so_rcvbuf = 0;
+ cfg->so_sndbuf = 0;
+ cfg->so_reuseport = 0;
+ cfg->num_ifs = 0;
+ cfg->ifs = NULL;
+ cfg->num_out_ifs = 0;
+ cfg->out_ifs = NULL;
+ cfg->stubs = NULL;
+ cfg->forwards = NULL;
+ cfg->acls = NULL;
+ cfg->harden_short_bufsize = 0;
+ cfg->harden_large_queries = 0;
+ cfg->harden_glue = 1;
+ cfg->harden_dnssec_stripped = 1;
+ cfg->harden_below_nxdomain = 0;
+ cfg->harden_referral_path = 0;
+ cfg->use_caps_bits_for_id = 0;
+ cfg->private_address = NULL;
+ cfg->private_domain = NULL;
+ cfg->unwanted_threshold = 0;
+ cfg->hide_identity = 0;
+ cfg->hide_version = 0;
+ cfg->identity = NULL;
+ cfg->version = NULL;
+ cfg->auto_trust_anchor_file_list = NULL;
+ cfg->trust_anchor_file_list = NULL;
+ cfg->trust_anchor_list = NULL;
+ cfg->trusted_keys_file_list = NULL;
+ cfg->dlv_anchor_file = NULL;
+ cfg->dlv_anchor_list = NULL;
+ cfg->domain_insecure = NULL;
+ cfg->val_date_override = 0;
+ cfg->val_sig_skew_min = 3600; /* at least daylight savings trouble */
+ cfg->val_sig_skew_max = 86400; /* at most timezone settings trouble */
+ cfg->val_clean_additional = 1;
+ cfg->val_log_level = 0;
+ cfg->val_log_squelch = 0;
+ cfg->val_permissive_mode = 0;
+ cfg->ignore_cd = 0;
+ cfg->add_holddown = 30*24*3600;
+ cfg->del_holddown = 30*24*3600;
+ cfg->keep_missing = 366*24*3600; /* one year plus a little leeway */
+ cfg->key_cache_size = 4 * 1024 * 1024;
+ cfg->key_cache_slabs = 4;
+ cfg->neg_cache_size = 1 * 1024 * 1024;
+ cfg->local_zones = NULL;
+ cfg->local_zones_nodefault = NULL;
+ cfg->local_data = NULL;
+ cfg->unblock_lan_zones = 0;
+ cfg->python_script = NULL;
+ cfg->remote_control_enable = 0;
+ cfg->control_ifs = NULL;
+ cfg->control_port = UNBOUND_CONTROL_PORT;
+ cfg->minimal_responses = 0;
+ cfg->rrset_roundrobin = 0;
+ cfg->max_udp_size = 4096;
+ if(!(cfg->server_key_file = strdup(RUN_DIR"/unbound_server.key")))
+ goto error_exit;
+ if(!(cfg->server_cert_file = strdup(RUN_DIR"/unbound_server.pem")))
+ goto error_exit;
+ if(!(cfg->control_key_file = strdup(RUN_DIR"/unbound_control.key")))
+ goto error_exit;
+ if(!(cfg->control_cert_file = strdup(RUN_DIR"/unbound_control.pem")))
+ goto error_exit;
+
+ if(!(cfg->module_conf = strdup("validator iterator"))) goto error_exit;
+ if(!(cfg->val_nsec3_key_iterations =
+ strdup("1024 150 2048 500 4096 2500"))) goto error_exit;
+#if defined(DNSTAP_SOCKET_PATH)
+ if(!(cfg->dnstap_socket_path = strdup(DNSTAP_SOCKET_PATH)))
+ goto error_exit;
+#endif
+ return cfg;
+error_exit:
+ config_delete(cfg);
+ return NULL;
+}
+
+struct config_file* config_create_forlib(void)
+{
+ struct config_file* cfg = config_create();
+ if(!cfg) return NULL;
+ /* modifications for library use, less verbose, less memory */
+ free(cfg->chrootdir);
+ cfg->chrootdir = NULL;
+ cfg->verbosity = 0;
+ cfg->outgoing_num_ports = 16; /* in library use, this is 'reasonable'
+ and probably within the ulimit(maxfds) of the user */
+ cfg->outgoing_num_tcp = 2;
+ cfg->msg_cache_size = 1024*1024;
+ cfg->msg_cache_slabs = 1;
+ cfg->rrset_cache_size = 1024*1024;
+ cfg->rrset_cache_slabs = 1;
+ cfg->infra_cache_slabs = 1;
+ cfg->use_syslog = 0;
+ cfg->key_cache_size = 1024*1024;
+ cfg->key_cache_slabs = 1;
+ cfg->neg_cache_size = 100 * 1024;
+ cfg->donotquery_localhost = 0; /* allow, so that you can ask a
+ forward nameserver running on localhost */
+ cfg->val_log_level = 2; /* to fill why_bogus with */
+ cfg->val_log_squelch = 1;
+ return cfg;
+}
+
+/** check that the value passed is >= 0 */
+#define IS_NUMBER_OR_ZERO \
+ if(atoi(val) == 0 && strcmp(val, "0") != 0) return 0
+/** check that the value passed is > 0 */
+#define IS_NONZERO_NUMBER \
+ if(atoi(val) == 0) return 0
+/** check that the value passed is not 0 and a power of 2 */
+#define IS_POW2_NUMBER \
+ if(atoi(val) == 0 || !is_pow2((size_t)atoi(val))) return 0
+/** check that the value passed is yes or no */
+#define IS_YES_OR_NO \
+ if(strcmp(val, "yes") != 0 && strcmp(val, "no") != 0) return 0
+/** put integer_or_zero into variable */
+#define S_NUMBER_OR_ZERO(str, var) if(strcmp(opt, str) == 0) \
+ { IS_NUMBER_OR_ZERO; cfg->var = atoi(val); }
+/** put integer_nonzero into variable */
+#define S_NUMBER_NONZERO(str, var) if(strcmp(opt, str) == 0) \
+ { IS_NONZERO_NUMBER; cfg->var = atoi(val); }
+/** put integer_or_zero into unsigned */
+#define S_UNSIGNED_OR_ZERO(str, var) if(strcmp(opt, str) == 0) \
+ { IS_NUMBER_OR_ZERO; cfg->var = (unsigned)atoi(val); }
+/** put integer_or_zero into size_t */
+#define S_SIZET_OR_ZERO(str, var) if(strcmp(opt, str) == 0) \
+ { IS_NUMBER_OR_ZERO; cfg->var = (size_t)atoi(val); }
+/** put integer_nonzero into size_t */
+#define S_SIZET_NONZERO(str, var) if(strcmp(opt, str) == 0) \
+ { IS_NONZERO_NUMBER; cfg->var = (size_t)atoi(val); }
+/** put yesno into variable */
+#define S_YNO(str, var) if(strcmp(opt, str) == 0) \
+ { IS_YES_OR_NO; cfg->var = (strcmp(val, "yes") == 0); }
+/** put memsize into variable */
+#define S_MEMSIZE(str, var) if(strcmp(opt, str)==0) \
+ { return cfg_parse_memsize(val, &cfg->var); }
+/** put pow2 number into variable */
+#define S_POW2(str, var) if(strcmp(opt, str)==0) \
+ { IS_POW2_NUMBER; cfg->var = (size_t)atoi(val); }
+/** put string into variable */
+#define S_STR(str, var) if(strcmp(opt, str)==0) \
+ { free(cfg->var); return (cfg->var = strdup(val)) != NULL; }
+/** put string into strlist */
+#define S_STRLIST(str, var) if(strcmp(opt, str)==0) \
+ { return cfg_strlist_insert(&cfg->var, strdup(val)); }
+
+int config_set_option(struct config_file* cfg, const char* opt,
+ const char* val)
+{
+ S_NUMBER_OR_ZERO("verbosity:", verbosity)
+ else if(strcmp(opt, "statistics-interval:") == 0) {
+ if(strcmp(val, "0") == 0 || strcmp(val, "") == 0)
+ cfg->stat_interval = 0;
+ else if(atoi(val) == 0)
+ return 0;
+ else cfg->stat_interval = atoi(val);
+ } else if(strcmp(opt, "num_threads:") == 0) {
+ /* not supported, library must have 1 thread in bgworker */
+ return 0;
+ } else if(strcmp(opt, "outgoing-port-permit:") == 0) {
+ return cfg_mark_ports(val, 1,
+ cfg->outgoing_avail_ports, 65536);
+ } else if(strcmp(opt, "outgoing-port-avoid:") == 0) {
+ return cfg_mark_ports(val, 0,
+ cfg->outgoing_avail_ports, 65536);
+ } else if(strcmp(opt, "local-zone:") == 0) {
+ return cfg_parse_local_zone(cfg, val);
+ } else if(strcmp(opt, "val-override-date:") == 0) {
+ if(strcmp(val, "") == 0 || strcmp(val, "0") == 0) {
+ cfg->val_date_override = 0;
+ } else if(strlen(val) == 14) {
+ cfg->val_date_override = cfg_convert_timeval(val);
+ return cfg->val_date_override != 0;
+ } else {
+ if(atoi(val) == 0) return 0;
+ cfg->val_date_override = (uint32_t)atoi(val);
+ }
+ } else if(strcmp(opt, "local-data-ptr:") == 0) {
+ char* ptr = cfg_ptr_reverse((char*)opt);
+ return cfg_strlist_insert(&cfg->local_data, ptr);
+ } else if(strcmp(opt, "logfile:") == 0) {
+ cfg->use_syslog = 0;
+ free(cfg->logfile);
+ return (cfg->logfile = strdup(val)) != NULL;
+ }
+ else if(strcmp(opt, "log-time-ascii:") == 0)
+ { IS_YES_OR_NO; cfg->log_time_ascii = (strcmp(val, "yes") == 0);
+ log_set_time_asc(cfg->log_time_ascii); }
+ else S_SIZET_NONZERO("max-udp-size:", max_udp_size)
+ else S_YNO("use-syslog:", use_syslog)
+ else S_YNO("extended-statistics:", stat_extended)
+ else S_YNO("statistics-cumulative:", stat_cumulative)
+ else S_YNO("do-ip4:", do_ip4)
+ else S_YNO("do-ip6:", do_ip6)
+ else S_YNO("do-udp:", do_udp)
+ else S_YNO("do-tcp:", do_tcp)
+ else S_YNO("tcp-upstream:", tcp_upstream)
+ else S_YNO("ssl-upstream:", ssl_upstream)
+ else S_STR("ssl-service-key:", ssl_service_key)
+ else S_STR("ssl-service-pem:", ssl_service_pem)
+ else S_NUMBER_NONZERO("ssl-port:", ssl_port)
+ else S_YNO("interface-automatic:", if_automatic)
+ else S_YNO("do-daemonize:", do_daemonize)
+ else S_NUMBER_NONZERO("port:", port)
+ else S_NUMBER_NONZERO("outgoing-range:", outgoing_num_ports)
+ else S_SIZET_OR_ZERO("outgoing-num-tcp:", outgoing_num_tcp)
+ else S_SIZET_OR_ZERO("incoming-num-tcp:", incoming_num_tcp)
+ else S_SIZET_NONZERO("edns-buffer-size:", edns_buffer_size)
+ else S_SIZET_NONZERO("msg-buffer-size:", msg_buffer_size)
+ else S_MEMSIZE("msg-cache-size:", msg_cache_size)
+ else S_POW2("msg-cache-slabs:", msg_cache_slabs)
+ else S_SIZET_NONZERO("num-queries-per-thread:",num_queries_per_thread)
+ else S_SIZET_OR_ZERO("jostle-timeout:", jostle_time)
+ else S_MEMSIZE("so-rcvbuf:", so_rcvbuf)
+ else S_MEMSIZE("so-sndbuf:", so_sndbuf)
+ else S_YNO("so-reuseport:", so_reuseport)
+ else S_MEMSIZE("rrset-cache-size:", rrset_cache_size)
+ else S_POW2("rrset-cache-slabs:", rrset_cache_slabs)
+ else S_YNO("prefetch:", prefetch)
+ else S_YNO("prefetch-key:", prefetch_key)
+ else if(strcmp(opt, "cache-max-ttl:") == 0)
+ { IS_NUMBER_OR_ZERO; cfg->max_ttl = atoi(val); MAX_TTL=(time_t)cfg->max_ttl;}
+ else if(strcmp(opt, "cache-min-ttl:") == 0)
+ { IS_NUMBER_OR_ZERO; cfg->min_ttl = atoi(val); MIN_TTL=(time_t)cfg->min_ttl;}
+ else S_NUMBER_OR_ZERO("infra-host-ttl:", host_ttl)
+ else S_POW2("infra-cache-slabs:", infra_cache_slabs)
+ else S_SIZET_NONZERO("infra-cache-numhosts:", infra_cache_numhosts)
+ else S_NUMBER_OR_ZERO("delay-close:", delay_close)
+ else S_STR("chroot:", chrootdir)
+ else S_STR("username:", username)
+ else S_STR("directory:", directory)
+ else S_STR("pidfile:", pidfile)
+ else S_YNO("hide-identity:", hide_identity)
+ else S_YNO("hide-version:", hide_version)
+ else S_STR("identity:", identity)
+ else S_STR("version:", version)
+ else S_STRLIST("root-hints:", root_hints)
+ else S_STR("target-fetch-policy:", target_fetch_policy)
+ else S_YNO("harden-glue:", harden_glue)
+ else S_YNO("harden-short-bufsize:", harden_short_bufsize)
+ else S_YNO("harden-large-queries:", harden_large_queries)
+ else S_YNO("harden-dnssec-stripped:", harden_dnssec_stripped)
+ else S_YNO("harden-below-nxdomain:", harden_below_nxdomain)
+ else S_YNO("harden-referral-path:", harden_referral_path)
+ else S_YNO("use-caps-for-id", use_caps_bits_for_id)
+ else S_SIZET_OR_ZERO("unwanted-reply-threshold:", unwanted_threshold)
+ else S_STRLIST("private-address:", private_address)
+ else S_STRLIST("private-domain:", private_domain)
+ else S_YNO("do-not-query-localhost:", donotquery_localhost)
+ else S_STRLIST("do-not-query-address:", donotqueryaddrs)
+ else S_STRLIST("auto-trust-anchor-file:", auto_trust_anchor_file_list)
+ else S_STRLIST("trust-anchor-file:", trust_anchor_file_list)
+ else S_STRLIST("trust-anchor:", trust_anchor_list)
+ else S_STRLIST("trusted-keys-file:", trusted_keys_file_list)
+ else S_STR("dlv-anchor-file:", dlv_anchor_file)
+ else S_STRLIST("dlv-anchor:", dlv_anchor_list)
+ else S_STRLIST("domain-insecure:", domain_insecure)
+ else S_NUMBER_OR_ZERO("val-bogus-ttl:", bogus_ttl)
+ else S_YNO("val-clean-additional:", val_clean_additional)
+ else S_NUMBER_OR_ZERO("val-log-level:", val_log_level)
+ else S_YNO("val-log-squelch:", val_log_squelch)
+ else S_YNO("log-queries:", log_queries)
+ else S_YNO("val-permissive-mode:", val_permissive_mode)
+ else S_YNO("ignore-cd-flag:", ignore_cd)
+ else S_STR("val-nsec3-keysize-iterations:", val_nsec3_key_iterations)
+ else S_UNSIGNED_OR_ZERO("add-holddown:", add_holddown)
+ else S_UNSIGNED_OR_ZERO("del-holddown:", del_holddown)
+ else S_UNSIGNED_OR_ZERO("keep-missing:", keep_missing)
+ else S_MEMSIZE("key-cache-size:", key_cache_size)
+ else S_POW2("key-cache-slabs:", key_cache_slabs)
+ else S_MEMSIZE("neg-cache-size:", neg_cache_size)
+ else S_YNO("minimal-responses:", minimal_responses)
+ else S_YNO("rrset-roundrobin:", rrset_roundrobin)
+ else S_STRLIST("local-data:", local_data)
+ else S_YNO("unblock-lan-zones:", unblock_lan_zones)
+ else S_YNO("control-enable:", remote_control_enable)
+ else S_STRLIST("control-interface:", control_ifs)
+ else S_NUMBER_NONZERO("control-port:", control_port)
+ else S_STR("server-key-file:", server_key_file)
+ else S_STR("server-cert-file:", server_cert_file)
+ else S_STR("control-key-file:", control_key_file)
+ else S_STR("control-cert-file:", control_cert_file)
+ else S_STR("module-config:", module_conf)
+ else S_STR("python-script:", python_script)
+ /* val_sig_skew_min and max are copied into val_env during init,
+ * so this does not update val_env with set_option */
+ else if(strcmp(opt, "val-sig-skew-min:") == 0)
+ { IS_NUMBER_OR_ZERO; cfg->val_sig_skew_min = (int32_t)atoi(val); }
+ else if(strcmp(opt, "val-sig-skew-max:") == 0)
+ { IS_NUMBER_OR_ZERO; cfg->val_sig_skew_max = (int32_t)atoi(val); }
+ else if (strcmp(opt, "outgoing-interface:") == 0) {
+ char* d = strdup(val);
+ char** oi = (char**)malloc((cfg->num_out_ifs+1)*sizeof(char*));
+ if(!d || !oi) { free(d); free(oi); return -1; }
+ if(cfg->out_ifs && cfg->num_out_ifs) {
+ memmove(oi, cfg->out_ifs, cfg->num_out_ifs*sizeof(char*));
+ free(cfg->out_ifs);
+ }
+ oi[cfg->num_out_ifs++] = d;
+ cfg->out_ifs = oi;
+ } else {
+ /* unknown or unsupported (from the set_option interface):
+ * interface, outgoing-interface, access-control,
+ * stub-zone, name, stub-addr, stub-host, stub-prime
+ * forward-first, stub-first,
+ * forward-zone, name, forward-addr, forward-host */
+ return 0;
+ }
+ return 1;
+}
+
+void config_print_func(char* line, void* arg)
+{
+ FILE* f = (FILE*)arg;
+ (void)fprintf(f, "%s\n", line);
+}
+
+/** collate func arg */
+struct config_collate_arg {
+ /** list of result items */
+ struct config_strlist_head list;
+ /** if a malloc error occurred, 0 is OK */
+ int status;
+};
+
+void config_collate_func(char* line, void* arg)
+{
+ struct config_collate_arg* m = (struct config_collate_arg*)arg;
+ if(m->status)
+ return;
+ if(!cfg_strlist_append(&m->list, strdup(line)))
+ m->status = 1;
+}
+
+int config_get_option_list(struct config_file* cfg, const char* opt,
+ struct config_strlist** list)
+{
+ struct config_collate_arg m;
+ memset(&m, 0, sizeof(m));
+ *list = NULL;
+ if(!config_get_option(cfg, opt, config_collate_func, &m))
+ return 1;
+ if(m.status) {
+ config_delstrlist(m.list.first);
+ return 2;
+ }
+ *list = m.list.first;
+ return 0;
+}
+
+int
+config_get_option_collate(struct config_file* cfg, const char* opt, char** str)
+{
+ struct config_strlist* list = NULL;
+ int r;
+ *str = NULL;
+ if((r = config_get_option_list(cfg, opt, &list)) != 0)
+ return r;
+ *str = config_collate_cat(list);
+ config_delstrlist(list);
+ if(!*str) return 2;
+ return 0;
+}
+
+char*
+config_collate_cat(struct config_strlist* list)
+{
+ size_t total = 0, left;
+ struct config_strlist* s;
+ char *r, *w;
+ if(!list) /* no elements */
+ return strdup("");
+ if(list->next == NULL) /* one element , no newline at end. */
+ return strdup(list->str);
+ /* count total length */
+ for(s=list; s; s=s->next)
+ total += strlen(s->str) + 1; /* len + newline */
+ left = total+1; /* one extra for nul at end */
+ r = malloc(left);
+ if(!r)
+ return NULL;
+ w = r;
+ for(s=list; s; s=s->next) {
+ size_t this = strlen(s->str);
+ if(this+2 > left) { /* sanity check */
+ free(r);
+ return NULL;
+ }
+ snprintf(w, left, "%s\n", s->str);
+ this = strlen(w);
+ w += this;
+ left -= this;
+ }
+ return r;
+}
+
+/** compare and print decimal option */
+#define O_DEC(opt, str, var) if(strcmp(opt, str)==0) \
+ {snprintf(buf, len, "%d", (int)cfg->var); \
+ func(buf, arg);}
+/** compare and print unsigned option */
+#define O_UNS(opt, str, var) if(strcmp(opt, str)==0) \
+ {snprintf(buf, len, "%u", (unsigned)cfg->var); \
+ func(buf, arg);}
+/** compare and print yesno option */
+#define O_YNO(opt, str, var) if(strcmp(opt, str)==0) \
+ {func(cfg->var?"yes":"no", arg);}
+/** compare and print string option */
+#define O_STR(opt, str, var) if(strcmp(opt, str)==0) \
+ {func(cfg->var?cfg->var:"", arg);}
+/** compare and print array option */
+#define O_IFC(opt, str, num, arr) if(strcmp(opt, str)==0) \
+ {int i; for(i=0; i<cfg->num; i++) func(cfg->arr[i], arg);}
+/** compare and print memorysize option */
+#define O_MEM(opt, str, var) if(strcmp(opt, str)==0) { \
+ if(cfg->var > 1024*1024*1024) { \
+ size_t f=cfg->var/(size_t)1000000, b=cfg->var%(size_t)1000000; \
+ snprintf(buf, len, "%u%6.6u\n", (unsigned)f, (unsigned)b); \
+ } else snprintf(buf, len, "%u\n", (unsigned)cfg->var); \
+ func(buf, arg);}
+/** compare and print list option */
+#define O_LST(opt, name, lst) if(strcmp(opt, name)==0) { \
+ struct config_strlist* p = cfg->lst; \
+ for(p = cfg->lst; p; p = p->next) \
+ func(p->str, arg); \
+ }
+/** compare and print list option */
+#define O_LS2(opt, name, lst) if(strcmp(opt, name)==0) { \
+ struct config_str2list* p = cfg->lst; \
+ for(p = cfg->lst; p; p = p->next) \
+ snprintf(buf, len, "%s %s\n", p->str, p->str2); \
+ func(buf, arg); \
+ }
+
+int
+config_get_option(struct config_file* cfg, const char* opt,
+ void (*func)(char*,void*), void* arg)
+{
+ char buf[1024];
+ size_t len = sizeof(buf);
+ fptr_ok(fptr_whitelist_print_func(func));
+ O_DEC(opt, "verbosity", verbosity)
+ else O_DEC(opt, "statistics-interval", stat_interval)
+ else O_YNO(opt, "statistics-cumulative", stat_cumulative)
+ else O_YNO(opt, "extended-statistics", stat_extended)
+ else O_YNO(opt, "use-syslog", use_syslog)
+ else O_YNO(opt, "log-time-ascii", log_time_ascii)
+ else O_DEC(opt, "num-threads", num_threads)
+ else O_IFC(opt, "interface", num_ifs, ifs)
+ else O_IFC(opt, "outgoing-interface", num_out_ifs, out_ifs)
+ else O_YNO(opt, "interface-automatic", if_automatic)
+ else O_DEC(opt, "port", port)
+ else O_DEC(opt, "outgoing-range", outgoing_num_ports)
+ else O_DEC(opt, "outgoing-num-tcp", outgoing_num_tcp)
+ else O_DEC(opt, "incoming-num-tcp", incoming_num_tcp)
+ else O_DEC(opt, "edns-buffer-size", edns_buffer_size)
+ else O_DEC(opt, "msg-buffer-size", msg_buffer_size)
+ else O_MEM(opt, "msg-cache-size", msg_cache_size)
+ else O_DEC(opt, "msg-cache-slabs", msg_cache_slabs)
+ else O_DEC(opt, "num-queries-per-thread", num_queries_per_thread)
+ else O_UNS(opt, "jostle-timeout", jostle_time)
+ else O_MEM(opt, "so-rcvbuf", so_rcvbuf)
+ else O_MEM(opt, "so-sndbuf", so_sndbuf)
+ else O_YNO(opt, "so-reuseport", so_reuseport)
+ else O_MEM(opt, "rrset-cache-size", rrset_cache_size)
+ else O_DEC(opt, "rrset-cache-slabs", rrset_cache_slabs)
+ else O_YNO(opt, "prefetch-key", prefetch_key)
+ else O_YNO(opt, "prefetch", prefetch)
+ else O_DEC(opt, "cache-max-ttl", max_ttl)
+ else O_DEC(opt, "cache-min-ttl", min_ttl)
+ else O_DEC(opt, "infra-host-ttl", host_ttl)
+ else O_DEC(opt, "infra-cache-slabs", infra_cache_slabs)
+ else O_MEM(opt, "infra-cache-numhosts", infra_cache_numhosts)
+ else O_UNS(opt, "delay-close", delay_close)
+ else O_YNO(opt, "do-ip4", do_ip4)
+ else O_YNO(opt, "do-ip6", do_ip6)
+ else O_YNO(opt, "do-udp", do_udp)
+ else O_YNO(opt, "do-tcp", do_tcp)
+ else O_YNO(opt, "tcp-upstream", tcp_upstream)
+ else O_YNO(opt, "ssl-upstream", ssl_upstream)
+ else O_STR(opt, "ssl-service-key", ssl_service_key)
+ else O_STR(opt, "ssl-service-pem", ssl_service_pem)
+ else O_DEC(opt, "ssl-port", ssl_port)
+ else O_YNO(opt, "do-daemonize", do_daemonize)
+ else O_STR(opt, "chroot", chrootdir)
+ else O_STR(opt, "username", username)
+ else O_STR(opt, "directory", directory)
+ else O_STR(opt, "logfile", logfile)
+ else O_YNO(opt, "log-queries", log_queries)
+ else O_STR(opt, "pidfile", pidfile)
+ else O_YNO(opt, "hide-identity", hide_identity)
+ else O_YNO(opt, "hide-version", hide_version)
+ else O_STR(opt, "identity", identity)
+ else O_STR(opt, "version", version)
+ else O_STR(opt, "target-fetch-policy", target_fetch_policy)
+ else O_YNO(opt, "harden-short-bufsize", harden_short_bufsize)
+ else O_YNO(opt, "harden-large-queries", harden_large_queries)
+ else O_YNO(opt, "harden-glue", harden_glue)
+ else O_YNO(opt, "harden-dnssec-stripped", harden_dnssec_stripped)
+ else O_YNO(opt, "harden-below-nxdomain", harden_below_nxdomain)
+ else O_YNO(opt, "harden-referral-path", harden_referral_path)
+ else O_YNO(opt, "use-caps-for-id", use_caps_bits_for_id)
+ else O_DEC(opt, "unwanted-reply-threshold", unwanted_threshold)
+ else O_YNO(opt, "do-not-query-localhost", donotquery_localhost)
+ else O_STR(opt, "module-config", module_conf)
+ else O_STR(opt, "dlv-anchor-file", dlv_anchor_file)
+ else O_DEC(opt, "val-bogus-ttl", bogus_ttl)
+ else O_YNO(opt, "val-clean-additional", val_clean_additional)
+ else O_DEC(opt, "val-log-level", val_log_level)
+ else O_YNO(opt, "val-permissive-mode", val_permissive_mode)
+ else O_YNO(opt, "ignore-cd-flag", ignore_cd)
+ else O_STR(opt, "val-nsec3-keysize-iterations",val_nsec3_key_iterations)
+ else O_UNS(opt, "add-holddown", add_holddown)
+ else O_UNS(opt, "del-holddown", del_holddown)
+ else O_UNS(opt, "keep-missing", keep_missing)
+ else O_MEM(opt, "key-cache-size", key_cache_size)
+ else O_DEC(opt, "key-cache-slabs", key_cache_slabs)
+ else O_MEM(opt, "neg-cache-size", neg_cache_size)
+ else O_YNO(opt, "control-enable", remote_control_enable)
+ else O_DEC(opt, "control-port", control_port)
+ else O_STR(opt, "server-key-file", server_key_file)
+ else O_STR(opt, "server-cert-file", server_cert_file)
+ else O_STR(opt, "control-key-file", control_key_file)
+ else O_STR(opt, "control-cert-file", control_cert_file)
+ else O_LST(opt, "root-hints", root_hints)
+ else O_LS2(opt, "access-control", acls)
+ else O_LST(opt, "do-not-query-address", donotqueryaddrs)
+ else O_LST(opt, "private-address", private_address)
+ else O_LST(opt, "private-domain", private_domain)
+ else O_LST(opt, "auto-trust-anchor-file", auto_trust_anchor_file_list)
+ else O_LST(opt, "trust-anchor-file", trust_anchor_file_list)
+ else O_LST(opt, "trust-anchor", trust_anchor_list)
+ else O_LST(opt, "trusted-keys-file", trusted_keys_file_list)
+ else O_LST(opt, "dlv-anchor", dlv_anchor_list)
+ else O_LST(opt, "control-interface", control_ifs)
+ else O_LST(opt, "domain-insecure", domain_insecure)
+ else O_UNS(opt, "val-override-date", val_date_override)
+ else O_YNO(opt, "minimal-responses", minimal_responses)
+ else O_YNO(opt, "rrset-roundrobin", rrset_roundrobin)
+ else O_YNO(opt, "unblock-lan-zones", unblock_lan_zones)
+ else O_DEC(opt, "max-udp-size", max_udp_size)
+ else O_STR(opt, "python-script", python_script)
+ else O_DEC(opt, "val-sig-skew-min", val_sig_skew_min)
+ else O_DEC(opt, "val-sig-skew-max", val_sig_skew_max)
+ /* not here:
+ * outgoing-permit, outgoing-avoid - have list of ports
+ * local-zone - zones and nodefault variables
+ * local-data - see below
+ * local-data-ptr - converted to local-data entries
+ * stub-zone, name, stub-addr, stub-host, stub-prime
+ * forward-zone, name, forward-addr, forward-host
+ */
+ else return 0;
+ return 1;
+}
+
+/** initialize the global cfg_parser object */
+static void
+create_cfg_parser(struct config_file* cfg, char* filename, const char* chroot)
+{
+ static struct config_parser_state st;
+ cfg_parser = &st;
+ cfg_parser->filename = filename;
+ cfg_parser->line = 1;
+ cfg_parser->errors = 0;
+ cfg_parser->cfg = cfg;
+ cfg_parser->chroot = chroot;
+ init_cfg_parse();
+}
+
+int
+config_read(struct config_file* cfg, const char* filename, const char* chroot)
+{
+ FILE *in;
+ char *fname = (char*)filename;
+#ifdef HAVE_GLOB
+ glob_t g;
+ size_t i;
+ int r, flags;
+#endif
+ if(!fname)
+ return 1;
+
+ /* check for wildcards */
+#ifdef HAVE_GLOB
+ if(!(!strchr(fname, '*') && !strchr(fname, '?') && !strchr(fname, '[') &&
+ !strchr(fname, '{') && !strchr(fname, '~'))) {
+ verbose(VERB_QUERY, "wildcard found, processing %s", fname);
+ flags = 0
+#ifdef GLOB_ERR
+ | GLOB_ERR
+#endif
+#ifdef GLOB_NOSORT
+ | GLOB_NOSORT
+#endif
+#ifdef GLOB_BRACE
+ | GLOB_BRACE
+#endif
+#ifdef GLOB_TILDE
+ | GLOB_TILDE
+#endif
+ ;
+ memset(&g, 0, sizeof(g));
+ r = glob(fname, flags, NULL, &g);
+ if(r) {
+ /* some error */
+ globfree(&g);
+ if(r == GLOB_NOMATCH) {
+ verbose(VERB_QUERY, "include: "
+ "no matches for %s", fname);
+ return 1;
+ } else if(r == GLOB_NOSPACE) {
+ log_err("include: %s: "
+ "fnametern out of memory", fname);
+ } else if(r == GLOB_ABORTED) {
+ log_err("wildcard include: %s: expansion "
+ "aborted (%s)", fname, strerror(errno));
+ } else {
+ log_err("wildcard include: %s: expansion "
+ "failed (%s)", fname, strerror(errno));
+ }
+ /* ignore globs that yield no files */
+ return 1;
+ }
+ /* process files found, if any */
+ for(i=0; i<(size_t)g.gl_pathc; i++) {
+ if(!config_read(cfg, g.gl_pathv[i], chroot)) {
+ log_err("error reading wildcard "
+ "include: %s", g.gl_pathv[i]);
+ globfree(&g);
+ return 0;
+ }
+ }
+ globfree(&g);
+ return 1;
+ }
+#endif /* HAVE_GLOB */
+
+ in = fopen(fname, "r");
+ if(!in) {
+ log_err("Could not open %s: %s", fname, strerror(errno));
+ return 0;
+ }
+ create_cfg_parser(cfg, fname, chroot);
+ ub_c_in = in;
+ ub_c_parse();
+ fclose(in);
+
+ if(cfg_parser->errors != 0) {
+ fprintf(stderr, "read %s failed: %d errors in configuration file\n",
+ fname, cfg_parser->errors);
+ errno=EINVAL;
+ return 0;
+ }
+ return 1;
+}
+
+void
+config_delstrlist(struct config_strlist* p)
+{
+ struct config_strlist *np;
+ while(p) {
+ np = p->next;
+ free(p->str);
+ free(p);
+ p = np;
+ }
+}
+
+void
+config_deldblstrlist(struct config_str2list* p)
+{
+ struct config_str2list *np;
+ while(p) {
+ np = p->next;
+ free(p->str);
+ free(p->str2);
+ free(p);
+ p = np;
+ }
+}
+
+void
+config_delstubs(struct config_stub* p)
+{
+ struct config_stub* np;
+ while(p) {
+ np = p->next;
+ free(p->name);
+ config_delstrlist(p->hosts);
+ config_delstrlist(p->addrs);
+ free(p);
+ p = np;
+ }
+}
+
+void
+config_delete(struct config_file* cfg)
+{
+ if(!cfg) return;
+ free(cfg->username);
+ free(cfg->chrootdir);
+ free(cfg->directory);
+ free(cfg->logfile);
+ free(cfg->pidfile);
+ free(cfg->target_fetch_policy);
+ free(cfg->ssl_service_key);
+ free(cfg->ssl_service_pem);
+ if(cfg->ifs) {
+ int i;
+ for(i=0; i<cfg->num_ifs; i++)
+ free(cfg->ifs[i]);
+ free(cfg->ifs);
+ }
+ if(cfg->out_ifs) {
+ int i;
+ for(i=0; i<cfg->num_out_ifs; i++)
+ free(cfg->out_ifs[i]);
+ free(cfg->out_ifs);
+ }
+ config_delstubs(cfg->stubs);
+ config_delstubs(cfg->forwards);
+ config_delstrlist(cfg->donotqueryaddrs);
+ config_delstrlist(cfg->root_hints);
+ free(cfg->identity);
+ free(cfg->version);
+ free(cfg->module_conf);
+ free(cfg->outgoing_avail_ports);
+ config_delstrlist(cfg->private_address);
+ config_delstrlist(cfg->private_domain);
+ config_delstrlist(cfg->auto_trust_anchor_file_list);
+ config_delstrlist(cfg->trust_anchor_file_list);
+ config_delstrlist(cfg->trusted_keys_file_list);
+ config_delstrlist(cfg->trust_anchor_list);
+ config_delstrlist(cfg->domain_insecure);
+ free(cfg->dlv_anchor_file);
+ config_delstrlist(cfg->dlv_anchor_list);
+ config_deldblstrlist(cfg->acls);
+ free(cfg->val_nsec3_key_iterations);
+ config_deldblstrlist(cfg->local_zones);
+ config_delstrlist(cfg->local_zones_nodefault);
+ config_delstrlist(cfg->local_data);
+ config_delstrlist(cfg->control_ifs);
+ free(cfg->server_key_file);
+ free(cfg->server_cert_file);
+ free(cfg->control_key_file);
+ free(cfg->control_cert_file);
+ free(cfg->dnstap_socket_path);
+ free(cfg->dnstap_identity);
+ free(cfg->dnstap_version);
+ free(cfg);
+}
+
+static void
+init_outgoing_availports(int* a, int num)
+{
+ /* generated with make iana_update */
+ const int iana_assigned[] = {
+#include "util/iana_ports.inc"
+ -1 }; /* end marker to put behind trailing comma */
+
+ int i;
+ /* do not use <1024, that could be trouble with the system, privs */
+ for(i=1024; i<num; i++) {
+ a[i] = i;
+ }
+ /* create empty spot at 49152 to keep ephemeral ports available
+ * to other programs */
+ for(i=49152; i<49152+256; i++)
+ a[i] = 0;
+ /* pick out all the IANA assigned ports */
+ for(i=0; iana_assigned[i]!=-1; i++) {
+ if(iana_assigned[i] < num)
+ a[iana_assigned[i]] = 0;
+ }
+}
+
+int
+cfg_mark_ports(const char* str, int allow, int* avail, int num)
+{
+ char* mid = strchr(str, '-');
+ if(!mid) {
+ int port = atoi(str);
+ if(port == 0 && strcmp(str, "0") != 0) {
+ log_err("cannot parse port number '%s'", str);
+ return 0;
+ }
+ if(port < num)
+ avail[port] = (allow?port:0);
+ } else {
+ int i, low, high = atoi(mid+1);
+ char buf[16];
+ if(high == 0 && strcmp(mid+1, "0") != 0) {
+ log_err("cannot parse port number '%s'", mid+1);
+ return 0;
+ }
+ if( (int)(mid-str)+1 >= (int)sizeof(buf) ) {
+ log_err("cannot parse port number '%s'", str);
+ return 0;
+ }
+ if(mid > str)
+ memcpy(buf, str, (size_t)(mid-str));
+ buf[mid-str] = 0;
+ low = atoi(buf);
+ if(low == 0 && strcmp(buf, "0") != 0) {
+ log_err("cannot parse port number '%s'", buf);
+ return 0;
+ }
+ for(i=low; i<=high; i++) {
+ if(i < num)
+ avail[i] = (allow?i:0);
+ }
+ return 1;
+ }
+ return 1;
+}
+
+int
+cfg_scan_ports(int* avail, int num)
+{
+ int i;
+ int count = 0;
+ for(i=0; i<num; i++) {
+ if(avail[i])
+ count++;
+ }
+ return count;
+}
+
+int cfg_condense_ports(struct config_file* cfg, int** avail)
+{
+ int num = cfg_scan_ports(cfg->outgoing_avail_ports, 65536);
+ int i, at = 0;
+ *avail = NULL;
+ if(num == 0)
+ return 0;
+ *avail = (int*)malloc(sizeof(int)*num);
+ if(!*avail)
+ return 0;
+ for(i=0; i<65536; i++) {
+ if(cfg->outgoing_avail_ports[i])
+ (*avail)[at++] = cfg->outgoing_avail_ports[i];
+ }
+ log_assert(at == num);
+ return num;
+}
+
+/** print error with file and line number */
+static void ub_c_error_va_list(const char *fmt, va_list args)
+{
+ cfg_parser->errors++;
+ fprintf(stderr, "%s:%d: error: ", cfg_parser->filename,
+ cfg_parser->line);
+ vfprintf(stderr, fmt, args);
+ fprintf(stderr, "\n");
+}
+
+/** print error with file and line number */
+void ub_c_error_msg(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ ub_c_error_va_list(fmt, args);
+ va_end(args);
+}
+
+void ub_c_error(const char *str)
+{
+ cfg_parser->errors++;
+ fprintf(stderr, "%s:%d: error: %s\n", cfg_parser->filename,
+ cfg_parser->line, str);
+}
+
+int ub_c_wrap(void)
+{
+ return 1;
+}
+
+int cfg_strlist_append(struct config_strlist_head* list, char* item)
+{
+ struct config_strlist *s;
+ if(!item || !list)
+ return 0;
+ s = (struct config_strlist*)calloc(1, sizeof(struct config_strlist));
+ if(!s)
+ return 0;
+ s->str = item;
+ s->next = NULL;
+ if(list->last)
+ list->last->next = s;
+ else
+ list->first = s;
+ list->last = s;
+ return 1;
+}
+
+int
+cfg_strlist_insert(struct config_strlist** head, char* item)
+{
+ struct config_strlist *s;
+ if(!item || !head)
+ return 0;
+ s = (struct config_strlist*)calloc(1, sizeof(struct config_strlist));
+ if(!s)
+ return 0;
+ s->str = item;
+ s->next = *head;
+ *head = s;
+ return 1;
+}
+
+int
+cfg_str2list_insert(struct config_str2list** head, char* item, char* i2)
+{
+ struct config_str2list *s;
+ if(!item || !i2 || !head)
+ return 0;
+ s = (struct config_str2list*)calloc(1, sizeof(struct config_str2list));
+ if(!s)
+ return 0;
+ s->str = item;
+ s->str2 = i2;
+ s->next = *head;
+ *head = s;
+ return 1;
+}
+
+time_t
+cfg_convert_timeval(const char* str)
+{
+ time_t t;
+ struct tm tm;
+ memset(&tm, 0, sizeof(tm));
+ if(strlen(str) < 14)
+ return 0;
+ if(sscanf(str, "%4d%2d%2d%2d%2d%2d", &tm.tm_year, &tm.tm_mon,
+ &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec) != 6)
+ return 0;
+ tm.tm_year -= 1900;
+ tm.tm_mon--;
+ /* Check values */
+ if (tm.tm_year < 70) return 0;
+ if (tm.tm_mon < 0 || tm.tm_mon > 11) return 0;
+ if (tm.tm_mday < 1 || tm.tm_mday > 31) return 0;
+ if (tm.tm_hour < 0 || tm.tm_hour > 23) return 0;
+ if (tm.tm_min < 0 || tm.tm_min > 59) return 0;
+ if (tm.tm_sec < 0 || tm.tm_sec > 59) return 0;
+ /* call ldns conversion function */
+ t = sldns_mktime_from_utc(&tm);
+ return t;
+}
+
+int
+cfg_count_numbers(const char* s)
+{
+ /* format ::= (sp num)+ sp */
+ /* num ::= [-](0-9)+ */
+ /* sp ::= (space|tab)* */
+ int num = 0;
+ while(*s) {
+ while(*s && isspace((int)*s))
+ s++;
+ if(!*s) /* end of string */
+ break;
+ if(*s == '-')
+ s++;
+ if(!*s) /* only - not allowed */
+ return 0;
+ if(!isdigit((int)*s)) /* bad character */
+ return 0;
+ while(*s && isdigit((int)*s))
+ s++;
+ num++;
+ }
+ return num;
+}
+
+/** all digit number */
+static int isalldigit(const char* str, size_t l)
+{
+ size_t i;
+ for(i=0; i<l; i++)
+ if(!isdigit(str[i]))
+ return 0;
+ return 1;
+}
+
+int
+cfg_parse_memsize(const char* str, size_t* res)
+{
+ size_t len;
+ size_t mult = 1;
+ if(!str || (len=(size_t)strlen(str)) == 0) {
+ log_err("not a size: '%s'", str);
+ return 0;
+ }
+ if(isalldigit(str, len)) {
+ *res = (size_t)atol(str);
+ return 1;
+ }
+ /* check appended num */
+ while(len>0 && str[len-1]==' ')
+ len--;
+ if(len > 1 && str[len-1] == 'b')
+ len--;
+ else if(len > 1 && str[len-1] == 'B')
+ len--;
+
+ if(len > 1 && tolower(str[len-1]) == 'g')
+ mult = 1024*1024*1024;
+ else if(len > 1 && tolower(str[len-1]) == 'm')
+ mult = 1024*1024;
+ else if(len > 1 && tolower(str[len-1]) == 'k')
+ mult = 1024;
+ else if(len > 0 && isdigit(str[len-1]))
+ mult = 1;
+ else {
+ log_err("unknown size specifier: '%s'", str);
+ return 0;
+ }
+ while(len>1 && str[len-2]==' ')
+ len--;
+
+ if(!isalldigit(str, len-1)) {
+ log_err("unknown size specifier: '%s'", str);
+ return 0;
+ }
+ *res = ((size_t)atol(str)) * mult;
+ return 1;
+}
+
+void
+config_apply(struct config_file* config)
+{
+ MAX_TTL = (time_t)config->max_ttl;
+ MIN_TTL = (time_t)config->min_ttl;
+ EDNS_ADVERTISED_SIZE = (uint16_t)config->edns_buffer_size;
+ MINIMAL_RESPONSES = config->minimal_responses;
+ RRSET_ROUNDROBIN = config->rrset_roundrobin;
+ log_set_time_asc(config->log_time_ascii);
+}
+
+/**
+ * Calculate string length of full pathname in original filesys
+ * @param fname: the path name to convert.
+ * Must not be null or empty.
+ * @param cfg: config struct for chroot and chdir (if set).
+ * @param use_chdir: if false, only chroot is applied.
+ * @return length of string.
+ * remember to allocate one more for 0 at end in mallocs.
+ */
+static size_t
+strlen_after_chroot(const char* fname, struct config_file* cfg, int use_chdir)
+{
+ size_t len = 0;
+ int slashit = 0;
+ if(cfg->chrootdir && cfg->chrootdir[0] &&
+ strncmp(cfg->chrootdir, fname, strlen(cfg->chrootdir)) == 0) {
+ /* already full pathname, return it */
+ return strlen(fname);
+ }
+ /* chroot */
+ if(cfg->chrootdir && cfg->chrootdir[0]) {
+ /* start with chrootdir */
+ len += strlen(cfg->chrootdir);
+ slashit = 1;
+ }
+ /* chdir */
+#ifdef UB_ON_WINDOWS
+ if(fname[0] != 0 && fname[1] == ':') {
+ /* full path, no chdir */
+ } else
+#endif
+ if(fname[0] == '/' || !use_chdir) {
+ /* full path, no chdir */
+ } else if(cfg->directory && cfg->directory[0]) {
+ /* prepend chdir */
+ if(slashit && cfg->directory[0] != '/')
+ len++;
+ if(cfg->chrootdir && cfg->chrootdir[0] &&
+ strncmp(cfg->chrootdir, cfg->directory,
+ strlen(cfg->chrootdir)) == 0)
+ len += strlen(cfg->directory)-strlen(cfg->chrootdir);
+ else len += strlen(cfg->directory);
+ slashit = 1;
+ }
+ /* fname */
+ if(slashit && fname[0] != '/')
+ len++;
+ len += strlen(fname);
+ return len;
+}
+
+char*
+fname_after_chroot(const char* fname, struct config_file* cfg, int use_chdir)
+{
+ size_t len = strlen_after_chroot(fname, cfg, use_chdir)+1;
+ int slashit = 0;
+ char* buf = (char*)malloc(len);
+ if(!buf)
+ return NULL;
+ buf[0] = 0;
+ /* is fname already in chroot ? */
+ if(cfg->chrootdir && cfg->chrootdir[0] &&
+ strncmp(cfg->chrootdir, fname, strlen(cfg->chrootdir)) == 0) {
+ /* already full pathname, return it */
+ (void)strlcpy(buf, fname, len);
+ buf[len-1] = 0;
+ return buf;
+ }
+ /* chroot */
+ if(cfg->chrootdir && cfg->chrootdir[0]) {
+ /* start with chrootdir */
+ (void)strlcpy(buf, cfg->chrootdir, len);
+ slashit = 1;
+ }
+#ifdef UB_ON_WINDOWS
+ if(fname[0] != 0 && fname[1] == ':') {
+ /* full path, no chdir */
+ } else
+#endif
+ /* chdir */
+ if(fname[0] == '/' || !use_chdir) {
+ /* full path, no chdir */
+ } else if(cfg->directory && cfg->directory[0]) {
+ /* prepend chdir */
+ if(slashit && cfg->directory[0] != '/')
+ (void)strlcat(buf, "/", len);
+ /* is the directory already in the chroot? */
+ if(cfg->chrootdir && cfg->chrootdir[0] &&
+ strncmp(cfg->chrootdir, cfg->directory,
+ strlen(cfg->chrootdir)) == 0)
+ (void)strlcat(buf, cfg->directory+strlen(cfg->chrootdir),
+ len);
+ else (void)strlcat(buf, cfg->directory, len);
+ slashit = 1;
+ }
+ /* fname */
+ if(slashit && fname[0] != '/')
+ (void)strlcat(buf, "/", len);
+ (void)strlcat(buf, fname, len);
+ buf[len-1] = 0;
+ return buf;
+}
+
+/** return next space character in string */
+static char* next_space_pos(const char* str)
+{
+ char* sp = strchr(str, ' ');
+ char* tab = strchr(str, '\t');
+ if(!tab && !sp)
+ return NULL;
+ if(!sp) return tab;
+ if(!tab) return sp;
+ return (sp<tab)?sp:tab;
+}
+
+/** return last space character in string */
+static char* last_space_pos(const char* str)
+{
+ char* sp = strrchr(str, ' ');
+ char* tab = strrchr(str, '\t');
+ if(!tab && !sp)
+ return NULL;
+ if(!sp) return tab;
+ if(!tab) return sp;
+ return (sp>tab)?sp:tab;
+}
+
+int
+cfg_parse_local_zone(struct config_file* cfg, const char* val)
+{
+ const char *type, *name_end, *name;
+ char buf[256];
+
+ /* parse it as: [zone_name] [between stuff] [zone_type] */
+ name = val;
+ while(*name && isspace(*name))
+ name++;
+ if(!*name) {
+ log_err("syntax error: too short: %s", val);
+ return 0;
+ }
+ name_end = next_space_pos(name);
+ if(!name_end || !*name_end) {
+ log_err("syntax error: expected zone type: %s", val);
+ return 0;
+ }
+ if (name_end - name > 255) {
+ log_err("syntax error: bad zone name: %s", val);
+ return 0;
+ }
+ (void)strlcpy(buf, name, sizeof(buf));
+ buf[name_end-name] = '\0';
+
+ type = last_space_pos(name_end);
+ while(type && *type && isspace(*type))
+ type++;
+ if(!type || !*type) {
+ log_err("syntax error: expected zone type: %s", val);
+ return 0;
+ }
+
+ if(strcmp(type, "nodefault")==0) {
+ return cfg_strlist_insert(&cfg->local_zones_nodefault,
+ strdup(name));
+ } else {
+ return cfg_str2list_insert(&cfg->local_zones, strdup(buf),
+ strdup(type));
+ }
+}
+
+char* cfg_ptr_reverse(char* str)
+{
+ char* ip, *ip_end;
+ char* name;
+ char* result;
+ char buf[1024];
+ struct sockaddr_storage addr;
+ socklen_t addrlen;
+
+ /* parse it as: [IP] [between stuff] [name] */
+ ip = str;
+ while(*ip && isspace(*ip))
+ ip++;
+ if(!*ip) {
+ log_err("syntax error: too short: %s", str);
+ return NULL;
+ }
+ ip_end = next_space_pos(ip);
+ if(!ip_end || !*ip_end) {
+ log_err("syntax error: expected name: %s", str);
+ return NULL;
+ }
+
+ name = last_space_pos(ip_end);
+ if(!name || !*name) {
+ log_err("syntax error: expected name: %s", str);
+ return NULL;
+ }
+
+ sscanf(ip, "%100s", buf);
+ buf[sizeof(buf)-1]=0;
+
+ if(!ipstrtoaddr(buf, UNBOUND_DNS_PORT, &addr, &addrlen)) {
+ log_err("syntax error: cannot parse address: %s", str);
+ return NULL;
+ }
+
+ /* reverse IPv4:
+ * ddd.ddd.ddd.ddd.in-addr-arpa.
+ * IPv6: (h.){32}.ip6.arpa. */
+
+ if(addr_is_ip6(&addr, addrlen)) {
+ uint8_t ad[16];
+ const char* hex = "0123456789abcdef";
+ char *p = buf;
+ int i;
+ memmove(ad, &((struct sockaddr_in6*)&addr)->sin6_addr,
+ sizeof(ad));
+ for(i=15; i>=0; i--) {
+ uint8_t b = ad[i];
+ *p++ = hex[ (b&0x0f) ];
+ *p++ = '.';
+ *p++ = hex[ (b&0xf0) >> 4 ];
+ *p++ = '.';
+ }
+ snprintf(buf+16*4, sizeof(buf)-16*4, "ip6.arpa. ");
+ } else {
+ uint8_t ad[4];
+ memmove(ad, &((struct sockaddr_in*)&addr)->sin_addr,
+ sizeof(ad));
+ snprintf(buf, sizeof(buf), "%u.%u.%u.%u.in-addr.arpa. ",
+ (unsigned)ad[3], (unsigned)ad[2],
+ (unsigned)ad[1], (unsigned)ad[0]);
+ }
+
+ /* printed the reverse address, now the between goop and name on end */
+ while(*ip_end && isspace(*ip_end))
+ ip_end++;
+ if(name>ip_end) {
+ snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%.*s",
+ (int)(name-ip_end), ip_end);
+ }
+ snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), " PTR %s", name);
+
+ result = strdup(buf);
+ if(!result) {
+ log_err("out of memory parsing %s", str);
+ return NULL;
+ }
+ return result;
+}
+
+#ifdef UB_ON_WINDOWS
+char*
+w_lookup_reg_str(const char* key, const char* name)
+{
+ HKEY hk = NULL;
+ DWORD type = 0;
+ BYTE buf[1024];
+ DWORD len = (DWORD)sizeof(buf);
+ LONG ret;
+ char* result = NULL;
+ ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hk);
+ if(ret == ERROR_FILE_NOT_FOUND)
+ return NULL; /* key does not exist */
+ else if(ret != ERROR_SUCCESS) {
+ log_err("RegOpenKeyEx failed");
+ return NULL;
+ }
+ ret = RegQueryValueEx(hk, (LPCTSTR)name, 0, &type, buf, &len);
+ if(RegCloseKey(hk))
+ log_err("RegCloseKey");
+ if(ret == ERROR_FILE_NOT_FOUND)
+ return NULL; /* name does not exist */
+ else if(ret != ERROR_SUCCESS) {
+ log_err("RegQueryValueEx failed");
+ return NULL;
+ }
+ if(type == REG_SZ || type == REG_MULTI_SZ || type == REG_EXPAND_SZ) {
+ buf[sizeof(buf)-1] = 0;
+ buf[sizeof(buf)-2] = 0; /* for multi_sz */
+ result = strdup((char*)buf);
+ if(!result) log_err("out of memory");
+ }
+ return result;
+}
+#endif /* UB_ON_WINDOWS */
+
+void errinf(struct module_qstate* qstate, const char* str)
+{
+ struct config_strlist* p;
+ if(qstate->env->cfg->val_log_level < 2 || !str)
+ return;
+ p = (struct config_strlist*)regional_alloc(qstate->region, sizeof(*p));
+ if(!p) {
+ log_err("malloc failure in validator-error-info string");
+ return;
+ }
+ p->next = NULL;
+ p->str = regional_strdup(qstate->region, str);
+ if(!p->str) {
+ log_err("malloc failure in validator-error-info string");
+ return;
+ }
+ /* add at end */
+ if(qstate->errinf) {
+ struct config_strlist* q = qstate->errinf;
+ while(q->next)
+ q = q->next;
+ q->next = p;
+ } else qstate->errinf = p;
+}
+
+void errinf_origin(struct module_qstate* qstate, struct sock_list *origin)
+{
+ struct sock_list* p;
+ if(qstate->env->cfg->val_log_level < 2)
+ return;
+ for(p=origin; p; p=p->next) {
+ char buf[256];
+ if(p == origin)
+ snprintf(buf, sizeof(buf), "from ");
+ else snprintf(buf, sizeof(buf), "and ");
+ if(p->len == 0)
+ snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf),
+ "cache");
+ else
+ addr_to_str(&p->addr, p->len, buf+strlen(buf),
+ sizeof(buf)-strlen(buf));
+ errinf(qstate, buf);
+ }
+}
+
+char* errinf_to_str(struct module_qstate* qstate)
+{
+ char buf[20480];
+ char* p = buf;
+ size_t left = sizeof(buf);
+ struct config_strlist* s;
+ char dname[LDNS_MAX_DOMAINLEN+1];
+ char t[16], c[16];
+ sldns_wire2str_type_buf(qstate->qinfo.qtype, t, sizeof(t));
+ sldns_wire2str_class_buf(qstate->qinfo.qclass, c, sizeof(c));
+ dname_str(qstate->qinfo.qname, dname);
+ snprintf(p, left, "validation failure <%s %s %s>:", dname, t, c);
+ left -= strlen(p); p += strlen(p);
+ if(!qstate->errinf)
+ snprintf(p, left, " misc failure");
+ else for(s=qstate->errinf; s; s=s->next) {
+ snprintf(p, left, " %s", s->str);
+ left -= strlen(p); p += strlen(p);
+ }
+ p = strdup(buf);
+ if(!p)
+ log_err("malloc failure in errinf_to_str");
+ return p;
+}
+
+void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr)
+{
+ char buf[1024];
+ char dname[LDNS_MAX_DOMAINLEN+1];
+ char t[16], c[16];
+ if(qstate->env->cfg->val_log_level < 2 || !rr)
+ return;
+ sldns_wire2str_type_buf(ntohs(rr->rk.type), t, sizeof(t));
+ sldns_wire2str_class_buf(ntohs(rr->rk.rrset_class), c, sizeof(c));
+ dname_str(rr->rk.dname, dname);
+ snprintf(buf, sizeof(buf), "for <%s %s %s>", dname, t, c);
+ errinf(qstate, buf);
+}
+
+void errinf_dname(struct module_qstate* qstate, const char* str, uint8_t* dname)
+{
+ char b[1024];
+ char buf[LDNS_MAX_DOMAINLEN+1];
+ if(qstate->env->cfg->val_log_level < 2 || !str || !dname)
+ return;
+ dname_str(dname, buf);
+ snprintf(b, sizeof(b), "%s %s", str, buf);
+ errinf(qstate, b);
+}
diff --git a/external/unbound/util/config_file.h b/external/unbound/util/config_file.h
new file mode 100644
index 000000000..49ffbdde4
--- /dev/null
+++ b/external/unbound/util/config_file.h
@@ -0,0 +1,704 @@
+/*
+ * util/config_file.h - reads and stores the config file for unbound.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 for the config file.
+ */
+
+#ifndef UTIL_CONFIG_FILE_H
+#define UTIL_CONFIG_FILE_H
+struct config_stub;
+struct config_strlist;
+struct config_str2list;
+struct module_qstate;
+struct sock_list;
+struct ub_packed_rrset_key;
+
+/**
+ * The configuration options.
+ * Strings are malloced.
+ */
+struct config_file {
+ /** verbosity level as specified in the config file */
+ int verbosity;
+
+ /** statistics interval (in seconds) */
+ int stat_interval;
+ /** if false, statistics values are reset after printing them */
+ int stat_cumulative;
+ /** if true, the statistics are kept in greater detail */
+ int stat_extended;
+
+ /** number of threads to create */
+ int num_threads;
+
+ /** port on which queries are answered. */
+ int port;
+ /** do ip4 query support. */
+ int do_ip4;
+ /** do ip6 query support. */
+ int do_ip6;
+ /** do udp query support. */
+ int do_udp;
+ /** do tcp query support. */
+ int do_tcp;
+ /** tcp upstream queries (no UDP upstream queries) */
+ int tcp_upstream;
+
+ /** private key file for dnstcp-ssl service (enabled if not NULL) */
+ char* ssl_service_key;
+ /** public key file for dnstcp-ssl service */
+ char* ssl_service_pem;
+ /** port on which to provide ssl service */
+ int ssl_port;
+ /** if outgoing tcp connections use SSL */
+ int ssl_upstream;
+
+ /** outgoing port range number of ports (per thread) */
+ int outgoing_num_ports;
+ /** number of outgoing tcp buffers per (per thread) */
+ size_t outgoing_num_tcp;
+ /** number of incoming tcp buffers per (per thread) */
+ size_t incoming_num_tcp;
+ /** allowed udp port numbers, array with 0 if not allowed */
+ int* outgoing_avail_ports;
+
+ /** EDNS buffer size to use */
+ size_t edns_buffer_size;
+ /** number of bytes buffer size for DNS messages */
+ size_t msg_buffer_size;
+ /** size of the message cache */
+ size_t msg_cache_size;
+ /** slabs in the message cache. */
+ size_t msg_cache_slabs;
+ /** number of queries every thread can service */
+ size_t num_queries_per_thread;
+ /** number of msec to wait before items can be jostled out */
+ size_t jostle_time;
+ /** size of the rrset cache */
+ size_t rrset_cache_size;
+ /** slabs in the rrset cache */
+ size_t rrset_cache_slabs;
+ /** host cache ttl in seconds */
+ int host_ttl;
+ /** number of slabs in the infra host cache */
+ size_t infra_cache_slabs;
+ /** max number of hosts in the infra cache */
+ size_t infra_cache_numhosts;
+ /** delay close of udp-timeouted ports, if 0 no delayclose. in msec */
+ int delay_close;
+
+ /** the target fetch policy for the iterator */
+ char* target_fetch_policy;
+
+ /** automatic interface for incoming messages. Uses ipv6 remapping,
+ * and recvmsg/sendmsg ancillary data to detect interfaces, boolean */
+ int if_automatic;
+ /** SO_RCVBUF size to set on port 53 UDP socket */
+ size_t so_rcvbuf;
+ /** SO_SNDBUF size to set on port 53 UDP socket */
+ size_t so_sndbuf;
+ /** SO_REUSEPORT requested on port 53 sockets */
+ int so_reuseport;
+
+ /** number of interfaces to open. If 0 default all interfaces. */
+ int num_ifs;
+ /** interface description strings (IP addresses) */
+ char **ifs;
+
+ /** number of outgoing interfaces to open.
+ * If 0 default all interfaces. */
+ int num_out_ifs;
+ /** outgoing interface description strings (IP addresses) */
+ char **out_ifs;
+
+ /** the root hints */
+ struct config_strlist* root_hints;
+ /** the stub definitions, linked list */
+ struct config_stub* stubs;
+ /** the forward zone definitions, linked list */
+ struct config_stub* forwards;
+ /** list of donotquery addresses, linked list */
+ struct config_strlist* donotqueryaddrs;
+ /** list of access control entries, linked list */
+ struct config_str2list* acls;
+ /** use default localhost donotqueryaddr entries */
+ int donotquery_localhost;
+
+ /** harden against very small edns buffer sizes */
+ int harden_short_bufsize;
+ /** harden against very large query sizes */
+ int harden_large_queries;
+ /** harden against spoofed glue (out of zone data) */
+ int harden_glue;
+ /** harden against receiving no DNSSEC data for trust anchor */
+ int harden_dnssec_stripped;
+ /** harden against queries that fall under known nxdomain names */
+ int harden_below_nxdomain;
+ /** harden the referral path, query for NS,A,AAAA and validate */
+ int harden_referral_path;
+ /** use 0x20 bits in query as random ID bits */
+ int use_caps_bits_for_id;
+ /** strip away these private addrs from answers, no DNS Rebinding */
+ struct config_strlist* private_address;
+ /** allow domain (and subdomains) to use private address space */
+ struct config_strlist* private_domain;
+ /** what threshold for unwanted action. */
+ size_t unwanted_threshold;
+ /** the number of seconds maximal TTL used for RRsets and messages */
+ int max_ttl;
+ /** the number of seconds minimum TTL used for RRsets and messages */
+ int min_ttl;
+ /** if prefetching of messages should be performed. */
+ int prefetch;
+ /** if prefetching of DNSKEYs should be performed. */
+ int prefetch_key;
+
+ /** chrootdir, if not "" or chroot will be done */
+ char* chrootdir;
+ /** username to change to, if not "". */
+ char* username;
+ /** working directory */
+ char* directory;
+ /** filename to log to. */
+ char* logfile;
+ /** pidfile to write pid to. */
+ char* pidfile;
+
+ /** should log messages be sent to syslogd */
+ int use_syslog;
+ /** log timestamp in ascii UTC */
+ int log_time_ascii;
+ /** log queries with one line per query */
+ int log_queries;
+
+ /** do not report identity (id.server, hostname.bind) */
+ int hide_identity;
+ /** do not report version (version.server, version.bind) */
+ int hide_version;
+ /** identity, hostname is returned if "". */
+ char* identity;
+ /** version, package version returned if "". */
+ char* version;
+
+ /** the module configuration string */
+ char* module_conf;
+
+ /** files with trusted DS and DNSKEYs in zonefile format, list */
+ struct config_strlist* trust_anchor_file_list;
+ /** list of trustanchor keys, linked list */
+ struct config_strlist* trust_anchor_list;
+ /** files with 5011 autotrust tracked keys */
+ struct config_strlist* auto_trust_anchor_file_list;
+ /** files with trusted DNSKEYs in named.conf format, list */
+ struct config_strlist* trusted_keys_file_list;
+ /** DLV anchor file */
+ char* dlv_anchor_file;
+ /** DLV anchor inline */
+ struct config_strlist* dlv_anchor_list;
+ /** insecure domain list */
+ struct config_strlist* domain_insecure;
+
+ /** if not 0, this value is the validation date for RRSIGs */
+ int32_t val_date_override;
+ /** the minimum for signature clock skew */
+ int32_t val_sig_skew_min;
+ /** the maximum for signature clock skew */
+ int32_t val_sig_skew_max;
+ /** this value sets the number of seconds before revalidating bogus */
+ int bogus_ttl;
+ /** should validator clean additional section for secure msgs */
+ int val_clean_additional;
+ /** log bogus messages by the validator */
+ int val_log_level;
+ /** squelch val_log_level to log - this is library goes to callback */
+ int val_log_squelch;
+ /** should validator allow bogus messages to go through */
+ int val_permissive_mode;
+ /** ignore the CD flag in incoming queries and refuse them bogus data */
+ int ignore_cd;
+ /** nsec3 maximum iterations per key size, string */
+ char* val_nsec3_key_iterations;
+ /** autotrust add holddown time, in seconds */
+ unsigned int add_holddown;
+ /** autotrust del holddown time, in seconds */
+ unsigned int del_holddown;
+ /** autotrust keep_missing time, in seconds. 0 is forever. */
+ unsigned int keep_missing;
+
+ /** size of the key cache */
+ size_t key_cache_size;
+ /** slabs in the key cache. */
+ size_t key_cache_slabs;
+ /** size of the neg cache */
+ size_t neg_cache_size;
+
+ /** local zones config */
+ struct config_str2list* local_zones;
+ /** local zones nodefault list */
+ struct config_strlist* local_zones_nodefault;
+ /** local data RRs configged */
+ struct config_strlist* local_data;
+ /** unblock lan zones (reverse lookups for 10/8 and so on) */
+ int unblock_lan_zones;
+
+ /** remote control section. enable toggle. */
+ int remote_control_enable;
+ /** the interfaces the remote control should listen on */
+ struct config_strlist* control_ifs;
+ /** port number for the control port */
+ int control_port;
+ /** private key file for server */
+ char* server_key_file;
+ /** certificate file for server */
+ char* server_cert_file;
+ /** private key file for unbound-control */
+ char* control_key_file;
+ /** certificate file for unbound-control */
+ char* control_cert_file;
+
+ /** Python script file */
+ char* python_script;
+
+ /** daemonize, i.e. fork into the background. */
+ int do_daemonize;
+
+ /* minimal response when positive answer */
+ int minimal_responses;
+
+ /* RRSet roundrobin */
+ int rrset_roundrobin;
+
+ /* maximum UDP response size */
+ size_t max_udp_size;
+
+ /* DNS64 prefix */
+ char* dns64_prefix;
+
+ /* Synthetize all AAAA record despite the presence of an authoritative one */
+ int dns64_synthall;
+
+ /** true to enable dnstap support */
+ int dnstap;
+ /** dnstap socket path */
+ char* dnstap_socket_path;
+ /** true to send "identity" via dnstap */
+ int dnstap_send_identity;
+ /** true to send "version" via dnstap */
+ int dnstap_send_version;
+ /** dnstap "identity", hostname is used if "". */
+ char* dnstap_identity;
+ /** dnstap "version", package version is used if "". */
+ char* dnstap_version;
+
+ /** true to log dnstap RESOLVER_QUERY message events */
+ int dnstap_log_resolver_query_messages;
+ /** true to log dnstap RESOLVER_RESPONSE message events */
+ int dnstap_log_resolver_response_messages;
+ /** true to log dnstap CLIENT_QUERY message events */
+ int dnstap_log_client_query_messages;
+ /** true to log dnstap CLIENT_RESPONSE message events */
+ int dnstap_log_client_response_messages;
+ /** true to log dnstap FORWARDER_QUERY message events */
+ int dnstap_log_forwarder_query_messages;
+ /** true to log dnstap FORWARDER_RESPONSE message events */
+ int dnstap_log_forwarder_response_messages;
+};
+
+/**
+ * Stub config options
+ */
+struct config_stub {
+ /** next in list */
+ struct config_stub* next;
+ /** domain name (in text) of the stub apex domain */
+ char* name;
+ /** list of stub nameserver hosts (domain name) */
+ struct config_strlist* hosts;
+ /** list of stub nameserver addresses (IP address) */
+ struct config_strlist* addrs;
+ /** if stub-prime is set */
+ int isprime;
+ /** if forward-first is set (failover to without if fails) */
+ int isfirst;
+};
+
+/**
+ * List of strings for config options
+ */
+struct config_strlist {
+ /** next item in list */
+ struct config_strlist* next;
+ /** config option string */
+ char* str;
+};
+
+/**
+ * List of two strings for config options
+ */
+struct config_str2list {
+ /** next item in list */
+ struct config_str2list* next;
+ /** first string */
+ char* str;
+ /** second string */
+ char* str2;
+};
+
+/** List head for strlist processing, used for append operation. */
+struct config_strlist_head {
+ /** first in list of text items */
+ struct config_strlist* first;
+ /** last in list of text items */
+ struct config_strlist* last;
+};
+
+/**
+ * Create config file structure. Filled with default values.
+ * @return: the new structure or NULL on memory error.
+ */
+struct config_file* config_create(void);
+
+/**
+ * Create config file structure for library use. Filled with default values.
+ * @return: the new structure or NULL on memory error.
+ */
+struct config_file* config_create_forlib(void);
+
+/**
+ * Read the config file from the specified filename.
+ * @param config: where options are stored into, must be freshly created.
+ * @param filename: name of configfile. If NULL nothing is done.
+ * @param chroot: if not NULL, the chroot dir currently in use (for include).
+ * @return: false on error. In that case errno is set, ENOENT means
+ * file not found.
+ */
+int config_read(struct config_file* config, const char* filename,
+ const char* chroot);
+
+/**
+ * Destroy the config file structure.
+ * @param config: to delete.
+ */
+void config_delete(struct config_file* config);
+
+/**
+ * Apply config to global constants; this routine is called in single thread.
+ * @param config: to apply. Side effect: global constants change.
+ */
+void config_apply(struct config_file* config);
+
+/**
+ * Set the given keyword to the given value.
+ * @param config: where to store config
+ * @param option: option name, including the ':' character.
+ * @param value: value, this string is copied if needed, or parsed.
+ * The caller owns the value string.
+ * @return 0 on error (malloc or syntax error).
+ */
+int config_set_option(struct config_file* config, const char* option,
+ const char* value);
+
+/**
+ * Call print routine for the given option.
+ * @param cfg: config.
+ * @param opt: option name without trailing :.
+ * This is different from config_set_option.
+ * @param func: print func, called as (str, arg) for every data element.
+ * @param arg: user argument for print func.
+ * @return false if the option name is not supported (syntax error).
+ */
+int config_get_option(struct config_file* cfg, const char* opt,
+ void (*func)(char*,void*), void* arg);
+
+/**
+ * Get an option and return strlist
+ * @param cfg: config file
+ * @param opt: option name.
+ * @param list: list is returned here. malloced, caller must free it.
+ * @return 0=OK, 1=syntax error, 2=malloc failed.
+ */
+int config_get_option_list(struct config_file* cfg, const char* opt,
+ struct config_strlist** list);
+
+/**
+ * Get an option and collate results into string
+ * @param cfg: config file
+ * @param opt: option name.
+ * @param str: string. malloced, caller must free it.
+ * @return 0=OK, 1=syntax error, 2=malloc failed.
+ */
+int config_get_option_collate(struct config_file* cfg, const char* opt,
+ char** str);
+
+/**
+ * function to print to a file, use as func with config_get_option.
+ * @param line: text to print. \n appended.
+ * @param arg: pass a FILE*, like stdout.
+ */
+void config_print_func(char* line, void* arg);
+
+/**
+ * function to collate the text strings into a strlist_head.
+ * @param line: text to append.
+ * @param arg: pass a strlist_head structure. zeroed on start.
+ */
+void config_collate_func(char* line, void* arg);
+
+/**
+ * take a strlist_head list and return a malloc string. separated with newline.
+ * @param list: strlist first to collate. zeroes return "".
+ * @return NULL on malloc failure. Or if malloc failure happened in strlist.
+ */
+char* config_collate_cat(struct config_strlist* list);
+
+/**
+ * Append text at end of list.
+ * @param list: list head. zeroed at start.
+ * @param item: new item. malloced by caller. if NULL the insertion fails.
+ * @return true on success.
+ */
+int cfg_strlist_append(struct config_strlist_head* list, char* item);
+
+/**
+ * Insert string into strlist.
+ * @param head: pointer to strlist head variable.
+ * @param item: new item. malloced by caller. If NULL the insertion fails.
+ * @return: true on success.
+ */
+int cfg_strlist_insert(struct config_strlist** head, char* item);
+
+/**
+ * Insert string into str2list.
+ * @param head: pointer to str2list head variable.
+ * @param item: new item. malloced by caller. If NULL the insertion fails.
+ * @param i2: 2nd string, malloced by caller. If NULL the insertion fails.
+ * @return: true on success.
+ */
+int cfg_str2list_insert(struct config_str2list** head, char* item, char* i2);
+
+/**
+ * Delete items in config string list.
+ * @param list: list.
+ */
+void config_delstrlist(struct config_strlist* list);
+
+/**
+ * Delete items in config double string list.
+ * @param list: list.
+ */
+void config_deldblstrlist(struct config_str2list* list);
+
+/**
+ * Delete items in config stub list.
+ * @param list: list.
+ */
+void config_delstubs(struct config_stub* list);
+
+/**
+ * Convert 14digit to time value
+ * @param str: string of 14 digits
+ * @return time value or 0 for error.
+ */
+time_t cfg_convert_timeval(const char* str);
+
+/**
+ * Count number of values in the string.
+ * format ::= (sp num)+ sp
+ * num ::= [-](0-9)+
+ * sp ::= (space|tab)*
+ *
+ * @param str: string
+ * @return: 0 on parse error, or empty string, else
+ * number of integer values in the string.
+ */
+int cfg_count_numbers(const char* str);
+
+/**
+ * Convert a 'nice' memory or file size into a bytecount
+ * From '100k' to 102400. and so on. Understands kKmMgG.
+ * k=1024, m=1024*1024, g=1024*1024*1024.
+ * @param str: string
+ * @param res: result is stored here, size in bytes.
+ * @return: true if parsed correctly, or 0 on a parse error (and an error
+ * is logged).
+ */
+int cfg_parse_memsize(const char* str, size_t* res);
+
+/**
+ * Parse local-zone directive into two strings and register it in the config.
+ * @param cfg: to put it in.
+ * @param val: argument strings to local-zone, "example.com nodefault".
+ * @return: false on failure
+ */
+int cfg_parse_local_zone(struct config_file* cfg, const char* val);
+
+/**
+ * Mark "number" or "low-high" as available or not in ports array.
+ * @param str: string in input
+ * @param allow: give true if this range is permitted.
+ * @param avail: the array from cfg.
+ * @param num: size of the array (65536).
+ * @return: true if parsed correctly, or 0 on a parse error (and an error
+ * is logged).
+ */
+int cfg_mark_ports(const char* str, int allow, int* avail, int num);
+
+/**
+ * Get a condensed list of ports returned. allocated.
+ * @param cfg: config file.
+ * @param avail: the available ports array is returned here.
+ * @return: number of ports in array or 0 on error.
+ */
+int cfg_condense_ports(struct config_file* cfg, int** avail);
+
+/**
+ * Scan ports available
+ * @param avail: the array from cfg.
+ * @param num: size of the array (65536).
+ * @return the number of ports available for use.
+ */
+int cfg_scan_ports(int* avail, int num);
+
+/**
+ * Convert a filename to full pathname in original filesys
+ * @param fname: the path name to convert.
+ * Must not be null or empty.
+ * @param cfg: config struct for chroot and chdir (if set).
+ * @param use_chdir: if false, only chroot is applied.
+ * @return pointer to malloced buffer which is: [chroot][chdir]fname
+ * or NULL on malloc failure.
+ */
+char* fname_after_chroot(const char* fname, struct config_file* cfg,
+ int use_chdir);
+
+/**
+ * Convert a ptr shorthand into a full reverse-notation PTR record.
+ * @param str: input string, "IP name"
+ * @return: malloced string "reversed-ip-name PTR name"
+ */
+char* cfg_ptr_reverse(char* str);
+
+/**
+ * Append text to the error info for validation.
+ * @param qstate: query state.
+ * @param str: copied into query region and appended.
+ * Failures to allocate are logged.
+ */
+void errinf(struct module_qstate* qstate, const char* str);
+
+/**
+ * Append text to error info: from 1.2.3.4
+ * @param qstate: query state.
+ * @param origin: sock list with origin of trouble.
+ * Every element added.
+ * If NULL: nothing is added.
+ * if 0len element: 'from cache' is added.
+ */
+void errinf_origin(struct module_qstate* qstate, struct sock_list *origin);
+
+/**
+ * Append text to error info: for RRset name type class
+ * @param qstate: query state.
+ * @param rr: rrset_key.
+ */
+void errinf_rrset(struct module_qstate* qstate, struct ub_packed_rrset_key *rr);
+
+/**
+ * Append text to error info: str dname
+ * @param qstate: query state.
+ * @param str: explanation string
+ * @param dname: the dname.
+ */
+void errinf_dname(struct module_qstate* qstate, const char* str,
+ uint8_t* dname);
+
+/**
+ * Create error info in string
+ * @param qstate: query state.
+ * @return string or NULL on malloc failure (already logged).
+ * This string is malloced and has to be freed by caller.
+ */
+char* errinf_to_str(struct module_qstate* qstate);
+
+/**
+ * Used during options parsing
+ */
+struct config_parser_state {
+ /** name of file being parser */
+ char* filename;
+ /** line number in the file, starts at 1 */
+ int line;
+ /** number of errors encountered */
+ int errors;
+ /** the result of parsing is stored here. */
+ struct config_file* cfg;
+ /** the current chroot dir (or NULL if none) */
+ const char* chroot;
+};
+
+/** global config parser object used during config parsing */
+extern struct config_parser_state* cfg_parser;
+/** init lex state */
+void init_cfg_parse(void);
+/** lex in file */
+extern FILE* ub_c_in;
+/** lex out file */
+extern FILE* ub_c_out;
+/** the yacc lex generated parse function */
+int ub_c_parse(void);
+/** the lexer function */
+int ub_c_lex(void);
+/** wrap function */
+int ub_c_wrap(void);
+/** parsing helpers: print error with file and line numbers */
+void ub_c_error(const char* msg);
+/** parsing helpers: print error with file and line numbers */
+void ub_c_error_msg(const char* fmt, ...) ATTR_FORMAT(printf, 1, 2);
+
+#ifdef UB_ON_WINDOWS
+/**
+ * Obtain registry string (if it exists).
+ * @param key: key string
+ * @param name: name of value to fetch.
+ * @return malloced string with the result or NULL if it did not
+ * exist on an error (logged with log_err) was encountered.
+ */
+char* w_lookup_reg_str(const char* key, const char* name);
+#endif /* UB_ON_WINDOWS */
+
+#endif /* UTIL_CONFIG_FILE_H */
diff --git a/external/unbound/util/configlexer.c b/external/unbound/util/configlexer.c
new file mode 100644
index 000000000..f1336a256
--- /dev/null
+++ b/external/unbound/util/configlexer.c
@@ -0,0 +1,4023 @@
+#include "config.h"
+#include "util/configyyrename.h"
+
+#line 3 "<stdout>"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 36
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE 16384
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ (yytext_ptr) -= (yy_more_len); \
+ yyleng = (size_t) (yy_cp - (yytext_ptr)); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 162
+#define YY_END_OF_BUFFER 163
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[1611] =
+ { 0,
+ 1, 1, 144, 144, 148, 148, 152, 152, 156, 156,
+ 1, 1, 163, 160, 1, 142, 142, 161, 2, 161,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 144,
+ 145, 145, 146, 161, 148, 149, 149, 150, 161, 155,
+ 152, 153, 153, 154, 161, 156, 157, 157, 158, 161,
+ 159, 143, 2, 147, 161, 159, 160, 0, 1, 2,
+ 2, 2, 2, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 144, 0, 148, 0, 155, 0, 152, 156,
+ 0, 159, 0, 2, 2, 159, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 159, 160, 160, 160, 160, 160, 160,
+
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 159, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+
+ 160, 160, 160, 160, 160, 65, 160, 160, 160, 160,
+ 160, 6, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 159, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 159, 160, 160, 160, 160, 29, 160, 160, 160,
+ 160, 160, 160, 160, 160, 129, 160, 12, 13, 160,
+ 15, 14, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 122,
+ 160, 160, 160, 160, 160, 3, 160, 160, 160, 160,
+
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 159, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 151, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 32, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 33, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 80, 151, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 79, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 63,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+
+ 160, 160, 20, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 30,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 31, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 22, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+
+ 160, 160, 160, 160, 26, 160, 27, 160, 160, 160,
+ 66, 160, 67, 160, 64, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 5, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 82, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 23, 160, 160, 160,
+ 160, 107, 106, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+
+ 160, 160, 34, 160, 160, 160, 160, 160, 160, 160,
+ 160, 69, 68, 160, 160, 160, 160, 160, 160, 160,
+ 103, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 50,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 54, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 105,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 4,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 100, 160, 160, 160, 160, 160, 160,
+ 160, 116, 101, 160, 127, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 21, 160, 160, 160, 160,
+ 71, 160, 72, 70, 160, 160, 160, 160, 160, 160,
+ 78, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 102, 160, 160, 160, 160, 126, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 62, 160, 160,
+ 160, 160, 160, 160, 160, 160, 28, 160, 160, 17,
+
+ 160, 160, 160, 16, 160, 87, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 41,
+ 42, 160, 160, 160, 160, 160, 160, 130, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 73, 160, 160, 160, 160, 160, 77, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 81, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 121, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 91, 160, 95, 160, 160, 160, 160, 76, 160,
+
+ 160, 114, 160, 160, 160, 128, 160, 160, 160, 160,
+ 160, 160, 160, 135, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 94, 160, 160, 160, 160, 43,
+ 44, 160, 49, 96, 160, 108, 104, 160, 160, 37,
+ 160, 98, 160, 160, 160, 160, 160, 7, 160, 61,
+ 113, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 83, 134, 160, 160,
+ 160, 160, 160, 160, 160, 160, 123, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 97,
+
+ 160, 36, 38, 160, 160, 160, 160, 160, 60, 160,
+ 160, 160, 160, 117, 18, 19, 160, 160, 160, 160,
+ 160, 160, 160, 58, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 119, 160, 160, 160, 160, 160, 160,
+ 160, 160, 35, 160, 160, 160, 160, 160, 160, 11,
+ 160, 160, 160, 160, 160, 160, 160, 10, 160, 160,
+ 39, 160, 125, 118, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 90, 89, 160, 120, 115,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 45, 160, 124, 160,
+
+ 160, 160, 160, 40, 160, 160, 160, 84, 86, 109,
+ 160, 160, 160, 88, 160, 160, 160, 160, 160, 160,
+ 160, 160, 131, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 24, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 133, 160, 160, 112, 160, 160, 160, 160, 160,
+ 160, 160, 25, 160, 9, 160, 160, 110, 51, 160,
+ 160, 160, 93, 160, 160, 160, 160, 160, 160, 132,
+ 74, 160, 160, 160, 53, 57, 52, 160, 46, 160,
+ 8, 160, 160, 92, 160, 160, 160, 160, 160, 160,
+
+ 160, 160, 160, 56, 160, 47, 160, 111, 160, 160,
+ 85, 160, 160, 160, 160, 160, 160, 75, 55, 48,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 59, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 99, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 138, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 136, 160,
+
+ 139, 140, 160, 160, 160, 160, 160, 137, 141, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 5, 6, 1, 1, 1, 7, 1,
+ 1, 1, 1, 1, 8, 1, 1, 1, 1, 1,
+ 9, 10, 1, 11, 1, 1, 1, 12, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 13, 1, 1, 1, 1, 14, 15, 16, 17,
+
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[40] =
+ { 0,
+ 1, 2, 3, 4, 5, 1, 6, 1, 1, 1,
+ 1, 7, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int16_t yy_base[1625] =
+ { 0,
+ 0, 0, 37, 40, 44, 51, 63, 75, 56, 68,
+ 87, 108, 2844, 2315, 50, 3201, 3201, 3201, 129, 94,
+ 70, 104, 130, 90, 92, 115, 127, 95, 84, 111,
+ 137, 148, 50, 150, 155, 157, 163, 171, 178, 2213,
+ 3201, 3201, 3201, 70, 2102, 3201, 3201, 3201, 42, 1930,
+ 1613, 3201, 3201, 3201, 195, 1340, 3201, 3201, 3201, 141,
+ 1156, 3201, 202, 3201, 206, 122, 1017, 212, 120, 0,
+ 223, 0, 0, 103, 147, 154, 158, 192, 199, 207,
+ 208, 205, 209, 221, 218, 220, 224, 225, 229, 230,
+ 231, 238, 251, 236, 247, 250, 237, 248, 256, 259,
+
+ 167, 263, 254, 249, 264, 265, 271, 273, 274, 125,
+ 275, 277, 284, 278, 281, 285, 288, 286, 289, 292,
+ 296, 298, 987, 308, 860, 315, 829, 326, 692, 342,
+ 319, 301, 330, 334, 0, 327, 331, 337, 314, 305,
+ 333, 335, 343, 340, 346, 349, 370, 350, 339, 352,
+ 49, 356, 354, 353, 361, 363, 362, 366, 364, 368,
+ 373, 377, 381, 392, 399, 386, 383, 401, 397, 405,
+ 408, 406, 182, 407, 409, 410, 385, 411, 414, 412,
+ 416, 418, 424, 420, 421, 422, 430, 428, 431, 441,
+ 444, 450, 433, 446, 448, 449, 456, 454, 453, 455,
+
+ 461, 460, 463, 464, 474, 475, 477, 470, 472, 479,
+ 480, 481, 488, 489, 491, 493, 499, 495, 496, 497,
+ 500, 501, 504, 505, 507, 511, 517, 512, 508, 521,
+ 510, 516, 523, 534, 527, 538, 532, 533, 542, 540,
+ 545, 543, 546, 547, 558, 554, 555, 559, 556, 557,
+ 563, 571, 575, 565, 568, 569, 577, 579, 581, 599,
+ 585, 583, 587, 590, 589, 596, 610, 597, 606, 607,
+ 624, 603, 612, 625, 627, 628, 632, 631, 634, 636,
+ 635, 637, 638, 640, 641, 644, 645, 656, 659, 648,
+ 665, 662, 667, 664, 670, 593, 677, 673, 675, 674,
+
+ 676, 646, 682, 678, 688, 3201, 690, 679, 685, 692,
+ 695, 3201, 696, 697, 698, 703, 702, 709, 705, 706,
+ 711, 714, 715, 719, 713, 720, 740, 722, 721, 731,
+ 735, 725, 733, 727, 743, 747, 749, 750, 751, 753,
+ 754, 755, 757, 758, 763, 774, 760, 768, 771, 778,
+ 779, 780, 782, 781, 787, 783, 794, 788, 798, 804,
+ 800, 806, 808, 814, 810, 811, 813, 820, 818, 819,
+ 812, 826, 823, 825, 830, 834, 827, 841, 837, 840,
+ 844, 847, 849, 850, 851, 853, 859, 857, 858, 866,
+ 868, 856, 864, 871, 872, 877, 884, 885, 881, 886,
+
+ 892, 893, 888, 894, 897, 898, 899, 900, 901, 902,
+ 906, 908, 909, 917, 903, 913, 919, 925, 927, 928,
+ 910, 930, 931, 934, 933, 937, 941, 935, 945, 947,
+ 948, 949, 955, 957, 950, 959, 3201, 969, 963, 965,
+ 966, 970, 972, 951, 991, 3201, 973, 3201, 3201, 975,
+ 3201, 3201, 974, 979, 982, 994, 1014, 993, 981, 980,
+ 1001, 1007, 995, 1008, 997, 1019, 1022, 1023, 1011, 1015,
+ 1027, 1029, 1024, 1036, 1037, 1041, 1043, 1049, 1045, 1046,
+ 1047, 1050, 1051, 1056, 1053, 1063, 1057, 1064, 1066, 3201,
+ 1067, 1068, 1071, 1073, 1075, 3201, 1074, 1076, 1077, 1079,
+
+ 1080, 1083, 1084, 1087, 1089, 1090, 1092, 1094, 1100, 1096,
+ 1097, 1110, 1117, 1114, 1104, 1113, 1115, 1119, 1121, 1129,
+ 1127, 1126, 1128, 1136, 1132, 1134, 1138, 1135, 1139, 1142,
+ 1145, 1146, 1170, 1147, 1148, 1149, 1153, 1154, 1157, 1158,
+ 1162, 1165, 1177, 1178, 1176, 1164, 1184, 1187, 1194, 1195,
+ 1197, 1191, 1155, 1199, 1204, 1206, 1208, 1188, 1211, 1212,
+ 3201, 1218, 1217, 1215, 1219, 1223, 1224, 1226, 1225, 1231,
+ 1227, 1237, 1229, 1245, 3201, 1230, 1239, 1233, 1241, 1250,
+ 1253, 1252, 1259, 1267, 3201, 1269, 1270, 1263, 1265, 1256,
+ 1272, 1273, 1277, 1278, 1279, 1281, 1284, 1287, 1289, 1288,
+
+ 1292, 1291, 1293, 1296, 1300, 1299, 1302, 1301, 1305, 1303,
+ 1242, 1315, 1322, 1311, 1321, 1318, 1324, 1323, 1329, 1327,
+ 1330, 1328, 1331, 3201, 239, 1332, 1333, 1334, 1341, 1349,
+ 1350, 1343, 1351, 1353, 1352, 1359, 1342, 1363, 1360, 1364,
+ 1366, 1368, 1371, 1372, 1373, 1377, 1375, 1381, 1383, 1382,
+ 1384, 1385, 1391, 1394, 1392, 1396, 1397, 1398, 1399, 1400,
+ 1402, 1406, 1405, 1410, 3201, 1427, 1412, 1415, 1413, 1424,
+ 1435, 1428, 1431, 1432, 1442, 1438, 1440, 1443, 1449, 1446,
+ 1451, 1452, 1436, 1458, 1462, 1459, 1461, 1460, 1468, 3201,
+ 1463, 1470, 1471, 1472, 1473, 1475, 1477, 1480, 1481, 1488,
+
+ 1482, 1494, 3201, 1496, 1490, 1484, 1501, 1502, 1505, 1507,
+ 1509, 1510, 1511, 1513, 1514, 1517, 1515, 1520, 1524, 3201,
+ 1528, 1532, 1529, 1540, 1536, 1525, 1537, 1539, 1541, 1542,
+ 1551, 1543, 1547, 1550, 1552, 1549, 1554, 1555, 1557, 1559,
+ 3201, 1571, 1572, 1574, 1414, 1562, 1583, 1556, 1575, 1558,
+ 1584, 1585, 1587, 1588, 1589, 1590, 1593, 1595, 1591, 1597,
+ 1596, 1599, 1600, 1608, 1598, 1617, 1618, 1619, 1601, 1623,
+ 1629, 1632, 1620, 3201, 1631, 1634, 1635, 1636, 1642, 1644,
+ 1638, 1640, 1645, 1646, 1647, 1656, 1648, 1650, 1654, 1658,
+ 1652, 1660, 1661, 1662, 1670, 1664, 1672, 1674, 1678, 1680,
+
+ 1682, 1684, 1686, 1694, 3201, 1690, 3201, 1691, 1692, 1700,
+ 3201, 1702, 3201, 1704, 3201, 1707, 1711, 1699, 1697, 1705,
+ 1713, 1709, 1716, 1717, 1720, 1723, 1725, 1726, 1727, 1728,
+ 3201, 1729, 1734, 1731, 1735, 1738, 1739, 1740, 1744, 1756,
+ 1741, 1743, 1753, 1754, 3201, 1750, 1762, 1764, 1765, 1766,
+ 1773, 1770, 1771, 1777, 1767, 1778, 1788, 1786, 1779, 1789,
+ 1790, 1791, 1793, 1794, 1801, 1798, 1795, 1802, 1804, 1805,
+ 1806, 1807, 1814, 1811, 1812, 1815, 3201, 1823, 1821, 1817,
+ 1825, 3201, 3201, 1834, 1827, 1835, 1837, 1839, 1842, 1843,
+ 1845, 1849, 1847, 1850, 1851, 1856, 1857, 1858, 1859, 1862,
+
+ 1860, 1866, 3201, 1872, 1868, 1878, 1869, 1865, 1887, 1879,
+ 1888, 3201, 3201, 1881, 1880, 1890, 1894, 1900, 1896, 1898,
+ 3201, 1899, 1901, 1902, 1904, 1906, 1914, 1903, 1910, 1918,
+ 1915, 1920, 1921, 1927, 1924, 1928, 1931, 1935, 1939, 3201,
+ 1940, 1942, 1943, 1945, 1944, 1947, 1948, 1951, 1952, 1957,
+ 1954, 1965, 1967, 1958, 1966, 1960, 1971, 1968, 1973, 1976,
+ 1983, 1981, 3201, 1987, 1986, 1994, 1990, 1992, 1995, 1998,
+ 1997, 1999, 2000, 2001, 2002, 2006, 2003, 2007, 2010, 3201,
+ 2013, 2018, 2012, 2024, 2025, 2014, 2032, 2026, 2028, 3201,
+ 2036, 2042, 2035, 2038, 2047, 2043, 2049, 2039, 2050, 2051,
+
+ 2053, 2054, 2057, 2062, 2056, 2064, 2069, 2071, 2078, 2075,
+ 2081, 2082, 2079, 2083, 2089, 2086, 2087, 2088, 2092, 2099,
+ 2093, 2101, 2097, 3201, 2103, 2108, 2111, 2112, 2114, 2116,
+ 2104, 3201, 3201, 2120, 3201, 2121, 2124, 2125, 2126, 2128,
+ 2129, 2127, 2134, 2141, 2130, 3201, 2137, 2140, 2142, 2143,
+ 3201, 2154, 3201, 3201, 2147, 2155, 2156, 2159, 2162, 2166,
+ 3201, 2163, 2157, 2167, 2169, 2171, 2172, 2174, 2176, 2175,
+ 3201, 2180, 2179, 2178, 2188, 3201, 2187, 2193, 2182, 2189,
+ 2198, 2199, 2202, 2203, 2205, 2211, 2209, 3201, 2210, 2212,
+ 2216, 2218, 2219, 2220, 2223, 2224, 3201, 2233, 2234, 3201,
+
+ 2227, 2217, 2235, 3201, 2241, 3201, 2242, 2243, 2244, 2245,
+ 2250, 2246, 2253, 2256, 2257, 2259, 2260, 2263, 2266, 3201,
+ 3201, 2267, 2271, 2277, 2268, 2279, 2282, 3201, 2265, 2283,
+ 2272, 2285, 2286, 2287, 2292, 2294, 2297, 2289, 2298, 2296,
+ 2299, 3201, 2302, 2306, 2307, 2309, 2310, 3201, 2312, 2313,
+ 2314, 2317, 2319, 2324, 2333, 2329, 2335, 2337, 2338, 2340,
+ 2344, 2341, 3201, 2345, 2347, 2348, 2352, 2353, 2349, 2356,
+ 2361, 2364, 2354, 2366, 3201, 2369, 2358, 2374, 2370, 2376,
+ 2378, 2372, 2380, 2381, 2382, 2385, 2386, 2389, 2390, 2396,
+ 2399, 3201, 2392, 3201, 2401, 2405, 2413, 2414, 3201, 2394,
+
+ 2407, 3201, 2417, 2411, 2422, 3201, 2425, 2418, 2426, 2428,
+ 2429, 2430, 2433, 3201, 2431, 2436, 2438, 2441, 2442, 2444,
+ 2445, 2447, 2455, 2451, 3201, 2453, 2454, 2456, 2458, 3201,
+ 3201, 2466, 3201, 3201, 2471, 3201, 3201, 2463, 2473, 3201,
+ 2475, 3201, 2481, 2477, 2479, 2461, 2480, 3201, 2487, 3201,
+ 3201, 2484, 2488, 2482, 2492, 2494, 2499, 2501, 2491, 2502,
+ 2504, 2505, 2506, 2507, 2508, 2510, 2513, 2511, 2514, 2519,
+ 2515, 2521, 2523, 2524, 2525, 2527, 3201, 3201, 2531, 2536,
+ 2533, 2538, 2540, 2542, 2543, 2544, 3201, 2547, 2548, 2550,
+ 2552, 2553, 2556, 2559, 2564, 2573, 2560, 2566, 2567, 3201,
+
+ 2569, 3201, 3201, 2574, 2576, 2581, 2577, 2582, 3201, 2584,
+ 2586, 2590, 2596, 3201, 3201, 3201, 2597, 2591, 2593, 2599,
+ 2601, 2603, 2607, 3201, 2608, 2609, 2611, 2610, 2618, 2620,
+ 2626, 2628, 2630, 3201, 2636, 2633, 2634, 2632, 2635, 2638,
+ 2640, 2612, 3201, 2644, 2642, 2643, 2648, 2653, 2649, 3201,
+ 2651, 2656, 2660, 2662, 2664, 2661, 2667, 3201, 2665, 2666,
+ 3201, 2677, 3201, 3201, 2668, 2680, 2682, 2684, 2687, 2690,
+ 2673, 2678, 2698, 2695, 2696, 3201, 3201, 2697, 3201, 3201,
+ 2699, 2701, 2702, 2704, 2705, 2708, 2709, 2710, 2711, 2712,
+ 2715, 2721, 2714, 2722, 2723, 2725, 3201, 2733, 3201, 2729,
+
+ 2738, 2735, 2740, 3201, 2741, 2742, 2727, 3201, 3201, 3201,
+ 2746, 2743, 2753, 3201, 2755, 2756, 2757, 2758, 2759, 2766,
+ 2764, 2768, 3201, 2769, 2770, 2772, 2773, 2774, 2775, 2776,
+ 2781, 2779, 2780, 2792, 2793, 3201, 2796, 2783, 2787, 2801,
+ 2807, 2797, 2802, 2804, 2811, 2808, 2812, 2813, 2823, 2819,
+ 2822, 3201, 2826, 2815, 3201, 2827, 2828, 2830, 2839, 2843,
+ 2835, 2845, 3201, 2846, 3201, 2849, 2850, 3201, 3201, 2851,
+ 2853, 2856, 3201, 2857, 2854, 2858, 2860, 2863, 2864, 3201,
+ 3201, 2865, 2867, 2871, 3201, 3201, 3201, 2880, 3201, 2882,
+ 3201, 2888, 2868, 3201, 2873, 2890, 2870, 2881, 2876, 2893,
+
+ 2894, 2892, 2901, 3201, 2903, 3201, 2905, 3201, 2906, 2907,
+ 3201, 2914, 2910, 2912, 2913, 2915, 2919, 3201, 3201, 3201,
+ 2916, 2921, 2923, 2925, 2922, 2926, 2927, 2928, 2930, 2937,
+ 2934, 2945, 2931, 2938, 2954, 2947, 3201, 2948, 2951, 2960,
+ 2962, 2958, 2964, 2959, 2965, 2966, 2967, 2968, 2969, 2971,
+ 2982, 2973, 2974, 2984, 2986, 2990, 2983, 2998, 2997, 2994,
+ 2999, 3000, 3008, 3004, 3007, 3201, 3005, 3006, 3009, 3011,
+ 3012, 3016, 3014, 3026, 3029, 3017, 3031, 3015, 3036, 3032,
+ 3037, 3040, 3041, 3042, 3201, 3043, 3045, 3047, 3049, 3051,
+ 3053, 3054, 3055, 3058, 3060, 3063, 3065, 3069, 3201, 3070,
+
+ 3201, 3201, 3074, 3071, 3077, 3081, 3083, 3201, 3201, 3201,
+ 3109, 3116, 3123, 3130, 3137, 94, 3144, 3151, 3158, 3165,
+ 3172, 3179, 3186, 3193
+ } ;
+
+static yyconst flex_int16_t yy_def[1625] =
+ { 0,
+ 1610, 1, 1611, 1611, 1612, 1612, 1613, 1613, 1614, 1614,
+ 1615, 1615, 1610, 1616, 1610, 1610, 1610, 1610, 1617, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1618,
+ 1610, 1610, 1610, 1618, 1619, 1610, 1610, 1610, 1619, 1620,
+ 1610, 1610, 1610, 1610, 1620, 1621, 1610, 1610, 1610, 1621,
+ 1622, 1610, 1623, 1610, 1622, 1622, 1616, 1616, 1610, 1624,
+ 1617, 1624, 1617, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1618, 1618, 1619, 1619, 1620, 1620, 1610, 1621,
+ 1621, 1622, 1622, 1623, 1623, 1622, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1622, 1616, 1616, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1622, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616,
+ 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1622, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1622, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1610, 1610, 1616,
+ 1610, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610,
+ 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1622, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1610, 1622, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1616, 1616, 1610, 1616, 1610, 1616, 1616, 1616,
+ 1610, 1616, 1610, 1616, 1610, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616,
+ 1616, 1610, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1610, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1610, 1610, 1616, 1610, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616,
+ 1610, 1616, 1610, 1610, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1610, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1610,
+
+ 1616, 1616, 1616, 1610, 1616, 1610, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610,
+ 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1610, 1616, 1610, 1616, 1616, 1616, 1616, 1610, 1616,
+
+ 1616, 1610, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1610,
+ 1610, 1616, 1610, 1610, 1616, 1610, 1610, 1616, 1616, 1610,
+ 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1610,
+ 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1610, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610,
+
+ 1616, 1610, 1610, 1616, 1616, 1616, 1616, 1616, 1610, 1616,
+ 1616, 1616, 1616, 1610, 1610, 1610, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1610,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616,
+ 1610, 1616, 1610, 1610, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1610, 1610, 1616, 1610, 1610,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1610, 1616,
+
+ 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1610, 1610, 1610,
+ 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1610, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1610, 1616, 1610, 1616, 1616, 1610, 1610, 1616,
+ 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1610,
+ 1610, 1616, 1616, 1616, 1610, 1610, 1610, 1616, 1610, 1616,
+ 1610, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616, 1616,
+
+ 1616, 1616, 1616, 1610, 1616, 1610, 1616, 1610, 1616, 1616,
+ 1610, 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1610, 1610,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1610, 1616, 1616, 1616, 1616, 1616,
+ 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1616, 1610, 1616,
+
+ 1610, 1610, 1616, 1616, 1616, 1616, 1616, 1610, 1610, 0,
+ 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
+ 1610, 1610, 1610, 1610
+ } ;
+
+static yyconst flex_int16_t yy_nxt[3241] =
+ { 0,
+ 14, 15, 16, 17, 18, 19, 18, 14, 14, 14,
+ 14, 18, 20, 21, 14, 22, 23, 24, 25, 14,
+ 26, 27, 28, 29, 30, 31, 32, 33, 34, 14,
+ 35, 36, 37, 38, 39, 14, 14, 14, 14, 41,
+ 42, 43, 41, 42, 43, 125, 46, 47, 125, 44,
+ 48, 69, 44, 46, 47, 70, 49, 48, 57, 58,
+ 59, 68, 68, 49, 51, 52, 53, 54, 60, 18,
+ 57, 58, 59, 123, 123, 55, 51, 52, 53, 54,
+ 60, 18, 68, 104, 215, 74, 75, 55, 15, 16,
+ 17, 62, 63, 64, 67, 67, 68, 67, 67, 65,
+
+ 67, 95, 68, 76, 68, 67, 85, 68, 66, 15,
+ 16, 17, 62, 63, 64, 68, 68, 77, 137, 87,
+ 65, 69, 94, 68, 78, 70, 86, 68, 88, 66,
+ 72, 79, 72, 72, 133, 72, 89, 68, 96, 68,
+ 72, 73, 68, 90, 130, 130, 91, 80, 136, 68,
+ 97, 81, 179, 92, 82, 93, 83, 84, 98, 68,
+ 68, 101, 68, 138, 99, 102, 68, 68, 100, 68,
+ 68, 105, 109, 140, 112, 68, 116, 106, 117, 68,
+ 107, 103, 110, 68, 113, 111, 139, 108, 114, 115,
+ 68, 121, 169, 118, 68, 122, 127, 119, 127, 127,
+
+ 239, 127, 120, 72, 68, 72, 72, 132, 72, 132,
+ 132, 68, 132, 67, 135, 67, 67, 68, 67, 68,
+ 68, 68, 141, 67, 72, 142, 72, 72, 147, 72,
+ 68, 143, 68, 68, 72, 73, 68, 68, 144, 145,
+ 146, 68, 68, 68, 149, 153, 148, 154, 68, 68,
+ 68, 133, 150, 156, 151, 152, 157, 155, 159, 68,
+ 68, 68, 68, 68, 161, 163, 68, 160, 68, 164,
+ 158, 68, 167, 165, 166, 68, 68, 68, 168, 171,
+ 173, 172, 170, 68, 162, 68, 68, 68, 175, 68,
+ 68, 182, 176, 68, 184, 174, 68, 68, 68, 178,
+
+ 68, 68, 183, 189, 68, 177, 180, 181, 68, 191,
+ 68, 123, 123, 133, 185, 186, 187, 68, 125, 188,
+ 192, 125, 130, 130, 190, 198, 68, 127, 193, 127,
+ 127, 132, 127, 132, 132, 72, 132, 72, 72, 133,
+ 72, 197, 194, 68, 196, 68, 135, 68, 195, 68,
+ 201, 68, 68, 204, 131, 68, 202, 203, 68, 205,
+ 199, 68, 68, 212, 68, 68, 68, 200, 68, 214,
+ 213, 217, 216, 68, 68, 68, 68, 224, 68, 218,
+ 68, 206, 68, 223, 227, 68, 207, 220, 219, 68,
+ 221, 208, 222, 68, 228, 68, 209, 68, 68, 229,
+
+ 225, 226, 210, 211, 68, 243, 231, 232, 234, 68,
+ 230, 68, 236, 68, 235, 237, 233, 68, 68, 68,
+ 68, 68, 68, 68, 68, 238, 68, 241, 68, 246,
+ 68, 250, 68, 68, 68, 252, 68, 254, 244, 240,
+ 68, 253, 68, 68, 242, 68, 245, 261, 248, 249,
+ 247, 258, 251, 68, 257, 256, 68, 260, 133, 255,
+ 68, 68, 68, 266, 262, 68, 68, 68, 68, 265,
+ 263, 267, 68, 68, 259, 68, 68, 273, 272, 264,
+ 268, 270, 68, 274, 68, 269, 68, 68, 275, 68,
+ 276, 68, 68, 68, 279, 282, 280, 271, 277, 278,
+
+ 68, 68, 281, 68, 284, 68, 286, 68, 68, 68,
+ 285, 68, 68, 68, 291, 283, 68, 68, 295, 68,
+ 68, 293, 68, 68, 68, 290, 288, 287, 68, 68,
+ 289, 294, 296, 68, 292, 68, 297, 298, 306, 68,
+ 299, 302, 300, 301, 68, 68, 68, 303, 304, 305,
+ 68, 312, 68, 307, 68, 68, 314, 68, 68, 68,
+ 310, 308, 313, 311, 309, 317, 68, 68, 68, 68,
+ 68, 68, 319, 315, 320, 68, 321, 68, 327, 316,
+ 68, 68, 322, 68, 326, 323, 318, 68, 324, 68,
+ 325, 68, 328, 68, 333, 68, 331, 68, 329, 133,
+
+ 330, 68, 68, 332, 344, 68, 380, 335, 68, 68,
+ 334, 68, 343, 336, 337, 68, 347, 349, 68, 68,
+ 345, 346, 68, 338, 68, 339, 340, 341, 348, 350,
+ 342, 353, 356, 351, 352, 354, 68, 68, 355, 68,
+ 68, 359, 360, 68, 68, 358, 68, 68, 68, 68,
+ 68, 365, 68, 68, 366, 357, 68, 68, 68, 386,
+ 68, 364, 362, 361, 363, 369, 371, 368, 68, 374,
+ 367, 68, 375, 372, 68, 373, 68, 68, 370, 68,
+ 376, 378, 68, 377, 381, 68, 68, 68, 68, 68,
+ 68, 68, 385, 129, 68, 379, 383, 68, 384, 387,
+
+ 68, 389, 68, 390, 68, 392, 382, 68, 68, 68,
+ 68, 388, 391, 393, 68, 68, 400, 68, 68, 394,
+ 398, 68, 399, 68, 397, 68, 68, 68, 395, 396,
+ 404, 68, 68, 68, 68, 401, 406, 68, 416, 68,
+ 402, 407, 405, 68, 403, 68, 420, 68, 417, 415,
+ 418, 408, 68, 409, 414, 68, 422, 419, 410, 68,
+ 411, 68, 68, 68, 421, 68, 68, 68, 412, 68,
+ 68, 428, 68, 424, 423, 133, 429, 425, 413, 432,
+ 68, 433, 426, 68, 434, 431, 68, 427, 430, 437,
+ 68, 68, 68, 68, 68, 68, 436, 440, 435, 68,
+
+ 68, 445, 442, 438, 439, 446, 68, 450, 441, 448,
+ 68, 443, 68, 447, 444, 449, 68, 451, 68, 452,
+ 68, 453, 68, 68, 68, 68, 68, 457, 455, 456,
+ 68, 68, 68, 461, 458, 68, 459, 68, 68, 68,
+ 462, 128, 68, 454, 460, 464, 68, 467, 469, 68,
+ 465, 463, 68, 68, 466, 471, 68, 468, 470, 68,
+ 472, 68, 68, 68, 474, 68, 479, 476, 68, 68,
+ 68, 68, 126, 481, 475, 480, 68, 478, 68, 477,
+ 68, 482, 473, 68, 68, 483, 484, 487, 486, 68,
+ 485, 489, 491, 68, 488, 490, 68, 68, 68, 495,
+
+ 68, 493, 492, 496, 68, 68, 68, 497, 499, 68,
+ 68, 68, 68, 68, 68, 68, 494, 504, 68, 498,
+ 68, 68, 68, 505, 509, 68, 511, 500, 501, 68,
+ 502, 68, 503, 506, 510, 512, 508, 68, 507, 68,
+ 68, 516, 68, 68, 514, 68, 68, 68, 513, 68,
+ 518, 519, 520, 68, 521, 517, 515, 68, 522, 68,
+ 68, 133, 68, 68, 524, 523, 527, 68, 525, 68,
+ 528, 68, 531, 529, 526, 68, 533, 68, 68, 534,
+ 532, 68, 68, 530, 68, 68, 68, 68, 539, 535,
+ 537, 68, 68, 68, 68, 547, 536, 548, 549, 124,
+
+ 545, 550, 538, 68, 546, 68, 68, 68, 540, 68,
+ 557, 558, 541, 68, 562, 542, 560, 559, 561, 68,
+ 68, 563, 543, 68, 564, 544, 68, 68, 551, 68,
+ 552, 68, 565, 553, 68, 68, 68, 566, 554, 68,
+ 567, 68, 571, 568, 555, 556, 569, 570, 68, 68,
+ 576, 572, 575, 68, 574, 68, 577, 68, 68, 68,
+ 578, 68, 68, 68, 579, 68, 573, 580, 68, 68,
+ 581, 587, 584, 583, 585, 68, 68, 586, 68, 68,
+ 68, 582, 589, 68, 591, 68, 68, 68, 68, 68,
+ 593, 68, 68, 596, 590, 68, 68, 588, 594, 68,
+
+ 592, 68, 68, 602, 68, 601, 68, 595, 68, 68,
+ 597, 598, 68, 605, 599, 600, 68, 610, 607, 603,
+ 606, 604, 68, 609, 611, 68, 68, 68, 608, 68,
+ 612, 68, 615, 68, 617, 613, 618, 614, 68, 68,
+ 68, 68, 619, 622, 68, 624, 68, 68, 68, 625,
+ 133, 68, 616, 621, 68, 627, 620, 68, 68, 68,
+ 68, 68, 626, 636, 623, 68, 68, 68, 133, 68,
+ 68, 640, 630, 628, 68, 637, 68, 68, 643, 659,
+ 639, 629, 68, 641, 642, 631, 638, 632, 68, 68,
+ 68, 633, 644, 634, 645, 647, 68, 649, 635, 68,
+
+ 68, 652, 648, 68, 646, 651, 68, 68, 653, 68,
+ 650, 68, 660, 654, 657, 655, 68, 658, 68, 664,
+ 68, 661, 665, 68, 68, 667, 662, 68, 666, 68,
+ 68, 68, 668, 656, 663, 68, 68, 68, 68, 68,
+ 671, 68, 68, 68, 670, 68, 669, 673, 675, 68,
+ 678, 68, 679, 68, 68, 672, 674, 68, 683, 676,
+ 682, 680, 68, 677, 68, 68, 716, 684, 68, 681,
+ 685, 68, 687, 686, 688, 68, 689, 68, 693, 68,
+ 690, 68, 68, 691, 68, 68, 692, 696, 695, 68,
+ 68, 68, 694, 68, 698, 699, 68, 700, 703, 68,
+
+ 68, 68, 702, 68, 68, 68, 697, 706, 68, 701,
+ 704, 68, 68, 68, 68, 68, 711, 68, 705, 712,
+ 714, 707, 717, 68, 708, 710, 715, 68, 709, 718,
+ 68, 713, 720, 68, 68, 68, 68, 724, 719, 68,
+ 68, 68, 68, 68, 68, 68, 68, 723, 732, 721,
+ 722, 726, 131, 68, 68, 68, 733, 725, 729, 727,
+ 730, 68, 68, 68, 68, 68, 731, 734, 728, 735,
+ 737, 68, 68, 740, 741, 68, 68, 736, 68, 738,
+ 68, 745, 743, 68, 68, 68, 739, 68, 746, 68,
+ 742, 747, 749, 68, 68, 68, 68, 68, 744, 748,
+
+ 752, 754, 751, 68, 68, 750, 68, 756, 68, 68,
+ 68, 68, 68, 753, 68, 757, 755, 68, 68, 758,
+ 764, 760, 68, 759, 68, 68, 68, 68, 848, 761,
+ 763, 767, 762, 765, 768, 770, 68, 766, 769, 68,
+ 68, 772, 773, 68, 68, 771, 774, 68, 68, 778,
+ 68, 779, 68, 777, 68, 68, 776, 780, 68, 775,
+ 781, 68, 782, 68, 68, 787, 786, 783, 784, 788,
+ 68, 68, 68, 68, 68, 68, 789, 790, 785, 796,
+ 68, 791, 68, 68, 68, 68, 792, 68, 793, 68,
+ 794, 795, 68, 68, 68, 801, 68, 797, 799, 805,
+
+ 68, 798, 68, 802, 800, 807, 68, 809, 68, 806,
+ 803, 808, 811, 68, 68, 810, 813, 68, 804, 68,
+ 815, 68, 68, 68, 814, 68, 68, 68, 817, 68,
+ 820, 819, 68, 818, 812, 824, 68, 68, 822, 825,
+ 68, 68, 816, 823, 68, 821, 826, 827, 68, 68,
+ 831, 68, 68, 68, 68, 68, 829, 828, 834, 68,
+ 830, 68, 68, 68, 68, 838, 68, 68, 68, 68,
+ 68, 68, 851, 832, 68, 835, 843, 833, 844, 836,
+ 837, 839, 845, 68, 68, 841, 68, 68, 849, 853,
+ 850, 840, 842, 846, 847, 68, 68, 68, 852, 68,
+
+ 68, 68, 68, 68, 856, 68, 859, 68, 68, 68,
+ 68, 68, 68, 68, 129, 855, 865, 862, 857, 866,
+ 68, 858, 854, 860, 863, 867, 861, 864, 868, 68,
+ 68, 68, 68, 876, 872, 68, 874, 871, 869, 875,
+ 873, 68, 877, 68, 68, 870, 68, 68, 68, 881,
+ 68, 878, 68, 882, 68, 883, 68, 68, 68, 68,
+ 68, 879, 68, 889, 68, 888, 68, 880, 68, 884,
+ 68, 885, 68, 68, 68, 897, 68, 887, 894, 890,
+ 899, 891, 68, 886, 68, 892, 68, 898, 896, 893,
+ 68, 903, 68, 895, 68, 901, 68, 900, 68, 904,
+
+ 905, 907, 68, 68, 68, 910, 68, 911, 909, 68,
+ 902, 68, 68, 912, 68, 913, 68, 68, 906, 68,
+ 908, 68, 914, 68, 915, 68, 916, 921, 68, 68,
+ 919, 918, 68, 923, 917, 68, 920, 68, 68, 68,
+ 68, 68, 926, 68, 931, 928, 68, 68, 925, 922,
+ 68, 68, 68, 68, 935, 68, 68, 924, 927, 929,
+ 930, 936, 68, 937, 940, 68, 68, 932, 68, 939,
+ 933, 934, 941, 938, 68, 943, 68, 68, 68, 68,
+ 949, 946, 68, 68, 947, 68, 942, 950, 944, 68,
+ 68, 68, 951, 954, 952, 955, 948, 945, 68, 956,
+
+ 68, 68, 68, 68, 953, 68, 68, 68, 960, 957,
+ 68, 962, 963, 68, 68, 964, 68, 68, 68, 68,
+ 958, 971, 959, 68, 68, 965, 68, 68, 961, 68,
+ 969, 968, 970, 68, 966, 68, 967, 68, 977, 68,
+ 976, 978, 981, 972, 973, 980, 68, 68, 974, 68,
+ 975, 68, 982, 979, 68, 68, 989, 68, 990, 68,
+ 984, 68, 68, 68, 986, 983, 988, 987, 68, 68,
+ 68, 68, 68, 985, 68, 997, 992, 68, 68, 1000,
+ 68, 68, 991, 994, 68, 1002, 993, 1003, 998, 996,
+ 68, 68, 68, 68, 1005, 995, 999, 1004, 1001, 68,
+
+ 68, 1009, 68, 1007, 1006, 1010, 68, 1013, 68, 1008,
+ 68, 68, 68, 68, 68, 68, 68, 1017, 68, 1018,
+ 1011, 1019, 68, 1020, 1014, 1012, 68, 68, 1015, 1024,
+ 68, 1016, 68, 68, 1028, 1021, 68, 1023, 1022, 68,
+ 68, 1025, 128, 68, 1026, 1027, 1032, 68, 1029, 1031,
+ 1033, 68, 68, 1035, 68, 68, 68, 68, 1030, 68,
+ 68, 1034, 1037, 68, 68, 1038, 68, 1036, 1041, 68,
+ 68, 1039, 68, 1042, 1047, 1040, 1046, 68, 68, 68,
+ 68, 1045, 1051, 68, 1053, 68, 1043, 1054, 68, 1044,
+ 1055, 1048, 1050, 68, 1057, 68, 1056, 1049, 68, 68,
+
+ 1052, 1059, 68, 1061, 68, 1063, 68, 68, 1062, 68,
+ 68, 68, 68, 68, 68, 68, 1058, 1071, 68, 68,
+ 1073, 1064, 68, 1065, 68, 68, 68, 1060, 1066, 1076,
+ 68, 1067, 1068, 1069, 1075, 1070, 68, 68, 68, 1077,
+ 68, 1072, 1074, 1078, 68, 1081, 1079, 68, 68, 1085,
+ 68, 68, 1080, 1084, 68, 68, 1083, 1087, 1088, 68,
+ 1089, 68, 68, 68, 1082, 68, 68, 1086, 68, 68,
+ 1090, 1091, 1095, 1097, 68, 1100, 68, 1092, 1096, 1098,
+ 1094, 68, 1093, 68, 1099, 1103, 1104, 68, 1105, 1107,
+ 68, 68, 1106, 68, 68, 68, 1110, 1102, 68, 68,
+
+ 68, 68, 1101, 1112, 68, 68, 1115, 1109, 1117, 68,
+ 1111, 68, 1113, 68, 126, 68, 68, 1108, 1119, 1120,
+ 68, 1118, 1121, 68, 68, 1125, 68, 1116, 68, 1114,
+ 1122, 1123, 68, 68, 1124, 1128, 68, 68, 68, 68,
+ 68, 68, 68, 1133, 1126, 1127, 68, 1130, 1135, 68,
+ 1137, 1134, 68, 68, 68, 68, 1136, 1129, 1131, 68,
+ 1132, 1138, 1144, 1140, 1141, 1142, 68, 68, 68, 68,
+ 1139, 68, 1146, 1143, 68, 68, 1147, 1148, 68, 68,
+ 1151, 68, 1149, 68, 68, 1145, 68, 68, 68, 1150,
+ 68, 68, 68, 1159, 68, 1153, 1154, 1158, 1155, 68,
+
+ 68, 68, 1152, 1156, 1163, 68, 1165, 1157, 1160, 1161,
+ 68, 68, 1166, 1162, 68, 68, 1167, 68, 1171, 1168,
+ 1164, 68, 68, 68, 68, 124, 1172, 1175, 68, 68,
+ 68, 68, 68, 1169, 1179, 68, 68, 1170, 1174, 68,
+ 1177, 1173, 1176, 1178, 1180, 68, 68, 68, 1181, 1185,
+ 1182, 1183, 1184, 68, 68, 68, 68, 68, 68, 1187,
+ 1188, 1192, 68, 1186, 1194, 68, 1191, 1193, 68, 68,
+ 1189, 68, 68, 1196, 1199, 68, 1197, 68, 68, 68,
+ 68, 1190, 1202, 68, 68, 1198, 1200, 1195, 1201, 68,
+ 1203, 68, 1204, 1206, 68, 68, 1205, 68, 68, 68,
+
+ 1208, 68, 1207, 1211, 68, 1214, 68, 1209, 68, 68,
+ 68, 68, 1210, 1215, 68, 1217, 1216, 1212, 68, 68,
+ 1213, 68, 68, 1225, 68, 68, 68, 68, 1226, 68,
+ 1219, 68, 1229, 1223, 1218, 1230, 68, 1221, 1220, 1227,
+ 1222, 68, 1228, 1224, 1231, 68, 1233, 68, 1234, 68,
+ 68, 1236, 68, 68, 1232, 1237, 68, 68, 1240, 68,
+ 68, 68, 1239, 1242, 68, 68, 68, 1244, 68, 1235,
+ 68, 1245, 1238, 68, 1246, 1248, 68, 1250, 68, 1241,
+ 1251, 68, 68, 1243, 68, 1249, 68, 1253, 68, 1247,
+ 68, 1254, 68, 68, 68, 1256, 1252, 68, 68, 1260,
+
+ 1255, 68, 68, 1265, 68, 1258, 68, 1262, 68, 1257,
+ 1263, 68, 1261, 68, 1259, 1266, 1264, 68, 1269, 68,
+ 1270, 1273, 1268, 68, 1267, 68, 68, 1271, 1276, 68,
+ 68, 1274, 1275, 1277, 68, 1272, 1278, 68, 68, 1280,
+ 68, 68, 68, 68, 1279, 68, 1284, 1285, 68, 1287,
+ 68, 1286, 1281, 68, 68, 1282, 68, 68, 1288, 68,
+ 1290, 1283, 1293, 68, 1292, 68, 68, 68, 68, 1294,
+ 68, 1296, 1298, 68, 1289, 68, 1297, 1291, 68, 1299,
+ 1301, 1295, 1300, 68, 1302, 68, 1303, 68, 1304, 68,
+ 1305, 68, 68, 68, 68, 1307, 68, 1308, 1309, 68,
+
+ 68, 1310, 1311, 68, 68, 1314, 68, 1306, 1312, 1313,
+ 1315, 68, 1316, 68, 68, 1317, 68, 68, 68, 68,
+ 68, 1324, 68, 68, 1322, 68, 68, 68, 1319, 1320,
+ 1321, 68, 1318, 68, 1325, 68, 68, 68, 1334, 68,
+ 1323, 1332, 1333, 68, 1328, 68, 1327, 1330, 68, 1326,
+ 68, 1329, 68, 1331, 68, 68, 68, 1342, 1343, 68,
+ 68, 1339, 68, 1335, 68, 68, 1336, 1337, 68, 1344,
+ 1338, 68, 68, 1341, 1340, 1350, 68, 1345, 68, 68,
+ 1351, 68, 1346, 1347, 1348, 68, 68, 1352, 68, 68,
+ 1349, 1357, 1358, 68, 68, 1361, 68, 1353, 68, 1354,
+
+ 1355, 1363, 68, 68, 1359, 68, 1356, 1364, 68, 68,
+ 1365, 68, 1360, 68, 1367, 68, 1368, 1362, 1369, 68,
+ 68, 68, 68, 68, 68, 1366, 1373, 1371, 1374, 1376,
+ 68, 1377, 68, 1378, 1370, 1372, 1388, 1375, 68, 1379,
+ 68, 1380, 68, 1381, 68, 68, 68, 68, 68, 1382,
+ 68, 1383, 68, 1384, 68, 68, 68, 1387, 1386, 1389,
+ 68, 68, 1385, 68, 1391, 68, 1393, 1390, 68, 1392,
+ 1394, 1397, 68, 68, 68, 1399, 68, 68, 68, 68,
+ 68, 1400, 1395, 1398, 1401, 68, 1402, 1396, 1404, 68,
+ 68, 1403, 68, 1406, 68, 1408, 68, 1407, 1409, 68,
+
+ 1405, 1410, 68, 1411, 1412, 1413, 1414, 68, 68, 68,
+ 68, 68, 1415, 68, 68, 1416, 68, 68, 1419, 1423,
+ 68, 68, 68, 68, 68, 1427, 68, 68, 1417, 1418,
+ 1425, 1422, 1420, 68, 68, 68, 1421, 68, 1429, 68,
+ 1424, 68, 1426, 1428, 1432, 68, 1430, 68, 1434, 1436,
+ 68, 1437, 68, 68, 68, 68, 1443, 1433, 68, 1435,
+ 1431, 1438, 1439, 1442, 1441, 68, 1440, 68, 68, 68,
+ 68, 68, 1445, 1450, 1444, 1448, 68, 1446, 68, 1452,
+ 68, 68, 68, 1455, 68, 68, 68, 68, 68, 1449,
+ 1447, 68, 68, 68, 1456, 68, 1459, 1454, 1460, 68,
+
+ 1453, 1451, 1457, 1463, 68, 68, 1458, 1465, 68, 68,
+ 1464, 1462, 1468, 68, 68, 1466, 68, 1461, 1469, 68,
+ 68, 1467, 1473, 68, 68, 68, 1471, 68, 1470, 1475,
+ 1477, 68, 1474, 1480, 68, 68, 1472, 1481, 68, 68,
+ 68, 1485, 68, 1610, 1476, 1484, 1482, 68, 1478, 1479,
+ 1486, 68, 1488, 1483, 1487, 68, 1489, 68, 68, 1490,
+ 1491, 68, 68, 68, 1494, 68, 68, 1492, 68, 68,
+ 68, 1493, 68, 1495, 1496, 68, 68, 68, 1504, 68,
+ 68, 1502, 68, 68, 1497, 68, 1498, 1505, 68, 1499,
+ 1500, 1506, 68, 68, 68, 1509, 1501, 1503, 1507, 1508,
+
+ 68, 1511, 68, 1510, 68, 68, 68, 1512, 1513, 1514,
+ 1515, 1516, 1518, 68, 1519, 68, 1520, 68, 68, 68,
+ 1522, 1523, 68, 1517, 68, 68, 68, 68, 68, 1525,
+ 1521, 68, 1529, 68, 68, 68, 1524, 68, 68, 68,
+ 68, 1537, 68, 68, 1526, 1527, 68, 1528, 1531, 68,
+ 68, 1539, 1533, 1530, 1534, 1536, 1532, 68, 1538, 68,
+ 68, 1543, 1540, 68, 1535, 1542, 68, 1547, 1541, 1548,
+ 68, 68, 68, 1544, 68, 1545, 68, 68, 68, 68,
+ 68, 68, 1546, 68, 1549, 68, 68, 1560, 1557, 1550,
+ 1551, 1552, 1554, 1555, 68, 68, 68, 1553, 68, 1558,
+
+ 1556, 1561, 68, 1562, 1559, 1565, 68, 1563, 1566, 68,
+ 68, 68, 68, 1567, 1564, 1570, 68, 68, 68, 68,
+ 68, 68, 1573, 68, 68, 1577, 68, 68, 68, 68,
+ 1568, 1569, 1572, 1578, 1582, 1571, 1576, 1574, 68, 1580,
+ 1575, 68, 1581, 68, 68, 1579, 1584, 1585, 68, 68,
+ 1583, 1586, 68, 68, 68, 68, 1587, 68, 1589, 68,
+ 1591, 68, 1592, 68, 1595, 68, 68, 68, 1598, 1599,
+ 68, 1588, 68, 1590, 1601, 68, 1602, 68, 1593, 1600,
+ 1594, 68, 68, 68, 1596, 1597, 68, 1604, 1603, 68,
+ 1610, 1605, 1608, 68, 1609, 68, 1610, 1610, 1610, 1610,
+
+ 1610, 1610, 1606, 1610, 1610, 1610, 1610, 1610, 1607, 40,
+ 40, 40, 40, 40, 40, 40, 45, 45, 45, 45,
+ 45, 45, 45, 50, 50, 50, 50, 50, 50, 50,
+ 56, 56, 56, 56, 56, 56, 56, 61, 61, 61,
+ 61, 61, 61, 61, 71, 71, 1610, 71, 71, 71,
+ 71, 123, 123, 1610, 1610, 1610, 123, 123, 125, 125,
+ 1610, 1610, 125, 1610, 125, 127, 1610, 1610, 1610, 1610,
+ 1610, 127, 130, 130, 1610, 1610, 1610, 130, 130, 132,
+ 1610, 1610, 1610, 1610, 1610, 132, 134, 134, 1610, 134,
+ 134, 134, 134, 72, 72, 1610, 72, 72, 72, 72,
+
+ 13, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
+ 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
+ 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
+ 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610
+ } ;
+
+static yyconst flex_int16_t yy_chk[3241] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 3,
+ 3, 3, 4, 4, 4, 49, 5, 5, 49, 3,
+ 5, 15, 4, 6, 6, 15, 5, 6, 9, 9,
+ 9, 151, 33, 6, 7, 7, 7, 7, 9, 7,
+ 10, 10, 10, 44, 44, 7, 8, 8, 8, 8,
+ 10, 8, 21, 33, 151, 21, 21, 8, 11, 11,
+ 11, 11, 11, 11, 1616, 20, 29, 20, 20, 11,
+
+ 20, 29, 24, 21, 25, 20, 24, 28, 11, 12,
+ 12, 12, 12, 12, 12, 74, 22, 22, 74, 25,
+ 12, 69, 28, 30, 22, 69, 24, 26, 26, 12,
+ 19, 22, 19, 19, 66, 19, 26, 110, 30, 27,
+ 19, 19, 23, 27, 60, 60, 27, 23, 66, 31,
+ 31, 23, 110, 27, 23, 27, 23, 23, 31, 75,
+ 32, 32, 34, 75, 31, 32, 76, 35, 31, 36,
+ 77, 34, 35, 77, 36, 37, 37, 34, 37, 101,
+ 34, 32, 35, 38, 36, 35, 76, 34, 36, 36,
+ 39, 39, 101, 37, 173, 39, 55, 38, 55, 55,
+
+ 173, 55, 38, 63, 78, 63, 63, 65, 63, 65,
+ 65, 79, 65, 68, 63, 68, 68, 82, 68, 80,
+ 81, 83, 78, 68, 71, 79, 71, 71, 84, 71,
+ 85, 80, 86, 84, 71, 71, 87, 88, 81, 82,
+ 83, 89, 90, 91, 85, 89, 84, 90, 94, 97,
+ 92, 625, 86, 92, 87, 88, 92, 91, 93, 95,
+ 98, 104, 96, 93, 95, 96, 103, 94, 99, 96,
+ 92, 100, 99, 97, 98, 102, 105, 106, 100, 103,
+ 105, 104, 102, 107, 95, 108, 109, 111, 107, 112,
+ 114, 113, 107, 115, 115, 106, 113, 116, 118, 109,
+
+ 117, 119, 114, 119, 120, 108, 111, 112, 121, 120,
+ 122, 124, 124, 132, 115, 116, 117, 140, 126, 118,
+ 121, 126, 131, 131, 119, 140, 139, 128, 122, 128,
+ 128, 133, 128, 133, 133, 134, 133, 134, 134, 136,
+ 134, 139, 136, 137, 138, 141, 134, 142, 137, 138,
+ 143, 149, 144, 145, 130, 143, 143, 144, 145, 146,
+ 141, 146, 148, 148, 150, 154, 153, 142, 152, 150,
+ 149, 153, 152, 155, 157, 156, 159, 159, 158, 154,
+ 160, 146, 147, 158, 162, 161, 147, 156, 155, 162,
+ 156, 147, 157, 163, 163, 167, 147, 177, 166, 164,
+
+ 160, 161, 147, 147, 164, 177, 165, 166, 168, 169,
+ 164, 165, 170, 168, 169, 171, 167, 170, 172, 174,
+ 171, 175, 176, 178, 180, 172, 179, 175, 181, 180,
+ 182, 183, 184, 185, 186, 185, 183, 187, 178, 174,
+ 188, 186, 187, 189, 176, 193, 179, 193, 182, 182,
+ 181, 191, 184, 190, 190, 189, 191, 192, 194, 188,
+ 195, 196, 192, 197, 193, 199, 198, 200, 197, 196,
+ 194, 198, 202, 201, 191, 203, 204, 204, 203, 195,
+ 199, 201, 208, 205, 209, 200, 205, 206, 206, 207,
+ 207, 210, 211, 212, 210, 213, 211, 202, 208, 209,
+
+ 213, 214, 212, 215, 215, 216, 217, 218, 219, 220,
+ 216, 217, 221, 222, 222, 214, 223, 224, 226, 225,
+ 229, 224, 231, 226, 228, 221, 219, 218, 232, 227,
+ 220, 225, 227, 230, 223, 233, 228, 229, 235, 235,
+ 229, 232, 230, 231, 237, 238, 234, 233, 234, 234,
+ 236, 240, 240, 236, 239, 242, 242, 241, 243, 244,
+ 238, 237, 241, 239, 237, 245, 246, 247, 249, 250,
+ 245, 248, 247, 243, 248, 251, 248, 254, 252, 244,
+ 255, 256, 249, 252, 251, 250, 246, 253, 250, 257,
+ 250, 258, 253, 259, 258, 262, 256, 261, 254, 263,
+
+ 255, 265, 264, 257, 262, 296, 296, 259, 266, 268,
+ 258, 260, 261, 260, 260, 272, 265, 267, 269, 270,
+ 263, 264, 267, 260, 273, 260, 260, 260, 266, 268,
+ 260, 271, 274, 269, 270, 272, 271, 274, 273, 275,
+ 276, 277, 277, 278, 277, 276, 279, 281, 280, 282,
+ 283, 282, 284, 285, 283, 275, 286, 287, 302, 302,
+ 290, 281, 279, 278, 280, 286, 287, 285, 288, 290,
+ 284, 289, 291, 288, 292, 289, 294, 291, 286, 293,
+ 292, 294, 295, 293, 297, 298, 300, 299, 301, 297,
+ 304, 308, 301, 129, 303, 295, 299, 309, 300, 303,
+
+ 305, 305, 307, 307, 310, 309, 298, 311, 313, 314,
+ 315, 304, 308, 310, 317, 316, 318, 319, 320, 311,
+ 316, 318, 317, 321, 315, 325, 322, 323, 313, 314,
+ 322, 324, 326, 329, 328, 319, 324, 332, 330, 334,
+ 320, 325, 323, 330, 321, 333, 333, 331, 330, 329,
+ 331, 326, 327, 327, 328, 335, 335, 332, 327, 336,
+ 327, 337, 338, 339, 334, 340, 341, 342, 327, 343,
+ 344, 341, 347, 337, 336, 345, 342, 338, 327, 345,
+ 348, 346, 339, 349, 347, 344, 346, 340, 343, 350,
+ 350, 351, 352, 354, 353, 356, 349, 353, 348, 355,
+
+ 358, 357, 355, 351, 352, 357, 357, 361, 354, 359,
+ 359, 356, 361, 358, 356, 360, 360, 362, 362, 363,
+ 363, 364, 365, 366, 371, 367, 364, 368, 366, 367,
+ 369, 370, 368, 372, 369, 373, 370, 374, 372, 377,
+ 373, 127, 375, 365, 371, 375, 376, 376, 378, 379,
+ 375, 374, 380, 378, 375, 380, 381, 377, 379, 382,
+ 381, 383, 384, 385, 382, 386, 387, 384, 392, 388,
+ 389, 387, 125, 389, 383, 388, 393, 386, 390, 385,
+ 391, 390, 381, 394, 395, 391, 392, 395, 394, 396,
+ 393, 397, 398, 399, 396, 397, 397, 398, 400, 401,
+
+ 403, 400, 399, 401, 401, 402, 404, 402, 404, 405,
+ 406, 407, 408, 409, 410, 415, 400, 409, 411, 403,
+ 412, 413, 421, 410, 414, 416, 416, 405, 406, 414,
+ 407, 417, 408, 411, 415, 417, 413, 418, 412, 419,
+ 420, 421, 422, 423, 419, 425, 424, 428, 418, 426,
+ 423, 424, 425, 427, 426, 422, 420, 429, 427, 430,
+ 431, 432, 435, 444, 429, 428, 432, 433, 430, 434,
+ 433, 436, 436, 434, 431, 439, 438, 440, 441, 439,
+ 436, 438, 442, 435, 443, 447, 453, 450, 444, 440,
+ 442, 454, 460, 459, 455, 453, 441, 454, 455, 123,
+
+ 447, 456, 443, 445, 450, 458, 456, 463, 445, 465,
+ 458, 459, 445, 461, 463, 445, 461, 460, 462, 462,
+ 464, 464, 445, 469, 465, 445, 457, 470, 457, 67,
+ 457, 466, 466, 457, 467, 468, 473, 467, 457, 471,
+ 468, 472, 472, 469, 457, 457, 470, 471, 474, 475,
+ 477, 473, 476, 476, 475, 477, 478, 479, 480, 481,
+ 479, 478, 482, 483, 480, 485, 474, 481, 484, 487,
+ 482, 488, 485, 484, 486, 486, 488, 487, 489, 491,
+ 492, 483, 491, 493, 493, 494, 497, 495, 498, 499,
+ 495, 500, 501, 498, 492, 502, 503, 489, 495, 504,
+
+ 494, 505, 506, 504, 507, 503, 508, 497, 510, 511,
+ 499, 500, 509, 507, 501, 502, 515, 512, 509, 505,
+ 508, 506, 512, 511, 513, 516, 514, 517, 510, 513,
+ 514, 518, 517, 519, 519, 515, 520, 516, 522, 521,
+ 523, 520, 521, 524, 525, 526, 526, 528, 524, 527,
+ 527, 529, 518, 523, 530, 529, 522, 531, 532, 534,
+ 535, 536, 528, 534, 525, 537, 538, 553, 61, 539,
+ 540, 538, 532, 530, 541, 535, 546, 542, 541, 553,
+ 537, 531, 533, 539, 540, 533, 536, 533, 545, 543,
+ 544, 533, 542, 533, 543, 544, 547, 546, 533, 548,
+
+ 558, 549, 545, 552, 543, 548, 549, 550, 550, 551,
+ 547, 554, 554, 550, 551, 550, 555, 552, 556, 558,
+ 557, 555, 559, 559, 560, 562, 556, 564, 560, 563,
+ 562, 565, 563, 550, 557, 566, 567, 569, 568, 571,
+ 566, 573, 576, 570, 565, 578, 564, 568, 570, 572,
+ 573, 577, 574, 579, 611, 567, 569, 574, 579, 571,
+ 578, 576, 580, 572, 582, 581, 611, 580, 590, 577,
+ 581, 583, 583, 582, 584, 588, 586, 589, 588, 584,
+ 586, 586, 587, 587, 591, 592, 587, 591, 590, 593,
+ 594, 595, 589, 596, 593, 594, 597, 595, 598, 598,
+
+ 600, 599, 597, 602, 601, 603, 592, 601, 604, 596,
+ 599, 606, 605, 608, 607, 610, 606, 609, 600, 607,
+ 609, 602, 612, 614, 603, 605, 610, 612, 604, 613,
+ 616, 608, 615, 615, 613, 618, 617, 619, 614, 620,
+ 622, 619, 621, 623, 626, 627, 628, 618, 629, 616,
+ 617, 621, 56, 629, 637, 632, 630, 620, 626, 622,
+ 627, 630, 631, 633, 635, 634, 628, 631, 623, 632,
+ 634, 636, 639, 637, 638, 638, 640, 633, 641, 635,
+ 642, 642, 640, 643, 644, 645, 636, 647, 643, 646,
+ 639, 644, 646, 648, 650, 649, 651, 652, 641, 645,
+
+ 649, 651, 648, 653, 655, 647, 654, 653, 656, 657,
+ 658, 659, 660, 650, 661, 654, 652, 663, 662, 655,
+ 661, 657, 664, 656, 667, 669, 745, 668, 745, 658,
+ 660, 664, 659, 662, 666, 668, 670, 663, 667, 666,
+ 672, 670, 671, 673, 674, 669, 671, 671, 683, 675,
+ 676, 676, 677, 674, 675, 678, 673, 677, 680, 672,
+ 678, 679, 679, 681, 682, 684, 683, 680, 681, 685,
+ 684, 686, 688, 687, 685, 691, 686, 687, 682, 691,
+ 689, 688, 692, 693, 694, 695, 688, 696, 688, 697,
+ 688, 689, 698, 699, 701, 696, 706, 692, 694, 700,
+
+ 700, 693, 705, 697, 695, 702, 702, 705, 704, 701,
+ 698, 704, 707, 707, 708, 706, 709, 709, 699, 710,
+ 711, 711, 712, 713, 710, 714, 715, 717, 713, 716,
+ 716, 715, 718, 714, 708, 721, 719, 726, 718, 722,
+ 721, 723, 712, 719, 722, 717, 723, 724, 725, 727,
+ 728, 728, 724, 729, 730, 732, 726, 725, 731, 733,
+ 727, 736, 734, 731, 735, 735, 737, 738, 748, 739,
+ 750, 740, 748, 729, 746, 732, 740, 730, 742, 733,
+ 734, 736, 742, 742, 743, 738, 744, 749, 746, 750,
+ 747, 737, 739, 743, 744, 747, 751, 752, 749, 753,
+
+ 754, 755, 756, 759, 753, 757, 756, 758, 761, 760,
+ 765, 762, 763, 769, 51, 752, 762, 759, 754, 763,
+ 764, 755, 751, 757, 760, 764, 758, 761, 765, 766,
+ 767, 768, 773, 773, 769, 770, 771, 768, 766, 772,
+ 770, 771, 775, 775, 772, 767, 776, 777, 778, 779,
+ 781, 776, 782, 779, 779, 780, 780, 783, 784, 785,
+ 787, 777, 788, 786, 791, 785, 789, 778, 786, 781,
+ 790, 782, 792, 793, 794, 794, 796, 784, 791, 787,
+ 796, 788, 795, 783, 797, 789, 798, 795, 793, 790,
+ 799, 800, 800, 792, 801, 798, 802, 797, 803, 801,
+
+ 802, 804, 806, 808, 809, 809, 804, 810, 808, 819,
+ 799, 818, 810, 812, 812, 814, 814, 820, 803, 816,
+ 806, 822, 816, 817, 817, 821, 818, 823, 823, 824,
+ 821, 820, 825, 825, 819, 826, 822, 827, 828, 829,
+ 830, 832, 828, 834, 834, 830, 833, 835, 827, 824,
+ 836, 837, 838, 841, 838, 842, 839, 826, 829, 832,
+ 833, 839, 846, 840, 843, 843, 844, 835, 840, 842,
+ 836, 837, 844, 841, 847, 847, 848, 849, 850, 855,
+ 851, 850, 852, 853, 850, 851, 846, 852, 848, 854,
+ 856, 859, 853, 856, 854, 857, 850, 849, 858, 858,
+
+ 857, 860, 861, 862, 855, 863, 864, 867, 862, 859,
+ 866, 864, 865, 865, 868, 866, 869, 870, 871, 872,
+ 860, 873, 861, 874, 875, 867, 873, 876, 863, 880,
+ 871, 870, 872, 879, 868, 878, 869, 881, 880, 885,
+ 879, 880, 885, 874, 875, 884, 884, 886, 876, 887,
+ 878, 888, 886, 881, 889, 890, 892, 891, 893, 893,
+ 888, 892, 894, 895, 890, 887, 891, 890, 896, 897,
+ 898, 899, 901, 889, 900, 900, 895, 908, 902, 904,
+ 905, 907, 894, 897, 904, 906, 896, 907, 901, 899,
+ 906, 910, 915, 914, 909, 898, 902, 908, 905, 909,
+
+ 911, 914, 916, 911, 910, 915, 917, 918, 919, 911,
+ 920, 922, 918, 923, 924, 928, 925, 923, 926, 924,
+ 916, 925, 929, 926, 919, 917, 927, 931, 920, 930,
+ 930, 922, 932, 933, 934, 927, 935, 929, 928, 934,
+ 936, 931, 50, 937, 932, 933, 938, 938, 935, 937,
+ 939, 939, 941, 942, 942, 943, 945, 944, 936, 946,
+ 947, 941, 944, 948, 949, 945, 951, 943, 948, 950,
+ 954, 946, 956, 949, 953, 947, 952, 952, 955, 953,
+ 958, 951, 957, 957, 959, 959, 949, 960, 960, 950,
+ 961, 954, 956, 962, 964, 961, 962, 955, 965, 964,
+
+ 958, 966, 967, 968, 968, 970, 966, 969, 969, 971,
+ 970, 972, 973, 974, 975, 977, 965, 976, 976, 978,
+ 978, 971, 979, 971, 983, 981, 986, 967, 971, 982,
+ 982, 972, 973, 974, 981, 975, 984, 985, 988, 983,
+ 989, 977, 979, 984, 987, 987, 985, 993, 991, 992,
+ 994, 998, 986, 991, 992, 996, 989, 994, 995, 995,
+ 996, 997, 999, 1000, 988, 1001, 1002, 993, 1005, 1003,
+ 997, 998, 1002, 1004, 1004, 1006, 1006, 999, 1003, 1005,
+ 1001, 1007, 1000, 1008, 1005, 1009, 1010, 1010, 1011, 1012,
+ 1009, 1013, 1011, 1011, 1012, 1014, 1015, 1008, 1016, 1017,
+
+ 1018, 1015, 1007, 1017, 1019, 1021, 1020, 1014, 1022, 1023,
+ 1016, 1020, 1018, 1022, 45, 1025, 1031, 1013, 1025, 1026,
+ 1026, 1023, 1027, 1027, 1028, 1031, 1029, 1021, 1030, 1019,
+ 1028, 1029, 1034, 1036, 1030, 1037, 1037, 1038, 1039, 1042,
+ 1040, 1041, 1045, 1042, 1034, 1036, 1043, 1039, 1044, 1047,
+ 1047, 1043, 1048, 1044, 1049, 1050, 1045, 1038, 1040, 1055,
+ 1041, 1047, 1056, 1049, 1050, 1052, 1052, 1056, 1057, 1063,
+ 1048, 1058, 1058, 1055, 1059, 1062, 1059, 1060, 1060, 1064,
+ 1064, 1065, 1062, 1066, 1067, 1057, 1068, 1070, 1069, 1063,
+ 1074, 1073, 1072, 1073, 1079, 1066, 1067, 1072, 1068, 1077,
+
+ 1075, 1080, 1065, 1069, 1078, 1078, 1080, 1070, 1074, 1075,
+ 1081, 1082, 1081, 1077, 1083, 1084, 1082, 1085, 1086, 1083,
+ 1079, 1087, 1089, 1086, 1090, 40, 1087, 1091, 1091, 1102,
+ 1092, 1093, 1094, 1084, 1094, 1095, 1096, 1085, 1090, 1101,
+ 1093, 1089, 1092, 1093, 1095, 1098, 1099, 1103, 1096, 1102,
+ 1098, 1099, 1101, 1105, 1107, 1108, 1109, 1110, 1112, 1105,
+ 1107, 1111, 1111, 1103, 1113, 1113, 1110, 1112, 1114, 1115,
+ 1108, 1116, 1117, 1115, 1118, 1118, 1116, 1129, 1119, 1122,
+ 1125, 1109, 1123, 1123, 1131, 1117, 1119, 1114, 1122, 1124,
+ 1124, 1126, 1125, 1127, 1127, 1130, 1126, 1132, 1133, 1134,
+
+ 1130, 1138, 1129, 1133, 1135, 1136, 1136, 1131, 1140, 1137,
+ 1139, 1141, 1132, 1137, 1143, 1139, 1138, 1134, 1144, 1145,
+ 1135, 1146, 1147, 1149, 1149, 1150, 1151, 14, 1150, 1152,
+ 1141, 1153, 1153, 1146, 1140, 1154, 1154, 1144, 1143, 1151,
+ 1145, 1156, 1152, 1147, 1155, 1155, 1157, 1157, 1158, 1158,
+ 1159, 1160, 1160, 1162, 1156, 1161, 1161, 1164, 1165, 1165,
+ 1166, 1169, 1164, 1167, 1167, 1168, 1173, 1169, 1170, 1159,
+ 1177, 1170, 1162, 1171, 1171, 1172, 1172, 1174, 1174, 1166,
+ 1176, 1176, 1179, 1168, 1182, 1173, 1178, 1178, 1180, 1171,
+ 1181, 1179, 1183, 1184, 1185, 1181, 1177, 1186, 1187, 1185,
+
+ 1180, 1188, 1189, 1190, 1193, 1183, 1200, 1187, 1190, 1182,
+ 1188, 1191, 1186, 1195, 1184, 1191, 1189, 1196, 1196, 1201,
+ 1197, 1200, 1195, 1204, 1193, 1197, 1198, 1198, 1204, 1203,
+ 1208, 1201, 1203, 1205, 1205, 1198, 1207, 1207, 1209, 1209,
+ 1210, 1211, 1212, 1215, 1208, 1213, 1213, 1215, 1216, 1217,
+ 1217, 1216, 1210, 1218, 1219, 1211, 1220, 1221, 1218, 1222,
+ 1220, 1212, 1223, 1224, 1222, 1226, 1227, 1223, 1228, 1224,
+ 1229, 1227, 1229, 1246, 1219, 1238, 1228, 1221, 1232, 1232,
+ 1238, 1226, 1235, 1235, 1239, 1239, 1241, 1241, 1243, 1244,
+ 1244, 1245, 1247, 1243, 1254, 1246, 1252, 1247, 1249, 1249,
+
+ 1253, 1252, 1253, 1259, 1255, 1256, 1256, 1245, 1254, 1255,
+ 1257, 1257, 1258, 1258, 1260, 1259, 1261, 1262, 1263, 1264,
+ 1265, 1266, 1266, 1268, 1264, 1267, 1269, 1271, 1261, 1262,
+ 1263, 1270, 1260, 1272, 1267, 1273, 1274, 1275, 1276, 1276,
+ 1265, 1274, 1275, 1279, 1270, 1281, 1269, 1272, 1280, 1268,
+ 1282, 1271, 1283, 1273, 1284, 1285, 1286, 1286, 1288, 1288,
+ 1289, 1283, 1290, 1279, 1291, 1292, 1280, 1281, 1293, 1289,
+ 1282, 1294, 1297, 1285, 1284, 1295, 1295, 1290, 1298, 1299,
+ 1296, 1301, 1291, 1292, 1293, 1296, 1304, 1297, 1305, 1307,
+ 1294, 1305, 1306, 1306, 1308, 1310, 1310, 1298, 1311, 1299,
+
+ 1301, 1312, 1312, 1318, 1307, 1319, 1304, 1313, 1313, 1317,
+ 1317, 1320, 1308, 1321, 1319, 1322, 1320, 1311, 1321, 1323,
+ 1325, 1326, 1328, 1327, 1342, 1318, 1326, 1323, 1327, 1329,
+ 1329, 1330, 1330, 1331, 1322, 1325, 1342, 1328, 1331, 1332,
+ 1332, 1333, 1333, 1335, 1338, 1336, 1337, 1339, 1335, 1336,
+ 1340, 1337, 1341, 1338, 1345, 1346, 1344, 1341, 1340, 1344,
+ 1347, 1349, 1339, 1351, 1346, 1348, 1348, 1345, 1352, 1347,
+ 1349, 1353, 1353, 1356, 1354, 1355, 1355, 1359, 1360, 1357,
+ 1365, 1356, 1351, 1354, 1357, 1371, 1359, 1352, 1362, 1362,
+ 1372, 1360, 1366, 1366, 1367, 1368, 1368, 1367, 1369, 1369,
+
+ 1365, 1370, 1370, 1371, 1372, 1373, 1374, 1374, 1375, 1378,
+ 1373, 1381, 1375, 1382, 1383, 1378, 1384, 1385, 1382, 1386,
+ 1386, 1387, 1388, 1389, 1390, 1390, 1393, 1391, 1381, 1381,
+ 1388, 1385, 1383, 1392, 1394, 1395, 1384, 1396, 1392, 1407,
+ 1387, 1400, 1389, 1391, 1395, 1398, 1393, 1402, 1398, 1401,
+ 1401, 1402, 1403, 1405, 1406, 1412, 1412, 1396, 1411, 1400,
+ 1394, 1403, 1405, 1411, 1407, 1413, 1406, 1415, 1416, 1417,
+ 1418, 1419, 1415, 1420, 1413, 1418, 1421, 1416, 1420, 1422,
+ 1422, 1424, 1425, 1426, 1426, 1427, 1428, 1429, 1430, 1419,
+ 1417, 1432, 1433, 1431, 1427, 1438, 1430, 1425, 1431, 1439,
+
+ 1424, 1421, 1428, 1434, 1434, 1435, 1429, 1437, 1437, 1442,
+ 1435, 1433, 1440, 1440, 1443, 1438, 1444, 1432, 1441, 1441,
+ 1446, 1439, 1445, 1445, 1447, 1448, 1443, 1454, 1442, 1447,
+ 1449, 1450, 1446, 1451, 1451, 1449, 1444, 1453, 1453, 1456,
+ 1457, 1458, 1458, 13, 1448, 1457, 1454, 1461, 1450, 1450,
+ 1459, 1459, 1461, 1456, 1460, 1460, 1462, 1462, 1464, 1464,
+ 1466, 1466, 1467, 1470, 1471, 1471, 1475, 1467, 1472, 1474,
+ 1476, 1470, 1477, 1472, 1474, 1478, 1479, 1482, 1483, 1483,
+ 1493, 1479, 1497, 1484, 1475, 1495, 1476, 1484, 1499, 1477,
+ 1477, 1488, 1488, 1498, 1490, 1493, 1478, 1482, 1490, 1492,
+
+ 1492, 1496, 1496, 1495, 1502, 1500, 1501, 1497, 1498, 1499,
+ 1500, 1501, 1503, 1503, 1505, 1505, 1507, 1507, 1509, 1510,
+ 1510, 1512, 1513, 1502, 1514, 1515, 1512, 1516, 1521, 1514,
+ 1509, 1517, 1521, 1522, 1525, 1523, 1513, 1524, 1526, 1527,
+ 1528, 1529, 1529, 1533, 1515, 1516, 1531, 1517, 1523, 1530,
+ 1534, 1531, 1525, 1522, 1526, 1528, 1524, 1532, 1530, 1536,
+ 1538, 1535, 1532, 1539, 1527, 1534, 1535, 1540, 1533, 1541,
+ 1542, 1544, 1540, 1536, 1541, 1538, 1543, 1545, 1546, 1547,
+ 1548, 1549, 1539, 1550, 1542, 1552, 1553, 1553, 1550, 1543,
+ 1544, 1545, 1547, 1548, 1551, 1557, 1554, 1546, 1555, 1551,
+
+ 1549, 1554, 1556, 1555, 1552, 1558, 1560, 1556, 1559, 1559,
+ 1558, 1561, 1562, 1560, 1557, 1563, 1564, 1567, 1568, 1565,
+ 1563, 1569, 1567, 1570, 1571, 1571, 1573, 1578, 1572, 1576,
+ 1561, 1562, 1565, 1572, 1576, 1564, 1570, 1568, 1574, 1574,
+ 1569, 1575, 1575, 1577, 1580, 1573, 1578, 1579, 1579, 1581,
+ 1577, 1580, 1582, 1583, 1584, 1586, 1581, 1587, 1583, 1588,
+ 1586, 1589, 1587, 1590, 1590, 1591, 1592, 1593, 1593, 1594,
+ 1594, 1582, 1595, 1584, 1596, 1596, 1597, 1597, 1588, 1595,
+ 1589, 1598, 1600, 1604, 1591, 1592, 1603, 1600, 1598, 1605,
+ 0, 1603, 1606, 1606, 1607, 1607, 0, 0, 0, 0,
+
+ 0, 0, 1604, 0, 0, 0, 0, 0, 1605, 1611,
+ 1611, 1611, 1611, 1611, 1611, 1611, 1612, 1612, 1612, 1612,
+ 1612, 1612, 1612, 1613, 1613, 1613, 1613, 1613, 1613, 1613,
+ 1614, 1614, 1614, 1614, 1614, 1614, 1614, 1615, 1615, 1615,
+ 1615, 1615, 1615, 1615, 1617, 1617, 0, 1617, 1617, 1617,
+ 1617, 1618, 1618, 0, 0, 0, 1618, 1618, 1619, 1619,
+ 0, 0, 1619, 0, 1619, 1620, 0, 0, 0, 0,
+ 0, 1620, 1621, 1621, 0, 0, 0, 1621, 1621, 1622,
+ 0, 0, 0, 0, 0, 1622, 1623, 1623, 0, 1623,
+ 1623, 1623, 1623, 1624, 1624, 0, 1624, 1624, 1624, 1624,
+
+ 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
+ 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
+ 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610,
+ 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610, 1610
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+static int yy_more_flag = 0;
+static int yy_more_len = 0;
+#define yymore() ((yy_more_flag) = 1)
+#define YY_MORE_ADJ (yy_more_len)
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "./util/configlexer.lex"
+#line 2 "./util/configlexer.lex"
+/*
+ * configlexer.lex - lexical analyzer for unbound config file
+ *
+ * Copyright (c) 2001-2006, NLnet Labs. All rights reserved
+ *
+ * See LICENSE for the license.
+ *
+ */
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#ifdef HAVE_GLOB_H
+# include <glob.h>
+#endif
+
+#include "util/config_file.h"
+#include "util/configparser.h"
+void ub_c_error(const char *message);
+
+#if 0
+#define LEXOUT(s) printf s /* used ONLY when debugging */
+#else
+#define LEXOUT(s)
+#endif
+
+/** avoid warning in about fwrite return value */
+#define ECHO ub_c_error_msg("syntax error at text: %s", yytext)
+
+/** A parser variable, this is a statement in the config file which is
+ * of the form variable: value1 value2 ... nargs is the number of values. */
+#define YDVAR(nargs, var) \
+ num_args=(nargs); \
+ LEXOUT(("v(%s%d) ", yytext, num_args)); \
+ if(num_args > 0) { BEGIN(val); } \
+ return (var);
+
+struct inc_state {
+ char* filename;
+ int line;
+ YY_BUFFER_STATE buffer;
+ struct inc_state* next;
+};
+static struct inc_state* config_include_stack = NULL;
+static int inc_depth = 0;
+static int inc_prev = 0;
+static int num_args = 0;
+
+void init_cfg_parse(void)
+{
+ config_include_stack = NULL;
+ inc_depth = 0;
+ inc_prev = 0;
+ num_args = 0;
+}
+
+static void config_start_include(const char* filename)
+{
+ FILE *input;
+ struct inc_state* s;
+ char* nm;
+ if(inc_depth++ > 100000) {
+ ub_c_error_msg("too many include files");
+ return;
+ }
+ if(strlen(filename) == 0) {
+ ub_c_error_msg("empty include file name");
+ return;
+ }
+ s = (struct inc_state*)malloc(sizeof(*s));
+ if(!s) {
+ ub_c_error_msg("include %s: malloc failure", filename);
+ return;
+ }
+ if(cfg_parser->chroot && strncmp(filename, cfg_parser->chroot,
+ strlen(cfg_parser->chroot)) == 0) {
+ filename += strlen(cfg_parser->chroot);
+ }
+ nm = strdup(filename);
+ if(!nm) {
+ ub_c_error_msg("include %s: strdup failure", filename);
+ free(s);
+ return;
+ }
+ input = fopen(filename, "r");
+ if(!input) {
+ ub_c_error_msg("cannot open include file '%s': %s",
+ filename, strerror(errno));
+ free(s);
+ free(nm);
+ return;
+ }
+ LEXOUT(("switch_to_include_file(%s)\n", filename));
+ s->filename = cfg_parser->filename;
+ s->line = cfg_parser->line;
+ s->buffer = YY_CURRENT_BUFFER;
+ s->next = config_include_stack;
+ config_include_stack = s;
+ cfg_parser->filename = nm;
+ cfg_parser->line = 1;
+ yy_switch_to_buffer(yy_create_buffer(input,YY_BUF_SIZE));
+}
+
+static void config_start_include_glob(const char* filename)
+{
+
+ /* check for wildcards */
+#ifdef HAVE_GLOB
+ glob_t g;
+ size_t i;
+ int r, flags;
+ if(!(!strchr(filename, '*') && !strchr(filename, '?') && !strchr(filename, '[') &&
+ !strchr(filename, '{') && !strchr(filename, '~'))) {
+ flags = 0
+#ifdef GLOB_ERR
+ | GLOB_ERR
+#endif
+#ifdef GLOB_NOSORT
+ | GLOB_NOSORT
+#endif
+#ifdef GLOB_BRACE
+ | GLOB_BRACE
+#endif
+#ifdef GLOB_TILDE
+ | GLOB_TILDE
+#endif
+ ;
+ memset(&g, 0, sizeof(g));
+ r = glob(filename, flags, NULL, &g);
+ if(r) {
+ /* some error */
+ globfree(&g);
+ if(r == GLOB_NOMATCH)
+ return; /* no matches for pattern */
+ config_start_include(filename); /* let original deal with it */
+ return;
+ }
+ /* process files found, if any */
+ for(i=0; i<(size_t)g.gl_pathc; i++) {
+ config_start_include(g.gl_pathv[i]);
+ }
+ globfree(&g);
+ return;
+ }
+#endif /* HAVE_GLOB */
+
+ config_start_include(filename);
+}
+
+static void config_end_include(void)
+{
+ struct inc_state* s = config_include_stack;
+ --inc_depth;
+ if(!s) return;
+ free(cfg_parser->filename);
+ cfg_parser->filename = s->filename;
+ cfg_parser->line = s->line;
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(s->buffer);
+ config_include_stack = s->next;
+ free(s);
+}
+
+#ifndef yy_set_bol /* compat definition, for flex 2.4.6 */
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \
+ }
+#endif
+
+#define YY_NO_INPUT 1
+#line 177 "./util/configlexer.lex"
+#ifndef YY_NO_UNPUT
+#define YY_NO_UNPUT 1
+#endif
+#ifndef YY_NO_INPUT
+#define YY_NO_INPUT 1
+#endif
+
+#line 1879 "<stdout>"
+
+#define INITIAL 0
+#define quotedstring 1
+#define singlequotedstr 2
+#define include 3
+#define include_quoted 4
+#define val 5
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *yyget_in (void );
+
+void yyset_in (FILE * in_str );
+
+FILE *yyget_out (void );
+
+void yyset_out (FILE * out_str );
+
+yy_size_t yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ size_t n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 197 "./util/configlexer.lex"
+
+#line 2066 "<stdout>"
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ (yy_more_len) = 0;
+ if ( (yy_more_flag) )
+ {
+ (yy_more_len) = (yy_c_buf_p) - (yytext_ptr);
+ (yy_more_flag) = 0;
+ }
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 1611 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 3201 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 198 "./util/configlexer.lex"
+{
+ LEXOUT(("SP ")); /* ignore */ }
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 200 "./util/configlexer.lex"
+{
+ /* note that flex makes the longest match and '.' is any but not nl */
+ LEXOUT(("comment(%s) ", yytext)); /* ignore */ }
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 203 "./util/configlexer.lex"
+{ YDVAR(0, VAR_SERVER) }
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 204 "./util/configlexer.lex"
+{ YDVAR(1, VAR_NUM_THREADS) }
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 205 "./util/configlexer.lex"
+{ YDVAR(1, VAR_VERBOSITY) }
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 206 "./util/configlexer.lex"
+{ YDVAR(1, VAR_PORT) }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 207 "./util/configlexer.lex"
+{ YDVAR(1, VAR_OUTGOING_RANGE) }
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 208 "./util/configlexer.lex"
+{ YDVAR(1, VAR_OUTGOING_PORT_PERMIT) }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 209 "./util/configlexer.lex"
+{ YDVAR(1, VAR_OUTGOING_PORT_AVOID) }
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 210 "./util/configlexer.lex"
+{ YDVAR(1, VAR_OUTGOING_NUM_TCP) }
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 211 "./util/configlexer.lex"
+{ YDVAR(1, VAR_INCOMING_NUM_TCP) }
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 212 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DO_IP4) }
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 213 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DO_IP6) }
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 214 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DO_UDP) }
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 215 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DO_TCP) }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 216 "./util/configlexer.lex"
+{ YDVAR(1, VAR_TCP_UPSTREAM) }
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 217 "./util/configlexer.lex"
+{ YDVAR(1, VAR_SSL_UPSTREAM) }
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 218 "./util/configlexer.lex"
+{ YDVAR(1, VAR_SSL_SERVICE_KEY) }
+ YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 219 "./util/configlexer.lex"
+{ YDVAR(1, VAR_SSL_SERVICE_PEM) }
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 220 "./util/configlexer.lex"
+{ YDVAR(1, VAR_SSL_PORT) }
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 221 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DO_DAEMONIZE) }
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 222 "./util/configlexer.lex"
+{ YDVAR(1, VAR_INTERFACE) }
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 223 "./util/configlexer.lex"
+{ YDVAR(1, VAR_INTERFACE) }
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 224 "./util/configlexer.lex"
+{ YDVAR(1, VAR_OUTGOING_INTERFACE) }
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 225 "./util/configlexer.lex"
+{ YDVAR(1, VAR_INTERFACE_AUTOMATIC) }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 226 "./util/configlexer.lex"
+{ YDVAR(1, VAR_SO_RCVBUF) }
+ YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 227 "./util/configlexer.lex"
+{ YDVAR(1, VAR_SO_SNDBUF) }
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 228 "./util/configlexer.lex"
+{ YDVAR(1, VAR_SO_REUSEPORT) }
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 229 "./util/configlexer.lex"
+{ YDVAR(1, VAR_CHROOT) }
+ YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 230 "./util/configlexer.lex"
+{ YDVAR(1, VAR_USERNAME) }
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 231 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DIRECTORY) }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 232 "./util/configlexer.lex"
+{ YDVAR(1, VAR_LOGFILE) }
+ YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 233 "./util/configlexer.lex"
+{ YDVAR(1, VAR_PIDFILE) }
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 234 "./util/configlexer.lex"
+{ YDVAR(1, VAR_ROOT_HINTS) }
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 235 "./util/configlexer.lex"
+{ YDVAR(1, VAR_EDNS_BUFFER_SIZE) }
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 236 "./util/configlexer.lex"
+{ YDVAR(1, VAR_MSG_BUFFER_SIZE) }
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 237 "./util/configlexer.lex"
+{ YDVAR(1, VAR_MSG_CACHE_SIZE) }
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 238 "./util/configlexer.lex"
+{ YDVAR(1, VAR_MSG_CACHE_SLABS) }
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 239 "./util/configlexer.lex"
+{ YDVAR(1, VAR_RRSET_CACHE_SIZE) }
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 240 "./util/configlexer.lex"
+{ YDVAR(1, VAR_RRSET_CACHE_SLABS) }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 241 "./util/configlexer.lex"
+{ YDVAR(1, VAR_CACHE_MAX_TTL) }
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 242 "./util/configlexer.lex"
+{ YDVAR(1, VAR_CACHE_MIN_TTL) }
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 243 "./util/configlexer.lex"
+{ YDVAR(1, VAR_INFRA_HOST_TTL) }
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 244 "./util/configlexer.lex"
+{ YDVAR(1, VAR_INFRA_LAME_TTL) }
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 245 "./util/configlexer.lex"
+{ YDVAR(1, VAR_INFRA_CACHE_SLABS) }
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 246 "./util/configlexer.lex"
+{ YDVAR(1, VAR_INFRA_CACHE_NUMHOSTS) }
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 247 "./util/configlexer.lex"
+{ YDVAR(1, VAR_INFRA_CACHE_LAME_SIZE) }
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 248 "./util/configlexer.lex"
+{ YDVAR(1, VAR_NUM_QUERIES_PER_THREAD) }
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 249 "./util/configlexer.lex"
+{ YDVAR(1, VAR_JOSTLE_TIMEOUT) }
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 250 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DELAY_CLOSE) }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 251 "./util/configlexer.lex"
+{ YDVAR(1, VAR_TARGET_FETCH_POLICY) }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 252 "./util/configlexer.lex"
+{ YDVAR(1, VAR_HARDEN_SHORT_BUFSIZE) }
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 253 "./util/configlexer.lex"
+{ YDVAR(1, VAR_HARDEN_LARGE_QUERIES) }
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 254 "./util/configlexer.lex"
+{ YDVAR(1, VAR_HARDEN_GLUE) }
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 255 "./util/configlexer.lex"
+{ YDVAR(1, VAR_HARDEN_DNSSEC_STRIPPED) }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 256 "./util/configlexer.lex"
+{ YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) }
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 257 "./util/configlexer.lex"
+{ YDVAR(1, VAR_HARDEN_REFERRAL_PATH) }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 258 "./util/configlexer.lex"
+{ YDVAR(1, VAR_USE_CAPS_FOR_ID) }
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 259 "./util/configlexer.lex"
+{ YDVAR(1, VAR_UNWANTED_REPLY_THRESHOLD) }
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 260 "./util/configlexer.lex"
+{ YDVAR(1, VAR_PRIVATE_ADDRESS) }
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 261 "./util/configlexer.lex"
+{ YDVAR(1, VAR_PRIVATE_DOMAIN) }
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 262 "./util/configlexer.lex"
+{ YDVAR(1, VAR_PREFETCH_KEY) }
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 263 "./util/configlexer.lex"
+{ YDVAR(1, VAR_PREFETCH) }
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 264 "./util/configlexer.lex"
+{ YDVAR(0, VAR_STUB_ZONE) }
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 265 "./util/configlexer.lex"
+{ YDVAR(1, VAR_NAME) }
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 266 "./util/configlexer.lex"
+{ YDVAR(1, VAR_STUB_ADDR) }
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 267 "./util/configlexer.lex"
+{ YDVAR(1, VAR_STUB_HOST) }
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 268 "./util/configlexer.lex"
+{ YDVAR(1, VAR_STUB_PRIME) }
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 269 "./util/configlexer.lex"
+{ YDVAR(1, VAR_STUB_FIRST) }
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 270 "./util/configlexer.lex"
+{ YDVAR(0, VAR_FORWARD_ZONE) }
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 271 "./util/configlexer.lex"
+{ YDVAR(1, VAR_FORWARD_ADDR) }
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 272 "./util/configlexer.lex"
+{ YDVAR(1, VAR_FORWARD_HOST) }
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 273 "./util/configlexer.lex"
+{ YDVAR(1, VAR_FORWARD_FIRST) }
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 274 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DO_NOT_QUERY_ADDRESS) }
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 275 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DO_NOT_QUERY_LOCALHOST) }
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 276 "./util/configlexer.lex"
+{ YDVAR(2, VAR_ACCESS_CONTROL) }
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 277 "./util/configlexer.lex"
+{ YDVAR(1, VAR_HIDE_IDENTITY) }
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 278 "./util/configlexer.lex"
+{ YDVAR(1, VAR_HIDE_VERSION) }
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 279 "./util/configlexer.lex"
+{ YDVAR(1, VAR_IDENTITY) }
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 280 "./util/configlexer.lex"
+{ YDVAR(1, VAR_VERSION) }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 281 "./util/configlexer.lex"
+{ YDVAR(1, VAR_MODULE_CONF) }
+ YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 282 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DLV_ANCHOR) }
+ YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 283 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DLV_ANCHOR_FILE) }
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 284 "./util/configlexer.lex"
+{ YDVAR(1, VAR_TRUST_ANCHOR_FILE) }
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 285 "./util/configlexer.lex"
+{ YDVAR(1, VAR_AUTO_TRUST_ANCHOR_FILE) }
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 286 "./util/configlexer.lex"
+{ YDVAR(1, VAR_TRUSTED_KEYS_FILE) }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 287 "./util/configlexer.lex"
+{ YDVAR(1, VAR_TRUST_ANCHOR) }
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 288 "./util/configlexer.lex"
+{ YDVAR(1, VAR_VAL_OVERRIDE_DATE) }
+ YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 289 "./util/configlexer.lex"
+{ YDVAR(1, VAR_VAL_SIG_SKEW_MIN) }
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 290 "./util/configlexer.lex"
+{ YDVAR(1, VAR_VAL_SIG_SKEW_MAX) }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 291 "./util/configlexer.lex"
+{ YDVAR(1, VAR_BOGUS_TTL) }
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 292 "./util/configlexer.lex"
+{ YDVAR(1, VAR_VAL_CLEAN_ADDITIONAL) }
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 293 "./util/configlexer.lex"
+{ YDVAR(1, VAR_VAL_PERMISSIVE_MODE) }
+ YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 294 "./util/configlexer.lex"
+{ YDVAR(1, VAR_IGNORE_CD_FLAG) }
+ YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 295 "./util/configlexer.lex"
+{ YDVAR(1, VAR_VAL_LOG_LEVEL) }
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 296 "./util/configlexer.lex"
+{ YDVAR(1, VAR_KEY_CACHE_SIZE) }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 297 "./util/configlexer.lex"
+{ YDVAR(1, VAR_KEY_CACHE_SLABS) }
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 298 "./util/configlexer.lex"
+{ YDVAR(1, VAR_NEG_CACHE_SIZE) }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+#line 299 "./util/configlexer.lex"
+{
+ YDVAR(1, VAR_VAL_NSEC3_KEYSIZE_ITERATIONS) }
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+#line 301 "./util/configlexer.lex"
+{ YDVAR(1, VAR_ADD_HOLDDOWN) }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 302 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DEL_HOLDDOWN) }
+ YY_BREAK
+case 102:
+YY_RULE_SETUP
+#line 303 "./util/configlexer.lex"
+{ YDVAR(1, VAR_KEEP_MISSING) }
+ YY_BREAK
+case 103:
+YY_RULE_SETUP
+#line 304 "./util/configlexer.lex"
+{ YDVAR(1, VAR_USE_SYSLOG) }
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+#line 305 "./util/configlexer.lex"
+{ YDVAR(1, VAR_LOG_TIME_ASCII) }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+#line 306 "./util/configlexer.lex"
+{ YDVAR(1, VAR_LOG_QUERIES) }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 307 "./util/configlexer.lex"
+{ YDVAR(2, VAR_LOCAL_ZONE) }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 308 "./util/configlexer.lex"
+{ YDVAR(1, VAR_LOCAL_DATA) }
+ YY_BREAK
+case 108:
+YY_RULE_SETUP
+#line 309 "./util/configlexer.lex"
+{ YDVAR(1, VAR_LOCAL_DATA_PTR) }
+ YY_BREAK
+case 109:
+YY_RULE_SETUP
+#line 310 "./util/configlexer.lex"
+{ YDVAR(1, VAR_UNBLOCK_LAN_ZONES) }
+ YY_BREAK
+case 110:
+YY_RULE_SETUP
+#line 311 "./util/configlexer.lex"
+{ YDVAR(1, VAR_STATISTICS_INTERVAL) }
+ YY_BREAK
+case 111:
+YY_RULE_SETUP
+#line 312 "./util/configlexer.lex"
+{ YDVAR(1, VAR_STATISTICS_CUMULATIVE) }
+ YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 313 "./util/configlexer.lex"
+{ YDVAR(1, VAR_EXTENDED_STATISTICS) }
+ YY_BREAK
+case 113:
+YY_RULE_SETUP
+#line 314 "./util/configlexer.lex"
+{ YDVAR(0, VAR_REMOTE_CONTROL) }
+ YY_BREAK
+case 114:
+YY_RULE_SETUP
+#line 315 "./util/configlexer.lex"
+{ YDVAR(1, VAR_CONTROL_ENABLE) }
+ YY_BREAK
+case 115:
+YY_RULE_SETUP
+#line 316 "./util/configlexer.lex"
+{ YDVAR(1, VAR_CONTROL_INTERFACE) }
+ YY_BREAK
+case 116:
+YY_RULE_SETUP
+#line 317 "./util/configlexer.lex"
+{ YDVAR(1, VAR_CONTROL_PORT) }
+ YY_BREAK
+case 117:
+YY_RULE_SETUP
+#line 318 "./util/configlexer.lex"
+{ YDVAR(1, VAR_SERVER_KEY_FILE) }
+ YY_BREAK
+case 118:
+YY_RULE_SETUP
+#line 319 "./util/configlexer.lex"
+{ YDVAR(1, VAR_SERVER_CERT_FILE) }
+ YY_BREAK
+case 119:
+YY_RULE_SETUP
+#line 320 "./util/configlexer.lex"
+{ YDVAR(1, VAR_CONTROL_KEY_FILE) }
+ YY_BREAK
+case 120:
+YY_RULE_SETUP
+#line 321 "./util/configlexer.lex"
+{ YDVAR(1, VAR_CONTROL_CERT_FILE) }
+ YY_BREAK
+case 121:
+YY_RULE_SETUP
+#line 322 "./util/configlexer.lex"
+{ YDVAR(1, VAR_PYTHON_SCRIPT) }
+ YY_BREAK
+case 122:
+YY_RULE_SETUP
+#line 323 "./util/configlexer.lex"
+{ YDVAR(0, VAR_PYTHON) }
+ YY_BREAK
+case 123:
+YY_RULE_SETUP
+#line 324 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DOMAIN_INSECURE) }
+ YY_BREAK
+case 124:
+YY_RULE_SETUP
+#line 325 "./util/configlexer.lex"
+{ YDVAR(1, VAR_MINIMAL_RESPONSES) }
+ YY_BREAK
+case 125:
+YY_RULE_SETUP
+#line 326 "./util/configlexer.lex"
+{ YDVAR(1, VAR_RRSET_ROUNDROBIN) }
+ YY_BREAK
+case 126:
+YY_RULE_SETUP
+#line 327 "./util/configlexer.lex"
+{ YDVAR(1, VAR_MAX_UDP_SIZE) }
+ YY_BREAK
+case 127:
+YY_RULE_SETUP
+#line 328 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DNS64_PREFIX) }
+ YY_BREAK
+case 128:
+YY_RULE_SETUP
+#line 329 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DNS64_SYNTHALL) }
+ YY_BREAK
+case 129:
+YY_RULE_SETUP
+#line 330 "./util/configlexer.lex"
+{ YDVAR(0, VAR_DNSTAP) }
+ YY_BREAK
+case 130:
+YY_RULE_SETUP
+#line 331 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DNSTAP_ENABLE) }
+ YY_BREAK
+case 131:
+YY_RULE_SETUP
+#line 332 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DNSTAP_SOCKET_PATH) }
+ YY_BREAK
+case 132:
+YY_RULE_SETUP
+#line 333 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DNSTAP_SEND_IDENTITY) }
+ YY_BREAK
+case 133:
+YY_RULE_SETUP
+#line 334 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DNSTAP_SEND_VERSION) }
+ YY_BREAK
+case 134:
+YY_RULE_SETUP
+#line 335 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DNSTAP_IDENTITY) }
+ YY_BREAK
+case 135:
+YY_RULE_SETUP
+#line 336 "./util/configlexer.lex"
+{ YDVAR(1, VAR_DNSTAP_VERSION) }
+ YY_BREAK
+case 136:
+YY_RULE_SETUP
+#line 337 "./util/configlexer.lex"
+{
+ YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES) }
+ YY_BREAK
+case 137:
+YY_RULE_SETUP
+#line 339 "./util/configlexer.lex"
+{
+ YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES) }
+ YY_BREAK
+case 138:
+YY_RULE_SETUP
+#line 341 "./util/configlexer.lex"
+{
+ YDVAR(1, VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES) }
+ YY_BREAK
+case 139:
+YY_RULE_SETUP
+#line 343 "./util/configlexer.lex"
+{
+ YDVAR(1, VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES) }
+ YY_BREAK
+case 140:
+YY_RULE_SETUP
+#line 345 "./util/configlexer.lex"
+{
+ YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) }
+ YY_BREAK
+case 141:
+YY_RULE_SETUP
+#line 347 "./util/configlexer.lex"
+{
+ YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) }
+ YY_BREAK
+case 142:
+/* rule 142 can match eol */
+YY_RULE_SETUP
+#line 349 "./util/configlexer.lex"
+{ LEXOUT(("NL\n")); cfg_parser->line++; }
+ YY_BREAK
+/* Quoted strings. Strip leading and ending quotes */
+case 143:
+YY_RULE_SETUP
+#line 352 "./util/configlexer.lex"
+{ BEGIN(quotedstring); LEXOUT(("QS ")); }
+ YY_BREAK
+case YY_STATE_EOF(quotedstring):
+#line 353 "./util/configlexer.lex"
+{
+ yyerror("EOF inside quoted string");
+ if(--num_args == 0) { BEGIN(INITIAL); }
+ else { BEGIN(val); }
+}
+ YY_BREAK
+case 144:
+YY_RULE_SETUP
+#line 358 "./util/configlexer.lex"
+{ LEXOUT(("STR(%s) ", yytext)); yymore(); }
+ YY_BREAK
+case 145:
+/* rule 145 can match eol */
+YY_RULE_SETUP
+#line 359 "./util/configlexer.lex"
+{ yyerror("newline inside quoted string, no end \"");
+ cfg_parser->line++; BEGIN(INITIAL); }
+ YY_BREAK
+case 146:
+YY_RULE_SETUP
+#line 361 "./util/configlexer.lex"
+{
+ LEXOUT(("QE "));
+ if(--num_args == 0) { BEGIN(INITIAL); }
+ else { BEGIN(val); }
+ yytext[yyleng - 1] = '\0';
+ yylval.str = strdup(yytext);
+ if(!yylval.str)
+ yyerror("out of memory");
+ return STRING_ARG;
+}
+ YY_BREAK
+/* Single Quoted strings. Strip leading and ending quotes */
+case 147:
+YY_RULE_SETUP
+#line 373 "./util/configlexer.lex"
+{ BEGIN(singlequotedstr); LEXOUT(("SQS ")); }
+ YY_BREAK
+case YY_STATE_EOF(singlequotedstr):
+#line 374 "./util/configlexer.lex"
+{
+ yyerror("EOF inside quoted string");
+ if(--num_args == 0) { BEGIN(INITIAL); }
+ else { BEGIN(val); }
+}
+ YY_BREAK
+case 148:
+YY_RULE_SETUP
+#line 379 "./util/configlexer.lex"
+{ LEXOUT(("STR(%s) ", yytext)); yymore(); }
+ YY_BREAK
+case 149:
+/* rule 149 can match eol */
+YY_RULE_SETUP
+#line 380 "./util/configlexer.lex"
+{ yyerror("newline inside quoted string, no end '");
+ cfg_parser->line++; BEGIN(INITIAL); }
+ YY_BREAK
+case 150:
+YY_RULE_SETUP
+#line 382 "./util/configlexer.lex"
+{
+ LEXOUT(("SQE "));
+ if(--num_args == 0) { BEGIN(INITIAL); }
+ else { BEGIN(val); }
+ yytext[yyleng - 1] = '\0';
+ yylval.str = strdup(yytext);
+ if(!yylval.str)
+ yyerror("out of memory");
+ return STRING_ARG;
+}
+ YY_BREAK
+/* include: directive */
+case 151:
+YY_RULE_SETUP
+#line 394 "./util/configlexer.lex"
+{
+ LEXOUT(("v(%s) ", yytext)); inc_prev = YYSTATE; BEGIN(include); }
+ YY_BREAK
+case YY_STATE_EOF(include):
+#line 396 "./util/configlexer.lex"
+{
+ yyerror("EOF inside include directive");
+ BEGIN(inc_prev);
+}
+ YY_BREAK
+case 152:
+YY_RULE_SETUP
+#line 400 "./util/configlexer.lex"
+{ LEXOUT(("ISP ")); /* ignore */ }
+ YY_BREAK
+case 153:
+/* rule 153 can match eol */
+YY_RULE_SETUP
+#line 401 "./util/configlexer.lex"
+{ LEXOUT(("NL\n")); cfg_parser->line++;}
+ YY_BREAK
+case 154:
+YY_RULE_SETUP
+#line 402 "./util/configlexer.lex"
+{ LEXOUT(("IQS ")); BEGIN(include_quoted); }
+ YY_BREAK
+case 155:
+YY_RULE_SETUP
+#line 403 "./util/configlexer.lex"
+{
+ LEXOUT(("Iunquotedstr(%s) ", yytext));
+ config_start_include_glob(yytext);
+ BEGIN(inc_prev);
+}
+ YY_BREAK
+case YY_STATE_EOF(include_quoted):
+#line 408 "./util/configlexer.lex"
+{
+ yyerror("EOF inside quoted string");
+ BEGIN(inc_prev);
+}
+ YY_BREAK
+case 156:
+YY_RULE_SETUP
+#line 412 "./util/configlexer.lex"
+{ LEXOUT(("ISTR(%s) ", yytext)); yymore(); }
+ YY_BREAK
+case 157:
+/* rule 157 can match eol */
+YY_RULE_SETUP
+#line 413 "./util/configlexer.lex"
+{ yyerror("newline before \" in include name");
+ cfg_parser->line++; BEGIN(inc_prev); }
+ YY_BREAK
+case 158:
+YY_RULE_SETUP
+#line 415 "./util/configlexer.lex"
+{
+ LEXOUT(("IQE "));
+ yytext[yyleng - 1] = '\0';
+ config_start_include_glob(yytext);
+ BEGIN(inc_prev);
+}
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(val):
+#line 421 "./util/configlexer.lex"
+{
+ LEXOUT(("LEXEOF "));
+ yy_set_bol(1); /* Set beginning of line, so "^" rules match. */
+ if (!config_include_stack) {
+ yyterminate();
+ } else {
+ fclose(yyin);
+ config_end_include();
+ }
+}
+ YY_BREAK
+case 159:
+YY_RULE_SETUP
+#line 432 "./util/configlexer.lex"
+{ LEXOUT(("unquotedstr(%s) ", yytext));
+ if(--num_args == 0) { BEGIN(INITIAL); }
+ yylval.str = strdup(yytext); return STRING_ARG; }
+ YY_BREAK
+case 160:
+YY_RULE_SETUP
+#line 436 "./util/configlexer.lex"
+{
+ ub_c_error_msg("unknown keyword '%s'", yytext);
+ }
+ YY_BREAK
+case 161:
+YY_RULE_SETUP
+#line 440 "./util/configlexer.lex"
+{
+ ub_c_error_msg("stray '%s'", yytext);
+ }
+ YY_BREAK
+case 162:
+YY_RULE_SETUP
+#line 444 "./util/configlexer.lex"
+ECHO;
+ YY_BREAK
+#line 3064 "<stdout>"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ yy_size_t num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 1611 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 1611 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 1610);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+yy_size_t yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yyset_lineno (int line_number )
+{
+
+ yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str )
+{
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str )
+{
+ yyout = out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug )
+{
+ yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 444 "./util/configlexer.lex"
+
+
+
diff --git a/external/unbound/util/configlexer.lex b/external/unbound/util/configlexer.lex
new file mode 100644
index 000000000..7ee7b9bd9
--- /dev/null
+++ b/external/unbound/util/configlexer.lex
@@ -0,0 +1,444 @@
+%{
+/*
+ * configlexer.lex - lexical analyzer for unbound config file
+ *
+ * Copyright (c) 2001-2006, NLnet Labs. All rights reserved
+ *
+ * See LICENSE for the license.
+ *
+ */
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#ifdef HAVE_GLOB_H
+# include <glob.h>
+#endif
+
+#include "util/config_file.h"
+#include "util/configparser.h"
+void ub_c_error(const char *message);
+
+#if 0
+#define LEXOUT(s) printf s /* used ONLY when debugging */
+#else
+#define LEXOUT(s)
+#endif
+
+/** avoid warning in about fwrite return value */
+#define ECHO ub_c_error_msg("syntax error at text: %s", yytext)
+
+/** A parser variable, this is a statement in the config file which is
+ * of the form variable: value1 value2 ... nargs is the number of values. */
+#define YDVAR(nargs, var) \
+ num_args=(nargs); \
+ LEXOUT(("v(%s%d) ", yytext, num_args)); \
+ if(num_args > 0) { BEGIN(val); } \
+ return (var);
+
+struct inc_state {
+ char* filename;
+ int line;
+ YY_BUFFER_STATE buffer;
+ struct inc_state* next;
+};
+static struct inc_state* config_include_stack = NULL;
+static int inc_depth = 0;
+static int inc_prev = 0;
+static int num_args = 0;
+
+void init_cfg_parse(void)
+{
+ config_include_stack = NULL;
+ inc_depth = 0;
+ inc_prev = 0;
+ num_args = 0;
+}
+
+static void config_start_include(const char* filename)
+{
+ FILE *input;
+ struct inc_state* s;
+ char* nm;
+ if(inc_depth++ > 100000) {
+ ub_c_error_msg("too many include files");
+ return;
+ }
+ if(strlen(filename) == 0) {
+ ub_c_error_msg("empty include file name");
+ return;
+ }
+ s = (struct inc_state*)malloc(sizeof(*s));
+ if(!s) {
+ ub_c_error_msg("include %s: malloc failure", filename);
+ return;
+ }
+ if(cfg_parser->chroot && strncmp(filename, cfg_parser->chroot,
+ strlen(cfg_parser->chroot)) == 0) {
+ filename += strlen(cfg_parser->chroot);
+ }
+ nm = strdup(filename);
+ if(!nm) {
+ ub_c_error_msg("include %s: strdup failure", filename);
+ free(s);
+ return;
+ }
+ input = fopen(filename, "r");
+ if(!input) {
+ ub_c_error_msg("cannot open include file '%s': %s",
+ filename, strerror(errno));
+ free(s);
+ free(nm);
+ return;
+ }
+ LEXOUT(("switch_to_include_file(%s)\n", filename));
+ s->filename = cfg_parser->filename;
+ s->line = cfg_parser->line;
+ s->buffer = YY_CURRENT_BUFFER;
+ s->next = config_include_stack;
+ config_include_stack = s;
+ cfg_parser->filename = nm;
+ cfg_parser->line = 1;
+ yy_switch_to_buffer(yy_create_buffer(input, YY_BUF_SIZE));
+}
+
+static void config_start_include_glob(const char* filename)
+{
+
+ /* check for wildcards */
+#ifdef HAVE_GLOB
+ glob_t g;
+ size_t i;
+ int r, flags;
+ if(!(!strchr(filename, '*') && !strchr(filename, '?') && !strchr(filename, '[') &&
+ !strchr(filename, '{') && !strchr(filename, '~'))) {
+ flags = 0
+#ifdef GLOB_ERR
+ | GLOB_ERR
+#endif
+#ifdef GLOB_NOSORT
+ | GLOB_NOSORT
+#endif
+#ifdef GLOB_BRACE
+ | GLOB_BRACE
+#endif
+#ifdef GLOB_TILDE
+ | GLOB_TILDE
+#endif
+ ;
+ memset(&g, 0, sizeof(g));
+ r = glob(filename, flags, NULL, &g);
+ if(r) {
+ /* some error */
+ globfree(&g);
+ if(r == GLOB_NOMATCH)
+ return; /* no matches for pattern */
+ config_start_include(filename); /* let original deal with it */
+ return;
+ }
+ /* process files found, if any */
+ for(i=0; i<(size_t)g.gl_pathc; i++) {
+ config_start_include(g.gl_pathv[i]);
+ }
+ globfree(&g);
+ return;
+ }
+#endif /* HAVE_GLOB */
+
+ config_start_include(filename);
+}
+
+static void config_end_include(void)
+{
+ struct inc_state* s = config_include_stack;
+ --inc_depth;
+ if(!s) return;
+ free(cfg_parser->filename);
+ cfg_parser->filename = s->filename;
+ cfg_parser->line = s->line;
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(s->buffer);
+ config_include_stack = s->next;
+ free(s);
+}
+
+#ifndef yy_set_bol /* compat definition, for flex 2.4.6 */
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_ch_buf[0] = ((at_bol)?'\n':' '); \
+ }
+#endif
+
+%}
+%option noinput
+%option nounput
+%{
+#ifndef YY_NO_UNPUT
+#define YY_NO_UNPUT 1
+#endif
+#ifndef YY_NO_INPUT
+#define YY_NO_INPUT 1
+#endif
+%}
+
+SPACE [ \t]
+LETTER [a-zA-Z]
+UNQUOTEDLETTER [^\'\"\n\r \t\\]|\\.
+UNQUOTEDLETTER_NOCOLON [^\:\'\"\n\r \t\\]|\\.
+NEWLINE [\r\n]
+COMMENT \#
+COLON \:
+DQANY [^\"\n\r\\]|\\.
+SQANY [^\'\n\r\\]|\\.
+
+%x quotedstring singlequotedstr include include_quoted val
+
+%%
+<INITIAL,val>{SPACE}* {
+ LEXOUT(("SP ")); /* ignore */ }
+<INITIAL,val>{SPACE}*{COMMENT}.* {
+ /* note that flex makes the longest match and '.' is any but not nl */
+ LEXOUT(("comment(%s) ", yytext)); /* ignore */ }
+server{COLON} { YDVAR(0, VAR_SERVER) }
+num-threads{COLON} { YDVAR(1, VAR_NUM_THREADS) }
+verbosity{COLON} { YDVAR(1, VAR_VERBOSITY) }
+port{COLON} { YDVAR(1, VAR_PORT) }
+outgoing-range{COLON} { YDVAR(1, VAR_OUTGOING_RANGE) }
+outgoing-port-permit{COLON} { YDVAR(1, VAR_OUTGOING_PORT_PERMIT) }
+outgoing-port-avoid{COLON} { YDVAR(1, VAR_OUTGOING_PORT_AVOID) }
+outgoing-num-tcp{COLON} { YDVAR(1, VAR_OUTGOING_NUM_TCP) }
+incoming-num-tcp{COLON} { YDVAR(1, VAR_INCOMING_NUM_TCP) }
+do-ip4{COLON} { YDVAR(1, VAR_DO_IP4) }
+do-ip6{COLON} { YDVAR(1, VAR_DO_IP6) }
+do-udp{COLON} { YDVAR(1, VAR_DO_UDP) }
+do-tcp{COLON} { YDVAR(1, VAR_DO_TCP) }
+tcp-upstream{COLON} { YDVAR(1, VAR_TCP_UPSTREAM) }
+ssl-upstream{COLON} { YDVAR(1, VAR_SSL_UPSTREAM) }
+ssl-service-key{COLON} { YDVAR(1, VAR_SSL_SERVICE_KEY) }
+ssl-service-pem{COLON} { YDVAR(1, VAR_SSL_SERVICE_PEM) }
+ssl-port{COLON} { YDVAR(1, VAR_SSL_PORT) }
+do-daemonize{COLON} { YDVAR(1, VAR_DO_DAEMONIZE) }
+interface{COLON} { YDVAR(1, VAR_INTERFACE) }
+ip-address{COLON} { YDVAR(1, VAR_INTERFACE) }
+outgoing-interface{COLON} { YDVAR(1, VAR_OUTGOING_INTERFACE) }
+interface-automatic{COLON} { YDVAR(1, VAR_INTERFACE_AUTOMATIC) }
+so-rcvbuf{COLON} { YDVAR(1, VAR_SO_RCVBUF) }
+so-sndbuf{COLON} { YDVAR(1, VAR_SO_SNDBUF) }
+so-reuseport{COLON} { YDVAR(1, VAR_SO_REUSEPORT) }
+chroot{COLON} { YDVAR(1, VAR_CHROOT) }
+username{COLON} { YDVAR(1, VAR_USERNAME) }
+directory{COLON} { YDVAR(1, VAR_DIRECTORY) }
+logfile{COLON} { YDVAR(1, VAR_LOGFILE) }
+pidfile{COLON} { YDVAR(1, VAR_PIDFILE) }
+root-hints{COLON} { YDVAR(1, VAR_ROOT_HINTS) }
+edns-buffer-size{COLON} { YDVAR(1, VAR_EDNS_BUFFER_SIZE) }
+msg-buffer-size{COLON} { YDVAR(1, VAR_MSG_BUFFER_SIZE) }
+msg-cache-size{COLON} { YDVAR(1, VAR_MSG_CACHE_SIZE) }
+msg-cache-slabs{COLON} { YDVAR(1, VAR_MSG_CACHE_SLABS) }
+rrset-cache-size{COLON} { YDVAR(1, VAR_RRSET_CACHE_SIZE) }
+rrset-cache-slabs{COLON} { YDVAR(1, VAR_RRSET_CACHE_SLABS) }
+cache-max-ttl{COLON} { YDVAR(1, VAR_CACHE_MAX_TTL) }
+cache-min-ttl{COLON} { YDVAR(1, VAR_CACHE_MIN_TTL) }
+infra-host-ttl{COLON} { YDVAR(1, VAR_INFRA_HOST_TTL) }
+infra-lame-ttl{COLON} { YDVAR(1, VAR_INFRA_LAME_TTL) }
+infra-cache-slabs{COLON} { YDVAR(1, VAR_INFRA_CACHE_SLABS) }
+infra-cache-numhosts{COLON} { YDVAR(1, VAR_INFRA_CACHE_NUMHOSTS) }
+infra-cache-lame-size{COLON} { YDVAR(1, VAR_INFRA_CACHE_LAME_SIZE) }
+num-queries-per-thread{COLON} { YDVAR(1, VAR_NUM_QUERIES_PER_THREAD) }
+jostle-timeout{COLON} { YDVAR(1, VAR_JOSTLE_TIMEOUT) }
+delay-close{COLON} { YDVAR(1, VAR_DELAY_CLOSE) }
+target-fetch-policy{COLON} { YDVAR(1, VAR_TARGET_FETCH_POLICY) }
+harden-short-bufsize{COLON} { YDVAR(1, VAR_HARDEN_SHORT_BUFSIZE) }
+harden-large-queries{COLON} { YDVAR(1, VAR_HARDEN_LARGE_QUERIES) }
+harden-glue{COLON} { YDVAR(1, VAR_HARDEN_GLUE) }
+harden-dnssec-stripped{COLON} { YDVAR(1, VAR_HARDEN_DNSSEC_STRIPPED) }
+harden-below-nxdomain{COLON} { YDVAR(1, VAR_HARDEN_BELOW_NXDOMAIN) }
+harden-referral-path{COLON} { YDVAR(1, VAR_HARDEN_REFERRAL_PATH) }
+use-caps-for-id{COLON} { YDVAR(1, VAR_USE_CAPS_FOR_ID) }
+unwanted-reply-threshold{COLON} { YDVAR(1, VAR_UNWANTED_REPLY_THRESHOLD) }
+private-address{COLON} { YDVAR(1, VAR_PRIVATE_ADDRESS) }
+private-domain{COLON} { YDVAR(1, VAR_PRIVATE_DOMAIN) }
+prefetch-key{COLON} { YDVAR(1, VAR_PREFETCH_KEY) }
+prefetch{COLON} { YDVAR(1, VAR_PREFETCH) }
+stub-zone{COLON} { YDVAR(0, VAR_STUB_ZONE) }
+name{COLON} { YDVAR(1, VAR_NAME) }
+stub-addr{COLON} { YDVAR(1, VAR_STUB_ADDR) }
+stub-host{COLON} { YDVAR(1, VAR_STUB_HOST) }
+stub-prime{COLON} { YDVAR(1, VAR_STUB_PRIME) }
+stub-first{COLON} { YDVAR(1, VAR_STUB_FIRST) }
+forward-zone{COLON} { YDVAR(0, VAR_FORWARD_ZONE) }
+forward-addr{COLON} { YDVAR(1, VAR_FORWARD_ADDR) }
+forward-host{COLON} { YDVAR(1, VAR_FORWARD_HOST) }
+forward-first{COLON} { YDVAR(1, VAR_FORWARD_FIRST) }
+do-not-query-address{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_ADDRESS) }
+do-not-query-localhost{COLON} { YDVAR(1, VAR_DO_NOT_QUERY_LOCALHOST) }
+access-control{COLON} { YDVAR(2, VAR_ACCESS_CONTROL) }
+hide-identity{COLON} { YDVAR(1, VAR_HIDE_IDENTITY) }
+hide-version{COLON} { YDVAR(1, VAR_HIDE_VERSION) }
+identity{COLON} { YDVAR(1, VAR_IDENTITY) }
+version{COLON} { YDVAR(1, VAR_VERSION) }
+module-config{COLON} { YDVAR(1, VAR_MODULE_CONF) }
+dlv-anchor{COLON} { YDVAR(1, VAR_DLV_ANCHOR) }
+dlv-anchor-file{COLON} { YDVAR(1, VAR_DLV_ANCHOR_FILE) }
+trust-anchor-file{COLON} { YDVAR(1, VAR_TRUST_ANCHOR_FILE) }
+auto-trust-anchor-file{COLON} { YDVAR(1, VAR_AUTO_TRUST_ANCHOR_FILE) }
+trusted-keys-file{COLON} { YDVAR(1, VAR_TRUSTED_KEYS_FILE) }
+trust-anchor{COLON} { YDVAR(1, VAR_TRUST_ANCHOR) }
+val-override-date{COLON} { YDVAR(1, VAR_VAL_OVERRIDE_DATE) }
+val-sig-skew-min{COLON} { YDVAR(1, VAR_VAL_SIG_SKEW_MIN) }
+val-sig-skew-max{COLON} { YDVAR(1, VAR_VAL_SIG_SKEW_MAX) }
+val-bogus-ttl{COLON} { YDVAR(1, VAR_BOGUS_TTL) }
+val-clean-additional{COLON} { YDVAR(1, VAR_VAL_CLEAN_ADDITIONAL) }
+val-permissive-mode{COLON} { YDVAR(1, VAR_VAL_PERMISSIVE_MODE) }
+ignore-cd-flag{COLON} { YDVAR(1, VAR_IGNORE_CD_FLAG) }
+val-log-level{COLON} { YDVAR(1, VAR_VAL_LOG_LEVEL) }
+key-cache-size{COLON} { YDVAR(1, VAR_KEY_CACHE_SIZE) }
+key-cache-slabs{COLON} { YDVAR(1, VAR_KEY_CACHE_SLABS) }
+neg-cache-size{COLON} { YDVAR(1, VAR_NEG_CACHE_SIZE) }
+val-nsec3-keysize-iterations{COLON} {
+ YDVAR(1, VAR_VAL_NSEC3_KEYSIZE_ITERATIONS) }
+add-holddown{COLON} { YDVAR(1, VAR_ADD_HOLDDOWN) }
+del-holddown{COLON} { YDVAR(1, VAR_DEL_HOLDDOWN) }
+keep-missing{COLON} { YDVAR(1, VAR_KEEP_MISSING) }
+use-syslog{COLON} { YDVAR(1, VAR_USE_SYSLOG) }
+log-time-ascii{COLON} { YDVAR(1, VAR_LOG_TIME_ASCII) }
+log-queries{COLON} { YDVAR(1, VAR_LOG_QUERIES) }
+local-zone{COLON} { YDVAR(2, VAR_LOCAL_ZONE) }
+local-data{COLON} { YDVAR(1, VAR_LOCAL_DATA) }
+local-data-ptr{COLON} { YDVAR(1, VAR_LOCAL_DATA_PTR) }
+unblock-lan-zones{COLON} { YDVAR(1, VAR_UNBLOCK_LAN_ZONES) }
+statistics-interval{COLON} { YDVAR(1, VAR_STATISTICS_INTERVAL) }
+statistics-cumulative{COLON} { YDVAR(1, VAR_STATISTICS_CUMULATIVE) }
+extended-statistics{COLON} { YDVAR(1, VAR_EXTENDED_STATISTICS) }
+remote-control{COLON} { YDVAR(0, VAR_REMOTE_CONTROL) }
+control-enable{COLON} { YDVAR(1, VAR_CONTROL_ENABLE) }
+control-interface{COLON} { YDVAR(1, VAR_CONTROL_INTERFACE) }
+control-port{COLON} { YDVAR(1, VAR_CONTROL_PORT) }
+server-key-file{COLON} { YDVAR(1, VAR_SERVER_KEY_FILE) }
+server-cert-file{COLON} { YDVAR(1, VAR_SERVER_CERT_FILE) }
+control-key-file{COLON} { YDVAR(1, VAR_CONTROL_KEY_FILE) }
+control-cert-file{COLON} { YDVAR(1, VAR_CONTROL_CERT_FILE) }
+python-script{COLON} { YDVAR(1, VAR_PYTHON_SCRIPT) }
+python{COLON} { YDVAR(0, VAR_PYTHON) }
+domain-insecure{COLON} { YDVAR(1, VAR_DOMAIN_INSECURE) }
+minimal-responses{COLON} { YDVAR(1, VAR_MINIMAL_RESPONSES) }
+rrset-roundrobin{COLON} { YDVAR(1, VAR_RRSET_ROUNDROBIN) }
+max-udp-size{COLON} { YDVAR(1, VAR_MAX_UDP_SIZE) }
+dns64-prefix{COLON} { YDVAR(1, VAR_DNS64_PREFIX) }
+dns64-synthall{COLON} { YDVAR(1, VAR_DNS64_SYNTHALL) }
+dnstap{COLON} { YDVAR(0, VAR_DNSTAP) }
+dnstap-enable{COLON} { YDVAR(1, VAR_DNSTAP_ENABLE) }
+dnstap-socket-path{COLON} { YDVAR(1, VAR_DNSTAP_SOCKET_PATH) }
+dnstap-send-identity{COLON} { YDVAR(1, VAR_DNSTAP_SEND_IDENTITY) }
+dnstap-send-version{COLON} { YDVAR(1, VAR_DNSTAP_SEND_VERSION) }
+dnstap-identity{COLON} { YDVAR(1, VAR_DNSTAP_IDENTITY) }
+dnstap-version{COLON} { YDVAR(1, VAR_DNSTAP_VERSION) }
+dnstap-log-resolver-query-messages{COLON} {
+ YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES) }
+dnstap-log-resolver-response-messages{COLON} {
+ YDVAR(1, VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES) }
+dnstap-log-client-query-messages{COLON} {
+ YDVAR(1, VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES) }
+dnstap-log-client-response-messages{COLON} {
+ YDVAR(1, VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES) }
+dnstap-log-forwarder-query-messages{COLON} {
+ YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES) }
+dnstap-log-forwarder-response-messages{COLON} {
+ YDVAR(1, VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES) }
+<INITIAL,val>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++; }
+
+ /* Quoted strings. Strip leading and ending quotes */
+<val>\" { BEGIN(quotedstring); LEXOUT(("QS ")); }
+<quotedstring><<EOF>> {
+ yyerror("EOF inside quoted string");
+ if(--num_args == 0) { BEGIN(INITIAL); }
+ else { BEGIN(val); }
+}
+<quotedstring>{DQANY}* { LEXOUT(("STR(%s) ", yytext)); yymore(); }
+<quotedstring>{NEWLINE} { yyerror("newline inside quoted string, no end \"");
+ cfg_parser->line++; BEGIN(INITIAL); }
+<quotedstring>\" {
+ LEXOUT(("QE "));
+ if(--num_args == 0) { BEGIN(INITIAL); }
+ else { BEGIN(val); }
+ yytext[yyleng - 1] = '\0';
+ yylval.str = strdup(yytext);
+ if(!yylval.str)
+ yyerror("out of memory");
+ return STRING_ARG;
+}
+
+ /* Single Quoted strings. Strip leading and ending quotes */
+<val>\' { BEGIN(singlequotedstr); LEXOUT(("SQS ")); }
+<singlequotedstr><<EOF>> {
+ yyerror("EOF inside quoted string");
+ if(--num_args == 0) { BEGIN(INITIAL); }
+ else { BEGIN(val); }
+}
+<singlequotedstr>{SQANY}* { LEXOUT(("STR(%s) ", yytext)); yymore(); }
+<singlequotedstr>{NEWLINE} { yyerror("newline inside quoted string, no end '");
+ cfg_parser->line++; BEGIN(INITIAL); }
+<singlequotedstr>\' {
+ LEXOUT(("SQE "));
+ if(--num_args == 0) { BEGIN(INITIAL); }
+ else { BEGIN(val); }
+ yytext[yyleng - 1] = '\0';
+ yylval.str = strdup(yytext);
+ if(!yylval.str)
+ yyerror("out of memory");
+ return STRING_ARG;
+}
+
+ /* include: directive */
+<INITIAL,val>include{COLON} {
+ LEXOUT(("v(%s) ", yytext)); inc_prev = YYSTATE; BEGIN(include); }
+<include><<EOF>> {
+ yyerror("EOF inside include directive");
+ BEGIN(inc_prev);
+}
+<include>{SPACE}* { LEXOUT(("ISP ")); /* ignore */ }
+<include>{NEWLINE} { LEXOUT(("NL\n")); cfg_parser->line++;}
+<include>\" { LEXOUT(("IQS ")); BEGIN(include_quoted); }
+<include>{UNQUOTEDLETTER}* {
+ LEXOUT(("Iunquotedstr(%s) ", yytext));
+ config_start_include_glob(yytext);
+ BEGIN(inc_prev);
+}
+<include_quoted><<EOF>> {
+ yyerror("EOF inside quoted string");
+ BEGIN(inc_prev);
+}
+<include_quoted>{DQANY}* { LEXOUT(("ISTR(%s) ", yytext)); yymore(); }
+<include_quoted>{NEWLINE} { yyerror("newline before \" in include name");
+ cfg_parser->line++; BEGIN(inc_prev); }
+<include_quoted>\" {
+ LEXOUT(("IQE "));
+ yytext[yyleng - 1] = '\0';
+ config_start_include_glob(yytext);
+ BEGIN(inc_prev);
+}
+<INITIAL,val><<EOF>> {
+ LEXOUT(("LEXEOF "));
+ yy_set_bol(1); /* Set beginning of line, so "^" rules match. */
+ if (!config_include_stack) {
+ yyterminate();
+ } else {
+ fclose(yyin);
+ config_end_include();
+ }
+}
+
+<val>{UNQUOTEDLETTER}* { LEXOUT(("unquotedstr(%s) ", yytext));
+ if(--num_args == 0) { BEGIN(INITIAL); }
+ yylval.str = strdup(yytext); return STRING_ARG; }
+
+{UNQUOTEDLETTER_NOCOLON}* {
+ ub_c_error_msg("unknown keyword '%s'", yytext);
+ }
+
+<*>. {
+ ub_c_error_msg("stray '%s'", yytext);
+ }
+
+%%
diff --git a/external/unbound/util/configparser.c b/external/unbound/util/configparser.c
new file mode 100644
index 000000000..089d675d9
--- /dev/null
+++ b/external/unbound/util/configparser.c
@@ -0,0 +1,4109 @@
+/* A Bison parser, made by GNU Bison 2.6.1. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "2.6.1"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations. */
+/* Line 336 of yacc.c */
+#line 38 "./util/configparser.y"
+
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "util/configyyrename.h"
+#include "util/config_file.h"
+#include "util/net_help.h"
+
+int ub_c_lex(void);
+void ub_c_error(const char *message);
+
+/* these need to be global, otherwise they cannot be used inside yacc */
+extern struct config_parser_state* cfg_parser;
+
+#if 0
+#define OUTYY(s) printf s /* used ONLY when debugging */
+#else
+#define OUTYY(s)
+#endif
+
+
+/* Line 336 of yacc.c */
+#line 95 "util/configparser.c"
+
+# ifndef YY_NULL
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULL nullptr
+# else
+# define YY_NULL 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "configparser.h". */
+#ifndef YY_UTIL_CONFIGPARSER_H
+# define YY_UTIL_CONFIGPARSER_H
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ SPACE = 258,
+ LETTER = 259,
+ NEWLINE = 260,
+ COMMENT = 261,
+ COLON = 262,
+ ANY = 263,
+ ZONESTR = 264,
+ STRING_ARG = 265,
+ VAR_SERVER = 266,
+ VAR_VERBOSITY = 267,
+ VAR_NUM_THREADS = 268,
+ VAR_PORT = 269,
+ VAR_OUTGOING_RANGE = 270,
+ VAR_INTERFACE = 271,
+ VAR_DO_IP4 = 272,
+ VAR_DO_IP6 = 273,
+ VAR_DO_UDP = 274,
+ VAR_DO_TCP = 275,
+ VAR_CHROOT = 276,
+ VAR_USERNAME = 277,
+ VAR_DIRECTORY = 278,
+ VAR_LOGFILE = 279,
+ VAR_PIDFILE = 280,
+ VAR_MSG_CACHE_SIZE = 281,
+ VAR_MSG_CACHE_SLABS = 282,
+ VAR_NUM_QUERIES_PER_THREAD = 283,
+ VAR_RRSET_CACHE_SIZE = 284,
+ VAR_RRSET_CACHE_SLABS = 285,
+ VAR_OUTGOING_NUM_TCP = 286,
+ VAR_INFRA_HOST_TTL = 287,
+ VAR_INFRA_LAME_TTL = 288,
+ VAR_INFRA_CACHE_SLABS = 289,
+ VAR_INFRA_CACHE_NUMHOSTS = 290,
+ VAR_INFRA_CACHE_LAME_SIZE = 291,
+ VAR_NAME = 292,
+ VAR_STUB_ZONE = 293,
+ VAR_STUB_HOST = 294,
+ VAR_STUB_ADDR = 295,
+ VAR_TARGET_FETCH_POLICY = 296,
+ VAR_HARDEN_SHORT_BUFSIZE = 297,
+ VAR_HARDEN_LARGE_QUERIES = 298,
+ VAR_FORWARD_ZONE = 299,
+ VAR_FORWARD_HOST = 300,
+ VAR_FORWARD_ADDR = 301,
+ VAR_DO_NOT_QUERY_ADDRESS = 302,
+ VAR_HIDE_IDENTITY = 303,
+ VAR_HIDE_VERSION = 304,
+ VAR_IDENTITY = 305,
+ VAR_VERSION = 306,
+ VAR_HARDEN_GLUE = 307,
+ VAR_MODULE_CONF = 308,
+ VAR_TRUST_ANCHOR_FILE = 309,
+ VAR_TRUST_ANCHOR = 310,
+ VAR_VAL_OVERRIDE_DATE = 311,
+ VAR_BOGUS_TTL = 312,
+ VAR_VAL_CLEAN_ADDITIONAL = 313,
+ VAR_VAL_PERMISSIVE_MODE = 314,
+ VAR_INCOMING_NUM_TCP = 315,
+ VAR_MSG_BUFFER_SIZE = 316,
+ VAR_KEY_CACHE_SIZE = 317,
+ VAR_KEY_CACHE_SLABS = 318,
+ VAR_TRUSTED_KEYS_FILE = 319,
+ VAR_VAL_NSEC3_KEYSIZE_ITERATIONS = 320,
+ VAR_USE_SYSLOG = 321,
+ VAR_OUTGOING_INTERFACE = 322,
+ VAR_ROOT_HINTS = 323,
+ VAR_DO_NOT_QUERY_LOCALHOST = 324,
+ VAR_CACHE_MAX_TTL = 325,
+ VAR_HARDEN_DNSSEC_STRIPPED = 326,
+ VAR_ACCESS_CONTROL = 327,
+ VAR_LOCAL_ZONE = 328,
+ VAR_LOCAL_DATA = 329,
+ VAR_INTERFACE_AUTOMATIC = 330,
+ VAR_STATISTICS_INTERVAL = 331,
+ VAR_DO_DAEMONIZE = 332,
+ VAR_USE_CAPS_FOR_ID = 333,
+ VAR_STATISTICS_CUMULATIVE = 334,
+ VAR_OUTGOING_PORT_PERMIT = 335,
+ VAR_OUTGOING_PORT_AVOID = 336,
+ VAR_DLV_ANCHOR_FILE = 337,
+ VAR_DLV_ANCHOR = 338,
+ VAR_NEG_CACHE_SIZE = 339,
+ VAR_HARDEN_REFERRAL_PATH = 340,
+ VAR_PRIVATE_ADDRESS = 341,
+ VAR_PRIVATE_DOMAIN = 342,
+ VAR_REMOTE_CONTROL = 343,
+ VAR_CONTROL_ENABLE = 344,
+ VAR_CONTROL_INTERFACE = 345,
+ VAR_CONTROL_PORT = 346,
+ VAR_SERVER_KEY_FILE = 347,
+ VAR_SERVER_CERT_FILE = 348,
+ VAR_CONTROL_KEY_FILE = 349,
+ VAR_CONTROL_CERT_FILE = 350,
+ VAR_EXTENDED_STATISTICS = 351,
+ VAR_LOCAL_DATA_PTR = 352,
+ VAR_JOSTLE_TIMEOUT = 353,
+ VAR_STUB_PRIME = 354,
+ VAR_UNWANTED_REPLY_THRESHOLD = 355,
+ VAR_LOG_TIME_ASCII = 356,
+ VAR_DOMAIN_INSECURE = 357,
+ VAR_PYTHON = 358,
+ VAR_PYTHON_SCRIPT = 359,
+ VAR_VAL_SIG_SKEW_MIN = 360,
+ VAR_VAL_SIG_SKEW_MAX = 361,
+ VAR_CACHE_MIN_TTL = 362,
+ VAR_VAL_LOG_LEVEL = 363,
+ VAR_AUTO_TRUST_ANCHOR_FILE = 364,
+ VAR_KEEP_MISSING = 365,
+ VAR_ADD_HOLDDOWN = 366,
+ VAR_DEL_HOLDDOWN = 367,
+ VAR_SO_RCVBUF = 368,
+ VAR_EDNS_BUFFER_SIZE = 369,
+ VAR_PREFETCH = 370,
+ VAR_PREFETCH_KEY = 371,
+ VAR_SO_SNDBUF = 372,
+ VAR_SO_REUSEPORT = 373,
+ VAR_HARDEN_BELOW_NXDOMAIN = 374,
+ VAR_IGNORE_CD_FLAG = 375,
+ VAR_LOG_QUERIES = 376,
+ VAR_TCP_UPSTREAM = 377,
+ VAR_SSL_UPSTREAM = 378,
+ VAR_SSL_SERVICE_KEY = 379,
+ VAR_SSL_SERVICE_PEM = 380,
+ VAR_SSL_PORT = 381,
+ VAR_FORWARD_FIRST = 382,
+ VAR_STUB_FIRST = 383,
+ VAR_MINIMAL_RESPONSES = 384,
+ VAR_RRSET_ROUNDROBIN = 385,
+ VAR_MAX_UDP_SIZE = 386,
+ VAR_DELAY_CLOSE = 387,
+ VAR_UNBLOCK_LAN_ZONES = 388,
+ VAR_DNS64_PREFIX = 389,
+ VAR_DNS64_SYNTHALL = 390,
+ VAR_DNSTAP = 391,
+ VAR_DNSTAP_ENABLE = 392,
+ VAR_DNSTAP_SOCKET_PATH = 393,
+ VAR_DNSTAP_SEND_IDENTITY = 394,
+ VAR_DNSTAP_SEND_VERSION = 395,
+ VAR_DNSTAP_IDENTITY = 396,
+ VAR_DNSTAP_VERSION = 397,
+ VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES = 398,
+ VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES = 399,
+ VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES = 400,
+ VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES = 401,
+ VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES = 402,
+ VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES = 403
+ };
+#endif
+/* Tokens. */
+#define SPACE 258
+#define LETTER 259
+#define NEWLINE 260
+#define COMMENT 261
+#define COLON 262
+#define ANY 263
+#define ZONESTR 264
+#define STRING_ARG 265
+#define VAR_SERVER 266
+#define VAR_VERBOSITY 267
+#define VAR_NUM_THREADS 268
+#define VAR_PORT 269
+#define VAR_OUTGOING_RANGE 270
+#define VAR_INTERFACE 271
+#define VAR_DO_IP4 272
+#define VAR_DO_IP6 273
+#define VAR_DO_UDP 274
+#define VAR_DO_TCP 275
+#define VAR_CHROOT 276
+#define VAR_USERNAME 277
+#define VAR_DIRECTORY 278
+#define VAR_LOGFILE 279
+#define VAR_PIDFILE 280
+#define VAR_MSG_CACHE_SIZE 281
+#define VAR_MSG_CACHE_SLABS 282
+#define VAR_NUM_QUERIES_PER_THREAD 283
+#define VAR_RRSET_CACHE_SIZE 284
+#define VAR_RRSET_CACHE_SLABS 285
+#define VAR_OUTGOING_NUM_TCP 286
+#define VAR_INFRA_HOST_TTL 287
+#define VAR_INFRA_LAME_TTL 288
+#define VAR_INFRA_CACHE_SLABS 289
+#define VAR_INFRA_CACHE_NUMHOSTS 290
+#define VAR_INFRA_CACHE_LAME_SIZE 291
+#define VAR_NAME 292
+#define VAR_STUB_ZONE 293
+#define VAR_STUB_HOST 294
+#define VAR_STUB_ADDR 295
+#define VAR_TARGET_FETCH_POLICY 296
+#define VAR_HARDEN_SHORT_BUFSIZE 297
+#define VAR_HARDEN_LARGE_QUERIES 298
+#define VAR_FORWARD_ZONE 299
+#define VAR_FORWARD_HOST 300
+#define VAR_FORWARD_ADDR 301
+#define VAR_DO_NOT_QUERY_ADDRESS 302
+#define VAR_HIDE_IDENTITY 303
+#define VAR_HIDE_VERSION 304
+#define VAR_IDENTITY 305
+#define VAR_VERSION 306
+#define VAR_HARDEN_GLUE 307
+#define VAR_MODULE_CONF 308
+#define VAR_TRUST_ANCHOR_FILE 309
+#define VAR_TRUST_ANCHOR 310
+#define VAR_VAL_OVERRIDE_DATE 311
+#define VAR_BOGUS_TTL 312
+#define VAR_VAL_CLEAN_ADDITIONAL 313
+#define VAR_VAL_PERMISSIVE_MODE 314
+#define VAR_INCOMING_NUM_TCP 315
+#define VAR_MSG_BUFFER_SIZE 316
+#define VAR_KEY_CACHE_SIZE 317
+#define VAR_KEY_CACHE_SLABS 318
+#define VAR_TRUSTED_KEYS_FILE 319
+#define VAR_VAL_NSEC3_KEYSIZE_ITERATIONS 320
+#define VAR_USE_SYSLOG 321
+#define VAR_OUTGOING_INTERFACE 322
+#define VAR_ROOT_HINTS 323
+#define VAR_DO_NOT_QUERY_LOCALHOST 324
+#define VAR_CACHE_MAX_TTL 325
+#define VAR_HARDEN_DNSSEC_STRIPPED 326
+#define VAR_ACCESS_CONTROL 327
+#define VAR_LOCAL_ZONE 328
+#define VAR_LOCAL_DATA 329
+#define VAR_INTERFACE_AUTOMATIC 330
+#define VAR_STATISTICS_INTERVAL 331
+#define VAR_DO_DAEMONIZE 332
+#define VAR_USE_CAPS_FOR_ID 333
+#define VAR_STATISTICS_CUMULATIVE 334
+#define VAR_OUTGOING_PORT_PERMIT 335
+#define VAR_OUTGOING_PORT_AVOID 336
+#define VAR_DLV_ANCHOR_FILE 337
+#define VAR_DLV_ANCHOR 338
+#define VAR_NEG_CACHE_SIZE 339
+#define VAR_HARDEN_REFERRAL_PATH 340
+#define VAR_PRIVATE_ADDRESS 341
+#define VAR_PRIVATE_DOMAIN 342
+#define VAR_REMOTE_CONTROL 343
+#define VAR_CONTROL_ENABLE 344
+#define VAR_CONTROL_INTERFACE 345
+#define VAR_CONTROL_PORT 346
+#define VAR_SERVER_KEY_FILE 347
+#define VAR_SERVER_CERT_FILE 348
+#define VAR_CONTROL_KEY_FILE 349
+#define VAR_CONTROL_CERT_FILE 350
+#define VAR_EXTENDED_STATISTICS 351
+#define VAR_LOCAL_DATA_PTR 352
+#define VAR_JOSTLE_TIMEOUT 353
+#define VAR_STUB_PRIME 354
+#define VAR_UNWANTED_REPLY_THRESHOLD 355
+#define VAR_LOG_TIME_ASCII 356
+#define VAR_DOMAIN_INSECURE 357
+#define VAR_PYTHON 358
+#define VAR_PYTHON_SCRIPT 359
+#define VAR_VAL_SIG_SKEW_MIN 360
+#define VAR_VAL_SIG_SKEW_MAX 361
+#define VAR_CACHE_MIN_TTL 362
+#define VAR_VAL_LOG_LEVEL 363
+#define VAR_AUTO_TRUST_ANCHOR_FILE 364
+#define VAR_KEEP_MISSING 365
+#define VAR_ADD_HOLDDOWN 366
+#define VAR_DEL_HOLDDOWN 367
+#define VAR_SO_RCVBUF 368
+#define VAR_EDNS_BUFFER_SIZE 369
+#define VAR_PREFETCH 370
+#define VAR_PREFETCH_KEY 371
+#define VAR_SO_SNDBUF 372
+#define VAR_SO_REUSEPORT 373
+#define VAR_HARDEN_BELOW_NXDOMAIN 374
+#define VAR_IGNORE_CD_FLAG 375
+#define VAR_LOG_QUERIES 376
+#define VAR_TCP_UPSTREAM 377
+#define VAR_SSL_UPSTREAM 378
+#define VAR_SSL_SERVICE_KEY 379
+#define VAR_SSL_SERVICE_PEM 380
+#define VAR_SSL_PORT 381
+#define VAR_FORWARD_FIRST 382
+#define VAR_STUB_FIRST 383
+#define VAR_MINIMAL_RESPONSES 384
+#define VAR_RRSET_ROUNDROBIN 385
+#define VAR_MAX_UDP_SIZE 386
+#define VAR_DELAY_CLOSE 387
+#define VAR_UNBLOCK_LAN_ZONES 388
+#define VAR_DNS64_PREFIX 389
+#define VAR_DNS64_SYNTHALL 390
+#define VAR_DNSTAP 391
+#define VAR_DNSTAP_ENABLE 392
+#define VAR_DNSTAP_SOCKET_PATH 393
+#define VAR_DNSTAP_SEND_IDENTITY 394
+#define VAR_DNSTAP_SEND_VERSION 395
+#define VAR_DNSTAP_IDENTITY 396
+#define VAR_DNSTAP_VERSION 397
+#define VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES 398
+#define VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES 399
+#define VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES 400
+#define VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES 401
+#define VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES 402
+#define VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES 403
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 350 of yacc.c */
+#line 64 "./util/configparser.y"
+
+ char* str;
+
+
+/* Line 350 of yacc.c */
+#line 439 "util/configparser.c"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_UTIL_CONFIGPARSER_H */
+
+/* Copy the second part of user declarations. */
+
+/* Line 353 of yacc.c */
+#line 467 "util/configparser.c"
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#elif (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+typedef signed char yytype_int8;
+#else
+typedef short int yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(msgid) dgettext ("bison-runtime", msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(msgid) msgid
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(e) ((void) (e))
+#else
+# define YYUSE(e) /* empty */
+#endif
+
+/* Identity function, used to suppress warnings about constant conditions. */
+#ifndef lint
+# define YYID(n) (n)
+#else
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static int
+YYID (int yyi)
+#else
+static int
+YYID (yyi)
+ int yyi;
+#endif
+{
+ return yyi;
+}
+#endif
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's `empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (YYID (0))
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (YYID (0))
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 276
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 149
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 154
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 293
+/* YYNRULES -- Number of states. */
+#define YYNSTATES 429
+
+/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 403
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 30, 31, 32, 33, 34,
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
+ 65, 66, 67, 68, 69, 70, 71, 72, 73, 74,
+ 75, 76, 77, 78, 79, 80, 81, 82, 83, 84,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
+ 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
+ 115, 116, 117, 118, 119, 120, 121, 122, 123, 124,
+ 125, 126, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 146, 147, 148
+};
+
+#if YYDEBUG
+/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
+ YYRHS. */
+static const yytype_uint16 yyprhs[] =
+{
+ 0, 0, 3, 4, 7, 10, 13, 16, 19, 22,
+ 25, 27, 30, 31, 33, 35, 37, 39, 41, 43,
+ 45, 47, 49, 51, 53, 55, 57, 59, 61, 63,
+ 65, 67, 69, 71, 73, 75, 77, 79, 81, 83,
+ 85, 87, 89, 91, 93, 95, 97, 99, 101, 103,
+ 105, 107, 109, 111, 113, 115, 117, 119, 121, 123,
+ 125, 127, 129, 131, 133, 135, 137, 139, 141, 143,
+ 145, 147, 149, 151, 153, 155, 157, 159, 161, 163,
+ 165, 167, 169, 171, 173, 175, 177, 179, 181, 183,
+ 185, 187, 189, 191, 193, 195, 197, 199, 201, 203,
+ 205, 207, 209, 211, 213, 215, 217, 219, 221, 223,
+ 225, 227, 229, 231, 233, 235, 237, 239, 241, 244,
+ 245, 247, 249, 251, 253, 255, 257, 260, 261, 263,
+ 265, 267, 269, 272, 275, 278, 281, 284, 287, 290,
+ 293, 296, 299, 302, 305, 308, 311, 314, 317, 320,
+ 323, 326, 329, 332, 335, 338, 341, 344, 347, 350,
+ 353, 356, 359, 362, 365, 368, 371, 374, 377, 380,
+ 383, 386, 389, 392, 395, 398, 401, 404, 407, 410,
+ 413, 416, 419, 422, 425, 428, 431, 434, 437, 440,
+ 443, 446, 449, 452, 455, 458, 461, 464, 467, 470,
+ 473, 476, 479, 482, 485, 488, 491, 494, 497, 500,
+ 504, 507, 510, 513, 516, 519, 522, 525, 528, 531,
+ 534, 537, 540, 543, 546, 549, 552, 555, 558, 562,
+ 565, 568, 571, 574, 577, 580, 583, 586, 589, 592,
+ 595, 598, 601, 604, 607, 610, 612, 615, 616, 618,
+ 620, 622, 624, 626, 628, 630, 633, 636, 639, 642,
+ 645, 648, 651, 653, 656, 657, 659, 661, 663, 665,
+ 667, 669, 671, 673, 675, 677, 679, 681, 684, 687,
+ 690, 693, 696, 699, 702, 705, 708, 711, 714, 717,
+ 719, 722, 723, 725
+};
+
+/* YYRHS -- A `-1'-separated list of the rules' RHS. */
+static const yytype_int16 yyrhs[] =
+{
+ 150, 0, -1, -1, 150, 151, -1, 152, 153, -1,
+ 155, 156, -1, 158, 159, -1, 299, 300, -1, 274,
+ 275, -1, 284, 285, -1, 11, -1, 153, 154, -1,
+ -1, 161, -1, 162, -1, 166, -1, 169, -1, 175,
+ -1, 176, -1, 177, -1, 178, -1, 167, -1, 188,
+ -1, 189, -1, 190, -1, 191, -1, 192, -1, 210,
+ -1, 211, -1, 212, -1, 216, -1, 217, -1, 172,
+ -1, 218, -1, 219, -1, 222, -1, 220, -1, 221,
+ -1, 223, -1, 224, -1, 225, -1, 236, -1, 201,
+ -1, 202, -1, 203, -1, 204, -1, 226, -1, 239,
+ -1, 197, -1, 199, -1, 240, -1, 245, -1, 246,
+ -1, 247, -1, 173, -1, 209, -1, 254, -1, 255,
+ -1, 198, -1, 250, -1, 185, -1, 168, -1, 193,
+ -1, 237, -1, 243, -1, 227, -1, 238, -1, 257,
+ -1, 258, -1, 174, -1, 163, -1, 184, -1, 230,
+ -1, 164, -1, 170, -1, 171, -1, 194, -1, 195,
+ -1, 256, -1, 229, -1, 231, -1, 232, -1, 165,
+ -1, 259, -1, 213, -1, 235, -1, 186, -1, 200,
+ -1, 241, -1, 242, -1, 244, -1, 249, -1, 196,
+ -1, 251, -1, 252, -1, 253, -1, 205, -1, 208,
+ -1, 233, -1, 234, -1, 206, -1, 228, -1, 248,
+ -1, 187, -1, 179, -1, 180, -1, 181, -1, 182,
+ -1, 183, -1, 260, -1, 261, -1, 262, -1, 207,
+ -1, 214, -1, 215, -1, 263, -1, 264, -1, 38,
+ -1, 156, 157, -1, -1, 265, -1, 266, -1, 267,
+ -1, 269, -1, 268, -1, 44, -1, 159, 160, -1,
+ -1, 270, -1, 271, -1, 272, -1, 273, -1, 13,
+ 10, -1, 12, 10, -1, 76, 10, -1, 79, 10,
+ -1, 96, 10, -1, 14, 10, -1, 16, 10, -1,
+ 67, 10, -1, 15, 10, -1, 80, 10, -1, 81,
+ 10, -1, 31, 10, -1, 60, 10, -1, 75, 10,
+ -1, 17, 10, -1, 18, 10, -1, 19, 10, -1,
+ 20, 10, -1, 122, 10, -1, 123, 10, -1, 124,
+ 10, -1, 125, 10, -1, 126, 10, -1, 77, 10,
+ -1, 66, 10, -1, 101, 10, -1, 121, 10, -1,
+ 21, 10, -1, 22, 10, -1, 23, 10, -1, 24,
+ 10, -1, 25, 10, -1, 68, 10, -1, 82, 10,
+ -1, 83, 10, -1, 109, 10, -1, 54, 10, -1,
+ 64, 10, -1, 55, 10, -1, 102, 10, -1, 48,
+ 10, -1, 49, 10, -1, 50, 10, -1, 51, 10,
+ -1, 113, 10, -1, 117, 10, -1, 118, 10, -1,
+ 114, 10, -1, 61, 10, -1, 26, 10, -1, 27,
+ 10, -1, 28, 10, -1, 98, 10, -1, 132, 10,
+ -1, 133, 10, -1, 29, 10, -1, 30, 10, -1,
+ 32, 10, -1, 33, 10, -1, 35, 10, -1, 36,
+ 10, -1, 34, 10, -1, 41, 10, -1, 42, 10,
+ -1, 43, 10, -1, 52, 10, -1, 71, 10, -1,
+ 119, 10, -1, 85, 10, -1, 78, 10, -1, 86,
+ 10, -1, 87, 10, -1, 115, 10, -1, 116, 10,
+ -1, 100, 10, -1, 47, 10, -1, 69, 10, -1,
+ 72, 10, 10, -1, 53, 10, -1, 56, 10, -1,
+ 105, 10, -1, 106, 10, -1, 70, 10, -1, 107,
+ 10, -1, 57, 10, -1, 58, 10, -1, 59, 10,
+ -1, 120, 10, -1, 108, 10, -1, 65, 10, -1,
+ 111, 10, -1, 112, 10, -1, 110, 10, -1, 62,
+ 10, -1, 63, 10, -1, 84, 10, -1, 73, 10,
+ 10, -1, 74, 10, -1, 97, 10, -1, 129, 10,
+ -1, 130, 10, -1, 131, 10, -1, 134, 10, -1,
+ 135, 10, -1, 37, 10, -1, 39, 10, -1, 40,
+ 10, -1, 128, 10, -1, 99, 10, -1, 37, 10,
+ -1, 45, 10, -1, 46, 10, -1, 127, 10, -1,
+ 88, -1, 275, 276, -1, -1, 277, -1, 279, -1,
+ 278, -1, 280, -1, 281, -1, 282, -1, 283, -1,
+ 89, 10, -1, 91, 10, -1, 90, 10, -1, 92,
+ 10, -1, 93, 10, -1, 94, 10, -1, 95, 10,
+ -1, 136, -1, 285, 286, -1, -1, 287, -1, 288,
+ -1, 289, -1, 290, -1, 291, -1, 292, -1, 293,
+ -1, 294, -1, 295, -1, 296, -1, 297, -1, 298,
+ -1, 137, 10, -1, 138, 10, -1, 139, 10, -1,
+ 140, 10, -1, 141, 10, -1, 142, 10, -1, 143,
+ 10, -1, 144, 10, -1, 145, 10, -1, 146, 10,
+ -1, 147, 10, -1, 148, 10, -1, 103, -1, 300,
+ 301, -1, -1, 302, -1, 104, 10, -1
+};
+
+/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 121, 121, 121, 122, 122, 123, 123, 124, 124,
+ 128, 133, 134, 135, 135, 135, 136, 136, 137, 137,
+ 137, 138, 138, 138, 139, 139, 139, 140, 140, 141,
+ 141, 142, 142, 143, 143, 144, 144, 145, 145, 146,
+ 146, 147, 147, 148, 148, 148, 149, 149, 149, 150,
+ 150, 150, 151, 151, 152, 152, 153, 153, 154, 154,
+ 155, 155, 155, 156, 156, 157, 157, 158, 158, 158,
+ 159, 159, 160, 160, 161, 161, 162, 162, 162, 163,
+ 163, 164, 164, 165, 165, 166, 166, 167, 167, 168,
+ 168, 168, 169, 169, 170, 170, 170, 171, 171, 171,
+ 172, 172, 172, 173, 173, 173, 174, 174, 174, 175,
+ 175, 175, 176, 176, 176, 177, 177, 179, 191, 192,
+ 193, 193, 193, 193, 193, 195, 207, 208, 209, 209,
+ 209, 209, 211, 220, 229, 240, 249, 258, 267, 280,
+ 295, 304, 313, 322, 331, 340, 349, 358, 367, 376,
+ 385, 394, 403, 410, 417, 426, 435, 449, 458, 467,
+ 474, 481, 488, 496, 503, 510, 517, 524, 532, 540,
+ 548, 555, 562, 571, 580, 587, 594, 602, 610, 620,
+ 633, 644, 652, 665, 674, 683, 692, 702, 710, 723,
+ 732, 740, 749, 757, 770, 777, 787, 797, 807, 817,
+ 827, 837, 847, 854, 861, 870, 879, 888, 895, 905,
+ 922, 929, 947, 960, 973, 982, 991, 1000, 1010, 1020,
+ 1029, 1038, 1045, 1054, 1063, 1072, 1080, 1093, 1101, 1123,
+ 1130, 1145, 1155, 1165, 1172, 1179, 1188, 1198, 1205, 1212,
+ 1221, 1231, 1241, 1248, 1255, 1264, 1269, 1270, 1271, 1271,
+ 1271, 1272, 1272, 1272, 1273, 1275, 1285, 1294, 1301, 1308,
+ 1315, 1322, 1329, 1334, 1335, 1336, 1336, 1337, 1337, 1338,
+ 1338, 1339, 1340, 1341, 1342, 1343, 1344, 1346, 1354, 1361,
+ 1369, 1377, 1384, 1391, 1400, 1409, 1418, 1427, 1436, 1445,
+ 1450, 1451, 1452, 1454
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "SPACE", "LETTER", "NEWLINE", "COMMENT",
+ "COLON", "ANY", "ZONESTR", "STRING_ARG", "VAR_SERVER", "VAR_VERBOSITY",
+ "VAR_NUM_THREADS", "VAR_PORT", "VAR_OUTGOING_RANGE", "VAR_INTERFACE",
+ "VAR_DO_IP4", "VAR_DO_IP6", "VAR_DO_UDP", "VAR_DO_TCP", "VAR_CHROOT",
+ "VAR_USERNAME", "VAR_DIRECTORY", "VAR_LOGFILE", "VAR_PIDFILE",
+ "VAR_MSG_CACHE_SIZE", "VAR_MSG_CACHE_SLABS",
+ "VAR_NUM_QUERIES_PER_THREAD", "VAR_RRSET_CACHE_SIZE",
+ "VAR_RRSET_CACHE_SLABS", "VAR_OUTGOING_NUM_TCP", "VAR_INFRA_HOST_TTL",
+ "VAR_INFRA_LAME_TTL", "VAR_INFRA_CACHE_SLABS",
+ "VAR_INFRA_CACHE_NUMHOSTS", "VAR_INFRA_CACHE_LAME_SIZE", "VAR_NAME",
+ "VAR_STUB_ZONE", "VAR_STUB_HOST", "VAR_STUB_ADDR",
+ "VAR_TARGET_FETCH_POLICY", "VAR_HARDEN_SHORT_BUFSIZE",
+ "VAR_HARDEN_LARGE_QUERIES", "VAR_FORWARD_ZONE", "VAR_FORWARD_HOST",
+ "VAR_FORWARD_ADDR", "VAR_DO_NOT_QUERY_ADDRESS", "VAR_HIDE_IDENTITY",
+ "VAR_HIDE_VERSION", "VAR_IDENTITY", "VAR_VERSION", "VAR_HARDEN_GLUE",
+ "VAR_MODULE_CONF", "VAR_TRUST_ANCHOR_FILE", "VAR_TRUST_ANCHOR",
+ "VAR_VAL_OVERRIDE_DATE", "VAR_BOGUS_TTL", "VAR_VAL_CLEAN_ADDITIONAL",
+ "VAR_VAL_PERMISSIVE_MODE", "VAR_INCOMING_NUM_TCP", "VAR_MSG_BUFFER_SIZE",
+ "VAR_KEY_CACHE_SIZE", "VAR_KEY_CACHE_SLABS", "VAR_TRUSTED_KEYS_FILE",
+ "VAR_VAL_NSEC3_KEYSIZE_ITERATIONS", "VAR_USE_SYSLOG",
+ "VAR_OUTGOING_INTERFACE", "VAR_ROOT_HINTS", "VAR_DO_NOT_QUERY_LOCALHOST",
+ "VAR_CACHE_MAX_TTL", "VAR_HARDEN_DNSSEC_STRIPPED", "VAR_ACCESS_CONTROL",
+ "VAR_LOCAL_ZONE", "VAR_LOCAL_DATA", "VAR_INTERFACE_AUTOMATIC",
+ "VAR_STATISTICS_INTERVAL", "VAR_DO_DAEMONIZE", "VAR_USE_CAPS_FOR_ID",
+ "VAR_STATISTICS_CUMULATIVE", "VAR_OUTGOING_PORT_PERMIT",
+ "VAR_OUTGOING_PORT_AVOID", "VAR_DLV_ANCHOR_FILE", "VAR_DLV_ANCHOR",
+ "VAR_NEG_CACHE_SIZE", "VAR_HARDEN_REFERRAL_PATH", "VAR_PRIVATE_ADDRESS",
+ "VAR_PRIVATE_DOMAIN", "VAR_REMOTE_CONTROL", "VAR_CONTROL_ENABLE",
+ "VAR_CONTROL_INTERFACE", "VAR_CONTROL_PORT", "VAR_SERVER_KEY_FILE",
+ "VAR_SERVER_CERT_FILE", "VAR_CONTROL_KEY_FILE", "VAR_CONTROL_CERT_FILE",
+ "VAR_EXTENDED_STATISTICS", "VAR_LOCAL_DATA_PTR", "VAR_JOSTLE_TIMEOUT",
+ "VAR_STUB_PRIME", "VAR_UNWANTED_REPLY_THRESHOLD", "VAR_LOG_TIME_ASCII",
+ "VAR_DOMAIN_INSECURE", "VAR_PYTHON", "VAR_PYTHON_SCRIPT",
+ "VAR_VAL_SIG_SKEW_MIN", "VAR_VAL_SIG_SKEW_MAX", "VAR_CACHE_MIN_TTL",
+ "VAR_VAL_LOG_LEVEL", "VAR_AUTO_TRUST_ANCHOR_FILE", "VAR_KEEP_MISSING",
+ "VAR_ADD_HOLDDOWN", "VAR_DEL_HOLDDOWN", "VAR_SO_RCVBUF",
+ "VAR_EDNS_BUFFER_SIZE", "VAR_PREFETCH", "VAR_PREFETCH_KEY",
+ "VAR_SO_SNDBUF", "VAR_SO_REUSEPORT", "VAR_HARDEN_BELOW_NXDOMAIN",
+ "VAR_IGNORE_CD_FLAG", "VAR_LOG_QUERIES", "VAR_TCP_UPSTREAM",
+ "VAR_SSL_UPSTREAM", "VAR_SSL_SERVICE_KEY", "VAR_SSL_SERVICE_PEM",
+ "VAR_SSL_PORT", "VAR_FORWARD_FIRST", "VAR_STUB_FIRST",
+ "VAR_MINIMAL_RESPONSES", "VAR_RRSET_ROUNDROBIN", "VAR_MAX_UDP_SIZE",
+ "VAR_DELAY_CLOSE", "VAR_UNBLOCK_LAN_ZONES", "VAR_DNS64_PREFIX",
+ "VAR_DNS64_SYNTHALL", "VAR_DNSTAP", "VAR_DNSTAP_ENABLE",
+ "VAR_DNSTAP_SOCKET_PATH", "VAR_DNSTAP_SEND_IDENTITY",
+ "VAR_DNSTAP_SEND_VERSION", "VAR_DNSTAP_IDENTITY", "VAR_DNSTAP_VERSION",
+ "VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES",
+ "VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES",
+ "VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES",
+ "VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES",
+ "VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES",
+ "VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES", "$accept", "toplevelvars",
+ "toplevelvar", "serverstart", "contents_server", "content_server",
+ "stubstart", "contents_stub", "content_stub", "forwardstart",
+ "contents_forward", "content_forward", "server_num_threads",
+ "server_verbosity", "server_statistics_interval",
+ "server_statistics_cumulative", "server_extended_statistics",
+ "server_port", "server_interface", "server_outgoing_interface",
+ "server_outgoing_range", "server_outgoing_port_permit",
+ "server_outgoing_port_avoid", "server_outgoing_num_tcp",
+ "server_incoming_num_tcp", "server_interface_automatic", "server_do_ip4",
+ "server_do_ip6", "server_do_udp", "server_do_tcp", "server_tcp_upstream",
+ "server_ssl_upstream", "server_ssl_service_key",
+ "server_ssl_service_pem", "server_ssl_port", "server_do_daemonize",
+ "server_use_syslog", "server_log_time_ascii", "server_log_queries",
+ "server_chroot", "server_username", "server_directory", "server_logfile",
+ "server_pidfile", "server_root_hints", "server_dlv_anchor_file",
+ "server_dlv_anchor", "server_auto_trust_anchor_file",
+ "server_trust_anchor_file", "server_trusted_keys_file",
+ "server_trust_anchor", "server_domain_insecure", "server_hide_identity",
+ "server_hide_version", "server_identity", "server_version",
+ "server_so_rcvbuf", "server_so_sndbuf", "server_so_reuseport",
+ "server_edns_buffer_size", "server_msg_buffer_size",
+ "server_msg_cache_size", "server_msg_cache_slabs",
+ "server_num_queries_per_thread", "server_jostle_timeout",
+ "server_delay_close", "server_unblock_lan_zones",
+ "server_rrset_cache_size", "server_rrset_cache_slabs",
+ "server_infra_host_ttl", "server_infra_lame_ttl",
+ "server_infra_cache_numhosts", "server_infra_cache_lame_size",
+ "server_infra_cache_slabs", "server_target_fetch_policy",
+ "server_harden_short_bufsize", "server_harden_large_queries",
+ "server_harden_glue", "server_harden_dnssec_stripped",
+ "server_harden_below_nxdomain", "server_harden_referral_path",
+ "server_use_caps_for_id", "server_private_address",
+ "server_private_domain", "server_prefetch", "server_prefetch_key",
+ "server_unwanted_reply_threshold", "server_do_not_query_address",
+ "server_do_not_query_localhost", "server_access_control",
+ "server_module_conf", "server_val_override_date",
+ "server_val_sig_skew_min", "server_val_sig_skew_max",
+ "server_cache_max_ttl", "server_cache_min_ttl", "server_bogus_ttl",
+ "server_val_clean_additional", "server_val_permissive_mode",
+ "server_ignore_cd_flag", "server_val_log_level",
+ "server_val_nsec3_keysize_iterations", "server_add_holddown",
+ "server_del_holddown", "server_keep_missing", "server_key_cache_size",
+ "server_key_cache_slabs", "server_neg_cache_size", "server_local_zone",
+ "server_local_data", "server_local_data_ptr", "server_minimal_responses",
+ "server_rrset_roundrobin", "server_max_udp_size", "server_dns64_prefix",
+ "server_dns64_synthall", "stub_name", "stub_host", "stub_addr",
+ "stub_first", "stub_prime", "forward_name", "forward_host",
+ "forward_addr", "forward_first", "rcstart", "contents_rc", "content_rc",
+ "rc_control_enable", "rc_control_port", "rc_control_interface",
+ "rc_server_key_file", "rc_server_cert_file", "rc_control_key_file",
+ "rc_control_cert_file", "dtstart", "contents_dt", "content_dt",
+ "dt_dnstap_enable", "dt_dnstap_socket_path", "dt_dnstap_send_identity",
+ "dt_dnstap_send_version", "dt_dnstap_identity", "dt_dnstap_version",
+ "dt_dnstap_log_resolver_query_messages",
+ "dt_dnstap_log_resolver_response_messages",
+ "dt_dnstap_log_client_query_messages",
+ "dt_dnstap_log_client_response_messages",
+ "dt_dnstap_log_forwarder_query_messages",
+ "dt_dnstap_log_forwarder_response_messages", "pythonstart",
+ "contents_py", "content_py", "py_script", YY_NULL
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
+ token YYLEX-NUM. */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280, 281, 282, 283, 284,
+ 285, 286, 287, 288, 289, 290, 291, 292, 293, 294,
+ 295, 296, 297, 298, 299, 300, 301, 302, 303, 304,
+ 305, 306, 307, 308, 309, 310, 311, 312, 313, 314,
+ 315, 316, 317, 318, 319, 320, 321, 322, 323, 324,
+ 325, 326, 327, 328, 329, 330, 331, 332, 333, 334,
+ 335, 336, 337, 338, 339, 340, 341, 342, 343, 344,
+ 345, 346, 347, 348, 349, 350, 351, 352, 353, 354,
+ 355, 356, 357, 358, 359, 360, 361, 362, 363, 364,
+ 365, 366, 367, 368, 369, 370, 371, 372, 373, 374,
+ 375, 376, 377, 378, 379, 380, 381, 382, 383, 384,
+ 385, 386, 387, 388, 389, 390, 391, 392, 393, 394,
+ 395, 396, 397, 398, 399, 400, 401, 402, 403
+};
+# endif
+
+/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint16 yyr1[] =
+{
+ 0, 149, 150, 150, 151, 151, 151, 151, 151, 151,
+ 152, 153, 153, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 154, 154, 154,
+ 154, 154, 154, 154, 154, 154, 154, 155, 156, 156,
+ 157, 157, 157, 157, 157, 158, 159, 159, 160, 160,
+ 160, 160, 161, 162, 163, 164, 165, 166, 167, 168,
+ 169, 170, 171, 172, 173, 174, 175, 176, 177, 178,
+ 179, 180, 181, 182, 183, 184, 185, 186, 187, 188,
+ 189, 190, 191, 192, 193, 194, 195, 196, 197, 198,
+ 199, 200, 201, 202, 203, 204, 205, 206, 207, 208,
+ 209, 210, 211, 212, 213, 214, 215, 216, 217, 218,
+ 219, 220, 221, 222, 223, 224, 225, 226, 227, 228,
+ 229, 230, 231, 232, 233, 234, 235, 236, 237, 238,
+ 239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
+ 249, 250, 251, 252, 253, 254, 255, 256, 257, 258,
+ 259, 260, 261, 262, 263, 264, 265, 266, 267, 268,
+ 269, 270, 271, 272, 273, 274, 275, 275, 276, 276,
+ 276, 276, 276, 276, 276, 277, 278, 279, 280, 281,
+ 282, 283, 284, 285, 285, 286, 286, 286, 286, 286,
+ 286, 286, 286, 286, 286, 286, 286, 287, 288, 289,
+ 290, 291, 292, 293, 294, 295, 296, 297, 298, 299,
+ 300, 300, 301, 302
+};
+
+/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 2, 2, 2, 2, 2, 2, 2,
+ 1, 2, 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 0,
+ 1, 1, 1, 1, 1, 1, 2, 0, 1, 1,
+ 1, 1, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 3, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 1, 2, 0, 1, 1,
+ 1, 1, 1, 1, 1, 2, 2, 2, 2, 2,
+ 2, 2, 1, 2, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 1,
+ 2, 0, 1, 2
+};
+
+/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE doesn't specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint16 yydefact[] =
+{
+ 2, 0, 1, 10, 117, 125, 245, 289, 262, 3,
+ 12, 119, 127, 247, 264, 291, 4, 5, 6, 8,
+ 9, 7, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 11, 13, 14, 70,
+ 73, 82, 15, 21, 61, 16, 74, 75, 32, 54,
+ 69, 17, 18, 19, 20, 104, 105, 106, 107, 108,
+ 71, 60, 86, 103, 22, 23, 24, 25, 26, 62,
+ 76, 77, 92, 48, 58, 49, 87, 42, 43, 44,
+ 45, 96, 100, 112, 97, 55, 27, 28, 29, 84,
+ 113, 114, 30, 31, 33, 34, 36, 37, 35, 38,
+ 39, 40, 46, 65, 101, 79, 72, 80, 81, 98,
+ 99, 85, 41, 63, 66, 47, 50, 88, 89, 64,
+ 90, 51, 52, 53, 102, 91, 59, 93, 94, 95,
+ 56, 57, 78, 67, 68, 83, 109, 110, 111, 115,
+ 116, 0, 0, 0, 0, 0, 118, 120, 121, 122,
+ 124, 123, 0, 0, 0, 0, 126, 128, 129, 130,
+ 131, 0, 0, 0, 0, 0, 0, 0, 246, 248,
+ 250, 249, 251, 252, 253, 254, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 263, 265,
+ 266, 267, 268, 269, 270, 271, 272, 273, 274, 275,
+ 276, 0, 290, 292, 133, 132, 137, 140, 138, 146,
+ 147, 148, 149, 159, 160, 161, 162, 163, 181, 182,
+ 183, 187, 188, 143, 189, 190, 193, 191, 192, 194,
+ 195, 196, 207, 172, 173, 174, 175, 197, 210, 168,
+ 170, 211, 216, 217, 218, 144, 180, 225, 226, 169,
+ 221, 156, 139, 164, 208, 214, 198, 0, 0, 229,
+ 145, 134, 155, 201, 135, 141, 142, 165, 166, 227,
+ 200, 202, 203, 136, 230, 184, 206, 157, 171, 212,
+ 213, 215, 220, 167, 224, 222, 223, 176, 179, 204,
+ 205, 177, 178, 199, 219, 158, 150, 151, 152, 153,
+ 154, 231, 232, 233, 185, 186, 234, 235, 236, 237,
+ 238, 240, 239, 241, 242, 243, 244, 255, 257, 256,
+ 258, 259, 260, 261, 277, 278, 279, 280, 281, 282,
+ 283, 284, 285, 286, 287, 288, 293, 209, 228
+};
+
+/* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int16 yydefgoto[] =
+{
+ -1, 1, 9, 10, 16, 126, 11, 17, 236, 12,
+ 18, 246, 127, 128, 129, 130, 131, 132, 133, 134,
+ 135, 136, 137, 138, 139, 140, 141, 142, 143, 144,
+ 145, 146, 147, 148, 149, 150, 151, 152, 153, 154,
+ 155, 156, 157, 158, 159, 160, 161, 162, 163, 164,
+ 165, 166, 167, 168, 169, 170, 171, 172, 173, 174,
+ 175, 176, 177, 178, 179, 180, 181, 182, 183, 184,
+ 185, 186, 187, 188, 189, 190, 191, 192, 193, 194,
+ 195, 196, 197, 198, 199, 200, 201, 202, 203, 204,
+ 205, 206, 207, 208, 209, 210, 211, 212, 213, 214,
+ 215, 216, 217, 218, 219, 220, 221, 222, 223, 224,
+ 225, 226, 227, 228, 229, 230, 237, 238, 239, 240,
+ 241, 247, 248, 249, 250, 13, 19, 258, 259, 260,
+ 261, 262, 263, 264, 265, 14, 20, 278, 279, 280,
+ 281, 282, 283, 284, 285, 286, 287, 288, 289, 290,
+ 15, 21, 292, 293
+};
+
+/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+#define YYPACT_NINF -123
+static const yytype_int16 yypact[] =
+{
+ -123, 0, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, 92, -36, -32, -62,
+ -122, -102, -4, -3, -2, -1, 2, 24, 25, 26,
+ 27, 29, 30, 31, 32, 33, 35, 36, 37, 38,
+ 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51, 52, 54, 55, 56, 57, 58, 59,
+ 60, 61, 62, 63, 64, 65, 66, 67, 68, 69,
+ 70, 71, 72, 73, 74, 75, 76, 77, 79, 80,
+ 81, 83, 84, 86, 87, 88, 89, 90, 91, 119,
+ 120, 121, 122, 127, 128, 170, 171, 172, 173, 174,
+ 175, 176, 177, 181, 185, 186, 209, 210, 218, 219,
+ 220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
+ 230, 231, 232, 233, 234, 235, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, 236, 237, 238, 239, 240, -123, -123, -123, -123,
+ -123, -123, 241, 242, 243, 244, -123, -123, -123, -123,
+ -123, 245, 246, 247, 248, 249, 250, 251, -123, -123,
+ -123, -123, -123, -123, -123, -123, 252, 253, 254, 255,
+ 256, 257, 258, 259, 260, 261, 262, 263, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, 264, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, 265, 266, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123
+};
+
+/* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123, -123, -123, -123, -123, -123, -123,
+ -123, -123, -123, -123
+};
+
+/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule which
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+#define YYTABLE_NINF -1
+static const yytype_uint16 yytable[] =
+{
+ 2, 231, 291, 232, 233, 242, 294, 295, 296, 297,
+ 0, 3, 298, 243, 244, 266, 267, 268, 269, 270,
+ 271, 272, 273, 274, 275, 276, 277, 251, 252, 253,
+ 254, 255, 256, 257, 299, 300, 301, 302, 4, 303,
+ 304, 305, 306, 307, 5, 308, 309, 310, 311, 312,
+ 313, 314, 315, 316, 317, 318, 319, 320, 321, 322,
+ 323, 324, 325, 234, 326, 327, 328, 329, 330, 331,
+ 332, 333, 334, 335, 336, 337, 338, 339, 340, 341,
+ 342, 343, 344, 345, 346, 347, 348, 349, 6, 350,
+ 351, 352, 235, 353, 354, 245, 355, 356, 357, 358,
+ 359, 360, 0, 7, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37,
+ 38, 39, 40, 41, 42, 43, 44, 45, 46, 361,
+ 362, 363, 364, 47, 48, 49, 8, 365, 366, 50,
+ 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
+ 61, 62, 63, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
+ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ 367, 368, 369, 370, 371, 372, 373, 374, 91, 92,
+ 93, 375, 94, 95, 96, 376, 377, 97, 98, 99,
+ 100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
+ 110, 111, 112, 113, 114, 115, 116, 117, 118, 378,
+ 379, 119, 120, 121, 122, 123, 124, 125, 380, 381,
+ 382, 383, 384, 385, 386, 387, 388, 389, 390, 391,
+ 392, 393, 394, 395, 396, 397, 398, 399, 400, 401,
+ 402, 403, 404, 405, 406, 407, 408, 409, 410, 411,
+ 412, 413, 414, 415, 416, 417, 418, 419, 420, 421,
+ 422, 423, 424, 425, 426, 427, 428
+};
+
+#define yypact_value_is_default(yystate) \
+ ((yystate) == (-123))
+
+#define yytable_value_is_error(yytable_value) \
+ YYID (0)
+
+static const yytype_int16 yycheck[] =
+{
+ 0, 37, 104, 39, 40, 37, 10, 10, 10, 10,
+ -1, 11, 10, 45, 46, 137, 138, 139, 140, 141,
+ 142, 143, 144, 145, 146, 147, 148, 89, 90, 91,
+ 92, 93, 94, 95, 10, 10, 10, 10, 38, 10,
+ 10, 10, 10, 10, 44, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 99, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 88, 10,
+ 10, 10, 128, 10, 10, 127, 10, 10, 10, 10,
+ 10, 10, -1, 103, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 26, 27,
+ 28, 29, 30, 31, 32, 33, 34, 35, 36, 10,
+ 10, 10, 10, 41, 42, 43, 136, 10, 10, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57,
+ 58, 59, 60, 61, 62, 63, 64, 65, 66, 67,
+ 68, 69, 70, 71, 72, 73, 74, 75, 76, 77,
+ 78, 79, 80, 81, 82, 83, 84, 85, 86, 87,
+ 10, 10, 10, 10, 10, 10, 10, 10, 96, 97,
+ 98, 10, 100, 101, 102, 10, 10, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+ 118, 119, 120, 121, 122, 123, 124, 125, 126, 10,
+ 10, 129, 130, 131, 132, 133, 134, 135, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10
+};
+
+/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint16 yystos[] =
+{
+ 0, 150, 0, 11, 38, 44, 88, 103, 136, 151,
+ 152, 155, 158, 274, 284, 299, 153, 156, 159, 275,
+ 285, 300, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+ 30, 31, 32, 33, 34, 35, 36, 41, 42, 43,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 56,
+ 57, 58, 59, 60, 61, 62, 63, 64, 65, 66,
+ 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
+ 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
+ 87, 96, 97, 98, 100, 101, 102, 105, 106, 107,
+ 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
+ 118, 119, 120, 121, 122, 123, 124, 125, 126, 129,
+ 130, 131, 132, 133, 134, 135, 154, 161, 162, 163,
+ 164, 165, 166, 167, 168, 169, 170, 171, 172, 173,
+ 174, 175, 176, 177, 178, 179, 180, 181, 182, 183,
+ 184, 185, 186, 187, 188, 189, 190, 191, 192, 193,
+ 194, 195, 196, 197, 198, 199, 200, 201, 202, 203,
+ 204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
+ 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231, 232, 233,
+ 234, 235, 236, 237, 238, 239, 240, 241, 242, 243,
+ 244, 245, 246, 247, 248, 249, 250, 251, 252, 253,
+ 254, 255, 256, 257, 258, 259, 260, 261, 262, 263,
+ 264, 37, 39, 40, 99, 128, 157, 265, 266, 267,
+ 268, 269, 37, 45, 46, 127, 160, 270, 271, 272,
+ 273, 89, 90, 91, 92, 93, 94, 95, 276, 277,
+ 278, 279, 280, 281, 282, 283, 137, 138, 139, 140,
+ 141, 142, 143, 144, 145, 146, 147, 148, 286, 287,
+ 288, 289, 290, 291, 292, 293, 294, 295, 296, 297,
+ 298, 104, 301, 302, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10
+};
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+/* Like YYERROR except do call yyerror. This remains here temporarily
+ to ease the transition to the new meaning of YYERROR, for GCC.
+ Once GCC version 2 has supplanted version 1, this can go. However,
+ YYFAIL appears to be in use. Nevertheless, it is formally deprecated
+ in Bison 2.4.2's NEWS entry, where a plan to phase it out is
+ discussed. */
+
+#define YYFAIL goto yyerrlab
+#if defined YYFAIL
+ /* This is here to suppress warnings from the GCC cpp's
+ -Wunused-macros. Normally we don't worry about that warning, but
+ some users do, and we want to make it easy for users to remove
+ YYFAIL uses, which will produce warnings from Bison 2.5. */
+#endif
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (YYID (0))
+
+
+#define YYTERROR 1
+#define YYERRCODE 256
+
+/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
+ If N is 0, then set CURRENT to the empty location which ends
+ the previous symbol: RHS[0] (always defined). */
+
+#ifndef YYLLOC_DEFAULT
+# define YYLLOC_DEFAULT(Current, Rhs, N) \
+ do \
+ if (YYID (N)) \
+ { \
+ (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \
+ (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \
+ (Current).last_line = YYRHSLOC (Rhs, N).last_line; \
+ (Current).last_column = YYRHSLOC (Rhs, N).last_column; \
+ } \
+ else \
+ { \
+ (Current).first_line = (Current).last_line = \
+ YYRHSLOC (Rhs, 0).last_line; \
+ (Current).first_column = (Current).last_column = \
+ YYRHSLOC (Rhs, 0).last_column; \
+ } \
+ while (YYID (0))
+#endif
+
+#define YYRHSLOC(Rhs, K) ((Rhs)[K])
+
+
+
+/* This macro is provided for backward compatibility. */
+
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+/* YYLEX -- calling `yylex' with the right arguments. */
+
+#ifdef YYLEX_PARAM
+# define YYLEX yylex (YYLEX_PARAM)
+#else
+# define YYLEX yylex ()
+#endif
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (YYID (0))
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (YYID (0))
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_value_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# else
+ YYUSE (yyoutput);
+# endif
+ switch (yytype)
+ {
+ default:
+ break;
+ }
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+#else
+static void
+yy_symbol_print (yyoutput, yytype, yyvaluep)
+ FILE *yyoutput;
+ int yytype;
+ YYSTYPE const * const yyvaluep;
+#endif
+{
+ if (yytype < YYNTOKENS)
+ YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
+ else
+ YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+#else
+static void
+yy_stack_print (yybottom, yytop)
+ yytype_int16 *yybottom;
+ yytype_int16 *yytop;
+#endif
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (YYID (0))
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
+#else
+static void
+yy_reduce_print (yyvsp, yyrule)
+ YYSTYPE *yyvsp;
+ int yyrule;
+#endif
+{
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ unsigned long int yylno = yyrline[yyrule];
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyvsp, Rule); \
+} while (YYID (0))
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static YYSIZE_T
+yystrlen (const char *yystr)
+#else
+static YYSIZE_T
+yystrlen (yystr)
+ const char *yystr;
+#endif
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+#else
+static char *
+yystpcpy (yydest, yysrc)
+ char *yydest;
+ const char *yysrc;
+#endif
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULL, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ YYSIZE_T yysize1;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULL;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - Assume YYFAIL is not used. It's too flawed to consider. See
+ <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
+ for details. YYERROR is fine as it does not invoke this
+ function.
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ yysize1 = yysize + yytnamerr (YY_NULL, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+/*ARGSUSED*/
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+#else
+static void
+yydestruct (yymsg, yytype, yyvaluep)
+ const char *yymsg;
+ int yytype;
+ YYSTYPE *yyvaluep;
+#endif
+{
+ YYUSE (yyvaluep);
+
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ switch (yytype)
+ {
+
+ default:
+ break;
+ }
+}
+
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+#ifdef YYPARSE_PARAM
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void *YYPARSE_PARAM)
+#else
+int
+yyparse (YYPARSE_PARAM)
+ void *YYPARSE_PARAM;
+#endif
+#else /* ! YYPARSE_PARAM */
+#if (defined __STDC__ || defined __C99__FUNC__ \
+ || defined __cplusplus || defined _MSC_VER)
+int
+yyparse (void)
+#else
+int
+yyparse ()
+
+#endif
+#endif
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ `yyss': related to states.
+ `yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yytoken = 0;
+ yyss = yyssa;
+ yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* Initialize stack pointers.
+ Waste one element of value and location stack
+ so that they stay on the same level as the state stack.
+ The wasted elements are never initialized. */
+ yyssp = yyss;
+ yyvsp = yyvs;
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = YYLEX;
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ *++yyvsp = yylval;
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ `$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 10:
+/* Line 1787 of yacc.c */
+#line 129 "./util/configparser.y"
+ {
+ OUTYY(("\nP(server:)\n"));
+ }
+ break;
+
+ case 117:
+/* Line 1787 of yacc.c */
+#line 180 "./util/configparser.y"
+ {
+ struct config_stub* s;
+ OUTYY(("\nP(stub_zone:)\n"));
+ s = (struct config_stub*)calloc(1, sizeof(struct config_stub));
+ if(s) {
+ s->next = cfg_parser->cfg->stubs;
+ cfg_parser->cfg->stubs = s;
+ } else
+ yyerror("out of memory");
+ }
+ break;
+
+ case 125:
+/* Line 1787 of yacc.c */
+#line 196 "./util/configparser.y"
+ {
+ struct config_stub* s;
+ OUTYY(("\nP(forward_zone:)\n"));
+ s = (struct config_stub*)calloc(1, sizeof(struct config_stub));
+ if(s) {
+ s->next = cfg_parser->cfg->forwards;
+ cfg_parser->cfg->forwards = s;
+ } else
+ yyerror("out of memory");
+ }
+ break;
+
+ case 132:
+/* Line 1787 of yacc.c */
+#line 212 "./util/configparser.y"
+ {
+ OUTYY(("P(server_num_threads:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->num_threads = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 133:
+/* Line 1787 of yacc.c */
+#line 221 "./util/configparser.y"
+ {
+ OUTYY(("P(server_verbosity:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->verbosity = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 134:
+/* Line 1787 of yacc.c */
+#line 230 "./util/configparser.y"
+ {
+ OUTYY(("P(server_statistics_interval:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "") == 0 || strcmp((yyvsp[(2) - (2)].str), "0") == 0)
+ cfg_parser->cfg->stat_interval = 0;
+ else if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->stat_interval = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 135:
+/* Line 1787 of yacc.c */
+#line 241 "./util/configparser.y"
+ {
+ OUTYY(("P(server_statistics_cumulative:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->stat_cumulative = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 136:
+/* Line 1787 of yacc.c */
+#line 250 "./util/configparser.y"
+ {
+ OUTYY(("P(server_extended_statistics:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->stat_extended = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 137:
+/* Line 1787 of yacc.c */
+#line 259 "./util/configparser.y"
+ {
+ OUTYY(("P(server_port:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("port number expected");
+ else cfg_parser->cfg->port = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 138:
+/* Line 1787 of yacc.c */
+#line 268 "./util/configparser.y"
+ {
+ OUTYY(("P(server_interface:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(cfg_parser->cfg->num_ifs == 0)
+ cfg_parser->cfg->ifs = calloc(1, sizeof(char*));
+ else cfg_parser->cfg->ifs = realloc(cfg_parser->cfg->ifs,
+ (cfg_parser->cfg->num_ifs+1)*sizeof(char*));
+ if(!cfg_parser->cfg->ifs)
+ yyerror("out of memory");
+ else
+ cfg_parser->cfg->ifs[cfg_parser->cfg->num_ifs++] = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 139:
+/* Line 1787 of yacc.c */
+#line 281 "./util/configparser.y"
+ {
+ OUTYY(("P(server_outgoing_interface:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(cfg_parser->cfg->num_out_ifs == 0)
+ cfg_parser->cfg->out_ifs = calloc(1, sizeof(char*));
+ else cfg_parser->cfg->out_ifs = realloc(
+ cfg_parser->cfg->out_ifs,
+ (cfg_parser->cfg->num_out_ifs+1)*sizeof(char*));
+ if(!cfg_parser->cfg->out_ifs)
+ yyerror("out of memory");
+ else
+ cfg_parser->cfg->out_ifs[
+ cfg_parser->cfg->num_out_ifs++] = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 140:
+/* Line 1787 of yacc.c */
+#line 296 "./util/configparser.y"
+ {
+ OUTYY(("P(server_outgoing_range:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->outgoing_num_ports = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 141:
+/* Line 1787 of yacc.c */
+#line 305 "./util/configparser.y"
+ {
+ OUTYY(("P(server_outgoing_port_permit:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_mark_ports((yyvsp[(2) - (2)].str), 1,
+ cfg_parser->cfg->outgoing_avail_ports, 65536))
+ yyerror("port number or range (\"low-high\") expected");
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 142:
+/* Line 1787 of yacc.c */
+#line 314 "./util/configparser.y"
+ {
+ OUTYY(("P(server_outgoing_port_avoid:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_mark_ports((yyvsp[(2) - (2)].str), 0,
+ cfg_parser->cfg->outgoing_avail_ports, 65536))
+ yyerror("port number or range (\"low-high\") expected");
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 143:
+/* Line 1787 of yacc.c */
+#line 323 "./util/configparser.y"
+ {
+ OUTYY(("P(server_outgoing_num_tcp:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->outgoing_num_tcp = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 144:
+/* Line 1787 of yacc.c */
+#line 332 "./util/configparser.y"
+ {
+ OUTYY(("P(server_incoming_num_tcp:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->incoming_num_tcp = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 145:
+/* Line 1787 of yacc.c */
+#line 341 "./util/configparser.y"
+ {
+ OUTYY(("P(server_interface_automatic:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->if_automatic = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 146:
+/* Line 1787 of yacc.c */
+#line 350 "./util/configparser.y"
+ {
+ OUTYY(("P(server_do_ip4:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_ip4 = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 147:
+/* Line 1787 of yacc.c */
+#line 359 "./util/configparser.y"
+ {
+ OUTYY(("P(server_do_ip6:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_ip6 = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 148:
+/* Line 1787 of yacc.c */
+#line 368 "./util/configparser.y"
+ {
+ OUTYY(("P(server_do_udp:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_udp = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 149:
+/* Line 1787 of yacc.c */
+#line 377 "./util/configparser.y"
+ {
+ OUTYY(("P(server_do_tcp:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_tcp = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 150:
+/* Line 1787 of yacc.c */
+#line 386 "./util/configparser.y"
+ {
+ OUTYY(("P(server_tcp_upstream:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->tcp_upstream = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 151:
+/* Line 1787 of yacc.c */
+#line 395 "./util/configparser.y"
+ {
+ OUTYY(("P(server_ssl_upstream:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->ssl_upstream = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 152:
+/* Line 1787 of yacc.c */
+#line 404 "./util/configparser.y"
+ {
+ OUTYY(("P(server_ssl_service_key:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->ssl_service_key);
+ cfg_parser->cfg->ssl_service_key = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 153:
+/* Line 1787 of yacc.c */
+#line 411 "./util/configparser.y"
+ {
+ OUTYY(("P(server_ssl_service_pem:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->ssl_service_pem);
+ cfg_parser->cfg->ssl_service_pem = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 154:
+/* Line 1787 of yacc.c */
+#line 418 "./util/configparser.y"
+ {
+ OUTYY(("P(server_ssl_port:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("port number expected");
+ else cfg_parser->cfg->ssl_port = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 155:
+/* Line 1787 of yacc.c */
+#line 427 "./util/configparser.y"
+ {
+ OUTYY(("P(server_do_daemonize:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_daemonize = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 156:
+/* Line 1787 of yacc.c */
+#line 436 "./util/configparser.y"
+ {
+ OUTYY(("P(server_use_syslog:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->use_syslog = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+#if !defined(HAVE_SYSLOG_H) && !defined(UB_ON_WINDOWS)
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") == 0)
+ yyerror("no syslog services are available. "
+ "(reconfigure and compile to add)");
+#endif
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 157:
+/* Line 1787 of yacc.c */
+#line 450 "./util/configparser.y"
+ {
+ OUTYY(("P(server_log_time_ascii:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->log_time_ascii = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 158:
+/* Line 1787 of yacc.c */
+#line 459 "./util/configparser.y"
+ {
+ OUTYY(("P(server_log_queries:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->log_queries = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 159:
+/* Line 1787 of yacc.c */
+#line 468 "./util/configparser.y"
+ {
+ OUTYY(("P(server_chroot:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->chrootdir);
+ cfg_parser->cfg->chrootdir = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 160:
+/* Line 1787 of yacc.c */
+#line 475 "./util/configparser.y"
+ {
+ OUTYY(("P(server_username:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->username);
+ cfg_parser->cfg->username = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 161:
+/* Line 1787 of yacc.c */
+#line 482 "./util/configparser.y"
+ {
+ OUTYY(("P(server_directory:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->directory);
+ cfg_parser->cfg->directory = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 162:
+/* Line 1787 of yacc.c */
+#line 489 "./util/configparser.y"
+ {
+ OUTYY(("P(server_logfile:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->logfile);
+ cfg_parser->cfg->logfile = (yyvsp[(2) - (2)].str);
+ cfg_parser->cfg->use_syslog = 0;
+ }
+ break;
+
+ case 163:
+/* Line 1787 of yacc.c */
+#line 497 "./util/configparser.y"
+ {
+ OUTYY(("P(server_pidfile:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->pidfile);
+ cfg_parser->cfg->pidfile = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 164:
+/* Line 1787 of yacc.c */
+#line 504 "./util/configparser.y"
+ {
+ OUTYY(("P(server_root_hints:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->root_hints, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 165:
+/* Line 1787 of yacc.c */
+#line 511 "./util/configparser.y"
+ {
+ OUTYY(("P(server_dlv_anchor_file:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->dlv_anchor_file);
+ cfg_parser->cfg->dlv_anchor_file = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 166:
+/* Line 1787 of yacc.c */
+#line 518 "./util/configparser.y"
+ {
+ OUTYY(("P(server_dlv_anchor:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->dlv_anchor_list, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 167:
+/* Line 1787 of yacc.c */
+#line 525 "./util/configparser.y"
+ {
+ OUTYY(("P(server_auto_trust_anchor_file:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ auto_trust_anchor_file_list, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 168:
+/* Line 1787 of yacc.c */
+#line 533 "./util/configparser.y"
+ {
+ OUTYY(("P(server_trust_anchor_file:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ trust_anchor_file_list, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 169:
+/* Line 1787 of yacc.c */
+#line 541 "./util/configparser.y"
+ {
+ OUTYY(("P(server_trusted_keys_file:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ trusted_keys_file_list, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 170:
+/* Line 1787 of yacc.c */
+#line 549 "./util/configparser.y"
+ {
+ OUTYY(("P(server_trust_anchor:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->trust_anchor_list, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 171:
+/* Line 1787 of yacc.c */
+#line 556 "./util/configparser.y"
+ {
+ OUTYY(("P(server_domain_insecure:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->domain_insecure, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 172:
+/* Line 1787 of yacc.c */
+#line 563 "./util/configparser.y"
+ {
+ OUTYY(("P(server_hide_identity:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->hide_identity = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 173:
+/* Line 1787 of yacc.c */
+#line 572 "./util/configparser.y"
+ {
+ OUTYY(("P(server_hide_version:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->hide_version = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 174:
+/* Line 1787 of yacc.c */
+#line 581 "./util/configparser.y"
+ {
+ OUTYY(("P(server_identity:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->identity);
+ cfg_parser->cfg->identity = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 175:
+/* Line 1787 of yacc.c */
+#line 588 "./util/configparser.y"
+ {
+ OUTYY(("P(server_version:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->version);
+ cfg_parser->cfg->version = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 176:
+/* Line 1787 of yacc.c */
+#line 595 "./util/configparser.y"
+ {
+ OUTYY(("P(server_so_rcvbuf:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->so_rcvbuf))
+ yyerror("buffer size expected");
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 177:
+/* Line 1787 of yacc.c */
+#line 603 "./util/configparser.y"
+ {
+ OUTYY(("P(server_so_sndbuf:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->so_sndbuf))
+ yyerror("buffer size expected");
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 178:
+/* Line 1787 of yacc.c */
+#line 611 "./util/configparser.y"
+ {
+ OUTYY(("P(server_so_reuseport:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->so_reuseport =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 179:
+/* Line 1787 of yacc.c */
+#line 621 "./util/configparser.y"
+ {
+ OUTYY(("P(server_edns_buffer_size:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ else if (atoi((yyvsp[(2) - (2)].str)) < 12)
+ yyerror("edns buffer size too small");
+ else if (atoi((yyvsp[(2) - (2)].str)) > 65535)
+ cfg_parser->cfg->edns_buffer_size = 65535;
+ else cfg_parser->cfg->edns_buffer_size = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 180:
+/* Line 1787 of yacc.c */
+#line 634 "./util/configparser.y"
+ {
+ OUTYY(("P(server_msg_buffer_size:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ else if (atoi((yyvsp[(2) - (2)].str)) < 4096)
+ yyerror("message buffer size too small (use 4096)");
+ else cfg_parser->cfg->msg_buffer_size = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 181:
+/* Line 1787 of yacc.c */
+#line 645 "./util/configparser.y"
+ {
+ OUTYY(("P(server_msg_cache_size:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->msg_cache_size))
+ yyerror("memory size expected");
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 182:
+/* Line 1787 of yacc.c */
+#line 653 "./util/configparser.y"
+ {
+ OUTYY(("P(server_msg_cache_slabs:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->cfg->msg_cache_slabs = atoi((yyvsp[(2) - (2)].str));
+ if(!is_pow2(cfg_parser->cfg->msg_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 183:
+/* Line 1787 of yacc.c */
+#line 666 "./util/configparser.y"
+ {
+ OUTYY(("P(server_num_queries_per_thread:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->num_queries_per_thread = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 184:
+/* Line 1787 of yacc.c */
+#line 675 "./util/configparser.y"
+ {
+ OUTYY(("P(server_jostle_timeout:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->jostle_time = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 185:
+/* Line 1787 of yacc.c */
+#line 684 "./util/configparser.y"
+ {
+ OUTYY(("P(server_delay_close:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->delay_close = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 186:
+/* Line 1787 of yacc.c */
+#line 693 "./util/configparser.y"
+ {
+ OUTYY(("P(server_unblock_lan_zones:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->unblock_lan_zones =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 187:
+/* Line 1787 of yacc.c */
+#line 703 "./util/configparser.y"
+ {
+ OUTYY(("P(server_rrset_cache_size:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->rrset_cache_size))
+ yyerror("memory size expected");
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 188:
+/* Line 1787 of yacc.c */
+#line 711 "./util/configparser.y"
+ {
+ OUTYY(("P(server_rrset_cache_slabs:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->cfg->rrset_cache_slabs = atoi((yyvsp[(2) - (2)].str));
+ if(!is_pow2(cfg_parser->cfg->rrset_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 189:
+/* Line 1787 of yacc.c */
+#line 724 "./util/configparser.y"
+ {
+ OUTYY(("P(server_infra_host_ttl:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->host_ttl = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 190:
+/* Line 1787 of yacc.c */
+#line 733 "./util/configparser.y"
+ {
+ OUTYY(("P(server_infra_lame_ttl:%s)\n", (yyvsp[(2) - (2)].str)));
+ verbose(VERB_DETAIL, "ignored infra-lame-ttl: %s (option "
+ "removed, use infra-host-ttl)", (yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 191:
+/* Line 1787 of yacc.c */
+#line 741 "./util/configparser.y"
+ {
+ OUTYY(("P(server_infra_cache_numhosts:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->infra_cache_numhosts = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 192:
+/* Line 1787 of yacc.c */
+#line 750 "./util/configparser.y"
+ {
+ OUTYY(("P(server_infra_cache_lame_size:%s)\n", (yyvsp[(2) - (2)].str)));
+ verbose(VERB_DETAIL, "ignored infra-cache-lame-size: %s "
+ "(option removed, use infra-cache-numhosts)", (yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 193:
+/* Line 1787 of yacc.c */
+#line 758 "./util/configparser.y"
+ {
+ OUTYY(("P(server_infra_cache_slabs:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->cfg->infra_cache_slabs = atoi((yyvsp[(2) - (2)].str));
+ if(!is_pow2(cfg_parser->cfg->infra_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 194:
+/* Line 1787 of yacc.c */
+#line 771 "./util/configparser.y"
+ {
+ OUTYY(("P(server_target_fetch_policy:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->target_fetch_policy);
+ cfg_parser->cfg->target_fetch_policy = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 195:
+/* Line 1787 of yacc.c */
+#line 778 "./util/configparser.y"
+ {
+ OUTYY(("P(server_harden_short_bufsize:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_short_bufsize =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 196:
+/* Line 1787 of yacc.c */
+#line 788 "./util/configparser.y"
+ {
+ OUTYY(("P(server_harden_large_queries:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_large_queries =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 197:
+/* Line 1787 of yacc.c */
+#line 798 "./util/configparser.y"
+ {
+ OUTYY(("P(server_harden_glue:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_glue =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 198:
+/* Line 1787 of yacc.c */
+#line 808 "./util/configparser.y"
+ {
+ OUTYY(("P(server_harden_dnssec_stripped:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_dnssec_stripped =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 199:
+/* Line 1787 of yacc.c */
+#line 818 "./util/configparser.y"
+ {
+ OUTYY(("P(server_harden_below_nxdomain:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_below_nxdomain =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 200:
+/* Line 1787 of yacc.c */
+#line 828 "./util/configparser.y"
+ {
+ OUTYY(("P(server_harden_referral_path:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_referral_path =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 201:
+/* Line 1787 of yacc.c */
+#line 838 "./util/configparser.y"
+ {
+ OUTYY(("P(server_use_caps_for_id:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->use_caps_bits_for_id =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 202:
+/* Line 1787 of yacc.c */
+#line 848 "./util/configparser.y"
+ {
+ OUTYY(("P(server_private_address:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->private_address, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 203:
+/* Line 1787 of yacc.c */
+#line 855 "./util/configparser.y"
+ {
+ OUTYY(("P(server_private_domain:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->private_domain, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 204:
+/* Line 1787 of yacc.c */
+#line 862 "./util/configparser.y"
+ {
+ OUTYY(("P(server_prefetch:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->prefetch = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 205:
+/* Line 1787 of yacc.c */
+#line 871 "./util/configparser.y"
+ {
+ OUTYY(("P(server_prefetch_key:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->prefetch_key = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 206:
+/* Line 1787 of yacc.c */
+#line 880 "./util/configparser.y"
+ {
+ OUTYY(("P(server_unwanted_reply_threshold:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->unwanted_threshold = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 207:
+/* Line 1787 of yacc.c */
+#line 889 "./util/configparser.y"
+ {
+ OUTYY(("P(server_do_not_query_address:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->donotqueryaddrs, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 208:
+/* Line 1787 of yacc.c */
+#line 896 "./util/configparser.y"
+ {
+ OUTYY(("P(server_do_not_query_localhost:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->donotquery_localhost =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 209:
+/* Line 1787 of yacc.c */
+#line 906 "./util/configparser.y"
+ {
+ OUTYY(("P(server_access_control:%s %s)\n", (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str)));
+ if(strcmp((yyvsp[(3) - (3)].str), "deny")!=0 && strcmp((yyvsp[(3) - (3)].str), "refuse")!=0 &&
+ strcmp((yyvsp[(3) - (3)].str), "deny_non_local")!=0 &&
+ strcmp((yyvsp[(3) - (3)].str), "refuse_non_local")!=0 &&
+ strcmp((yyvsp[(3) - (3)].str), "allow")!=0 &&
+ strcmp((yyvsp[(3) - (3)].str), "allow_snoop")!=0) {
+ yyerror("expected deny, refuse, deny_non_local, "
+ "refuse_non_local, allow or allow_snoop "
+ "in access control action");
+ } else {
+ if(!cfg_str2list_insert(&cfg_parser->cfg->acls, (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str)))
+ fatal_exit("out of memory adding acl");
+ }
+ }
+ break;
+
+ case 210:
+/* Line 1787 of yacc.c */
+#line 923 "./util/configparser.y"
+ {
+ OUTYY(("P(server_module_conf:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->module_conf);
+ cfg_parser->cfg->module_conf = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 211:
+/* Line 1787 of yacc.c */
+#line 930 "./util/configparser.y"
+ {
+ OUTYY(("P(server_val_override_date:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strlen((yyvsp[(2) - (2)].str)) == 0 || strcmp((yyvsp[(2) - (2)].str), "0") == 0) {
+ cfg_parser->cfg->val_date_override = 0;
+ } else if(strlen((yyvsp[(2) - (2)].str)) == 14) {
+ cfg_parser->cfg->val_date_override =
+ cfg_convert_timeval((yyvsp[(2) - (2)].str));
+ if(!cfg_parser->cfg->val_date_override)
+ yyerror("bad date/time specification");
+ } else {
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ cfg_parser->cfg->val_date_override = atoi((yyvsp[(2) - (2)].str));
+ }
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 212:
+/* Line 1787 of yacc.c */
+#line 948 "./util/configparser.y"
+ {
+ OUTYY(("P(server_val_sig_skew_min:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strlen((yyvsp[(2) - (2)].str)) == 0 || strcmp((yyvsp[(2) - (2)].str), "0") == 0) {
+ cfg_parser->cfg->val_sig_skew_min = 0;
+ } else {
+ cfg_parser->cfg->val_sig_skew_min = atoi((yyvsp[(2) - (2)].str));
+ if(!cfg_parser->cfg->val_sig_skew_min)
+ yyerror("number expected");
+ }
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 213:
+/* Line 1787 of yacc.c */
+#line 961 "./util/configparser.y"
+ {
+ OUTYY(("P(server_val_sig_skew_max:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strlen((yyvsp[(2) - (2)].str)) == 0 || strcmp((yyvsp[(2) - (2)].str), "0") == 0) {
+ cfg_parser->cfg->val_sig_skew_max = 0;
+ } else {
+ cfg_parser->cfg->val_sig_skew_max = atoi((yyvsp[(2) - (2)].str));
+ if(!cfg_parser->cfg->val_sig_skew_max)
+ yyerror("number expected");
+ }
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 214:
+/* Line 1787 of yacc.c */
+#line 974 "./util/configparser.y"
+ {
+ OUTYY(("P(server_cache_max_ttl:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->max_ttl = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 215:
+/* Line 1787 of yacc.c */
+#line 983 "./util/configparser.y"
+ {
+ OUTYY(("P(server_cache_min_ttl:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->min_ttl = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 216:
+/* Line 1787 of yacc.c */
+#line 992 "./util/configparser.y"
+ {
+ OUTYY(("P(server_bogus_ttl:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->bogus_ttl = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 217:
+/* Line 1787 of yacc.c */
+#line 1001 "./util/configparser.y"
+ {
+ OUTYY(("P(server_val_clean_additional:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->val_clean_additional =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 218:
+/* Line 1787 of yacc.c */
+#line 1011 "./util/configparser.y"
+ {
+ OUTYY(("P(server_val_permissive_mode:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->val_permissive_mode =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 219:
+/* Line 1787 of yacc.c */
+#line 1021 "./util/configparser.y"
+ {
+ OUTYY(("P(server_ignore_cd_flag:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->ignore_cd = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 220:
+/* Line 1787 of yacc.c */
+#line 1030 "./util/configparser.y"
+ {
+ OUTYY(("P(server_val_log_level:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->val_log_level = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 221:
+/* Line 1787 of yacc.c */
+#line 1039 "./util/configparser.y"
+ {
+ OUTYY(("P(server_val_nsec3_keysize_iterations:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->val_nsec3_key_iterations);
+ cfg_parser->cfg->val_nsec3_key_iterations = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 222:
+/* Line 1787 of yacc.c */
+#line 1046 "./util/configparser.y"
+ {
+ OUTYY(("P(server_add_holddown:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->add_holddown = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 223:
+/* Line 1787 of yacc.c */
+#line 1055 "./util/configparser.y"
+ {
+ OUTYY(("P(server_del_holddown:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->del_holddown = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 224:
+/* Line 1787 of yacc.c */
+#line 1064 "./util/configparser.y"
+ {
+ OUTYY(("P(server_keep_missing:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0 && strcmp((yyvsp[(2) - (2)].str), "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->keep_missing = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 225:
+/* Line 1787 of yacc.c */
+#line 1073 "./util/configparser.y"
+ {
+ OUTYY(("P(server_key_cache_size:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->key_cache_size))
+ yyerror("memory size expected");
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 226:
+/* Line 1787 of yacc.c */
+#line 1081 "./util/configparser.y"
+ {
+ OUTYY(("P(server_key_cache_slabs:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->cfg->key_cache_slabs = atoi((yyvsp[(2) - (2)].str));
+ if(!is_pow2(cfg_parser->cfg->key_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 227:
+/* Line 1787 of yacc.c */
+#line 1094 "./util/configparser.y"
+ {
+ OUTYY(("P(server_neg_cache_size:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_parse_memsize((yyvsp[(2) - (2)].str), &cfg_parser->cfg->neg_cache_size))
+ yyerror("memory size expected");
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 228:
+/* Line 1787 of yacc.c */
+#line 1102 "./util/configparser.y"
+ {
+ OUTYY(("P(server_local_zone:%s %s)\n", (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str)));
+ if(strcmp((yyvsp[(3) - (3)].str), "static")!=0 && strcmp((yyvsp[(3) - (3)].str), "deny")!=0 &&
+ strcmp((yyvsp[(3) - (3)].str), "refuse")!=0 && strcmp((yyvsp[(3) - (3)].str), "redirect")!=0 &&
+ strcmp((yyvsp[(3) - (3)].str), "transparent")!=0 && strcmp((yyvsp[(3) - (3)].str), "nodefault")!=0
+ && strcmp((yyvsp[(3) - (3)].str), "typetransparent")!=0)
+ yyerror("local-zone type: expected static, deny, "
+ "refuse, redirect, transparent, "
+ "typetransparent or nodefault");
+ else if(strcmp((yyvsp[(3) - (3)].str), "nodefault")==0) {
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ local_zones_nodefault, (yyvsp[(2) - (3)].str)))
+ fatal_exit("out of memory adding local-zone");
+ free((yyvsp[(3) - (3)].str));
+ } else {
+ if(!cfg_str2list_insert(&cfg_parser->cfg->local_zones,
+ (yyvsp[(2) - (3)].str), (yyvsp[(3) - (3)].str)))
+ fatal_exit("out of memory adding local-zone");
+ }
+ }
+ break;
+
+ case 229:
+/* Line 1787 of yacc.c */
+#line 1124 "./util/configparser.y"
+ {
+ OUTYY(("P(server_local_data:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->local_data, (yyvsp[(2) - (2)].str)))
+ fatal_exit("out of memory adding local-data");
+ }
+ break;
+
+ case 230:
+/* Line 1787 of yacc.c */
+#line 1131 "./util/configparser.y"
+ {
+ char* ptr;
+ OUTYY(("P(server_local_data_ptr:%s)\n", (yyvsp[(2) - (2)].str)));
+ ptr = cfg_ptr_reverse((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ if(ptr) {
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ local_data, ptr))
+ fatal_exit("out of memory adding local-data");
+ } else {
+ yyerror("local-data-ptr could not be reversed");
+ }
+ }
+ break;
+
+ case 231:
+/* Line 1787 of yacc.c */
+#line 1146 "./util/configparser.y"
+ {
+ OUTYY(("P(server_minimal_responses:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->minimal_responses =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 232:
+/* Line 1787 of yacc.c */
+#line 1156 "./util/configparser.y"
+ {
+ OUTYY(("P(server_rrset_roundrobin:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->rrset_roundrobin =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 233:
+/* Line 1787 of yacc.c */
+#line 1166 "./util/configparser.y"
+ {
+ OUTYY(("P(server_max_udp_size:%s)\n", (yyvsp[(2) - (2)].str)));
+ cfg_parser->cfg->max_udp_size = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 234:
+/* Line 1787 of yacc.c */
+#line 1173 "./util/configparser.y"
+ {
+ OUTYY(("P(dns64_prefix:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->dns64_prefix);
+ cfg_parser->cfg->dns64_prefix = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 235:
+/* Line 1787 of yacc.c */
+#line 1180 "./util/configparser.y"
+ {
+ OUTYY(("P(server_dns64_synthall:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dns64_synthall = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 236:
+/* Line 1787 of yacc.c */
+#line 1189 "./util/configparser.y"
+ {
+ OUTYY(("P(name:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(cfg_parser->cfg->stubs->name)
+ yyerror("stub name override, there must be one name "
+ "for one stub-zone");
+ free(cfg_parser->cfg->stubs->name);
+ cfg_parser->cfg->stubs->name = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 237:
+/* Line 1787 of yacc.c */
+#line 1199 "./util/configparser.y"
+ {
+ OUTYY(("P(stub-host:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->stubs->hosts, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 238:
+/* Line 1787 of yacc.c */
+#line 1206 "./util/configparser.y"
+ {
+ OUTYY(("P(stub-addr:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->stubs->addrs, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 239:
+/* Line 1787 of yacc.c */
+#line 1213 "./util/configparser.y"
+ {
+ OUTYY(("P(stub-first:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->stubs->isfirst=(strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 240:
+/* Line 1787 of yacc.c */
+#line 1222 "./util/configparser.y"
+ {
+ OUTYY(("P(stub-prime:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->stubs->isprime =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 241:
+/* Line 1787 of yacc.c */
+#line 1232 "./util/configparser.y"
+ {
+ OUTYY(("P(name:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(cfg_parser->cfg->forwards->name)
+ yyerror("forward name override, there must be one "
+ "name for one forward-zone");
+ free(cfg_parser->cfg->forwards->name);
+ cfg_parser->cfg->forwards->name = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 242:
+/* Line 1787 of yacc.c */
+#line 1242 "./util/configparser.y"
+ {
+ OUTYY(("P(forward-host:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->forwards->hosts, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 243:
+/* Line 1787 of yacc.c */
+#line 1249 "./util/configparser.y"
+ {
+ OUTYY(("P(forward-addr:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->forwards->addrs, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 244:
+/* Line 1787 of yacc.c */
+#line 1256 "./util/configparser.y"
+ {
+ OUTYY(("P(forward-first:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->forwards->isfirst=(strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 245:
+/* Line 1787 of yacc.c */
+#line 1265 "./util/configparser.y"
+ {
+ OUTYY(("\nP(remote-control:)\n"));
+ }
+ break;
+
+ case 255:
+/* Line 1787 of yacc.c */
+#line 1276 "./util/configparser.y"
+ {
+ OUTYY(("P(control_enable:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->remote_control_enable =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 256:
+/* Line 1787 of yacc.c */
+#line 1286 "./util/configparser.y"
+ {
+ OUTYY(("P(control_port:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(atoi((yyvsp[(2) - (2)].str)) == 0)
+ yyerror("control port number expected");
+ else cfg_parser->cfg->control_port = atoi((yyvsp[(2) - (2)].str));
+ free((yyvsp[(2) - (2)].str));
+ }
+ break;
+
+ case 257:
+/* Line 1787 of yacc.c */
+#line 1295 "./util/configparser.y"
+ {
+ OUTYY(("P(control_interface:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->control_ifs, (yyvsp[(2) - (2)].str)))
+ yyerror("out of memory");
+ }
+ break;
+
+ case 258:
+/* Line 1787 of yacc.c */
+#line 1302 "./util/configparser.y"
+ {
+ OUTYY(("P(rc_server_key_file:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->server_key_file);
+ cfg_parser->cfg->server_key_file = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 259:
+/* Line 1787 of yacc.c */
+#line 1309 "./util/configparser.y"
+ {
+ OUTYY(("P(rc_server_cert_file:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->server_cert_file);
+ cfg_parser->cfg->server_cert_file = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 260:
+/* Line 1787 of yacc.c */
+#line 1316 "./util/configparser.y"
+ {
+ OUTYY(("P(rc_control_key_file:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->control_key_file);
+ cfg_parser->cfg->control_key_file = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 261:
+/* Line 1787 of yacc.c */
+#line 1323 "./util/configparser.y"
+ {
+ OUTYY(("P(rc_control_cert_file:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->control_cert_file);
+ cfg_parser->cfg->control_cert_file = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 262:
+/* Line 1787 of yacc.c */
+#line 1330 "./util/configparser.y"
+ {
+ OUTYY(("\nP(dnstap:)\n"));
+ }
+ break;
+
+ case 277:
+/* Line 1787 of yacc.c */
+#line 1347 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_enable:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ }
+ break;
+
+ case 278:
+/* Line 1787 of yacc.c */
+#line 1355 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_socket_path:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->dnstap_socket_path);
+ cfg_parser->cfg->dnstap_socket_path = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 279:
+/* Line 1787 of yacc.c */
+#line 1362 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_send_identity:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_send_identity = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ }
+ break;
+
+ case 280:
+/* Line 1787 of yacc.c */
+#line 1370 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_send_version:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_send_version = (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ }
+ break;
+
+ case 281:
+/* Line 1787 of yacc.c */
+#line 1378 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_identity:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->dnstap_identity);
+ cfg_parser->cfg->dnstap_identity = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 282:
+/* Line 1787 of yacc.c */
+#line 1385 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_version:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->dnstap_version);
+ cfg_parser->cfg->dnstap_version = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+ case 283:
+/* Line 1787 of yacc.c */
+#line 1392 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_log_resolver_query_messages:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_resolver_query_messages =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ }
+ break;
+
+ case 284:
+/* Line 1787 of yacc.c */
+#line 1401 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_log_resolver_response_messages:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_resolver_response_messages =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ }
+ break;
+
+ case 285:
+/* Line 1787 of yacc.c */
+#line 1410 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_log_client_query_messages:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_client_query_messages =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ }
+ break;
+
+ case 286:
+/* Line 1787 of yacc.c */
+#line 1419 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_log_client_response_messages:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_client_response_messages =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ }
+ break;
+
+ case 287:
+/* Line 1787 of yacc.c */
+#line 1428 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_log_forwarder_query_messages:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_forwarder_query_messages =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ }
+ break;
+
+ case 288:
+/* Line 1787 of yacc.c */
+#line 1437 "./util/configparser.y"
+ {
+ OUTYY(("P(dt_dnstap_log_forwarder_response_messages:%s)\n", (yyvsp[(2) - (2)].str)));
+ if(strcmp((yyvsp[(2) - (2)].str), "yes") != 0 && strcmp((yyvsp[(2) - (2)].str), "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_forwarder_response_messages =
+ (strcmp((yyvsp[(2) - (2)].str), "yes")==0);
+ }
+ break;
+
+ case 289:
+/* Line 1787 of yacc.c */
+#line 1446 "./util/configparser.y"
+ {
+ OUTYY(("\nP(python:)\n"));
+ }
+ break;
+
+ case 293:
+/* Line 1787 of yacc.c */
+#line 1455 "./util/configparser.y"
+ {
+ OUTYY(("P(python-script:%s)\n", (yyvsp[(2) - (2)].str)));
+ free(cfg_parser->cfg->python_script);
+ cfg_parser->cfg->python_script = (yyvsp[(2) - (2)].str);
+ }
+ break;
+
+
+/* Line 1787 of yacc.c */
+#line 3876 "util/configparser.c"
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now `shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*------------------------------------.
+| yyerrlab -- here on detecting error |
+`------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ *++yyvsp = yylval;
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule which action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ /* Make sure YYID is used. */
+ return YYID (yyresult);
+}
+
+
+/* Line 2048 of yacc.c */
+#line 1460 "./util/configparser.y"
+
+
+/* parse helper routines could be here */
+
diff --git a/external/unbound/util/configparser.h b/external/unbound/util/configparser.h
new file mode 100644
index 000000000..b0e07227b
--- /dev/null
+++ b/external/unbound/util/configparser.h
@@ -0,0 +1,380 @@
+/* A Bison parser, made by GNU Bison 2.6.1. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2012 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_UTIL_CONFIGPARSER_H
+# define YY_UTIL_CONFIGPARSER_H
+/* Enabling traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 0
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Tokens. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ /* Put the tokens into the symbol table, so that GDB and other debuggers
+ know about them. */
+ enum yytokentype {
+ SPACE = 258,
+ LETTER = 259,
+ NEWLINE = 260,
+ COMMENT = 261,
+ COLON = 262,
+ ANY = 263,
+ ZONESTR = 264,
+ STRING_ARG = 265,
+ VAR_SERVER = 266,
+ VAR_VERBOSITY = 267,
+ VAR_NUM_THREADS = 268,
+ VAR_PORT = 269,
+ VAR_OUTGOING_RANGE = 270,
+ VAR_INTERFACE = 271,
+ VAR_DO_IP4 = 272,
+ VAR_DO_IP6 = 273,
+ VAR_DO_UDP = 274,
+ VAR_DO_TCP = 275,
+ VAR_CHROOT = 276,
+ VAR_USERNAME = 277,
+ VAR_DIRECTORY = 278,
+ VAR_LOGFILE = 279,
+ VAR_PIDFILE = 280,
+ VAR_MSG_CACHE_SIZE = 281,
+ VAR_MSG_CACHE_SLABS = 282,
+ VAR_NUM_QUERIES_PER_THREAD = 283,
+ VAR_RRSET_CACHE_SIZE = 284,
+ VAR_RRSET_CACHE_SLABS = 285,
+ VAR_OUTGOING_NUM_TCP = 286,
+ VAR_INFRA_HOST_TTL = 287,
+ VAR_INFRA_LAME_TTL = 288,
+ VAR_INFRA_CACHE_SLABS = 289,
+ VAR_INFRA_CACHE_NUMHOSTS = 290,
+ VAR_INFRA_CACHE_LAME_SIZE = 291,
+ VAR_NAME = 292,
+ VAR_STUB_ZONE = 293,
+ VAR_STUB_HOST = 294,
+ VAR_STUB_ADDR = 295,
+ VAR_TARGET_FETCH_POLICY = 296,
+ VAR_HARDEN_SHORT_BUFSIZE = 297,
+ VAR_HARDEN_LARGE_QUERIES = 298,
+ VAR_FORWARD_ZONE = 299,
+ VAR_FORWARD_HOST = 300,
+ VAR_FORWARD_ADDR = 301,
+ VAR_DO_NOT_QUERY_ADDRESS = 302,
+ VAR_HIDE_IDENTITY = 303,
+ VAR_HIDE_VERSION = 304,
+ VAR_IDENTITY = 305,
+ VAR_VERSION = 306,
+ VAR_HARDEN_GLUE = 307,
+ VAR_MODULE_CONF = 308,
+ VAR_TRUST_ANCHOR_FILE = 309,
+ VAR_TRUST_ANCHOR = 310,
+ VAR_VAL_OVERRIDE_DATE = 311,
+ VAR_BOGUS_TTL = 312,
+ VAR_VAL_CLEAN_ADDITIONAL = 313,
+ VAR_VAL_PERMISSIVE_MODE = 314,
+ VAR_INCOMING_NUM_TCP = 315,
+ VAR_MSG_BUFFER_SIZE = 316,
+ VAR_KEY_CACHE_SIZE = 317,
+ VAR_KEY_CACHE_SLABS = 318,
+ VAR_TRUSTED_KEYS_FILE = 319,
+ VAR_VAL_NSEC3_KEYSIZE_ITERATIONS = 320,
+ VAR_USE_SYSLOG = 321,
+ VAR_OUTGOING_INTERFACE = 322,
+ VAR_ROOT_HINTS = 323,
+ VAR_DO_NOT_QUERY_LOCALHOST = 324,
+ VAR_CACHE_MAX_TTL = 325,
+ VAR_HARDEN_DNSSEC_STRIPPED = 326,
+ VAR_ACCESS_CONTROL = 327,
+ VAR_LOCAL_ZONE = 328,
+ VAR_LOCAL_DATA = 329,
+ VAR_INTERFACE_AUTOMATIC = 330,
+ VAR_STATISTICS_INTERVAL = 331,
+ VAR_DO_DAEMONIZE = 332,
+ VAR_USE_CAPS_FOR_ID = 333,
+ VAR_STATISTICS_CUMULATIVE = 334,
+ VAR_OUTGOING_PORT_PERMIT = 335,
+ VAR_OUTGOING_PORT_AVOID = 336,
+ VAR_DLV_ANCHOR_FILE = 337,
+ VAR_DLV_ANCHOR = 338,
+ VAR_NEG_CACHE_SIZE = 339,
+ VAR_HARDEN_REFERRAL_PATH = 340,
+ VAR_PRIVATE_ADDRESS = 341,
+ VAR_PRIVATE_DOMAIN = 342,
+ VAR_REMOTE_CONTROL = 343,
+ VAR_CONTROL_ENABLE = 344,
+ VAR_CONTROL_INTERFACE = 345,
+ VAR_CONTROL_PORT = 346,
+ VAR_SERVER_KEY_FILE = 347,
+ VAR_SERVER_CERT_FILE = 348,
+ VAR_CONTROL_KEY_FILE = 349,
+ VAR_CONTROL_CERT_FILE = 350,
+ VAR_EXTENDED_STATISTICS = 351,
+ VAR_LOCAL_DATA_PTR = 352,
+ VAR_JOSTLE_TIMEOUT = 353,
+ VAR_STUB_PRIME = 354,
+ VAR_UNWANTED_REPLY_THRESHOLD = 355,
+ VAR_LOG_TIME_ASCII = 356,
+ VAR_DOMAIN_INSECURE = 357,
+ VAR_PYTHON = 358,
+ VAR_PYTHON_SCRIPT = 359,
+ VAR_VAL_SIG_SKEW_MIN = 360,
+ VAR_VAL_SIG_SKEW_MAX = 361,
+ VAR_CACHE_MIN_TTL = 362,
+ VAR_VAL_LOG_LEVEL = 363,
+ VAR_AUTO_TRUST_ANCHOR_FILE = 364,
+ VAR_KEEP_MISSING = 365,
+ VAR_ADD_HOLDDOWN = 366,
+ VAR_DEL_HOLDDOWN = 367,
+ VAR_SO_RCVBUF = 368,
+ VAR_EDNS_BUFFER_SIZE = 369,
+ VAR_PREFETCH = 370,
+ VAR_PREFETCH_KEY = 371,
+ VAR_SO_SNDBUF = 372,
+ VAR_SO_REUSEPORT = 373,
+ VAR_HARDEN_BELOW_NXDOMAIN = 374,
+ VAR_IGNORE_CD_FLAG = 375,
+ VAR_LOG_QUERIES = 376,
+ VAR_TCP_UPSTREAM = 377,
+ VAR_SSL_UPSTREAM = 378,
+ VAR_SSL_SERVICE_KEY = 379,
+ VAR_SSL_SERVICE_PEM = 380,
+ VAR_SSL_PORT = 381,
+ VAR_FORWARD_FIRST = 382,
+ VAR_STUB_FIRST = 383,
+ VAR_MINIMAL_RESPONSES = 384,
+ VAR_RRSET_ROUNDROBIN = 385,
+ VAR_MAX_UDP_SIZE = 386,
+ VAR_DELAY_CLOSE = 387,
+ VAR_UNBLOCK_LAN_ZONES = 388,
+ VAR_DNS64_PREFIX = 389,
+ VAR_DNS64_SYNTHALL = 390,
+ VAR_DNSTAP = 391,
+ VAR_DNSTAP_ENABLE = 392,
+ VAR_DNSTAP_SOCKET_PATH = 393,
+ VAR_DNSTAP_SEND_IDENTITY = 394,
+ VAR_DNSTAP_SEND_VERSION = 395,
+ VAR_DNSTAP_IDENTITY = 396,
+ VAR_DNSTAP_VERSION = 397,
+ VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES = 398,
+ VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES = 399,
+ VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES = 400,
+ VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES = 401,
+ VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES = 402,
+ VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES = 403
+ };
+#endif
+/* Tokens. */
+#define SPACE 258
+#define LETTER 259
+#define NEWLINE 260
+#define COMMENT 261
+#define COLON 262
+#define ANY 263
+#define ZONESTR 264
+#define STRING_ARG 265
+#define VAR_SERVER 266
+#define VAR_VERBOSITY 267
+#define VAR_NUM_THREADS 268
+#define VAR_PORT 269
+#define VAR_OUTGOING_RANGE 270
+#define VAR_INTERFACE 271
+#define VAR_DO_IP4 272
+#define VAR_DO_IP6 273
+#define VAR_DO_UDP 274
+#define VAR_DO_TCP 275
+#define VAR_CHROOT 276
+#define VAR_USERNAME 277
+#define VAR_DIRECTORY 278
+#define VAR_LOGFILE 279
+#define VAR_PIDFILE 280
+#define VAR_MSG_CACHE_SIZE 281
+#define VAR_MSG_CACHE_SLABS 282
+#define VAR_NUM_QUERIES_PER_THREAD 283
+#define VAR_RRSET_CACHE_SIZE 284
+#define VAR_RRSET_CACHE_SLABS 285
+#define VAR_OUTGOING_NUM_TCP 286
+#define VAR_INFRA_HOST_TTL 287
+#define VAR_INFRA_LAME_TTL 288
+#define VAR_INFRA_CACHE_SLABS 289
+#define VAR_INFRA_CACHE_NUMHOSTS 290
+#define VAR_INFRA_CACHE_LAME_SIZE 291
+#define VAR_NAME 292
+#define VAR_STUB_ZONE 293
+#define VAR_STUB_HOST 294
+#define VAR_STUB_ADDR 295
+#define VAR_TARGET_FETCH_POLICY 296
+#define VAR_HARDEN_SHORT_BUFSIZE 297
+#define VAR_HARDEN_LARGE_QUERIES 298
+#define VAR_FORWARD_ZONE 299
+#define VAR_FORWARD_HOST 300
+#define VAR_FORWARD_ADDR 301
+#define VAR_DO_NOT_QUERY_ADDRESS 302
+#define VAR_HIDE_IDENTITY 303
+#define VAR_HIDE_VERSION 304
+#define VAR_IDENTITY 305
+#define VAR_VERSION 306
+#define VAR_HARDEN_GLUE 307
+#define VAR_MODULE_CONF 308
+#define VAR_TRUST_ANCHOR_FILE 309
+#define VAR_TRUST_ANCHOR 310
+#define VAR_VAL_OVERRIDE_DATE 311
+#define VAR_BOGUS_TTL 312
+#define VAR_VAL_CLEAN_ADDITIONAL 313
+#define VAR_VAL_PERMISSIVE_MODE 314
+#define VAR_INCOMING_NUM_TCP 315
+#define VAR_MSG_BUFFER_SIZE 316
+#define VAR_KEY_CACHE_SIZE 317
+#define VAR_KEY_CACHE_SLABS 318
+#define VAR_TRUSTED_KEYS_FILE 319
+#define VAR_VAL_NSEC3_KEYSIZE_ITERATIONS 320
+#define VAR_USE_SYSLOG 321
+#define VAR_OUTGOING_INTERFACE 322
+#define VAR_ROOT_HINTS 323
+#define VAR_DO_NOT_QUERY_LOCALHOST 324
+#define VAR_CACHE_MAX_TTL 325
+#define VAR_HARDEN_DNSSEC_STRIPPED 326
+#define VAR_ACCESS_CONTROL 327
+#define VAR_LOCAL_ZONE 328
+#define VAR_LOCAL_DATA 329
+#define VAR_INTERFACE_AUTOMATIC 330
+#define VAR_STATISTICS_INTERVAL 331
+#define VAR_DO_DAEMONIZE 332
+#define VAR_USE_CAPS_FOR_ID 333
+#define VAR_STATISTICS_CUMULATIVE 334
+#define VAR_OUTGOING_PORT_PERMIT 335
+#define VAR_OUTGOING_PORT_AVOID 336
+#define VAR_DLV_ANCHOR_FILE 337
+#define VAR_DLV_ANCHOR 338
+#define VAR_NEG_CACHE_SIZE 339
+#define VAR_HARDEN_REFERRAL_PATH 340
+#define VAR_PRIVATE_ADDRESS 341
+#define VAR_PRIVATE_DOMAIN 342
+#define VAR_REMOTE_CONTROL 343
+#define VAR_CONTROL_ENABLE 344
+#define VAR_CONTROL_INTERFACE 345
+#define VAR_CONTROL_PORT 346
+#define VAR_SERVER_KEY_FILE 347
+#define VAR_SERVER_CERT_FILE 348
+#define VAR_CONTROL_KEY_FILE 349
+#define VAR_CONTROL_CERT_FILE 350
+#define VAR_EXTENDED_STATISTICS 351
+#define VAR_LOCAL_DATA_PTR 352
+#define VAR_JOSTLE_TIMEOUT 353
+#define VAR_STUB_PRIME 354
+#define VAR_UNWANTED_REPLY_THRESHOLD 355
+#define VAR_LOG_TIME_ASCII 356
+#define VAR_DOMAIN_INSECURE 357
+#define VAR_PYTHON 358
+#define VAR_PYTHON_SCRIPT 359
+#define VAR_VAL_SIG_SKEW_MIN 360
+#define VAR_VAL_SIG_SKEW_MAX 361
+#define VAR_CACHE_MIN_TTL 362
+#define VAR_VAL_LOG_LEVEL 363
+#define VAR_AUTO_TRUST_ANCHOR_FILE 364
+#define VAR_KEEP_MISSING 365
+#define VAR_ADD_HOLDDOWN 366
+#define VAR_DEL_HOLDDOWN 367
+#define VAR_SO_RCVBUF 368
+#define VAR_EDNS_BUFFER_SIZE 369
+#define VAR_PREFETCH 370
+#define VAR_PREFETCH_KEY 371
+#define VAR_SO_SNDBUF 372
+#define VAR_SO_REUSEPORT 373
+#define VAR_HARDEN_BELOW_NXDOMAIN 374
+#define VAR_IGNORE_CD_FLAG 375
+#define VAR_LOG_QUERIES 376
+#define VAR_TCP_UPSTREAM 377
+#define VAR_SSL_UPSTREAM 378
+#define VAR_SSL_SERVICE_KEY 379
+#define VAR_SSL_SERVICE_PEM 380
+#define VAR_SSL_PORT 381
+#define VAR_FORWARD_FIRST 382
+#define VAR_STUB_FIRST 383
+#define VAR_MINIMAL_RESPONSES 384
+#define VAR_RRSET_ROUNDROBIN 385
+#define VAR_MAX_UDP_SIZE 386
+#define VAR_DELAY_CLOSE 387
+#define VAR_UNBLOCK_LAN_ZONES 388
+#define VAR_DNS64_PREFIX 389
+#define VAR_DNS64_SYNTHALL 390
+#define VAR_DNSTAP 391
+#define VAR_DNSTAP_ENABLE 392
+#define VAR_DNSTAP_SOCKET_PATH 393
+#define VAR_DNSTAP_SEND_IDENTITY 394
+#define VAR_DNSTAP_SEND_VERSION 395
+#define VAR_DNSTAP_IDENTITY 396
+#define VAR_DNSTAP_VERSION 397
+#define VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES 398
+#define VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES 399
+#define VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES 400
+#define VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES 401
+#define VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES 402
+#define VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES 403
+
+
+
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef union YYSTYPE
+{
+/* Line 2049 of yacc.c */
+#line 64 "./util/configparser.y"
+
+ char* str;
+
+
+/* Line 2049 of yacc.c */
+#line 358 "util/configparser.h"
+} YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define yystype YYSTYPE /* obsolescent; will be withdrawn */
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+extern YYSTYPE yylval;
+
+#ifdef YYPARSE_PARAM
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void *YYPARSE_PARAM);
+#else
+int yyparse ();
+#endif
+#else /* ! YYPARSE_PARAM */
+#if defined __STDC__ || defined __cplusplus
+int yyparse (void);
+#else
+int yyparse ();
+#endif
+#endif /* ! YYPARSE_PARAM */
+
+#endif /* !YY_UTIL_CONFIGPARSER_H */
diff --git a/external/unbound/util/configparser.y b/external/unbound/util/configparser.y
new file mode 100644
index 000000000..7a92d9ee7
--- /dev/null
+++ b/external/unbound/util/configparser.y
@@ -0,0 +1,1462 @@
+/*
+ * configparser.y -- yacc grammar for unbound configuration files
+ *
+ * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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.
+ */
+
+%{
+#include "config.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "util/configyyrename.h"
+#include "util/config_file.h"
+#include "util/net_help.h"
+
+int ub_c_lex(void);
+void ub_c_error(const char *message);
+
+/* these need to be global, otherwise they cannot be used inside yacc */
+extern struct config_parser_state* cfg_parser;
+
+#if 0
+#define OUTYY(s) printf s /* used ONLY when debugging */
+#else
+#define OUTYY(s)
+#endif
+
+%}
+%union {
+ char* str;
+};
+
+%token SPACE LETTER NEWLINE COMMENT COLON ANY ZONESTR
+%token <str> STRING_ARG
+%token VAR_SERVER VAR_VERBOSITY VAR_NUM_THREADS VAR_PORT
+%token VAR_OUTGOING_RANGE VAR_INTERFACE
+%token VAR_DO_IP4 VAR_DO_IP6 VAR_DO_UDP VAR_DO_TCP
+%token VAR_CHROOT VAR_USERNAME VAR_DIRECTORY VAR_LOGFILE VAR_PIDFILE
+%token VAR_MSG_CACHE_SIZE VAR_MSG_CACHE_SLABS VAR_NUM_QUERIES_PER_THREAD
+%token VAR_RRSET_CACHE_SIZE VAR_RRSET_CACHE_SLABS VAR_OUTGOING_NUM_TCP
+%token VAR_INFRA_HOST_TTL VAR_INFRA_LAME_TTL VAR_INFRA_CACHE_SLABS
+%token VAR_INFRA_CACHE_NUMHOSTS VAR_INFRA_CACHE_LAME_SIZE VAR_NAME
+%token VAR_STUB_ZONE VAR_STUB_HOST VAR_STUB_ADDR VAR_TARGET_FETCH_POLICY
+%token VAR_HARDEN_SHORT_BUFSIZE VAR_HARDEN_LARGE_QUERIES
+%token VAR_FORWARD_ZONE VAR_FORWARD_HOST VAR_FORWARD_ADDR
+%token VAR_DO_NOT_QUERY_ADDRESS VAR_HIDE_IDENTITY VAR_HIDE_VERSION
+%token VAR_IDENTITY VAR_VERSION VAR_HARDEN_GLUE VAR_MODULE_CONF
+%token VAR_TRUST_ANCHOR_FILE VAR_TRUST_ANCHOR VAR_VAL_OVERRIDE_DATE
+%token VAR_BOGUS_TTL VAR_VAL_CLEAN_ADDITIONAL VAR_VAL_PERMISSIVE_MODE
+%token VAR_INCOMING_NUM_TCP VAR_MSG_BUFFER_SIZE VAR_KEY_CACHE_SIZE
+%token VAR_KEY_CACHE_SLABS VAR_TRUSTED_KEYS_FILE
+%token VAR_VAL_NSEC3_KEYSIZE_ITERATIONS VAR_USE_SYSLOG
+%token VAR_OUTGOING_INTERFACE VAR_ROOT_HINTS VAR_DO_NOT_QUERY_LOCALHOST
+%token VAR_CACHE_MAX_TTL VAR_HARDEN_DNSSEC_STRIPPED VAR_ACCESS_CONTROL
+%token VAR_LOCAL_ZONE VAR_LOCAL_DATA VAR_INTERFACE_AUTOMATIC
+%token VAR_STATISTICS_INTERVAL VAR_DO_DAEMONIZE VAR_USE_CAPS_FOR_ID
+%token VAR_STATISTICS_CUMULATIVE VAR_OUTGOING_PORT_PERMIT
+%token VAR_OUTGOING_PORT_AVOID VAR_DLV_ANCHOR_FILE VAR_DLV_ANCHOR
+%token VAR_NEG_CACHE_SIZE VAR_HARDEN_REFERRAL_PATH VAR_PRIVATE_ADDRESS
+%token VAR_PRIVATE_DOMAIN VAR_REMOTE_CONTROL VAR_CONTROL_ENABLE
+%token VAR_CONTROL_INTERFACE VAR_CONTROL_PORT VAR_SERVER_KEY_FILE
+%token VAR_SERVER_CERT_FILE VAR_CONTROL_KEY_FILE VAR_CONTROL_CERT_FILE
+%token VAR_EXTENDED_STATISTICS VAR_LOCAL_DATA_PTR VAR_JOSTLE_TIMEOUT
+%token VAR_STUB_PRIME VAR_UNWANTED_REPLY_THRESHOLD VAR_LOG_TIME_ASCII
+%token VAR_DOMAIN_INSECURE VAR_PYTHON VAR_PYTHON_SCRIPT VAR_VAL_SIG_SKEW_MIN
+%token VAR_VAL_SIG_SKEW_MAX VAR_CACHE_MIN_TTL VAR_VAL_LOG_LEVEL
+%token VAR_AUTO_TRUST_ANCHOR_FILE VAR_KEEP_MISSING VAR_ADD_HOLDDOWN
+%token VAR_DEL_HOLDDOWN VAR_SO_RCVBUF VAR_EDNS_BUFFER_SIZE VAR_PREFETCH
+%token VAR_PREFETCH_KEY VAR_SO_SNDBUF VAR_SO_REUSEPORT VAR_HARDEN_BELOW_NXDOMAIN
+%token VAR_IGNORE_CD_FLAG VAR_LOG_QUERIES VAR_TCP_UPSTREAM VAR_SSL_UPSTREAM
+%token VAR_SSL_SERVICE_KEY VAR_SSL_SERVICE_PEM VAR_SSL_PORT VAR_FORWARD_FIRST
+%token VAR_STUB_FIRST VAR_MINIMAL_RESPONSES VAR_RRSET_ROUNDROBIN
+%token VAR_MAX_UDP_SIZE VAR_DELAY_CLOSE VAR_UNBLOCK_LAN_ZONES
+%token VAR_DNS64_PREFIX VAR_DNS64_SYNTHALL
+%token VAR_DNSTAP VAR_DNSTAP_ENABLE VAR_DNSTAP_SOCKET_PATH
+%token VAR_DNSTAP_SEND_IDENTITY VAR_DNSTAP_SEND_VERSION
+%token VAR_DNSTAP_IDENTITY VAR_DNSTAP_VERSION
+%token VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES
+%token VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES
+%token VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES
+%token VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES
+%token VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES
+%token VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES
+
+%%
+toplevelvars: /* empty */ | toplevelvars toplevelvar ;
+toplevelvar: serverstart contents_server | stubstart contents_stub |
+ forwardstart contents_forward | pythonstart contents_py |
+ rcstart contents_rc | dtstart contents_dt
+ ;
+
+/* server: declaration */
+serverstart: VAR_SERVER
+ {
+ OUTYY(("\nP(server:)\n"));
+ }
+ ;
+contents_server: contents_server content_server
+ | ;
+content_server: server_num_threads | server_verbosity | server_port |
+ server_outgoing_range | server_do_ip4 |
+ server_do_ip6 | server_do_udp | server_do_tcp |
+ server_interface | server_chroot | server_username |
+ server_directory | server_logfile | server_pidfile |
+ server_msg_cache_size | server_msg_cache_slabs |
+ server_num_queries_per_thread | server_rrset_cache_size |
+ server_rrset_cache_slabs | server_outgoing_num_tcp |
+ server_infra_host_ttl | server_infra_lame_ttl |
+ server_infra_cache_slabs | server_infra_cache_numhosts |
+ server_infra_cache_lame_size | server_target_fetch_policy |
+ server_harden_short_bufsize | server_harden_large_queries |
+ server_do_not_query_address | server_hide_identity |
+ server_hide_version | server_identity | server_version |
+ server_harden_glue | server_module_conf | server_trust_anchor_file |
+ server_trust_anchor | server_val_override_date | server_bogus_ttl |
+ server_val_clean_additional | server_val_permissive_mode |
+ server_incoming_num_tcp | server_msg_buffer_size |
+ server_key_cache_size | server_key_cache_slabs |
+ server_trusted_keys_file | server_val_nsec3_keysize_iterations |
+ server_use_syslog | server_outgoing_interface | server_root_hints |
+ server_do_not_query_localhost | server_cache_max_ttl |
+ server_harden_dnssec_stripped | server_access_control |
+ server_local_zone | server_local_data | server_interface_automatic |
+ server_statistics_interval | server_do_daemonize |
+ server_use_caps_for_id | server_statistics_cumulative |
+ server_outgoing_port_permit | server_outgoing_port_avoid |
+ server_dlv_anchor_file | server_dlv_anchor | server_neg_cache_size |
+ server_harden_referral_path | server_private_address |
+ server_private_domain | server_extended_statistics |
+ server_local_data_ptr | server_jostle_timeout |
+ server_unwanted_reply_threshold | server_log_time_ascii |
+ server_domain_insecure | server_val_sig_skew_min |
+ server_val_sig_skew_max | server_cache_min_ttl | server_val_log_level |
+ server_auto_trust_anchor_file | server_add_holddown |
+ server_del_holddown | server_keep_missing | server_so_rcvbuf |
+ server_edns_buffer_size | server_prefetch | server_prefetch_key |
+ server_so_sndbuf | server_harden_below_nxdomain | server_ignore_cd_flag |
+ server_log_queries | server_tcp_upstream | server_ssl_upstream |
+ server_ssl_service_key | server_ssl_service_pem | server_ssl_port |
+ server_minimal_responses | server_rrset_roundrobin | server_max_udp_size |
+ server_so_reuseport | server_delay_close | server_unblock_lan_zones |
+ server_dns64_prefix | server_dns64_synthall
+ ;
+stubstart: VAR_STUB_ZONE
+ {
+ struct config_stub* s;
+ OUTYY(("\nP(stub_zone:)\n"));
+ s = (struct config_stub*)calloc(1, sizeof(struct config_stub));
+ if(s) {
+ s->next = cfg_parser->cfg->stubs;
+ cfg_parser->cfg->stubs = s;
+ } else
+ yyerror("out of memory");
+ }
+ ;
+contents_stub: contents_stub content_stub
+ | ;
+content_stub: stub_name | stub_host | stub_addr | stub_prime | stub_first
+ ;
+forwardstart: VAR_FORWARD_ZONE
+ {
+ struct config_stub* s;
+ OUTYY(("\nP(forward_zone:)\n"));
+ s = (struct config_stub*)calloc(1, sizeof(struct config_stub));
+ if(s) {
+ s->next = cfg_parser->cfg->forwards;
+ cfg_parser->cfg->forwards = s;
+ } else
+ yyerror("out of memory");
+ }
+ ;
+contents_forward: contents_forward content_forward
+ | ;
+content_forward: forward_name | forward_host | forward_addr | forward_first
+ ;
+server_num_threads: VAR_NUM_THREADS STRING_ARG
+ {
+ OUTYY(("P(server_num_threads:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->num_threads = atoi($2);
+ free($2);
+ }
+ ;
+server_verbosity: VAR_VERBOSITY STRING_ARG
+ {
+ OUTYY(("P(server_verbosity:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->verbosity = atoi($2);
+ free($2);
+ }
+ ;
+server_statistics_interval: VAR_STATISTICS_INTERVAL STRING_ARG
+ {
+ OUTYY(("P(server_statistics_interval:%s)\n", $2));
+ if(strcmp($2, "") == 0 || strcmp($2, "0") == 0)
+ cfg_parser->cfg->stat_interval = 0;
+ else if(atoi($2) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->stat_interval = atoi($2);
+ free($2);
+ }
+ ;
+server_statistics_cumulative: VAR_STATISTICS_CUMULATIVE STRING_ARG
+ {
+ OUTYY(("P(server_statistics_cumulative:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->stat_cumulative = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_extended_statistics: VAR_EXTENDED_STATISTICS STRING_ARG
+ {
+ OUTYY(("P(server_extended_statistics:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->stat_extended = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_port: VAR_PORT STRING_ARG
+ {
+ OUTYY(("P(server_port:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("port number expected");
+ else cfg_parser->cfg->port = atoi($2);
+ free($2);
+ }
+ ;
+server_interface: VAR_INTERFACE STRING_ARG
+ {
+ OUTYY(("P(server_interface:%s)\n", $2));
+ if(cfg_parser->cfg->num_ifs == 0)
+ cfg_parser->cfg->ifs = calloc(1, sizeof(char*));
+ else cfg_parser->cfg->ifs = realloc(cfg_parser->cfg->ifs,
+ (cfg_parser->cfg->num_ifs+1)*sizeof(char*));
+ if(!cfg_parser->cfg->ifs)
+ yyerror("out of memory");
+ else
+ cfg_parser->cfg->ifs[cfg_parser->cfg->num_ifs++] = $2;
+ }
+ ;
+server_outgoing_interface: VAR_OUTGOING_INTERFACE STRING_ARG
+ {
+ OUTYY(("P(server_outgoing_interface:%s)\n", $2));
+ if(cfg_parser->cfg->num_out_ifs == 0)
+ cfg_parser->cfg->out_ifs = calloc(1, sizeof(char*));
+ else cfg_parser->cfg->out_ifs = realloc(
+ cfg_parser->cfg->out_ifs,
+ (cfg_parser->cfg->num_out_ifs+1)*sizeof(char*));
+ if(!cfg_parser->cfg->out_ifs)
+ yyerror("out of memory");
+ else
+ cfg_parser->cfg->out_ifs[
+ cfg_parser->cfg->num_out_ifs++] = $2;
+ }
+ ;
+server_outgoing_range: VAR_OUTGOING_RANGE STRING_ARG
+ {
+ OUTYY(("P(server_outgoing_range:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->outgoing_num_ports = atoi($2);
+ free($2);
+ }
+ ;
+server_outgoing_port_permit: VAR_OUTGOING_PORT_PERMIT STRING_ARG
+ {
+ OUTYY(("P(server_outgoing_port_permit:%s)\n", $2));
+ if(!cfg_mark_ports($2, 1,
+ cfg_parser->cfg->outgoing_avail_ports, 65536))
+ yyerror("port number or range (\"low-high\") expected");
+ free($2);
+ }
+ ;
+server_outgoing_port_avoid: VAR_OUTGOING_PORT_AVOID STRING_ARG
+ {
+ OUTYY(("P(server_outgoing_port_avoid:%s)\n", $2));
+ if(!cfg_mark_ports($2, 0,
+ cfg_parser->cfg->outgoing_avail_ports, 65536))
+ yyerror("port number or range (\"low-high\") expected");
+ free($2);
+ }
+ ;
+server_outgoing_num_tcp: VAR_OUTGOING_NUM_TCP STRING_ARG
+ {
+ OUTYY(("P(server_outgoing_num_tcp:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->outgoing_num_tcp = atoi($2);
+ free($2);
+ }
+ ;
+server_incoming_num_tcp: VAR_INCOMING_NUM_TCP STRING_ARG
+ {
+ OUTYY(("P(server_incoming_num_tcp:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->incoming_num_tcp = atoi($2);
+ free($2);
+ }
+ ;
+server_interface_automatic: VAR_INTERFACE_AUTOMATIC STRING_ARG
+ {
+ OUTYY(("P(server_interface_automatic:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->if_automatic = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_do_ip4: VAR_DO_IP4 STRING_ARG
+ {
+ OUTYY(("P(server_do_ip4:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_ip4 = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_do_ip6: VAR_DO_IP6 STRING_ARG
+ {
+ OUTYY(("P(server_do_ip6:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_ip6 = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_do_udp: VAR_DO_UDP STRING_ARG
+ {
+ OUTYY(("P(server_do_udp:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_udp = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_do_tcp: VAR_DO_TCP STRING_ARG
+ {
+ OUTYY(("P(server_do_tcp:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_tcp = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_tcp_upstream: VAR_TCP_UPSTREAM STRING_ARG
+ {
+ OUTYY(("P(server_tcp_upstream:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->tcp_upstream = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_ssl_upstream: VAR_SSL_UPSTREAM STRING_ARG
+ {
+ OUTYY(("P(server_ssl_upstream:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->ssl_upstream = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_ssl_service_key: VAR_SSL_SERVICE_KEY STRING_ARG
+ {
+ OUTYY(("P(server_ssl_service_key:%s)\n", $2));
+ free(cfg_parser->cfg->ssl_service_key);
+ cfg_parser->cfg->ssl_service_key = $2;
+ }
+ ;
+server_ssl_service_pem: VAR_SSL_SERVICE_PEM STRING_ARG
+ {
+ OUTYY(("P(server_ssl_service_pem:%s)\n", $2));
+ free(cfg_parser->cfg->ssl_service_pem);
+ cfg_parser->cfg->ssl_service_pem = $2;
+ }
+ ;
+server_ssl_port: VAR_SSL_PORT STRING_ARG
+ {
+ OUTYY(("P(server_ssl_port:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("port number expected");
+ else cfg_parser->cfg->ssl_port = atoi($2);
+ free($2);
+ }
+ ;
+server_do_daemonize: VAR_DO_DAEMONIZE STRING_ARG
+ {
+ OUTYY(("P(server_do_daemonize:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->do_daemonize = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_use_syslog: VAR_USE_SYSLOG STRING_ARG
+ {
+ OUTYY(("P(server_use_syslog:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->use_syslog = (strcmp($2, "yes")==0);
+#if !defined(HAVE_SYSLOG_H) && !defined(UB_ON_WINDOWS)
+ if(strcmp($2, "yes") == 0)
+ yyerror("no syslog services are available. "
+ "(reconfigure and compile to add)");
+#endif
+ free($2);
+ }
+ ;
+server_log_time_ascii: VAR_LOG_TIME_ASCII STRING_ARG
+ {
+ OUTYY(("P(server_log_time_ascii:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->log_time_ascii = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_log_queries: VAR_LOG_QUERIES STRING_ARG
+ {
+ OUTYY(("P(server_log_queries:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->log_queries = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_chroot: VAR_CHROOT STRING_ARG
+ {
+ OUTYY(("P(server_chroot:%s)\n", $2));
+ free(cfg_parser->cfg->chrootdir);
+ cfg_parser->cfg->chrootdir = $2;
+ }
+ ;
+server_username: VAR_USERNAME STRING_ARG
+ {
+ OUTYY(("P(server_username:%s)\n", $2));
+ free(cfg_parser->cfg->username);
+ cfg_parser->cfg->username = $2;
+ }
+ ;
+server_directory: VAR_DIRECTORY STRING_ARG
+ {
+ OUTYY(("P(server_directory:%s)\n", $2));
+ free(cfg_parser->cfg->directory);
+ cfg_parser->cfg->directory = $2;
+ }
+ ;
+server_logfile: VAR_LOGFILE STRING_ARG
+ {
+ OUTYY(("P(server_logfile:%s)\n", $2));
+ free(cfg_parser->cfg->logfile);
+ cfg_parser->cfg->logfile = $2;
+ cfg_parser->cfg->use_syslog = 0;
+ }
+ ;
+server_pidfile: VAR_PIDFILE STRING_ARG
+ {
+ OUTYY(("P(server_pidfile:%s)\n", $2));
+ free(cfg_parser->cfg->pidfile);
+ cfg_parser->cfg->pidfile = $2;
+ }
+ ;
+server_root_hints: VAR_ROOT_HINTS STRING_ARG
+ {
+ OUTYY(("P(server_root_hints:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->root_hints, $2))
+ yyerror("out of memory");
+ }
+ ;
+server_dlv_anchor_file: VAR_DLV_ANCHOR_FILE STRING_ARG
+ {
+ OUTYY(("P(server_dlv_anchor_file:%s)\n", $2));
+ free(cfg_parser->cfg->dlv_anchor_file);
+ cfg_parser->cfg->dlv_anchor_file = $2;
+ }
+ ;
+server_dlv_anchor: VAR_DLV_ANCHOR STRING_ARG
+ {
+ OUTYY(("P(server_dlv_anchor:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->dlv_anchor_list, $2))
+ yyerror("out of memory");
+ }
+ ;
+server_auto_trust_anchor_file: VAR_AUTO_TRUST_ANCHOR_FILE STRING_ARG
+ {
+ OUTYY(("P(server_auto_trust_anchor_file:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ auto_trust_anchor_file_list, $2))
+ yyerror("out of memory");
+ }
+ ;
+server_trust_anchor_file: VAR_TRUST_ANCHOR_FILE STRING_ARG
+ {
+ OUTYY(("P(server_trust_anchor_file:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ trust_anchor_file_list, $2))
+ yyerror("out of memory");
+ }
+ ;
+server_trusted_keys_file: VAR_TRUSTED_KEYS_FILE STRING_ARG
+ {
+ OUTYY(("P(server_trusted_keys_file:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ trusted_keys_file_list, $2))
+ yyerror("out of memory");
+ }
+ ;
+server_trust_anchor: VAR_TRUST_ANCHOR STRING_ARG
+ {
+ OUTYY(("P(server_trust_anchor:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->trust_anchor_list, $2))
+ yyerror("out of memory");
+ }
+ ;
+server_domain_insecure: VAR_DOMAIN_INSECURE STRING_ARG
+ {
+ OUTYY(("P(server_domain_insecure:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->domain_insecure, $2))
+ yyerror("out of memory");
+ }
+ ;
+server_hide_identity: VAR_HIDE_IDENTITY STRING_ARG
+ {
+ OUTYY(("P(server_hide_identity:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->hide_identity = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_hide_version: VAR_HIDE_VERSION STRING_ARG
+ {
+ OUTYY(("P(server_hide_version:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->hide_version = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_identity: VAR_IDENTITY STRING_ARG
+ {
+ OUTYY(("P(server_identity:%s)\n", $2));
+ free(cfg_parser->cfg->identity);
+ cfg_parser->cfg->identity = $2;
+ }
+ ;
+server_version: VAR_VERSION STRING_ARG
+ {
+ OUTYY(("P(server_version:%s)\n", $2));
+ free(cfg_parser->cfg->version);
+ cfg_parser->cfg->version = $2;
+ }
+ ;
+server_so_rcvbuf: VAR_SO_RCVBUF STRING_ARG
+ {
+ OUTYY(("P(server_so_rcvbuf:%s)\n", $2));
+ if(!cfg_parse_memsize($2, &cfg_parser->cfg->so_rcvbuf))
+ yyerror("buffer size expected");
+ free($2);
+ }
+ ;
+server_so_sndbuf: VAR_SO_SNDBUF STRING_ARG
+ {
+ OUTYY(("P(server_so_sndbuf:%s)\n", $2));
+ if(!cfg_parse_memsize($2, &cfg_parser->cfg->so_sndbuf))
+ yyerror("buffer size expected");
+ free($2);
+ }
+ ;
+server_so_reuseport: VAR_SO_REUSEPORT STRING_ARG
+ {
+ OUTYY(("P(server_so_reuseport:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->so_reuseport =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_edns_buffer_size: VAR_EDNS_BUFFER_SIZE STRING_ARG
+ {
+ OUTYY(("P(server_edns_buffer_size:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else if (atoi($2) < 12)
+ yyerror("edns buffer size too small");
+ else if (atoi($2) > 65535)
+ cfg_parser->cfg->edns_buffer_size = 65535;
+ else cfg_parser->cfg->edns_buffer_size = atoi($2);
+ free($2);
+ }
+ ;
+server_msg_buffer_size: VAR_MSG_BUFFER_SIZE STRING_ARG
+ {
+ OUTYY(("P(server_msg_buffer_size:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else if (atoi($2) < 4096)
+ yyerror("message buffer size too small (use 4096)");
+ else cfg_parser->cfg->msg_buffer_size = atoi($2);
+ free($2);
+ }
+ ;
+server_msg_cache_size: VAR_MSG_CACHE_SIZE STRING_ARG
+ {
+ OUTYY(("P(server_msg_cache_size:%s)\n", $2));
+ if(!cfg_parse_memsize($2, &cfg_parser->cfg->msg_cache_size))
+ yyerror("memory size expected");
+ free($2);
+ }
+ ;
+server_msg_cache_slabs: VAR_MSG_CACHE_SLABS STRING_ARG
+ {
+ OUTYY(("P(server_msg_cache_slabs:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->cfg->msg_cache_slabs = atoi($2);
+ if(!is_pow2(cfg_parser->cfg->msg_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free($2);
+ }
+ ;
+server_num_queries_per_thread: VAR_NUM_QUERIES_PER_THREAD STRING_ARG
+ {
+ OUTYY(("P(server_num_queries_per_thread:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->num_queries_per_thread = atoi($2);
+ free($2);
+ }
+ ;
+server_jostle_timeout: VAR_JOSTLE_TIMEOUT STRING_ARG
+ {
+ OUTYY(("P(server_jostle_timeout:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->jostle_time = atoi($2);
+ free($2);
+ }
+ ;
+server_delay_close: VAR_DELAY_CLOSE STRING_ARG
+ {
+ OUTYY(("P(server_delay_close:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->delay_close = atoi($2);
+ free($2);
+ }
+ ;
+server_unblock_lan_zones: VAR_UNBLOCK_LAN_ZONES STRING_ARG
+ {
+ OUTYY(("P(server_unblock_lan_zones:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->unblock_lan_zones =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_rrset_cache_size: VAR_RRSET_CACHE_SIZE STRING_ARG
+ {
+ OUTYY(("P(server_rrset_cache_size:%s)\n", $2));
+ if(!cfg_parse_memsize($2, &cfg_parser->cfg->rrset_cache_size))
+ yyerror("memory size expected");
+ free($2);
+ }
+ ;
+server_rrset_cache_slabs: VAR_RRSET_CACHE_SLABS STRING_ARG
+ {
+ OUTYY(("P(server_rrset_cache_slabs:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->cfg->rrset_cache_slabs = atoi($2);
+ if(!is_pow2(cfg_parser->cfg->rrset_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free($2);
+ }
+ ;
+server_infra_host_ttl: VAR_INFRA_HOST_TTL STRING_ARG
+ {
+ OUTYY(("P(server_infra_host_ttl:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->host_ttl = atoi($2);
+ free($2);
+ }
+ ;
+server_infra_lame_ttl: VAR_INFRA_LAME_TTL STRING_ARG
+ {
+ OUTYY(("P(server_infra_lame_ttl:%s)\n", $2));
+ verbose(VERB_DETAIL, "ignored infra-lame-ttl: %s (option "
+ "removed, use infra-host-ttl)", $2);
+ free($2);
+ }
+ ;
+server_infra_cache_numhosts: VAR_INFRA_CACHE_NUMHOSTS STRING_ARG
+ {
+ OUTYY(("P(server_infra_cache_numhosts:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->infra_cache_numhosts = atoi($2);
+ free($2);
+ }
+ ;
+server_infra_cache_lame_size: VAR_INFRA_CACHE_LAME_SIZE STRING_ARG
+ {
+ OUTYY(("P(server_infra_cache_lame_size:%s)\n", $2));
+ verbose(VERB_DETAIL, "ignored infra-cache-lame-size: %s "
+ "(option removed, use infra-cache-numhosts)", $2);
+ free($2);
+ }
+ ;
+server_infra_cache_slabs: VAR_INFRA_CACHE_SLABS STRING_ARG
+ {
+ OUTYY(("P(server_infra_cache_slabs:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->cfg->infra_cache_slabs = atoi($2);
+ if(!is_pow2(cfg_parser->cfg->infra_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free($2);
+ }
+ ;
+server_target_fetch_policy: VAR_TARGET_FETCH_POLICY STRING_ARG
+ {
+ OUTYY(("P(server_target_fetch_policy:%s)\n", $2));
+ free(cfg_parser->cfg->target_fetch_policy);
+ cfg_parser->cfg->target_fetch_policy = $2;
+ }
+ ;
+server_harden_short_bufsize: VAR_HARDEN_SHORT_BUFSIZE STRING_ARG
+ {
+ OUTYY(("P(server_harden_short_bufsize:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_short_bufsize =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_harden_large_queries: VAR_HARDEN_LARGE_QUERIES STRING_ARG
+ {
+ OUTYY(("P(server_harden_large_queries:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_large_queries =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_harden_glue: VAR_HARDEN_GLUE STRING_ARG
+ {
+ OUTYY(("P(server_harden_glue:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_glue =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_harden_dnssec_stripped: VAR_HARDEN_DNSSEC_STRIPPED STRING_ARG
+ {
+ OUTYY(("P(server_harden_dnssec_stripped:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_dnssec_stripped =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_harden_below_nxdomain: VAR_HARDEN_BELOW_NXDOMAIN STRING_ARG
+ {
+ OUTYY(("P(server_harden_below_nxdomain:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_below_nxdomain =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_harden_referral_path: VAR_HARDEN_REFERRAL_PATH STRING_ARG
+ {
+ OUTYY(("P(server_harden_referral_path:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->harden_referral_path =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_use_caps_for_id: VAR_USE_CAPS_FOR_ID STRING_ARG
+ {
+ OUTYY(("P(server_use_caps_for_id:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->use_caps_bits_for_id =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_private_address: VAR_PRIVATE_ADDRESS STRING_ARG
+ {
+ OUTYY(("P(server_private_address:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->private_address, $2))
+ yyerror("out of memory");
+ }
+ ;
+server_private_domain: VAR_PRIVATE_DOMAIN STRING_ARG
+ {
+ OUTYY(("P(server_private_domain:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->private_domain, $2))
+ yyerror("out of memory");
+ }
+ ;
+server_prefetch: VAR_PREFETCH STRING_ARG
+ {
+ OUTYY(("P(server_prefetch:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->prefetch = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_prefetch_key: VAR_PREFETCH_KEY STRING_ARG
+ {
+ OUTYY(("P(server_prefetch_key:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->prefetch_key = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_unwanted_reply_threshold: VAR_UNWANTED_REPLY_THRESHOLD STRING_ARG
+ {
+ OUTYY(("P(server_unwanted_reply_threshold:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->unwanted_threshold = atoi($2);
+ free($2);
+ }
+ ;
+server_do_not_query_address: VAR_DO_NOT_QUERY_ADDRESS STRING_ARG
+ {
+ OUTYY(("P(server_do_not_query_address:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->donotqueryaddrs, $2))
+ yyerror("out of memory");
+ }
+ ;
+server_do_not_query_localhost: VAR_DO_NOT_QUERY_LOCALHOST STRING_ARG
+ {
+ OUTYY(("P(server_do_not_query_localhost:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->donotquery_localhost =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_access_control: VAR_ACCESS_CONTROL STRING_ARG STRING_ARG
+ {
+ OUTYY(("P(server_access_control:%s %s)\n", $2, $3));
+ if(strcmp($3, "deny")!=0 && strcmp($3, "refuse")!=0 &&
+ strcmp($3, "deny_non_local")!=0 &&
+ strcmp($3, "refuse_non_local")!=0 &&
+ strcmp($3, "allow")!=0 &&
+ strcmp($3, "allow_snoop")!=0) {
+ yyerror("expected deny, refuse, deny_non_local, "
+ "refuse_non_local, allow or allow_snoop "
+ "in access control action");
+ } else {
+ if(!cfg_str2list_insert(&cfg_parser->cfg->acls, $2, $3))
+ fatal_exit("out of memory adding acl");
+ }
+ }
+ ;
+server_module_conf: VAR_MODULE_CONF STRING_ARG
+ {
+ OUTYY(("P(server_module_conf:%s)\n", $2));
+ free(cfg_parser->cfg->module_conf);
+ cfg_parser->cfg->module_conf = $2;
+ }
+ ;
+server_val_override_date: VAR_VAL_OVERRIDE_DATE STRING_ARG
+ {
+ OUTYY(("P(server_val_override_date:%s)\n", $2));
+ if(strlen($2) == 0 || strcmp($2, "0") == 0) {
+ cfg_parser->cfg->val_date_override = 0;
+ } else if(strlen($2) == 14) {
+ cfg_parser->cfg->val_date_override =
+ cfg_convert_timeval($2);
+ if(!cfg_parser->cfg->val_date_override)
+ yyerror("bad date/time specification");
+ } else {
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ cfg_parser->cfg->val_date_override = atoi($2);
+ }
+ free($2);
+ }
+ ;
+server_val_sig_skew_min: VAR_VAL_SIG_SKEW_MIN STRING_ARG
+ {
+ OUTYY(("P(server_val_sig_skew_min:%s)\n", $2));
+ if(strlen($2) == 0 || strcmp($2, "0") == 0) {
+ cfg_parser->cfg->val_sig_skew_min = 0;
+ } else {
+ cfg_parser->cfg->val_sig_skew_min = atoi($2);
+ if(!cfg_parser->cfg->val_sig_skew_min)
+ yyerror("number expected");
+ }
+ free($2);
+ }
+ ;
+server_val_sig_skew_max: VAR_VAL_SIG_SKEW_MAX STRING_ARG
+ {
+ OUTYY(("P(server_val_sig_skew_max:%s)\n", $2));
+ if(strlen($2) == 0 || strcmp($2, "0") == 0) {
+ cfg_parser->cfg->val_sig_skew_max = 0;
+ } else {
+ cfg_parser->cfg->val_sig_skew_max = atoi($2);
+ if(!cfg_parser->cfg->val_sig_skew_max)
+ yyerror("number expected");
+ }
+ free($2);
+ }
+ ;
+server_cache_max_ttl: VAR_CACHE_MAX_TTL STRING_ARG
+ {
+ OUTYY(("P(server_cache_max_ttl:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->max_ttl = atoi($2);
+ free($2);
+ }
+ ;
+server_cache_min_ttl: VAR_CACHE_MIN_TTL STRING_ARG
+ {
+ OUTYY(("P(server_cache_min_ttl:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->min_ttl = atoi($2);
+ free($2);
+ }
+ ;
+server_bogus_ttl: VAR_BOGUS_TTL STRING_ARG
+ {
+ OUTYY(("P(server_bogus_ttl:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->bogus_ttl = atoi($2);
+ free($2);
+ }
+ ;
+server_val_clean_additional: VAR_VAL_CLEAN_ADDITIONAL STRING_ARG
+ {
+ OUTYY(("P(server_val_clean_additional:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->val_clean_additional =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_val_permissive_mode: VAR_VAL_PERMISSIVE_MODE STRING_ARG
+ {
+ OUTYY(("P(server_val_permissive_mode:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->val_permissive_mode =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_ignore_cd_flag: VAR_IGNORE_CD_FLAG STRING_ARG
+ {
+ OUTYY(("P(server_ignore_cd_flag:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->ignore_cd = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_val_log_level: VAR_VAL_LOG_LEVEL STRING_ARG
+ {
+ OUTYY(("P(server_val_log_level:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->val_log_level = atoi($2);
+ free($2);
+ }
+ ;
+server_val_nsec3_keysize_iterations: VAR_VAL_NSEC3_KEYSIZE_ITERATIONS STRING_ARG
+ {
+ OUTYY(("P(server_val_nsec3_keysize_iterations:%s)\n", $2));
+ free(cfg_parser->cfg->val_nsec3_key_iterations);
+ cfg_parser->cfg->val_nsec3_key_iterations = $2;
+ }
+ ;
+server_add_holddown: VAR_ADD_HOLDDOWN STRING_ARG
+ {
+ OUTYY(("P(server_add_holddown:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->add_holddown = atoi($2);
+ free($2);
+ }
+ ;
+server_del_holddown: VAR_DEL_HOLDDOWN STRING_ARG
+ {
+ OUTYY(("P(server_del_holddown:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->del_holddown = atoi($2);
+ free($2);
+ }
+ ;
+server_keep_missing: VAR_KEEP_MISSING STRING_ARG
+ {
+ OUTYY(("P(server_keep_missing:%s)\n", $2));
+ if(atoi($2) == 0 && strcmp($2, "0") != 0)
+ yyerror("number expected");
+ else cfg_parser->cfg->keep_missing = atoi($2);
+ free($2);
+ }
+ ;
+server_key_cache_size: VAR_KEY_CACHE_SIZE STRING_ARG
+ {
+ OUTYY(("P(server_key_cache_size:%s)\n", $2));
+ if(!cfg_parse_memsize($2, &cfg_parser->cfg->key_cache_size))
+ yyerror("memory size expected");
+ free($2);
+ }
+ ;
+server_key_cache_slabs: VAR_KEY_CACHE_SLABS STRING_ARG
+ {
+ OUTYY(("P(server_key_cache_slabs:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("number expected");
+ else {
+ cfg_parser->cfg->key_cache_slabs = atoi($2);
+ if(!is_pow2(cfg_parser->cfg->key_cache_slabs))
+ yyerror("must be a power of 2");
+ }
+ free($2);
+ }
+ ;
+server_neg_cache_size: VAR_NEG_CACHE_SIZE STRING_ARG
+ {
+ OUTYY(("P(server_neg_cache_size:%s)\n", $2));
+ if(!cfg_parse_memsize($2, &cfg_parser->cfg->neg_cache_size))
+ yyerror("memory size expected");
+ free($2);
+ }
+ ;
+server_local_zone: VAR_LOCAL_ZONE STRING_ARG STRING_ARG
+ {
+ OUTYY(("P(server_local_zone:%s %s)\n", $2, $3));
+ if(strcmp($3, "static")!=0 && strcmp($3, "deny")!=0 &&
+ strcmp($3, "refuse")!=0 && strcmp($3, "redirect")!=0 &&
+ strcmp($3, "transparent")!=0 && strcmp($3, "nodefault")!=0
+ && strcmp($3, "typetransparent")!=0)
+ yyerror("local-zone type: expected static, deny, "
+ "refuse, redirect, transparent, "
+ "typetransparent or nodefault");
+ else if(strcmp($3, "nodefault")==0) {
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ local_zones_nodefault, $2))
+ fatal_exit("out of memory adding local-zone");
+ free($3);
+ } else {
+ if(!cfg_str2list_insert(&cfg_parser->cfg->local_zones,
+ $2, $3))
+ fatal_exit("out of memory adding local-zone");
+ }
+ }
+ ;
+server_local_data: VAR_LOCAL_DATA STRING_ARG
+ {
+ OUTYY(("P(server_local_data:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->local_data, $2))
+ fatal_exit("out of memory adding local-data");
+ }
+ ;
+server_local_data_ptr: VAR_LOCAL_DATA_PTR STRING_ARG
+ {
+ char* ptr;
+ OUTYY(("P(server_local_data_ptr:%s)\n", $2));
+ ptr = cfg_ptr_reverse($2);
+ free($2);
+ if(ptr) {
+ if(!cfg_strlist_insert(&cfg_parser->cfg->
+ local_data, ptr))
+ fatal_exit("out of memory adding local-data");
+ } else {
+ yyerror("local-data-ptr could not be reversed");
+ }
+ }
+ ;
+server_minimal_responses: VAR_MINIMAL_RESPONSES STRING_ARG
+ {
+ OUTYY(("P(server_minimal_responses:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->minimal_responses =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_rrset_roundrobin: VAR_RRSET_ROUNDROBIN STRING_ARG
+ {
+ OUTYY(("P(server_rrset_roundrobin:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->rrset_roundrobin =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+server_max_udp_size: VAR_MAX_UDP_SIZE STRING_ARG
+ {
+ OUTYY(("P(server_max_udp_size:%s)\n", $2));
+ cfg_parser->cfg->max_udp_size = atoi($2);
+ free($2);
+ }
+ ;
+server_dns64_prefix: VAR_DNS64_PREFIX STRING_ARG
+ {
+ OUTYY(("P(dns64_prefix:%s)\n", $2));
+ free(cfg_parser->cfg->dns64_prefix);
+ cfg_parser->cfg->dns64_prefix = $2;
+ }
+ ;
+server_dns64_synthall: VAR_DNS64_SYNTHALL STRING_ARG
+ {
+ OUTYY(("P(server_dns64_synthall:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dns64_synthall = (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+stub_name: VAR_NAME STRING_ARG
+ {
+ OUTYY(("P(name:%s)\n", $2));
+ if(cfg_parser->cfg->stubs->name)
+ yyerror("stub name override, there must be one name "
+ "for one stub-zone");
+ free(cfg_parser->cfg->stubs->name);
+ cfg_parser->cfg->stubs->name = $2;
+ }
+ ;
+stub_host: VAR_STUB_HOST STRING_ARG
+ {
+ OUTYY(("P(stub-host:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->stubs->hosts, $2))
+ yyerror("out of memory");
+ }
+ ;
+stub_addr: VAR_STUB_ADDR STRING_ARG
+ {
+ OUTYY(("P(stub-addr:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->stubs->addrs, $2))
+ yyerror("out of memory");
+ }
+ ;
+stub_first: VAR_STUB_FIRST STRING_ARG
+ {
+ OUTYY(("P(stub-first:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->stubs->isfirst=(strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+stub_prime: VAR_STUB_PRIME STRING_ARG
+ {
+ OUTYY(("P(stub-prime:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->stubs->isprime =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+forward_name: VAR_NAME STRING_ARG
+ {
+ OUTYY(("P(name:%s)\n", $2));
+ if(cfg_parser->cfg->forwards->name)
+ yyerror("forward name override, there must be one "
+ "name for one forward-zone");
+ free(cfg_parser->cfg->forwards->name);
+ cfg_parser->cfg->forwards->name = $2;
+ }
+ ;
+forward_host: VAR_FORWARD_HOST STRING_ARG
+ {
+ OUTYY(("P(forward-host:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->forwards->hosts, $2))
+ yyerror("out of memory");
+ }
+ ;
+forward_addr: VAR_FORWARD_ADDR STRING_ARG
+ {
+ OUTYY(("P(forward-addr:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->forwards->addrs, $2))
+ yyerror("out of memory");
+ }
+ ;
+forward_first: VAR_FORWARD_FIRST STRING_ARG
+ {
+ OUTYY(("P(forward-first:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->forwards->isfirst=(strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+rcstart: VAR_REMOTE_CONTROL
+ {
+ OUTYY(("\nP(remote-control:)\n"));
+ }
+ ;
+contents_rc: contents_rc content_rc
+ | ;
+content_rc: rc_control_enable | rc_control_interface | rc_control_port |
+ rc_server_key_file | rc_server_cert_file | rc_control_key_file |
+ rc_control_cert_file
+ ;
+rc_control_enable: VAR_CONTROL_ENABLE STRING_ARG
+ {
+ OUTYY(("P(control_enable:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->remote_control_enable =
+ (strcmp($2, "yes")==0);
+ free($2);
+ }
+ ;
+rc_control_port: VAR_CONTROL_PORT STRING_ARG
+ {
+ OUTYY(("P(control_port:%s)\n", $2));
+ if(atoi($2) == 0)
+ yyerror("control port number expected");
+ else cfg_parser->cfg->control_port = atoi($2);
+ free($2);
+ }
+ ;
+rc_control_interface: VAR_CONTROL_INTERFACE STRING_ARG
+ {
+ OUTYY(("P(control_interface:%s)\n", $2));
+ if(!cfg_strlist_insert(&cfg_parser->cfg->control_ifs, $2))
+ yyerror("out of memory");
+ }
+ ;
+rc_server_key_file: VAR_SERVER_KEY_FILE STRING_ARG
+ {
+ OUTYY(("P(rc_server_key_file:%s)\n", $2));
+ free(cfg_parser->cfg->server_key_file);
+ cfg_parser->cfg->server_key_file = $2;
+ }
+ ;
+rc_server_cert_file: VAR_SERVER_CERT_FILE STRING_ARG
+ {
+ OUTYY(("P(rc_server_cert_file:%s)\n", $2));
+ free(cfg_parser->cfg->server_cert_file);
+ cfg_parser->cfg->server_cert_file = $2;
+ }
+ ;
+rc_control_key_file: VAR_CONTROL_KEY_FILE STRING_ARG
+ {
+ OUTYY(("P(rc_control_key_file:%s)\n", $2));
+ free(cfg_parser->cfg->control_key_file);
+ cfg_parser->cfg->control_key_file = $2;
+ }
+ ;
+rc_control_cert_file: VAR_CONTROL_CERT_FILE STRING_ARG
+ {
+ OUTYY(("P(rc_control_cert_file:%s)\n", $2));
+ free(cfg_parser->cfg->control_cert_file);
+ cfg_parser->cfg->control_cert_file = $2;
+ }
+ ;
+dtstart: VAR_DNSTAP
+ {
+ OUTYY(("\nP(dnstap:)\n"));
+ }
+ ;
+contents_dt: contents_dt content_dt
+ | ;
+content_dt: dt_dnstap_enable | dt_dnstap_socket_path |
+ dt_dnstap_send_identity | dt_dnstap_send_version |
+ dt_dnstap_identity | dt_dnstap_version |
+ dt_dnstap_log_resolver_query_messages |
+ dt_dnstap_log_resolver_response_messages |
+ dt_dnstap_log_client_query_messages |
+ dt_dnstap_log_client_response_messages |
+ dt_dnstap_log_forwarder_query_messages |
+ dt_dnstap_log_forwarder_response_messages
+ ;
+dt_dnstap_enable: VAR_DNSTAP_ENABLE STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_enable:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap = (strcmp($2, "yes")==0);
+ }
+ ;
+dt_dnstap_socket_path: VAR_DNSTAP_SOCKET_PATH STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_socket_path:%s)\n", $2));
+ free(cfg_parser->cfg->dnstap_socket_path);
+ cfg_parser->cfg->dnstap_socket_path = $2;
+ }
+ ;
+dt_dnstap_send_identity: VAR_DNSTAP_SEND_IDENTITY STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_send_identity:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_send_identity = (strcmp($2, "yes")==0);
+ }
+ ;
+dt_dnstap_send_version: VAR_DNSTAP_SEND_VERSION STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_send_version:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_send_version = (strcmp($2, "yes")==0);
+ }
+ ;
+dt_dnstap_identity: VAR_DNSTAP_IDENTITY STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_identity:%s)\n", $2));
+ free(cfg_parser->cfg->dnstap_identity);
+ cfg_parser->cfg->dnstap_identity = $2;
+ }
+ ;
+dt_dnstap_version: VAR_DNSTAP_VERSION STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_version:%s)\n", $2));
+ free(cfg_parser->cfg->dnstap_version);
+ cfg_parser->cfg->dnstap_version = $2;
+ }
+ ;
+dt_dnstap_log_resolver_query_messages: VAR_DNSTAP_LOG_RESOLVER_QUERY_MESSAGES STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_log_resolver_query_messages:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_resolver_query_messages =
+ (strcmp($2, "yes")==0);
+ }
+ ;
+dt_dnstap_log_resolver_response_messages: VAR_DNSTAP_LOG_RESOLVER_RESPONSE_MESSAGES STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_log_resolver_response_messages:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_resolver_response_messages =
+ (strcmp($2, "yes")==0);
+ }
+ ;
+dt_dnstap_log_client_query_messages: VAR_DNSTAP_LOG_CLIENT_QUERY_MESSAGES STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_log_client_query_messages:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_client_query_messages =
+ (strcmp($2, "yes")==0);
+ }
+ ;
+dt_dnstap_log_client_response_messages: VAR_DNSTAP_LOG_CLIENT_RESPONSE_MESSAGES STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_log_client_response_messages:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_client_response_messages =
+ (strcmp($2, "yes")==0);
+ }
+ ;
+dt_dnstap_log_forwarder_query_messages: VAR_DNSTAP_LOG_FORWARDER_QUERY_MESSAGES STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_log_forwarder_query_messages:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_forwarder_query_messages =
+ (strcmp($2, "yes")==0);
+ }
+ ;
+dt_dnstap_log_forwarder_response_messages: VAR_DNSTAP_LOG_FORWARDER_RESPONSE_MESSAGES STRING_ARG
+ {
+ OUTYY(("P(dt_dnstap_log_forwarder_response_messages:%s)\n", $2));
+ if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
+ yyerror("expected yes or no.");
+ else cfg_parser->cfg->dnstap_log_forwarder_response_messages =
+ (strcmp($2, "yes")==0);
+ }
+ ;
+pythonstart: VAR_PYTHON
+ {
+ OUTYY(("\nP(python:)\n"));
+ }
+ ;
+contents_py: contents_py content_py
+ | ;
+content_py: py_script
+ ;
+py_script: VAR_PYTHON_SCRIPT STRING_ARG
+ {
+ OUTYY(("P(python-script:%s)\n", $2));
+ free(cfg_parser->cfg->python_script);
+ cfg_parser->cfg->python_script = $2;
+ }
+%%
+
+/* parse helper routines could be here */
diff --git a/external/unbound/util/configyyrename.h b/external/unbound/util/configyyrename.h
new file mode 100644
index 000000000..f529be577
--- /dev/null
+++ b/external/unbound/util/configyyrename.h
@@ -0,0 +1,88 @@
+/*
+ * configyyrename.h -- renames for config file yy values to avoid conflicts.
+ *
+ * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
+ *
+ * See LICENSE for the license.
+ *
+ */
+
+#ifndef UTIL_CONFIGYYRENAME_H
+#define UTIL_CONFIGYYRENAME_H
+
+/* defines to change symbols so that no yacc/lex symbols clash */
+#define yymaxdepth ub_c_maxdepth
+#define yyparse ub_c_parse
+#define yylex ub_c_lex
+#define yyerror ub_c_error
+#define yylval ub_c_lval
+#define yychar ub_c_char
+#define yydebug ub_c_debug
+#define yypact ub_c_pact
+#define yyr1 ub_c_r1
+#define yyr2 ub_c_r2
+#define yydef ub_c_def
+#define yychk ub_c_chk
+#define yypgo ub_c_pgo
+#define yyact ub_c_act
+#define yyexca ub_c_exca
+#define yyerrflag ub_c_errflag
+#define yynerrs ub_c_nerrs
+#define yyps ub_c_ps
+#define yypv ub_c_pv
+#define yys ub_c_s
+#define yy_yys ub_c_yys
+#define yystate ub_c_state
+#define yytmp ub_c_tmp
+#define yyv ub_c_v
+#define yy_yyv ub_c_yyv
+#define yyval ub_c_val
+#define yylloc ub_c_lloc
+#define yyreds ub_c_reds
+#define yytoks ub_c_toks
+#define yylhs ub_c_yylhs
+#define yylen ub_c_yylen
+#define yydefred ub_c_yydefred
+#define yydgoto ub_c_yydgoto
+#define yysindex ub_c_yysindex
+#define yyrindex ub_c_yyrindex
+#define yygindex ub_c_yygindex
+#define yytable ub_c_yytable
+#define yycheck ub_c_yycheck
+#define yyname ub_c_yyname
+#define yyrule ub_c_yyrule
+#define yyin ub_c_in
+#define yyout ub_c_out
+#define yywrap ub_c_wrap
+#define yy_load_buffer_state ub_c_load_buffer_state
+#define yy_switch_to_buffer ub_c_switch_to_buffer
+#define yy_flush_buffer ub_c_flush_buffer
+#define yy_init_buffer ub_c_init_buffer
+#define yy_scan_buffer ub_c_scan_buffer
+#define yy_scan_bytes ub_c_scan_bytes
+#define yy_scan_string ub_c_scan_string
+#define yy_create_buffer ub_c_create_buffer
+#define yyrestart ub_c_restart
+#define yy_delete_buffer ub_c_delete_buffer
+#define yypop_buffer_state ub_c_pop_buffer_state
+#define yypush_buffer_state ub_c_push_buffer_state
+#define yyunput ub_c_unput
+#define yyset_in ub_c_set_in
+#define yyget_in ub_c_get_in
+#define yyset_out ub_c_set_out
+#define yyget_out ub_c_get_out
+#define yyget_lineno ub_c_get_lineno
+#define yyset_lineno ub_c_set_lineno
+#define yyset_debug ub_c_set_debug
+#define yyget_debug ub_c_get_debug
+#define yy_flex_debug ub_c_flex_debug
+#define yylex_destroy ub_c_lex_destroy
+#define yyfree ub_c_free
+#define yyrealloc ub_c_realloc
+#define yyalloc ub_c_alloc
+#define yymalloc ub_c_malloc
+#define yyget_leng ub_c_get_leng
+#define yylineno ub_c_lineno
+#define yyget_text ub_c_get_text
+
+#endif /* UTIL_CONFIGYYRENAME_H */
diff --git a/external/unbound/util/data/dname.c b/external/unbound/util/data/dname.c
new file mode 100644
index 000000000..76f2e6458
--- /dev/null
+++ b/external/unbound/util/data/dname.c
@@ -0,0 +1,782 @@
+/*
+ * util/data/dname.h - domain name handling
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 domain name handling functions.
+ */
+
+#include "config.h"
+#include <ctype.h>
+#include "util/data/dname.h"
+#include "util/data/msgparse.h"
+#include "util/log.h"
+#include "util/storage/lookup3.h"
+#include "ldns/sbuffer.h"
+
+/* determine length of a dname in buffer, no compression pointers allowed */
+size_t
+query_dname_len(sldns_buffer* query)
+{
+ size_t len = 0;
+ size_t labellen;
+ while(1) {
+ if(sldns_buffer_remaining(query) < 1)
+ return 0; /* parse error, need label len */
+ labellen = sldns_buffer_read_u8(query);
+ if(labellen&0xc0)
+ return 0; /* no compression allowed in queries */
+ len += labellen + 1;
+ if(len > LDNS_MAX_DOMAINLEN)
+ return 0; /* too long */
+ if(labellen == 0)
+ return len;
+ if(sldns_buffer_remaining(query) < labellen)
+ return 0; /* parse error, need content */
+ sldns_buffer_skip(query, (ssize_t)labellen);
+ }
+}
+
+size_t
+dname_valid(uint8_t* dname, size_t maxlen)
+{
+ size_t len = 0;
+ size_t labellen;
+ labellen = *dname++;
+ while(labellen) {
+ if(labellen&0xc0)
+ return 0; /* no compression ptrs allowed */
+ len += labellen + 1;
+ if(len >= LDNS_MAX_DOMAINLEN)
+ return 0; /* too long */
+ if(len > maxlen)
+ return 0; /* does not fit in memory allocation */
+ dname += labellen;
+ labellen = *dname++;
+ }
+ len += 1;
+ if(len > maxlen)
+ return 0; /* does not fit in memory allocation */
+ return len;
+}
+
+/** compare uncompressed, noncanonical, registers are hints for speed */
+int
+query_dname_compare(register uint8_t* d1, register uint8_t* d2)
+{
+ register uint8_t lab1, lab2;
+ log_assert(d1 && d2);
+ lab1 = *d1++;
+ lab2 = *d2++;
+ while( lab1 != 0 || lab2 != 0 ) {
+ /* compare label length */
+ /* if one dname ends, it has labellength 0 */
+ if(lab1 != lab2) {
+ if(lab1 < lab2)
+ return -1;
+ return 1;
+ }
+ log_assert(lab1 == lab2 && lab1 != 0);
+ /* compare lowercased labels. */
+ while(lab1--) {
+ /* compare bytes first for speed */
+ if(*d1 != *d2 &&
+ tolower((int)*d1) != tolower((int)*d2)) {
+ if(tolower((int)*d1) < tolower((int)*d2))
+ return -1;
+ return 1;
+ }
+ d1++;
+ d2++;
+ }
+ /* next pair of labels. */
+ lab1 = *d1++;
+ lab2 = *d2++;
+ }
+ return 0;
+}
+
+void
+query_dname_tolower(uint8_t* dname)
+{
+ /* the dname is stored uncompressed */
+ uint8_t labellen;
+ labellen = *dname;
+ while(labellen) {
+ dname++;
+ while(labellen--) {
+ *dname = (uint8_t)tolower((int)*dname);
+ dname++;
+ }
+ labellen = *dname;
+ }
+}
+
+void
+pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname)
+{
+ uint8_t lablen;
+ int count = 0;
+ if(dname >= sldns_buffer_end(pkt))
+ return;
+ lablen = *dname++;
+ while(lablen) {
+ if(LABEL_IS_PTR(lablen)) {
+ if((size_t)PTR_OFFSET(lablen, *dname)
+ >= sldns_buffer_limit(pkt))
+ return;
+ dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
+ lablen = *dname++;
+ if(count++ > MAX_COMPRESS_PTRS)
+ return;
+ continue;
+ }
+ if(dname+lablen >= sldns_buffer_end(pkt))
+ return;
+ while(lablen--) {
+ *dname = (uint8_t)tolower((int)*dname);
+ dname++;
+ }
+ if(dname >= sldns_buffer_end(pkt))
+ return;
+ lablen = *dname++;
+ }
+}
+
+
+size_t
+pkt_dname_len(sldns_buffer* pkt)
+{
+ size_t len = 0;
+ int ptrcount = 0;
+ uint8_t labellen;
+ size_t endpos = 0;
+
+ /* read dname and determine length */
+ /* check compression pointers, loops, out of bounds */
+ while(1) {
+ /* read next label */
+ if(sldns_buffer_remaining(pkt) < 1)
+ return 0;
+ labellen = sldns_buffer_read_u8(pkt);
+ if(LABEL_IS_PTR(labellen)) {
+ /* compression ptr */
+ uint16_t ptr;
+ if(sldns_buffer_remaining(pkt) < 1)
+ return 0;
+ ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
+ if(ptrcount++ > MAX_COMPRESS_PTRS)
+ return 0; /* loop! */
+ if(sldns_buffer_limit(pkt) <= ptr)
+ return 0; /* out of bounds! */
+ if(!endpos)
+ endpos = sldns_buffer_position(pkt);
+ sldns_buffer_set_position(pkt, ptr);
+ } else {
+ /* label contents */
+ if(labellen > 0x3f)
+ return 0; /* label too long */
+ len += 1 + labellen;
+ if(len > LDNS_MAX_DOMAINLEN)
+ return 0;
+ if(labellen == 0) {
+ /* end of dname */
+ break;
+ }
+ if(sldns_buffer_remaining(pkt) < labellen)
+ return 0;
+ sldns_buffer_skip(pkt, (ssize_t)labellen);
+ }
+ }
+ if(endpos)
+ sldns_buffer_set_position(pkt, endpos);
+
+ return len;
+}
+
+int
+dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
+{
+ uint8_t len1, len2;
+ log_assert(pkt && d1 && d2);
+ len1 = *d1++;
+ len2 = *d2++;
+ while( len1 != 0 || len2 != 0 ) {
+ /* resolve ptrs */
+ if(LABEL_IS_PTR(len1)) {
+ d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1));
+ len1 = *d1++;
+ continue;
+ }
+ if(LABEL_IS_PTR(len2)) {
+ d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2));
+ len2 = *d2++;
+ continue;
+ }
+ /* check label length */
+ log_assert(len1 <= LDNS_MAX_LABELLEN);
+ log_assert(len2 <= LDNS_MAX_LABELLEN);
+ if(len1 != len2) {
+ if(len1 < len2) return -1;
+ return 1;
+ }
+ log_assert(len1 == len2 && len1 != 0);
+ /* compare labels */
+ while(len1--) {
+ if(tolower((int)*d1++) != tolower((int)*d2++)) {
+ if(tolower((int)d1[-1]) < tolower((int)d2[-1]))
+ return -1;
+ return 1;
+ }
+ }
+ len1 = *d1++;
+ len2 = *d2++;
+ }
+ return 0;
+}
+
+hashvalue_t
+dname_query_hash(uint8_t* dname, hashvalue_t h)
+{
+ uint8_t labuf[LDNS_MAX_LABELLEN+1];
+ uint8_t lablen;
+ int i;
+
+ /* preserve case of query, make hash label by label */
+ lablen = *dname++;
+ while(lablen) {
+ log_assert(lablen <= LDNS_MAX_LABELLEN);
+ labuf[0] = lablen;
+ i=0;
+ while(lablen--)
+ labuf[++i] = (uint8_t)tolower((int)*dname++);
+ h = hashlittle(labuf, labuf[0] + 1, h);
+ lablen = *dname++;
+ }
+
+ return h;
+}
+
+hashvalue_t
+dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_t h)
+{
+ uint8_t labuf[LDNS_MAX_LABELLEN+1];
+ uint8_t lablen;
+ int i;
+
+ /* preserve case of query, make hash label by label */
+ lablen = *dname++;
+ while(lablen) {
+ if(LABEL_IS_PTR(lablen)) {
+ /* follow pointer */
+ dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
+ lablen = *dname++;
+ continue;
+ }
+ log_assert(lablen <= LDNS_MAX_LABELLEN);
+ labuf[0] = lablen;
+ i=0;
+ while(lablen--)
+ labuf[++i] = (uint8_t)tolower((int)*dname++);
+ h = hashlittle(labuf, labuf[0] + 1, h);
+ lablen = *dname++;
+ }
+
+ return h;
+}
+
+void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname)
+{
+ /* copy over the dname and decompress it at the same time */
+ size_t len = 0;
+ uint8_t lablen;
+ lablen = *dname++;
+ while(lablen) {
+ if(LABEL_IS_PTR(lablen)) {
+ /* follow pointer */
+ dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
+ lablen = *dname++;
+ continue;
+ }
+ log_assert(lablen <= LDNS_MAX_LABELLEN);
+ len += (size_t)lablen+1;
+ if(len >= LDNS_MAX_DOMAINLEN) {
+ *to = 0; /* end the result prematurely */
+ log_err("bad dname in dname_pkt_copy");
+ return;
+ }
+ *to++ = lablen;
+ memmove(to, dname, lablen);
+ dname += lablen;
+ to += lablen;
+ lablen = *dname++;
+ }
+ /* copy last \0 */
+ *to = 0;
+}
+
+void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname)
+{
+ uint8_t lablen;
+ if(!out) out = stdout;
+ if(!dname) return;
+
+ lablen = *dname++;
+ if(!lablen)
+ fputc('.', out);
+ while(lablen) {
+ if(LABEL_IS_PTR(lablen)) {
+ /* follow pointer */
+ if(!pkt) {
+ fputs("??compressionptr??", out);
+ return;
+ }
+ dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname));
+ lablen = *dname++;
+ continue;
+ }
+ if(lablen > LDNS_MAX_LABELLEN) {
+ fputs("??extendedlabel??", out);
+ return;
+ }
+ while(lablen--)
+ fputc((int)*dname++, out);
+ fputc('.', out);
+ lablen = *dname++;
+ }
+}
+
+int
+dname_count_labels(uint8_t* dname)
+{
+ uint8_t lablen;
+ int labs = 1;
+
+ lablen = *dname++;
+ while(lablen) {
+ labs++;
+ dname += lablen;
+ lablen = *dname++;
+ }
+ return labs;
+}
+
+int
+dname_count_size_labels(uint8_t* dname, size_t* size)
+{
+ uint8_t lablen;
+ int labs = 1;
+ size_t sz = 1;
+
+ lablen = *dname++;
+ while(lablen) {
+ labs++;
+ sz += lablen+1;
+ dname += lablen;
+ lablen = *dname++;
+ }
+ *size = sz;
+ return labs;
+}
+
+/**
+ * Compare labels in memory, lowercase while comparing.
+ * @param p1: label 1
+ * @param p2: label 2
+ * @param len: number of bytes to compare.
+ * @return: 0, -1, +1 comparison result.
+ */
+static int
+memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len)
+{
+ while(len--) {
+ if(*p1 != *p2 && tolower((int)*p1) != tolower((int)*p2)) {
+ if(tolower((int)*p1) < tolower((int)*p2))
+ return -1;
+ return 1;
+ }
+ p1++;
+ p2++;
+ }
+ return 0;
+}
+
+int
+dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
+{
+ uint8_t len1, len2;
+ int atlabel = labs1;
+ int lastmlabs;
+ int lastdiff = 0;
+ /* first skip so that we compare same label. */
+ if(labs1 > labs2) {
+ while(atlabel > labs2) {
+ len1 = *d1++;
+ d1 += len1;
+ atlabel--;
+ }
+ log_assert(atlabel == labs2);
+ } else if(labs1 < labs2) {
+ atlabel = labs2;
+ while(atlabel > labs1) {
+ len2 = *d2++;
+ d2 += len2;
+ atlabel--;
+ }
+ log_assert(atlabel == labs1);
+ }
+ lastmlabs = atlabel+1;
+ /* now at same label in d1 and d2, atlabel */
+ /* www.example.com. */
+ /* 4 3 2 1 atlabel number */
+ /* repeat until at root label (which is always the same) */
+ while(atlabel > 1) {
+ len1 = *d1++;
+ len2 = *d2++;
+ if(len1 != len2) {
+ log_assert(len1 != 0 && len2 != 0);
+ if(len1<len2)
+ lastdiff = -1;
+ else lastdiff = 1;
+ lastmlabs = atlabel;
+ d1 += len1;
+ d2 += len2;
+ } else {
+ /* memlowercmp is inlined here; or just like
+ * if((c=memlowercmp(d1, d2, len1)) != 0) {
+ * lastdiff = c;
+ * lastmlabs = atlabel; } apart from d1++,d2++ */
+ while(len1) {
+ if(*d1 != *d2 && tolower((int)*d1)
+ != tolower((int)*d2)) {
+ if(tolower((int)*d1) <
+ tolower((int)*d2)) {
+ lastdiff = -1;
+ lastmlabs = atlabel;
+ d1 += len1;
+ d2 += len1;
+ break;
+ }
+ lastdiff = 1;
+ lastmlabs = atlabel;
+ d1 += len1;
+ d2 += len1;
+ break; /* out of memlowercmp */
+ }
+ d1++;
+ d2++;
+ len1--;
+ }
+ }
+ atlabel--;
+ }
+ /* last difference atlabel number, so number of labels matching,
+ * at the right side, is one less. */
+ *mlabs = lastmlabs-1;
+ if(lastdiff == 0) {
+ /* all labels compared were equal, check if one has more
+ * labels, so that example.com. > com. */
+ if(labs1 > labs2)
+ return 1;
+ else if(labs1 < labs2)
+ return -1;
+ }
+ return lastdiff;
+}
+
+int
+dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
+{
+ uint8_t lablen;
+
+ if(sldns_buffer_remaining(pkt) < 1)
+ return 0;
+ lablen = *dname++;
+ sldns_buffer_write_u8(pkt, lablen);
+ while(lablen) {
+ if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
+ return 0;
+ sldns_buffer_write(pkt, dname, lablen);
+ dname += lablen;
+ lablen = *dname++;
+ sldns_buffer_write_u8(pkt, lablen);
+ }
+ return 1;
+}
+
+void dname_str(uint8_t* dname, char* str)
+{
+ size_t len = 0;
+ uint8_t lablen = 0;
+ char* s = str;
+ if(!dname || !*dname) {
+ *s++ = '.';
+ *s = 0;
+ return;
+ }
+ lablen = *dname++;
+ while(lablen) {
+ if(lablen > LDNS_MAX_LABELLEN) {
+ *s++ = '#';
+ *s = 0;
+ return;
+ }
+ len += lablen+1;
+ if(len >= LDNS_MAX_DOMAINLEN-1) {
+ *s++ = '&';
+ *s = 0;
+ return;
+ }
+ while(lablen--) {
+ if(isalnum((int)*dname)
+ || *dname == '-' || *dname == '_'
+ || *dname == '*')
+ *s++ = *(char*)dname++;
+ else {
+ *s++ = '?';
+ dname++;
+ }
+ }
+ *s++ = '.';
+ lablen = *dname++;
+ }
+ *s = 0;
+}
+
+int
+dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2)
+{
+ int m;
+ /* check subdomain: d1: www.example.com. and d2: example.com. */
+ if(labs2 >= labs1)
+ return 0;
+ if(dname_lab_cmp(d1, labs1, d2, labs2, &m) > 0) {
+ /* subdomain if all labels match */
+ return (m == labs2);
+ }
+ return 0;
+}
+
+int
+dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2)
+{
+ return dname_strict_subdomain(d1, dname_count_labels(d1), d2,
+ dname_count_labels(d2));
+}
+
+int
+dname_subdomain_c(uint8_t* d1, uint8_t* d2)
+{
+ int m;
+ /* check subdomain: d1: www.example.com. and d2: example.com. */
+ /* or d1: example.com. and d2: example.com. */
+ int labs1 = dname_count_labels(d1);
+ int labs2 = dname_count_labels(d2);
+ if(labs2 > labs1)
+ return 0;
+ if(dname_lab_cmp(d1, labs1, d2, labs2, &m) < 0) {
+ /* must have been example.com , www.example.com - wrong */
+ /* or otherwise different dnames */
+ return 0;
+ }
+ return (m == labs2);
+}
+
+int
+dname_is_root(uint8_t* dname)
+{
+ uint8_t len;
+ log_assert(dname);
+ len = dname[0];
+ log_assert(!LABEL_IS_PTR(len));
+ return (len == 0);
+}
+
+void
+dname_remove_label(uint8_t** dname, size_t* len)
+{
+ size_t lablen;
+ log_assert(dname && *dname && len);
+ lablen = (*dname)[0];
+ log_assert(!LABEL_IS_PTR(lablen));
+ log_assert(*len > lablen);
+ if(lablen == 0)
+ return; /* do not modify root label */
+ *len -= lablen+1;
+ *dname += lablen+1;
+}
+
+void
+dname_remove_labels(uint8_t** dname, size_t* len, int n)
+{
+ int i;
+ for(i=0; i<n; i++)
+ dname_remove_label(dname, len);
+}
+
+int
+dname_signame_label_count(uint8_t* dname)
+{
+ uint8_t lablen;
+ int count = 0;
+ if(!*dname)
+ return 0;
+ if(dname[0] == 1 && dname[1] == '*')
+ dname += 2;
+ lablen = dname[0];
+ while(lablen) {
+ count++;
+ dname += lablen;
+ dname += 1;
+ lablen = dname[0];
+ }
+ return count;
+}
+
+int
+dname_is_wild(uint8_t* dname)
+{
+ return (dname[0] == 1 && dname[1] == '*');
+}
+
+/**
+ * Compare labels in memory, lowercase while comparing.
+ * Returns canonical order for labels. If all is equal, the
+ * shortest is first.
+ *
+ * @param p1: label 1
+ * @param len1: length of label 1.
+ * @param p2: label 2
+ * @param len2: length of label 2.
+ * @return: 0, -1, +1 comparison result.
+ */
+static int
+memcanoncmp(uint8_t* p1, uint8_t len1, uint8_t* p2, uint8_t len2)
+{
+ uint8_t min = (len1<len2)?len1:len2;
+ int c = memlowercmp(p1, p2, min);
+ if(c != 0)
+ return c;
+ /* equal, see who is shortest */
+ if(len1 < len2)
+ return -1;
+ if(len1 > len2)
+ return 1;
+ return 0;
+}
+
+
+int
+dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
+{
+ /* like dname_lab_cmp, but with different label comparison,
+ * empty character sorts before \000.
+ * So ylyly is before z. */
+ uint8_t len1, len2;
+ int atlabel = labs1;
+ int lastmlabs;
+ int lastdiff = 0;
+ int c;
+ /* first skip so that we compare same label. */
+ if(labs1 > labs2) {
+ while(atlabel > labs2) {
+ len1 = *d1++;
+ d1 += len1;
+ atlabel--;
+ }
+ log_assert(atlabel == labs2);
+ } else if(labs1 < labs2) {
+ atlabel = labs2;
+ while(atlabel > labs1) {
+ len2 = *d2++;
+ d2 += len2;
+ atlabel--;
+ }
+ log_assert(atlabel == labs1);
+ }
+ lastmlabs = atlabel+1;
+ /* now at same label in d1 and d2, atlabel */
+ /* www.example.com. */
+ /* 4 3 2 1 atlabel number */
+ /* repeat until at root label (which is always the same) */
+ while(atlabel > 1) {
+ len1 = *d1++;
+ len2 = *d2++;
+
+ if((c=memcanoncmp(d1, len1, d2, len2)) != 0) {
+ if(c<0)
+ lastdiff = -1;
+ else lastdiff = 1;
+ lastmlabs = atlabel;
+ }
+
+ d1 += len1;
+ d2 += len2;
+ atlabel--;
+ }
+ /* last difference atlabel number, so number of labels matching,
+ * at the right side, is one less. */
+ *mlabs = lastmlabs-1;
+ if(lastdiff == 0) {
+ /* all labels compared were equal, check if one has more
+ * labels, so that example.com. > com. */
+ if(labs1 > labs2)
+ return 1;
+ else if(labs1 < labs2)
+ return -1;
+ }
+ return lastdiff;
+}
+
+int
+dname_canonical_compare(uint8_t* d1, uint8_t* d2)
+{
+ int labs1, labs2, m;
+ labs1 = dname_count_labels(d1);
+ labs2 = dname_count_labels(d2);
+ return dname_canon_lab_cmp(d1, labs1, d2, labs2, &m);
+}
+
+uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2)
+{
+ int labs1, labs2, m;
+ size_t len = LDNS_MAX_DOMAINLEN;
+ labs1 = dname_count_labels(d1);
+ labs2 = dname_count_labels(d2);
+ (void)dname_lab_cmp(d1, labs1, d2, labs2, &m);
+ dname_remove_labels(&d1, &len, labs1-m);
+ return d1;
+}
diff --git a/external/unbound/util/data/dname.h b/external/unbound/util/data/dname.h
new file mode 100644
index 000000000..ae2fbadc1
--- /dev/null
+++ b/external/unbound/util/data/dname.h
@@ -0,0 +1,304 @@
+/*
+ * util/data/dname.h - domain name routines
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 deal with domain names (dnames).
+ *
+ * Some of the functions deal with domain names as a wireformat buffer,
+ * with a length.
+ */
+
+#ifndef UTIL_DATA_DNAME_H
+#define UTIL_DATA_DNAME_H
+#include "util/storage/lruhash.h"
+struct sldns_buffer;
+
+/** max number of compression ptrs to follow */
+#define MAX_COMPRESS_PTRS 256
+
+/**
+ * Determine length of dname in buffer, no compression ptrs allowed,
+ * @param query: the ldns buffer, current position at start of dname.
+ * at end, position is at end of the dname.
+ * @return: 0 on parse failure, or length including ending 0 of dname.
+ */
+size_t query_dname_len(struct sldns_buffer* query);
+
+/**
+ * Determine if dname in memory is correct. no compression ptrs allowed.
+ * @param dname: where dname starts in memory.
+ * @param len: dname is not allowed to exceed this length (i.e. of allocation).
+ * @return length of dname if dname is ok, 0 on a parse error.
+ */
+size_t dname_valid(uint8_t* dname, size_t len);
+
+/** lowercase query dname */
+void query_dname_tolower(uint8_t* dname);
+
+/**
+ * lowercase pkt dname (follows compression pointers)
+ * @param pkt: the packet, used to follow compression pointers. Position
+ * is unchanged.
+ * @param dname: start of dname in packet.
+ */
+void pkt_dname_tolower(struct sldns_buffer* pkt, uint8_t* dname);
+
+/**
+ * Compare query dnames (uncompressed storage). The Dnames passed do not
+ * have to be lowercased, comparison routine does this.
+ *
+ * This routine is special, in that the comparison that it does corresponds
+ * with the canonical comparison needed when comparing dnames inside rdata
+ * for RR types that need canonicalization. That means that the first byte
+ * that is smaller (possibly after lowercasing) makes an RR smaller, or the
+ * shortest name makes an RR smaller.
+ *
+ * This routine does not compute the canonical order needed for NSEC
+ * processing.
+ *
+ * Dnames have to be valid format.
+ * @param d1: dname to compare
+ * @param d2: dname to compare
+ * @return: -1, 0, or +1 depending on comparison results.
+ * Sort order is first difference found. not the canonical ordering.
+ */
+int query_dname_compare(uint8_t* d1, uint8_t* d2);
+
+/**
+ * Determine correct, compressed, dname present in packet.
+ * Checks for parse errors.
+ * @param pkt: packet to read from (from current start position).
+ * @return: 0 on parse error.
+ * At exit the position is right after the (compressed) dname.
+ * Compression pointers are followed and checked for loops.
+ * The uncompressed wireformat length is returned.
+ */
+size_t pkt_dname_len(struct sldns_buffer* pkt);
+
+/**
+ * Compare dnames in packet (compressed). Dnames must be valid.
+ * routine performs lowercasing, so the packet casing is preserved.
+ * @param pkt: packet, used to resolve compression pointers.
+ * @param d1: dname to compare
+ * @param d2: dname to compare
+ * @return: -1, 0, or +1 depending on comparison results.
+ * Sort order is first difference found. not the canonical ordering.
+ */
+int dname_pkt_compare(struct sldns_buffer* pkt, uint8_t* d1, uint8_t* d2);
+
+/**
+ * Hash dname, label by label, lowercasing, into hashvalue.
+ * Dname in query format (not compressed).
+ * @param dname: dname to hash.
+ * @param h: initial hash value.
+ * @return: result hash value.
+ */
+hashvalue_t dname_query_hash(uint8_t* dname, hashvalue_t h);
+
+/**
+ * Hash dname, label by label, lowercasing, into hashvalue.
+ * Dname in pkt format (compressed).
+ * @param pkt: packet, for resolving compression pointers.
+ * @param dname: dname to hash, pointer to the pkt buffer.
+ * Must be valid format. No loops, etc.
+ * @param h: initial hash value.
+ * @return: result hash value.
+ * Result is the same as dname_query_hash, even if compression is used.
+ */
+hashvalue_t dname_pkt_hash(struct sldns_buffer* pkt, uint8_t* dname, hashvalue_t h);
+
+/**
+ * Copy over a valid dname and decompress it.
+ * @param pkt: packet to resolve compression pointers.
+ * @param to: buffer of size from pkt_len function to hold result.
+ * @param dname: pointer into packet where dname starts.
+ */
+void dname_pkt_copy(struct sldns_buffer* pkt, uint8_t* to, uint8_t* dname);
+
+/**
+ * Copy over a valid dname to a packet.
+ * @param pkt: packet to copy to.
+ * @param dname: dname to copy.
+ * @return: 0 if not enough space in buffer.
+ */
+int dname_buffer_write(struct sldns_buffer* pkt, uint8_t* dname);
+
+/**
+ * Count the number of labels in an uncompressed dname in memory.
+ * @param dname: pointer to uncompressed dname.
+ * @return: count of labels, including root label, "com." has 2 labels.
+ */
+int dname_count_labels(uint8_t* dname);
+
+/**
+ * Count labels and dname length both, for uncompressed dname in memory.
+ * @param dname: pointer to uncompressed dname.
+ * @param size: length of dname, including root label.
+ * @return: count of labels, including root label, "com." has 2 labels.
+ */
+int dname_count_size_labels(uint8_t* dname, size_t* size);
+
+/**
+ * Compare dnames, sorted not canonical, but by label.
+ * Such that zone contents follows zone apex.
+ * @param d1: first dname. pointer to uncompressed wireformat.
+ * @param labs1: number of labels in first dname.
+ * @param d2: second dname. pointer to uncompressed wireformat.
+ * @param labs2: number of labels in second dname.
+ * @param mlabs: number of labels that matched exactly (the shared topdomain).
+ * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2.
+ */
+int dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs);
+
+/**
+ * See if domain name d1 is a strict subdomain of d2.
+ * That is a subdomain, but not equal.
+ * @param d1: domain name, uncompressed wireformat
+ * @param labs1: number of labels in d1, including root label.
+ * @param d2: domain name, uncompressed wireformat
+ * @param labs2: number of labels in d2, including root label.
+ * @return true if d1 is a subdomain of d2, but not equal to d2.
+ */
+int dname_strict_subdomain(uint8_t* d1, int labs1, uint8_t* d2, int labs2);
+
+/**
+ * Like dname_strict_subdomain but counts labels
+ * @param d1: domain name, uncompressed wireformat
+ * @param d2: domain name, uncompressed wireformat
+ * @return true if d1 is a subdomain of d2, but not equal to d2.
+ */
+int dname_strict_subdomain_c(uint8_t* d1, uint8_t* d2);
+
+/**
+ * Counts labels. Tests is d1 is a subdomain of d2.
+ * @param d1: domain name, uncompressed wireformat
+ * @param d2: domain name, uncompressed wireformat
+ * @return true if d1 is a subdomain of d2.
+ */
+int dname_subdomain_c(uint8_t* d1, uint8_t* d2);
+
+/**
+ * Debug helper. Print wireformat dname to output.
+ * @param out: like stdout or a file.
+ * @param pkt: if not NULL, the packet for resolving compression ptrs.
+ * @param dname: pointer to (start of) dname.
+ */
+void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname);
+
+/**
+ * Debug helper. Print dname to given string buffer (string buffer must
+ * be at least 255 chars + 1 for the 0, in printable form.
+ * This may lose information (? for nonprintable characters, or & if
+ * the name is too long, # for a bad label length).
+ * @param dname: uncompressed wireformat.
+ * @param str: buffer of 255+1 length.
+ */
+void dname_str(uint8_t* dname, char* str);
+
+/**
+ * Returns true if the uncompressed wireformat dname is the root "."
+ * @param dname: the dname to check
+ * @return true if ".", false if not.
+ */
+int dname_is_root(uint8_t* dname);
+
+/**
+ * Snip off first label from a dname, returning the parent zone.
+ * @param dname: from what to strip off. uncompressed wireformat.
+ * @param len: length, adjusted to become less.
+ * @return stripped off, or "." if input was ".".
+ */
+void dname_remove_label(uint8_t** dname, size_t* len);
+
+/**
+ * Snip off first N labels from a dname, returning the parent zone.
+ * @param dname: from what to strip off. uncompressed wireformat.
+ * @param len: length, adjusted to become less.
+ * @param n: number of labels to strip off (from the left).
+ * if 0, nothing happens.
+ * @return stripped off, or "." if input was ".".
+ */
+void dname_remove_labels(uint8_t** dname, size_t* len, int n);
+
+/**
+ * Count labels for the RRSIG signature label field.
+ * Like a normal labelcount, but "*" wildcard and "." root are not counted.
+ * @param dname: valid uncompressed wireformat.
+ * @return number of labels like in RRSIG; '*' and '.' are not counted.
+ */
+int dname_signame_label_count(uint8_t* dname);
+
+/**
+ * Return true if the label is a wildcard, *.example.com.
+ * @param dname: valid uncompressed wireformat.
+ * @return true if wildcard, or false.
+ */
+int dname_is_wild(uint8_t* dname);
+
+/**
+ * Compare dnames, Canonical in rfc4034 sense, but by label.
+ * Such that zone contents follows zone apex.
+ *
+ * @param d1: first dname. pointer to uncompressed wireformat.
+ * @param labs1: number of labels in first dname.
+ * @param d2: second dname. pointer to uncompressed wireformat.
+ * @param labs2: number of labels in second dname.
+ * @param mlabs: number of labels that matched exactly (the shared topdomain).
+ * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2.
+ */
+int dname_canon_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2,
+ int* mlabs);
+
+/**
+ * Canonical dname compare. Takes care of counting labels.
+ * Per rfc 4034 canonical order.
+ *
+ * @param d1: first dname. pointer to uncompressed wireformat.
+ * @param d2: second dname. pointer to uncompressed wireformat.
+ * @return: 0 for equal, -1 smaller, or +1 d1 larger than d2.
+ */
+int dname_canonical_compare(uint8_t* d1, uint8_t* d2);
+
+/**
+ * Get the shared topdomain between two names. Root "." or longer.
+ * @param d1: first dname. pointer to uncompressed wireformat.
+ * @param d2: second dname. pointer to uncompressed wireformat.
+ * @return pointer to shared topdomain. Ptr to a part of d1.
+ */
+uint8_t* dname_get_shared_topdomain(uint8_t* d1, uint8_t* d2);
+
+#endif /* UTIL_DATA_DNAME_H */
diff --git a/external/unbound/util/data/msgencode.c b/external/unbound/util/data/msgencode.c
new file mode 100644
index 000000000..26b5deabe
--- /dev/null
+++ b/external/unbound/util/data/msgencode.c
@@ -0,0 +1,841 @@
+/*
+ * util/data/msgencode.c - Encode DNS messages, queries and replies.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 a routines to encode DNS messages.
+ */
+
+#include "config.h"
+#include "util/data/msgencode.h"
+#include "util/data/msgreply.h"
+#include "util/data/msgparse.h"
+#include "util/data/dname.h"
+#include "util/log.h"
+#include "util/regional.h"
+#include "util/net_help.h"
+#include "ldns/sbuffer.h"
+
+/** return code that means the function ran out of memory. negative so it does
+ * not conflict with DNS rcodes. */
+#define RETVAL_OUTMEM -2
+/** return code that means the data did not fit (completely) in the packet */
+#define RETVAL_TRUNC -4
+/** return code that means all is peachy keen. Equal to DNS rcode NOERROR */
+#define RETVAL_OK 0
+
+/**
+ * Data structure to help domain name compression in outgoing messages.
+ * A tree of dnames and their offsets in the packet is kept.
+ * It is kept sorted, not canonical, but by label at least, so that after
+ * a lookup of a name you know its closest match, and the parent from that
+ * closest match. These are possible compression targets.
+ *
+ * It is a binary tree, not a rbtree or balanced tree, as the effort
+ * of keeping it balanced probably outweighs usefulness (given typical
+ * DNS packet size).
+ */
+struct compress_tree_node {
+ /** left node in tree, all smaller to this */
+ struct compress_tree_node* left;
+ /** right node in tree, all larger than this */
+ struct compress_tree_node* right;
+
+ /** the parent node - not for tree, but zone parent. One less label */
+ struct compress_tree_node* parent;
+ /** the domain name for this node. Pointer to uncompressed memory. */
+ uint8_t* dname;
+ /** number of labels in domain name, kept to help compare func. */
+ int labs;
+ /** offset in packet that points to this dname */
+ size_t offset;
+};
+
+/**
+ * Find domain name in tree, returns exact and closest match.
+ * @param tree: root of tree.
+ * @param dname: pointer to uncompressed dname.
+ * @param labs: number of labels in domain name.
+ * @param match: closest or exact match.
+ * guaranteed to be smaller or equal to the sought dname.
+ * can be null if the tree is empty.
+ * @param matchlabels: number of labels that match with closest match.
+ * can be zero is there is no match.
+ * @param insertpt: insert location for dname, if not found.
+ * @return: 0 if no exact match.
+ */
+static int
+compress_tree_search(struct compress_tree_node** tree, uint8_t* dname,
+ int labs, struct compress_tree_node** match, int* matchlabels,
+ struct compress_tree_node*** insertpt)
+{
+ int c, n, closen=0;
+ struct compress_tree_node* p = *tree;
+ struct compress_tree_node* close = 0;
+ struct compress_tree_node** prev = tree;
+ while(p) {
+ if((c = dname_lab_cmp(dname, labs, p->dname, p->labs, &n))
+ == 0) {
+ *matchlabels = n;
+ *match = p;
+ return 1;
+ }
+ if(c<0) {
+ prev = &p->left;
+ p = p->left;
+ } else {
+ closen = n;
+ close = p; /* p->dname is smaller than dname */
+ prev = &p->right;
+ p = p->right;
+ }
+ }
+ *insertpt = prev;
+ *matchlabels = closen;
+ *match = close;
+ return 0;
+}
+
+/**
+ * Lookup a domain name in compression tree.
+ * @param tree: root of tree (not the node with '.').
+ * @param dname: pointer to uncompressed dname.
+ * @param labs: number of labels in domain name.
+ * @param insertpt: insert location for dname, if not found.
+ * @return: 0 if not found or compress treenode with best compression.
+ */
+static struct compress_tree_node*
+compress_tree_lookup(struct compress_tree_node** tree, uint8_t* dname,
+ int labs, struct compress_tree_node*** insertpt)
+{
+ struct compress_tree_node* p;
+ int m;
+ if(labs <= 1)
+ return 0; /* do not compress root node */
+ if(compress_tree_search(tree, dname, labs, &p, &m, insertpt)) {
+ /* exact match */
+ return p;
+ }
+ /* return some ancestor of p that compresses well. */
+ if(m>1) {
+ /* www.example.com. (labs=4) matched foo.example.com.(labs=4)
+ * then matchcount = 3. need to go up. */
+ while(p && p->labs > m)
+ p = p->parent;
+ return p;
+ }
+ return 0;
+}
+
+/**
+ * Create node for domain name compression tree.
+ * @param dname: pointer to uncompressed dname (stored in tree).
+ * @param labs: number of labels in dname.
+ * @param offset: offset into packet for dname.
+ * @param region: how to allocate memory for new node.
+ * @return new node or 0 on malloc failure.
+ */
+static struct compress_tree_node*
+compress_tree_newnode(uint8_t* dname, int labs, size_t offset,
+ struct regional* region)
+{
+ struct compress_tree_node* n = (struct compress_tree_node*)
+ regional_alloc(region, sizeof(struct compress_tree_node));
+ if(!n) return 0;
+ n->left = 0;
+ n->right = 0;
+ n->parent = 0;
+ n->dname = dname;
+ n->labs = labs;
+ n->offset = offset;
+ return n;
+}
+
+/**
+ * Store domain name and ancestors into compression tree.
+ * @param dname: pointer to uncompressed dname (stored in tree).
+ * @param labs: number of labels in dname.
+ * @param offset: offset into packet for dname.
+ * @param region: how to allocate memory for new node.
+ * @param closest: match from previous lookup, used to compress dname.
+ * may be NULL if no previous match.
+ * if the tree has an ancestor of dname already, this must be it.
+ * @param insertpt: where to insert the dname in tree.
+ * @return: 0 on memory error.
+ */
+static int
+compress_tree_store(uint8_t* dname, int labs, size_t offset,
+ struct regional* region, struct compress_tree_node* closest,
+ struct compress_tree_node** insertpt)
+{
+ uint8_t lablen;
+ struct compress_tree_node* newnode;
+ struct compress_tree_node* prevnode = NULL;
+ int uplabs = labs-1; /* does not store root in tree */
+ if(closest) uplabs = labs - closest->labs;
+ log_assert(uplabs >= 0);
+ /* algorithms builds up a vine of dname-labels to hang into tree */
+ while(uplabs--) {
+ if(offset > PTR_MAX_OFFSET) {
+ /* insertion failed, drop vine */
+ return 1; /* compression pointer no longer useful */
+ }
+ if(!(newnode = compress_tree_newnode(dname, labs, offset,
+ region))) {
+ /* insertion failed, drop vine */
+ return 0;
+ }
+
+ if(prevnode) {
+ /* chain nodes together, last one has one label more,
+ * so is larger than newnode, thus goes right. */
+ newnode->right = prevnode;
+ prevnode->parent = newnode;
+ }
+
+ /* next label */
+ lablen = *dname++;
+ dname += lablen;
+ offset += lablen+1;
+ prevnode = newnode;
+ labs--;
+ }
+ /* if we have a vine, hang the vine into the tree */
+ if(prevnode) {
+ *insertpt = prevnode;
+ prevnode->parent = closest;
+ }
+ return 1;
+}
+
+/** compress a domain name */
+static int
+write_compressed_dname(sldns_buffer* pkt, uint8_t* dname, int labs,
+ struct compress_tree_node* p)
+{
+ /* compress it */
+ int labcopy = labs - p->labs;
+ uint8_t lablen;
+ uint16_t ptr;
+
+ if(labs == 1) {
+ /* write root label */
+ if(sldns_buffer_remaining(pkt) < 1)
+ return 0;
+ sldns_buffer_write_u8(pkt, 0);
+ return 1;
+ }
+
+ /* copy the first couple of labels */
+ while(labcopy--) {
+ lablen = *dname++;
+ if(sldns_buffer_remaining(pkt) < (size_t)lablen+1)
+ return 0;
+ sldns_buffer_write_u8(pkt, lablen);
+ sldns_buffer_write(pkt, dname, lablen);
+ dname += lablen;
+ }
+ /* insert compression ptr */
+ if(sldns_buffer_remaining(pkt) < 2)
+ return 0;
+ ptr = PTR_CREATE(p->offset);
+ sldns_buffer_write_u16(pkt, ptr);
+ return 1;
+}
+
+/** compress owner name of RR, return RETVAL_OUTMEM RETVAL_TRUNC */
+static int
+compress_owner(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
+ struct regional* region, struct compress_tree_node** tree,
+ size_t owner_pos, uint16_t* owner_ptr, int owner_labs)
+{
+ struct compress_tree_node* p;
+ struct compress_tree_node** insertpt;
+ if(!*owner_ptr) {
+ /* compress first time dname */
+ if((p = compress_tree_lookup(tree, key->rk.dname,
+ owner_labs, &insertpt))) {
+ if(p->labs == owner_labs)
+ /* avoid ptr chains, since some software is
+ * not capable of decoding ptr after a ptr. */
+ *owner_ptr = htons(PTR_CREATE(p->offset));
+ if(!write_compressed_dname(pkt, key->rk.dname,
+ owner_labs, p))
+ return RETVAL_TRUNC;
+ /* check if typeclass+4 ttl + rdatalen is available */
+ if(sldns_buffer_remaining(pkt) < 4+4+2)
+ return RETVAL_TRUNC;
+ } else {
+ /* no compress */
+ if(sldns_buffer_remaining(pkt) < key->rk.dname_len+4+4+2)
+ return RETVAL_TRUNC;
+ sldns_buffer_write(pkt, key->rk.dname,
+ key->rk.dname_len);
+ if(owner_pos <= PTR_MAX_OFFSET)
+ *owner_ptr = htons(PTR_CREATE(owner_pos));
+ }
+ if(!compress_tree_store(key->rk.dname, owner_labs,
+ owner_pos, region, p, insertpt))
+ return RETVAL_OUTMEM;
+ } else {
+ /* always compress 2nd-further RRs in RRset */
+ if(owner_labs == 1) {
+ if(sldns_buffer_remaining(pkt) < 1+4+4+2)
+ return RETVAL_TRUNC;
+ sldns_buffer_write_u8(pkt, 0);
+ } else {
+ if(sldns_buffer_remaining(pkt) < 2+4+4+2)
+ return RETVAL_TRUNC;
+ sldns_buffer_write(pkt, owner_ptr, 2);
+ }
+ }
+ return RETVAL_OK;
+}
+
+/** compress any domain name to the packet, return RETVAL_* */
+static int
+compress_any_dname(uint8_t* dname, sldns_buffer* pkt, int labs,
+ struct regional* region, struct compress_tree_node** tree)
+{
+ struct compress_tree_node* p;
+ struct compress_tree_node** insertpt = NULL;
+ size_t pos = sldns_buffer_position(pkt);
+ if((p = compress_tree_lookup(tree, dname, labs, &insertpt))) {
+ if(!write_compressed_dname(pkt, dname, labs, p))
+ return RETVAL_TRUNC;
+ } else {
+ if(!dname_buffer_write(pkt, dname))
+ return RETVAL_TRUNC;
+ }
+ if(!compress_tree_store(dname, labs, pos, region, p, insertpt))
+ return RETVAL_OUTMEM;
+ return RETVAL_OK;
+}
+
+/** return true if type needs domain name compression in rdata */
+static const sldns_rr_descriptor*
+type_rdata_compressable(struct ub_packed_rrset_key* key)
+{
+ uint16_t t = ntohs(key->rk.type);
+ if(sldns_rr_descript(t) &&
+ sldns_rr_descript(t)->_compress == LDNS_RR_COMPRESS)
+ return sldns_rr_descript(t);
+ return 0;
+}
+
+/** compress domain names in rdata, return RETVAL_* */
+static int
+compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen,
+ struct regional* region, struct compress_tree_node** tree,
+ const sldns_rr_descriptor* desc)
+{
+ int labs, r, rdf = 0;
+ size_t dname_len, len, pos = sldns_buffer_position(pkt);
+ uint8_t count = desc->_dname_count;
+
+ sldns_buffer_skip(pkt, 2); /* rdata len fill in later */
+ /* space for rdatalen checked for already */
+ rdata += 2;
+ todolen -= 2;
+ while(todolen > 0 && count) {
+ switch(desc->_wireformat[rdf]) {
+ case LDNS_RDF_TYPE_DNAME:
+ labs = dname_count_size_labels(rdata, &dname_len);
+ if((r=compress_any_dname(rdata, pkt, labs, region,
+ tree)) != RETVAL_OK)
+ return r;
+ rdata += dname_len;
+ todolen -= dname_len;
+ count--;
+ len = 0;
+ break;
+ case LDNS_RDF_TYPE_STR:
+ len = *rdata + 1;
+ break;
+ default:
+ len = get_rdf_size(desc->_wireformat[rdf]);
+ }
+ if(len) {
+ /* copy over */
+ if(sldns_buffer_remaining(pkt) < len)
+ return RETVAL_TRUNC;
+ sldns_buffer_write(pkt, rdata, len);
+ todolen -= len;
+ rdata += len;
+ }
+ rdf++;
+ }
+ /* copy remainder */
+ if(todolen > 0) {
+ if(sldns_buffer_remaining(pkt) < todolen)
+ return RETVAL_TRUNC;
+ sldns_buffer_write(pkt, rdata, todolen);
+ }
+
+ /* set rdata len */
+ sldns_buffer_write_u16_at(pkt, pos, sldns_buffer_position(pkt)-pos-2);
+ return RETVAL_OK;
+}
+
+/** Returns true if RR type should be included */
+static int
+rrset_belongs_in_reply(sldns_pkt_section s, uint16_t rrtype, uint16_t qtype,
+ int dnssec)
+{
+ if(dnssec)
+ return 1;
+ /* skip non DNSSEC types, except if directly queried for */
+ if(s == LDNS_SECTION_ANSWER) {
+ if(qtype == LDNS_RR_TYPE_ANY || qtype == rrtype)
+ return 1;
+ }
+ /* check DNSSEC-ness */
+ switch(rrtype) {
+ case LDNS_RR_TYPE_SIG:
+ case LDNS_RR_TYPE_KEY:
+ case LDNS_RR_TYPE_NXT:
+ case LDNS_RR_TYPE_DS:
+ case LDNS_RR_TYPE_RRSIG:
+ case LDNS_RR_TYPE_NSEC:
+ case LDNS_RR_TYPE_DNSKEY:
+ case LDNS_RR_TYPE_NSEC3:
+ case LDNS_RR_TYPE_NSEC3PARAMS:
+ return 0;
+ }
+ return 1;
+}
+
+/** store rrset in buffer in wireformat, return RETVAL_* */
+static int
+packed_rrset_encode(struct ub_packed_rrset_key* key, sldns_buffer* pkt,
+ uint16_t* num_rrs, time_t timenow, struct regional* region,
+ int do_data, int do_sig, struct compress_tree_node** tree,
+ sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset)
+{
+ size_t i, j, owner_pos;
+ int r, owner_labs;
+ uint16_t owner_ptr = 0;
+ struct packed_rrset_data* data = (struct packed_rrset_data*)
+ key->entry.data;
+
+ /* does this RR type belong in the answer? */
+ if(!rrset_belongs_in_reply(s, ntohs(key->rk.type), qtype, dnssec))
+ return RETVAL_OK;
+
+ owner_labs = dname_count_labels(key->rk.dname);
+ owner_pos = sldns_buffer_position(pkt);
+
+ if(do_data) {
+ const sldns_rr_descriptor* c = type_rdata_compressable(key);
+ for(i=0; i<data->count; i++) {
+ /* rrset roundrobin */
+ j = (i + rr_offset) % data->count;
+ if((r=compress_owner(key, pkt, region, tree,
+ owner_pos, &owner_ptr, owner_labs))
+ != RETVAL_OK)
+ return r;
+ sldns_buffer_write(pkt, &key->rk.type, 2);
+ sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
+ if(data->rr_ttl[j] < timenow)
+ sldns_buffer_write_u32(pkt, 0);
+ else sldns_buffer_write_u32(pkt,
+ data->rr_ttl[j]-timenow);
+ if(c) {
+ if((r=compress_rdata(pkt, data->rr_data[j],
+ data->rr_len[j], region, tree, c))
+ != RETVAL_OK)
+ return r;
+ } else {
+ if(sldns_buffer_remaining(pkt) < data->rr_len[j])
+ return RETVAL_TRUNC;
+ sldns_buffer_write(pkt, data->rr_data[j],
+ data->rr_len[j]);
+ }
+ }
+ }
+ /* insert rrsigs */
+ if(do_sig && dnssec) {
+ size_t total = data->count+data->rrsig_count;
+ for(i=data->count; i<total; i++) {
+ if(owner_ptr && owner_labs != 1) {
+ if(sldns_buffer_remaining(pkt) <
+ 2+4+4+data->rr_len[i])
+ return RETVAL_TRUNC;
+ sldns_buffer_write(pkt, &owner_ptr, 2);
+ } else {
+ if((r=compress_any_dname(key->rk.dname,
+ pkt, owner_labs, region, tree))
+ != RETVAL_OK)
+ return r;
+ if(sldns_buffer_remaining(pkt) <
+ 4+4+data->rr_len[i])
+ return RETVAL_TRUNC;
+ }
+ sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_RRSIG);
+ sldns_buffer_write(pkt, &key->rk.rrset_class, 2);
+ if(data->rr_ttl[i] < timenow)
+ sldns_buffer_write_u32(pkt, 0);
+ else sldns_buffer_write_u32(pkt,
+ data->rr_ttl[i]-timenow);
+ /* rrsig rdata cannot be compressed, perform 100+ byte
+ * memcopy. */
+ sldns_buffer_write(pkt, data->rr_data[i],
+ data->rr_len[i]);
+ }
+ }
+ /* change rrnum only after we are sure it fits */
+ if(do_data)
+ *num_rrs += data->count;
+ if(do_sig && dnssec)
+ *num_rrs += data->rrsig_count;
+
+ return RETVAL_OK;
+}
+
+/** store msg section in wireformat buffer, return RETVAL_* */
+static int
+insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs,
+ sldns_buffer* pkt, size_t rrsets_before, time_t timenow,
+ struct regional* region, struct compress_tree_node** tree,
+ sldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset)
+{
+ int r;
+ size_t i, setstart;
+ *num_rrs = 0;
+ if(s != LDNS_SECTION_ADDITIONAL) {
+ if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY)
+ dnssec = 1; /* include all types in ANY answer */
+ for(i=0; i<num_rrsets; i++) {
+ setstart = sldns_buffer_position(pkt);
+ if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
+ pkt, num_rrs, timenow, region, 1, 1, tree,
+ s, qtype, dnssec, rr_offset))
+ != RETVAL_OK) {
+ /* Bad, but if due to size must set TC bit */
+ /* trim off the rrset neatly. */
+ sldns_buffer_set_position(pkt, setstart);
+ return r;
+ }
+ }
+ } else {
+ for(i=0; i<num_rrsets; i++) {
+ setstart = sldns_buffer_position(pkt);
+ if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
+ pkt, num_rrs, timenow, region, 1, 0, tree,
+ s, qtype, dnssec, rr_offset))
+ != RETVAL_OK) {
+ sldns_buffer_set_position(pkt, setstart);
+ return r;
+ }
+ }
+ if(dnssec)
+ for(i=0; i<num_rrsets; i++) {
+ setstart = sldns_buffer_position(pkt);
+ if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i],
+ pkt, num_rrs, timenow, region, 0, 1, tree,
+ s, qtype, dnssec, rr_offset))
+ != RETVAL_OK) {
+ sldns_buffer_set_position(pkt, setstart);
+ return r;
+ }
+ }
+ }
+ return RETVAL_OK;
+}
+
+/** store query section in wireformat buffer, return RETVAL */
+static int
+insert_query(struct query_info* qinfo, struct compress_tree_node** tree,
+ sldns_buffer* buffer, struct regional* region)
+{
+ if(sldns_buffer_remaining(buffer) <
+ qinfo->qname_len+sizeof(uint16_t)*2)
+ return RETVAL_TRUNC; /* buffer too small */
+ /* the query is the first name inserted into the tree */
+ if(!compress_tree_store(qinfo->qname,
+ dname_count_labels(qinfo->qname),
+ sldns_buffer_position(buffer), region, NULL, tree))
+ return RETVAL_OUTMEM;
+ if(sldns_buffer_current(buffer) == qinfo->qname)
+ sldns_buffer_skip(buffer, (ssize_t)qinfo->qname_len);
+ else sldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len);
+ sldns_buffer_write_u16(buffer, qinfo->qtype);
+ sldns_buffer_write_u16(buffer, qinfo->qclass);
+ return RETVAL_OK;
+}
+
+static int
+positive_answer(struct reply_info* rep, uint16_t qtype) {
+ size_t i;
+ if (FLAGS_GET_RCODE(rep->flags) != LDNS_RCODE_NOERROR)
+ return 0;
+
+ for(i=0;i<rep->an_numrrsets; i++) {
+ if(ntohs(rep->rrsets[i]->rk.type) == qtype) {
+ /* in case it is a wildcard with DNSSEC, there will
+ * be NSEC/NSEC3 records in the authority section
+ * that we cannot remove */
+ for(i=rep->an_numrrsets; i<rep->an_numrrsets+
+ rep->ns_numrrsets; i++) {
+ if(ntohs(rep->rrsets[i]->rk.type) ==
+ LDNS_RR_TYPE_NSEC ||
+ ntohs(rep->rrsets[i]->rk.type) ==
+ LDNS_RR_TYPE_NSEC3)
+ return 0;
+ }
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
+ uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow,
+ struct regional* region, uint16_t udpsize, int dnssec)
+{
+ uint16_t ancount=0, nscount=0, arcount=0;
+ struct compress_tree_node* tree = 0;
+ int r;
+ size_t rr_offset;
+
+ sldns_buffer_clear(buffer);
+ if(udpsize < sldns_buffer_limit(buffer))
+ sldns_buffer_set_limit(buffer, udpsize);
+ if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE)
+ return 0;
+
+ sldns_buffer_write(buffer, &id, sizeof(uint16_t));
+ sldns_buffer_write_u16(buffer, flags);
+ sldns_buffer_write_u16(buffer, rep->qdcount);
+ /* set an, ns, ar counts to zero in case of small packets */
+ sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6);
+
+ /* insert query section */
+ if(rep->qdcount) {
+ if((r=insert_query(qinfo, &tree, buffer, region)) !=
+ RETVAL_OK) {
+ if(r == RETVAL_TRUNC) {
+ /* create truncated message */
+ sldns_buffer_write_u16_at(buffer, 4, 0);
+ LDNS_TC_SET(sldns_buffer_begin(buffer));
+ sldns_buffer_flip(buffer);
+ return 1;
+ }
+ return 0;
+ }
+ }
+ /* roundrobin offset. using query id for random number. With ntohs
+ * for different roundrobins for sequential id client senders. */
+ rr_offset = RRSET_ROUNDROBIN?ntohs(id):0;
+
+ /* insert answer section */
+ if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer,
+ 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype,
+ dnssec, rr_offset)) != RETVAL_OK) {
+ if(r == RETVAL_TRUNC) {
+ /* create truncated message */
+ sldns_buffer_write_u16_at(buffer, 6, ancount);
+ LDNS_TC_SET(sldns_buffer_begin(buffer));
+ sldns_buffer_flip(buffer);
+ return 1;
+ }
+ return 0;
+ }
+ sldns_buffer_write_u16_at(buffer, 6, ancount);
+
+ /* if response is positive answer, auth/add sections are not required */
+ if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) {
+ /* insert auth section */
+ if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer,
+ rep->an_numrrsets, timenow, region, &tree,
+ LDNS_SECTION_AUTHORITY, qinfo->qtype,
+ dnssec, rr_offset)) != RETVAL_OK) {
+ if(r == RETVAL_TRUNC) {
+ /* create truncated message */
+ sldns_buffer_write_u16_at(buffer, 8, nscount);
+ LDNS_TC_SET(sldns_buffer_begin(buffer));
+ sldns_buffer_flip(buffer);
+ return 1;
+ }
+ return 0;
+ }
+ sldns_buffer_write_u16_at(buffer, 8, nscount);
+
+ /* insert add section */
+ if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer,
+ rep->an_numrrsets + rep->ns_numrrsets, timenow, region,
+ &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype,
+ dnssec, rr_offset)) != RETVAL_OK) {
+ if(r == RETVAL_TRUNC) {
+ /* no need to set TC bit, this is the additional */
+ sldns_buffer_write_u16_at(buffer, 10, arcount);
+ sldns_buffer_flip(buffer);
+ return 1;
+ }
+ return 0;
+ }
+ sldns_buffer_write_u16_at(buffer, 10, arcount);
+ }
+ sldns_buffer_flip(buffer);
+ return 1;
+}
+
+uint16_t
+calc_edns_field_size(struct edns_data* edns)
+{
+ if(!edns || !edns->edns_present)
+ return 0;
+ /* domain root '.' + type + class + ttl + rdatalen(=0) */
+ return 1 + 2 + 2 + 4 + 2;
+}
+
+void
+attach_edns_record(sldns_buffer* pkt, struct edns_data* edns)
+{
+ size_t len;
+ if(!edns || !edns->edns_present)
+ return;
+ /* inc additional count */
+ sldns_buffer_write_u16_at(pkt, 10,
+ sldns_buffer_read_u16_at(pkt, 10) + 1);
+ len = sldns_buffer_limit(pkt);
+ sldns_buffer_clear(pkt);
+ sldns_buffer_set_position(pkt, len);
+ /* write EDNS record */
+ sldns_buffer_write_u8(pkt, 0); /* '.' label */
+ sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */
+ sldns_buffer_write_u16(pkt, edns->udp_size); /* class */
+ sldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */
+ sldns_buffer_write_u8(pkt, edns->edns_version);
+ sldns_buffer_write_u16(pkt, edns->bits);
+ sldns_buffer_write_u16(pkt, 0); /* rdatalen */
+ sldns_buffer_flip(pkt);
+}
+
+int
+reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
+ uint16_t id, uint16_t qflags, sldns_buffer* pkt, time_t timenow,
+ int cached, struct regional* region, uint16_t udpsize,
+ struct edns_data* edns, int dnssec, int secure)
+{
+ uint16_t flags;
+ int attach_edns = 1;
+
+ if(!cached || rep->authoritative) {
+ /* original flags, copy RD and CD bits from query. */
+ flags = rep->flags | (qflags & (BIT_RD|BIT_CD));
+ } else {
+ /* remove AA bit, copy RD and CD bits from query. */
+ flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD));
+ }
+ if(secure && (dnssec || (qflags&BIT_AD)))
+ flags |= BIT_AD;
+ log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
+ if(udpsize < LDNS_HEADER_SIZE)
+ return 0;
+ if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns)) {
+ /* packet too small to contain edns, omit it. */
+ attach_edns = 0;
+ } else {
+ /* reserve space for edns record */
+ udpsize -= calc_edns_field_size(edns);
+ }
+
+ if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
+ udpsize, dnssec)) {
+ log_err("reply encode: out of memory");
+ return 0;
+ }
+ if(attach_edns)
+ attach_edns_record(pkt, edns);
+ return 1;
+}
+
+void
+qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo)
+{
+ uint16_t flags = 0; /* QUERY, NOERROR */
+ sldns_buffer_clear(pkt);
+ log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
+ sldns_buffer_skip(pkt, 2); /* id done later */
+ sldns_buffer_write_u16(pkt, flags);
+ sldns_buffer_write_u16(pkt, 1); /* query count */
+ sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
+ sldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len);
+ sldns_buffer_write_u16(pkt, qinfo->qtype);
+ sldns_buffer_write_u16(pkt, qinfo->qclass);
+ sldns_buffer_flip(pkt);
+}
+
+void
+error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
+ uint16_t qid, uint16_t qflags, struct edns_data* edns)
+{
+ uint16_t flags;
+
+ sldns_buffer_clear(buf);
+ sldns_buffer_write(buf, &qid, sizeof(uint16_t));
+ flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/
+ flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
+ sldns_buffer_write_u16(buf, flags);
+ if(qinfo) flags = 1;
+ else flags = 0;
+ sldns_buffer_write_u16(buf, flags);
+ flags = 0;
+ sldns_buffer_write(buf, &flags, sizeof(uint16_t));
+ sldns_buffer_write(buf, &flags, sizeof(uint16_t));
+ sldns_buffer_write(buf, &flags, sizeof(uint16_t));
+ if(qinfo) {
+ if(sldns_buffer_current(buf) == qinfo->qname)
+ sldns_buffer_skip(buf, (ssize_t)qinfo->qname_len);
+ else sldns_buffer_write(buf, qinfo->qname, qinfo->qname_len);
+ sldns_buffer_write_u16(buf, qinfo->qtype);
+ sldns_buffer_write_u16(buf, qinfo->qclass);
+ }
+ sldns_buffer_flip(buf);
+ if(edns) {
+ struct edns_data es = *edns;
+ es.edns_version = EDNS_ADVERTISED_VERSION;
+ es.udp_size = EDNS_ADVERTISED_SIZE;
+ es.ext_rcode = 0;
+ es.bits &= EDNS_DO;
+ if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
+ edns->udp_size)
+ return;
+ attach_edns_record(buf, &es);
+ }
+}
diff --git a/external/unbound/util/data/msgencode.h b/external/unbound/util/data/msgencode.h
new file mode 100644
index 000000000..eea129d98
--- /dev/null
+++ b/external/unbound/util/data/msgencode.h
@@ -0,0 +1,131 @@
+/*
+ * util/data/msgencode.h - encode compressed DNS messages.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 temporary data structures and routines to create
+ * compressed DNS messages.
+ */
+
+#ifndef UTIL_DATA_MSGENCODE_H
+#define UTIL_DATA_MSGENCODE_H
+struct sldns_buffer;
+struct query_info;
+struct reply_info;
+struct regional;
+struct edns_data;
+
+/**
+ * Generate answer from reply_info.
+ * @param qinf: query information that provides query section in packet.
+ * @param rep: reply to fill in.
+ * @param id: id word from the query.
+ * @param qflags: flags word from the query.
+ * @param dest: buffer to put message into; will truncate if it does not fit.
+ * @param timenow: time to subtract.
+ * @param cached: set true if a cached reply (so no AA bit).
+ * set false for the first reply.
+ * @param region: where to allocate temp variables (for compression).
+ * @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
+ * @param edns: EDNS data included in the answer, NULL for none.
+ * or if edns_present = 0, it is not included.
+ * @param dnssec: if 0 DNSSEC records are omitted from the answer.
+ * @param secure: if 1, the AD bit is set in the reply.
+ * @return: 0 on error (server failure).
+ */
+int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
+ uint16_t id, uint16_t qflags, struct sldns_buffer* dest, time_t timenow,
+ int cached, struct regional* region, uint16_t udpsize,
+ struct edns_data* edns, int dnssec, int secure);
+
+/**
+ * Regenerate the wireformat from the stored msg reply.
+ * If the buffer is too small then the message is truncated at a whole
+ * rrset and the TC bit set, or whole rrsets are left out of the additional
+ * and the TC bit is not set.
+ * @param qinfo: query info to store.
+ * @param rep: reply to store.
+ * @param id: id value to store, network order.
+ * @param flags: flags value to store, host order.
+ * @param buffer: buffer to store the packet into.
+ * @param timenow: time now, to adjust ttl values.
+ * @param region: to store temporary data in.
+ * @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
+ * @param dnssec: if 0 DNSSEC records are omitted from the answer.
+ * @return: nonzero is success, or
+ * 0 on error: malloc failure (no log_err has been done).
+ */
+int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
+ uint16_t id, uint16_t flags, struct sldns_buffer* buffer, time_t timenow,
+ struct regional* region, uint16_t udpsize, int dnssec);
+
+/**
+ * Encode query packet. Assumes the buffer is large enough.
+ * @param pkt: where to store the packet.
+ * @param qinfo: query info.
+ */
+void qinfo_query_encode(struct sldns_buffer* pkt, struct query_info* qinfo);
+
+/**
+ * Estimate size of EDNS record in packet. EDNS record will be no larger.
+ * @param edns: edns data or NULL.
+ * @return octets to reserve for EDNS.
+ */
+uint16_t calc_edns_field_size(struct edns_data* edns);
+
+/**
+ * Attach EDNS record to buffer. Buffer has complete packet. There must
+ * be enough room left for the EDNS record.
+ * @param pkt: packet added to.
+ * @param edns: if NULL or present=0, nothing is added to the packet.
+ */
+void attach_edns_record(struct sldns_buffer* pkt, struct edns_data* edns);
+
+/**
+ * Encode an error. With QR and RA set.
+ *
+ * @param pkt: where to store the packet.
+ * @param r: RCODE value to encode.
+ * @param qinfo: if not NULL, the query is included.
+ * @param qid: query ID to set in packet. network order.
+ * @param qflags: original query flags (to copy RD and CD bits). host order.
+ * @param edns: if not NULL, this is the query edns info,
+ * and an edns reply is attached. Only attached if EDNS record fits reply.
+ */
+void error_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo,
+ uint16_t qid, uint16_t qflags, struct edns_data* edns);
+
+#endif /* UTIL_DATA_MSGENCODE_H */
diff --git a/external/unbound/util/data/msgparse.c b/external/unbound/util/data/msgparse.c
new file mode 100644
index 000000000..abe778a89
--- /dev/null
+++ b/external/unbound/util/data/msgparse.c
@@ -0,0 +1,1022 @@
+/*
+ * util/data/msgparse.c - parse wireformat DNS messages.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ * Routines for message parsing a packet buffer to a descriptive structure.
+ */
+#include "config.h"
+#include "util/data/msgparse.h"
+#include "util/data/dname.h"
+#include "util/data/packed_rrset.h"
+#include "util/storage/lookup3.h"
+#include "util/regional.h"
+#include "ldns/rrdef.h"
+#include "ldns/sbuffer.h"
+#include "ldns/parseutil.h"
+#include "ldns/wire2str.h"
+
+/** smart comparison of (compressed, valid) dnames from packet */
+static int
+smart_compare(sldns_buffer* pkt, uint8_t* dnow,
+ uint8_t* dprfirst, uint8_t* dprlast)
+{
+ if(LABEL_IS_PTR(*dnow)) {
+ /* ptr points to a previous dname */
+ uint8_t* p = sldns_buffer_at(pkt, PTR_OFFSET(dnow[0], dnow[1]));
+ if( p == dprfirst || p == dprlast )
+ return 0;
+ /* prev dname is also a ptr, both ptrs are the same. */
+ if(LABEL_IS_PTR(*dprlast) &&
+ dprlast[0] == dnow[0] && dprlast[1] == dnow[1])
+ return 0;
+ }
+ return dname_pkt_compare(pkt, dnow, dprlast);
+}
+
+/**
+ * Allocate new rrset in region, fill with data.
+ */
+static struct rrset_parse*
+new_rrset(struct msg_parse* msg, uint8_t* dname, size_t dnamelen,
+ uint16_t type, uint16_t dclass, hashvalue_t hash,
+ uint32_t rrset_flags, sldns_pkt_section section,
+ struct regional* region)
+{
+ struct rrset_parse* p = regional_alloc(region, sizeof(*p));
+ if(!p) return NULL;
+ p->rrset_bucket_next = msg->hashtable[hash & (PARSE_TABLE_SIZE-1)];
+ msg->hashtable[hash & (PARSE_TABLE_SIZE-1)] = p;
+ p->rrset_all_next = 0;
+ if(msg->rrset_last)
+ msg->rrset_last->rrset_all_next = p;
+ else msg->rrset_first = p;
+ msg->rrset_last = p;
+ p->hash = hash;
+ p->section = section;
+ p->dname = dname;
+ p->dname_len = dnamelen;
+ p->type = type;
+ p->rrset_class = dclass;
+ p->flags = rrset_flags;
+ p->rr_count = 0;
+ p->size = 0;
+ p->rr_first = 0;
+ p->rr_last = 0;
+ p->rrsig_count = 0;
+ p->rrsig_first = 0;
+ p->rrsig_last = 0;
+ return p;
+}
+
+/** See if next rrset is nsec at zone apex */
+static int
+nsec_at_apex(sldns_buffer* pkt)
+{
+ /* we are at ttl position in packet. */
+ size_t pos = sldns_buffer_position(pkt);
+ uint16_t rdatalen;
+ if(sldns_buffer_remaining(pkt) < 7) /* ttl+len+root */
+ return 0; /* eek! */
+ sldns_buffer_skip(pkt, 4); /* ttl */;
+ rdatalen = sldns_buffer_read_u16(pkt);
+ if(sldns_buffer_remaining(pkt) < rdatalen) {
+ sldns_buffer_set_position(pkt, pos);
+ return 0; /* parse error happens later */
+ }
+ /* must validate the nsec next domain name format */
+ if(pkt_dname_len(pkt) == 0) {
+ sldns_buffer_set_position(pkt, pos);
+ return 0; /* parse error */
+ }
+
+ /* see if SOA bit is set. */
+ if(sldns_buffer_position(pkt) < pos+4+rdatalen) {
+ /* nsec type bitmap contains items */
+ uint8_t win, blen, bits;
+ /* need: windownum, bitmap len, firstbyte */
+ if(sldns_buffer_position(pkt)+3 > pos+4+rdatalen) {
+ sldns_buffer_set_position(pkt, pos);
+ return 0; /* malformed nsec */
+ }
+ win = sldns_buffer_read_u8(pkt);
+ blen = sldns_buffer_read_u8(pkt);
+ bits = sldns_buffer_read_u8(pkt);
+ /* 0window always first window. bitlen >=1 or parse
+ error really. bit 0x2 is SOA. */
+ if(win == 0 && blen >= 1 && (bits & 0x02)) {
+ sldns_buffer_set_position(pkt, pos);
+ return 1;
+ }
+ }
+
+ sldns_buffer_set_position(pkt, pos);
+ return 0;
+}
+
+/** Calculate rrset flags */
+static uint32_t
+pkt_rrset_flags(sldns_buffer* pkt, uint16_t type, sldns_pkt_section sec)
+{
+ uint32_t f = 0;
+ if(type == LDNS_RR_TYPE_NSEC && nsec_at_apex(pkt)) {
+ f |= PACKED_RRSET_NSEC_AT_APEX;
+ } else if(type == LDNS_RR_TYPE_SOA && sec == LDNS_SECTION_AUTHORITY) {
+ f |= PACKED_RRSET_SOA_NEG;
+ }
+ return f;
+}
+
+hashvalue_t
+pkt_hash_rrset(sldns_buffer* pkt, uint8_t* dname, uint16_t type,
+ uint16_t dclass, uint32_t rrset_flags)
+{
+ /* note this MUST be identical to rrset_key_hash in packed_rrset.c */
+ /* this routine handles compressed names */
+ hashvalue_t h = 0xab;
+ h = dname_pkt_hash(pkt, dname, h);
+ h = hashlittle(&type, sizeof(type), h); /* host order */
+ h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */
+ h = hashlittle(&rrset_flags, sizeof(uint32_t), h);
+ return h;
+}
+
+/** create partial dname hash for rrset hash */
+static hashvalue_t
+pkt_hash_rrset_first(sldns_buffer* pkt, uint8_t* dname)
+{
+ /* works together with pkt_hash_rrset_rest */
+ /* note this MUST be identical to rrset_key_hash in packed_rrset.c */
+ /* this routine handles compressed names */
+ hashvalue_t h = 0xab;
+ h = dname_pkt_hash(pkt, dname, h);
+ return h;
+}
+
+/** create a rrset hash from a partial dname hash */
+static hashvalue_t
+pkt_hash_rrset_rest(hashvalue_t dname_h, uint16_t type, uint16_t dclass,
+ uint32_t rrset_flags)
+{
+ /* works together with pkt_hash_rrset_first */
+ /* note this MUST be identical to rrset_key_hash in packed_rrset.c */
+ hashvalue_t h;
+ h = hashlittle(&type, sizeof(type), dname_h); /* host order */
+ h = hashlittle(&dclass, sizeof(dclass), h); /* netw order */
+ h = hashlittle(&rrset_flags, sizeof(uint32_t), h);
+ return h;
+}
+
+/** compare rrset_parse with data */
+static int
+rrset_parse_equals(struct rrset_parse* p, sldns_buffer* pkt, hashvalue_t h,
+ uint32_t rrset_flags, uint8_t* dname, size_t dnamelen,
+ uint16_t type, uint16_t dclass)
+{
+ if(p->hash == h && p->dname_len == dnamelen && p->type == type &&
+ p->rrset_class == dclass && p->flags == rrset_flags &&
+ dname_pkt_compare(pkt, dname, p->dname) == 0)
+ return 1;
+ return 0;
+}
+
+
+struct rrset_parse*
+msgparse_hashtable_lookup(struct msg_parse* msg, sldns_buffer* pkt,
+ hashvalue_t h, uint32_t rrset_flags, uint8_t* dname, size_t dnamelen,
+ uint16_t type, uint16_t dclass)
+{
+ struct rrset_parse* p = msg->hashtable[h & (PARSE_TABLE_SIZE-1)];
+ while(p) {
+ if(rrset_parse_equals(p, pkt, h, rrset_flags, dname, dnamelen,
+ type, dclass))
+ return p;
+ p = p->rrset_bucket_next;
+ }
+ return NULL;
+}
+
+/** return type networkformat that rrsig in packet covers */
+static int
+pkt_rrsig_covered(sldns_buffer* pkt, uint8_t* here, uint16_t* type)
+{
+ size_t pos = sldns_buffer_position(pkt);
+ sldns_buffer_set_position(pkt, (size_t)(here-sldns_buffer_begin(pkt)));
+ /* ttl + len + size of small rrsig(rootlabel, no signature) */
+ if(sldns_buffer_remaining(pkt) < 4+2+19)
+ return 0;
+ sldns_buffer_skip(pkt, 4); /* ttl */
+ if(sldns_buffer_read_u16(pkt) < 19) /* too short */ {
+ sldns_buffer_set_position(pkt, pos);
+ return 0;
+ }
+ *type = sldns_buffer_read_u16(pkt);
+ sldns_buffer_set_position(pkt, pos);
+ return 1;
+}
+
+/** true if covered type equals prevtype */
+static int
+pkt_rrsig_covered_equals(sldns_buffer* pkt, uint8_t* here, uint16_t type)
+{
+ uint16_t t;
+ if(pkt_rrsig_covered(pkt, here, &t) && t == type)
+ return 1;
+ return 0;
+}
+
+void
+msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset)
+{
+ struct rrset_parse** p;
+ p = &msg->hashtable[ rrset->hash & (PARSE_TABLE_SIZE-1) ];
+ while(*p) {
+ if(*p == rrset) {
+ *p = rrset->rrset_bucket_next;
+ return;
+ }
+ p = &( (*p)->rrset_bucket_next );
+ }
+}
+
+/** change section of rrset from previous to current section */
+static void
+change_section(struct msg_parse* msg, struct rrset_parse* rrset,
+ sldns_pkt_section section)
+{
+ struct rrset_parse *p, *prev;
+ /* remove from list */
+ if(section == rrset->section)
+ return;
+ p = msg->rrset_first;
+ prev = 0;
+ while(p) {
+ if(p == rrset) {
+ if(prev) prev->rrset_all_next = p->rrset_all_next;
+ else msg->rrset_first = p->rrset_all_next;
+ if(msg->rrset_last == rrset)
+ msg->rrset_last = prev;
+ break;
+ }
+ prev = p;
+ p = p->rrset_all_next;
+ }
+ /* remove from count */
+ switch(rrset->section) {
+ case LDNS_SECTION_ANSWER: msg->an_rrsets--; break;
+ case LDNS_SECTION_AUTHORITY: msg->ns_rrsets--; break;
+ case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets--; break;
+ default: log_assert(0);
+ }
+ /* insert at end of list */
+ rrset->rrset_all_next = 0;
+ if(msg->rrset_last)
+ msg->rrset_last->rrset_all_next = rrset;
+ else msg->rrset_first = rrset;
+ msg->rrset_last = rrset;
+ /* up count of new section */
+ switch(section) {
+ case LDNS_SECTION_AUTHORITY: msg->ns_rrsets++; break;
+ case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets++; break;
+ default: log_assert(0);
+ }
+ rrset->section = section;
+}
+
+/** see if rrset of type RRSIG contains sig over given type */
+static int
+rrset_has_sigover(sldns_buffer* pkt, struct rrset_parse* rrset, uint16_t type,
+ int* hasother)
+{
+ int res = 0;
+ struct rr_parse* rr = rrset->rr_first;
+ log_assert( rrset->type == LDNS_RR_TYPE_RRSIG );
+ while(rr) {
+ if(pkt_rrsig_covered_equals(pkt, rr->ttl_data, type))
+ res = 1;
+ else *hasother = 1;
+ rr = rr->next;
+ }
+ return res;
+}
+
+/** move rrsigs from sigset to dataset */
+static int
+moveover_rrsigs(sldns_buffer* pkt, struct regional* region,
+ struct rrset_parse* sigset, struct rrset_parse* dataset, int duplicate)
+{
+ struct rr_parse* sig = sigset->rr_first;
+ struct rr_parse* prev = NULL;
+ struct rr_parse* insert;
+ struct rr_parse* nextsig;
+ while(sig) {
+ nextsig = sig->next;
+ if(pkt_rrsig_covered_equals(pkt, sig->ttl_data,
+ dataset->type)) {
+ if(duplicate) {
+ /* new */
+ insert = (struct rr_parse*)regional_alloc(
+ region, sizeof(struct rr_parse));
+ if(!insert) return 0;
+ insert->outside_packet = 0;
+ insert->ttl_data = sig->ttl_data;
+ insert->size = sig->size;
+ /* prev not used */
+ } else {
+ /* remove from sigset */
+ if(prev) prev->next = sig->next;
+ else sigset->rr_first = sig->next;
+ if(sigset->rr_last == sig)
+ sigset->rr_last = prev;
+ sigset->rr_count--;
+ sigset->size -= sig->size;
+ insert = sig;
+ /* prev not changed */
+ }
+ /* add to dataset */
+ dataset->rrsig_count++;
+ insert->next = 0;
+ if(dataset->rrsig_last)
+ dataset->rrsig_last->next = insert;
+ else dataset->rrsig_first = insert;
+ dataset->rrsig_last = insert;
+ dataset->size += insert->size;
+ } else {
+ prev = sig;
+ }
+ sig = nextsig;
+ }
+ return 1;
+}
+
+/** change an rrsig rrset for use as data rrset */
+static struct rrset_parse*
+change_rrsig_rrset(struct rrset_parse* sigset, struct msg_parse* msg,
+ sldns_buffer* pkt, uint16_t datatype, uint32_t rrset_flags,
+ int hasother, sldns_pkt_section section, struct regional* region)
+{
+ struct rrset_parse* dataset = sigset;
+ hashvalue_t hash = pkt_hash_rrset(pkt, sigset->dname, datatype,
+ sigset->rrset_class, rrset_flags);
+ log_assert( sigset->type == LDNS_RR_TYPE_RRSIG );
+ log_assert( datatype != LDNS_RR_TYPE_RRSIG );
+ if(hasother) {
+ /* need to make new rrset to hold data type */
+ dataset = new_rrset(msg, sigset->dname, sigset->dname_len,
+ datatype, sigset->rrset_class, hash, rrset_flags,
+ section, region);
+ if(!dataset)
+ return NULL;
+ switch(section) {
+ case LDNS_SECTION_ANSWER: msg->an_rrsets++; break;
+ case LDNS_SECTION_AUTHORITY: msg->ns_rrsets++; break;
+ case LDNS_SECTION_ADDITIONAL: msg->ar_rrsets++; break;
+ default: log_assert(0);
+ }
+ if(!moveover_rrsigs(pkt, region, sigset, dataset,
+ msg->qtype == LDNS_RR_TYPE_RRSIG ||
+ (msg->qtype == LDNS_RR_TYPE_ANY &&
+ section != LDNS_SECTION_ANSWER) ))
+ return NULL;
+ return dataset;
+ }
+ /* changeover the type of the rrset to data set */
+ msgparse_bucket_remove(msg, dataset);
+ /* insert into new hash bucket */
+ dataset->rrset_bucket_next = msg->hashtable[hash&(PARSE_TABLE_SIZE-1)];
+ msg->hashtable[hash&(PARSE_TABLE_SIZE-1)] = dataset;
+ dataset->hash = hash;
+ /* use section of data item for result */
+ change_section(msg, dataset, section);
+ dataset->type = datatype;
+ dataset->flags = rrset_flags;
+ dataset->rrsig_count += dataset->rr_count;
+ dataset->rr_count = 0;
+ /* move sigs to end of siglist */
+ if(dataset->rrsig_last)
+ dataset->rrsig_last->next = dataset->rr_first;
+ else dataset->rrsig_first = dataset->rr_first;
+ dataset->rrsig_last = dataset->rr_last;
+ dataset->rr_first = 0;
+ dataset->rr_last = 0;
+ return dataset;
+}
+
+/** Find rrset. If equal to previous it is fast. hash if not so.
+ * @param msg: the message with hash table.
+ * @param pkt: the packet in wireformat (needed for compression ptrs).
+ * @param dname: pointer to start of dname (compressed) in packet.
+ * @param dnamelen: uncompressed wirefmt length of dname.
+ * @param type: type of current rr.
+ * @param dclass: class of current rr.
+ * @param hash: hash value is returned if the rrset could not be found.
+ * @param rrset_flags: is returned if the rrset could not be found.
+ * @param prev_dname_first: dname of last seen RR. First seen dname.
+ * @param prev_dname_last: dname of last seen RR. Last seen dname.
+ * @param prev_dnamelen: dname len of last seen RR.
+ * @param prev_type: type of last seen RR.
+ * @param prev_dclass: class of last seen RR.
+ * @param rrset_prev: last seen RRset.
+ * @param section: the current section in the packet.
+ * @param region: used to allocate temporary parsing data.
+ * @return 0 on out of memory.
+ */
+static int
+find_rrset(struct msg_parse* msg, sldns_buffer* pkt, uint8_t* dname,
+ size_t dnamelen, uint16_t type, uint16_t dclass, hashvalue_t* hash,
+ uint32_t* rrset_flags,
+ uint8_t** prev_dname_first, uint8_t** prev_dname_last,
+ size_t* prev_dnamelen, uint16_t* prev_type,
+ uint16_t* prev_dclass, struct rrset_parse** rrset_prev,
+ sldns_pkt_section section, struct regional* region)
+{
+ hashvalue_t dname_h = pkt_hash_rrset_first(pkt, dname);
+ uint16_t covtype;
+ if(*rrset_prev) {
+ /* check if equal to previous item */
+ if(type == *prev_type && dclass == *prev_dclass &&
+ dnamelen == *prev_dnamelen &&
+ smart_compare(pkt, dname, *prev_dname_first,
+ *prev_dname_last) == 0 &&
+ type != LDNS_RR_TYPE_RRSIG) {
+ /* same as previous */
+ *prev_dname_last = dname;
+ return 1;
+ }
+ /* check if rrsig over previous item */
+ if(type == LDNS_RR_TYPE_RRSIG && dclass == *prev_dclass &&
+ pkt_rrsig_covered_equals(pkt, sldns_buffer_current(pkt),
+ *prev_type) &&
+ smart_compare(pkt, dname, *prev_dname_first,
+ *prev_dname_last) == 0) {
+ /* covers previous */
+ *prev_dname_last = dname;
+ return 1;
+ }
+ }
+ /* find by hashing and lookup in hashtable */
+ *rrset_flags = pkt_rrset_flags(pkt, type, section);
+
+ /* if rrsig - try to lookup matching data set first */
+ if(type == LDNS_RR_TYPE_RRSIG && pkt_rrsig_covered(pkt,
+ sldns_buffer_current(pkt), &covtype)) {
+ *hash = pkt_hash_rrset_rest(dname_h, covtype, dclass,
+ *rrset_flags);
+ *rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash,
+ *rrset_flags, dname, dnamelen, covtype, dclass);
+ if(!*rrset_prev && covtype == LDNS_RR_TYPE_NSEC) {
+ /* if NSEC try with NSEC apex bit twiddled */
+ *rrset_flags ^= PACKED_RRSET_NSEC_AT_APEX;
+ *hash = pkt_hash_rrset_rest(dname_h, covtype, dclass,
+ *rrset_flags);
+ *rrset_prev = msgparse_hashtable_lookup(msg, pkt,
+ *hash, *rrset_flags, dname, dnamelen, covtype,
+ dclass);
+ if(!*rrset_prev) /* untwiddle if not found */
+ *rrset_flags ^= PACKED_RRSET_NSEC_AT_APEX;
+ }
+ if(!*rrset_prev && covtype == LDNS_RR_TYPE_SOA) {
+ /* if SOA try with SOA neg flag twiddled */
+ *rrset_flags ^= PACKED_RRSET_SOA_NEG;
+ *hash = pkt_hash_rrset_rest(dname_h, covtype, dclass,
+ *rrset_flags);
+ *rrset_prev = msgparse_hashtable_lookup(msg, pkt,
+ *hash, *rrset_flags, dname, dnamelen, covtype,
+ dclass);
+ if(!*rrset_prev) /* untwiddle if not found */
+ *rrset_flags ^= PACKED_RRSET_SOA_NEG;
+ }
+ if(*rrset_prev) {
+ *prev_dname_first = (*rrset_prev)->dname;
+ *prev_dname_last = dname;
+ *prev_dnamelen = dnamelen;
+ *prev_type = covtype;
+ *prev_dclass = dclass;
+ return 1;
+ }
+ }
+ if(type != LDNS_RR_TYPE_RRSIG) {
+ int hasother = 0;
+ /* find matching rrsig */
+ *hash = pkt_hash_rrset_rest(dname_h, LDNS_RR_TYPE_RRSIG,
+ dclass, 0);
+ *rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash,
+ 0, dname, dnamelen, LDNS_RR_TYPE_RRSIG,
+ dclass);
+ if(*rrset_prev && rrset_has_sigover(pkt, *rrset_prev, type,
+ &hasother)) {
+ /* yes! */
+ *prev_dname_first = (*rrset_prev)->dname;
+ *prev_dname_last = dname;
+ *prev_dnamelen = dnamelen;
+ *prev_type = type;
+ *prev_dclass = dclass;
+ *rrset_prev = change_rrsig_rrset(*rrset_prev, msg,
+ pkt, type, *rrset_flags, hasother, section,
+ region);
+ if(!*rrset_prev) return 0;
+ return 1;
+ }
+ }
+
+ *hash = pkt_hash_rrset_rest(dname_h, type, dclass, *rrset_flags);
+ *rrset_prev = msgparse_hashtable_lookup(msg, pkt, *hash, *rrset_flags,
+ dname, dnamelen, type, dclass);
+ if(*rrset_prev)
+ *prev_dname_first = (*rrset_prev)->dname;
+ else *prev_dname_first = dname;
+ *prev_dname_last = dname;
+ *prev_dnamelen = dnamelen;
+ *prev_type = type;
+ *prev_dclass = dclass;
+ return 1;
+}
+
+/**
+ * Parse query section.
+ * @param pkt: packet, position at call must be at start of query section.
+ * at end position is after query section.
+ * @param msg: store results here.
+ * @return: 0 if OK, or rcode on error.
+ */
+static int
+parse_query_section(sldns_buffer* pkt, struct msg_parse* msg)
+{
+ if(msg->qdcount == 0)
+ return 0;
+ if(msg->qdcount > 1)
+ return LDNS_RCODE_FORMERR;
+ log_assert(msg->qdcount == 1);
+ if(sldns_buffer_remaining(pkt) <= 0)
+ return LDNS_RCODE_FORMERR;
+ msg->qname = sldns_buffer_current(pkt);
+ if((msg->qname_len = pkt_dname_len(pkt)) == 0)
+ return LDNS_RCODE_FORMERR;
+ if(sldns_buffer_remaining(pkt) < sizeof(uint16_t)*2)
+ return LDNS_RCODE_FORMERR;
+ msg->qtype = sldns_buffer_read_u16(pkt);
+ msg->qclass = sldns_buffer_read_u16(pkt);
+ return 0;
+}
+
+size_t
+get_rdf_size(sldns_rdf_type rdf)
+{
+ switch(rdf) {
+ case LDNS_RDF_TYPE_CLASS:
+ case LDNS_RDF_TYPE_ALG:
+ case LDNS_RDF_TYPE_INT8:
+ return 1;
+ break;
+ case LDNS_RDF_TYPE_INT16:
+ case LDNS_RDF_TYPE_TYPE:
+ case LDNS_RDF_TYPE_CERT_ALG:
+ return 2;
+ break;
+ case LDNS_RDF_TYPE_INT32:
+ case LDNS_RDF_TYPE_TIME:
+ case LDNS_RDF_TYPE_A:
+ case LDNS_RDF_TYPE_PERIOD:
+ return 4;
+ break;
+ case LDNS_RDF_TYPE_TSIGTIME:
+ return 6;
+ break;
+ case LDNS_RDF_TYPE_AAAA:
+ return 16;
+ break;
+ default:
+ log_assert(0); /* add type above */
+ /* only types that appear before a domain *
+ * name are needed. rest is simply copied. */
+ }
+ return 0;
+}
+
+/** calculate the size of one rr */
+static int
+calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr)
+{
+ const sldns_rr_descriptor* desc;
+ uint16_t pkt_len; /* length of rr inside the packet */
+ rr->size = sizeof(uint16_t); /* the rdatalen */
+ sldns_buffer_skip(pkt, 4); /* skip ttl */
+ pkt_len = sldns_buffer_read_u16(pkt);
+ if(sldns_buffer_remaining(pkt) < pkt_len)
+ return 0;
+ desc = sldns_rr_descript(type);
+ if(pkt_len > 0 && desc && desc->_dname_count > 0) {
+ int count = (int)desc->_dname_count;
+ int rdf = 0;
+ size_t len;
+ size_t oldpos;
+ /* skip first part. */
+ while(pkt_len > 0 && count) {
+ switch(desc->_wireformat[rdf]) {
+ case LDNS_RDF_TYPE_DNAME:
+ /* decompress every domain name */
+ oldpos = sldns_buffer_position(pkt);
+ if((len = pkt_dname_len(pkt)) == 0)
+ return 0; /* malformed dname */
+ if(sldns_buffer_position(pkt)-oldpos > pkt_len)
+ return 0; /* dname exceeds rdata */
+ pkt_len -= sldns_buffer_position(pkt)-oldpos;
+ rr->size += len;
+ count--;
+ len = 0;
+ break;
+ case LDNS_RDF_TYPE_STR:
+ if(pkt_len < 1) {
+ /* NOTREACHED, due to 'while(>0)' */
+ return 0; /* len byte exceeds rdata */
+ }
+ len = sldns_buffer_current(pkt)[0] + 1;
+ break;
+ default:
+ len = get_rdf_size(desc->_wireformat[rdf]);
+ }
+ if(len) {
+ if(pkt_len < len)
+ return 0; /* exceeds rdata */
+ pkt_len -= len;
+ sldns_buffer_skip(pkt, (ssize_t)len);
+ rr->size += len;
+ }
+ rdf++;
+ }
+ }
+ /* remaining rdata */
+ rr->size += pkt_len;
+ sldns_buffer_skip(pkt, (ssize_t)pkt_len);
+ return 1;
+}
+
+/** skip rr ttl and rdata */
+static int
+skip_ttl_rdata(sldns_buffer* pkt)
+{
+ uint16_t rdatalen;
+ if(sldns_buffer_remaining(pkt) < 6) /* ttl + rdatalen */
+ return 0;
+ sldns_buffer_skip(pkt, 4); /* ttl */
+ rdatalen = sldns_buffer_read_u16(pkt);
+ if(sldns_buffer_remaining(pkt) < rdatalen)
+ return 0;
+ sldns_buffer_skip(pkt, (ssize_t)rdatalen);
+ return 1;
+}
+
+/** see if RRSIG is a duplicate of another */
+static int
+sig_is_double(sldns_buffer* pkt, struct rrset_parse* rrset, uint8_t* ttldata)
+{
+ uint16_t rlen, siglen;
+ size_t pos = sldns_buffer_position(pkt);
+ struct rr_parse* sig;
+ if(sldns_buffer_remaining(pkt) < 6)
+ return 0;
+ sldns_buffer_skip(pkt, 4); /* ttl */
+ rlen = sldns_buffer_read_u16(pkt);
+ if(sldns_buffer_remaining(pkt) < rlen) {
+ sldns_buffer_set_position(pkt, pos);
+ return 0;
+ }
+ sldns_buffer_set_position(pkt, pos);
+
+ sig = rrset->rrsig_first;
+ while(sig) {
+ /* check if rdatalen is same */
+ memmove(&siglen, sig->ttl_data+4, sizeof(siglen));
+ siglen = ntohs(siglen);
+ /* checks if data in packet is exactly the same, this means
+ * also dname in rdata is the same, but rrsig is not allowed
+ * to have compressed dnames anyway. If it is compressed anyway
+ * it will lead to duplicate rrs for qtype=RRSIG. (or ANY).
+ *
+ * Cannot use sig->size because size of the other one is not
+ * calculated yet.
+ */
+ if(siglen == rlen) {
+ if(siglen>0 && memcmp(sig->ttl_data+6, ttldata+6,
+ siglen) == 0) {
+ /* same! */
+ return 1;
+ }
+ }
+ sig = sig->next;
+ }
+ return 0;
+}
+
+/** Add rr (from packet here) to rrset, skips rr */
+static int
+add_rr_to_rrset(struct rrset_parse* rrset, sldns_buffer* pkt,
+ struct msg_parse* msg, struct regional* region,
+ sldns_pkt_section section, uint16_t type)
+{
+ struct rr_parse* rr;
+ /* check section of rrset. */
+ if(rrset->section != section && type != LDNS_RR_TYPE_RRSIG &&
+ rrset->type != LDNS_RR_TYPE_RRSIG) {
+ /* silently drop it - we drop the last part, since
+ * trust in rr data depends on the section it is in.
+ * the less trustworthy part is discarded.
+ * also the last part is more likely to be incomplete.
+ * RFC 2181: must put RRset only once in response. */
+ /*
+ verbose(VERB_QUERY, "Packet contains rrset data in "
+ "multiple sections, dropped last part.");
+ log_buf(VERB_QUERY, "packet was", pkt);
+ */
+ /* forwards */
+ if(!skip_ttl_rdata(pkt))
+ return LDNS_RCODE_FORMERR;
+ return 0;
+ }
+
+ if( (msg->qtype == LDNS_RR_TYPE_RRSIG ||
+ msg->qtype == LDNS_RR_TYPE_ANY)
+ && sig_is_double(pkt, rrset, sldns_buffer_current(pkt))) {
+ if(!skip_ttl_rdata(pkt))
+ return LDNS_RCODE_FORMERR;
+ return 0;
+ }
+
+ /* create rr */
+ if(!(rr = (struct rr_parse*)regional_alloc(region, sizeof(*rr))))
+ return LDNS_RCODE_SERVFAIL;
+ rr->outside_packet = 0;
+ rr->ttl_data = sldns_buffer_current(pkt);
+ rr->next = 0;
+ if(type == LDNS_RR_TYPE_RRSIG && rrset->type != LDNS_RR_TYPE_RRSIG) {
+ if(rrset->rrsig_last)
+ rrset->rrsig_last->next = rr;
+ else rrset->rrsig_first = rr;
+ rrset->rrsig_last = rr;
+ rrset->rrsig_count++;
+ } else {
+ if(rrset->rr_last)
+ rrset->rr_last->next = rr;
+ else rrset->rr_first = rr;
+ rrset->rr_last = rr;
+ rrset->rr_count++;
+ }
+
+ /* calc decompressed size */
+ if(!calc_size(pkt, type, rr))
+ return LDNS_RCODE_FORMERR;
+ rrset->size += rr->size;
+
+ return 0;
+}
+
+/**
+ * Parse packet RR section, for answer, authority and additional sections.
+ * @param pkt: packet, position at call must be at start of section.
+ * at end position is after section.
+ * @param msg: store results here.
+ * @param region: how to alloc results.
+ * @param section: section enum.
+ * @param num_rrs: how many rrs are in the section.
+ * @param num_rrsets: returns number of rrsets in the section.
+ * @return: 0 if OK, or rcode on error.
+ */
+static int
+parse_section(sldns_buffer* pkt, struct msg_parse* msg,
+ struct regional* region, sldns_pkt_section section,
+ uint16_t num_rrs, size_t* num_rrsets)
+{
+ uint16_t i;
+ uint8_t* dname, *prev_dname_f = NULL, *prev_dname_l = NULL;
+ size_t dnamelen, prev_dnamelen = 0;
+ uint16_t type, prev_type = 0;
+ uint16_t dclass, prev_dclass = 0;
+ uint32_t rrset_flags = 0;
+ hashvalue_t hash = 0;
+ struct rrset_parse* rrset = NULL;
+ int r;
+
+ if(num_rrs == 0)
+ return 0;
+ if(sldns_buffer_remaining(pkt) <= 0)
+ return LDNS_RCODE_FORMERR;
+ for(i=0; i<num_rrs; i++) {
+ /* parse this RR. */
+ dname = sldns_buffer_current(pkt);
+ if((dnamelen = pkt_dname_len(pkt)) == 0)
+ return LDNS_RCODE_FORMERR;
+ if(sldns_buffer_remaining(pkt) < 10) /* type, class, ttl, len */
+ return LDNS_RCODE_FORMERR;
+ type = sldns_buffer_read_u16(pkt);
+ sldns_buffer_read(pkt, &dclass, sizeof(dclass));
+
+ if(0) { /* debug show what is being parsed. */
+ if(type == LDNS_RR_TYPE_RRSIG) {
+ uint16_t t;
+ if(pkt_rrsig_covered(pkt,
+ sldns_buffer_current(pkt), &t))
+ fprintf(stderr, "parse of %s(%d) [%s(%d)]",
+ sldns_rr_descript(type)?
+ sldns_rr_descript(type)->_name: "??",
+ (int)type,
+ sldns_rr_descript(t)?
+ sldns_rr_descript(t)->_name: "??",
+ (int)t);
+ } else
+ fprintf(stderr, "parse of %s(%d)",
+ sldns_rr_descript(type)?
+ sldns_rr_descript(type)->_name: "??",
+ (int)type);
+ fprintf(stderr, " %s(%d) ",
+ sldns_lookup_by_id(sldns_rr_classes,
+ (int)ntohs(dclass))?sldns_lookup_by_id(
+ sldns_rr_classes, (int)ntohs(dclass))->name:
+ "??", (int)ntohs(dclass));
+ dname_print(stderr, pkt, dname);
+ fprintf(stderr, "\n");
+ }
+
+ /* see if it is part of an existing RR set */
+ if(!find_rrset(msg, pkt, dname, dnamelen, type, dclass, &hash,
+ &rrset_flags, &prev_dname_f, &prev_dname_l,
+ &prev_dnamelen, &prev_type, &prev_dclass, &rrset,
+ section, region))
+ return LDNS_RCODE_SERVFAIL;
+ if(!rrset) {
+ /* it is a new RR set. hash&flags already calculated.*/
+ (*num_rrsets)++;
+ rrset = new_rrset(msg, dname, dnamelen, type, dclass,
+ hash, rrset_flags, section, region);
+ if(!rrset)
+ return LDNS_RCODE_SERVFAIL;
+ }
+ else if(0) {
+ fprintf(stderr, "is part of existing: ");
+ dname_print(stderr, pkt, rrset->dname);
+ fprintf(stderr, " type %s(%d)\n",
+ sldns_rr_descript(rrset->type)?
+ sldns_rr_descript(rrset->type)->_name: "??",
+ (int)rrset->type);
+ }
+ /* add to rrset. */
+ if((r=add_rr_to_rrset(rrset, pkt, msg, region, section,
+ type)) != 0)
+ return r;
+ }
+ return 0;
+}
+
+int
+parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
+{
+ int ret;
+ if(sldns_buffer_remaining(pkt) < LDNS_HEADER_SIZE)
+ return LDNS_RCODE_FORMERR;
+ /* read the header */
+ sldns_buffer_read(pkt, &msg->id, sizeof(uint16_t));
+ msg->flags = sldns_buffer_read_u16(pkt);
+ msg->qdcount = sldns_buffer_read_u16(pkt);
+ msg->ancount = sldns_buffer_read_u16(pkt);
+ msg->nscount = sldns_buffer_read_u16(pkt);
+ msg->arcount = sldns_buffer_read_u16(pkt);
+ if(msg->qdcount > 1)
+ return LDNS_RCODE_FORMERR;
+ if((ret = parse_query_section(pkt, msg)) != 0)
+ return ret;
+ if((ret = parse_section(pkt, msg, region, LDNS_SECTION_ANSWER,
+ msg->ancount, &msg->an_rrsets)) != 0)
+ return ret;
+ if((ret = parse_section(pkt, msg, region, LDNS_SECTION_AUTHORITY,
+ msg->nscount, &msg->ns_rrsets)) != 0)
+ return ret;
+ if(sldns_buffer_remaining(pkt) == 0 && msg->arcount == 1) {
+ /* BIND accepts leniently that an EDNS record is missing.
+ * so, we do too. */
+ } else if((ret = parse_section(pkt, msg, region,
+ LDNS_SECTION_ADDITIONAL, msg->arcount, &msg->ar_rrsets)) != 0)
+ return ret;
+ /* if(sldns_buffer_remaining(pkt) > 0) { */
+ /* there is spurious data at end of packet. ignore */
+ /* } */
+ msg->rrset_count = msg->an_rrsets + msg->ns_rrsets + msg->ar_rrsets;
+ return 0;
+}
+
+int
+parse_extract_edns(struct msg_parse* msg, struct edns_data* edns)
+{
+ struct rrset_parse* rrset = msg->rrset_first;
+ struct rrset_parse* prev = 0;
+ struct rrset_parse* found = 0;
+ struct rrset_parse* found_prev = 0;
+ /* since the class encodes the UDP size, we cannot use hash table to
+ * find the EDNS OPT record. Scan the packet. */
+ while(rrset) {
+ if(rrset->type == LDNS_RR_TYPE_OPT) {
+ /* only one OPT RR allowed. */
+ if(found) return LDNS_RCODE_FORMERR;
+ /* found it! */
+ found_prev = prev;
+ found = rrset;
+ }
+ prev = rrset;
+ rrset = rrset->rrset_all_next;
+ }
+ if(!found) {
+ memset(edns, 0, sizeof(*edns));
+ edns->udp_size = 512;
+ return 0;
+ }
+ /* check the found RRset */
+ /* most lenient check possible. ignore dname, use last opt */
+ if(found->section != LDNS_SECTION_ADDITIONAL)
+ return LDNS_RCODE_FORMERR;
+ if(found->rr_count == 0)
+ return LDNS_RCODE_FORMERR;
+ if(0) { /* strict checking of dname and RRcount */
+ if(found->dname_len != 1 || !found->dname
+ || found->dname[0] != 0) return LDNS_RCODE_FORMERR;
+ if(found->rr_count != 1) return LDNS_RCODE_FORMERR;
+ }
+ log_assert(found->rr_first && found->rr_last);
+
+ /* remove from packet */
+ if(found_prev) found_prev->rrset_all_next = found->rrset_all_next;
+ else msg->rrset_first = found->rrset_all_next;
+ if(found == msg->rrset_last)
+ msg->rrset_last = found_prev;
+ msg->arcount --;
+ msg->ar_rrsets --;
+ msg->rrset_count --;
+
+ /* take the data ! */
+ edns->edns_present = 1;
+ edns->ext_rcode = found->rr_last->ttl_data[0];
+ edns->edns_version = found->rr_last->ttl_data[1];
+ edns->bits = sldns_read_uint16(&found->rr_last->ttl_data[2]);
+ edns->udp_size = ntohs(found->rrset_class);
+ /* ignore rdata and rrsigs */
+ return 0;
+}
+
+int
+parse_edns_from_pkt(sldns_buffer* pkt, struct edns_data* edns)
+{
+ log_assert(LDNS_QDCOUNT(sldns_buffer_begin(pkt)) == 1);
+ log_assert(LDNS_ANCOUNT(sldns_buffer_begin(pkt)) == 0);
+ log_assert(LDNS_NSCOUNT(sldns_buffer_begin(pkt)) == 0);
+ /* check edns section is present */
+ if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) > 1) {
+ return LDNS_RCODE_FORMERR;
+ }
+ if(LDNS_ARCOUNT(sldns_buffer_begin(pkt)) == 0) {
+ memset(edns, 0, sizeof(*edns));
+ edns->udp_size = 512;
+ return 0;
+ }
+ /* domain name must be the root of length 1. */
+ if(pkt_dname_len(pkt) != 1)
+ return LDNS_RCODE_FORMERR;
+ if(sldns_buffer_remaining(pkt) < 10) /* type, class, ttl, rdatalen */
+ return LDNS_RCODE_FORMERR;
+ if(sldns_buffer_read_u16(pkt) != LDNS_RR_TYPE_OPT)
+ return LDNS_RCODE_FORMERR;
+ edns->edns_present = 1;
+ edns->udp_size = sldns_buffer_read_u16(pkt); /* class is udp size */
+ edns->ext_rcode = sldns_buffer_read_u8(pkt); /* ttl used for bits */
+ edns->edns_version = sldns_buffer_read_u8(pkt);
+ edns->bits = sldns_buffer_read_u16(pkt);
+ /* ignore rdata and rrsigs */
+ return 0;
+}
diff --git a/external/unbound/util/data/msgparse.h b/external/unbound/util/data/msgparse.h
new file mode 100644
index 000000000..221a45aad
--- /dev/null
+++ b/external/unbound/util/data/msgparse.h
@@ -0,0 +1,301 @@
+/*
+ * util/data/msgparse.h - parse wireformat DNS messages.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ * Contains message parsing data structures.
+ * These point back into the packet buffer.
+ *
+ * During parsing RRSIGS are put together with the rrsets they (claim to) sign.
+ * This process works as follows:
+ * o if RRSIG follows the data rrset, it is added to the rrset rrsig list.
+ * o if no matching data rrset is found, the RRSIG becomes a new rrset.
+ * o If the data rrset later follows the RRSIG
+ * o See if the RRSIG rrset contains multiple types, and needs to
+ * have the rrsig(s) for that data type split off.
+ * o Put the data rr as data type in the rrset and rrsig in list.
+ * o RRSIGs are allowed to move to a different section. The section of
+ * the data item is used for the final rrset.
+ * o multiple signatures over an RRset are possible.
+ *
+ * For queries of qtype=RRSIG, some special handling is needed, to avoid
+ * splitting the RRSIG in the answer section.
+ * o duplicate, not split, RRSIGs from the answer section, if qtype=RRSIG.
+ * o check for doubles in the rrsig list when adding an RRSIG to data,
+ * so that a data rrset is signed by RRSIGs with different rdata.
+ * when qtype=RRSIG.
+ * This will move the RRSIG from the answer section to sign the data further
+ * in the packet (if possible). If then after that, more RRSIGs are found
+ * that sign the data as well, doubles are removed.
+ */
+
+#ifndef UTIL_DATA_MSGPARSE_H
+#define UTIL_DATA_MSGPARSE_H
+#include "util/storage/lruhash.h"
+#include "ldns/pkthdr.h"
+#include "ldns/rrdef.h"
+struct sldns_buffer;
+struct rrset_parse;
+struct rr_parse;
+struct regional;
+
+/** number of buckets in parse rrset hash table. Must be power of 2. */
+#define PARSE_TABLE_SIZE 32
+/** Maximum TTL that is allowed. */
+extern time_t MAX_TTL;
+/** Minimum TTL that is allowed. */
+extern time_t MIN_TTL;
+/** Negative cache time (for entries without any RRs.) */
+#define NORR_TTL 5 /* seconds */
+
+/**
+ * Data stored in scratch pad memory during parsing.
+ * Stores the data that will enter into the msgreply and packet result.
+ */
+struct msg_parse {
+ /** id from message, network format. */
+ uint16_t id;
+ /** flags from message, host format. */
+ uint16_t flags;
+ /** count of RRs, host format */
+ uint16_t qdcount;
+ /** count of RRs, host format */
+ uint16_t ancount;
+ /** count of RRs, host format */
+ uint16_t nscount;
+ /** count of RRs, host format */
+ uint16_t arcount;
+ /** count of RRsets per section. */
+ size_t an_rrsets;
+ /** count of RRsets per section. */
+ size_t ns_rrsets;
+ /** count of RRsets per section. */
+ size_t ar_rrsets;
+ /** total number of rrsets found. */
+ size_t rrset_count;
+
+ /** query dname (pointer to start location in packet, NULL if none */
+ uint8_t* qname;
+ /** length of query dname in octets, 0 if none */
+ size_t qname_len;
+ /** query type, host order. 0 if qdcount=0 */
+ uint16_t qtype;
+ /** query class, host order. 0 if qdcount=0 */
+ uint16_t qclass;
+
+ /**
+ * Hash table array used during parsing to lookup rrset types.
+ * Based on name, type, class. Same hash value as in rrset cache.
+ */
+ struct rrset_parse* hashtable[PARSE_TABLE_SIZE];
+
+ /** linked list of rrsets that have been found (in order). */
+ struct rrset_parse* rrset_first;
+ /** last element of rrset list. */
+ struct rrset_parse* rrset_last;
+};
+
+/**
+ * Data stored for an rrset during parsing.
+ */
+struct rrset_parse {
+ /** next in hash bucket */
+ struct rrset_parse* rrset_bucket_next;
+ /** next in list of all rrsets */
+ struct rrset_parse* rrset_all_next;
+ /** hash value of rrset */
+ hashvalue_t hash;
+ /** which section was it found in: one of
+ * LDNS_SECTION_ANSWER, LDNS_SECTION_AUTHORITY, LDNS_SECTION_ADDITIONAL
+ */
+ sldns_pkt_section section;
+ /** start of (possibly compressed) dname in packet */
+ uint8_t* dname;
+ /** length of the dname uncompressed wireformat */
+ size_t dname_len;
+ /** type, host order. */
+ uint16_t type;
+ /** class, network order. var name so that it is not a c++ keyword. */
+ uint16_t rrset_class;
+ /** the flags for the rrset, like for packedrrset */
+ uint32_t flags;
+ /** number of RRs in the rr list */
+ size_t rr_count;
+ /** sum of RR rdata sizes */
+ size_t size;
+ /** linked list of RRs in this rrset. */
+ struct rr_parse* rr_first;
+ /** last in list of RRs in this rrset. */
+ struct rr_parse* rr_last;
+ /** number of RRSIGs over this rrset. */
+ size_t rrsig_count;
+ /** linked list of RRsig RRs over this rrset. */
+ struct rr_parse* rrsig_first;
+ /** last in list of RRSIG RRs over this rrset. */
+ struct rr_parse* rrsig_last;
+};
+
+/**
+ * Data stored for an RR during parsing.
+ */
+struct rr_parse {
+ /**
+ * Pointer to the RR. Points to start of TTL value in the packet.
+ * Rdata length and rdata follow it.
+ * its dname, type and class are the same and stored for the rrset.
+ */
+ uint8_t* ttl_data;
+ /** true if ttl_data is not part of the packet, but elsewhere in mem.
+ * Set for generated CNAMEs for DNAMEs. */
+ int outside_packet;
+ /** the length of the rdata if allocated (with no dname compression)*/
+ size_t size;
+ /** next in list of RRs. */
+ struct rr_parse* next;
+};
+
+/** Check if label length is first octet of a compression pointer, pass u8. */
+#define LABEL_IS_PTR(x) ( ((x)&0xc0) == 0xc0 )
+/** Calculate destination offset of a compression pointer. pass first and
+ * second octets of the compression pointer. */
+#define PTR_OFFSET(x, y) ( ((x)&0x3f)<<8 | (y) )
+/** create a compression pointer to the given offset. */
+#define PTR_CREATE(offset) ((uint16_t)(0xc000 | (offset)))
+
+/** error codes, extended with EDNS, so > 15. */
+#define EDNS_RCODE_BADVERS 16 /** bad EDNS version */
+/** largest valid compression offset */
+#define PTR_MAX_OFFSET 0x3fff
+
+/**
+ * EDNS data storage
+ * EDNS rdata is ignored.
+ */
+struct edns_data {
+ /** if EDNS OPT record was present */
+ int edns_present;
+ /** Extended RCODE */
+ uint8_t ext_rcode;
+ /** The EDNS version number */
+ uint8_t edns_version;
+ /** the EDNS bits field from ttl (host order): Z */
+ uint16_t bits;
+ /** UDP reassembly size. */
+ uint16_t udp_size;
+};
+
+/**
+ * Obtain size in the packet of an rr type, that is before dname type.
+ * Do TYPE_DNAME, and type STR, yourself. Gives size for most regular types.
+ * @param rdf: the rdf type from the descriptor.
+ * @return: size in octets. 0 on failure.
+ */
+size_t get_rdf_size(sldns_rdf_type rdf);
+
+/**
+ * Parse the packet.
+ * @param pkt: packet, position at call must be at start of packet.
+ * at end position is after packet.
+ * @param msg: where to store results.
+ * @param region: how to alloc results.
+ * @return: 0 if OK, or rcode on error.
+ */
+int parse_packet(struct sldns_buffer* pkt, struct msg_parse* msg,
+ struct regional* region);
+
+/**
+ * After parsing the packet, extract EDNS data from packet.
+ * If not present this is noted in the data structure.
+ * If a parse error happens, an error code is returned.
+ *
+ * Quirks:
+ * o ignores OPT rdata.
+ * o ignores OPT owner name.
+ * o ignores extra OPT records, except the last one in the packet.
+ *
+ * @param msg: parsed message structure. Modified on exit, if EDNS was present
+ * it is removed from the additional section.
+ * @param edns: the edns data is stored here. Does not have to be initialised.
+ * @return: 0 on success. or an RCODE on an error.
+ * RCODE formerr if OPT in wrong section, and so on.
+ */
+int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns);
+
+/**
+ * If EDNS data follows a query section, extract it and initialize edns struct.
+ * @param pkt: the packet. position at start must be right after the query
+ * section. At end, right after EDNS data or no movement if failed.
+ * @param edns: the edns data allocated by the caller. Does not have to be
+ * initialised.
+ * @return: 0 on success, or an RCODE on error.
+ * RCODE formerr if OPT is badly formatted and so on.
+ */
+int parse_edns_from_pkt(struct sldns_buffer* pkt, struct edns_data* edns);
+
+/**
+ * Calculate hash value for rrset in packet.
+ * @param pkt: the packet.
+ * @param dname: pointer to uncompressed dname, or compressed dname in packet.
+ * @param type: rrset type in host order.
+ * @param dclass: rrset class in network order.
+ * @param rrset_flags: rrset flags (same as packed_rrset flags).
+ * @return hash value
+ */
+hashvalue_t pkt_hash_rrset(struct sldns_buffer* pkt, uint8_t* dname, uint16_t type,
+ uint16_t dclass, uint32_t rrset_flags);
+
+/**
+ * Lookup in msg hashtable to find a rrset.
+ * @param msg: with the hashtable.
+ * @param pkt: packet for compressed names.
+ * @param h: hash value
+ * @param rrset_flags: flags of rrset sought for.
+ * @param dname: name of rrset sought for.
+ * @param dnamelen: len of dname.
+ * @param type: rrset type, host order.
+ * @param dclass: rrset class, network order.
+ * @return NULL or the rrset_parse if found.
+ */
+struct rrset_parse* msgparse_hashtable_lookup(struct msg_parse* msg,
+ struct sldns_buffer* pkt, hashvalue_t h, uint32_t rrset_flags,
+ uint8_t* dname, size_t dnamelen, uint16_t type, uint16_t dclass);
+
+/**
+ * Remove rrset from hash table.
+ * @param msg: with hashtable.
+ * @param rrset: with hash value and id info.
+ */
+void msgparse_bucket_remove(struct msg_parse* msg, struct rrset_parse* rrset);
+
+#endif /* UTIL_DATA_MSGPARSE_H */
diff --git a/external/unbound/util/data/msgreply.c b/external/unbound/util/data/msgreply.c
new file mode 100644
index 000000000..126e7bef4
--- /dev/null
+++ b/external/unbound/util/data/msgreply.c
@@ -0,0 +1,830 @@
+/*
+ * util/data/msgreply.c - store message and reply data.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 a data structure to store a message and its reply.
+ */
+
+#include "config.h"
+#include "util/data/msgreply.h"
+#include "util/storage/lookup3.h"
+#include "util/log.h"
+#include "util/alloc.h"
+#include "util/netevent.h"
+#include "util/net_help.h"
+#include "util/data/dname.h"
+#include "util/regional.h"
+#include "util/data/msgparse.h"
+#include "util/data/msgencode.h"
+#include "ldns/sbuffer.h"
+#include "ldns/wire2str.h"
+
+/** MAX TTL default for messages and rrsets */
+time_t MAX_TTL = 3600 * 24 * 10; /* ten days */
+/** MIN TTL default for messages and rrsets */
+time_t MIN_TTL = 0;
+
+/** allocate qinfo, return 0 on error */
+static int
+parse_create_qinfo(sldns_buffer* pkt, struct msg_parse* msg,
+ struct query_info* qinf, struct regional* region)
+{
+ if(msg->qname) {
+ if(region)
+ qinf->qname = (uint8_t*)regional_alloc(region,
+ msg->qname_len);
+ else qinf->qname = (uint8_t*)malloc(msg->qname_len);
+ if(!qinf->qname) return 0;
+ dname_pkt_copy(pkt, qinf->qname, msg->qname);
+ } else qinf->qname = 0;
+ qinf->qname_len = msg->qname_len;
+ qinf->qtype = msg->qtype;
+ qinf->qclass = msg->qclass;
+ return 1;
+}
+
+/** constructor for replyinfo */
+struct reply_info*
+construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
+ time_t ttl, time_t prettl, size_t an, size_t ns, size_t ar,
+ size_t total, enum sec_status sec)
+{
+ struct reply_info* rep;
+ /* rrset_count-1 because the first ref is part of the struct. */
+ size_t s = sizeof(struct reply_info) - sizeof(struct rrset_ref) +
+ sizeof(struct ub_packed_rrset_key*) * total;
+ if(region)
+ rep = (struct reply_info*)regional_alloc(region, s);
+ else rep = (struct reply_info*)malloc(s +
+ sizeof(struct rrset_ref) * (total));
+ if(!rep)
+ return NULL;
+ rep->flags = flags;
+ rep->qdcount = qd;
+ rep->ttl = ttl;
+ rep->prefetch_ttl = prettl;
+ rep->an_numrrsets = an;
+ rep->ns_numrrsets = ns;
+ rep->ar_numrrsets = ar;
+ rep->rrset_count = total;
+ rep->security = sec;
+ rep->authoritative = 0;
+ /* array starts after the refs */
+ if(region)
+ rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[0]);
+ else rep->rrsets = (struct ub_packed_rrset_key**)&(rep->ref[total]);
+ /* zero the arrays to assist cleanup in case of malloc failure */
+ memset( rep->rrsets, 0, sizeof(struct ub_packed_rrset_key*) * total);
+ if(!region)
+ memset( &rep->ref[0], 0, sizeof(struct rrset_ref) * total);
+ return rep;
+}
+
+/** allocate replyinfo, return 0 on error */
+static int
+parse_create_repinfo(struct msg_parse* msg, struct reply_info** rep,
+ struct regional* region)
+{
+ *rep = construct_reply_info_base(region, msg->flags, msg->qdcount, 0,
+ 0, msg->an_rrsets, msg->ns_rrsets, msg->ar_rrsets,
+ msg->rrset_count, sec_status_unchecked);
+ if(!*rep)
+ return 0;
+ return 1;
+}
+
+/** allocate (special) rrset keys, return 0 on error */
+static int
+repinfo_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
+ struct regional* region)
+{
+ size_t i;
+ for(i=0; i<rep->rrset_count; i++) {
+ if(region) {
+ rep->rrsets[i] = (struct ub_packed_rrset_key*)
+ regional_alloc(region,
+ sizeof(struct ub_packed_rrset_key));
+ if(rep->rrsets[i]) {
+ memset(rep->rrsets[i], 0,
+ sizeof(struct ub_packed_rrset_key));
+ rep->rrsets[i]->entry.key = rep->rrsets[i];
+ }
+ }
+ else rep->rrsets[i] = alloc_special_obtain(alloc);
+ if(!rep->rrsets[i])
+ return 0;
+ rep->rrsets[i]->entry.data = NULL;
+ }
+ return 1;
+}
+
+/** do the rdata copy */
+static int
+rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to,
+ struct rr_parse* rr, time_t* rr_ttl, uint16_t type)
+{
+ uint16_t pkt_len;
+ const sldns_rr_descriptor* desc;
+
+ *rr_ttl = sldns_read_uint32(rr->ttl_data);
+ /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */
+ if(*rr_ttl & 0x80000000U)
+ *rr_ttl = 0;
+ if(*rr_ttl < MIN_TTL)
+ *rr_ttl = MIN_TTL;
+ if(*rr_ttl < data->ttl)
+ data->ttl = *rr_ttl;
+
+ if(rr->outside_packet) {
+ /* uncompressed already, only needs copy */
+ memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size);
+ return 1;
+ }
+
+ sldns_buffer_set_position(pkt, (size_t)
+ (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t)));
+ /* insert decompressed size into rdata len stored in memory */
+ /* -2 because rdatalen bytes are not included. */
+ pkt_len = htons(rr->size - 2);
+ memmove(to, &pkt_len, sizeof(uint16_t));
+ to += 2;
+ /* read packet rdata len */
+ pkt_len = sldns_buffer_read_u16(pkt);
+ if(sldns_buffer_remaining(pkt) < pkt_len)
+ return 0;
+ desc = sldns_rr_descript(type);
+ if(pkt_len > 0 && desc && desc->_dname_count > 0) {
+ int count = (int)desc->_dname_count;
+ int rdf = 0;
+ size_t len;
+ size_t oldpos;
+ /* decompress dnames. */
+ while(pkt_len > 0 && count) {
+ switch(desc->_wireformat[rdf]) {
+ case LDNS_RDF_TYPE_DNAME:
+ oldpos = sldns_buffer_position(pkt);
+ dname_pkt_copy(pkt, to,
+ sldns_buffer_current(pkt));
+ to += pkt_dname_len(pkt);
+ pkt_len -= sldns_buffer_position(pkt)-oldpos;
+ count--;
+ len = 0;
+ break;
+ case LDNS_RDF_TYPE_STR:
+ len = sldns_buffer_current(pkt)[0] + 1;
+ break;
+ default:
+ len = get_rdf_size(desc->_wireformat[rdf]);
+ break;
+ }
+ if(len) {
+ memmove(to, sldns_buffer_current(pkt), len);
+ to += len;
+ sldns_buffer_skip(pkt, (ssize_t)len);
+ log_assert(len <= pkt_len);
+ pkt_len -= len;
+ }
+ rdf++;
+ }
+ }
+ /* copy remaining rdata */
+ if(pkt_len > 0)
+ memmove(to, sldns_buffer_current(pkt), pkt_len);
+
+ return 1;
+}
+
+/** copy over the data into packed rrset */
+static int
+parse_rr_copy(sldns_buffer* pkt, struct rrset_parse* pset,
+ struct packed_rrset_data* data)
+{
+ size_t i;
+ struct rr_parse* rr = pset->rr_first;
+ uint8_t* nextrdata;
+ size_t total = pset->rr_count + pset->rrsig_count;
+ data->ttl = MAX_TTL;
+ data->count = pset->rr_count;
+ data->rrsig_count = pset->rrsig_count;
+ data->trust = rrset_trust_none;
+ data->security = sec_status_unchecked;
+ /* layout: struct - rr_len - rr_data - rr_ttl - rdata - rrsig */
+ data->rr_len = (size_t*)((uint8_t*)data +
+ sizeof(struct packed_rrset_data));
+ data->rr_data = (uint8_t**)&(data->rr_len[total]);
+ data->rr_ttl = (time_t*)&(data->rr_data[total]);
+ nextrdata = (uint8_t*)&(data->rr_ttl[total]);
+ for(i=0; i<data->count; i++) {
+ data->rr_len[i] = rr->size;
+ data->rr_data[i] = nextrdata;
+ nextrdata += rr->size;
+ if(!rdata_copy(pkt, data, data->rr_data[i], rr,
+ &data->rr_ttl[i], pset->type))
+ return 0;
+ rr = rr->next;
+ }
+ /* if rrsig, its rdata is at nextrdata */
+ rr = pset->rrsig_first;
+ for(i=data->count; i<total; i++) {
+ data->rr_len[i] = rr->size;
+ data->rr_data[i] = nextrdata;
+ nextrdata += rr->size;
+ if(!rdata_copy(pkt, data, data->rr_data[i], rr,
+ &data->rr_ttl[i], LDNS_RR_TYPE_RRSIG))
+ return 0;
+ rr = rr->next;
+ }
+ return 1;
+}
+
+/** create rrset return 0 on failure */
+static int
+parse_create_rrset(sldns_buffer* pkt, struct rrset_parse* pset,
+ struct packed_rrset_data** data, struct regional* region)
+{
+ /* allocate */
+ size_t s = sizeof(struct packed_rrset_data) +
+ (pset->rr_count + pset->rrsig_count) *
+ (sizeof(size_t)+sizeof(uint8_t*)+sizeof(time_t)) +
+ pset->size;
+ if(region)
+ *data = regional_alloc(region, s);
+ else *data = malloc(s);
+ if(!*data)
+ return 0;
+ /* copy & decompress */
+ if(!parse_rr_copy(pkt, pset, *data)) {
+ if(!region) free(*data);
+ return 0;
+ }
+ return 1;
+}
+
+/** get trust value for rrset */
+static enum rrset_trust
+get_rrset_trust(struct msg_parse* msg, struct rrset_parse* rrset)
+{
+ uint16_t AA = msg->flags & BIT_AA;
+ if(rrset->section == LDNS_SECTION_ANSWER) {
+ if(AA) {
+ /* RFC2181 says remainder of CNAME chain is nonauth*/
+ if(msg->rrset_first &&
+ msg->rrset_first->section==LDNS_SECTION_ANSWER
+ && msg->rrset_first->type==LDNS_RR_TYPE_CNAME){
+ if(rrset == msg->rrset_first)
+ return rrset_trust_ans_AA;
+ else return rrset_trust_ans_noAA;
+ }
+ if(msg->rrset_first &&
+ msg->rrset_first->section==LDNS_SECTION_ANSWER
+ && msg->rrset_first->type==LDNS_RR_TYPE_DNAME){
+ if(rrset == msg->rrset_first ||
+ rrset == msg->rrset_first->rrset_all_next)
+ return rrset_trust_ans_AA;
+ else return rrset_trust_ans_noAA;
+ }
+ return rrset_trust_ans_AA;
+ }
+ else return rrset_trust_ans_noAA;
+ } else if(rrset->section == LDNS_SECTION_AUTHORITY) {
+ if(AA) return rrset_trust_auth_AA;
+ else return rrset_trust_auth_noAA;
+ } else {
+ /* addit section */
+ if(AA) return rrset_trust_add_AA;
+ else return rrset_trust_add_noAA;
+ }
+ /* NOTREACHED */
+ return rrset_trust_none;
+}
+
+int
+parse_copy_decompress_rrset(sldns_buffer* pkt, struct msg_parse* msg,
+ struct rrset_parse *pset, struct regional* region,
+ struct ub_packed_rrset_key* pk)
+{
+ struct packed_rrset_data* data;
+ pk->rk.flags = pset->flags;
+ pk->rk.dname_len = pset->dname_len;
+ if(region)
+ pk->rk.dname = (uint8_t*)regional_alloc(
+ region, pset->dname_len);
+ else pk->rk.dname =
+ (uint8_t*)malloc(pset->dname_len);
+ if(!pk->rk.dname)
+ return 0;
+ /** copy & decompress dname */
+ dname_pkt_copy(pkt, pk->rk.dname, pset->dname);
+ /** copy over type and class */
+ pk->rk.type = htons(pset->type);
+ pk->rk.rrset_class = pset->rrset_class;
+ /** read data part. */
+ if(!parse_create_rrset(pkt, pset, &data, region))
+ return 0;
+ pk->entry.data = (void*)data;
+ pk->entry.key = (void*)pk;
+ pk->entry.hash = pset->hash;
+ data->trust = get_rrset_trust(msg, pset);
+ return 1;
+}
+
+/**
+ * Copy and decompress rrs
+ * @param pkt: the packet for compression pointer resolution.
+ * @param msg: the parsed message
+ * @param rep: reply info to put rrs into.
+ * @param region: if not NULL, used for allocation.
+ * @return 0 on failure.
+ */
+static int
+parse_copy_decompress(sldns_buffer* pkt, struct msg_parse* msg,
+ struct reply_info* rep, struct regional* region)
+{
+ size_t i;
+ struct rrset_parse *pset = msg->rrset_first;
+ struct packed_rrset_data* data;
+ log_assert(rep);
+ rep->ttl = MAX_TTL;
+ rep->security = sec_status_unchecked;
+ if(rep->rrset_count == 0)
+ rep->ttl = NORR_TTL;
+
+ for(i=0; i<rep->rrset_count; i++) {
+ if(!parse_copy_decompress_rrset(pkt, msg, pset, region,
+ rep->rrsets[i]))
+ return 0;
+ data = (struct packed_rrset_data*)rep->rrsets[i]->entry.data;
+ if(data->ttl < rep->ttl)
+ rep->ttl = data->ttl;
+
+ pset = pset->rrset_all_next;
+ }
+ rep->prefetch_ttl = PREFETCH_TTL_CALC(rep->ttl);
+ return 1;
+}
+
+int
+parse_create_msg(sldns_buffer* pkt, struct msg_parse* msg,
+ struct alloc_cache* alloc, struct query_info* qinf,
+ struct reply_info** rep, struct regional* region)
+{
+ log_assert(pkt && msg);
+ if(!parse_create_qinfo(pkt, msg, qinf, region))
+ return 0;
+ if(!parse_create_repinfo(msg, rep, region))
+ return 0;
+ if(!repinfo_alloc_rrset_keys(*rep, alloc, region))
+ return 0;
+ if(!parse_copy_decompress(pkt, msg, *rep, region))
+ return 0;
+ return 1;
+}
+
+int reply_info_parse(sldns_buffer* pkt, struct alloc_cache* alloc,
+ struct query_info* qinf, struct reply_info** rep,
+ struct regional* region, struct edns_data* edns)
+{
+ /* use scratch pad region-allocator during parsing. */
+ struct msg_parse* msg;
+ int ret;
+
+ qinf->qname = NULL;
+ *rep = NULL;
+ if(!(msg = regional_alloc(region, sizeof(*msg)))) {
+ return LDNS_RCODE_SERVFAIL;
+ }
+ memset(msg, 0, sizeof(*msg));
+
+ sldns_buffer_set_position(pkt, 0);
+ if((ret = parse_packet(pkt, msg, region)) != 0) {
+ return ret;
+ }
+ if((ret = parse_extract_edns(msg, edns)) != 0)
+ return ret;
+
+ /* parse OK, allocate return structures */
+ /* this also performs dname decompression */
+ if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) {
+ query_info_clear(qinf);
+ reply_info_parsedelete(*rep, alloc);
+ *rep = NULL;
+ return LDNS_RCODE_SERVFAIL;
+ }
+ return 0;
+}
+
+/** helper compare function to sort in lock order */
+static int
+reply_info_sortref_cmp(const void* a, const void* b)
+{
+ struct rrset_ref* x = (struct rrset_ref*)a;
+ struct rrset_ref* y = (struct rrset_ref*)b;
+ if(x->key < y->key) return -1;
+ if(x->key > y->key) return 1;
+ return 0;
+}
+
+void
+reply_info_sortref(struct reply_info* rep)
+{
+ qsort(&rep->ref[0], rep->rrset_count, sizeof(struct rrset_ref),
+ reply_info_sortref_cmp);
+}
+
+void
+reply_info_set_ttls(struct reply_info* rep, time_t timenow)
+{
+ size_t i, j;
+ rep->ttl += timenow;
+ rep->prefetch_ttl += timenow;
+ for(i=0; i<rep->rrset_count; i++) {
+ struct packed_rrset_data* data = (struct packed_rrset_data*)
+ rep->ref[i].key->entry.data;
+ if(i>0 && rep->ref[i].key == rep->ref[i-1].key)
+ continue;
+ data->ttl += timenow;
+ for(j=0; j<data->count + data->rrsig_count; j++) {
+ data->rr_ttl[j] += timenow;
+ }
+ }
+}
+
+void
+reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc)
+{
+ size_t i;
+ if(!rep)
+ return;
+ /* no need to lock, since not shared in hashtables. */
+ for(i=0; i<rep->rrset_count; i++) {
+ ub_packed_rrset_parsedelete(rep->rrsets[i], alloc);
+ }
+ free(rep);
+}
+
+int
+query_info_parse(struct query_info* m, sldns_buffer* query)
+{
+ uint8_t* q = sldns_buffer_begin(query);
+ /* minimum size: header + \0 + qtype + qclass */
+ if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5)
+ return 0;
+ if(LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY ||
+ LDNS_QDCOUNT(q) != 1 || sldns_buffer_position(query) != 0)
+ return 0;
+ sldns_buffer_skip(query, LDNS_HEADER_SIZE);
+ m->qname = sldns_buffer_current(query);
+ if((m->qname_len = query_dname_len(query)) == 0)
+ return 0; /* parse error */
+ if(sldns_buffer_remaining(query) < 4)
+ return 0; /* need qtype, qclass */
+ m->qtype = sldns_buffer_read_u16(query);
+ m->qclass = sldns_buffer_read_u16(query);
+ return 1;
+}
+
+/** tiny subroutine for msgreply_compare */
+#define COMPARE_IT(x, y) \
+ if( (x) < (y) ) return -1; \
+ else if( (x) > (y) ) return +1; \
+ log_assert( (x) == (y) );
+
+int
+query_info_compare(void* m1, void* m2)
+{
+ struct query_info* msg1 = (struct query_info*)m1;
+ struct query_info* msg2 = (struct query_info*)m2;
+ int mc;
+ /* from most different to least different for speed */
+ COMPARE_IT(msg1->qtype, msg2->qtype);
+ if((mc = query_dname_compare(msg1->qname, msg2->qname)) != 0)
+ return mc;
+ log_assert(msg1->qname_len == msg2->qname_len);
+ COMPARE_IT(msg1->qclass, msg2->qclass);
+ return 0;
+#undef COMPARE_IT
+}
+
+void
+query_info_clear(struct query_info* m)
+{
+ free(m->qname);
+ m->qname = NULL;
+}
+
+size_t
+msgreply_sizefunc(void* k, void* d)
+{
+ struct msgreply_entry* q = (struct msgreply_entry*)k;
+ struct reply_info* r = (struct reply_info*)d;
+ size_t s = sizeof(struct msgreply_entry) + sizeof(struct reply_info)
+ + q->key.qname_len + lock_get_mem(&q->entry.lock)
+ - sizeof(struct rrset_ref);
+ s += r->rrset_count * sizeof(struct rrset_ref);
+ s += r->rrset_count * sizeof(struct ub_packed_rrset_key*);
+ return s;
+}
+
+void
+query_entry_delete(void *k, void* ATTR_UNUSED(arg))
+{
+ struct msgreply_entry* q = (struct msgreply_entry*)k;
+ lock_rw_destroy(&q->entry.lock);
+ query_info_clear(&q->key);
+ free(q);
+}
+
+void
+reply_info_delete(void* d, void* ATTR_UNUSED(arg))
+{
+ struct reply_info* r = (struct reply_info*)d;
+ free(r);
+}
+
+hashvalue_t
+query_info_hash(struct query_info *q)
+{
+ hashvalue_t h = 0xab;
+ h = hashlittle(&q->qtype, sizeof(q->qtype), h);
+ h = hashlittle(&q->qclass, sizeof(q->qclass), h);
+ h = dname_query_hash(q->qname, h);
+ return h;
+}
+
+struct msgreply_entry*
+query_info_entrysetup(struct query_info* q, struct reply_info* r,
+ hashvalue_t h)
+{
+ struct msgreply_entry* e = (struct msgreply_entry*)malloc(
+ sizeof(struct msgreply_entry));
+ if(!e) return NULL;
+ memcpy(&e->key, q, sizeof(*q));
+ e->entry.hash = h;
+ e->entry.key = e;
+ e->entry.data = r;
+ lock_rw_init(&e->entry.lock);
+ lock_protect(&e->entry.lock, &e->key, sizeof(e->key));
+ lock_protect(&e->entry.lock, &e->entry.hash, sizeof(e->entry.hash) +
+ sizeof(e->entry.key) + sizeof(e->entry.data));
+ lock_protect(&e->entry.lock, e->key.qname, e->key.qname_len);
+ q->qname = NULL;
+ return e;
+}
+
+/** copy rrsets from replyinfo to dest replyinfo */
+static int
+repinfo_copy_rrsets(struct reply_info* dest, struct reply_info* from,
+ struct regional* region)
+{
+ size_t i, s;
+ struct packed_rrset_data* fd, *dd;
+ struct ub_packed_rrset_key* fk, *dk;
+ for(i=0; i<dest->rrset_count; i++) {
+ fk = from->rrsets[i];
+ dk = dest->rrsets[i];
+ fd = (struct packed_rrset_data*)fk->entry.data;
+ dk->entry.hash = fk->entry.hash;
+ dk->rk = fk->rk;
+ if(region) {
+ dk->id = fk->id;
+ dk->rk.dname = (uint8_t*)regional_alloc_init(region,
+ fk->rk.dname, fk->rk.dname_len);
+ } else
+ dk->rk.dname = (uint8_t*)memdup(fk->rk.dname,
+ fk->rk.dname_len);
+ if(!dk->rk.dname)
+ return 0;
+ s = packed_rrset_sizeof(fd);
+ if(region)
+ dd = (struct packed_rrset_data*)regional_alloc_init(
+ region, fd, s);
+ else dd = (struct packed_rrset_data*)memdup(fd, s);
+ if(!dd)
+ return 0;
+ packed_rrset_ptr_fixup(dd);
+ dk->entry.data = (void*)dd;
+ }
+ return 1;
+}
+
+struct reply_info*
+reply_info_copy(struct reply_info* rep, struct alloc_cache* alloc,
+ struct regional* region)
+{
+ struct reply_info* cp;
+ cp = construct_reply_info_base(region, rep->flags, rep->qdcount,
+ rep->ttl, rep->prefetch_ttl, rep->an_numrrsets,
+ rep->ns_numrrsets, rep->ar_numrrsets, rep->rrset_count,
+ rep->security);
+ if(!cp)
+ return NULL;
+ /* allocate ub_key structures special or not */
+ if(!repinfo_alloc_rrset_keys(cp, alloc, region)) {
+ if(!region)
+ reply_info_parsedelete(cp, alloc);
+ return NULL;
+ }
+ if(!repinfo_copy_rrsets(cp, rep, region)) {
+ if(!region)
+ reply_info_parsedelete(cp, alloc);
+ return NULL;
+ }
+ return cp;
+}
+
+uint8_t*
+reply_find_final_cname_target(struct query_info* qinfo, struct reply_info* rep)
+{
+ uint8_t* sname = qinfo->qname;
+ size_t snamelen = qinfo->qname_len;
+ size_t i;
+ for(i=0; i<rep->an_numrrsets; i++) {
+ struct ub_packed_rrset_key* s = rep->rrsets[i];
+ /* follow CNAME chain (if any) */
+ if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
+ ntohs(s->rk.rrset_class) == qinfo->qclass &&
+ snamelen == s->rk.dname_len &&
+ query_dname_compare(sname, s->rk.dname) == 0) {
+ get_cname_target(s, &sname, &snamelen);
+ }
+ }
+ if(sname != qinfo->qname)
+ return sname;
+ return NULL;
+}
+
+struct ub_packed_rrset_key*
+reply_find_answer_rrset(struct query_info* qinfo, struct reply_info* rep)
+{
+ uint8_t* sname = qinfo->qname;
+ size_t snamelen = qinfo->qname_len;
+ size_t i;
+ for(i=0; i<rep->an_numrrsets; i++) {
+ struct ub_packed_rrset_key* s = rep->rrsets[i];
+ /* first match type, for query of qtype cname */
+ if(ntohs(s->rk.type) == qinfo->qtype &&
+ ntohs(s->rk.rrset_class) == qinfo->qclass &&
+ snamelen == s->rk.dname_len &&
+ query_dname_compare(sname, s->rk.dname) == 0) {
+ return s;
+ }
+ /* follow CNAME chain (if any) */
+ if(ntohs(s->rk.type) == LDNS_RR_TYPE_CNAME &&
+ ntohs(s->rk.rrset_class) == qinfo->qclass &&
+ snamelen == s->rk.dname_len &&
+ query_dname_compare(sname, s->rk.dname) == 0) {
+ get_cname_target(s, &sname, &snamelen);
+ }
+ }
+ return NULL;
+}
+
+struct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep,
+ uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
+{
+ size_t i;
+ for(i=0; i<rep->an_numrrsets; i++) {
+ struct ub_packed_rrset_key* s = rep->rrsets[i];
+ if(ntohs(s->rk.type) == type &&
+ ntohs(s->rk.rrset_class) == dclass &&
+ namelen == s->rk.dname_len &&
+ query_dname_compare(name, s->rk.dname) == 0) {
+ return s;
+ }
+ }
+ return NULL;
+}
+
+struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep,
+ uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
+{
+ size_t i;
+ for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
+ struct ub_packed_rrset_key* s = rep->rrsets[i];
+ if(ntohs(s->rk.type) == type &&
+ ntohs(s->rk.rrset_class) == dclass &&
+ namelen == s->rk.dname_len &&
+ query_dname_compare(name, s->rk.dname) == 0) {
+ return s;
+ }
+ }
+ return NULL;
+}
+
+struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep,
+ uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass)
+{
+ size_t i;
+ for(i=0; i<rep->rrset_count; i++) {
+ struct ub_packed_rrset_key* s = rep->rrsets[i];
+ if(ntohs(s->rk.type) == type &&
+ ntohs(s->rk.rrset_class) == dclass &&
+ namelen == s->rk.dname_len &&
+ query_dname_compare(name, s->rk.dname) == 0) {
+ return s;
+ }
+ }
+ return NULL;
+}
+
+void
+log_dns_msg(const char* str, struct query_info* qinfo, struct reply_info* rep)
+{
+ /* not particularly fast but flexible, make wireformat and print */
+ sldns_buffer* buf = sldns_buffer_new(65535);
+ struct regional* region = regional_create();
+ if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0,
+ region, 65535, 1)) {
+ log_info("%s: log_dns_msg: out of memory", str);
+ } else {
+ char* str = sldns_wire2str_pkt(sldns_buffer_begin(buf),
+ sldns_buffer_limit(buf));
+ if(!str) {
+ log_info("%s: log_dns_msg: ldns tostr failed", str);
+ } else {
+ log_info("%s %s",
+ str, (char*)sldns_buffer_begin(buf));
+ }
+ free(str);
+ }
+ sldns_buffer_free(buf);
+ regional_destroy(region);
+}
+
+void
+log_query_info(enum verbosity_value v, const char* str,
+ struct query_info* qinf)
+{
+ log_nametypeclass(v, str, qinf->qname, qinf->qtype, qinf->qclass);
+}
+
+int
+reply_check_cname_chain(struct reply_info* rep)
+{
+ /* check only answer section rrs for matching cname chain.
+ * the cache may return changed rdata, but owner names are untouched.*/
+ size_t i;
+ uint8_t* sname = rep->rrsets[0]->rk.dname;
+ size_t snamelen = rep->rrsets[0]->rk.dname_len;
+ for(i=0; i<rep->an_numrrsets; i++) {
+ uint16_t t = ntohs(rep->rrsets[i]->rk.type);
+ if(t == LDNS_RR_TYPE_DNAME)
+ continue; /* skip dnames; note TTL 0 not cached */
+ /* verify that owner matches current sname */
+ if(query_dname_compare(sname, rep->rrsets[i]->rk.dname) != 0){
+ /* cname chain broken */
+ return 0;
+ }
+ /* if this is a cname; move on */
+ if(t == LDNS_RR_TYPE_CNAME) {
+ get_cname_target(rep->rrsets[i], &sname, &snamelen);
+ }
+ }
+ return 1;
+}
+
+int
+reply_all_rrsets_secure(struct reply_info* rep)
+{
+ size_t i;
+ for(i=0; i<rep->rrset_count; i++) {
+ if( ((struct packed_rrset_data*)rep->rrsets[i]->entry.data)
+ ->security != sec_status_secure )
+ return 0;
+ }
+ return 1;
+}
diff --git a/external/unbound/util/data/msgreply.h b/external/unbound/util/data/msgreply.h
new file mode 100644
index 000000000..ccbd0d748
--- /dev/null
+++ b/external/unbound/util/data/msgreply.h
@@ -0,0 +1,438 @@
+/*
+ * util/data/msgreply.h - store message and reply data.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 a data structure to store a message and its reply.
+ */
+
+#ifndef UTIL_DATA_MSGREPLY_H
+#define UTIL_DATA_MSGREPLY_H
+#include "util/storage/lruhash.h"
+#include "util/data/packed_rrset.h"
+struct sldns_buffer;
+struct comm_reply;
+struct alloc_cache;
+struct iovec;
+struct regional;
+struct edns_data;
+struct msg_parse;
+struct rrset_parse;
+
+/** calculate the prefetch TTL as 90% of original. Calculation
+ * without numerical overflow (uin32_t) */
+#define PREFETCH_TTL_CALC(ttl) ((ttl) - (ttl)/10)
+
+/**
+ * Structure to store query information that makes answers to queries
+ * different.
+ */
+struct query_info {
+ /**
+ * Salient data on the query: qname, in wireformat.
+ * can be allocated or a pointer to outside buffer.
+ * User has to keep track on the status of this.
+ */
+ uint8_t* qname;
+ /** length of qname (including last 0 octet) */
+ size_t qname_len;
+ /** qtype, host byte order */
+ uint16_t qtype;
+ /** qclass, host byte order */
+ uint16_t qclass;
+};
+
+/**
+ * Information to reference an rrset
+ */
+struct rrset_ref {
+ /** the key with lock, and ptr to packed data. */
+ struct ub_packed_rrset_key* key;
+ /** id needed */
+ rrset_id_t id;
+};
+
+/**
+ * Structure to store DNS query and the reply packet.
+ * To use it, copy over the flags from reply and modify using flags from
+ * the query (RD,CD if not AA). prepend ID.
+ *
+ * Memory layout is:
+ * o struct
+ * o rrset_ref array
+ * o packed_rrset_key* array.
+ *
+ * Memory layout is sometimes not packed, when the message is synthesized,
+ * for easy of the generation. It is allocated packed when it is copied
+ * from the region allocation to the malloc allocation.
+ */
+struct reply_info {
+ /** the flags for the answer, host byte order. */
+ uint16_t flags;
+
+ /**
+ * This flag informs unbound the answer is authoritative and
+ * the AA flag should be preserved.
+ */
+ uint8_t authoritative;
+
+ /**
+ * Number of RRs in the query section.
+ * If qdcount is not 0, then it is 1, and the data that appears
+ * in the reply is the same as the query_info.
+ * Host byte order.
+ */
+ uint8_t qdcount;
+
+ /** 32 bit padding to pad struct member alignment to 64 bits. */
+ uint32_t padding;
+
+ /**
+ * TTL of the entire reply (for negative caching).
+ * only for use when there are 0 RRsets in this message.
+ * if there are RRsets, check those instead.
+ */
+ time_t ttl;
+
+ /**
+ * TTL for prefetch. After it has expired, a prefetch is suitable.
+ * Smaller than the TTL, otherwise the prefetch would not happen.
+ */
+ time_t prefetch_ttl;
+
+ /**
+ * The security status from DNSSEC validation of this message.
+ */
+ enum sec_status security;
+
+ /**
+ * Number of RRsets in each section.
+ * The answer section. Add up the RRs in every RRset to calculate
+ * the number of RRs, and the count for the dns packet.
+ * The number of RRs in RRsets can change due to RRset updates.
+ */
+ size_t an_numrrsets;
+
+ /** Count of authority section RRsets */
+ size_t ns_numrrsets;
+ /** Count of additional section RRsets */
+ size_t ar_numrrsets;
+
+ /** number of RRsets: an_numrrsets + ns_numrrsets + ar_numrrsets */
+ size_t rrset_count;
+
+ /**
+ * List of pointers (only) to the rrsets in the order in which
+ * they appear in the reply message.
+ * Number of elements is ancount+nscount+arcount RRsets.
+ * This is a pointer to that array.
+ * Use the accessor function for access.
+ */
+ struct ub_packed_rrset_key** rrsets;
+
+ /**
+ * Packed array of ids (see counts) and pointers to packed_rrset_key.
+ * The number equals ancount+nscount+arcount RRsets.
+ * These are sorted in ascending pointer, the locking order. So
+ * this list can be locked (and id, ttl checked), to see if
+ * all the data is available and recent enough.
+ *
+ * This is defined as an array of size 1, so that the compiler
+ * associates the identifier with this position in the structure.
+ * Array bound overflow on this array then gives access to the further
+ * elements of the array, which are allocated after the main structure.
+ *
+ * It could be more pure to define as array of size 0, ref[0].
+ * But ref[1] may be less confusing for compilers.
+ * Use the accessor function for access.
+ */
+ struct rrset_ref ref[1];
+};
+
+/**
+ * Structure to keep hash table entry for message replies.
+ */
+struct msgreply_entry {
+ /** the hash table key */
+ struct query_info key;
+ /** the hash table entry, data is struct reply_info* */
+ struct lruhash_entry entry;
+};
+
+/**
+ * Constructor for replyinfo.
+ * @param region: where to allocate the results, pass NULL to use malloc.
+ * @param flags: flags for the replyinfo.
+ * @param qd: qd count
+ * @param ttl: TTL of replyinfo
+ * @param prettl: prefetch ttl
+ * @param an: an count
+ * @param ns: ns count
+ * @param ar: ar count
+ * @param total: total rrset count (presumably an+ns+ar).
+ * @param sec: security status of the reply info.
+ * @return the reply_info base struct with the array for putting the rrsets
+ * in. The array has been zeroed. Returns NULL on malloc failure.
+ */
+struct reply_info*
+construct_reply_info_base(struct regional* region, uint16_t flags, size_t qd,
+ time_t ttl, time_t prettl, size_t an, size_t ns, size_t ar,
+ size_t total, enum sec_status sec);
+
+/**
+ * Parse wire query into a queryinfo structure, return 0 on parse error.
+ * initialises the (prealloced) queryinfo structure as well.
+ * This query structure contains a pointer back info the buffer!
+ * This pointer avoids memory allocation. allocqname does memory allocation.
+ * @param m: the prealloced queryinfo structure to put query into.
+ * must be unused, or _clear()ed.
+ * @param query: the wireformat packet query. starts with ID.
+ * @return: 0 on format error.
+ */
+int query_info_parse(struct query_info* m, struct sldns_buffer* query);
+
+/**
+ * Parse query reply.
+ * Fills in preallocated query_info structure (with ptr into buffer).
+ * Allocates reply_info and packed_rrsets. These are not yet added to any
+ * caches or anything, this is only parsing. Returns formerror on qdcount > 1.
+ * @param pkt: the packet buffer. Must be positioned after the query section.
+ * @param alloc: creates packed rrset key structures.
+ * @param rep: allocated reply_info is returned (only on no error).
+ * @param qinf: query_info is returned (only on no error).
+ * @param region: where to store temporary data (for parsing).
+ * @param edns: where to store edns information, does not need to be inited.
+ * @return: zero is OK, or DNS error code in case of error
+ * o FORMERR for parse errors.
+ * o SERVFAIL for memory allocation errors.
+ */
+int reply_info_parse(struct sldns_buffer* pkt, struct alloc_cache* alloc,
+ struct query_info* qinf, struct reply_info** rep,
+ struct regional* region, struct edns_data* edns);
+
+/**
+ * Allocate and decompress parsed message and rrsets.
+ * @param pkt: for name decompression.
+ * @param msg: parsed message in scratch region.
+ * @param alloc: alloc cache for special rrset key structures.
+ * Not used if region!=NULL, it can be NULL in that case.
+ * @param qinf: where to store query info.
+ * qinf itself is allocated by the caller.
+ * @param rep: reply info is allocated and returned.
+ * @param region: if this parameter is NULL then malloc and the alloc is used.
+ * otherwise, everything is allocated in this region.
+ * In a region, no special rrset key structures are needed (not shared),
+ * and no rrset_ref array in the reply is built up.
+ * @return 0 if allocation failed.
+ */
+int parse_create_msg(struct sldns_buffer* pkt, struct msg_parse* msg,
+ struct alloc_cache* alloc, struct query_info* qinf,
+ struct reply_info** rep, struct regional* region);
+
+/**
+ * Sorts the ref array.
+ * @param rep: reply info. rrsets must be filled in.
+ */
+void reply_info_sortref(struct reply_info* rep);
+
+/**
+ * Set TTLs inside the replyinfo to absolute values.
+ * @param rep: reply info. rrsets must be filled in.
+ * Also refs must be filled in.
+ * @param timenow: the current time.
+ */
+void reply_info_set_ttls(struct reply_info* rep, time_t timenow);
+
+/**
+ * Delete reply_info and packed_rrsets (while they are not yet added to the
+ * hashtables.). Returns rrsets to the alloc cache.
+ * @param rep: reply_info to delete.
+ * @param alloc: where to return rrset structures to.
+ */
+void reply_info_parsedelete(struct reply_info* rep, struct alloc_cache* alloc);
+
+/**
+ * Compare two queryinfo structures, on query and type, class.
+ * It is _not_ sorted in canonical ordering.
+ * @param m1: struct query_info* , void* here to ease use as function pointer.
+ * @param m2: struct query_info* , void* here to ease use as function pointer.
+ * @return: 0 = same, -1 m1 is smaller, +1 m1 is larger.
+ */
+int query_info_compare(void* m1, void* m2);
+
+/** clear out query info structure */
+void query_info_clear(struct query_info* m);
+
+/** calculate size of struct query_info + reply_info */
+size_t msgreply_sizefunc(void* k, void* d);
+
+/** delete msgreply_entry key structure */
+void query_entry_delete(void *q, void* arg);
+
+/** delete reply_info data structure */
+void reply_info_delete(void* d, void* arg);
+
+/** calculate hash value of query_info, lowercases the qname */
+hashvalue_t query_info_hash(struct query_info *q);
+
+/**
+ * Setup query info entry
+ * @param q: query info to copy. Emptied as if clear is called.
+ * @param r: reply to init data.
+ * @param h: hash value.
+ * @return: newly allocated message reply cache item.
+ */
+struct msgreply_entry* query_info_entrysetup(struct query_info* q,
+ struct reply_info* r, hashvalue_t h);
+
+/**
+ * Copy reply_info and all rrsets in it and allocate.
+ * @param rep: what to copy, probably inside region, no ref[] array in it.
+ * @param alloc: how to allocate rrset keys.
+ * Not used if region!=NULL, it can be NULL in that case.
+ * @param region: if this parameter is NULL then malloc and the alloc is used.
+ * otherwise, everything is allocated in this region.
+ * In a region, no special rrset key structures are needed (not shared),
+ * and no rrset_ref array in the reply is built up.
+ * @return new reply info or NULL on memory error.
+ */
+struct reply_info* reply_info_copy(struct reply_info* rep,
+ struct alloc_cache* alloc, struct regional* region);
+
+/**
+ * Copy a parsed rrset into given key, decompressing and allocating rdata.
+ * @param pkt: packet for decompression
+ * @param msg: the parser message (for flags for trust).
+ * @param pset: the parsed rrset to copy.
+ * @param region: if NULL - malloc, else data is allocated in this region.
+ * @param pk: a freshly obtained rrsetkey structure. No dname is set yet,
+ * will be set on return.
+ * Note that TTL will still be relative on return.
+ * @return false on alloc failure.
+ */
+int parse_copy_decompress_rrset(struct sldns_buffer* pkt, struct msg_parse* msg,
+ struct rrset_parse *pset, struct regional* region,
+ struct ub_packed_rrset_key* pk);
+
+/**
+ * Find final cname target in reply, the one matching qinfo. Follows CNAMEs.
+ * @param qinfo: what to start with.
+ * @param rep: looks in answer section of this message.
+ * @return: pointer dname, or NULL if not found.
+ */
+uint8_t* reply_find_final_cname_target(struct query_info* qinfo,
+ struct reply_info* rep);
+
+/**
+ * Check if cname chain in cached reply is still valid.
+ * @param rep: reply to check.
+ * @return: true if valid, false if invalid.
+ */
+int reply_check_cname_chain(struct reply_info* rep);
+
+/**
+ * Check security status of all RRs in the message.
+ * @param rep: reply to check
+ * @return: true if all RRs are secure. False if not.
+ * True if there are zero RRs.
+ */
+int reply_all_rrsets_secure(struct reply_info* rep);
+
+/**
+ * Find answer rrset in reply, the one matching qinfo. Follows CNAMEs, so the
+ * result may have a different owner name.
+ * @param qinfo: what to look for.
+ * @param rep: looks in answer section of this message.
+ * @return: pointer to rrset, or NULL if not found.
+ */
+struct ub_packed_rrset_key* reply_find_answer_rrset(struct query_info* qinfo,
+ struct reply_info* rep);
+
+/**
+ * Find rrset in reply, inside the answer section. Does not follow CNAMEs.
+ * @param rep: looks in answer section of this message.
+ * @param name: what to look for.
+ * @param namelen: length of name.
+ * @param type: looks for (host order).
+ * @param dclass: looks for (host order).
+ * @return: pointer to rrset, or NULL if not found.
+ */
+struct ub_packed_rrset_key* reply_find_rrset_section_an(struct reply_info* rep,
+ uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass);
+
+/**
+ * Find rrset in reply, inside the authority section. Does not follow CNAMEs.
+ * @param rep: looks in authority section of this message.
+ * @param name: what to look for.
+ * @param namelen: length of name.
+ * @param type: looks for (host order).
+ * @param dclass: looks for (host order).
+ * @return: pointer to rrset, or NULL if not found.
+ */
+struct ub_packed_rrset_key* reply_find_rrset_section_ns(struct reply_info* rep,
+ uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass);
+
+/**
+ * Find rrset in reply, inside any section. Does not follow CNAMEs.
+ * @param rep: looks in answer,authority and additional section of this message.
+ * @param name: what to look for.
+ * @param namelen: length of name.
+ * @param type: looks for (host order).
+ * @param dclass: looks for (host order).
+ * @return: pointer to rrset, or NULL if not found.
+ */
+struct ub_packed_rrset_key* reply_find_rrset(struct reply_info* rep,
+ uint8_t* name, size_t namelen, uint16_t type, uint16_t dclass);
+
+/**
+ * Debug send the query info and reply info to the log in readable form.
+ * @param str: descriptive string printed with packet content.
+ * @param qinfo: query section.
+ * @param rep: rest of message.
+ */
+void log_dns_msg(const char* str, struct query_info* qinfo,
+ struct reply_info* rep);
+
+/**
+ * Print string with neat domain name, type, class from query info.
+ * @param v: at what verbosity level to print this.
+ * @param str: string of message.
+ * @param qinf: query info structure with name, type and class.
+ */
+void log_query_info(enum verbosity_value v, const char* str,
+ struct query_info* qinf);
+
+#endif /* UTIL_DATA_MSGREPLY_H */
diff --git a/external/unbound/util/data/packed_rrset.c b/external/unbound/util/data/packed_rrset.c
new file mode 100644
index 000000000..807468576
--- /dev/null
+++ b/external/unbound/util/data/packed_rrset.c
@@ -0,0 +1,389 @@
+/*
+ * util/data/packed_rrset.c - data storage for a set of resource records.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 data storage for RRsets.
+ */
+
+#include "config.h"
+#include "util/data/packed_rrset.h"
+#include "util/data/dname.h"
+#include "util/storage/lookup3.h"
+#include "util/log.h"
+#include "util/alloc.h"
+#include "util/regional.h"
+#include "util/net_help.h"
+#include "ldns/rrdef.h"
+#include "ldns/sbuffer.h"
+#include "ldns/wire2str.h"
+
+void
+ub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey,
+ struct alloc_cache* alloc)
+{
+ if(!pkey)
+ return;
+ if(pkey->entry.data)
+ free(pkey->entry.data);
+ pkey->entry.data = NULL;
+ if(pkey->rk.dname)
+ free(pkey->rk.dname);
+ pkey->rk.dname = NULL;
+ pkey->id = 0;
+ alloc_special_release(alloc, pkey);
+}
+
+size_t
+ub_rrset_sizefunc(void* key, void* data)
+{
+ struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
+ struct packed_rrset_data* d = (struct packed_rrset_data*)data;
+ size_t s = sizeof(struct ub_packed_rrset_key) + k->rk.dname_len;
+ s += packed_rrset_sizeof(d) + lock_get_mem(&k->entry.lock);
+ return s;
+}
+
+size_t
+packed_rrset_sizeof(struct packed_rrset_data* d)
+{
+ size_t s;
+ if(d->rrsig_count > 0) {
+ s = ((uint8_t*)d->rr_data[d->count+d->rrsig_count-1] -
+ (uint8_t*)d) + d->rr_len[d->count+d->rrsig_count-1];
+ } else {
+ log_assert(d->count > 0);
+ s = ((uint8_t*)d->rr_data[d->count-1] - (uint8_t*)d) +
+ d->rr_len[d->count-1];
+ }
+ return s;
+}
+
+int
+ub_rrset_compare(void* k1, void* k2)
+{
+ struct ub_packed_rrset_key* key1 = (struct ub_packed_rrset_key*)k1;
+ struct ub_packed_rrset_key* key2 = (struct ub_packed_rrset_key*)k2;
+ int c;
+ if(key1 == key2)
+ return 0;
+ if(key1->rk.type != key2->rk.type) {
+ if(key1->rk.type < key2->rk.type)
+ return -1;
+ return 1;
+ }
+ if(key1->rk.dname_len != key2->rk.dname_len) {
+ if(key1->rk.dname_len < key2->rk.dname_len)
+ return -1;
+ return 1;
+ }
+ if((c=query_dname_compare(key1->rk.dname, key2->rk.dname)) != 0)
+ return c;
+ if(key1->rk.rrset_class != key2->rk.rrset_class) {
+ if(key1->rk.rrset_class < key2->rk.rrset_class)
+ return -1;
+ return 1;
+ }
+ if(key1->rk.flags != key2->rk.flags) {
+ if(key1->rk.flags < key2->rk.flags)
+ return -1;
+ return 1;
+ }
+ return 0;
+}
+
+void
+ub_rrset_key_delete(void* key, void* userdata)
+{
+ struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)key;
+ struct alloc_cache* a = (struct alloc_cache*)userdata;
+ k->id = 0;
+ free(k->rk.dname);
+ k->rk.dname = NULL;
+ alloc_special_release(a, k);
+}
+
+void
+rrset_data_delete(void* data, void* ATTR_UNUSED(userdata))
+{
+ struct packed_rrset_data* d = (struct packed_rrset_data*)data;
+ free(d);
+}
+
+int
+rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2)
+{
+ size_t i;
+ size_t total;
+ if(d1->count != d2->count || d1->rrsig_count != d2->rrsig_count)
+ return 0;
+ total = d1->count + d1->rrsig_count;
+ for(i=0; i<total; i++) {
+ if(d1->rr_len[i] != d2->rr_len[i])
+ return 0;
+ if(memcmp(d1->rr_data[i], d2->rr_data[i], d1->rr_len[i]) != 0)
+ return 0;
+ }
+ return 1;
+}
+
+hashvalue_t
+rrset_key_hash(struct packed_rrset_key* key)
+{
+ /* type is hashed in host order */
+ uint16_t t = ntohs(key->type);
+ /* Note this MUST be identical to pkt_hash_rrset in msgparse.c */
+ /* this routine does not have a compressed name */
+ hashvalue_t h = 0xab;
+ h = dname_query_hash(key->dname, h);
+ h = hashlittle(&t, sizeof(t), h);
+ h = hashlittle(&key->rrset_class, sizeof(uint16_t), h);
+ h = hashlittle(&key->flags, sizeof(uint32_t), h);
+ return h;
+}
+
+void
+packed_rrset_ptr_fixup(struct packed_rrset_data* data)
+{
+ size_t i;
+ size_t total = data->count + data->rrsig_count;
+ uint8_t* nextrdata;
+ /* fixup pointers in packed rrset data */
+ data->rr_len = (size_t*)((uint8_t*)data +
+ sizeof(struct packed_rrset_data));
+ data->rr_data = (uint8_t**)&(data->rr_len[total]);
+ data->rr_ttl = (time_t*)&(data->rr_data[total]);
+ nextrdata = (uint8_t*)&(data->rr_ttl[total]);
+ for(i=0; i<total; i++) {
+ data->rr_data[i] = nextrdata;
+ nextrdata += data->rr_len[i];
+ }
+}
+
+void
+get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname,
+ size_t* dname_len)
+{
+ struct packed_rrset_data* d;
+ size_t len;
+ if(ntohs(rrset->rk.type) != LDNS_RR_TYPE_CNAME &&
+ ntohs(rrset->rk.type) != LDNS_RR_TYPE_DNAME)
+ return;
+ d = (struct packed_rrset_data*)rrset->entry.data;
+ if(d->count < 1)
+ return;
+ if(d->rr_len[0] < 3) /* at least rdatalen + 0byte root label */
+ return;
+ len = sldns_read_uint16(d->rr_data[0]);
+ if(len != d->rr_len[0] - sizeof(uint16_t))
+ return;
+ if(dname_valid(d->rr_data[0]+sizeof(uint16_t), len) != len)
+ return;
+ *dname = d->rr_data[0]+sizeof(uint16_t);
+ *dname_len = len;
+}
+
+void
+packed_rrset_ttl_add(struct packed_rrset_data* data, time_t add)
+{
+ size_t i;
+ size_t total = data->count + data->rrsig_count;
+ data->ttl += add;
+ for(i=0; i<total; i++)
+ data->rr_ttl[i] += add;
+}
+
+const char*
+rrset_trust_to_string(enum rrset_trust s)
+{
+ switch(s) {
+ case rrset_trust_none: return "rrset_trust_none";
+ case rrset_trust_add_noAA: return "rrset_trust_add_noAA";
+ case rrset_trust_auth_noAA: return "rrset_trust_auth_noAA";
+ case rrset_trust_add_AA: return "rrset_trust_add_AA";
+ case rrset_trust_nonauth_ans_AA:return "rrset_trust_nonauth_ans_AA";
+ case rrset_trust_ans_noAA: return "rrset_trust_ans_noAA";
+ case rrset_trust_glue: return "rrset_trust_glue";
+ case rrset_trust_auth_AA: return "rrset_trust_auth_AA";
+ case rrset_trust_ans_AA: return "rrset_trust_ans_AA";
+ case rrset_trust_sec_noglue: return "rrset_trust_sec_noglue";
+ case rrset_trust_prim_noglue: return "rrset_trust_prim_noglue";
+ case rrset_trust_validated: return "rrset_trust_validated";
+ case rrset_trust_ultimate: return "rrset_trust_ultimate";
+ }
+ return "unknown_rrset_trust_value";
+}
+
+const char*
+sec_status_to_string(enum sec_status s)
+{
+ switch(s) {
+ case sec_status_unchecked: return "sec_status_unchecked";
+ case sec_status_bogus: return "sec_status_bogus";
+ case sec_status_indeterminate: return "sec_status_indeterminate";
+ case sec_status_insecure: return "sec_status_insecure";
+ case sec_status_secure: return "sec_status_secure";
+ }
+ return "unknown_sec_status_value";
+}
+
+void log_rrset_key(enum verbosity_value v, const char* str,
+ struct ub_packed_rrset_key* rrset)
+{
+ if(verbosity >= v)
+ log_nametypeclass(v, str, rrset->rk.dname,
+ ntohs(rrset->rk.type), ntohs(rrset->rk.rrset_class));
+}
+
+int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i,
+ time_t now, char* dest, size_t dest_len)
+{
+ struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
+ entry.data;
+ uint8_t rr[65535];
+ size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i];
+ log_assert(dest_len > 0 && dest);
+ if(rlen > dest_len) {
+ dest[0] = 0;
+ return 0;
+ }
+ memmove(rr, rrset->rk.dname, rrset->rk.dname_len);
+ if(i < d->count)
+ memmove(rr+rrset->rk.dname_len, &rrset->rk.type, 2);
+ else sldns_write_uint16(rr+rrset->rk.dname_len, LDNS_RR_TYPE_RRSIG);
+ memmove(rr+rrset->rk.dname_len+2, &rrset->rk.rrset_class, 2);
+ sldns_write_uint32(rr+rrset->rk.dname_len+4,
+ (uint32_t)(d->rr_ttl[i]-now));
+ memmove(rr+rrset->rk.dname_len+8, d->rr_data[i], d->rr_len[i]);
+ if(sldns_wire2str_rr_buf(rr, rlen, dest, dest_len) == -1) {
+ log_info("rrbuf failure %d %s", (int)d->rr_len[i], dest);
+ dest[0] = 0;
+ return 0;
+ }
+ return 1;
+}
+
+void log_packed_rrset(enum verbosity_value v, const char* str,
+ struct ub_packed_rrset_key* rrset)
+{
+ struct packed_rrset_data* d = (struct packed_rrset_data*)rrset->
+ entry.data;
+ char buf[65535];
+ size_t i;
+ if(verbosity < v)
+ return;
+ for(i=0; i<d->count+d->rrsig_count; i++) {
+ if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) {
+ log_info("%s: rr %d wire2str-error", str, (int)i);
+ } else {
+ log_info("%s: %s", str, buf);
+ }
+ }
+}
+
+time_t
+ub_packed_rrset_ttl(struct ub_packed_rrset_key* key)
+{
+ struct packed_rrset_data* d = (struct packed_rrset_data*)key->
+ entry.data;
+ return d->ttl;
+}
+
+struct ub_packed_rrset_key*
+packed_rrset_copy_region(struct ub_packed_rrset_key* key,
+ struct regional* region, time_t now)
+{
+ struct ub_packed_rrset_key* ck = regional_alloc(region,
+ sizeof(struct ub_packed_rrset_key));
+ struct packed_rrset_data* d;
+ struct packed_rrset_data* data = (struct packed_rrset_data*)
+ key->entry.data;
+ size_t dsize, i;
+ if(!ck)
+ return NULL;
+ ck->id = key->id;
+ memset(&ck->entry, 0, sizeof(ck->entry));
+ ck->entry.hash = key->entry.hash;
+ ck->entry.key = ck;
+ ck->rk = key->rk;
+ ck->rk.dname = regional_alloc_init(region, key->rk.dname,
+ key->rk.dname_len);
+ if(!ck->rk.dname)
+ return NULL;
+ dsize = packed_rrset_sizeof(data);
+ d = (struct packed_rrset_data*)regional_alloc_init(region, data, dsize);
+ if(!d)
+ return NULL;
+ ck->entry.data = d;
+ packed_rrset_ptr_fixup(d);
+ /* make TTLs relative - once per rrset */
+ for(i=0; i<d->count + d->rrsig_count; i++) {
+ if(d->rr_ttl[i] < now)
+ d->rr_ttl[i] = 0;
+ else d->rr_ttl[i] -= now;
+ }
+ if(d->ttl < now)
+ d->ttl = 0;
+ else d->ttl -= now;
+ return ck;
+}
+
+struct ub_packed_rrset_key*
+packed_rrset_copy_alloc(struct ub_packed_rrset_key* key,
+ struct alloc_cache* alloc, time_t now)
+{
+ struct packed_rrset_data* fd, *dd;
+ struct ub_packed_rrset_key* dk = alloc_special_obtain(alloc);
+ if(!dk) return NULL;
+ fd = (struct packed_rrset_data*)key->entry.data;
+ dk->entry.hash = key->entry.hash;
+ dk->rk = key->rk;
+ dk->rk.dname = (uint8_t*)memdup(key->rk.dname, key->rk.dname_len);
+ if(!dk->rk.dname) {
+ alloc_special_release(alloc, dk);
+ return NULL;
+ }
+ dd = (struct packed_rrset_data*)memdup(fd, packed_rrset_sizeof(fd));
+ if(!dd) {
+ free(dk->rk.dname);
+ alloc_special_release(alloc, dk);
+ return NULL;
+ }
+ packed_rrset_ptr_fixup(dd);
+ dk->entry.data = (void*)dd;
+ packed_rrset_ttl_add(dd, now);
+ return dk;
+}
diff --git a/external/unbound/util/data/packed_rrset.h b/external/unbound/util/data/packed_rrset.h
new file mode 100644
index 000000000..5d7990a2b
--- /dev/null
+++ b/external/unbound/util/data/packed_rrset.h
@@ -0,0 +1,428 @@
+/*
+ * util/data/packed_rrset.h - data storage for a set of resource records.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 data storage for RRsets.
+ */
+
+#ifndef UTIL_DATA_PACKED_RRSET_H
+#define UTIL_DATA_PACKED_RRSET_H
+#include "util/storage/lruhash.h"
+struct alloc_cache;
+struct regional;
+
+/** type used to uniquely identify rrsets. Cannot be reused without
+ * clearing the cache. */
+typedef uint64_t rrset_id_t;
+
+/** this rrset is NSEC and is at zone apex (at child side of zonecut) */
+#define PACKED_RRSET_NSEC_AT_APEX 0x1
+/** this rrset is A/AAAA and is in-zone-glue (from parent side of zonecut) */
+#define PACKED_RRSET_PARENT_SIDE 0x2
+/** this rrset is SOA and has the negative ttl (from nxdomain or nodata),
+ * this is set on SOA rrsets in the authority section, to keep its TTL separate
+ * from the SOA in the answer section from a direct SOA query or ANY query. */
+#define PACKED_RRSET_SOA_NEG 0x4
+
+/**
+ * The identifying information for an RRset.
+ */
+struct packed_rrset_key {
+ /**
+ * The domain name. If not null (for id=0) it is allocated, and
+ * contains the wireformat domain name.
+ * This dname is not canonicalized.
+ */
+ uint8_t* dname;
+ /**
+ * Length of the domain name, including last 0 root octet.
+ */
+ size_t dname_len;
+ /**
+ * Flags. 32bit to be easy for hashing:
+ * o PACKED_RRSET_NSEC_AT_APEX
+ * o PACKED_RRSET_PARENT_SIDE
+ * o PACKED_RRSET_SOA_NEG
+ */
+ uint32_t flags;
+ /** the rrset type in network format */
+ uint16_t type;
+ /** the rrset class in network format */
+ uint16_t rrset_class;
+};
+
+/**
+ * This structure contains an RRset. A set of resource records that
+ * share the same domain name, type and class.
+ *
+ * Due to memory management and threading, the key structure cannot be
+ * deleted, although the data can be. The id can be set to 0 to store and the
+ * structure can be recycled with a new id.
+ */
+struct ub_packed_rrset_key {
+ /**
+ * entry into hashtable. Note the lock is never destroyed,
+ * even when this key is retired to the cache.
+ * the data pointer (if not null) points to a struct packed_rrset.
+ */
+ struct lruhash_entry entry;
+ /**
+ * the ID of this rrset. unique, based on threadid + sequenceno.
+ * ids are not reused, except after flushing the cache.
+ * zero is an unused entry, and never a valid id.
+ * Check this value after getting entry.lock.
+ * The other values in this struct may only be altered after changing
+ * the id (which needs a writelock on entry.lock).
+ */
+ rrset_id_t id;
+ /** key data: dname, type and class */
+ struct packed_rrset_key rk;
+};
+
+/**
+ * RRset trustworthiness. Bigger value is more trust. RFC 2181.
+ * The rrset_trust_add_noAA, rrset_trust_auth_noAA, rrset_trust_add_AA,
+ * are mentioned as the same trustworthiness in 2181, but split up here
+ * for ease of processing.
+ *
+ * rrset_trust_nonauth_ans_AA, rrset_trust_ans_noAA
+ * are also mentioned as the same trustworthiness in 2181, but split up here
+ * for ease of processing.
+ *
+ * Added trust_none for a sane initial value, smaller than anything else.
+ * Added validated and ultimate trust for keys and rrsig validated content.
+ */
+enum rrset_trust {
+ /** initial value for trust */
+ rrset_trust_none = 0,
+ /** Additional information from non-authoritative answers */
+ rrset_trust_add_noAA,
+ /** Data from the authority section of a non-authoritative answer */
+ rrset_trust_auth_noAA,
+ /** Additional information from an authoritative answer */
+ rrset_trust_add_AA,
+ /** non-authoritative data from the answer section of authoritative
+ * answers */
+ rrset_trust_nonauth_ans_AA,
+ /** Data from the answer section of a non-authoritative answer */
+ rrset_trust_ans_noAA,
+ /** Glue from a primary zone, or glue from a zone transfer */
+ rrset_trust_glue,
+ /** Data from the authority section of an authoritative answer */
+ rrset_trust_auth_AA,
+ /** The authoritative data included in the answer section of an
+ * authoritative reply */
+ rrset_trust_ans_AA,
+ /** Data from a zone transfer, other than glue */
+ rrset_trust_sec_noglue,
+ /** Data from a primary zone file, other than glue data */
+ rrset_trust_prim_noglue,
+ /** DNSSEC(rfc4034) validated with trusted keys */
+ rrset_trust_validated,
+ /** ultimately trusted, no more trust is possible;
+ * trusted keys from the unbound configuration setup. */
+ rrset_trust_ultimate
+};
+
+/**
+ * Security status from validation for data.
+ * The order is significant; more secure, more proven later.
+ */
+enum sec_status {
+ /** UNCHECKED means that object has yet to be validated. */
+ sec_status_unchecked = 0,
+ /** BOGUS means that the object (RRset or message) failed to validate
+ * (according to local policy), but should have validated. */
+ sec_status_bogus,
+ /** INDETERMINATE means that the object is insecure, but not
+ * authoritatively so. Generally this means that the RRset is not
+ * below a configured trust anchor. */
+ sec_status_indeterminate,
+ /** INSECURE means that the object is authoritatively known to be
+ * insecure. Generally this means that this RRset is below a trust
+ * anchor, but also below a verified, insecure delegation. */
+ sec_status_insecure,
+ /** SECURE means that the object (RRset or message) validated
+ * according to local policy. */
+ sec_status_secure
+};
+
+/**
+ * RRset data.
+ *
+ * The data is packed, stored contiguously in memory.
+ * memory layout:
+ * o base struct
+ * o rr_len size_t array
+ * o rr_data uint8_t* array
+ * o rr_ttl time_t array (after size_t and ptrs because those may be
+ * 64bit and this array before those would make them unaligned).
+ * Since the stuff before is 32/64bit, rr_ttl is 32 bit aligned.
+ * o rr_data rdata wireformats
+ * o rrsig_data rdata wireformat(s)
+ *
+ * Rdata is stored in wireformat. The dname is stored in wireformat.
+ * TTLs are stored as absolute values (and could be expired).
+ *
+ * RRSIGs are stored in the arrays after the regular rrs.
+ *
+ * You need the packed_rrset_key to know dname, type, class of the
+ * resource records in this RRset. (if signed the rrsig gives the type too).
+ *
+ * On the wire an RR is:
+ * name, type, class, ttl, rdlength, rdata.
+ * So we need to send the following per RR:
+ * key.dname, ttl, rr_data[i].
+ * since key.dname ends with type and class.
+ * and rr_data starts with the rdlength.
+ * the ttl value to send changes due to time.
+ */
+struct packed_rrset_data {
+ /** TTL (in seconds like time()) of the rrset.
+ * Same for all RRs see rfc2181(5.2). */
+ time_t ttl;
+ /** number of rrs. */
+ size_t count;
+ /** number of rrsigs, if 0 no rrsigs */
+ size_t rrsig_count;
+ /** the trustworthiness of the rrset data */
+ enum rrset_trust trust;
+ /** security status of the rrset data */
+ enum sec_status security;
+ /** length of every rr's rdata, rr_len[i] is size of rr_data[i]. */
+ size_t* rr_len;
+ /** ttl of every rr. rr_ttl[i] ttl of rr i. */
+ time_t *rr_ttl;
+ /**
+ * Array of pointers to every rr's rdata.
+ * The rr_data[i] rdata is stored in uncompressed wireformat.
+ * The first uint16_t of rr_data[i] is network format rdlength.
+ *
+ * rr_data[count] to rr_data[count+rrsig_count] contain the rrsig data.
+ */
+ uint8_t** rr_data;
+};
+
+/**
+ * An RRset can be represented using both key and data together.
+ * Split into key and data structures to simplify implementation of
+ * caching schemes.
+ */
+struct packed_rrset {
+ /** domain name, type and class */
+ struct packed_rrset_key* k;
+ /** ttl, count and rdatas (and rrsig) */
+ struct packed_rrset_data* d;
+};
+
+/**
+ * list of packed rrsets
+ */
+struct packed_rrset_list {
+ /** next in list */
+ struct packed_rrset_list* next;
+ /** rrset key and data */
+ struct packed_rrset rrset;
+};
+
+/**
+ * Delete packed rrset key and data, not entered in hashtables yet.
+ * Used during parsing.
+ * @param pkey: rrset key structure with locks, key and data pointers.
+ * @param alloc: where to return the unfree-able key structure.
+ */
+void ub_packed_rrset_parsedelete(struct ub_packed_rrset_key* pkey,
+ struct alloc_cache* alloc);
+
+/**
+ * Memory size of rrset data. RRset data must be filled in correctly.
+ * @param data: data to examine.
+ * @return size in bytes.
+ */
+size_t packed_rrset_sizeof(struct packed_rrset_data* data);
+
+/**
+ * Get TTL of rrset. RRset data must be filled in correctly.
+ * @param key: rrset key, with data to examine.
+ * @return ttl value.
+ */
+time_t ub_packed_rrset_ttl(struct ub_packed_rrset_key* key);
+
+/**
+ * Calculate memory size of rrset entry. For hash table usage.
+ * @param key: struct ub_packed_rrset_key*.
+ * @param data: struct packed_rrset_data*.
+ * @return size in bytes.
+ */
+size_t ub_rrset_sizefunc(void* key, void* data);
+
+/**
+ * compares two rrset keys.
+ * @param k1: struct ub_packed_rrset_key*.
+ * @param k2: struct ub_packed_rrset_key*.
+ * @return 0 if equal.
+ */
+int ub_rrset_compare(void* k1, void* k2);
+
+/**
+ * compare two rrset data structures.
+ * Compared rdata and rrsigdata, not the trust or ttl value.
+ * @param d1: data to compare.
+ * @param d2: data to compare.
+ * @return 1 if equal.
+ */
+int rrsetdata_equal(struct packed_rrset_data* d1, struct packed_rrset_data* d2);
+
+/**
+ * Old key to be deleted. RRset keys are recycled via alloc.
+ * The id is set to 0. So that other threads, after acquiring a lock always
+ * get the correct value, in this case the 0 deleted-special value.
+ * @param key: struct ub_packed_rrset_key*.
+ * @param userdata: alloc structure to use for recycling.
+ */
+void ub_rrset_key_delete(void* key, void* userdata);
+
+/**
+ * Old data to be deleted.
+ * @param data: what to delete.
+ * @param userdata: user data ptr.
+ */
+void rrset_data_delete(void* data, void* userdata);
+
+/**
+ * Calculate hash value for a packed rrset key.
+ * @param key: the rrset key with name, type, class, flags.
+ * @return hash value.
+ */
+hashvalue_t rrset_key_hash(struct packed_rrset_key* key);
+
+/**
+ * Fixup pointers in fixed data packed_rrset_data blob.
+ * After a memcpy of the data for example. Will set internal pointers right.
+ * @param data: rrset data structure. Otherwise correctly filled in.
+ */
+void packed_rrset_ptr_fixup(struct packed_rrset_data* data);
+
+/**
+ * Fixup TTLs in fixed data packed_rrset_data blob.
+ * @param data: rrset data structure. Otherwise correctly filled in.
+ * @param add: how many seconds to add, pass time(0) for example.
+ */
+void packed_rrset_ttl_add(struct packed_rrset_data* data, time_t add);
+
+/**
+ * Utility procedure to extract CNAME target name from its rdata.
+ * Failsafes; it will change passed dname to a valid dname or do nothing.
+ * @param rrset: the rrset structure. Must be a CNAME.
+ * Only first RR is used (multiple RRs are technically illegal anyway).
+ * Also works on type DNAME. Returns target name.
+ * @param dname: this pointer is updated to point into the cname rdata.
+ * If a failsafe fails, nothing happens to the pointer (such as the
+ * rdata was not a valid dname, not a CNAME, ...).
+ * @param dname_len: length of dname is returned.
+ */
+void get_cname_target(struct ub_packed_rrset_key* rrset, uint8_t** dname,
+ size_t* dname_len);
+
+/**
+ * Get a printable string for a rrset trust value
+ * @param s: rrset trust value
+ * @return printable string.
+ */
+const char* rrset_trust_to_string(enum rrset_trust s);
+
+/**
+ * Get a printable string for a security status value
+ * @param s: security status
+ * @return printable string.
+ */
+const char* sec_status_to_string(enum sec_status s);
+
+/**
+ * Print string with neat domain name, type, class from rrset.
+ * @param v: at what verbosity level to print this.
+ * @param str: string of message.
+ * @param rrset: structure with name, type and class.
+ */
+void log_rrset_key(enum verbosity_value v, const char* str,
+ struct ub_packed_rrset_key* rrset);
+
+/**
+ * Convert RR from RRset to string.
+ * @param rrset: structure with data.
+ * @param i: index of rr or RRSIG.
+ * @param now: time that is subtracted from ttl before printout. Can be 0.
+ * @param dest: destination string buffer. Must be nonNULL.
+ * @param dest_len: length of dest buffer (>0).
+ * @return false on failure.
+ */
+int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i,
+ time_t now, char* dest, size_t dest_len);
+
+/**
+ * Print the string with prefix, one rr per line.
+ * @param v: at what verbosity level to print this.
+ * @param str: string of message.
+ * @param rrset: with name, and rdata, and rrsigs.
+ */
+void log_packed_rrset(enum verbosity_value v, const char* str,
+ struct ub_packed_rrset_key* rrset);
+
+/**
+ * Allocate rrset in region - no more locks needed
+ * @param key: a (just from rrset cache looked up) rrset key + valid,
+ * packed data record.
+ * @param region: where to alloc the copy
+ * @param now: adjust the TTLs to be relative (subtract from all TTLs).
+ * @return new region-alloced rrset key or NULL on alloc failure.
+ */
+struct ub_packed_rrset_key* packed_rrset_copy_region(
+ struct ub_packed_rrset_key* key, struct regional* region,
+ time_t now);
+
+/**
+ * Allocate rrset with malloc (from region or you are holding the lock).
+ * @param key: key with data entry.
+ * @param alloc: alloc_cache to create rrset_keys
+ * @param now: adjust the TTLs to be absolute (add to all TTLs).
+ * @return new region-alloced rrset key or NULL on alloc failure.
+ */
+struct ub_packed_rrset_key* packed_rrset_copy_alloc(
+ struct ub_packed_rrset_key* key, struct alloc_cache* alloc,
+ time_t now);
+
+#endif /* UTIL_DATA_PACKED_RRSET_H */
diff --git a/external/unbound/util/fptr_wlist.c b/external/unbound/util/fptr_wlist.c
new file mode 100644
index 000000000..3a5fc5f06
--- /dev/null
+++ b/external/unbound/util/fptr_wlist.c
@@ -0,0 +1,409 @@
+/*
+ * util/fptr_wlist.c - function pointer whitelists.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 that check function pointers.
+ * The functions contain a whitelist of known good callback values.
+ * Any other values lead to an error.
+ *
+ * Due to the listing nature, this file violates all the modularization
+ * boundaries in the program.
+ */
+#include "config.h"
+#include "util/fptr_wlist.h"
+#include "util/mini_event.h"
+#include "services/outside_network.h"
+#include "services/mesh.h"
+#include "services/localzone.h"
+#include "services/cache/infra.h"
+#include "services/cache/rrset.h"
+#include "dns64/dns64.h"
+#include "iterator/iterator.h"
+#include "iterator/iter_fwd.h"
+#include "validator/validator.h"
+#include "validator/val_anchor.h"
+#include "validator/val_nsec3.h"
+#include "validator/val_sigcrypt.h"
+#include "validator/val_kentry.h"
+#include "validator/val_neg.h"
+#include "validator/autotrust.h"
+#include "util/data/msgreply.h"
+#include "util/data/packed_rrset.h"
+#include "util/storage/slabhash.h"
+#include "util/storage/dnstree.h"
+#include "util/locks.h"
+#include "libunbound/libworker.h"
+#include "libunbound/context.h"
+#include "libunbound/worker.h"
+#include "util/tube.h"
+#include "util/config_file.h"
+#ifdef UB_ON_WINDOWS
+#include "winrc/win_svc.h"
+#endif
+
+#ifdef WITH_PYTHONMODULE
+#include "pythonmod/pythonmod.h"
+#endif
+
+int
+fptr_whitelist_comm_point(comm_point_callback_t *fptr)
+{
+ if(fptr == &worker_handle_request) return 1;
+ else if(fptr == &outnet_udp_cb) return 1;
+ else if(fptr == &outnet_tcp_cb) return 1;
+ else if(fptr == &tube_handle_listen) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_comm_point_raw(comm_point_callback_t *fptr)
+{
+ if(fptr == &tube_handle_listen) return 1;
+ else if(fptr == &tube_handle_write) return 1;
+ else if(fptr == &remote_accept_callback) return 1;
+ else if(fptr == &remote_control_callback) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_comm_timer(void (*fptr)(void*))
+{
+ if(fptr == &pending_udp_timer_cb) return 1;
+ else if(fptr == &outnet_tcptimer) return 1;
+ else if(fptr == &pending_udp_timer_delay_cb) return 1;
+ else if(fptr == &worker_stat_timer_cb) return 1;
+ else if(fptr == &worker_probe_timer_cb) return 1;
+#ifdef UB_ON_WINDOWS
+ else if(fptr == &wsvc_cron_cb) return 1;
+#endif
+ return 0;
+}
+
+int
+fptr_whitelist_comm_signal(void (*fptr)(int, void*))
+{
+ if(fptr == &worker_sighandler) return 1;
+ return 0;
+}
+
+int fptr_whitelist_start_accept(void (*fptr)(void*))
+{
+ if(fptr == &worker_start_accept) return 1;
+ return 0;
+}
+
+int fptr_whitelist_stop_accept(void (*fptr)(void*))
+{
+ if(fptr == &worker_stop_accept) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_event(void (*fptr)(int, short, void *))
+{
+ if(fptr == &comm_point_udp_callback) return 1;
+ else if(fptr == &comm_point_udp_ancil_callback) return 1;
+ else if(fptr == &comm_point_tcp_accept_callback) return 1;
+ else if(fptr == &comm_point_tcp_handle_callback) return 1;
+ else if(fptr == &comm_timer_callback) return 1;
+ else if(fptr == &comm_signal_callback) return 1;
+ else if(fptr == &comm_point_local_handle_callback) return 1;
+ else if(fptr == &comm_point_raw_handle_callback) return 1;
+ else if(fptr == &tube_handle_signal) return 1;
+ else if(fptr == &comm_base_handle_slow_accept) return 1;
+#ifdef UB_ON_WINDOWS
+ else if(fptr == &worker_win_stop_cb) return 1;
+#endif
+ return 0;
+}
+
+int
+fptr_whitelist_pending_udp(comm_point_callback_t *fptr)
+{
+ if(fptr == &serviced_udp_callback) return 1;
+ else if(fptr == &worker_handle_reply) return 1;
+ else if(fptr == &libworker_handle_reply) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_pending_tcp(comm_point_callback_t *fptr)
+{
+ if(fptr == &serviced_tcp_callback) return 1;
+ else if(fptr == &worker_handle_reply) return 1;
+ else if(fptr == &libworker_handle_reply) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_serviced_query(comm_point_callback_t *fptr)
+{
+ if(fptr == &worker_handle_service_reply) return 1;
+ else if(fptr == &libworker_handle_service_reply) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *))
+{
+ if(fptr == &mesh_state_compare) return 1;
+ else if(fptr == &mesh_state_ref_compare) return 1;
+ else if(fptr == &addr_tree_compare) return 1;
+ else if(fptr == &local_zone_cmp) return 1;
+ else if(fptr == &local_data_cmp) return 1;
+ else if(fptr == &fwd_cmp) return 1;
+ else if(fptr == &pending_cmp) return 1;
+ else if(fptr == &serviced_cmp) return 1;
+ else if(fptr == &name_tree_compare) return 1;
+ else if(fptr == &order_lock_cmp) return 1;
+ else if(fptr == &codeline_cmp) return 1;
+ else if(fptr == &nsec3_hash_cmp) return 1;
+ else if(fptr == &mini_ev_cmp) return 1;
+ else if(fptr == &anchor_cmp) return 1;
+ else if(fptr == &canonical_tree_compare) return 1;
+ else if(fptr == &context_query_cmp) return 1;
+ else if(fptr == &val_neg_data_compare) return 1;
+ else if(fptr == &val_neg_zone_compare) return 1;
+ else if(fptr == &probetree_cmp) return 1;
+ else if(fptr == &replay_var_compare) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_hash_sizefunc(lruhash_sizefunc_t fptr)
+{
+ if(fptr == &msgreply_sizefunc) return 1;
+ else if(fptr == &ub_rrset_sizefunc) return 1;
+ else if(fptr == &infra_sizefunc) return 1;
+ else if(fptr == &key_entry_sizefunc) return 1;
+ else if(fptr == &test_slabhash_sizefunc) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_hash_compfunc(lruhash_compfunc_t fptr)
+{
+ if(fptr == &query_info_compare) return 1;
+ else if(fptr == &ub_rrset_compare) return 1;
+ else if(fptr == &infra_compfunc) return 1;
+ else if(fptr == &key_entry_compfunc) return 1;
+ else if(fptr == &test_slabhash_compfunc) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_hash_delkeyfunc(lruhash_delkeyfunc_t fptr)
+{
+ if(fptr == &query_entry_delete) return 1;
+ else if(fptr == &ub_rrset_key_delete) return 1;
+ else if(fptr == &infra_delkeyfunc) return 1;
+ else if(fptr == &key_entry_delkeyfunc) return 1;
+ else if(fptr == &test_slabhash_delkey) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_hash_deldatafunc(lruhash_deldatafunc_t fptr)
+{
+ if(fptr == &reply_info_delete) return 1;
+ else if(fptr == &rrset_data_delete) return 1;
+ else if(fptr == &infra_deldatafunc) return 1;
+ else if(fptr == &key_entry_deldatafunc) return 1;
+ else if(fptr == &test_slabhash_deldata) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr)
+{
+ if(fptr == NULL) return 1;
+ else if(fptr == &rrset_markdel) return 1;
+ return 0;
+}
+
+/** whitelist env->send_query callbacks */
+int
+fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
+ uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
+ uint16_t flags, int dnssec, int want_dnssec, int nocaps,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen,
+ struct module_qstate* q))
+{
+ if(fptr == &worker_send_query) return 1;
+ else if(fptr == &libworker_send_query) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_modenv_detach_subs(void (*fptr)(
+ struct module_qstate* qstate))
+{
+ if(fptr == &mesh_detach_subs) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_modenv_attach_sub(int (*fptr)(
+ struct module_qstate* qstate, struct query_info* qinfo,
+ uint16_t qflags, int prime, struct module_qstate** newq))
+{
+ if(fptr == &mesh_attach_sub) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_modenv_kill_sub(void (*fptr)(struct module_qstate* newq))
+{
+ if(fptr == &mesh_state_delete) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_modenv_detect_cycle(int (*fptr)(
+ struct module_qstate* qstate, struct query_info* qinfo,
+ uint16_t flags, int prime))
+{
+ if(fptr == &mesh_detect_cycle) return 1;
+ return 0;
+}
+
+int
+fptr_whitelist_mod_init(int (*fptr)(struct module_env* env, int id))
+{
+ if(fptr == &iter_init) return 1;
+ else if(fptr == &val_init) return 1;
+ else if(fptr == &dns64_init) return 1;
+#ifdef WITH_PYTHONMODULE
+ else if(fptr == &pythonmod_init) return 1;
+#endif
+ return 0;
+}
+
+int
+fptr_whitelist_mod_deinit(void (*fptr)(struct module_env* env, int id))
+{
+ if(fptr == &iter_deinit) return 1;
+ else if(fptr == &val_deinit) return 1;
+ else if(fptr == &dns64_deinit) return 1;
+#ifdef WITH_PYTHONMODULE
+ else if(fptr == &pythonmod_deinit) return 1;
+#endif
+ return 0;
+}
+
+int
+fptr_whitelist_mod_operate(void (*fptr)(struct module_qstate* qstate,
+ enum module_ev event, int id, struct outbound_entry* outbound))
+{
+ if(fptr == &iter_operate) return 1;
+ else if(fptr == &val_operate) return 1;
+ else if(fptr == &dns64_operate) return 1;
+#ifdef WITH_PYTHONMODULE
+ else if(fptr == &pythonmod_operate) return 1;
+#endif
+ return 0;
+}
+
+int
+fptr_whitelist_mod_inform_super(void (*fptr)(
+ struct module_qstate* qstate, int id, struct module_qstate* super))
+{
+ if(fptr == &iter_inform_super) return 1;
+ else if(fptr == &val_inform_super) return 1;
+ else if(fptr == &dns64_inform_super) return 1;
+#ifdef WITH_PYTHONMODULE
+ else if(fptr == &pythonmod_inform_super) return 1;
+#endif
+ return 0;
+}
+
+int
+fptr_whitelist_mod_clear(void (*fptr)(struct module_qstate* qstate,
+ int id))
+{
+ if(fptr == &iter_clear) return 1;
+ else if(fptr == &val_clear) return 1;
+ else if(fptr == &dns64_clear) return 1;
+#ifdef WITH_PYTHONMODULE
+ else if(fptr == &pythonmod_clear) return 1;
+#endif
+ return 0;
+}
+
+int
+fptr_whitelist_mod_get_mem(size_t (*fptr)(struct module_env* env, int id))
+{
+ if(fptr == &iter_get_mem) return 1;
+ else if(fptr == &val_get_mem) return 1;
+ else if(fptr == &dns64_get_mem) return 1;
+#ifdef WITH_PYTHONMODULE
+ else if(fptr == &pythonmod_get_mem) return 1;
+#endif
+ return 0;
+}
+
+int
+fptr_whitelist_alloc_cleanup(void (*fptr)(void*))
+{
+ if(fptr == &worker_alloc_cleanup) return 1;
+ return 0;
+}
+
+int fptr_whitelist_tube_listen(tube_callback_t* fptr)
+{
+ if(fptr == &worker_handle_control_cmd) return 1;
+ else if(fptr == &libworker_handle_control_cmd) return 1;
+ return 0;
+}
+
+int fptr_whitelist_mesh_cb(mesh_cb_func_t fptr)
+{
+ if(fptr == &libworker_fg_done_cb) return 1;
+ else if(fptr == &libworker_bg_done_cb) return 1;
+ else if(fptr == &libworker_event_done_cb) return 1;
+ else if(fptr == &probe_answer_cb) return 1;
+ return 0;
+}
+
+int fptr_whitelist_print_func(void (*fptr)(char*,void*))
+{
+ if(fptr == &config_print_func) return 1;
+ else if(fptr == &config_collate_func) return 1;
+ else if(fptr == &remote_get_opt_ssl) return 1;
+ return 0;
+}
diff --git a/external/unbound/util/fptr_wlist.h b/external/unbound/util/fptr_wlist.h
new file mode 100644
index 000000000..62692ba8b
--- /dev/null
+++ b/external/unbound/util/fptr_wlist.h
@@ -0,0 +1,359 @@
+/*
+ * util/fptr_wlist.h - function pointer whitelists.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 that check function pointers.
+ * The functions contain a whitelist of known good callback values.
+ * Any other values lead to an error.
+ *
+ * This prevent heap overflow based exploits, where the callback pointer
+ * is overwritten by a buffer overflow (apart from this defense, buffer
+ * overflows should be fixed of course).
+ *
+ * Function pointers are used in
+ * o network code callbacks.
+ * o rbtree, lruhash, region data manipulation
+ * in lruhash, the assertions are before the critical regions.
+ * in other places, assertions are before the callback.
+ * o module operations.
+ */
+
+#ifndef UTIL_FPTR_WLIST_H
+#define UTIL_FPTR_WLIST_H
+#include "util/netevent.h"
+#include "util/storage/lruhash.h"
+#include "util/module.h"
+#include "util/tube.h"
+#include "services/mesh.h"
+
+/**
+ * Macro to perform an assertion check for fptr wlist checks.
+ * Does not get disabled in optimize mode. Check adds security by layers.
+ */
+#if defined(EXPORT_ALL_SYMBOLS)
+#define fptr_ok(x) /* nothing, dll-exe memory layout on win disables it */
+#else
+#define fptr_ok(x) \
+ do { if(!(x)) \
+ fatal_exit("%s:%d: %s: pointer whitelist %s failed", \
+ __FILE__, __LINE__, __func__, #x); \
+ } while(0);
+#endif
+
+/**
+ * Check function pointer whitelist for comm_point callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_comm_point(comm_point_callback_t *fptr);
+
+/**
+ * Check function pointer whitelist for raw comm_point callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_comm_point_raw(comm_point_callback_t *fptr);
+
+/**
+ * Check function pointer whitelist for comm_timer callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_comm_timer(void (*fptr)(void*));
+
+/**
+ * Check function pointer whitelist for comm_signal callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_comm_signal(void (*fptr)(int, void*));
+
+/**
+ * Check function pointer whitelist for start_accept callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_start_accept(void (*fptr)(void*));
+
+/**
+ * Check function pointer whitelist for stop_accept callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_stop_accept(void (*fptr)(void*));
+
+/**
+ * Check function pointer whitelist for event structure callback values.
+ * This is not called by libevent itself, but checked by netevent.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_event(void (*fptr)(int, short, void *));
+
+/**
+ * Check function pointer whitelist for pending udp callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_pending_udp(comm_point_callback_t *fptr);
+
+/**
+ * Check function pointer whitelist for pending tcp callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_pending_tcp(comm_point_callback_t *fptr);
+
+/**
+ * Check function pointer whitelist for serviced query callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_serviced_query(comm_point_callback_t *fptr);
+
+/**
+ * Check function pointer whitelist for rbtree cmp callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *));
+
+/**
+ * Check function pointer whitelist for lruhash sizefunc callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_hash_sizefunc(lruhash_sizefunc_t fptr);
+
+/**
+ * Check function pointer whitelist for lruhash compfunc callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_hash_compfunc(lruhash_compfunc_t fptr);
+
+/**
+ * Check function pointer whitelist for lruhash delkeyfunc callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_hash_delkeyfunc(lruhash_delkeyfunc_t fptr);
+
+/**
+ * Check function pointer whitelist for lruhash deldata callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_hash_deldatafunc(lruhash_deldatafunc_t fptr);
+
+/**
+ * Check function pointer whitelist for lruhash markdel callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_hash_markdelfunc(lruhash_markdelfunc_t fptr);
+
+/**
+ * Check function pointer whitelist for module_env send_query callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
+ uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
+ uint16_t flags, int dnssec, int want_dnssec, int nocaps,
+ struct sockaddr_storage* addr, socklen_t addrlen,
+ uint8_t* zone, size_t zonelen,
+ struct module_qstate* q));
+
+/**
+ * Check function pointer whitelist for module_env detach_subs callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_modenv_detach_subs(void (*fptr)(
+ struct module_qstate* qstate));
+
+/**
+ * Check function pointer whitelist for module_env attach_sub callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_modenv_attach_sub(int (*fptr)(
+ struct module_qstate* qstate, struct query_info* qinfo,
+ uint16_t qflags, int prime, struct module_qstate** newq));
+
+/**
+ * Check function pointer whitelist for module_env kill_sub callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_modenv_kill_sub(void (*fptr)(struct module_qstate* newq));
+
+/**
+ * Check function pointer whitelist for module_env detect_cycle callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_modenv_detect_cycle(int (*fptr)(
+ struct module_qstate* qstate, struct query_info* qinfo,
+ uint16_t flags, int prime));
+
+/**
+ * Check function pointer whitelist for module init call values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_mod_init(int (*fptr)(struct module_env* env, int id));
+
+/**
+ * Check function pointer whitelist for module deinit call values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_mod_deinit(void (*fptr)(struct module_env* env, int id));
+
+/**
+ * Check function pointer whitelist for module operate call values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_mod_operate(void (*fptr)(struct module_qstate* qstate,
+ enum module_ev event, int id, struct outbound_entry* outbound));
+
+/**
+ * Check function pointer whitelist for module inform_super call values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_mod_inform_super(void (*fptr)(
+ struct module_qstate* qstate, int id, struct module_qstate* super));
+
+/**
+ * Check function pointer whitelist for module clear call values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_mod_clear(void (*fptr)(struct module_qstate* qstate,
+ int id));
+
+/**
+ * Check function pointer whitelist for module get_mem call values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_mod_get_mem(size_t (*fptr)(struct module_env* env, int id));
+
+/**
+ * Check function pointer whitelist for alloc clear on id overflow call values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_alloc_cleanup(void (*fptr)(void*));
+
+/**
+ * Check function pointer whitelist for tube listen handler values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_tube_listen(tube_callback_t* fptr);
+
+/**
+ * Check function pointer whitelist for mesh state callback values.
+ *
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_mesh_cb(mesh_cb_func_t fptr);
+
+/**
+ * Check function pointer whitelist for config_get_option func values.
+ * @param fptr: function pointer to check.
+ * @return false if not in whitelist.
+ */
+int fptr_whitelist_print_func(void (*fptr)(char*,void*));
+
+/** Due to module breakage by fptr wlist, these test app declarations
+ * are presented here */
+/**
+ * compare two order_ids from lock-verify test app
+ * @param e1: first order_id
+ * @param e2: second order_id
+ * @return compare code -1, 0, +1 (like memcmp).
+ */
+int order_lock_cmp(const void* e1, const void* e2);
+
+/**
+ * compare two codeline structs for rbtree from memstats test app
+ * @param a: codeline
+ * @param b: codeline
+ * @return compare code -1, 0, +1 (like memcmp).
+ */
+int codeline_cmp(const void* a, const void* b);
+
+/** compare two replay_vars */
+int replay_var_compare(const void* a, const void* b);
+
+#endif /* UTIL_FPTR_WLIST_H */
diff --git a/external/unbound/util/iana_ports.inc b/external/unbound/util/iana_ports.inc
new file mode 100644
index 000000000..6754521b3
--- /dev/null
+++ b/external/unbound/util/iana_ports.inc
@@ -0,0 +1,5408 @@
+1,
+2,
+3,
+5,
+7,
+9,
+11,
+13,
+17,
+18,
+19,
+20,
+21,
+22,
+23,
+24,
+25,
+27,
+29,
+31,
+33,
+35,
+37,
+38,
+39,
+41,
+42,
+43,
+44,
+45,
+46,
+47,
+48,
+49,
+50,
+52,
+53,
+54,
+55,
+56,
+57,
+58,
+59,
+61,
+62,
+63,
+64,
+65,
+66,
+67,
+68,
+69,
+70,
+71,
+72,
+73,
+74,
+75,
+76,
+77,
+78,
+79,
+80,
+82,
+83,
+84,
+85,
+86,
+87,
+88,
+89,
+90,
+91,
+92,
+93,
+94,
+95,
+96,
+97,
+98,
+99,
+101,
+102,
+103,
+104,
+105,
+106,
+107,
+108,
+109,
+110,
+111,
+112,
+113,
+115,
+116,
+117,
+118,
+119,
+120,
+121,
+122,
+123,
+124,
+125,
+126,
+127,
+128,
+129,
+130,
+131,
+132,
+133,
+134,
+135,
+136,
+137,
+138,
+139,
+140,
+141,
+142,
+143,
+144,
+145,
+146,
+147,
+148,
+149,
+150,
+151,
+152,
+153,
+154,
+155,
+156,
+157,
+158,
+159,
+160,
+161,
+162,
+163,
+164,
+165,
+166,
+167,
+168,
+169,
+170,
+171,
+172,
+173,
+174,
+175,
+176,
+177,
+178,
+179,
+180,
+181,
+182,
+183,
+184,
+185,
+186,
+187,
+188,
+189,
+190,
+191,
+192,
+193,
+194,
+195,
+196,
+197,
+198,
+199,
+200,
+201,
+202,
+203,
+204,
+205,
+206,
+207,
+208,
+209,
+210,
+211,
+212,
+213,
+214,
+215,
+216,
+217,
+218,
+219,
+220,
+221,
+222,
+223,
+224,
+242,
+243,
+244,
+245,
+246,
+247,
+248,
+256,
+257,
+259,
+260,
+261,
+262,
+263,
+264,
+265,
+266,
+267,
+268,
+269,
+270,
+280,
+281,
+282,
+283,
+284,
+286,
+287,
+308,
+309,
+310,
+311,
+312,
+313,
+314,
+315,
+316,
+317,
+318,
+319,
+320,
+321,
+322,
+333,
+344,
+345,
+346,
+347,
+348,
+349,
+350,
+351,
+352,
+353,
+354,
+355,
+356,
+357,
+358,
+359,
+360,
+361,
+362,
+363,
+364,
+365,
+366,
+367,
+368,
+369,
+370,
+371,
+372,
+373,
+374,
+375,
+376,
+377,
+378,
+379,
+380,
+381,
+382,
+383,
+384,
+385,
+386,
+387,
+388,
+389,
+390,
+391,
+392,
+393,
+394,
+395,
+396,
+397,
+398,
+399,
+400,
+401,
+402,
+403,
+404,
+405,
+406,
+407,
+408,
+409,
+410,
+411,
+412,
+413,
+414,
+415,
+416,
+417,
+418,
+419,
+420,
+421,
+422,
+423,
+424,
+425,
+426,
+427,
+428,
+429,
+430,
+431,
+432,
+433,
+434,
+435,
+436,
+437,
+438,
+439,
+440,
+441,
+442,
+443,
+444,
+445,
+446,
+447,
+448,
+449,
+450,
+451,
+452,
+453,
+454,
+455,
+456,
+457,
+458,
+459,
+460,
+461,
+462,
+463,
+464,
+465,
+466,
+467,
+468,
+469,
+470,
+471,
+472,
+473,
+474,
+475,
+476,
+477,
+478,
+479,
+480,
+481,
+482,
+483,
+484,
+485,
+486,
+487,
+488,
+489,
+490,
+491,
+492,
+493,
+494,
+495,
+496,
+497,
+498,
+499,
+500,
+501,
+502,
+503,
+504,
+505,
+506,
+507,
+508,
+509,
+510,
+511,
+512,
+513,
+514,
+515,
+516,
+517,
+518,
+519,
+520,
+521,
+522,
+523,
+524,
+525,
+526,
+527,
+528,
+529,
+530,
+531,
+532,
+533,
+534,
+535,
+536,
+537,
+538,
+539,
+540,
+541,
+542,
+543,
+544,
+545,
+546,
+547,
+548,
+549,
+550,
+551,
+552,
+553,
+554,
+555,
+556,
+557,
+558,
+559,
+560,
+561,
+562,
+563,
+564,
+565,
+566,
+567,
+568,
+569,
+570,
+571,
+572,
+573,
+574,
+575,
+576,
+577,
+578,
+579,
+580,
+581,
+582,
+583,
+584,
+586,
+587,
+588,
+589,
+590,
+591,
+592,
+593,
+594,
+595,
+596,
+597,
+598,
+599,
+600,
+601,
+602,
+603,
+604,
+605,
+606,
+607,
+608,
+609,
+610,
+611,
+612,
+613,
+614,
+615,
+616,
+617,
+618,
+619,
+620,
+621,
+622,
+623,
+624,
+625,
+626,
+627,
+628,
+629,
+630,
+631,
+632,
+633,
+634,
+635,
+636,
+637,
+638,
+639,
+640,
+641,
+642,
+643,
+644,
+645,
+646,
+647,
+648,
+649,
+650,
+651,
+652,
+653,
+654,
+655,
+656,
+657,
+658,
+660,
+661,
+662,
+663,
+664,
+665,
+666,
+667,
+668,
+669,
+670,
+671,
+672,
+673,
+674,
+675,
+676,
+677,
+678,
+679,
+680,
+681,
+682,
+683,
+684,
+685,
+686,
+687,
+688,
+689,
+690,
+691,
+692,
+693,
+694,
+695,
+696,
+697,
+698,
+699,
+700,
+701,
+702,
+704,
+705,
+706,
+707,
+709,
+710,
+711,
+712,
+713,
+714,
+715,
+716,
+729,
+730,
+731,
+741,
+742,
+744,
+747,
+748,
+749,
+750,
+751,
+752,
+753,
+754,
+758,
+759,
+760,
+761,
+762,
+763,
+764,
+765,
+767,
+769,
+770,
+771,
+772,
+773,
+774,
+775,
+776,
+777,
+780,
+800,
+801,
+802,
+810,
+828,
+829,
+830,
+831,
+832,
+833,
+847,
+848,
+860,
+861,
+862,
+873,
+886,
+887,
+888,
+900,
+901,
+902,
+903,
+910,
+911,
+912,
+913,
+989,
+990,
+991,
+992,
+993,
+995,
+996,
+997,
+998,
+999,
+1000,
+1008,
+1010,
+1021,
+1022,
+1025,
+1026,
+1027,
+1029,
+1033,
+1034,
+1035,
+1036,
+1037,
+1038,
+1039,
+1040,
+1041,
+1042,
+1043,
+1044,
+1045,
+1046,
+1047,
+1048,
+1049,
+1050,
+1051,
+1052,
+1053,
+1054,
+1055,
+1056,
+1057,
+1058,
+1059,
+1060,
+1061,
+1062,
+1063,
+1064,
+1065,
+1066,
+1067,
+1068,
+1069,
+1070,
+1071,
+1072,
+1073,
+1074,
+1075,
+1076,
+1077,
+1078,
+1079,
+1080,
+1081,
+1082,
+1083,
+1084,
+1085,
+1086,
+1087,
+1088,
+1089,
+1090,
+1091,
+1092,
+1093,
+1094,
+1095,
+1096,
+1097,
+1098,
+1099,
+1100,
+1101,
+1102,
+1103,
+1104,
+1105,
+1106,
+1107,
+1108,
+1110,
+1111,
+1112,
+1113,
+1114,
+1115,
+1116,
+1117,
+1118,
+1119,
+1120,
+1121,
+1122,
+1123,
+1124,
+1125,
+1126,
+1127,
+1128,
+1129,
+1130,
+1131,
+1132,
+1133,
+1134,
+1135,
+1136,
+1137,
+1138,
+1139,
+1140,
+1141,
+1142,
+1143,
+1144,
+1145,
+1146,
+1147,
+1148,
+1149,
+1150,
+1151,
+1152,
+1153,
+1154,
+1155,
+1156,
+1157,
+1158,
+1159,
+1160,
+1161,
+1162,
+1163,
+1164,
+1165,
+1166,
+1167,
+1168,
+1169,
+1170,
+1171,
+1172,
+1173,
+1174,
+1175,
+1176,
+1177,
+1178,
+1179,
+1180,
+1181,
+1182,
+1183,
+1184,
+1185,
+1186,
+1187,
+1188,
+1189,
+1190,
+1191,
+1192,
+1193,
+1194,
+1195,
+1196,
+1197,
+1198,
+1199,
+1200,
+1201,
+1202,
+1203,
+1204,
+1205,
+1206,
+1207,
+1208,
+1209,
+1210,
+1211,
+1212,
+1213,
+1214,
+1215,
+1216,
+1217,
+1218,
+1219,
+1220,
+1221,
+1222,
+1223,
+1224,
+1225,
+1226,
+1227,
+1228,
+1229,
+1230,
+1231,
+1232,
+1233,
+1234,
+1235,
+1236,
+1237,
+1238,
+1239,
+1240,
+1241,
+1242,
+1243,
+1244,
+1245,
+1246,
+1247,
+1248,
+1249,
+1250,
+1251,
+1252,
+1253,
+1254,
+1255,
+1256,
+1257,
+1258,
+1259,
+1260,
+1261,
+1262,
+1263,
+1264,
+1265,
+1266,
+1267,
+1268,
+1269,
+1270,
+1271,
+1272,
+1273,
+1274,
+1275,
+1277,
+1278,
+1279,
+1280,
+1281,
+1282,
+1283,
+1284,
+1285,
+1286,
+1287,
+1288,
+1289,
+1290,
+1291,
+1292,
+1293,
+1294,
+1295,
+1296,
+1297,
+1298,
+1299,
+1300,
+1301,
+1302,
+1303,
+1304,
+1305,
+1306,
+1307,
+1308,
+1309,
+1310,
+1311,
+1312,
+1313,
+1314,
+1315,
+1316,
+1317,
+1318,
+1319,
+1320,
+1321,
+1322,
+1323,
+1324,
+1325,
+1326,
+1327,
+1328,
+1329,
+1330,
+1331,
+1332,
+1333,
+1334,
+1335,
+1336,
+1337,
+1338,
+1339,
+1340,
+1341,
+1342,
+1343,
+1344,
+1345,
+1346,
+1347,
+1348,
+1349,
+1350,
+1351,
+1352,
+1353,
+1354,
+1355,
+1356,
+1357,
+1358,
+1359,
+1360,
+1361,
+1362,
+1363,
+1364,
+1365,
+1366,
+1367,
+1368,
+1369,
+1370,
+1371,
+1372,
+1373,
+1374,
+1375,
+1376,
+1377,
+1378,
+1379,
+1380,
+1381,
+1382,
+1383,
+1384,
+1385,
+1386,
+1387,
+1388,
+1389,
+1390,
+1391,
+1392,
+1393,
+1394,
+1395,
+1396,
+1397,
+1398,
+1399,
+1400,
+1401,
+1402,
+1403,
+1404,
+1405,
+1406,
+1407,
+1408,
+1409,
+1410,
+1411,
+1412,
+1413,
+1414,
+1415,
+1416,
+1417,
+1418,
+1419,
+1420,
+1421,
+1422,
+1423,
+1424,
+1425,
+1426,
+1427,
+1428,
+1429,
+1430,
+1431,
+1432,
+1433,
+1434,
+1435,
+1436,
+1437,
+1438,
+1439,
+1440,
+1441,
+1442,
+1443,
+1444,
+1445,
+1446,
+1447,
+1448,
+1449,
+1450,
+1451,
+1452,
+1453,
+1454,
+1455,
+1456,
+1457,
+1458,
+1459,
+1460,
+1461,
+1462,
+1463,
+1464,
+1465,
+1466,
+1467,
+1468,
+1469,
+1470,
+1471,
+1472,
+1473,
+1474,
+1475,
+1476,
+1477,
+1478,
+1479,
+1480,
+1481,
+1482,
+1483,
+1484,
+1485,
+1486,
+1487,
+1488,
+1489,
+1490,
+1492,
+1493,
+1494,
+1495,
+1496,
+1497,
+1498,
+1499,
+1500,
+1501,
+1502,
+1503,
+1504,
+1505,
+1506,
+1507,
+1508,
+1509,
+1510,
+1511,
+1512,
+1513,
+1514,
+1515,
+1516,
+1517,
+1518,
+1519,
+1520,
+1521,
+1522,
+1523,
+1524,
+1525,
+1526,
+1527,
+1529,
+1530,
+1531,
+1532,
+1533,
+1534,
+1535,
+1536,
+1537,
+1538,
+1539,
+1540,
+1541,
+1542,
+1543,
+1544,
+1545,
+1546,
+1547,
+1548,
+1549,
+1550,
+1551,
+1552,
+1553,
+1554,
+1555,
+1556,
+1557,
+1558,
+1559,
+1560,
+1561,
+1562,
+1563,
+1564,
+1565,
+1566,
+1567,
+1568,
+1569,
+1570,
+1571,
+1572,
+1573,
+1574,
+1575,
+1576,
+1577,
+1578,
+1579,
+1580,
+1581,
+1582,
+1583,
+1584,
+1585,
+1586,
+1587,
+1588,
+1589,
+1590,
+1591,
+1592,
+1593,
+1594,
+1595,
+1596,
+1597,
+1598,
+1599,
+1600,
+1601,
+1602,
+1603,
+1604,
+1605,
+1606,
+1607,
+1608,
+1609,
+1610,
+1611,
+1612,
+1613,
+1614,
+1615,
+1616,
+1617,
+1618,
+1619,
+1620,
+1621,
+1622,
+1623,
+1624,
+1625,
+1626,
+1627,
+1628,
+1629,
+1630,
+1631,
+1632,
+1633,
+1634,
+1635,
+1636,
+1637,
+1638,
+1639,
+1640,
+1641,
+1642,
+1643,
+1644,
+1645,
+1646,
+1647,
+1648,
+1649,
+1650,
+1651,
+1652,
+1653,
+1654,
+1655,
+1656,
+1657,
+1658,
+1659,
+1660,
+1661,
+1662,
+1663,
+1664,
+1665,
+1666,
+1667,
+1668,
+1669,
+1670,
+1671,
+1672,
+1673,
+1674,
+1675,
+1676,
+1677,
+1678,
+1679,
+1680,
+1681,
+1682,
+1683,
+1684,
+1685,
+1686,
+1687,
+1688,
+1689,
+1690,
+1691,
+1692,
+1693,
+1694,
+1695,
+1696,
+1697,
+1698,
+1699,
+1700,
+1701,
+1702,
+1703,
+1704,
+1705,
+1706,
+1707,
+1708,
+1709,
+1710,
+1711,
+1712,
+1713,
+1714,
+1715,
+1716,
+1717,
+1718,
+1719,
+1720,
+1721,
+1722,
+1723,
+1724,
+1725,
+1726,
+1727,
+1728,
+1729,
+1730,
+1731,
+1732,
+1733,
+1734,
+1735,
+1736,
+1737,
+1738,
+1739,
+1740,
+1741,
+1742,
+1743,
+1744,
+1745,
+1746,
+1747,
+1748,
+1749,
+1750,
+1751,
+1752,
+1754,
+1755,
+1756,
+1757,
+1758,
+1759,
+1760,
+1761,
+1762,
+1763,
+1764,
+1765,
+1766,
+1767,
+1768,
+1769,
+1770,
+1771,
+1772,
+1773,
+1774,
+1776,
+1777,
+1778,
+1779,
+1780,
+1781,
+1782,
+1784,
+1785,
+1786,
+1787,
+1788,
+1789,
+1790,
+1791,
+1792,
+1793,
+1794,
+1795,
+1796,
+1797,
+1798,
+1799,
+1800,
+1801,
+1802,
+1803,
+1804,
+1805,
+1806,
+1807,
+1808,
+1809,
+1810,
+1811,
+1812,
+1813,
+1814,
+1815,
+1816,
+1817,
+1818,
+1819,
+1820,
+1821,
+1822,
+1823,
+1824,
+1825,
+1826,
+1827,
+1828,
+1829,
+1830,
+1831,
+1832,
+1833,
+1834,
+1835,
+1836,
+1837,
+1838,
+1839,
+1840,
+1841,
+1842,
+1843,
+1844,
+1845,
+1846,
+1847,
+1848,
+1849,
+1850,
+1851,
+1852,
+1853,
+1854,
+1855,
+1856,
+1857,
+1858,
+1859,
+1860,
+1861,
+1862,
+1863,
+1864,
+1865,
+1866,
+1867,
+1868,
+1869,
+1870,
+1871,
+1872,
+1873,
+1874,
+1875,
+1876,
+1877,
+1878,
+1879,
+1880,
+1881,
+1882,
+1883,
+1884,
+1885,
+1886,
+1887,
+1888,
+1889,
+1890,
+1891,
+1892,
+1893,
+1894,
+1896,
+1897,
+1898,
+1899,
+1900,
+1901,
+1902,
+1903,
+1904,
+1905,
+1906,
+1907,
+1908,
+1909,
+1910,
+1911,
+1912,
+1913,
+1914,
+1915,
+1916,
+1917,
+1918,
+1919,
+1920,
+1921,
+1922,
+1923,
+1924,
+1925,
+1926,
+1927,
+1928,
+1929,
+1930,
+1931,
+1932,
+1933,
+1934,
+1935,
+1936,
+1937,
+1938,
+1939,
+1940,
+1941,
+1942,
+1943,
+1944,
+1945,
+1946,
+1947,
+1948,
+1949,
+1950,
+1951,
+1952,
+1953,
+1954,
+1955,
+1956,
+1957,
+1958,
+1959,
+1960,
+1961,
+1962,
+1963,
+1964,
+1965,
+1966,
+1967,
+1968,
+1969,
+1970,
+1971,
+1972,
+1973,
+1974,
+1975,
+1976,
+1977,
+1978,
+1979,
+1980,
+1981,
+1982,
+1983,
+1984,
+1985,
+1986,
+1987,
+1988,
+1989,
+1990,
+1991,
+1992,
+1993,
+1994,
+1995,
+1996,
+1997,
+1998,
+1999,
+2000,
+2001,
+2002,
+2003,
+2004,
+2005,
+2006,
+2007,
+2008,
+2009,
+2010,
+2011,
+2012,
+2013,
+2014,
+2015,
+2016,
+2017,
+2018,
+2019,
+2020,
+2021,
+2022,
+2023,
+2024,
+2025,
+2026,
+2027,
+2028,
+2029,
+2030,
+2031,
+2032,
+2033,
+2034,
+2035,
+2036,
+2037,
+2038,
+2039,
+2040,
+2041,
+2042,
+2043,
+2044,
+2045,
+2046,
+2047,
+2048,
+2049,
+2050,
+2051,
+2052,
+2053,
+2054,
+2055,
+2056,
+2057,
+2058,
+2059,
+2060,
+2061,
+2062,
+2063,
+2064,
+2065,
+2066,
+2067,
+2068,
+2069,
+2070,
+2071,
+2072,
+2073,
+2074,
+2075,
+2076,
+2077,
+2078,
+2079,
+2080,
+2081,
+2082,
+2083,
+2084,
+2085,
+2086,
+2087,
+2088,
+2089,
+2090,
+2091,
+2092,
+2093,
+2094,
+2095,
+2096,
+2097,
+2098,
+2099,
+2100,
+2101,
+2102,
+2103,
+2104,
+2105,
+2106,
+2107,
+2108,
+2109,
+2110,
+2111,
+2112,
+2113,
+2114,
+2115,
+2116,
+2117,
+2118,
+2119,
+2120,
+2121,
+2122,
+2123,
+2124,
+2125,
+2126,
+2127,
+2128,
+2129,
+2130,
+2131,
+2132,
+2133,
+2134,
+2135,
+2136,
+2137,
+2138,
+2139,
+2140,
+2141,
+2142,
+2143,
+2144,
+2145,
+2146,
+2147,
+2148,
+2149,
+2150,
+2151,
+2152,
+2153,
+2154,
+2155,
+2156,
+2157,
+2158,
+2159,
+2160,
+2161,
+2162,
+2163,
+2164,
+2165,
+2166,
+2167,
+2168,
+2169,
+2170,
+2171,
+2172,
+2173,
+2174,
+2175,
+2176,
+2177,
+2178,
+2179,
+2180,
+2181,
+2182,
+2183,
+2184,
+2185,
+2186,
+2187,
+2190,
+2191,
+2192,
+2193,
+2197,
+2198,
+2199,
+2200,
+2201,
+2202,
+2203,
+2204,
+2205,
+2206,
+2207,
+2208,
+2209,
+2210,
+2211,
+2212,
+2213,
+2214,
+2215,
+2216,
+2217,
+2218,
+2219,
+2220,
+2221,
+2222,
+2223,
+2224,
+2226,
+2227,
+2228,
+2229,
+2230,
+2231,
+2232,
+2233,
+2234,
+2235,
+2236,
+2237,
+2238,
+2239,
+2240,
+2241,
+2242,
+2243,
+2244,
+2245,
+2246,
+2247,
+2248,
+2249,
+2250,
+2251,
+2252,
+2253,
+2254,
+2255,
+2256,
+2257,
+2258,
+2260,
+2261,
+2262,
+2263,
+2264,
+2265,
+2266,
+2267,
+2268,
+2269,
+2270,
+2271,
+2272,
+2273,
+2274,
+2275,
+2276,
+2277,
+2278,
+2279,
+2280,
+2281,
+2282,
+2283,
+2284,
+2285,
+2286,
+2287,
+2288,
+2289,
+2290,
+2291,
+2292,
+2293,
+2294,
+2295,
+2296,
+2297,
+2298,
+2299,
+2300,
+2301,
+2302,
+2303,
+2304,
+2305,
+2306,
+2307,
+2308,
+2309,
+2310,
+2311,
+2312,
+2313,
+2314,
+2315,
+2316,
+2317,
+2318,
+2319,
+2320,
+2321,
+2322,
+2323,
+2324,
+2325,
+2326,
+2327,
+2328,
+2329,
+2330,
+2331,
+2332,
+2333,
+2334,
+2335,
+2336,
+2337,
+2338,
+2339,
+2340,
+2341,
+2342,
+2343,
+2344,
+2345,
+2346,
+2347,
+2348,
+2349,
+2350,
+2351,
+2352,
+2353,
+2354,
+2355,
+2356,
+2357,
+2358,
+2359,
+2360,
+2361,
+2362,
+2363,
+2364,
+2365,
+2366,
+2367,
+2368,
+2370,
+2372,
+2381,
+2382,
+2383,
+2384,
+2385,
+2386,
+2387,
+2388,
+2389,
+2390,
+2391,
+2392,
+2393,
+2394,
+2395,
+2396,
+2397,
+2398,
+2399,
+2400,
+2401,
+2402,
+2403,
+2404,
+2405,
+2406,
+2407,
+2409,
+2410,
+2411,
+2412,
+2413,
+2414,
+2415,
+2416,
+2417,
+2418,
+2419,
+2420,
+2421,
+2422,
+2423,
+2424,
+2425,
+2427,
+2428,
+2429,
+2430,
+2431,
+2432,
+2433,
+2434,
+2435,
+2436,
+2437,
+2438,
+2439,
+2440,
+2441,
+2442,
+2443,
+2444,
+2445,
+2446,
+2447,
+2448,
+2449,
+2450,
+2451,
+2452,
+2453,
+2454,
+2455,
+2456,
+2457,
+2458,
+2459,
+2460,
+2461,
+2462,
+2463,
+2464,
+2465,
+2466,
+2467,
+2468,
+2469,
+2470,
+2471,
+2472,
+2473,
+2474,
+2475,
+2476,
+2477,
+2478,
+2479,
+2480,
+2481,
+2482,
+2483,
+2484,
+2485,
+2486,
+2487,
+2488,
+2489,
+2490,
+2491,
+2492,
+2493,
+2494,
+2495,
+2496,
+2497,
+2498,
+2499,
+2500,
+2501,
+2502,
+2503,
+2504,
+2505,
+2506,
+2507,
+2508,
+2509,
+2510,
+2511,
+2512,
+2513,
+2514,
+2515,
+2516,
+2517,
+2518,
+2519,
+2520,
+2521,
+2522,
+2523,
+2524,
+2525,
+2526,
+2527,
+2528,
+2529,
+2530,
+2531,
+2532,
+2533,
+2534,
+2535,
+2536,
+2537,
+2538,
+2539,
+2540,
+2541,
+2542,
+2543,
+2544,
+2545,
+2546,
+2547,
+2548,
+2549,
+2550,
+2551,
+2552,
+2553,
+2554,
+2555,
+2556,
+2557,
+2558,
+2559,
+2560,
+2561,
+2562,
+2563,
+2564,
+2565,
+2566,
+2567,
+2568,
+2569,
+2570,
+2571,
+2572,
+2573,
+2574,
+2575,
+2576,
+2577,
+2578,
+2579,
+2580,
+2581,
+2582,
+2583,
+2584,
+2585,
+2586,
+2587,
+2588,
+2589,
+2590,
+2591,
+2592,
+2593,
+2594,
+2595,
+2596,
+2597,
+2598,
+2599,
+2600,
+2601,
+2602,
+2603,
+2604,
+2605,
+2606,
+2607,
+2608,
+2609,
+2610,
+2611,
+2612,
+2613,
+2614,
+2615,
+2616,
+2617,
+2618,
+2619,
+2620,
+2621,
+2622,
+2623,
+2624,
+2625,
+2626,
+2627,
+2628,
+2629,
+2630,
+2631,
+2632,
+2633,
+2634,
+2635,
+2636,
+2637,
+2638,
+2639,
+2640,
+2641,
+2642,
+2643,
+2644,
+2645,
+2646,
+2647,
+2648,
+2649,
+2650,
+2651,
+2652,
+2653,
+2654,
+2655,
+2656,
+2657,
+2658,
+2659,
+2660,
+2661,
+2662,
+2663,
+2664,
+2665,
+2666,
+2667,
+2668,
+2669,
+2670,
+2671,
+2672,
+2673,
+2674,
+2675,
+2676,
+2677,
+2678,
+2679,
+2680,
+2681,
+2683,
+2684,
+2685,
+2686,
+2687,
+2688,
+2689,
+2690,
+2691,
+2692,
+2694,
+2695,
+2696,
+2697,
+2698,
+2699,
+2700,
+2701,
+2702,
+2703,
+2704,
+2705,
+2706,
+2707,
+2708,
+2709,
+2710,
+2711,
+2712,
+2713,
+2714,
+2715,
+2716,
+2717,
+2718,
+2719,
+2720,
+2721,
+2722,
+2723,
+2724,
+2725,
+2726,
+2727,
+2728,
+2729,
+2730,
+2731,
+2732,
+2733,
+2734,
+2735,
+2736,
+2737,
+2738,
+2739,
+2740,
+2741,
+2742,
+2743,
+2744,
+2745,
+2746,
+2747,
+2748,
+2749,
+2750,
+2751,
+2752,
+2753,
+2754,
+2755,
+2756,
+2757,
+2758,
+2759,
+2760,
+2761,
+2762,
+2763,
+2764,
+2765,
+2766,
+2767,
+2768,
+2769,
+2770,
+2771,
+2772,
+2773,
+2774,
+2775,
+2776,
+2777,
+2778,
+2779,
+2780,
+2781,
+2782,
+2783,
+2784,
+2785,
+2786,
+2787,
+2788,
+2789,
+2790,
+2791,
+2792,
+2793,
+2795,
+2796,
+2797,
+2798,
+2799,
+2800,
+2801,
+2802,
+2803,
+2804,
+2805,
+2806,
+2807,
+2808,
+2809,
+2810,
+2811,
+2812,
+2813,
+2814,
+2815,
+2816,
+2817,
+2818,
+2819,
+2820,
+2821,
+2822,
+2823,
+2824,
+2826,
+2827,
+2828,
+2829,
+2830,
+2831,
+2832,
+2833,
+2834,
+2835,
+2836,
+2837,
+2838,
+2839,
+2840,
+2841,
+2842,
+2843,
+2844,
+2845,
+2846,
+2847,
+2848,
+2849,
+2850,
+2851,
+2852,
+2853,
+2854,
+2856,
+2857,
+2858,
+2859,
+2860,
+2861,
+2862,
+2863,
+2864,
+2865,
+2866,
+2867,
+2868,
+2869,
+2870,
+2871,
+2872,
+2874,
+2875,
+2876,
+2877,
+2878,
+2879,
+2880,
+2881,
+2882,
+2883,
+2884,
+2885,
+2886,
+2887,
+2888,
+2889,
+2890,
+2891,
+2892,
+2893,
+2894,
+2895,
+2896,
+2897,
+2898,
+2899,
+2900,
+2901,
+2902,
+2903,
+2904,
+2906,
+2907,
+2908,
+2909,
+2910,
+2911,
+2912,
+2913,
+2914,
+2915,
+2916,
+2917,
+2918,
+2919,
+2920,
+2921,
+2922,
+2923,
+2924,
+2926,
+2927,
+2928,
+2929,
+2930,
+2931,
+2932,
+2933,
+2934,
+2935,
+2936,
+2937,
+2938,
+2939,
+2940,
+2941,
+2942,
+2943,
+2944,
+2945,
+2946,
+2947,
+2948,
+2949,
+2950,
+2951,
+2952,
+2953,
+2954,
+2955,
+2956,
+2957,
+2958,
+2959,
+2960,
+2961,
+2962,
+2963,
+2964,
+2965,
+2966,
+2967,
+2968,
+2969,
+2970,
+2971,
+2972,
+2973,
+2974,
+2975,
+2976,
+2977,
+2978,
+2979,
+2980,
+2981,
+2982,
+2983,
+2984,
+2985,
+2986,
+2987,
+2988,
+2989,
+2990,
+2991,
+2992,
+2993,
+2994,
+2995,
+2996,
+2997,
+2998,
+3000,
+3002,
+3003,
+3004,
+3005,
+3006,
+3007,
+3008,
+3009,
+3010,
+3011,
+3012,
+3013,
+3014,
+3015,
+3016,
+3017,
+3018,
+3019,
+3020,
+3021,
+3022,
+3023,
+3024,
+3025,
+3026,
+3027,
+3028,
+3029,
+3030,
+3031,
+3032,
+3033,
+3034,
+3035,
+3036,
+3037,
+3038,
+3039,
+3040,
+3041,
+3042,
+3043,
+3044,
+3045,
+3046,
+3047,
+3048,
+3049,
+3050,
+3051,
+3052,
+3053,
+3054,
+3055,
+3056,
+3057,
+3058,
+3059,
+3060,
+3061,
+3062,
+3063,
+3064,
+3065,
+3066,
+3067,
+3068,
+3069,
+3070,
+3071,
+3072,
+3073,
+3074,
+3075,
+3076,
+3077,
+3078,
+3079,
+3080,
+3081,
+3082,
+3083,
+3084,
+3085,
+3086,
+3087,
+3088,
+3089,
+3090,
+3091,
+3093,
+3094,
+3095,
+3096,
+3098,
+3099,
+3100,
+3101,
+3102,
+3103,
+3104,
+3105,
+3106,
+3107,
+3108,
+3109,
+3110,
+3111,
+3112,
+3113,
+3114,
+3115,
+3116,
+3117,
+3118,
+3119,
+3120,
+3122,
+3123,
+3124,
+3125,
+3127,
+3128,
+3129,
+3130,
+3131,
+3132,
+3133,
+3134,
+3135,
+3136,
+3137,
+3138,
+3139,
+3140,
+3141,
+3142,
+3143,
+3144,
+3145,
+3146,
+3147,
+3148,
+3149,
+3150,
+3151,
+3152,
+3153,
+3154,
+3155,
+3156,
+3157,
+3158,
+3159,
+3160,
+3161,
+3162,
+3163,
+3164,
+3165,
+3166,
+3167,
+3168,
+3169,
+3170,
+3171,
+3172,
+3173,
+3174,
+3175,
+3176,
+3177,
+3178,
+3179,
+3180,
+3181,
+3182,
+3183,
+3184,
+3185,
+3186,
+3187,
+3188,
+3189,
+3190,
+3191,
+3192,
+3193,
+3194,
+3195,
+3196,
+3197,
+3198,
+3199,
+3200,
+3201,
+3202,
+3203,
+3204,
+3205,
+3206,
+3207,
+3208,
+3209,
+3210,
+3211,
+3212,
+3213,
+3214,
+3215,
+3216,
+3217,
+3218,
+3219,
+3220,
+3221,
+3222,
+3223,
+3224,
+3225,
+3226,
+3227,
+3228,
+3229,
+3230,
+3231,
+3232,
+3233,
+3234,
+3235,
+3236,
+3237,
+3238,
+3239,
+3240,
+3241,
+3242,
+3243,
+3244,
+3245,
+3246,
+3247,
+3248,
+3249,
+3250,
+3251,
+3252,
+3253,
+3254,
+3255,
+3256,
+3257,
+3258,
+3259,
+3260,
+3261,
+3262,
+3263,
+3264,
+3265,
+3266,
+3267,
+3268,
+3269,
+3270,
+3271,
+3272,
+3273,
+3274,
+3275,
+3276,
+3277,
+3278,
+3279,
+3280,
+3281,
+3282,
+3283,
+3284,
+3285,
+3286,
+3287,
+3288,
+3289,
+3290,
+3291,
+3292,
+3293,
+3294,
+3295,
+3296,
+3297,
+3298,
+3299,
+3302,
+3303,
+3304,
+3305,
+3306,
+3307,
+3308,
+3309,
+3310,
+3311,
+3312,
+3313,
+3314,
+3315,
+3316,
+3317,
+3318,
+3319,
+3320,
+3321,
+3326,
+3327,
+3328,
+3329,
+3330,
+3331,
+3332,
+3333,
+3334,
+3335,
+3336,
+3337,
+3338,
+3339,
+3340,
+3341,
+3342,
+3343,
+3344,
+3345,
+3346,
+3347,
+3348,
+3349,
+3350,
+3351,
+3352,
+3353,
+3354,
+3355,
+3356,
+3357,
+3358,
+3359,
+3360,
+3361,
+3362,
+3363,
+3364,
+3365,
+3366,
+3372,
+3373,
+3374,
+3375,
+3376,
+3377,
+3378,
+3379,
+3380,
+3381,
+3382,
+3383,
+3384,
+3385,
+3386,
+3387,
+3388,
+3389,
+3390,
+3391,
+3392,
+3393,
+3394,
+3395,
+3396,
+3397,
+3398,
+3399,
+3400,
+3401,
+3402,
+3405,
+3406,
+3407,
+3408,
+3409,
+3410,
+3411,
+3412,
+3413,
+3414,
+3415,
+3416,
+3417,
+3418,
+3419,
+3420,
+3421,
+3422,
+3423,
+3424,
+3425,
+3426,
+3427,
+3428,
+3429,
+3430,
+3431,
+3432,
+3433,
+3434,
+3435,
+3436,
+3437,
+3438,
+3439,
+3440,
+3441,
+3442,
+3443,
+3444,
+3445,
+3446,
+3447,
+3448,
+3449,
+3450,
+3451,
+3452,
+3453,
+3454,
+3455,
+3456,
+3457,
+3458,
+3459,
+3460,
+3461,
+3462,
+3463,
+3464,
+3465,
+3466,
+3467,
+3468,
+3469,
+3470,
+3471,
+3472,
+3473,
+3474,
+3475,
+3476,
+3477,
+3478,
+3479,
+3480,
+3481,
+3482,
+3483,
+3484,
+3485,
+3486,
+3487,
+3488,
+3489,
+3490,
+3491,
+3492,
+3493,
+3494,
+3495,
+3496,
+3497,
+3498,
+3499,
+3500,
+3501,
+3502,
+3503,
+3504,
+3505,
+3506,
+3507,
+3508,
+3509,
+3510,
+3511,
+3512,
+3513,
+3514,
+3515,
+3516,
+3517,
+3518,
+3519,
+3520,
+3521,
+3522,
+3523,
+3524,
+3525,
+3526,
+3527,
+3528,
+3529,
+3530,
+3531,
+3532,
+3533,
+3534,
+3535,
+3536,
+3537,
+3538,
+3539,
+3540,
+3541,
+3542,
+3543,
+3544,
+3545,
+3547,
+3548,
+3549,
+3550,
+3551,
+3552,
+3553,
+3554,
+3555,
+3556,
+3557,
+3558,
+3559,
+3560,
+3561,
+3562,
+3563,
+3564,
+3567,
+3568,
+3569,
+3570,
+3571,
+3572,
+3573,
+3574,
+3575,
+3576,
+3577,
+3578,
+3579,
+3580,
+3581,
+3582,
+3583,
+3584,
+3585,
+3586,
+3587,
+3588,
+3589,
+3590,
+3591,
+3592,
+3593,
+3594,
+3595,
+3596,
+3597,
+3598,
+3599,
+3600,
+3601,
+3602,
+3603,
+3604,
+3605,
+3606,
+3607,
+3608,
+3609,
+3610,
+3611,
+3612,
+3613,
+3614,
+3615,
+3616,
+3617,
+3618,
+3619,
+3620,
+3621,
+3622,
+3623,
+3624,
+3625,
+3626,
+3627,
+3628,
+3629,
+3630,
+3631,
+3632,
+3633,
+3634,
+3635,
+3636,
+3637,
+3638,
+3639,
+3640,
+3641,
+3642,
+3643,
+3644,
+3645,
+3646,
+3647,
+3648,
+3649,
+3650,
+3651,
+3652,
+3653,
+3654,
+3655,
+3656,
+3657,
+3658,
+3659,
+3660,
+3661,
+3662,
+3663,
+3664,
+3665,
+3666,
+3667,
+3668,
+3669,
+3670,
+3671,
+3672,
+3673,
+3674,
+3675,
+3676,
+3677,
+3678,
+3679,
+3680,
+3681,
+3682,
+3683,
+3684,
+3685,
+3686,
+3687,
+3688,
+3689,
+3690,
+3691,
+3692,
+3695,
+3696,
+3697,
+3698,
+3699,
+3700,
+3701,
+3702,
+3703,
+3704,
+3705,
+3706,
+3707,
+3708,
+3709,
+3710,
+3711,
+3712,
+3713,
+3714,
+3715,
+3716,
+3717,
+3718,
+3719,
+3720,
+3721,
+3722,
+3723,
+3724,
+3725,
+3726,
+3727,
+3728,
+3729,
+3730,
+3731,
+3732,
+3733,
+3734,
+3735,
+3736,
+3738,
+3739,
+3740,
+3741,
+3742,
+3743,
+3744,
+3745,
+3746,
+3747,
+3748,
+3749,
+3750,
+3751,
+3752,
+3753,
+3754,
+3755,
+3756,
+3757,
+3758,
+3759,
+3760,
+3761,
+3762,
+3763,
+3764,
+3765,
+3767,
+3768,
+3769,
+3770,
+3771,
+3772,
+3773,
+3774,
+3775,
+3776,
+3777,
+3778,
+3779,
+3780,
+3781,
+3782,
+3783,
+3784,
+3785,
+3786,
+3787,
+3788,
+3789,
+3790,
+3791,
+3792,
+3793,
+3794,
+3795,
+3796,
+3797,
+3798,
+3799,
+3800,
+3801,
+3802,
+3803,
+3804,
+3805,
+3806,
+3807,
+3808,
+3809,
+3810,
+3811,
+3812,
+3813,
+3814,
+3815,
+3816,
+3817,
+3818,
+3819,
+3820,
+3821,
+3822,
+3823,
+3824,
+3825,
+3826,
+3827,
+3828,
+3829,
+3830,
+3831,
+3832,
+3833,
+3834,
+3835,
+3836,
+3837,
+3838,
+3839,
+3840,
+3842,
+3843,
+3844,
+3845,
+3846,
+3847,
+3848,
+3849,
+3850,
+3851,
+3852,
+3853,
+3854,
+3855,
+3856,
+3857,
+3858,
+3859,
+3860,
+3861,
+3862,
+3863,
+3865,
+3866,
+3867,
+3869,
+3870,
+3871,
+3872,
+3873,
+3874,
+3875,
+3876,
+3877,
+3878,
+3879,
+3880,
+3881,
+3882,
+3883,
+3884,
+3885,
+3886,
+3887,
+3888,
+3889,
+3890,
+3891,
+3892,
+3893,
+3894,
+3895,
+3896,
+3897,
+3898,
+3899,
+3900,
+3901,
+3902,
+3903,
+3904,
+3905,
+3906,
+3907,
+3908,
+3909,
+3910,
+3911,
+3912,
+3913,
+3914,
+3915,
+3916,
+3917,
+3918,
+3919,
+3920,
+3921,
+3922,
+3923,
+3924,
+3925,
+3926,
+3927,
+3928,
+3929,
+3930,
+3931,
+3932,
+3933,
+3934,
+3935,
+3936,
+3937,
+3938,
+3939,
+3940,
+3941,
+3942,
+3943,
+3944,
+3945,
+3946,
+3947,
+3948,
+3949,
+3950,
+3951,
+3952,
+3953,
+3954,
+3955,
+3956,
+3957,
+3958,
+3959,
+3960,
+3961,
+3962,
+3963,
+3964,
+3965,
+3966,
+3967,
+3968,
+3969,
+3970,
+3971,
+3972,
+3973,
+3974,
+3975,
+3976,
+3977,
+3978,
+3979,
+3980,
+3981,
+3982,
+3983,
+3984,
+3985,
+3986,
+3987,
+3988,
+3989,
+3990,
+3991,
+3992,
+3993,
+3995,
+3996,
+3997,
+3998,
+3999,
+4000,
+4001,
+4002,
+4003,
+4004,
+4005,
+4006,
+4007,
+4008,
+4009,
+4010,
+4011,
+4012,
+4013,
+4014,
+4015,
+4016,
+4017,
+4018,
+4019,
+4020,
+4021,
+4022,
+4023,
+4024,
+4025,
+4026,
+4027,
+4028,
+4029,
+4030,
+4031,
+4032,
+4033,
+4034,
+4035,
+4036,
+4037,
+4038,
+4039,
+4040,
+4041,
+4042,
+4043,
+4044,
+4045,
+4046,
+4047,
+4049,
+4050,
+4051,
+4052,
+4053,
+4054,
+4055,
+4056,
+4057,
+4058,
+4059,
+4060,
+4061,
+4062,
+4063,
+4064,
+4065,
+4066,
+4067,
+4068,
+4069,
+4070,
+4071,
+4072,
+4073,
+4074,
+4075,
+4076,
+4077,
+4079,
+4080,
+4081,
+4082,
+4083,
+4084,
+4086,
+4089,
+4090,
+4091,
+4092,
+4093,
+4094,
+4095,
+4096,
+4097,
+4098,
+4099,
+4100,
+4101,
+4102,
+4103,
+4104,
+4105,
+4106,
+4107,
+4108,
+4109,
+4110,
+4111,
+4112,
+4113,
+4114,
+4115,
+4116,
+4117,
+4118,
+4119,
+4121,
+4122,
+4123,
+4124,
+4125,
+4126,
+4127,
+4128,
+4129,
+4130,
+4131,
+4132,
+4133,
+4134,
+4135,
+4136,
+4137,
+4138,
+4139,
+4140,
+4141,
+4142,
+4143,
+4145,
+4146,
+4147,
+4148,
+4149,
+4150,
+4151,
+4152,
+4153,
+4154,
+4155,
+4156,
+4157,
+4158,
+4159,
+4160,
+4161,
+4162,
+4163,
+4164,
+4165,
+4166,
+4167,
+4168,
+4169,
+4172,
+4173,
+4174,
+4177,
+4178,
+4179,
+4180,
+4181,
+4182,
+4183,
+4184,
+4185,
+4188,
+4191,
+4192,
+4199,
+4300,
+4301,
+4302,
+4303,
+4304,
+4305,
+4306,
+4307,
+4308,
+4309,
+4310,
+4320,
+4321,
+4322,
+4323,
+4324,
+4325,
+4326,
+4327,
+4328,
+4333,
+4340,
+4341,
+4342,
+4343,
+4344,
+4345,
+4346,
+4347,
+4348,
+4349,
+4350,
+4351,
+4352,
+4353,
+4354,
+4355,
+4356,
+4357,
+4358,
+4359,
+4361,
+4362,
+4368,
+4369,
+4370,
+4371,
+4372,
+4373,
+4375,
+4376,
+4377,
+4378,
+4379,
+4389,
+4390,
+4394,
+4395,
+4400,
+4401,
+4402,
+4403,
+4404,
+4405,
+4406,
+4425,
+4426,
+4430,
+4432,
+4441,
+4442,
+4443,
+4444,
+4445,
+4446,
+4447,
+4448,
+4449,
+4450,
+4451,
+4452,
+4453,
+4454,
+4455,
+4456,
+4457,
+4458,
+4484,
+4486,
+4488,
+4500,
+4534,
+4535,
+4536,
+4537,
+4538,
+4545,
+4546,
+4547,
+4548,
+4549,
+4550,
+4551,
+4552,
+4554,
+4555,
+4556,
+4557,
+4558,
+4559,
+4566,
+4567,
+4568,
+4569,
+4591,
+4592,
+4593,
+4594,
+4595,
+4596,
+4597,
+4598,
+4599,
+4600,
+4601,
+4658,
+4659,
+4660,
+4661,
+4662,
+4663,
+4664,
+4665,
+4666,
+4667,
+4668,
+4669,
+4670,
+4671,
+4672,
+4673,
+4674,
+4675,
+4676,
+4677,
+4678,
+4679,
+4680,
+4681,
+4682,
+4683,
+4684,
+4685,
+4686,
+4687,
+4688,
+4689,
+4690,
+4691,
+4692,
+4700,
+4701,
+4702,
+4725,
+4726,
+4727,
+4728,
+4729,
+4730,
+4732,
+4737,
+4738,
+4739,
+4740,
+4741,
+4742,
+4743,
+4744,
+4745,
+4747,
+4749,
+4750,
+4751,
+4752,
+4753,
+4784,
+4785,
+4789,
+4790,
+4800,
+4801,
+4802,
+4803,
+4804,
+4827,
+4837,
+4838,
+4839,
+4840,
+4841,
+4842,
+4843,
+4844,
+4845,
+4846,
+4847,
+4848,
+4849,
+4850,
+4851,
+4867,
+4868,
+4869,
+4870,
+4871,
+4876,
+4877,
+4878,
+4881,
+4882,
+4884,
+4885,
+4894,
+4899,
+4900,
+4914,
+4936,
+4937,
+4940,
+4941,
+4942,
+4949,
+4950,
+4951,
+4952,
+4969,
+4970,
+4986,
+4987,
+4988,
+4989,
+4990,
+4991,
+4999,
+5000,
+5001,
+5002,
+5003,
+5004,
+5005,
+5006,
+5007,
+5008,
+5009,
+5010,
+5011,
+5012,
+5013,
+5014,
+5020,
+5021,
+5022,
+5023,
+5024,
+5025,
+5026,
+5027,
+5029,
+5030,
+5031,
+5042,
+5043,
+5044,
+5046,
+5047,
+5049,
+5050,
+5051,
+5052,
+5053,
+5055,
+5056,
+5057,
+5058,
+5059,
+5060,
+5061,
+5062,
+5064,
+5065,
+5066,
+5067,
+5069,
+5070,
+5071,
+5072,
+5073,
+5074,
+5078,
+5079,
+5080,
+5081,
+5082,
+5083,
+5084,
+5085,
+5092,
+5093,
+5094,
+5099,
+5100,
+5101,
+5102,
+5104,
+5105,
+5111,
+5112,
+5116,
+5120,
+5133,
+5136,
+5137,
+5145,
+5150,
+5151,
+5152,
+5154,
+5155,
+5164,
+5165,
+5166,
+5167,
+5168,
+5190,
+5191,
+5192,
+5193,
+5200,
+5201,
+5202,
+5203,
+5223,
+5224,
+5225,
+5226,
+5227,
+5234,
+5235,
+5236,
+5237,
+5245,
+5246,
+5247,
+5248,
+5249,
+5250,
+5251,
+5252,
+5264,
+5265,
+5270,
+5271,
+5272,
+5282,
+5298,
+5299,
+5300,
+5301,
+5302,
+5303,
+5304,
+5305,
+5306,
+5307,
+5308,
+5309,
+5310,
+5312,
+5313,
+5314,
+5315,
+5343,
+5344,
+5349,
+5350,
+5351,
+5352,
+5353,
+5354,
+5355,
+5356,
+5357,
+5358,
+5359,
+5360,
+5361,
+5362,
+5363,
+5364,
+5397,
+5398,
+5399,
+5400,
+5401,
+5402,
+5403,
+5404,
+5405,
+5406,
+5407,
+5408,
+5409,
+5410,
+5411,
+5412,
+5413,
+5414,
+5415,
+5416,
+5417,
+5418,
+5419,
+5420,
+5421,
+5422,
+5423,
+5424,
+5425,
+5426,
+5427,
+5428,
+5429,
+5430,
+5431,
+5432,
+5433,
+5434,
+5435,
+5436,
+5437,
+5443,
+5453,
+5454,
+5455,
+5456,
+5461,
+5462,
+5463,
+5464,
+5465,
+5500,
+5501,
+5502,
+5503,
+5504,
+5505,
+5506,
+5553,
+5554,
+5555,
+5556,
+5567,
+5568,
+5569,
+5573,
+5580,
+5581,
+5582,
+5583,
+5584,
+5585,
+5597,
+5598,
+5599,
+5600,
+5601,
+5602,
+5603,
+5604,
+5605,
+5627,
+5628,
+5629,
+5630,
+5631,
+5632,
+5633,
+5634,
+5670,
+5671,
+5672,
+5673,
+5674,
+5675,
+5676,
+5677,
+5678,
+5679,
+5680,
+5681,
+5682,
+5683,
+5684,
+5687,
+5688,
+5689,
+5713,
+5714,
+5715,
+5716,
+5717,
+5718,
+5719,
+5720,
+5721,
+5722,
+5723,
+5724,
+5728,
+5729,
+5730,
+5741,
+5742,
+5743,
+5744,
+5745,
+5746,
+5747,
+5748,
+5750,
+5755,
+5757,
+5766,
+5767,
+5768,
+5769,
+5770,
+5771,
+5777,
+5781,
+5782,
+5783,
+5784,
+5785,
+5786,
+5787,
+5793,
+5794,
+5813,
+5814,
+5859,
+5863,
+5900,
+5910,
+5911,
+5912,
+5913,
+5963,
+5968,
+5969,
+5984,
+5985,
+5986,
+5987,
+5988,
+5989,
+5990,
+5991,
+5992,
+5999,
+6000,
+6064,
+6065,
+6066,
+6069,
+6070,
+6071,
+6072,
+6073,
+6074,
+6081,
+6082,
+6083,
+6085,
+6086,
+6087,
+6088,
+6100,
+6101,
+6102,
+6103,
+6104,
+6105,
+6106,
+6107,
+6108,
+6109,
+6110,
+6111,
+6112,
+6118,
+6122,
+6123,
+6124,
+6133,
+6140,
+6141,
+6142,
+6143,
+6144,
+6145,
+6146,
+6147,
+6148,
+6149,
+6160,
+6161,
+6162,
+6163,
+6200,
+6201,
+6222,
+6241,
+6242,
+6243,
+6244,
+6251,
+6252,
+6253,
+6268,
+6269,
+6300,
+6301,
+6306,
+6315,
+6316,
+6317,
+6320,
+6321,
+6322,
+6324,
+6343,
+6346,
+6347,
+6350,
+6355,
+6360,
+6363,
+6370,
+6382,
+6389,
+6390,
+6417,
+6420,
+6421,
+6443,
+6444,
+6445,
+6446,
+6455,
+6456,
+6471,
+6480,
+6481,
+6482,
+6483,
+6484,
+6485,
+6486,
+6487,
+6488,
+6489,
+6500,
+6501,
+6502,
+6503,
+6505,
+6506,
+6507,
+6508,
+6509,
+6510,
+6511,
+6514,
+6515,
+6543,
+6544,
+6547,
+6548,
+6549,
+6550,
+6551,
+6558,
+6566,
+6568,
+6579,
+6580,
+6581,
+6582,
+6583,
+6619,
+6620,
+6621,
+6622,
+6623,
+6626,
+6627,
+6628,
+6633,
+6634,
+6653,
+6657,
+6670,
+6671,
+6672,
+6673,
+6678,
+6679,
+6689,
+6696,
+6701,
+6702,
+6703,
+6714,
+6715,
+6767,
+6768,
+6769,
+6770,
+6771,
+6784,
+6785,
+6786,
+6787,
+6788,
+6789,
+6790,
+6791,
+6801,
+6831,
+6841,
+6842,
+6850,
+6868,
+6888,
+6935,
+6936,
+6946,
+6951,
+6961,
+6962,
+6963,
+6964,
+6965,
+6966,
+6969,
+6997,
+6998,
+6999,
+7000,
+7001,
+7002,
+7003,
+7004,
+7005,
+7006,
+7007,
+7008,
+7009,
+7010,
+7011,
+7012,
+7013,
+7014,
+7015,
+7019,
+7020,
+7021,
+7022,
+7023,
+7024,
+7025,
+7030,
+7040,
+7070,
+7071,
+7080,
+7095,
+7099,
+7100,
+7101,
+7107,
+7121,
+7128,
+7129,
+7161,
+7162,
+7163,
+7164,
+7165,
+7166,
+7169,
+7170,
+7171,
+7174,
+7181,
+7200,
+7201,
+7227,
+7235,
+7262,
+7272,
+7273,
+7274,
+7275,
+7276,
+7277,
+7278,
+7279,
+7280,
+7281,
+7282,
+7365,
+7391,
+7392,
+7393,
+7394,
+7395,
+7397,
+7400,
+7401,
+7402,
+7410,
+7411,
+7421,
+7426,
+7427,
+7428,
+7429,
+7430,
+7431,
+7437,
+7443,
+7473,
+7491,
+7500,
+7501,
+7510,
+7511,
+7542,
+7543,
+7544,
+7545,
+7546,
+7547,
+7548,
+7549,
+7550,
+7560,
+7566,
+7570,
+7574,
+7588,
+7624,
+7627,
+7628,
+7629,
+7633,
+7648,
+7674,
+7675,
+7676,
+7677,
+7680,
+7689,
+7697,
+7707,
+7708,
+7720,
+7724,
+7725,
+7726,
+7727,
+7734,
+7738,
+7741,
+7743,
+7744,
+7747,
+7777,
+7778,
+7779,
+7781,
+7786,
+7787,
+7789,
+7794,
+7797,
+7798,
+7799,
+7800,
+7801,
+7802,
+7810,
+7845,
+7846,
+7872,
+7880,
+7887,
+7900,
+7901,
+7902,
+7903,
+7913,
+7932,
+7933,
+7962,
+7967,
+7979,
+7980,
+7982,
+7998,
+7999,
+8000,
+8001,
+8002,
+8003,
+8005,
+8008,
+8019,
+8020,
+8021,
+8022,
+8025,
+8026,
+8032,
+8033,
+8034,
+8040,
+8052,
+8053,
+8054,
+8055,
+8056,
+8057,
+8058,
+8059,
+8060,
+8074,
+8080,
+8081,
+8082,
+8083,
+8086,
+8087,
+8088,
+8097,
+8100,
+8115,
+8116,
+8118,
+8121,
+8122,
+8128,
+8129,
+8130,
+8131,
+8132,
+8148,
+8149,
+8160,
+8161,
+8182,
+8184,
+8192,
+8194,
+8195,
+8199,
+8200,
+8201,
+8202,
+8204,
+8205,
+8206,
+8207,
+8208,
+8230,
+8243,
+8276,
+8280,
+8292,
+8294,
+8300,
+8301,
+8320,
+8321,
+8351,
+8376,
+8377,
+8378,
+8379,
+8380,
+8383,
+8400,
+8401,
+8402,
+8403,
+8416,
+8417,
+8442,
+8443,
+8444,
+8445,
+8450,
+8472,
+8473,
+8474,
+8500,
+8501,
+8554,
+8555,
+8567,
+8600,
+8609,
+8610,
+8611,
+8612,
+8613,
+8614,
+8675,
+8686,
+8732,
+8733,
+8763,
+8764,
+8765,
+8766,
+8770,
+8786,
+8787,
+8793,
+8800,
+8804,
+8873,
+8880,
+8883,
+8888,
+8889,
+8890,
+8891,
+8892,
+8893,
+8894,
+8899,
+8900,
+8901,
+8910,
+8911,
+8912,
+8913,
+8954,
+8989,
+8990,
+8991,
+8999,
+9000,
+9001,
+9002,
+9007,
+9009,
+9020,
+9021,
+9022,
+9023,
+9024,
+9025,
+9026,
+9080,
+9084,
+9085,
+9086,
+9087,
+9088,
+9089,
+9090,
+9091,
+9092,
+9100,
+9101,
+9102,
+9103,
+9104,
+9105,
+9106,
+9119,
+9131,
+9160,
+9161,
+9162,
+9163,
+9164,
+9191,
+9200,
+9201,
+9202,
+9203,
+9204,
+9205,
+9206,
+9207,
+9208,
+9209,
+9210,
+9211,
+9212,
+9213,
+9214,
+9215,
+9216,
+9217,
+9222,
+9255,
+9277,
+9278,
+9279,
+9280,
+9281,
+9282,
+9283,
+9284,
+9285,
+9286,
+9287,
+9292,
+9293,
+9294,
+9295,
+9300,
+9318,
+9321,
+9343,
+9344,
+9346,
+9374,
+9380,
+9396,
+9397,
+9400,
+9401,
+9402,
+9418,
+9443,
+9444,
+9450,
+9500,
+9522,
+9535,
+9536,
+9555,
+9592,
+9593,
+9594,
+9595,
+9596,
+9597,
+9598,
+9599,
+9600,
+9612,
+9618,
+9628,
+9629,
+9632,
+9667,
+9668,
+9694,
+9695,
+9700,
+9747,
+9750,
+9753,
+9762,
+9800,
+9801,
+9802,
+9875,
+9878,
+9888,
+9889,
+9898,
+9899,
+9900,
+9901,
+9903,
+9909,
+9911,
+9950,
+9951,
+9952,
+9953,
+9955,
+9956,
+9966,
+9987,
+9990,
+9991,
+9992,
+9993,
+9994,
+9995,
+9996,
+9997,
+9998,
+9999,
+10000,
+10001,
+10002,
+10003,
+10007,
+10008,
+10009,
+10023,
+10050,
+10051,
+10080,
+10081,
+10100,
+10101,
+10102,
+10103,
+10104,
+10107,
+10110,
+10111,
+10113,
+10114,
+10115,
+10116,
+10117,
+10128,
+10160,
+10161,
+10162,
+10200,
+10201,
+10252,
+10260,
+10288,
+10439,
+10500,
+10540,
+10541,
+10542,
+10543,
+10544,
+10800,
+10805,
+10810,
+10860,
+10880,
+10990,
+11000,
+11001,
+11095,
+11106,
+11108,
+11111,
+11112,
+11161,
+11162,
+11163,
+11164,
+11165,
+11171,
+11201,
+11208,
+11211,
+11319,
+11320,
+11321,
+11367,
+11371,
+11430,
+11600,
+11720,
+11723,
+11751,
+11796,
+11876,
+11877,
+11967,
+12000,
+12001,
+12002,
+12003,
+12004,
+12005,
+12006,
+12007,
+12008,
+12009,
+12012,
+12013,
+12109,
+12121,
+12168,
+12172,
+12300,
+12321,
+12322,
+12345,
+12753,
+13160,
+13216,
+13217,
+13218,
+13223,
+13224,
+13400,
+13720,
+13721,
+13722,
+13724,
+13782,
+13783,
+13785,
+13786,
+13818,
+13819,
+13820,
+13821,
+13822,
+13894,
+13929,
+14000,
+14001,
+14002,
+14033,
+14034,
+14141,
+14142,
+14145,
+14149,
+14154,
+14250,
+14414,
+14936,
+14937,
+15000,
+15118,
+15345,
+15363,
+15555,
+15660,
+15740,
+15998,
+16003,
+16161,
+16309,
+16310,
+16311,
+16360,
+16361,
+16367,
+16368,
+16384,
+16666,
+16900,
+16950,
+16991,
+16992,
+16993,
+16994,
+16995,
+17007,
+17185,
+17219,
+17220,
+17221,
+17222,
+17234,
+17235,
+17500,
+17729,
+17754,
+17755,
+17756,
+18000,
+18181,
+18182,
+18183,
+18184,
+18185,
+18186,
+18187,
+18241,
+18262,
+18463,
+18634,
+18635,
+18769,
+18881,
+18888,
+19000,
+19007,
+19191,
+19194,
+19283,
+19315,
+19398,
+19410,
+19411,
+19412,
+19539,
+19540,
+19541,
+19788,
+19999,
+20000,
+20001,
+20002,
+20003,
+20005,
+20012,
+20014,
+20034,
+20046,
+20048,
+20049,
+20167,
+20202,
+20222,
+20480,
+20670,
+20999,
+21000,
+21554,
+21590,
+21800,
+21845,
+21846,
+21847,
+21848,
+21849,
+22000,
+22001,
+22002,
+22003,
+22004,
+22005,
+22273,
+22305,
+22343,
+22347,
+22350,
+22555,
+22763,
+22800,
+22951,
+23000,
+23001,
+23002,
+23003,
+23004,
+23005,
+23272,
+23333,
+23400,
+23401,
+23402,
+24000,
+24001,
+24002,
+24003,
+24004,
+24005,
+24006,
+24242,
+24249,
+24321,
+24322,
+24386,
+24465,
+24554,
+24577,
+24676,
+24677,
+24678,
+24680,
+24850,
+24922,
+25000,
+25001,
+25002,
+25003,
+25004,
+25005,
+25006,
+25007,
+25008,
+25009,
+25793,
+25900,
+25901,
+25902,
+25903,
+25954,
+25955,
+26000,
+26133,
+26208,
+26260,
+26261,
+26262,
+26263,
+26486,
+26487,
+26489,
+27345,
+27442,
+27504,
+27782,
+27999,
+28000,
+28119,
+28200,
+28240,
+29167,
+30001,
+30002,
+30003,
+30004,
+30260,
+30832,
+30999,
+31029,
+31416,
+31457,
+31620,
+31765,
+31948,
+31949,
+32034,
+32249,
+32483,
+32635,
+32636,
+32767,
+32768,
+32769,
+32770,
+32771,
+32772,
+32773,
+32774,
+32775,
+32776,
+32777,
+32801,
+32896,
+33123,
+33331,
+33334,
+33434,
+33656,
+34249,
+34378,
+34379,
+34962,
+34963,
+34964,
+34980,
+35001,
+35004,
+35355,
+36001,
+36865,
+37475,
+37654,
+38201,
+38202,
+38203,
+39681,
+40000,
+40841,
+40842,
+40843,
+40853,
+41111,
+41794,
+41795,
+42508,
+42509,
+42510,
+43000,
+43188,
+43189,
+43190,
+43210,
+43439,
+43440,
+43441,
+44321,
+44322,
+44544,
+44553,
+44600,
+44818,
+44900,
+45000,
+45054,
+45678,
+45825,
+45966,
+46999,
+47000,
+47100,
+47557,
+47624,
+47806,
+47808,
+47809,
+48000,
+48001,
+48002,
+48003,
+48128,
+48129,
+48556,
+48619,
+48653,
diff --git a/external/unbound/util/locks.c b/external/unbound/util/locks.c
new file mode 100644
index 000000000..509895d02
--- /dev/null
+++ b/external/unbound/util/locks.c
@@ -0,0 +1,264 @@
+/**
+ * util/locks.c - unbound locking primitives
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ * Implementation of locking and threading support.
+ * A place for locking debug code since most locking functions are macros.
+ */
+
+#include "config.h"
+#include "util/locks.h"
+#include <signal.h>
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+
+/** block all signals, masks them away. */
+void
+ub_thread_blocksigs(void)
+{
+#if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) || defined(HAVE_SIGPROCMASK)
+# if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS)
+ int err;
+# endif
+ sigset_t sigset;
+ sigfillset(&sigset);
+#ifdef HAVE_PTHREAD
+ if((err=pthread_sigmask(SIG_SETMASK, &sigset, NULL)))
+ fatal_exit("pthread_sigmask: %s", strerror(err));
+#else
+# ifdef HAVE_SOLARIS_THREADS
+ if((err=thr_sigsetmask(SIG_SETMASK, &sigset, NULL)))
+ fatal_exit("thr_sigsetmask: %s", strerror(err));
+# else
+ /* have nothing, do single process signal mask */
+ if(sigprocmask(SIG_SETMASK, &sigset, NULL))
+ fatal_exit("sigprocmask: %s", strerror(errno));
+# endif /* HAVE_SOLARIS_THREADS */
+#endif /* HAVE_PTHREAD */
+#endif /* have signal stuff */
+}
+
+/** unblock one signal, so we can catch it */
+void ub_thread_sig_unblock(int sig)
+{
+#if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS) || defined(HAVE_SIGPROCMASK)
+# if defined(HAVE_PTHREAD) || defined(HAVE_SOLARIS_THREADS)
+ int err;
+# endif
+ sigset_t sigset;
+ sigemptyset(&sigset);
+ sigaddset(&sigset, sig);
+#ifdef HAVE_PTHREAD
+ if((err=pthread_sigmask(SIG_UNBLOCK, &sigset, NULL)))
+ fatal_exit("pthread_sigmask: %s", strerror(err));
+#else
+# ifdef HAVE_SOLARIS_THREADS
+ if((err=thr_sigsetmask(SIG_UNBLOCK, &sigset, NULL)))
+ fatal_exit("thr_sigsetmask: %s", strerror(err));
+# else
+ /* have nothing, do single thread case */
+ if(sigprocmask(SIG_UNBLOCK, &sigset, NULL))
+ fatal_exit("sigprocmask: %s", strerror(errno));
+# endif /* HAVE_SOLARIS_THREADS */
+#endif /* HAVE_PTHREAD */
+#else
+ (void)sig;
+#endif /* have signal stuff */
+}
+
+#if !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS)
+/**
+ * No threading available: fork a new process.
+ * This means no shared data structure, and no locking.
+ * Only the main thread ever returns. Exits on errors.
+ * @param thr: the location where to store the thread-id.
+ * @param func: function body of the thread. Return value of func is lost.
+ * @param arg: user argument to func.
+ */
+void
+ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg)
+{
+ pid_t pid = fork();
+ switch(pid) {
+ default: /* main */
+ *thr = (ub_thread_t)pid;
+ return;
+ case 0: /* child */
+ *thr = (ub_thread_t)getpid();
+ (void)(*func)(arg);
+ exit(0);
+ case -1: /* error */
+ fatal_exit("could not fork: %s", strerror(errno));
+ }
+}
+
+/**
+ * There is no threading. Wait for a process to terminate.
+ * Note that ub_thread_t is defined as pid_t.
+ * @param thread: the process id to wait for.
+ */
+void ub_thr_fork_wait(ub_thread_t thread)
+{
+ int status = 0;
+ if(waitpid((pid_t)thread, &status, 0) == -1)
+ log_err("waitpid(%d): %s", (int)thread, strerror(errno));
+ if(status != 0)
+ log_warn("process %d abnormal exit with status %d",
+ (int)thread, status);
+}
+#endif /* !defined(HAVE_PTHREAD) && !defined(HAVE_SOLARIS_THREADS) && !defined(HAVE_WINDOWS_THREADS) */
+
+#ifdef HAVE_SOLARIS_THREADS
+void* ub_thread_key_get(ub_thread_key_t key)
+{
+ void* ret=NULL;
+ LOCKRET(thr_getspecific(key, &ret));
+ return ret;
+}
+#endif
+
+#ifdef HAVE_WINDOWS_THREADS
+/** log a windows GetLastError message */
+static void log_win_err(const char* str, DWORD err)
+{
+ LPTSTR buf;
+ if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
+ NULL, err, 0, (LPTSTR)&buf, 0, NULL) == 0) {
+ /* could not format error message */
+ log_err("%s, GetLastError=%d", str, (int)err);
+ return;
+ }
+ log_err("%s, (err=%d): %s", str, (int)err, buf);
+ LocalFree(buf);
+}
+
+void lock_basic_init(lock_basic_t* lock)
+{
+ /* implement own lock, because windows HANDLE as Mutex usage
+ * uses too many handles and would bog down the whole system. */
+ (void)InterlockedExchange(lock, 0);
+}
+
+void lock_basic_destroy(lock_basic_t* lock)
+{
+ (void)InterlockedExchange(lock, 0);
+}
+
+void lock_basic_lock(lock_basic_t* lock)
+{
+ LONG wait = 1; /* wait 1 msec at first */
+
+ while(InterlockedExchange(lock, 1)) {
+ /* if the old value was 1 then if was already locked */
+ Sleep(wait); /* wait with sleep */
+ wait *= 2; /* exponential backoff for waiting */
+ }
+ /* the old value was 0, but we inserted 1, we locked it! */
+}
+
+void lock_basic_unlock(lock_basic_t* lock)
+{
+ /* unlock it by inserting the value of 0. xchg for cache coherency. */
+ (void)InterlockedExchange(lock, 0);
+}
+
+void ub_thread_key_create(ub_thread_key_t* key, void* f)
+{
+ *key = TlsAlloc();
+ if(*key == TLS_OUT_OF_INDEXES) {
+ *key = 0;
+ log_win_err("TlsAlloc Failed(OUT_OF_INDEXES)", GetLastError());
+ }
+ else ub_thread_key_set(*key, f);
+}
+
+void ub_thread_key_set(ub_thread_key_t key, void* v)
+{
+ if(!TlsSetValue(key, v)) {
+ log_win_err("TlsSetValue failed", GetLastError());
+ }
+}
+
+void* ub_thread_key_get(ub_thread_key_t key)
+{
+ void* ret = (void*)TlsGetValue(key);
+ if(ret == NULL && GetLastError() != ERROR_SUCCESS) {
+ log_win_err("TlsGetValue failed", GetLastError());
+ }
+ return ret;
+}
+
+void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg)
+{
+#ifndef HAVE__BEGINTHREADEX
+ *thr = CreateThread(NULL, /* default security (no inherit handle) */
+ 0, /* default stack size */
+ (LPTHREAD_START_ROUTINE)func, arg,
+ 0, /* default flags, run immediately */
+ NULL); /* do not store thread identifier anywhere */
+#else
+ /* the begintheadex routine setups for the C lib; aligns stack */
+ *thr=(ub_thread_t)_beginthreadex(NULL, 0, (void*)func, arg, 0, NULL);
+#endif
+ if(*thr == NULL) {
+ log_win_err("CreateThread failed", GetLastError());
+ fatal_exit("thread create failed");
+ }
+}
+
+ub_thread_t ub_thread_self(void)
+{
+ return GetCurrentThread();
+}
+
+void ub_thread_join(ub_thread_t thr)
+{
+ DWORD ret = WaitForSingleObject(thr, INFINITE);
+ if(ret == WAIT_FAILED) {
+ log_win_err("WaitForSingleObject(Thread):WAIT_FAILED",
+ GetLastError());
+ } else if(ret == WAIT_TIMEOUT) {
+ log_win_err("WaitForSingleObject(Thread):WAIT_TIMEOUT",
+ GetLastError());
+ }
+ /* and close the handle to the thread */
+ if(!CloseHandle(thr)) {
+ log_win_err("CloseHandle(Thread) failed", GetLastError());
+ }
+}
+#endif /* HAVE_WINDOWS_THREADS */
diff --git a/external/unbound/util/locks.h b/external/unbound/util/locks.h
new file mode 100644
index 000000000..3776912aa
--- /dev/null
+++ b/external/unbound/util/locks.h
@@ -0,0 +1,296 @@
+/**
+ * util/locks.h - unbound locking primitives
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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.
+ */
+
+#ifndef UTIL_LOCKS_H
+#define UTIL_LOCKS_H
+
+/**
+ * \file
+ * Locking primitives.
+ * If pthreads is available, these are used.
+ * If no locking exists, they do nothing.
+ *
+ * The idea is to have different sorts of locks for different tasks.
+ * This allows the locking code to be ported more easily.
+ *
+ * Types of locks that are supported.
+ * o lock_rw: lock that has many readers and one writer (to a data entry).
+ * o lock_basic: simple mutex. Blocking, one person has access only.
+ * This lock is meant for non performance sensitive uses.
+ * o lock_quick: speed lock. For performance sensitive locking of critical
+ * sections. Could be implemented by a mutex or a spinlock.
+ *
+ * Also thread creation and deletion functions are defined here.
+ */
+
+/* if you define your own LOCKRET before including locks.h, you can get most
+ * locking functions without the dependency on log_err. */
+#ifndef LOCKRET
+#include "util/log.h"
+/**
+ * The following macro is used to check the return value of the
+ * pthread calls. They return 0 on success and an errno on error.
+ * The errno is logged to the logfile with a descriptive comment.
+ */
+#define LOCKRET(func) do {\
+ int lockret_err; \
+ if( (lockret_err=(func)) != 0) \
+ log_err("%s at %d could not " #func ": %s", \
+ __FILE__, __LINE__, strerror(lockret_err)); \
+ } while(0)
+#endif
+
+/** DEBUG: use thread debug whenever possible */
+#if defined(HAVE_PTHREAD) && defined(HAVE_PTHREAD_SPINLOCK_T) && defined(ENABLE_LOCK_CHECKS)
+# define USE_THREAD_DEBUG
+#endif
+
+#ifdef USE_THREAD_DEBUG
+/******************* THREAD DEBUG ************************/
+/* (some) checking; to detect races and deadlocks. */
+#include "testcode/checklocks.h"
+
+#else /* USE_THREAD_DEBUG */
+#define lock_protect(lock, area, size) /* nop */
+#define lock_unprotect(lock, area) /* nop */
+#define lock_get_mem(lock) (0) /* nothing */
+#define checklock_start() /* nop */
+#define checklock_stop() /* nop */
+
+#ifdef HAVE_PTHREAD
+#include <pthread.h>
+
+/******************* PTHREAD ************************/
+
+/** use pthread mutex for basic lock */
+typedef pthread_mutex_t lock_basic_t;
+/** small front for pthread init func, NULL is default attrs. */
+#define lock_basic_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
+#define lock_basic_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
+#define lock_basic_lock(lock) LOCKRET(pthread_mutex_lock(lock))
+#define lock_basic_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
+
+#ifndef HAVE_PTHREAD_RWLOCK_T
+/** in case rwlocks are not supported, use a mutex. */
+typedef pthread_mutex_t lock_rw_t;
+#define lock_rw_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
+#define lock_rw_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
+#define lock_rw_rdlock(lock) LOCKRET(pthread_mutex_lock(lock))
+#define lock_rw_wrlock(lock) LOCKRET(pthread_mutex_lock(lock))
+#define lock_rw_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
+#else /* HAVE_PTHREAD_RWLOCK_T */
+/** we use the pthread rwlock */
+typedef pthread_rwlock_t lock_rw_t;
+/** small front for pthread init func, NULL is default attrs. */
+#define lock_rw_init(lock) LOCKRET(pthread_rwlock_init(lock, NULL))
+#define lock_rw_destroy(lock) LOCKRET(pthread_rwlock_destroy(lock))
+#define lock_rw_rdlock(lock) LOCKRET(pthread_rwlock_rdlock(lock))
+#define lock_rw_wrlock(lock) LOCKRET(pthread_rwlock_wrlock(lock))
+#define lock_rw_unlock(lock) LOCKRET(pthread_rwlock_unlock(lock))
+#endif /* HAVE_PTHREAD_RWLOCK_T */
+
+#ifndef HAVE_PTHREAD_SPINLOCK_T
+/** in case spinlocks are not supported, use a mutex. */
+typedef pthread_mutex_t lock_quick_t;
+/** small front for pthread init func, NULL is default attrs. */
+#define lock_quick_init(lock) LOCKRET(pthread_mutex_init(lock, NULL))
+#define lock_quick_destroy(lock) LOCKRET(pthread_mutex_destroy(lock))
+#define lock_quick_lock(lock) LOCKRET(pthread_mutex_lock(lock))
+#define lock_quick_unlock(lock) LOCKRET(pthread_mutex_unlock(lock))
+
+#else /* HAVE_PTHREAD_SPINLOCK_T */
+/** use pthread spinlock for the quick lock */
+typedef pthread_spinlock_t lock_quick_t;
+/**
+ * allocate process private since this is available whether
+ * Thread Process-Shared Synchronization is supported or not.
+ * This means only threads inside this process may access the lock.
+ * (not threads from another process that shares memory).
+ * spinlocks are not supported on all pthread platforms.
+ */
+#define lock_quick_init(lock) LOCKRET(pthread_spin_init(lock, PTHREAD_PROCESS_PRIVATE))
+#define lock_quick_destroy(lock) LOCKRET(pthread_spin_destroy(lock))
+#define lock_quick_lock(lock) LOCKRET(pthread_spin_lock(lock))
+#define lock_quick_unlock(lock) LOCKRET(pthread_spin_unlock(lock))
+
+#endif /* HAVE SPINLOCK */
+
+/** Thread creation */
+typedef pthread_t ub_thread_t;
+/** Pass where to store tread_t in thr. Use default NULL attributes. */
+#define ub_thread_create(thr, func, arg) LOCKRET(pthread_create(thr, NULL, func, arg))
+/** get self id. */
+#define ub_thread_self() pthread_self()
+/** wait for another thread to terminate */
+#define ub_thread_join(thread) LOCKRET(pthread_join(thread, NULL))
+typedef pthread_key_t ub_thread_key_t;
+#define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f))
+#define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v))
+#define ub_thread_key_get(key) pthread_getspecific(key)
+
+#else /* we do not HAVE_PTHREAD */
+#ifdef HAVE_SOLARIS_THREADS
+
+/******************* SOLARIS THREADS ************************/
+#include <synch.h>
+#include <thread.h>
+
+typedef rwlock_t lock_rw_t;
+#define lock_rw_init(lock) LOCKRET(rwlock_init(lock, USYNC_THREAD, NULL))
+#define lock_rw_destroy(lock) LOCKRET(rwlock_destroy(lock))
+#define lock_rw_rdlock(lock) LOCKRET(rw_rdlock(lock))
+#define lock_rw_wrlock(lock) LOCKRET(rw_wrlock(lock))
+#define lock_rw_unlock(lock) LOCKRET(rw_unlock(lock))
+
+/** use basic mutex */
+typedef mutex_t lock_basic_t;
+#define lock_basic_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
+#define lock_basic_destroy(lock) LOCKRET(mutex_destroy(lock))
+#define lock_basic_lock(lock) LOCKRET(mutex_lock(lock))
+#define lock_basic_unlock(lock) LOCKRET(mutex_unlock(lock))
+
+/** No spinlocks in solaris threads API. Use a mutex. */
+typedef mutex_t lock_quick_t;
+#define lock_quick_init(lock) LOCKRET(mutex_init(lock, USYNC_THREAD, NULL))
+#define lock_quick_destroy(lock) LOCKRET(mutex_destroy(lock))
+#define lock_quick_lock(lock) LOCKRET(mutex_lock(lock))
+#define lock_quick_unlock(lock) LOCKRET(mutex_unlock(lock))
+
+/** Thread creation, create a default thread. */
+typedef thread_t ub_thread_t;
+#define ub_thread_create(thr, func, arg) LOCKRET(thr_create(NULL, NULL, func, arg, NULL, thr))
+#define ub_thread_self() thr_self()
+#define ub_thread_join(thread) LOCKRET(thr_join(thread, NULL, NULL))
+typedef thread_key_t ub_thread_key_t;
+#define ub_thread_key_create(key, f) LOCKRET(thr_keycreate(key, f))
+#define ub_thread_key_set(key, v) LOCKRET(thr_setspecific(key, v))
+void* ub_thread_key_get(ub_thread_key_t key);
+
+
+#else /* we do not HAVE_SOLARIS_THREADS and no PTHREADS */
+/******************* WINDOWS THREADS ************************/
+#ifdef HAVE_WINDOWS_THREADS
+#include <windows.h>
+
+/* Use a mutex */
+typedef LONG lock_rw_t;
+#define lock_rw_init(lock) lock_basic_init(lock)
+#define lock_rw_destroy(lock) lock_basic_destroy(lock)
+#define lock_rw_rdlock(lock) lock_basic_lock(lock)
+#define lock_rw_wrlock(lock) lock_basic_lock(lock)
+#define lock_rw_unlock(lock) lock_basic_unlock(lock)
+
+/** the basic lock is a mutex, implemented opaquely, for error handling. */
+typedef LONG lock_basic_t;
+void lock_basic_init(lock_basic_t* lock);
+void lock_basic_destroy(lock_basic_t* lock);
+void lock_basic_lock(lock_basic_t* lock);
+void lock_basic_unlock(lock_basic_t* lock);
+
+/** on windows no spinlock, use mutex too. */
+typedef LONG lock_quick_t;
+#define lock_quick_init(lock) lock_basic_init(lock)
+#define lock_quick_destroy(lock) lock_basic_destroy(lock)
+#define lock_quick_lock(lock) lock_basic_lock(lock)
+#define lock_quick_unlock(lock) lock_basic_unlock(lock)
+
+/** Thread creation, create a default thread. */
+typedef HANDLE ub_thread_t;
+void ub_thread_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
+ub_thread_t ub_thread_self(void);
+void ub_thread_join(ub_thread_t thr);
+typedef DWORD ub_thread_key_t;
+void ub_thread_key_create(ub_thread_key_t* key, void* f);
+void ub_thread_key_set(ub_thread_key_t key, void* v);
+void* ub_thread_key_get(ub_thread_key_t key);
+
+#else /* we do not HAVE_SOLARIS_THREADS, PTHREADS or WINDOWS_THREADS */
+
+/******************* NO THREADS ************************/
+#define THREADS_DISABLED 1
+/** In case there is no thread support, define locks to do nothing */
+typedef int lock_rw_t;
+#define lock_rw_init(lock) /* nop */
+#define lock_rw_destroy(lock) /* nop */
+#define lock_rw_rdlock(lock) /* nop */
+#define lock_rw_wrlock(lock) /* nop */
+#define lock_rw_unlock(lock) /* nop */
+
+/** define locks to do nothing */
+typedef int lock_basic_t;
+#define lock_basic_init(lock) /* nop */
+#define lock_basic_destroy(lock) /* nop */
+#define lock_basic_lock(lock) /* nop */
+#define lock_basic_unlock(lock) /* nop */
+
+/** define locks to do nothing */
+typedef int lock_quick_t;
+#define lock_quick_init(lock) /* nop */
+#define lock_quick_destroy(lock) /* nop */
+#define lock_quick_lock(lock) /* nop */
+#define lock_quick_unlock(lock) /* nop */
+
+/** Thread creation, threads do not exist */
+typedef pid_t ub_thread_t;
+/** ub_thread_create is simulated with fork (extremely heavy threads,
+ * with no shared memory). */
+#define ub_thread_create(thr, func, arg) \
+ ub_thr_fork_create(thr, func, arg)
+#define ub_thread_self() getpid()
+#define ub_thread_join(thread) ub_thr_fork_wait(thread)
+void ub_thr_fork_wait(ub_thread_t thread);
+void ub_thr_fork_create(ub_thread_t* thr, void* (*func)(void*), void* arg);
+typedef void* ub_thread_key_t;
+#define ub_thread_key_create(key, f) (*(key)) = NULL
+#define ub_thread_key_set(key, v) (key) = (v)
+#define ub_thread_key_get(key) (key)
+
+#endif /* HAVE_WINDOWS_THREADS */
+#endif /* HAVE_SOLARIS_THREADS */
+#endif /* HAVE_PTHREAD */
+#endif /* USE_THREAD_DEBUG */
+
+/**
+ * Block all signals for this thread.
+ * fatal exit on error.
+ */
+void ub_thread_blocksigs(void);
+
+/**
+ * unblock one signal for this thread.
+ */
+void ub_thread_sig_unblock(int sig);
+
+#endif /* UTIL_LOCKS_H */
diff --git a/external/unbound/util/log.c b/external/unbound/util/log.c
new file mode 100644
index 000000000..f90efa71c
--- /dev/null
+++ b/external/unbound/util/log.c
@@ -0,0 +1,485 @@
+/*
+ * util/log.c - implementation of the log code
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ * Implementation of log.h.
+ */
+
+#include "config.h"
+#include "util/log.h"
+#include "util/locks.h"
+#include "ldns/sbuffer.h"
+#include <stdarg.h>
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#else
+/**define LOG_ constants */
+# define LOG_CRIT 2
+# define LOG_ERR 3
+# define LOG_WARNING 4
+# define LOG_NOTICE 5
+# define LOG_INFO 6
+# define LOG_DEBUG 7
+#endif
+#ifdef UB_ON_WINDOWS
+# include "winrc/win_svc.h"
+#endif
+
+/* default verbosity */
+enum verbosity_value verbosity = 0;
+/** the file logged to. */
+static FILE* logfile = 0;
+/** if key has been created */
+static int key_created = 0;
+/** pthread key for thread ids in logfile */
+static ub_thread_key_t logkey;
+#ifndef THREADS_DISABLED
+/** pthread mutex to protect FILE* */
+static lock_quick_t log_lock;
+#endif
+/** the identity of this executable/process */
+static const char* ident="unbound";
+#if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS)
+/** are we using syslog(3) to log to */
+static int logging_to_syslog = 0;
+#endif /* HAVE_SYSLOG_H */
+/** time to print in log, if NULL, use time(2) */
+static time_t* log_now = NULL;
+/** print time in UTC or in secondsfrom1970 */
+static int log_time_asc = 0;
+
+void
+log_init(const char* filename, int use_syslog, const char* chrootdir)
+{
+ FILE *f;
+ if(!key_created) {
+ key_created = 1;
+ ub_thread_key_create(&logkey, NULL);
+ lock_quick_init(&log_lock);
+ }
+ lock_quick_lock(&log_lock);
+ if(logfile
+#if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS)
+ || logging_to_syslog
+#endif
+ ) {
+ lock_quick_unlock(&log_lock); /* verbose() needs the lock */
+ verbose(VERB_QUERY, "switching log to %s",
+ use_syslog?"syslog":(filename&&filename[0]?filename:"stderr"));
+ lock_quick_lock(&log_lock);
+ }
+ if(logfile && logfile != stderr)
+ fclose(logfile);
+#ifdef HAVE_SYSLOG_H
+ if(logging_to_syslog) {
+ closelog();
+ logging_to_syslog = 0;
+ }
+ if(use_syslog) {
+ /* do not delay opening until first write, because we may
+ * chroot and no longer be able to access dev/log and so on */
+ openlog(ident, LOG_NDELAY, LOG_DAEMON);
+ logging_to_syslog = 1;
+ lock_quick_unlock(&log_lock);
+ return;
+ }
+#elif defined(UB_ON_WINDOWS)
+ if(logging_to_syslog) {
+ logging_to_syslog = 0;
+ }
+ if(use_syslog) {
+ logging_to_syslog = 1;
+ lock_quick_unlock(&log_lock);
+ return;
+ }
+#endif /* HAVE_SYSLOG_H */
+ if(!filename || !filename[0]) {
+ logfile = stderr;
+ lock_quick_unlock(&log_lock);
+ return;
+ }
+ /* open the file for logging */
+ if(chrootdir && chrootdir[0] && strncmp(filename, chrootdir,
+ strlen(chrootdir)) == 0)
+ filename += strlen(chrootdir);
+ f = fopen(filename, "a");
+ if(!f) {
+ lock_quick_unlock(&log_lock);
+ log_err("Could not open logfile %s: %s", filename,
+ strerror(errno));
+ return;
+ }
+#ifndef UB_ON_WINDOWS
+ /* line buffering does not work on windows */
+ setvbuf(f, NULL, (int)_IOLBF, 0);
+#endif
+ logfile = f;
+ lock_quick_unlock(&log_lock);
+}
+
+void log_file(FILE *f)
+{
+ lock_quick_lock(&log_lock);
+ logfile = f;
+ lock_quick_unlock(&log_lock);
+}
+
+void log_thread_set(int* num)
+{
+ ub_thread_key_set(logkey, num);
+}
+
+void log_ident_set(const char* id)
+{
+ ident = id;
+}
+
+void log_set_time(time_t* t)
+{
+ log_now = t;
+}
+
+void log_set_time_asc(int use_asc)
+{
+ log_time_asc = use_asc;
+}
+
+void
+log_vmsg(int pri, const char* type,
+ const char *format, va_list args)
+{
+ char message[MAXSYSLOGMSGLEN];
+ unsigned int* tid = (unsigned int*)ub_thread_key_get(logkey);
+ time_t now;
+#if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R)
+ char tmbuf[32];
+ struct tm tm;
+#elif defined(UB_ON_WINDOWS)
+ char tmbuf[128], dtbuf[128];
+#endif
+ (void)pri;
+ vsnprintf(message, sizeof(message), format, args);
+#ifdef HAVE_SYSLOG_H
+ if(logging_to_syslog) {
+ syslog(pri, "[%d:%x] %s: %s",
+ (int)getpid(), tid?*tid:0, type, message);
+ return;
+ }
+#elif defined(UB_ON_WINDOWS)
+ if(logging_to_syslog) {
+ char m[32768];
+ HANDLE* s;
+ LPCTSTR str = m;
+ DWORD tp = MSG_GENERIC_ERR;
+ WORD wt = EVENTLOG_ERROR_TYPE;
+ if(strcmp(type, "info") == 0) {
+ tp=MSG_GENERIC_INFO;
+ wt=EVENTLOG_INFORMATION_TYPE;
+ } else if(strcmp(type, "warning") == 0) {
+ tp=MSG_GENERIC_WARN;
+ wt=EVENTLOG_WARNING_TYPE;
+ } else if(strcmp(type, "notice") == 0
+ || strcmp(type, "debug") == 0) {
+ tp=MSG_GENERIC_SUCCESS;
+ wt=EVENTLOG_SUCCESS;
+ }
+ snprintf(m, sizeof(m), "[%s:%x] %s: %s",
+ ident, tid?*tid:0, type, message);
+ s = RegisterEventSource(NULL, SERVICE_NAME);
+ if(!s) return;
+ ReportEvent(s, wt, 0, tp, NULL, 1, 0, &str, NULL);
+ DeregisterEventSource(s);
+ return;
+ }
+#endif /* HAVE_SYSLOG_H */
+ lock_quick_lock(&log_lock);
+ if(!logfile) {
+ lock_quick_unlock(&log_lock);
+ return;
+ }
+ if(log_now)
+ now = (time_t)*log_now;
+ else now = (time_t)time(NULL);
+#if defined(HAVE_STRFTIME) && defined(HAVE_LOCALTIME_R)
+ if(log_time_asc && strftime(tmbuf, sizeof(tmbuf), "%b %d %H:%M:%S",
+ localtime_r(&now, &tm))%(sizeof(tmbuf)) != 0) {
+ /* %sizeof buf!=0 because old strftime returned max on error */
+ fprintf(logfile, "%s %s[%d:%x] %s: %s\n", tmbuf,
+ ident, (int)getpid(), tid?*tid:0, type, message);
+ } else
+#elif defined(UB_ON_WINDOWS)
+ if(log_time_asc && GetTimeFormat(LOCALE_USER_DEFAULT, 0, NULL, NULL,
+ tmbuf, sizeof(tmbuf)) && GetDateFormat(LOCALE_USER_DEFAULT, 0,
+ NULL, NULL, dtbuf, sizeof(dtbuf))) {
+ fprintf(logfile, "%s %s %s[%d:%x] %s: %s\n", dtbuf, tmbuf,
+ ident, (int)getpid(), tid?*tid:0, type, message);
+ } else
+#endif
+ fprintf(logfile, "[" ARG_LL "d] %s[%d:%x] %s: %s\n", (long long)now,
+ ident, (int)getpid(), tid?*tid:0, type, message);
+#ifdef UB_ON_WINDOWS
+ /* line buffering does not work on windows */
+ fflush(logfile);
+#endif
+ lock_quick_unlock(&log_lock);
+}
+
+/**
+ * implementation of log_info
+ * @param format: format string printf-style.
+ */
+void
+log_info(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ log_vmsg(LOG_INFO, "info", format, args);
+ va_end(args);
+}
+
+/**
+ * implementation of log_err
+ * @param format: format string printf-style.
+ */
+void
+log_err(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ log_vmsg(LOG_ERR, "error", format, args);
+ va_end(args);
+}
+
+/**
+ * implementation of log_warn
+ * @param format: format string printf-style.
+ */
+void
+log_warn(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ log_vmsg(LOG_WARNING, "warning", format, args);
+ va_end(args);
+}
+
+/**
+ * implementation of fatal_exit
+ * @param format: format string printf-style.
+ */
+void
+fatal_exit(const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ log_vmsg(LOG_CRIT, "fatal error", format, args);
+ va_end(args);
+ exit(1);
+}
+
+/**
+ * implementation of verbose
+ * @param level: verbose level for the message.
+ * @param format: format string printf-style.
+ */
+void
+verbose(enum verbosity_value level, const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ if(verbosity >= level) {
+ if(level == VERB_OPS)
+ log_vmsg(LOG_NOTICE, "notice", format, args);
+ else if(level == VERB_DETAIL)
+ log_vmsg(LOG_INFO, "info", format, args);
+ else log_vmsg(LOG_DEBUG, "debug", format, args);
+ }
+ va_end(args);
+}
+
+/** log hex data */
+static void
+log_hex_f(enum verbosity_value v, const char* msg, void* data, size_t length)
+{
+ size_t i, j;
+ uint8_t* data8 = (uint8_t*)data;
+ const char* hexchar = "0123456789ABCDEF";
+ char buf[1024+1]; /* alloc blocksize hex chars + \0 */
+ const size_t blocksize = 512;
+ size_t len;
+
+ if(length == 0) {
+ verbose(v, "%s[%u]", msg, (unsigned)length);
+ return;
+ }
+
+ for(i=0; i<length; i+=blocksize/2) {
+ len = blocksize/2;
+ if(length - i < blocksize/2)
+ len = length - i;
+ for(j=0; j<len; j++) {
+ buf[j*2] = hexchar[ data8[i+j] >> 4 ];
+ buf[j*2 + 1] = hexchar[ data8[i+j] & 0xF ];
+ }
+ buf[len*2] = 0;
+ verbose(v, "%s[%u:%u] %.*s", msg, (unsigned)length,
+ (unsigned)i, (int)len*2, buf);
+ }
+}
+
+void
+log_hex(const char* msg, void* data, size_t length)
+{
+ log_hex_f(verbosity, msg, data, length);
+}
+
+void log_buf(enum verbosity_value level, const char* msg, sldns_buffer* buf)
+{
+ if(verbosity < level)
+ return;
+ log_hex_f(level, msg, sldns_buffer_begin(buf), sldns_buffer_limit(buf));
+}
+
+#ifdef USE_WINSOCK
+char* wsa_strerror(DWORD err)
+{
+ static char unknown[32];
+
+ switch(err) {
+ case WSA_INVALID_HANDLE: return "Specified event object handle is invalid.";
+ case WSA_NOT_ENOUGH_MEMORY: return "Insufficient memory available.";
+ case WSA_INVALID_PARAMETER: return "One or more parameters are invalid.";
+ case WSA_OPERATION_ABORTED: return "Overlapped operation aborted.";
+ case WSA_IO_INCOMPLETE: return "Overlapped I/O event object not in signaled state.";
+ case WSA_IO_PENDING: return "Overlapped operations will complete later.";
+ case WSAEINTR: return "Interrupted function call.";
+ case WSAEBADF: return "File handle is not valid.";
+ case WSAEACCES: return "Permission denied.";
+ case WSAEFAULT: return "Bad address.";
+ case WSAEINVAL: return "Invalid argument.";
+ case WSAEMFILE: return "Too many open files.";
+ case WSAEWOULDBLOCK: return "Resource temporarily unavailable.";
+ case WSAEINPROGRESS: return "Operation now in progress.";
+ case WSAEALREADY: return "Operation already in progress.";
+ case WSAENOTSOCK: return "Socket operation on nonsocket.";
+ case WSAEDESTADDRREQ: return "Destination address required.";
+ case WSAEMSGSIZE: return "Message too long.";
+ case WSAEPROTOTYPE: return "Protocol wrong type for socket.";
+ case WSAENOPROTOOPT: return "Bad protocol option.";
+ case WSAEPROTONOSUPPORT: return "Protocol not supported.";
+ case WSAESOCKTNOSUPPORT: return "Socket type not supported.";
+ case WSAEOPNOTSUPP: return "Operation not supported.";
+ case WSAEPFNOSUPPORT: return "Protocol family not supported.";
+ case WSAEAFNOSUPPORT: return "Address family not supported by protocol family.";
+ case WSAEADDRINUSE: return "Address already in use.";
+ case WSAEADDRNOTAVAIL: return "Cannot assign requested address.";
+ case WSAENETDOWN: return "Network is down.";
+ case WSAENETUNREACH: return "Network is unreachable.";
+ case WSAENETRESET: return "Network dropped connection on reset.";
+ case WSAECONNABORTED: return "Software caused connection abort.";
+ case WSAECONNRESET: return "Connection reset by peer.";
+ case WSAENOBUFS: return "No buffer space available.";
+ case WSAEISCONN: return "Socket is already connected.";
+ case WSAENOTCONN: return "Socket is not connected.";
+ case WSAESHUTDOWN: return "Cannot send after socket shutdown.";
+ case WSAETOOMANYREFS: return "Too many references.";
+ case WSAETIMEDOUT: return "Connection timed out.";
+ case WSAECONNREFUSED: return "Connection refused.";
+ case WSAELOOP: return "Cannot translate name.";
+ case WSAENAMETOOLONG: return "Name too long.";
+ case WSAEHOSTDOWN: return "Host is down.";
+ case WSAEHOSTUNREACH: return "No route to host.";
+ case WSAENOTEMPTY: return "Directory not empty.";
+ case WSAEPROCLIM: return "Too many processes.";
+ case WSAEUSERS: return "User quota exceeded.";
+ case WSAEDQUOT: return "Disk quota exceeded.";
+ case WSAESTALE: return "Stale file handle reference.";
+ case WSAEREMOTE: return "Item is remote.";
+ case WSASYSNOTREADY: return "Network subsystem is unavailable.";
+ case WSAVERNOTSUPPORTED: return "Winsock.dll version out of range.";
+ case WSANOTINITIALISED: return "Successful WSAStartup not yet performed.";
+ case WSAEDISCON: return "Graceful shutdown in progress.";
+ case WSAENOMORE: return "No more results.";
+ case WSAECANCELLED: return "Call has been canceled.";
+ case WSAEINVALIDPROCTABLE: return "Procedure call table is invalid.";
+ case WSAEINVALIDPROVIDER: return "Service provider is invalid.";
+ case WSAEPROVIDERFAILEDINIT: return "Service provider failed to initialize.";
+ case WSASYSCALLFAILURE: return "System call failure.";
+ case WSASERVICE_NOT_FOUND: return "Service not found.";
+ case WSATYPE_NOT_FOUND: return "Class type not found.";
+ case WSA_E_NO_MORE: return "No more results.";
+ case WSA_E_CANCELLED: return "Call was canceled.";
+ case WSAEREFUSED: return "Database query was refused.";
+ case WSAHOST_NOT_FOUND: return "Host not found.";
+ case WSATRY_AGAIN: return "Nonauthoritative host not found.";
+ case WSANO_RECOVERY: return "This is a nonrecoverable error.";
+ case WSANO_DATA: return "Valid name, no data record of requested type.";
+ case WSA_QOS_RECEIVERS: return "QOS receivers.";
+ case WSA_QOS_SENDERS: return "QOS senders.";
+ case WSA_QOS_NO_SENDERS: return "No QOS senders.";
+ case WSA_QOS_NO_RECEIVERS: return "QOS no receivers.";
+ case WSA_QOS_REQUEST_CONFIRMED: return "QOS request confirmed.";
+ case WSA_QOS_ADMISSION_FAILURE: return "QOS admission error.";
+ case WSA_QOS_POLICY_FAILURE: return "QOS policy failure.";
+ case WSA_QOS_BAD_STYLE: return "QOS bad style.";
+ case WSA_QOS_BAD_OBJECT: return "QOS bad object.";
+ case WSA_QOS_TRAFFIC_CTRL_ERROR: return "QOS traffic control error.";
+ case WSA_QOS_GENERIC_ERROR: return "QOS generic error.";
+ case WSA_QOS_ESERVICETYPE: return "QOS service type error.";
+ case WSA_QOS_EFLOWSPEC: return "QOS flowspec error.";
+ case WSA_QOS_EPROVSPECBUF: return "Invalid QOS provider buffer.";
+ case WSA_QOS_EFILTERSTYLE: return "Invalid QOS filter style.";
+ case WSA_QOS_EFILTERTYPE: return "Invalid QOS filter type.";
+ case WSA_QOS_EFILTERCOUNT: return "Incorrect QOS filter count.";
+ case WSA_QOS_EOBJLENGTH: return "Invalid QOS object length.";
+ case WSA_QOS_EFLOWCOUNT: return "Incorrect QOS flow count.";
+ /*case WSA_QOS_EUNKOWNPSOBJ: return "Unrecognized QOS object.";*/
+ case WSA_QOS_EPOLICYOBJ: return "Invalid QOS policy object.";
+ case WSA_QOS_EFLOWDESC: return "Invalid QOS flow descriptor.";
+ case WSA_QOS_EPSFLOWSPEC: return "Invalid QOS provider-specific flowspec.";
+ case WSA_QOS_EPSFILTERSPEC: return "Invalid QOS provider-specific filterspec.";
+ case WSA_QOS_ESDMODEOBJ: return "Invalid QOS shape discard mode object.";
+ case WSA_QOS_ESHAPERATEOBJ: return "Invalid QOS shaping rate object.";
+ case WSA_QOS_RESERVED_PETYPE: return "Reserved policy QOS element type.";
+ default:
+ snprintf(unknown, sizeof(unknown),
+ "unknown WSA error code %d", (int)err);
+ return unknown;
+ }
+}
+#endif /* USE_WINSOCK */
diff --git a/external/unbound/util/log.h b/external/unbound/util/log.h
new file mode 100644
index 000000000..ea283da7b
--- /dev/null
+++ b/external/unbound/util/log.h
@@ -0,0 +1,198 @@
+/*
+ * util/log.h - logging service
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 logging functions.
+ */
+
+#ifndef UTIL_LOG_H
+#define UTIL_LOG_H
+struct sldns_buffer;
+
+/**
+ * verbosity value:
+ */
+enum verbosity_value {
+ /** 0 - no verbose messages */
+ NO_VERBOSE = 0,
+ /** 1 - operational information */
+ VERB_OPS,
+ /** 2 - detailed information */
+ VERB_DETAIL,
+ /** 3 - query level information */
+ VERB_QUERY,
+ /** 4 - algorithm level information */
+ VERB_ALGO,
+ /** 5 - querier client information */
+ VERB_CLIENT
+};
+
+/** The global verbosity setting */
+extern enum verbosity_value verbosity;
+
+/**
+ * log a verbose message, pass the level for this message.
+ * It has printf formatted arguments. No trailing newline is needed.
+ * @param level: verbosity level for this message, compared to global
+ * verbosity setting.
+ * @param format: printf-style format string. Arguments follow.
+ */
+void verbose(enum verbosity_value level,
+ const char* format, ...) ATTR_FORMAT(printf, 2, 3);
+
+/**
+ * call this to initialize logging services.
+ * @param filename: if NULL stderr is used.
+ * @param use_syslog: set to true to ignore filename and use syslog(3).
+ * @param chrootdir: to which directory we have been chrooted, if any.
+ */
+void log_init(const char* filename, int use_syslog, const char* chrootdir);
+
+/**
+ * Set logging to go to the specified file *.
+ * This setting does not affect the use_syslog setting.
+ * @param f: to that file, or pass NULL to disable logging.
+ */
+void log_file(FILE *f);
+
+/**
+ * Init a thread (will print this number for the thread log entries).
+ * Must be called from the thread itself. If not called 0 is printed.
+ * @param num: number to print for this thread. Owned by caller, must
+ * continue to exist.
+ */
+void log_thread_set(int* num);
+
+/**
+ * Set identity to print, default is 'unbound'.
+ * @param id: string to print. Name of executable.
+ */
+void log_ident_set(const char* id);
+
+/**
+ * Set the time value to print in log entries.
+ * @param t: the point is copied and used to find the time.
+ * if NULL, time(2) is used.
+ */
+void log_set_time(time_t* t);
+
+/**
+ * Set if the time value is printed ascii or decimal in log entries.
+ * @param use_asc: if true, ascii is printed, otherwise decimal.
+ * If the conversion fails or you have no time functions,
+ * decimal is printed.
+ */
+void log_set_time_asc(int use_asc);
+
+/**
+ * Log informational message.
+ * Pass printf formatted arguments. No trailing newline is needed.
+ * @param format: printf-style format string. Arguments follow.
+ */
+void log_info(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
+
+/**
+ * Log error message.
+ * Pass printf formatted arguments. No trailing newline is needed.
+ * @param format: printf-style format string. Arguments follow.
+ */
+void log_err(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
+
+/**
+ * Log warning message.
+ * Pass printf formatted arguments. No trailing newline is needed.
+ * @param format: printf-style format string. Arguments follow.
+ */
+void log_warn(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
+
+/**
+ * Log a hex-string to the log. Can be any length.
+ * performs mallocs to do so, slow. But debug useful.
+ * @param msg: string desc to accompany the hexdump.
+ * @param data: data to dump in hex format.
+ * @param length: length of data.
+ */
+void log_hex(const char* msg, void* data, size_t length);
+
+/**
+ * Easy alternative for log_hex, takes a sldns_buffer.
+ * @param level: verbosity level for this message, compared to global
+ * verbosity setting.
+ * @param msg: string desc to print
+ * @param buf: the buffer.
+ */
+void log_buf(enum verbosity_value level, const char* msg, struct sldns_buffer* buf);
+
+/**
+ * Log fatal error message, and exit the current process.
+ * Pass printf formatted arguments. No trailing newline is needed.
+ * @param format: printf-style format string. Arguments follow.
+ */
+void fatal_exit(const char* format, ...) ATTR_FORMAT(printf, 1, 2);
+
+/**
+ * va_list argument version of log_info.
+ * @param pri: priority type, for example 5 (INFO).
+ * @param type: string to designate type of message (info, error).
+ * @param format: the printf style format to print. no newline.
+ * @param args: arguments for format string.
+ */
+void log_vmsg(int pri, const char* type, const char* format, va_list args);
+
+/**
+ * an assertion that is thrown to the logfile.
+ */
+#ifdef UNBOUND_DEBUG
+# define log_assert(x) \
+ do { if(!(x)) \
+ fatal_exit("%s:%d: %s: assertion %s failed", \
+ __FILE__, __LINE__, __func__, #x); \
+ } while(0);
+#else
+# define log_assert(x) /*nothing*/
+#endif
+
+#ifdef USE_WINSOCK
+/**
+ * Convert WSA error into string.
+ * @param err: from WSAGetLastError()
+ * @return: string.
+ */
+char* wsa_strerror(DWORD err);
+#endif /* USE_WINSOCK */
+
+#endif /* UTIL_LOG_H */
diff --git a/external/unbound/util/mini_event.c b/external/unbound/util/mini_event.c
new file mode 100644
index 000000000..40dca375a
--- /dev/null
+++ b/external/unbound/util/mini_event.c
@@ -0,0 +1,394 @@
+/*
+ * mini_event.c - implementation of part of libevent api, portably.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ * fake libevent implementation. Less broad in functionality, and only
+ * supports select(2).
+ */
+
+#include "config.h"
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include <sys/time.h>
+
+#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
+#include <signal.h>
+#include "util/mini_event.h"
+#include "util/fptr_wlist.h"
+
+/** compare events in tree, based on timevalue, ptr for uniqueness */
+int mini_ev_cmp(const void* a, const void* b)
+{
+ const struct event *e = (const struct event*)a;
+ const struct event *f = (const struct event*)b;
+ if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
+ return -1;
+ if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
+ return 1;
+ if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
+ return -1;
+ if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
+ return 1;
+ if(e < f)
+ return -1;
+ if(e > f)
+ return 1;
+ return 0;
+}
+
+/** set time */
+static int
+settime(struct event_base* base)
+{
+ if(gettimeofday(base->time_tv, NULL) < 0) {
+ return -1;
+ }
+#ifndef S_SPLINT_S
+ *base->time_secs = (time_t)base->time_tv->tv_sec;
+#endif
+ return 0;
+}
+
+/** create event base */
+void *event_init(time_t* time_secs, struct timeval* time_tv)
+{
+ struct event_base* base = (struct event_base*)malloc(
+ sizeof(struct event_base));
+ if(!base)
+ return NULL;
+ memset(base, 0, sizeof(*base));
+ base->time_secs = time_secs;
+ base->time_tv = time_tv;
+ if(settime(base) < 0) {
+ event_base_free(base);
+ return NULL;
+ }
+ base->times = rbtree_create(mini_ev_cmp);
+ if(!base->times) {
+ event_base_free(base);
+ return NULL;
+ }
+ base->capfd = MAX_FDS;
+#ifdef FD_SETSIZE
+ if((int)FD_SETSIZE < base->capfd)
+ base->capfd = (int)FD_SETSIZE;
+#endif
+ base->fds = (struct event**)calloc((size_t)base->capfd,
+ sizeof(struct event*));
+ if(!base->fds) {
+ event_base_free(base);
+ return NULL;
+ }
+ base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*));
+ if(!base->signals) {
+ event_base_free(base);
+ return NULL;
+ }
+#ifndef S_SPLINT_S
+ FD_ZERO(&base->reads);
+ FD_ZERO(&base->writes);
+#endif
+ return base;
+}
+
+/** get version */
+const char *event_get_version(void)
+{
+ return "mini-event-"PACKAGE_VERSION;
+}
+
+/** get polling method, select */
+const char *event_get_method(void)
+{
+ return "select";
+}
+
+/** call timeouts handlers, and return how long to wait for next one or -1 */
+static void handle_timeouts(struct event_base* base, struct timeval* now,
+ struct timeval* wait)
+{
+ struct event* p;
+#ifndef S_SPLINT_S
+ wait->tv_sec = (time_t)-1;
+#endif
+
+ while((rbnode_t*)(p = (struct event*)rbtree_first(base->times))
+ !=RBTREE_NULL) {
+#ifndef S_SPLINT_S
+ if(p->ev_timeout.tv_sec > now->tv_sec ||
+ (p->ev_timeout.tv_sec==now->tv_sec &&
+ p->ev_timeout.tv_usec > now->tv_usec)) {
+ /* there is a next larger timeout. wait for it */
+ wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
+ if(now->tv_usec > p->ev_timeout.tv_usec) {
+ wait->tv_sec--;
+ wait->tv_usec = 1000000 - (now->tv_usec -
+ p->ev_timeout.tv_usec);
+ } else {
+ wait->tv_usec = p->ev_timeout.tv_usec
+ - now->tv_usec;
+ }
+ return;
+ }
+#endif
+ /* event times out, remove it */
+ (void)rbtree_delete(base->times, p);
+ p->ev_events &= ~EV_TIMEOUT;
+ fptr_ok(fptr_whitelist_event(p->ev_callback));
+ (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
+ }
+}
+
+/** call select and callbacks for that */
+static int handle_select(struct event_base* base, struct timeval* wait)
+{
+ fd_set r, w;
+ int ret, i;
+
+#ifndef S_SPLINT_S
+ if(wait->tv_sec==(time_t)-1)
+ wait = NULL;
+#endif
+ memmove(&r, &base->reads, sizeof(fd_set));
+ memmove(&w, &base->writes, sizeof(fd_set));
+ memmove(&base->ready, &base->content, sizeof(fd_set));
+
+ if((ret = select(base->maxfd+1, &r, &w, NULL, wait)) == -1) {
+ ret = errno;
+ if(settime(base) < 0)
+ return -1;
+ errno = ret;
+ if(ret == EAGAIN || ret == EINTR)
+ return 0;
+ return -1;
+ }
+ if(settime(base) < 0)
+ return -1;
+
+ for(i=0; i<base->maxfd+1; i++) {
+ short bits = 0;
+ if(!base->fds[i] || !(FD_ISSET(i, &base->ready))) {
+ continue;
+ }
+ if(FD_ISSET(i, &r)) {
+ bits |= EV_READ;
+ ret--;
+ }
+ if(FD_ISSET(i, &w)) {
+ bits |= EV_WRITE;
+ ret--;
+ }
+ bits &= base->fds[i]->ev_events;
+ if(bits) {
+ fptr_ok(fptr_whitelist_event(
+ base->fds[i]->ev_callback));
+ (*base->fds[i]->ev_callback)(base->fds[i]->ev_fd,
+ bits, base->fds[i]->ev_arg);
+ if(ret==0)
+ break;
+ }
+ }
+ return 0;
+}
+
+/** run select in a loop */
+int event_base_dispatch(struct event_base* base)
+{
+ struct timeval wait;
+ if(settime(base) < 0)
+ return -1;
+ while(!base->need_to_exit)
+ {
+ /* see if timeouts need handling */
+ handle_timeouts(base, base->time_tv, &wait);
+ if(base->need_to_exit)
+ return 0;
+ /* do select */
+ if(handle_select(base, &wait) < 0) {
+ if(base->need_to_exit)
+ return 0;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+/** exit that loop */
+int event_base_loopexit(struct event_base* base,
+ struct timeval* ATTR_UNUSED(tv))
+{
+ base->need_to_exit = 1;
+ return 0;
+}
+
+/* free event base, free events yourself */
+void event_base_free(struct event_base* base)
+{
+ if(!base)
+ return;
+ if(base->times)
+ free(base->times);
+ if(base->fds)
+ free(base->fds);
+ if(base->signals)
+ free(base->signals);
+ free(base);
+}
+
+/** set content of event */
+void event_set(struct event* ev, int fd, short bits,
+ void (*cb)(int, short, void *), void* arg)
+{
+ ev->node.key = ev;
+ ev->ev_fd = fd;
+ ev->ev_events = bits;
+ ev->ev_callback = cb;
+ fptr_ok(fptr_whitelist_event(ev->ev_callback));
+ ev->ev_arg = arg;
+ ev->added = 0;
+}
+
+/* add event to a base */
+int event_base_set(struct event_base* base, struct event* ev)
+{
+ ev->ev_base = base;
+ ev->added = 0;
+ return 0;
+}
+
+/* add event to make it active, you may not change it with event_set anymore */
+int event_add(struct event* ev, struct timeval* tv)
+{
+ if(ev->added)
+ event_del(ev);
+ if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
+ return -1;
+ if( (ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
+ ev->ev_base->fds[ev->ev_fd] = ev;
+ if(ev->ev_events&EV_READ) {
+ FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
+ }
+ if(ev->ev_events&EV_WRITE) {
+ FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
+ }
+ FD_SET(FD_SET_T ev->ev_fd, &ev->ev_base->content);
+ FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
+ if(ev->ev_fd > ev->ev_base->maxfd)
+ ev->ev_base->maxfd = ev->ev_fd;
+ }
+ if(tv && (ev->ev_events&EV_TIMEOUT)) {
+#ifndef S_SPLINT_S
+ struct timeval *now = ev->ev_base->time_tv;
+ ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
+ ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
+ while(ev->ev_timeout.tv_usec > 1000000) {
+ ev->ev_timeout.tv_usec -= 1000000;
+ ev->ev_timeout.tv_sec++;
+ }
+#endif
+ (void)rbtree_insert(ev->ev_base->times, &ev->node);
+ }
+ ev->added = 1;
+ return 0;
+}
+
+/* remove event, you may change it again */
+int event_del(struct event* ev)
+{
+ if(ev->ev_fd != -1 && ev->ev_fd >= ev->ev_base->capfd)
+ return -1;
+ if((ev->ev_events&EV_TIMEOUT))
+ (void)rbtree_delete(ev->ev_base->times, &ev->node);
+ if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
+ ev->ev_base->fds[ev->ev_fd] = NULL;
+ FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->reads);
+ FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->writes);
+ FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->ready);
+ FD_CLR(FD_SET_T ev->ev_fd, &ev->ev_base->content);
+ }
+ ev->added = 0;
+ return 0;
+}
+
+/** which base gets to handle signals */
+static struct event_base* signal_base = NULL;
+/** signal handler */
+static RETSIGTYPE sigh(int sig)
+{
+ struct event* ev;
+ if(!signal_base || sig < 0 || sig >= MAX_SIG)
+ return;
+ ev = signal_base->signals[sig];
+ if(!ev)
+ return;
+ fptr_ok(fptr_whitelist_event(ev->ev_callback));
+ (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
+}
+
+/** install signal handler */
+int signal_add(struct event* ev, struct timeval* ATTR_UNUSED(tv))
+{
+ if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
+ return -1;
+ signal_base = ev->ev_base;
+ ev->ev_base->signals[ev->ev_fd] = ev;
+ ev->added = 1;
+ if(signal(ev->ev_fd, sigh) == SIG_ERR) {
+ return -1;
+ }
+ return 0;
+}
+
+/** remove signal handler */
+int signal_del(struct event* ev)
+{
+ if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
+ return -1;
+ ev->ev_base->signals[ev->ev_fd] = NULL;
+ ev->added = 0;
+ return 0;
+}
+
+#else /* USE_MINI_EVENT */
+#ifndef USE_WINSOCK
+int mini_ev_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
+{
+ return 0;
+}
+#endif /* not USE_WINSOCK */
+#endif /* USE_MINI_EVENT */
diff --git a/external/unbound/util/mini_event.h b/external/unbound/util/mini_event.h
new file mode 100644
index 000000000..58bbc8073
--- /dev/null
+++ b/external/unbound/util/mini_event.h
@@ -0,0 +1,177 @@
+/*
+ * mini-event.h - micro implementation of libevent api, using select() only.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 implements part of the event(3) libevent api.
+ * The back end is only select. Max number of fds is limited.
+ * Max number of signals is limited, one handler per signal only.
+ * And one handler per fd.
+ *
+ * Although limited to select() and a max (1024) open fds, it
+ * is efficient:
+ * o dispatch call caches fd_sets to use.
+ * o handler calling takes time ~ to the number of fds.
+ * o timeouts are stored in a redblack tree, sorted, so take log(n).
+ * Timeouts are only accurate to the second (no subsecond accuracy).
+ * To avoid cpu hogging, fractional timeouts are rounded up to a whole second.
+ */
+
+#ifndef MINI_EVENT_H
+#define MINI_EVENT_H
+
+#if defined(USE_MINI_EVENT) && !defined(USE_WINSOCK)
+
+#ifndef HAVE_EVENT_BASE_FREE
+#define HAVE_EVENT_BASE_FREE
+#endif
+
+/** event timeout */
+#define EV_TIMEOUT 0x01
+/** event fd readable */
+#define EV_READ 0x02
+/** event fd writable */
+#define EV_WRITE 0x04
+/** event signal */
+#define EV_SIGNAL 0x08
+/** event must persist */
+#define EV_PERSIST 0x10
+
+/* needs our redblack tree */
+#include "rbtree.h"
+
+/** max number of file descriptors to support */
+#define MAX_FDS 1024
+/** max number of signals to support */
+#define MAX_SIG 32
+
+/** event base */
+struct event_base
+{
+ /** sorted by timeout (absolute), ptr */
+ rbtree_t* times;
+ /** array of 0 - maxfd of ptr to event for it */
+ struct event** fds;
+ /** max fd in use */
+ int maxfd;
+ /** capacity - size of the fds array */
+ int capfd;
+ /* fdset for read write, for fds ready, and added */
+ fd_set
+ /** fds for reading */
+ reads,
+ /** fds for writing */
+ writes,
+ /** fds determined ready for use */
+ ready,
+ /** ready plus newly added events. */
+ content;
+ /** array of 0 - maxsig of ptr to event for it */
+ struct event** signals;
+ /** if we need to exit */
+ int need_to_exit;
+ /** where to store time in seconds */
+ time_t* time_secs;
+ /** where to store time in microseconds */
+ struct timeval* time_tv;
+};
+
+/**
+ * Event structure. Has some of the event elements.
+ */
+struct event {
+ /** node in timeout rbtree */
+ rbnode_t node;
+ /** is event already added */
+ int added;
+
+ /** event base it belongs to */
+ struct event_base *ev_base;
+ /** fd to poll or -1 for timeouts. signal number for sigs. */
+ int ev_fd;
+ /** what events this event is interested in, see EV_.. above. */
+ short ev_events;
+ /** timeout value */
+ struct timeval ev_timeout;
+
+ /** callback to call: fd, eventbits, userarg */
+ void (*ev_callback)(int, short, void *arg);
+ /** callback user arg */
+ void *ev_arg;
+};
+
+/* function prototypes (some are as they appear in event.h) */
+/** create event base */
+void *event_init(time_t* time_secs, struct timeval* time_tv);
+/** get version */
+const char *event_get_version(void);
+/** get polling method, select */
+const char *event_get_method(void);
+/** run select in a loop */
+int event_base_dispatch(struct event_base *);
+/** exit that loop */
+int event_base_loopexit(struct event_base *, struct timeval *);
+/** free event base. Free events yourself */
+void event_base_free(struct event_base *);
+/** set content of event */
+void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
+/** add event to a base. You *must* call this for every event. */
+int event_base_set(struct event_base *, struct event *);
+/** add event to make it active. You may not change it with event_set anymore */
+int event_add(struct event *, struct timeval *);
+/** remove event. You may change it again */
+int event_del(struct event *);
+
+/** add a timer */
+#define evtimer_add(ev, tv) event_add(ev, tv)
+/** remove a timer */
+#define evtimer_del(ev) event_del(ev)
+
+/* uses different implementation. Cannot mix fd/timeouts and signals inside
+ * the same struct event. create several event structs for that. */
+/** install signal handler */
+int signal_add(struct event *, struct timeval *);
+/** set signal event contents */
+#define signal_set(ev, x, cb, arg) \
+ event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
+/** remove signal handler */
+int signal_del(struct event *);
+
+#endif /* USE_MINI_EVENT and not USE_WINSOCK */
+
+/** compare events in tree, based on timevalue, ptr for uniqueness */
+int mini_ev_cmp(const void* a, const void* b);
+
+#endif /* MINI_EVENT_H */
diff --git a/external/unbound/util/module.c b/external/unbound/util/module.c
new file mode 100644
index 000000000..09e276c30
--- /dev/null
+++ b/external/unbound/util/module.c
@@ -0,0 +1,71 @@
+/*
+ * util/module.c - module interface
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ * Implementation of module.h.
+ */
+
+#include "config.h"
+#include "util/module.h"
+
+const char*
+strextstate(enum module_ext_state s)
+{
+ switch(s) {
+ case module_state_initial: return "module_state_initial";
+ case module_wait_reply: return "module_wait_reply";
+ case module_wait_module: return "module_wait_module";
+ case module_restart_next: return "module_restart_next";
+ case module_wait_subquery: return "module_wait_subquery";
+ case module_error: return "module_error";
+ case module_finished: return "module_finished";
+ }
+ return "bad_extstate_value";
+}
+
+const char*
+strmodulevent(enum module_ev e)
+{
+ switch(e) {
+ case module_event_new: return "module_event_new";
+ case module_event_pass: return "module_event_pass";
+ case module_event_reply: return "module_event_reply";
+ case module_event_noreply: return "module_event_noreply";
+ case module_event_capsfail: return "module_event_capsfail";
+ case module_event_moddone: return "module_event_moddone";
+ case module_event_error: return "module_event_error";
+ }
+ return "bad_event_value";
+}
diff --git a/external/unbound/util/module.h b/external/unbound/util/module.h
new file mode 100644
index 000000000..f95ff6dc8
--- /dev/null
+++ b/external/unbound/util/module.h
@@ -0,0 +1,517 @@
+/*
+ * util/module.h - DNS handling module interface
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 interface for DNS handling modules.
+ *
+ * The module interface uses the DNS modules as state machines. The
+ * state machines are activated in sequence to operate on queries. Once
+ * they are done, the reply is passed back. In the usual setup the mesh
+ * is the caller of the state machines and once things are done sends replies
+ * and invokes result callbacks.
+ *
+ * The module provides a number of functions, listed in the module_func_block.
+ * The module is inited and destroyed and memory usage queries, for the
+ * module as a whole, for entire-module state (such as a cache). And per-query
+ * functions are called, operate to move the state machine and cleanup of
+ * the per-query state.
+ *
+ * Most per-query state should simply be allocated in the query region.
+ * This is destroyed at the end of the query.
+ *
+ * The module environment contains services and information and caches
+ * shared by the modules and the rest of the system. It also contains
+ * function pointers for module-specific tasks (like sending queries).
+ *
+ * *** Example module calls for a normal query
+ *
+ * In this example, the query does not need recursion, all the other data
+ * can be found in the cache. This makes the example shorter.
+ *
+ * At the start of the program the iterator module is initialised.
+ * The iterator module sets up its global state, such as donotquery lists
+ * and private address trees.
+ *
+ * A query comes in, and a mesh entry is created for it. The mesh
+ * starts the resolution process. The validator module is the first
+ * in the list of modules, and it is started on this new query. The
+ * operate() function is called. The validator decides it needs not do
+ * anything yet until there is a result and returns wait_module, that
+ * causes the next module in the list to be started.
+ *
+ * The next module is the iterator. It is started on the passed query and
+ * decides to perform a lookup. For this simple example, the delegation
+ * point information is available, and all the iterator wants to do is
+ * send a UDP query. The iterator uses env.send_query() to send the
+ * query. Then the iterator suspends (returns from the operate call).
+ *
+ * When the UDP reply comes back (and on errors and timeouts), the
+ * operate function is called for the query, on the iterator module,
+ * with the event that there is a reply. The iterator decides that this
+ * is enough, the work is done. It returns the value finished from the
+ * operate call, which causes the previous module to be started.
+ *
+ * The previous module, the validator module, is started with the event
+ * that the iterator module is done. The validator decides to validate
+ * the query. Once it is done (which could take recursive lookups, but
+ * in this example no recursive lookups are needed), it returns from the
+ * operate function with finished.
+ *
+ * There is no previous module from the validator module, and the mesh
+ * takes this to mean that the query is finally done. The mesh invokes
+ * callbacks and sends packets to queriers.
+ *
+ * If other modules had been waiting (recursively) on the answer to this
+ * query, then the mesh will tell them about it. It calls the inform_super
+ * routine on all the waiting modules, and once that is done it calls all of
+ * them with the operate() call. During inform_super the query that is done
+ * still exists and information can be copied from it (but the module should
+ * not really re-entry codepoints and services). During the operate call
+ * the modules can use stored state to continue operation with the results.
+ * (network buffers are used to contain the answer packet during the
+ * inform_super phase, but after that the network buffers will be cleared
+ * of their contents so that other tasks can be performed).
+ *
+ * *** Example module calls for recursion
+ *
+ * A module is called in operate, and it decides that it wants to perform
+ * recursion. That is, it wants the full state-machine-list to operate on
+ * a different query. It calls env.attach_sub() to create a new query state.
+ * The routine returns the newly created state, and potentially the module
+ * can edit the module-states for the newly created query (i.e. pass along
+ * some information, like delegation points). The module then suspends,
+ * returns from the operate routine.
+ *
+ * The mesh meanwhile will have the newly created query (or queries) on
+ * a waiting list, and will call operate() on this query (or queries).
+ * It starts again at the start of the module list for them. The query
+ * (or queries) continue to operate their state machines, until they are
+ * done. When they are done the mesh calls inform_super on the module that
+ * wanted the recursion. After that the mesh calls operate() on the module
+ * that wanted to do the recursion, and during this phase the module could,
+ * for example, decide to create more recursions.
+ *
+ * If the module decides it no longer wants the recursive information
+ * it can call detach_subs. Those queries will still run to completion,
+ * potentially filling the cache with information. Inform_super is not
+ * called any more.
+ *
+ * The iterator module will fetch items from the cache, so a recursion
+ * attempt may complete very quickly if the item is in cache. The calling
+ * module has to wait for completion or eventual timeout. A recursive query
+ * that times out returns a servfail rcode (servfail is also returned for
+ * other errors during the lookup).
+ *
+ * Results are passed in the qstate, the rcode member is used to pass
+ * errors without requiring memory allocation, so that the code can continue
+ * in out-of-memory conditions. If the rcode member is 0 (NOERROR) then
+ * the dns_msg entry contains a filled out message. This message may
+ * also contain an rcode that is nonzero, but in this case additional
+ * information (query, additional) can be passed along.
+ *
+ * The rcode and dns_msg are used to pass the result from the the rightmost
+ * module towards the leftmost modules and then towards the user.
+ *
+ * If you want to avoid recursion-cycles where queries need other queries
+ * that need the first one, use detect_cycle() to see if that will happen.
+ *
+ */
+
+#ifndef UTIL_MODULE_H
+#define UTIL_MODULE_H
+#include "util/storage/lruhash.h"
+#include "util/data/msgreply.h"
+#include "util/data/msgparse.h"
+struct sldns_buffer;
+struct alloc_cache;
+struct rrset_cache;
+struct key_cache;
+struct config_file;
+struct slabhash;
+struct query_info;
+struct edns_data;
+struct regional;
+struct worker;
+struct module_qstate;
+struct ub_randstate;
+struct mesh_area;
+struct mesh_state;
+struct val_anchors;
+struct val_neg_cache;
+struct iter_forwards;
+struct iter_hints;
+
+/** Maximum number of modules in operation */
+#define MAX_MODULE 5
+
+/**
+ * Module environment.
+ * Services and data provided to the module.
+ */
+struct module_env {
+ /* --- data --- */
+ /** config file with config options */
+ struct config_file* cfg;
+ /** shared message cache */
+ struct slabhash* msg_cache;
+ /** shared rrset cache */
+ struct rrset_cache* rrset_cache;
+ /** shared infrastructure cache (edns, lameness) */
+ struct infra_cache* infra_cache;
+ /** shared key cache */
+ struct key_cache* key_cache;
+
+ /* --- services --- */
+ /**
+ * Send serviced DNS query to server. UDP/TCP and EDNS is handled.
+ * operate() should return with wait_reply. Later on a callback
+ * will cause operate() to be called with event timeout or reply.
+ * The time until a timeout is calculated from roundtrip timing,
+ * several UDP retries are attempted.
+ * @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 bits set.
+ * If EDNS_DO bit is set, DO bit is set in EDNS records.
+ * If BIT_CD is set, CD bit is set in queries with EDNS records.
+ * @param want_dnssec: if set, the validator wants DNSSEC. Without
+ * EDNS, the answer is likely to be useless for this domain.
+ * @param nocaps: do not use caps_for_id, use the qname as given.
+ * (ignored if caps_for_id is disabled).
+ * @param addr: where to.
+ * @param addrlen: length of addr.
+ * @param zone: delegation point name.
+ * @param zonelen: length of zone name.
+ * @param q: wich query state to reactivate upon return.
+ * @return: false on failure (memory or socket related). no query was
+ * sent. Or returns an outbound entry with qsent and qstate set.
+ * This outbound_entry will be used on later module invocations
+ * that involve this query (timeout, error or reply).
+ */
+ struct outbound_entry* (*send_query)(uint8_t* qname, size_t qnamelen,
+ uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
+ int want_dnssec, int nocaps, struct sockaddr_storage* addr,
+ socklen_t addrlen, uint8_t* zone, size_t zonelen,
+ struct module_qstate* q);
+
+ /**
+ * Detach-subqueries.
+ * Remove all sub-query references from this query state.
+ * Keeps super-references of those sub-queries correct.
+ * Updates stat items in mesh_area structure.
+ * @param qstate: used to find mesh state.
+ */
+ void (*detach_subs)(struct module_qstate* qstate);
+
+ /**
+ * Attach subquery.
+ * Creates it if it does not exist already.
+ * Keeps sub and super references correct.
+ * Updates stat items in mesh_area structure.
+ * Pass if it is priming query or not.
+ * return:
+ * o if error (malloc) happened.
+ * o need to initialise the new state (module init; it is a new state).
+ * so that the next run of the query with this module is successful.
+ * o no init needed, attachment successful.
+ *
+ * @param qstate: the state to find mesh state, and that wants to
+ * receive the results from the new subquery.
+ * @param qinfo: what to query for (copied).
+ * @param qflags: what flags to use (RD, CD flag or not).
+ * @param prime: if it is a (stub) priming query.
+ * @param newq: If the new subquery needs initialisation, it is
+ * returned, otherwise NULL is returned.
+ * @return: false on error, true if success (and init may be needed).
+ */
+ int (*attach_sub)(struct module_qstate* qstate,
+ struct query_info* qinfo, uint16_t qflags, int prime,
+ struct module_qstate** newq);
+
+ /**
+ * Kill newly attached sub. If attach_sub returns newq for
+ * initialisation, but that fails, then this routine will cleanup and
+ * delete the fresly created sub.
+ * @param newq: the new subquery that is no longer needed.
+ * It is removed.
+ */
+ void (*kill_sub)(struct module_qstate* newq);
+
+ /**
+ * Detect if adding a dependency for qstate on name,type,class will
+ * create a dependency cycle.
+ * @param qstate: given mesh querystate.
+ * @param qinfo: query info for dependency.
+ * @param flags: query flags of dependency, RD/CD flags.
+ * @param prime: if dependency is a priming query or not.
+ * @return true if the name,type,class exists and the given
+ * qstate mesh exists as a dependency of that name. Thus
+ * if qstate becomes dependent on name,type,class then a
+ * cycle is created.
+ */
+ int (*detect_cycle)(struct module_qstate* qstate,
+ struct query_info* qinfo, uint16_t flags, int prime);
+
+ /** region for temporary usage. May be cleared after operate() call. */
+ struct regional* scratch;
+ /** buffer for temporary usage. May be cleared after operate() call. */
+ struct sldns_buffer* scratch_buffer;
+ /** internal data for daemon - worker thread. */
+ struct worker* worker;
+ /** mesh area with query state dependencies */
+ struct mesh_area* mesh;
+ /** allocation service */
+ struct alloc_cache* alloc;
+ /** random table to generate random numbers */
+ struct ub_randstate* rnd;
+ /** time in seconds, converted to integer */
+ time_t* now;
+ /** time in microseconds. Relatively recent. */
+ struct timeval* now_tv;
+ /** is validation required for messages, controls client-facing
+ * validation status (AD bits) and servfails */
+ int need_to_validate;
+ /** trusted key storage; these are the configured keys, if not NULL,
+ * otherwise configured by validator. These are the trust anchors,
+ * and are not primed and ready for validation, but on the bright
+ * side, they are read only memory, thus no locks and fast. */
+ struct val_anchors* anchors;
+ /** negative cache, configured by the validator. if not NULL,
+ * contains NSEC record lookup trees. */
+ struct val_neg_cache* neg_cache;
+ /** the 5011-probe timer (if any) */
+ struct comm_timer* probe_timer;
+ /** Mapping of forwarding zones to targets.
+ * iterator forwarder information. per-thread, created by worker */
+ struct iter_forwards* fwds;
+ /**
+ * iterator forwarder information. per-thread, created by worker.
+ * The hints -- these aren't stored in the cache because they don't
+ * expire. The hints are always used to "prime" the cache. Note
+ * that both root hints and stub zone "hints" are stored in this
+ * data structure.
+ */
+ struct iter_hints* hints;
+ /** module specific data. indexed by module id. */
+ void* modinfo[MAX_MODULE];
+};
+
+/**
+ * External visible states of the module state machine
+ * Modules may also have an internal state.
+ * Modules are supposed to run to completion or until blocked.
+ */
+enum module_ext_state {
+ /** initial state - new query */
+ module_state_initial = 0,
+ /** waiting for reply to outgoing network query */
+ module_wait_reply,
+ /** module is waiting for another module */
+ module_wait_module,
+ /** module is waiting for another module; that other is restarted */
+ module_restart_next,
+ /** module is waiting for sub-query */
+ module_wait_subquery,
+ /** module could not finish the query */
+ module_error,
+ /** module is finished with query */
+ module_finished
+};
+
+/**
+ * Events that happen to modules, that start or wakeup modules.
+ */
+enum module_ev {
+ /** new query */
+ module_event_new = 0,
+ /** query passed by other module */
+ module_event_pass,
+ /** reply inbound from server */
+ module_event_reply,
+ /** no reply, timeout or other error */
+ module_event_noreply,
+ /** reply is there, but capitalisation check failed */
+ module_event_capsfail,
+ /** next module is done, and its reply is awaiting you */
+ module_event_moddone,
+ /** error */
+ module_event_error
+};
+
+/**
+ * Linked list of sockaddrs
+ * May be allocated such that only 'len' bytes of addr exist for the structure.
+ */
+struct sock_list {
+ /** next in list */
+ struct sock_list* next;
+ /** length of addr */
+ socklen_t len;
+ /** sockaddr */
+ struct sockaddr_storage addr;
+};
+
+/**
+ * Module state, per query.
+ */
+struct module_qstate {
+ /** which query is being answered: name, type, class */
+ struct query_info qinfo;
+ /** flags uint16 from query */
+ uint16_t query_flags;
+ /** if this is a (stub or root) priming query (with hints) */
+ int is_priming;
+
+ /** comm_reply contains server replies */
+ struct comm_reply* reply;
+ /** the reply message, with message for client and calling module */
+ struct dns_msg* return_msg;
+ /** the rcode, in case of error, instead of a reply message */
+ int return_rcode;
+ /** origin of the reply (can be NULL from cache, list for cnames) */
+ struct sock_list* reply_origin;
+ /** IP blacklist for queries */
+ struct sock_list* blacklist;
+ /** region for this query. Cleared when query process finishes. */
+ struct regional* region;
+ /** failure reason information if val-log-level is high */
+ struct config_strlist* errinf;
+
+ /** which module is executing */
+ int curmod;
+ /** module states */
+ enum module_ext_state ext_state[MAX_MODULE];
+ /** module specific data for query. indexed by module id. */
+ void* minfo[MAX_MODULE];
+ /** environment for this query */
+ struct module_env* env;
+ /** mesh related information for this query */
+ struct mesh_state* mesh_info;
+ /** how many seconds before expiry is this prefetched (0 if not) */
+ time_t prefetch_leeway;
+};
+
+/**
+ * Module functionality block
+ */
+struct module_func_block {
+ /** text string name of module */
+ const char* name;
+
+ /**
+ * init the module. Called once for the global state.
+ * This is the place to apply settings from the config file.
+ * @param env: module environment.
+ * @param id: module id number.
+ * return: 0 on error
+ */
+ int (*init)(struct module_env* env, int id);
+
+ /**
+ * de-init, delete, the module. Called once for the global state.
+ * @param env: module environment.
+ * @param id: module id number.
+ */
+ void (*deinit)(struct module_env* env, int id);
+
+ /**
+ * accept a new query, or work further on existing query.
+ * Changes the qstate->ext_state to be correct on exit.
+ * @param ev: event that causes the module state machine to
+ * (re-)activate.
+ * @param qstate: the query state.
+ * Note that this method is not allowed to change the
+ * query state 'identity', that is query info, qflags,
+ * and priming status.
+ * Attach a subquery to get results to a different query.
+ * @param id: module id number that operate() is called on.
+ * @param outbound: if not NULL this event is due to the reply/timeout
+ * or error on this outbound query.
+ * @return: if at exit the ext_state is:
+ * o wait_module: next module is started. (with pass event).
+ * o error or finished: previous module is resumed.
+ * o otherwise it waits until that event happens (assumes
+ * the service routine to make subrequest or send message
+ * have been called.
+ */
+ void (*operate)(struct module_qstate* qstate, enum module_ev event,
+ int id, struct outbound_entry* outbound);
+
+ /**
+ * inform super querystate about the results from this subquerystate.
+ * Is called when the querystate is finished. The method invoked is
+ * the one from the current module active in the super querystate.
+ * @param qstate: the query state that is finished.
+ * Examine return_rcode and return_reply in the qstate.
+ * @param id: module id for this module.
+ * This coincides with the current module for the super qstate.
+ * @param super: the super querystate that needs to be informed.
+ */
+ void (*inform_super)(struct module_qstate* qstate, int id,
+ struct module_qstate* super);
+
+ /**
+ * clear module specific data
+ */
+ void (*clear)(struct module_qstate* qstate, int id);
+
+ /**
+ * How much memory is the module specific data using.
+ * @param env: module environment.
+ * @param id: the module id.
+ * @return the number of bytes that are alloced.
+ */
+ size_t (*get_mem)(struct module_env* env, int id);
+};
+
+/**
+ * Debug utility: module external qstate to string
+ * @param s: the state value.
+ * @return descriptive string.
+ */
+const char* strextstate(enum module_ext_state s);
+
+/**
+ * Debug utility: module event to string
+ * @param e: the module event value.
+ * @return descriptive string.
+ */
+const char* strmodulevent(enum module_ev e);
+
+#endif /* UTIL_MODULE_H */
diff --git a/external/unbound/util/net_help.c b/external/unbound/util/net_help.c
new file mode 100644
index 000000000..30d543e00
--- /dev/null
+++ b/external/unbound/util/net_help.c
@@ -0,0 +1,804 @@
+/*
+ * util/net_help.c - implementation of the network helper code
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ * Implementation of net_help.h.
+ */
+
+#include "config.h"
+#include "util/net_help.h"
+#include "util/log.h"
+#include "util/data/dname.h"
+#include "util/module.h"
+#include "util/regional.h"
+#include "ldns/parseutil.h"
+#include "ldns/wire2str.h"
+#include <fcntl.h>
+#ifdef HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#endif
+#ifdef HAVE_OPENSSL_ERR_H
+#include <openssl/err.h>
+#endif
+
+/** max length of an IP address (the address portion) that we allow */
+#define MAX_ADDR_STRLEN 128 /* characters */
+/** default value for EDNS ADVERTISED size */
+uint16_t EDNS_ADVERTISED_SIZE = 4096;
+
+/** minimal responses when positive answer: default is no */
+int MINIMAL_RESPONSES = 0;
+
+/** rrset order roundrobin: default is no */
+int RRSET_ROUNDROBIN = 0;
+
+/* returns true is string addr is an ip6 specced address */
+int
+str_is_ip6(const char* str)
+{
+ if(strchr(str, ':'))
+ return 1;
+ else return 0;
+}
+
+int
+fd_set_nonblock(int s)
+{
+#ifdef HAVE_FCNTL
+ int flag;
+ if((flag = fcntl(s, F_GETFL)) == -1) {
+ log_err("can't fcntl F_GETFL: %s", strerror(errno));
+ flag = 0;
+ }
+ flag |= O_NONBLOCK;
+ if(fcntl(s, F_SETFL, flag) == -1) {
+ log_err("can't fcntl F_SETFL: %s", strerror(errno));
+ return 0;
+ }
+#elif defined(HAVE_IOCTLSOCKET)
+ unsigned long on = 1;
+ if(ioctlsocket(s, FIONBIO, &on) != 0) {
+ log_err("can't ioctlsocket FIONBIO on: %s",
+ wsa_strerror(WSAGetLastError()));
+ }
+#endif
+ return 1;
+}
+
+int
+fd_set_block(int s)
+{
+#ifdef HAVE_FCNTL
+ int flag;
+ if((flag = fcntl(s, F_GETFL)) == -1) {
+ log_err("cannot fcntl F_GETFL: %s", strerror(errno));
+ flag = 0;
+ }
+ flag &= ~O_NONBLOCK;
+ if(fcntl(s, F_SETFL, flag) == -1) {
+ log_err("cannot fcntl F_SETFL: %s", strerror(errno));
+ return 0;
+ }
+#elif defined(HAVE_IOCTLSOCKET)
+ unsigned long off = 0;
+ if(ioctlsocket(s, FIONBIO, &off) != 0) {
+ log_err("can't ioctlsocket FIONBIO off: %s",
+ wsa_strerror(WSAGetLastError()));
+ }
+#endif
+ return 1;
+}
+
+int
+is_pow2(size_t num)
+{
+ if(num == 0) return 1;
+ return (num & (num-1)) == 0;
+}
+
+void*
+memdup(void* data, size_t len)
+{
+ void* d;
+ if(!data) return NULL;
+ if(len == 0) return NULL;
+ d = malloc(len);
+ if(!d) return NULL;
+ memcpy(d, data, len);
+ return d;
+}
+
+void
+log_addr(enum verbosity_value v, const char* str,
+ struct sockaddr_storage* addr, socklen_t addrlen)
+{
+ uint16_t port;
+ const char* family = "unknown";
+ char dest[100];
+ int af = (int)((struct sockaddr_in*)addr)->sin_family;
+ void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
+ if(verbosity < v)
+ return;
+ switch(af) {
+ case AF_INET: family="ip4"; break;
+ case AF_INET6: family="ip6";
+ sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
+ break;
+ case AF_UNIX: family="unix"; break;
+ default: break;
+ }
+ if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
+ (void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
+ }
+ dest[sizeof(dest)-1] = 0;
+ port = ntohs(((struct sockaddr_in*)addr)->sin_port);
+ if(verbosity >= 4)
+ verbose(v, "%s %s %s port %d (len %d)", str, family, dest,
+ (int)port, (int)addrlen);
+ else verbose(v, "%s %s port %d", str, dest, (int)port);
+}
+
+int
+extstrtoaddr(const char* str, struct sockaddr_storage* addr,
+ socklen_t* addrlen)
+{
+ char* s;
+ int port = UNBOUND_DNS_PORT;
+ if((s=strchr(str, '@'))) {
+ char buf[MAX_ADDR_STRLEN];
+ if(s-str >= MAX_ADDR_STRLEN) {
+ return 0;
+ }
+ (void)strlcpy(buf, str, sizeof(buf));
+ buf[s-str] = 0;
+ port = atoi(s+1);
+ if(port == 0 && strcmp(s+1,"0")!=0) {
+ return 0;
+ }
+ return ipstrtoaddr(buf, port, addr, addrlen);
+ }
+ return ipstrtoaddr(str, port, addr, addrlen);
+}
+
+
+int
+ipstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
+ socklen_t* addrlen)
+{
+ uint16_t p;
+ if(!ip) return 0;
+ p = (uint16_t) port;
+ if(str_is_ip6(ip)) {
+ char buf[MAX_ADDR_STRLEN];
+ char* s;
+ struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
+ *addrlen = (socklen_t)sizeof(struct sockaddr_in6);
+ memset(sa, 0, *addrlen);
+ sa->sin6_family = AF_INET6;
+ sa->sin6_port = (in_port_t)htons(p);
+ if((s=strchr(ip, '%'))) { /* ip6%interface, rfc 4007 */
+ if(s-ip >= MAX_ADDR_STRLEN)
+ return 0;
+ (void)strlcpy(buf, ip, sizeof(buf));
+ buf[s-ip]=0;
+ sa->sin6_scope_id = (uint32_t)atoi(s+1);
+ ip = buf;
+ }
+ if(inet_pton((int)sa->sin6_family, ip, &sa->sin6_addr) <= 0) {
+ return 0;
+ }
+ } else { /* ip4 */
+ struct sockaddr_in* sa = (struct sockaddr_in*)addr;
+ *addrlen = (socklen_t)sizeof(struct sockaddr_in);
+ memset(sa, 0, *addrlen);
+ sa->sin_family = AF_INET;
+ sa->sin_port = (in_port_t)htons(p);
+ if(inet_pton((int)sa->sin_family, ip, &sa->sin_addr) <= 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr,
+ socklen_t* addrlen, int* net)
+{
+ char* s = NULL;
+ *net = (str_is_ip6(str)?128:32);
+ if((s=strchr(str, '/'))) {
+ if(atoi(s+1) > *net) {
+ log_err("netblock too large: %s", str);
+ return 0;
+ }
+ *net = atoi(s+1);
+ if(*net == 0 && strcmp(s+1, "0") != 0) {
+ log_err("cannot parse netblock: '%s'", str);
+ return 0;
+ }
+ if(!(s = strdup(str))) {
+ log_err("out of memory");
+ return 0;
+ }
+ *strchr(s, '/') = '\0';
+ }
+ if(!ipstrtoaddr(s?s:str, port, addr, addrlen)) {
+ free(s);
+ log_err("cannot parse ip address: '%s'", str);
+ return 0;
+ }
+ if(s) {
+ free(s);
+ addr_mask(addr, *addrlen, *net);
+ }
+ return 1;
+}
+
+void
+log_nametypeclass(enum verbosity_value v, const char* str, uint8_t* name,
+ uint16_t type, uint16_t dclass)
+{
+ char buf[LDNS_MAX_DOMAINLEN+1];
+ char t[12], c[12];
+ const char *ts, *cs;
+ if(verbosity < v)
+ return;
+ dname_str(name, buf);
+ if(type == LDNS_RR_TYPE_TSIG) ts = "TSIG";
+ else if(type == LDNS_RR_TYPE_IXFR) ts = "IXFR";
+ else if(type == LDNS_RR_TYPE_AXFR) ts = "AXFR";
+ else if(type == LDNS_RR_TYPE_MAILB) ts = "MAILB";
+ else if(type == LDNS_RR_TYPE_MAILA) ts = "MAILA";
+ else if(type == LDNS_RR_TYPE_ANY) ts = "ANY";
+ else if(sldns_rr_descript(type) && sldns_rr_descript(type)->_name)
+ ts = sldns_rr_descript(type)->_name;
+ else {
+ snprintf(t, sizeof(t), "TYPE%d", (int)type);
+ ts = t;
+ }
+ if(sldns_lookup_by_id(sldns_rr_classes, (int)dclass) &&
+ sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name)
+ cs = sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name;
+ else {
+ snprintf(c, sizeof(c), "CLASS%d", (int)dclass);
+ cs = c;
+ }
+ log_info("%s %s %s %s", str, buf, ts, cs);
+}
+
+void log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone,
+ struct sockaddr_storage* addr, socklen_t addrlen)
+{
+ uint16_t port;
+ const char* family = "unknown_family ";
+ char namebuf[LDNS_MAX_DOMAINLEN+1];
+ char dest[100];
+ int af = (int)((struct sockaddr_in*)addr)->sin_family;
+ void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
+ if(verbosity < v)
+ return;
+ switch(af) {
+ case AF_INET: family=""; break;
+ case AF_INET6: family="";
+ sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
+ break;
+ case AF_UNIX: family="unix_family "; break;
+ default: break;
+ }
+ if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
+ (void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
+ }
+ dest[sizeof(dest)-1] = 0;
+ port = ntohs(((struct sockaddr_in*)addr)->sin_port);
+ dname_str(zone, namebuf);
+ if(af != AF_INET && af != AF_INET6)
+ verbose(v, "%s <%s> %s%s#%d (addrlen %d)",
+ str, namebuf, family, dest, (int)port, (int)addrlen);
+ else verbose(v, "%s <%s> %s%s#%d",
+ str, namebuf, family, dest, (int)port);
+}
+
+void log_err_addr(const char* str, const char* err,
+ struct sockaddr_storage* addr, socklen_t addrlen)
+{
+ uint16_t port;
+ char dest[100];
+ int af = (int)((struct sockaddr_in*)addr)->sin_family;
+ void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
+ if(af == AF_INET6)
+ sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
+ if(inet_ntop(af, sinaddr, dest, (socklen_t)sizeof(dest)) == 0) {
+ (void)strlcpy(dest, "(inet_ntop error)", sizeof(dest));
+ }
+ dest[sizeof(dest)-1] = 0;
+ port = ntohs(((struct sockaddr_in*)addr)->sin_port);
+ if(verbosity >= 4)
+ log_err("%s: %s for %s port %d (len %d)", str, err, dest,
+ (int)port, (int)addrlen);
+ else log_err("%s: %s for %s", str, err, dest);
+}
+
+int
+sockaddr_cmp(struct sockaddr_storage* addr1, socklen_t len1,
+ struct sockaddr_storage* addr2, socklen_t len2)
+{
+ struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
+ struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
+ struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
+ struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
+ if(len1 < len2)
+ return -1;
+ if(len1 > len2)
+ return 1;
+ log_assert(len1 == len2);
+ if( p1_in->sin_family < p2_in->sin_family)
+ return -1;
+ if( p1_in->sin_family > p2_in->sin_family)
+ return 1;
+ log_assert( p1_in->sin_family == p2_in->sin_family );
+ /* compare ip4 */
+ if( p1_in->sin_family == AF_INET ) {
+ /* just order it, ntohs not required */
+ if(p1_in->sin_port < p2_in->sin_port)
+ return -1;
+ if(p1_in->sin_port > p2_in->sin_port)
+ return 1;
+ log_assert(p1_in->sin_port == p2_in->sin_port);
+ return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
+ } else if (p1_in6->sin6_family == AF_INET6) {
+ /* just order it, ntohs not required */
+ if(p1_in6->sin6_port < p2_in6->sin6_port)
+ return -1;
+ if(p1_in6->sin6_port > p2_in6->sin6_port)
+ return 1;
+ log_assert(p1_in6->sin6_port == p2_in6->sin6_port);
+ return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
+ INET6_SIZE);
+ } else {
+ /* eek unknown type, perform this comparison for sanity. */
+ return memcmp(addr1, addr2, len1);
+ }
+}
+
+int
+sockaddr_cmp_addr(struct sockaddr_storage* addr1, socklen_t len1,
+ struct sockaddr_storage* addr2, socklen_t len2)
+{
+ struct sockaddr_in* p1_in = (struct sockaddr_in*)addr1;
+ struct sockaddr_in* p2_in = (struct sockaddr_in*)addr2;
+ struct sockaddr_in6* p1_in6 = (struct sockaddr_in6*)addr1;
+ struct sockaddr_in6* p2_in6 = (struct sockaddr_in6*)addr2;
+ if(len1 < len2)
+ return -1;
+ if(len1 > len2)
+ return 1;
+ log_assert(len1 == len2);
+ if( p1_in->sin_family < p2_in->sin_family)
+ return -1;
+ if( p1_in->sin_family > p2_in->sin_family)
+ return 1;
+ log_assert( p1_in->sin_family == p2_in->sin_family );
+ /* compare ip4 */
+ if( p1_in->sin_family == AF_INET ) {
+ return memcmp(&p1_in->sin_addr, &p2_in->sin_addr, INET_SIZE);
+ } else if (p1_in6->sin6_family == AF_INET6) {
+ return memcmp(&p1_in6->sin6_addr, &p2_in6->sin6_addr,
+ INET6_SIZE);
+ } else {
+ /* eek unknown type, perform this comparison for sanity. */
+ return memcmp(addr1, addr2, len1);
+ }
+}
+
+int
+addr_is_ip6(struct sockaddr_storage* addr, socklen_t len)
+{
+ if(len == (socklen_t)sizeof(struct sockaddr_in6) &&
+ ((struct sockaddr_in6*)addr)->sin6_family == AF_INET6)
+ return 1;
+ else return 0;
+}
+
+void
+addr_mask(struct sockaddr_storage* addr, socklen_t len, int net)
+{
+ uint8_t mask[8] = {0x0, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe};
+ int i, max;
+ uint8_t* s;
+ if(addr_is_ip6(addr, len)) {
+ s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
+ max = 128;
+ } else {
+ s = (uint8_t*)&((struct sockaddr_in*)addr)->sin_addr;
+ max = 32;
+ }
+ if(net >= max)
+ return;
+ for(i=net/8+1; i<max/8; i++) {
+ s[i] = 0;
+ }
+ s[net/8] &= mask[net&0x7];
+}
+
+int
+addr_in_common(struct sockaddr_storage* addr1, int net1,
+ struct sockaddr_storage* addr2, int net2, socklen_t addrlen)
+{
+ int min = (net1<net2)?net1:net2;
+ int i, to;
+ int match = 0;
+ uint8_t* s1, *s2;
+ if(addr_is_ip6(addr1, addrlen)) {
+ s1 = (uint8_t*)&((struct sockaddr_in6*)addr1)->sin6_addr;
+ s2 = (uint8_t*)&((struct sockaddr_in6*)addr2)->sin6_addr;
+ to = 16;
+ } else {
+ s1 = (uint8_t*)&((struct sockaddr_in*)addr1)->sin_addr;
+ s2 = (uint8_t*)&((struct sockaddr_in*)addr2)->sin_addr;
+ to = 4;
+ }
+ /* match = bits_in_common(s1, s2, to); */
+ for(i=0; i<to; i++) {
+ if(s1[i] == s2[i]) {
+ match += 8;
+ } else {
+ uint8_t z = s1[i]^s2[i];
+ log_assert(z);
+ while(!(z&0x80)) {
+ match++;
+ z<<=1;
+ }
+ break;
+ }
+ }
+ if(match > min) match = min;
+ return match;
+}
+
+void
+addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen,
+ char* buf, size_t len)
+{
+ int af = (int)((struct sockaddr_in*)addr)->sin_family;
+ void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
+ if(addr_is_ip6(addr, addrlen))
+ sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
+ if(inet_ntop(af, sinaddr, buf, (socklen_t)len) == 0) {
+ snprintf(buf, len, "(inet_ntop_error)");
+ }
+}
+
+int
+addr_is_ip4mapped(struct sockaddr_storage* addr, socklen_t addrlen)
+{
+ /* prefix for ipv4 into ipv6 mapping is ::ffff:x.x.x.x */
+ const uint8_t map_prefix[16] =
+ {0,0,0,0, 0,0,0,0, 0,0,0xff,0xff, 0,0,0,0};
+ uint8_t* s;
+ if(!addr_is_ip6(addr, addrlen))
+ return 0;
+ /* s is 16 octet ipv6 address string */
+ s = (uint8_t*)&((struct sockaddr_in6*)addr)->sin6_addr;
+ return (memcmp(s, map_prefix, 12) == 0);
+}
+
+int addr_is_broadcast(struct sockaddr_storage* addr, socklen_t addrlen)
+{
+ int af = (int)((struct sockaddr_in*)addr)->sin_family;
+ void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
+ return af == AF_INET && addrlen>=(socklen_t)sizeof(struct sockaddr_in)
+ && memcmp(sinaddr, "\377\377\377\377", 4) == 0;
+}
+
+int addr_is_any(struct sockaddr_storage* addr, socklen_t addrlen)
+{
+ int af = (int)((struct sockaddr_in*)addr)->sin_family;
+ void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
+ void* sin6addr = &((struct sockaddr_in6*)addr)->sin6_addr;
+ if(af == AF_INET && addrlen>=(socklen_t)sizeof(struct sockaddr_in)
+ && memcmp(sinaddr, "\000\000\000\000", 4) == 0)
+ return 1;
+ else if(af==AF_INET6 && addrlen>=(socklen_t)sizeof(struct sockaddr_in6)
+ && memcmp(sin6addr, "\000\000\000\000\000\000\000\000"
+ "\000\000\000\000\000\000\000\000", 16) == 0)
+ return 1;
+ return 0;
+}
+
+void sock_list_insert(struct sock_list** list, struct sockaddr_storage* addr,
+ socklen_t len, struct regional* region)
+{
+ struct sock_list* add = (struct sock_list*)regional_alloc(region,
+ sizeof(*add) - sizeof(add->addr) + (size_t)len);
+ if(!add) {
+ log_err("out of memory in socketlist insert");
+ return;
+ }
+ log_assert(list);
+ add->next = *list;
+ add->len = len;
+ *list = add;
+ if(len) memmove(&add->addr, addr, len);
+}
+
+void sock_list_prepend(struct sock_list** list, struct sock_list* add)
+{
+ struct sock_list* last = add;
+ if(!last)
+ return;
+ while(last->next)
+ last = last->next;
+ last->next = *list;
+ *list = add;
+}
+
+int sock_list_find(struct sock_list* list, struct sockaddr_storage* addr,
+ socklen_t len)
+{
+ while(list) {
+ if(len == list->len) {
+ if(len == 0 || sockaddr_cmp_addr(addr, len,
+ &list->addr, list->len) == 0)
+ return 1;
+ }
+ list = list->next;
+ }
+ return 0;
+}
+
+void sock_list_merge(struct sock_list** list, struct regional* region,
+ struct sock_list* add)
+{
+ struct sock_list* p;
+ for(p=add; p; p=p->next) {
+ if(!sock_list_find(*list, &p->addr, p->len))
+ sock_list_insert(list, &p->addr, p->len, region);
+ }
+}
+
+void
+log_crypto_err(const char* str)
+{
+#ifdef HAVE_SSL
+ /* error:[error code]:[library name]:[function name]:[reason string] */
+ char buf[128];
+ unsigned long e;
+ ERR_error_string_n(ERR_get_error(), buf, sizeof(buf));
+ log_err("%s crypto %s", str, buf);
+ while( (e=ERR_get_error()) ) {
+ ERR_error_string_n(e, buf, sizeof(buf));
+ log_err("and additionally crypto %s", buf);
+ }
+#else
+ (void)str;
+#endif /* HAVE_SSL */
+}
+
+void* listen_sslctx_create(char* key, char* pem, char* verifypem)
+{
+#ifdef HAVE_SSL
+ SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method());
+ if(!ctx) {
+ log_crypto_err("could not SSL_CTX_new");
+ return NULL;
+ }
+ /* no SSLv2 because has defects */
+ if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)){
+ log_crypto_err("could not set SSL_OP_NO_SSLv2");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) {
+ log_err("error for cert file: %s", pem);
+ log_crypto_err("error in SSL_CTX use_certificate_file");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
+ log_err("error for private key file: %s", key);
+ log_crypto_err("Error in SSL_CTX use_PrivateKey_file");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!SSL_CTX_check_private_key(ctx)) {
+ log_err("error for key file: %s", key);
+ log_crypto_err("Error in SSL_CTX check_private_key");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+
+ if(verifypem && verifypem[0]) {
+ if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL)) {
+ log_crypto_err("Error in SSL_CTX verify locations");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(
+ verifypem));
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+ }
+ return ctx;
+#else
+ (void)key; (void)pem; (void)verifypem;
+ return NULL;
+#endif
+}
+
+void* connect_sslctx_create(char* key, char* pem, char* verifypem)
+{
+#ifdef HAVE_SSL
+ SSL_CTX* ctx = SSL_CTX_new(SSLv23_client_method());
+ if(!ctx) {
+ log_crypto_err("could not allocate SSL_CTX pointer");
+ return NULL;
+ }
+ if(!(SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2) & SSL_OP_NO_SSLv2)) {
+ log_crypto_err("could not set SSL_OP_NO_SSLv2");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(key && key[0]) {
+ if(!SSL_CTX_use_certificate_file(ctx, pem, SSL_FILETYPE_PEM)) {
+ log_err("error in client certificate %s", pem);
+ log_crypto_err("error in certificate file");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
+ log_err("error in client private key %s", key);
+ log_crypto_err("error in key file");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ if(!SSL_CTX_check_private_key(ctx)) {
+ log_err("error in client key %s", key);
+ log_crypto_err("error in SSL_CTX_check_private_key");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ }
+ if(verifypem && verifypem[0]) {
+ if(!SSL_CTX_load_verify_locations(ctx, verifypem, NULL) != 1) {
+ log_crypto_err("error in SSL_CTX verify");
+ SSL_CTX_free(ctx);
+ return NULL;
+ }
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
+ }
+ return ctx;
+#else
+ (void)key; (void)pem; (void)verifypem;
+ return NULL;
+#endif
+}
+
+void* incoming_ssl_fd(void* sslctx, int fd)
+{
+#ifdef HAVE_SSL
+ SSL* ssl = SSL_new((SSL_CTX*)sslctx);
+ if(!ssl) {
+ log_crypto_err("could not SSL_new");
+ return NULL;
+ }
+ SSL_set_accept_state(ssl);
+ (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+ if(!SSL_set_fd(ssl, fd)) {
+ log_crypto_err("could not SSL_set_fd");
+ SSL_free(ssl);
+ return NULL;
+ }
+ return ssl;
+#else
+ (void)sslctx; (void)fd;
+ return NULL;
+#endif
+}
+
+void* outgoing_ssl_fd(void* sslctx, int fd)
+{
+#ifdef HAVE_SSL
+ SSL* ssl = SSL_new((SSL_CTX*)sslctx);
+ if(!ssl) {
+ log_crypto_err("could not SSL_new");
+ return NULL;
+ }
+ SSL_set_connect_state(ssl);
+ (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY);
+ if(!SSL_set_fd(ssl, fd)) {
+ log_crypto_err("could not SSL_set_fd");
+ SSL_free(ssl);
+ return NULL;
+ }
+ return ssl;
+#else
+ (void)sslctx; (void)fd;
+ return NULL;
+#endif
+}
+
+#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
+/** global lock list for openssl locks */
+static lock_basic_t *ub_openssl_locks = NULL;
+
+/** callback that gets thread id for openssl */
+static unsigned long
+ub_crypto_id_cb(void)
+{
+ return (unsigned long)ub_thread_self();
+}
+
+static void
+ub_crypto_lock_cb(int mode, int type, const char *ATTR_UNUSED(file),
+ int ATTR_UNUSED(line))
+{
+ if((mode&CRYPTO_LOCK)) {
+ lock_basic_lock(&ub_openssl_locks[type]);
+ } else {
+ lock_basic_unlock(&ub_openssl_locks[type]);
+ }
+}
+#endif /* OPENSSL_THREADS */
+
+int ub_openssl_lock_init(void)
+{
+#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
+ int i;
+ ub_openssl_locks = (lock_basic_t*)malloc(
+ sizeof(lock_basic_t)*CRYPTO_num_locks());
+ if(!ub_openssl_locks)
+ return 0;
+ for(i=0; i<CRYPTO_num_locks(); i++) {
+ lock_basic_init(&ub_openssl_locks[i]);
+ }
+ CRYPTO_set_id_callback(&ub_crypto_id_cb);
+ CRYPTO_set_locking_callback(&ub_crypto_lock_cb);
+#endif /* OPENSSL_THREADS */
+ return 1;
+}
+
+void ub_openssl_lock_delete(void)
+{
+#if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
+ int i;
+ if(!ub_openssl_locks)
+ return;
+ CRYPTO_set_id_callback(NULL);
+ CRYPTO_set_locking_callback(NULL);
+ for(i=0; i<CRYPTO_num_locks(); i++) {
+ lock_basic_destroy(&ub_openssl_locks[i]);
+ }
+ free(ub_openssl_locks);
+#endif /* OPENSSL_THREADS */
+}
+
diff --git a/external/unbound/util/net_help.h b/external/unbound/util/net_help.h
new file mode 100644
index 000000000..54f4c9c0e
--- /dev/null
+++ b/external/unbound/util/net_help.h
@@ -0,0 +1,393 @@
+/*
+ * util/net_help.h - network help functions
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 perform network related tasks.
+ */
+
+#ifndef NET_HELP_H
+#define NET_HELP_H
+#include "util/log.h"
+struct sock_list;
+struct regional;
+
+/** DNS constants for uint16_t style flag manipulation. host byteorder.
+ * 1 1 1 1 1 1
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ * |QR| Opcode |AA|TC|RD|RA| Z|AD|CD| RCODE |
+ * +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
+ */
+/** CD flag */
+#define BIT_CD 0x0010
+/** AD flag */
+#define BIT_AD 0x0020
+/** Z flag */
+#define BIT_Z 0x0040
+/** RA flag */
+#define BIT_RA 0x0080
+/** RD flag */
+#define BIT_RD 0x0100
+/** TC flag */
+#define BIT_TC 0x0200
+/** AA flag */
+#define BIT_AA 0x0400
+/** QR flag */
+#define BIT_QR 0x8000
+/** get RCODE bits from uint16 flags */
+#define FLAGS_GET_RCODE(f) ((f) & 0xf)
+/** set RCODE bits in uint16 flags */
+#define FLAGS_SET_RCODE(f, r) (f = (((f) & 0xfff0) | (r)))
+
+/** timeout in seconds for UDP queries to auth servers. */
+#define UDP_AUTH_QUERY_TIMEOUT 4
+/** timeout in seconds for TCP queries to auth servers. */
+#define TCP_AUTH_QUERY_TIMEOUT 30
+/** Advertised version of EDNS capabilities */
+#define EDNS_ADVERTISED_VERSION 0
+/** Advertised size of EDNS capabilities */
+extern uint16_t EDNS_ADVERTISED_SIZE;
+/** bits for EDNS bitfield */
+#define EDNS_DO 0x8000 /* Dnssec Ok */
+/** byte size of ip4 address */
+#define INET_SIZE 4
+/** byte size of ip6 address */
+#define INET6_SIZE 16
+
+/** DNSKEY zone sign key flag */
+#define DNSKEY_BIT_ZSK 0x0100
+/** DNSKEY secure entry point, KSK flag */
+#define DNSKEY_BIT_SEP 0x0001
+
+/** minimal responses when positive answer */
+extern int MINIMAL_RESPONSES;
+
+/** rrset order roundrobin */
+extern int RRSET_ROUNDROBIN;
+
+/**
+ * See if string is ip4 or ip6.
+ * @param str: IP specification.
+ * @return: true if string addr is an ip6 specced address.
+ */
+int str_is_ip6(const char* str);
+
+/**
+ * Set fd nonblocking.
+ * @param s: file descriptor.
+ * @return: 0 on error (error is printed to log).
+ */
+int fd_set_nonblock(int s);
+
+/**
+ * Set fd (back to) blocking.
+ * @param s: file descriptor.
+ * @return: 0 on error (error is printed to log).
+ */
+int fd_set_block(int s);
+
+/**
+ * See if number is a power of 2.
+ * @param num: the value.
+ * @return: true if the number is a power of 2.
+ */
+int is_pow2(size_t num);
+
+/**
+ * Allocate memory and copy over contents.
+ * @param data: what to copy over.
+ * @param len: length of data.
+ * @return: NULL on malloc failure, or newly malloced data.
+ */
+void* memdup(void* data, size_t len);
+
+/**
+ * Prints the sockaddr in readable format with log_info. Debug helper.
+ * @param v: at what verbosity level to print this.
+ * @param str: descriptive string printed with it.
+ * @param addr: the sockaddr to print. Can be ip4 or ip6.
+ * @param addrlen: length of addr.
+ */
+void log_addr(enum verbosity_value v, const char* str,
+ struct sockaddr_storage* addr, socklen_t addrlen);
+
+/**
+ * Prints zone name and sockaddr in readable format with log_info. Debug.
+ * @param v: at what verbosity level to print this.
+ * @param str: descriptive string printed with it.
+ * @param zone: DNS domain name, uncompressed wireformat.
+ * @param addr: the sockaddr to print. Can be ip4 or ip6.
+ * @param addrlen: length of addr.
+ */
+void log_name_addr(enum verbosity_value v, const char* str, uint8_t* zone,
+ struct sockaddr_storage* addr, socklen_t addrlen);
+
+/**
+ * Log errno and addr.
+ * @param str: descriptive string printed with it.
+ * @param err: errno string to print, i.e. strerror(errno).
+ * @param addr: the sockaddr to print. Can be ip4 or ip6.
+ * @param addrlen: length of addr.
+ */
+void log_err_addr(const char* str, const char* err,
+ struct sockaddr_storage* addr, socklen_t addrlen);
+
+/**
+ * Convert address string, with "@port" appendix, to sockaddr.
+ * Uses DNS port by default.
+ * @param str: the string
+ * @param addr: where to store sockaddr.
+ * @param addrlen: length of stored sockaddr is returned.
+ * @return 0 on error.
+ */
+int extstrtoaddr(const char* str, struct sockaddr_storage* addr,
+ socklen_t* addrlen);
+
+/**
+ * Convert ip address string and port to sockaddr.
+ * @param ip: ip4 or ip6 address string.
+ * @param port: port number, host format.
+ * @param addr: where to store sockaddr.
+ * @param addrlen: length of stored sockaddr is returned.
+ * @return 0 on error.
+ */
+int ipstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
+ socklen_t* addrlen);
+
+/**
+ * Convert ip netblock (ip/netsize) string and port to sockaddr.
+ * *SLOW*, does a malloc internally to avoid writing over 'ip' string.
+ * @param ip: ip4 or ip6 address string.
+ * @param port: port number, host format.
+ * @param addr: where to store sockaddr.
+ * @param addrlen: length of stored sockaddr is returned.
+ * @param net: netblock size is returned.
+ * @return 0 on error.
+ */
+int netblockstrtoaddr(const char* ip, int port, struct sockaddr_storage* addr,
+ socklen_t* addrlen, int* net);
+
+/**
+ * Print string with neat domain name, type and class.
+ * @param v: at what verbosity level to print this.
+ * @param str: string of message.
+ * @param name: domain name uncompressed wireformat.
+ * @param type: host format RR type.
+ * @param dclass: host format RR class.
+ */
+void log_nametypeclass(enum verbosity_value v, const char* str,
+ uint8_t* name, uint16_t type, uint16_t dclass);
+
+/**
+ * Compare two sockaddrs. Imposes an ordering on the addresses.
+ * Compares address and port.
+ * @param addr1: address 1.
+ * @param len1: lengths of addr1.
+ * @param addr2: address 2.
+ * @param len2: lengths of addr2.
+ * @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger.
+ */
+int sockaddr_cmp(struct sockaddr_storage* addr1, socklen_t len1,
+ struct sockaddr_storage* addr2, socklen_t len2);
+
+/**
+ * Compare two sockaddrs. Compares address, not the port.
+ * @param addr1: address 1.
+ * @param len1: lengths of addr1.
+ * @param addr2: address 2.
+ * @param len2: lengths of addr2.
+ * @return: 0 if addr1 == addr2. -1 if addr1 is smaller, +1 if larger.
+ */
+int sockaddr_cmp_addr(struct sockaddr_storage* addr1, socklen_t len1,
+ struct sockaddr_storage* addr2, socklen_t len2);
+
+/**
+ * Checkout address family.
+ * @param addr: the sockaddr to examine.
+ * @param len: the length of addr.
+ * @return: true if sockaddr is ip6.
+ */
+int addr_is_ip6(struct sockaddr_storage* addr, socklen_t len);
+
+/**
+ * Make sure the sockaddr ends in zeroes. For tree insertion and subsequent
+ * comparison.
+ * @param addr: the ip4 or ip6 addr.
+ * @param len: length of addr.
+ * @param net: number of bits to leave untouched, the rest of the netblock
+ * address is zeroed.
+ */
+void addr_mask(struct sockaddr_storage* addr, socklen_t len, int net);
+
+/**
+ * See how many bits are shared, equal, between two addrs.
+ * @param addr1: first addr.
+ * @param net1: netblock size of first addr.
+ * @param addr2: second addr.
+ * @param net2: netblock size of second addr.
+ * @param addrlen: length of first addr and of second addr.
+ * They must be of the same length (i.e. same type IP4, IP6).
+ * @return: number of bits the same.
+ */
+int addr_in_common(struct sockaddr_storage* addr1, int net1,
+ struct sockaddr_storage* addr2, int net2, socklen_t addrlen);
+
+/**
+ * Put address into string, works for IPv4 and IPv6.
+ * @param addr: address
+ * @param addrlen: length of address
+ * @param buf: result string stored here
+ * @param len: length of buf.
+ * On failure a string with "error" is stored inside.
+ */
+void addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen,
+ char* buf, size_t len);
+
+/**
+ * See if sockaddr is an ipv6 mapped ipv4 address, "::ffff:0.0.0.0"
+ * @param addr: address
+ * @param addrlen: length of address
+ * @return true if so
+ */
+int addr_is_ip4mapped(struct sockaddr_storage* addr, socklen_t addrlen);
+
+/**
+ * See if sockaddr is 255.255.255.255.
+ * @param addr: address
+ * @param addrlen: length of address
+ * @return true if so
+ */
+int addr_is_broadcast(struct sockaddr_storage* addr, socklen_t addrlen);
+
+/**
+ * See if sockaddr is 0.0.0.0 or ::0.
+ * @param addr: address
+ * @param addrlen: length of address
+ * @return true if so
+ */
+int addr_is_any(struct sockaddr_storage* addr, socklen_t addrlen);
+
+/**
+ * Insert new socket list item. If fails logs error.
+ * @param list: pointer to pointer to first item.
+ * @param addr: address or NULL if 'cache'.
+ * @param len: length of addr, or 0 if 'cache'.
+ * @param region: where to allocate
+ */
+void sock_list_insert(struct sock_list** list, struct sockaddr_storage* addr,
+ socklen_t len, struct regional* region);
+
+/**
+ * Append one list to another. Must both be from same qstate(regional).
+ * @param list: pointer to result list that is modified.
+ * @param add: item(s) to add. They are prepended to list.
+ */
+void sock_list_prepend(struct sock_list** list, struct sock_list* add);
+
+/**
+ * Find addr in list.
+ * @param list: to search in
+ * @param addr: address to look for.
+ * @param len: length. Can be 0, look for 'cache entry'.
+ * @return true if found.
+ */
+int sock_list_find(struct sock_list* list, struct sockaddr_storage* addr,
+ socklen_t len);
+
+/**
+ * Merge socklist into another socket list. Allocates the new entries
+ * freshly and copies them over, so also performs a region switchover.
+ * Allocation failures are logged.
+ * @param list: the destination list (checked for duplicates)
+ * @param region: where to allocate
+ * @param add: the list of entries to add.
+ */
+void sock_list_merge(struct sock_list** list, struct regional* region,
+ struct sock_list* add);
+
+/**
+ * Log libcrypto error with descriptive string. Calls log_err().
+ * @param str: what failed.
+ */
+void log_crypto_err(const char* str);
+
+/**
+ * create SSL listen context
+ * @param key: private key file.
+ * @param pem: public key cert.
+ * @param verifypem: if nonNULL, verifylocation file.
+ * return SSL_CTX* or NULL on failure (logged).
+ */
+void* listen_sslctx_create(char* key, char* pem, char* verifypem);
+
+/**
+ * create SSL connect context
+ * @param key: if nonNULL (also pem nonNULL), the client private key.
+ * @param pem: client public key (or NULL if key is NULL).
+ * @param verifypem: if nonNULL used for verifylocation file.
+ * @return SSL_CTX* or NULL on failure (logged).
+ */
+void* connect_sslctx_create(char* key, char* pem, char* verifypem);
+
+/**
+ * accept a new fd and wrap it in a BIO in SSL
+ * @param sslctx: the SSL_CTX to use (from listen_sslctx_create()).
+ * @param fd: from accept, nonblocking.
+ * @return SSL or NULL on alloc failure.
+ */
+void* incoming_ssl_fd(void* sslctx, int fd);
+
+/**
+ * connect a new fd and wrap it in a BIO in SSL
+ * @param sslctx: the SSL_CTX to use (from connect_sslctx_create())
+ * @param fd: from connect.
+ * @return SSL or NULL on alloc failure
+ */
+void* outgoing_ssl_fd(void* sslctx, int fd);
+
+/**
+ * Initialize openssl locking for thread safety
+ * @return false on failure (alloc failure).
+ */
+int ub_openssl_lock_init(void);
+
+/**
+ * De-init the allocated openssl locks
+ */
+void ub_openssl_lock_delete(void);
+
+#endif /* NET_HELP_H */
diff --git a/external/unbound/util/netevent.c b/external/unbound/util/netevent.c
new file mode 100644
index 000000000..c7ed30e6c
--- /dev/null
+++ b/external/unbound/util/netevent.c
@@ -0,0 +1,2217 @@
+/*
+ * util/netevent.c - event notification
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 event notification functions.
+ */
+#include "config.h"
+#include "util/netevent.h"
+#include "util/log.h"
+#include "util/net_help.h"
+#include "util/fptr_wlist.h"
+#include "ldns/pkthdr.h"
+#include "ldns/sbuffer.h"
+#include "dnstap/dnstap.h"
+#ifdef HAVE_OPENSSL_SSL_H
+#include <openssl/ssl.h>
+#endif
+#ifdef HAVE_OPENSSL_ERR_H
+#include <openssl/err.h>
+#endif
+
+/* -------- Start of local definitions -------- */
+/** if CMSG_ALIGN is not defined on this platform, a workaround */
+#ifndef CMSG_ALIGN
+# ifdef _CMSG_DATA_ALIGN
+# define CMSG_ALIGN _CMSG_DATA_ALIGN
+# else
+# define CMSG_ALIGN(len) (((len)+sizeof(long)-1) & ~(sizeof(long)-1))
+# endif
+#endif
+
+/** if CMSG_LEN is not defined on this platform, a workaround */
+#ifndef CMSG_LEN
+# define CMSG_LEN(len) (CMSG_ALIGN(sizeof(struct cmsghdr))+(len))
+#endif
+
+/** if CMSG_SPACE is not defined on this platform, a workaround */
+#ifndef CMSG_SPACE
+# ifdef _CMSG_HDR_ALIGN
+# define CMSG_SPACE(l) (CMSG_ALIGN(l)+_CMSG_HDR_ALIGN(sizeof(struct cmsghdr)))
+# else
+# define CMSG_SPACE(l) (CMSG_ALIGN(l)+CMSG_ALIGN(sizeof(struct cmsghdr)))
+# endif
+#endif
+
+/** The TCP reading or writing query timeout in seconds */
+#define TCP_QUERY_TIMEOUT 120
+
+#ifndef NONBLOCKING_IS_BROKEN
+/** number of UDP reads to perform per read indication from select */
+#define NUM_UDP_PER_SELECT 100
+#else
+#define NUM_UDP_PER_SELECT 1
+#endif
+
+/* We define libevent structures here to hide the libevent stuff. */
+
+#ifdef USE_MINI_EVENT
+# ifdef USE_WINSOCK
+# include "util/winsock_event.h"
+# else
+# include "util/mini_event.h"
+# endif /* USE_WINSOCK */
+#else /* USE_MINI_EVENT */
+ /* we use libevent */
+# ifdef HAVE_EVENT_H
+# include <event.h>
+# else
+# include "event2/event.h"
+# include "event2/event_struct.h"
+# include "event2/event_compat.h"
+# endif
+#endif /* USE_MINI_EVENT */
+
+/**
+ * The internal event structure for keeping libevent info for the event.
+ * Possibly other structures (list, tree) this is part of.
+ */
+struct internal_event {
+ /** the comm base */
+ struct comm_base* base;
+ /** libevent event type, alloced here */
+ struct event ev;
+};
+
+/**
+ * Internal base structure, so that every thread has its own events.
+ */
+struct internal_base {
+ /** libevent event_base type. */
+ struct event_base* base;
+ /** seconds time pointer points here */
+ time_t secs;
+ /** timeval with current time */
+ struct timeval now;
+ /** the event used for slow_accept timeouts */
+ struct event slow_accept;
+ /** true if slow_accept is enabled */
+ int slow_accept_enabled;
+};
+
+/**
+ * Internal timer structure, to store timer event in.
+ */
+struct internal_timer {
+ /** the comm base */
+ struct comm_base* base;
+ /** libevent event type, alloced here */
+ struct event ev;
+ /** is timer enabled */
+ uint8_t enabled;
+};
+
+/**
+ * Internal signal structure, to store signal event in.
+ */
+struct internal_signal {
+ /** libevent event type, alloced here */
+ struct event ev;
+ /** next in signal list */
+ struct internal_signal* next;
+};
+
+/** create a tcp handler with a parent */
+static struct comm_point* comm_point_create_tcp_handler(
+ struct comm_base *base, struct comm_point* parent, size_t bufsize,
+ comm_point_callback_t* callback, void* callback_arg);
+
+/* -------- End of local definitions -------- */
+
+#ifdef USE_MINI_EVENT
+/** minievent updates the time when it blocks. */
+#define comm_base_now(x) /* nothing to do */
+#else /* !USE_MINI_EVENT */
+/** fillup the time values in the event base */
+static void
+comm_base_now(struct comm_base* b)
+{
+ if(gettimeofday(&b->eb->now, NULL) < 0) {
+ log_err("gettimeofday: %s", strerror(errno));
+ }
+ b->eb->secs = (time_t)b->eb->now.tv_sec;
+}
+#endif /* USE_MINI_EVENT */
+
+struct comm_base*
+comm_base_create(int sigs)
+{
+ struct comm_base* b = (struct comm_base*)calloc(1,
+ sizeof(struct comm_base));
+ if(!b)
+ return NULL;
+ b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
+ if(!b->eb) {
+ free(b);
+ return NULL;
+ }
+#ifdef USE_MINI_EVENT
+ (void)sigs;
+ /* use mini event time-sharing feature */
+ b->eb->base = event_init(&b->eb->secs, &b->eb->now);
+#else
+# if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
+ /* libev */
+ if(sigs)
+ b->eb->base=(struct event_base *)ev_default_loop(EVFLAG_AUTO);
+ else
+ b->eb->base=(struct event_base *)ev_loop_new(EVFLAG_AUTO);
+# else
+ (void)sigs;
+# ifdef HAVE_EVENT_BASE_NEW
+ b->eb->base = event_base_new();
+# else
+ b->eb->base = event_init();
+# endif
+# endif
+#endif
+ if(!b->eb->base) {
+ free(b->eb);
+ free(b);
+ return NULL;
+ }
+ comm_base_now(b);
+ /* avoid event_get_method call which causes crashes even when
+ * not printing, because its result is passed */
+ verbose(VERB_ALGO,
+#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
+ "libev"
+#elif defined(USE_MINI_EVENT)
+ "event "
+#else
+ "libevent "
+#endif
+ "%s uses %s method.",
+ event_get_version(),
+#ifdef HAVE_EVENT_BASE_GET_METHOD
+ event_base_get_method(b->eb->base)
+#else
+ "not_obtainable"
+#endif
+ );
+ return b;
+}
+
+struct comm_base*
+comm_base_create_event(struct event_base* base)
+{
+ struct comm_base* b = (struct comm_base*)calloc(1,
+ sizeof(struct comm_base));
+ if(!b)
+ return NULL;
+ b->eb = (struct internal_base*)calloc(1, sizeof(struct internal_base));
+ if(!b->eb) {
+ free(b);
+ return NULL;
+ }
+ b->eb->base = base;
+ comm_base_now(b);
+ return b;
+}
+
+void
+comm_base_delete(struct comm_base* b)
+{
+ if(!b)
+ return;
+ if(b->eb->slow_accept_enabled) {
+ if(event_del(&b->eb->slow_accept) != 0) {
+ log_err("could not event_del slow_accept");
+ }
+ }
+#ifdef USE_MINI_EVENT
+ event_base_free(b->eb->base);
+#elif defined(HAVE_EVENT_BASE_FREE) && defined(HAVE_EVENT_BASE_ONCE)
+ /* only libevent 1.2+ has it, but in 1.2 it is broken -
+ assertion fails on signal handling ev that is not deleted
+ in libevent 1.3c (event_base_once appears) this is fixed. */
+ event_base_free(b->eb->base);
+#endif /* HAVE_EVENT_BASE_FREE and HAVE_EVENT_BASE_ONCE */
+ b->eb->base = NULL;
+ free(b->eb);
+ free(b);
+}
+
+void
+comm_base_delete_no_base(struct comm_base* b)
+{
+ if(!b)
+ return;
+ if(b->eb->slow_accept_enabled) {
+ if(event_del(&b->eb->slow_accept) != 0) {
+ log_err("could not event_del slow_accept");
+ }
+ }
+ b->eb->base = NULL;
+ free(b->eb);
+ free(b);
+}
+
+void
+comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv)
+{
+ *tt = &b->eb->secs;
+ *tv = &b->eb->now;
+}
+
+void
+comm_base_dispatch(struct comm_base* b)
+{
+ int retval;
+ retval = event_base_dispatch(b->eb->base);
+ if(retval != 0) {
+ fatal_exit("event_dispatch returned error %d, "
+ "errno is %s", retval, strerror(errno));
+ }
+}
+
+void comm_base_exit(struct comm_base* b)
+{
+ if(event_base_loopexit(b->eb->base, NULL) != 0) {
+ log_err("Could not loopexit");
+ }
+}
+
+void comm_base_set_slow_accept_handlers(struct comm_base* b,
+ void (*stop_acc)(void*), void (*start_acc)(void*), void* arg)
+{
+ b->stop_accept = stop_acc;
+ b->start_accept = start_acc;
+ b->cb_arg = arg;
+}
+
+struct event_base* comm_base_internal(struct comm_base* b)
+{
+ return b->eb->base;
+}
+
+/** see if errno for udp has to be logged or not uses globals */
+static int
+udp_send_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
+{
+ /* do not log transient errors (unless high verbosity) */
+#if defined(ENETUNREACH) || defined(EHOSTDOWN) || defined(EHOSTUNREACH) || defined(ENETDOWN)
+ switch(errno) {
+# ifdef ENETUNREACH
+ case ENETUNREACH:
+# endif
+# ifdef EHOSTDOWN
+ case EHOSTDOWN:
+# endif
+# ifdef EHOSTUNREACH
+ case EHOSTUNREACH:
+# endif
+# ifdef ENETDOWN
+ case ENETDOWN:
+# endif
+ if(verbosity < VERB_ALGO)
+ return 0;
+ default:
+ break;
+ }
+#endif
+ /* permission denied is gotten for every send if the
+ * network is disconnected (on some OS), squelch it */
+ if(errno == EPERM && verbosity < VERB_DETAIL)
+ return 0;
+ /* squelch errors where people deploy AAAA ::ffff:bla for
+ * authority servers, which we try for intranets. */
+ if(errno == EINVAL && addr_is_ip4mapped(
+ (struct sockaddr_storage*)addr, addrlen) &&
+ verbosity < VERB_DETAIL)
+ return 0;
+ /* SO_BROADCAST sockopt can give access to 255.255.255.255,
+ * but a dns cache does not need it. */
+ if(errno == EACCES && addr_is_broadcast(
+ (struct sockaddr_storage*)addr, addrlen) &&
+ verbosity < VERB_DETAIL)
+ return 0;
+ return 1;
+}
+
+int tcp_connect_errno_needs_log(struct sockaddr* addr, socklen_t addrlen)
+{
+ return udp_send_errno_needs_log(addr, addrlen);
+}
+
+/* send a UDP reply */
+int
+comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
+ struct sockaddr* addr, socklen_t addrlen)
+{
+ ssize_t sent;
+ log_assert(c->fd != -1);
+#ifdef UNBOUND_DEBUG
+ if(sldns_buffer_remaining(packet) == 0)
+ log_err("error: send empty UDP packet");
+#endif
+ log_assert(addr && addrlen > 0);
+ sent = sendto(c->fd, (void*)sldns_buffer_begin(packet),
+ sldns_buffer_remaining(packet), 0,
+ addr, addrlen);
+ if(sent == -1) {
+ if(!udp_send_errno_needs_log(addr, addrlen))
+ return 0;
+#ifndef USE_WINSOCK
+ verbose(VERB_OPS, "sendto failed: %s", strerror(errno));
+#else
+ verbose(VERB_OPS, "sendto failed: %s",
+ wsa_strerror(WSAGetLastError()));
+#endif
+ log_addr(VERB_OPS, "remote address is",
+ (struct sockaddr_storage*)addr, addrlen);
+ return 0;
+ } else if((size_t)sent != sldns_buffer_remaining(packet)) {
+ log_err("sent %d in place of %d bytes",
+ (int)sent, (int)sldns_buffer_remaining(packet));
+ return 0;
+ }
+ return 1;
+}
+
+#if defined(AF_INET6) && defined(IPV6_PKTINFO) && (defined(HAVE_RECVMSG) || defined(HAVE_SENDMSG))
+/** print debug ancillary info */
+static void p_ancil(const char* str, struct comm_reply* r)
+{
+ if(r->srctype != 4 && r->srctype != 6) {
+ log_info("%s: unknown srctype %d", str, r->srctype);
+ return;
+ }
+ if(r->srctype == 6) {
+ char buf[1024];
+ if(inet_ntop(AF_INET6, &r->pktinfo.v6info.ipi6_addr,
+ buf, (socklen_t)sizeof(buf)) == 0) {
+ (void)strlcpy(buf, "(inet_ntop error)", sizeof(buf));
+ }
+ buf[sizeof(buf)-1]=0;
+ log_info("%s: %s %d", str, buf, r->pktinfo.v6info.ipi6_ifindex);
+ } else if(r->srctype == 4) {
+#ifdef IP_PKTINFO
+ char buf1[1024], buf2[1024];
+ if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_addr,
+ buf1, (socklen_t)sizeof(buf1)) == 0) {
+ (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
+ }
+ buf1[sizeof(buf1)-1]=0;
+#ifdef HAVE_STRUCT_IN_PKTINFO_IPI_SPEC_DST
+ if(inet_ntop(AF_INET, &r->pktinfo.v4info.ipi_spec_dst,
+ buf2, (socklen_t)sizeof(buf2)) == 0) {
+ (void)strlcpy(buf2, "(inet_ntop error)", sizeof(buf2));
+ }
+ buf2[sizeof(buf2)-1]=0;
+#else
+ buf2[0]=0;
+#endif
+ log_info("%s: %d %s %s", str, r->pktinfo.v4info.ipi_ifindex,
+ buf1, buf2);
+#elif defined(IP_RECVDSTADDR)
+ char buf1[1024];
+ if(inet_ntop(AF_INET, &r->pktinfo.v4addr,
+ buf1, (socklen_t)sizeof(buf1)) == 0) {
+ (void)strlcpy(buf1, "(inet_ntop error)", sizeof(buf1));
+ }
+ buf1[sizeof(buf1)-1]=0;
+ log_info("%s: %s", str, buf1);
+#endif /* IP_PKTINFO or PI_RECVDSTDADDR */
+ }
+}
+#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG||HAVE_SENDMSG */
+
+/** send a UDP reply over specified interface*/
+static int
+comm_point_send_udp_msg_if(struct comm_point *c, sldns_buffer* packet,
+ struct sockaddr* addr, socklen_t addrlen, struct comm_reply* r)
+{
+#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_SENDMSG)
+ ssize_t sent;
+ struct msghdr msg;
+ struct iovec iov[1];
+ char control[256];
+#ifndef S_SPLINT_S
+ struct cmsghdr *cmsg;
+#endif /* S_SPLINT_S */
+
+ log_assert(c->fd != -1);
+#ifdef UNBOUND_DEBUG
+ if(sldns_buffer_remaining(packet) == 0)
+ log_err("error: send empty UDP packet");
+#endif
+ log_assert(addr && addrlen > 0);
+
+ msg.msg_name = addr;
+ msg.msg_namelen = addrlen;
+ iov[0].iov_base = sldns_buffer_begin(packet);
+ iov[0].iov_len = sldns_buffer_remaining(packet);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = control;
+#ifndef S_SPLINT_S
+ msg.msg_controllen = sizeof(control);
+#endif /* S_SPLINT_S */
+ msg.msg_flags = 0;
+
+#ifndef S_SPLINT_S
+ cmsg = CMSG_FIRSTHDR(&msg);
+ if(r->srctype == 4) {
+#ifdef IP_PKTINFO
+ msg.msg_controllen = CMSG_SPACE(sizeof(struct in_pktinfo));
+ log_assert(msg.msg_controllen <= sizeof(control));
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ memmove(CMSG_DATA(cmsg), &r->pktinfo.v4info,
+ sizeof(struct in_pktinfo));
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_pktinfo));
+#elif defined(IP_SENDSRCADDR)
+ msg.msg_controllen = CMSG_SPACE(sizeof(struct in_addr));
+ log_assert(msg.msg_controllen <= sizeof(control));
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_SENDSRCADDR;
+ memmove(CMSG_DATA(cmsg), &r->pktinfo.v4addr,
+ sizeof(struct in_addr));
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
+#else
+ verbose(VERB_ALGO, "no IP_PKTINFO or IP_SENDSRCADDR");
+ msg.msg_control = NULL;
+#endif /* IP_PKTINFO or IP_SENDSRCADDR */
+ } else if(r->srctype == 6) {
+ msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
+ log_assert(msg.msg_controllen <= sizeof(control));
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ memmove(CMSG_DATA(cmsg), &r->pktinfo.v6info,
+ sizeof(struct in6_pktinfo));
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ } else {
+ /* try to pass all 0 to use default route */
+ msg.msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo));
+ log_assert(msg.msg_controllen <= sizeof(control));
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ memset(CMSG_DATA(cmsg), 0, sizeof(struct in6_pktinfo));
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo));
+ }
+#endif /* S_SPLINT_S */
+ if(verbosity >= VERB_ALGO)
+ p_ancil("send_udp over interface", r);
+ sent = sendmsg(c->fd, &msg, 0);
+ if(sent == -1) {
+ if(!udp_send_errno_needs_log(addr, addrlen))
+ return 0;
+ verbose(VERB_OPS, "sendmsg failed: %s", strerror(errno));
+ log_addr(VERB_OPS, "remote address is",
+ (struct sockaddr_storage*)addr, addrlen);
+ return 0;
+ } else if((size_t)sent != sldns_buffer_remaining(packet)) {
+ log_err("sent %d in place of %d bytes",
+ (int)sent, (int)sldns_buffer_remaining(packet));
+ return 0;
+ }
+ return 1;
+#else
+ (void)c;
+ (void)packet;
+ (void)addr;
+ (void)addrlen;
+ (void)r;
+ log_err("sendmsg: IPV6_PKTINFO not supported");
+ return 0;
+#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_SENDMSG */
+}
+
+void
+comm_point_udp_ancil_callback(int fd, short event, void* arg)
+{
+#if defined(AF_INET6) && defined(IPV6_PKTINFO) && defined(HAVE_RECVMSG)
+ struct comm_reply rep;
+ struct msghdr msg;
+ struct iovec iov[1];
+ ssize_t rcv;
+ char ancil[256];
+ int i;
+#ifndef S_SPLINT_S
+ struct cmsghdr* cmsg;
+#endif /* S_SPLINT_S */
+
+ rep.c = (struct comm_point*)arg;
+ log_assert(rep.c->type == comm_udp);
+
+ if(!(event&EV_READ))
+ return;
+ log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
+ comm_base_now(rep.c->ev->base);
+ for(i=0; i<NUM_UDP_PER_SELECT; i++) {
+ sldns_buffer_clear(rep.c->buffer);
+ rep.addrlen = (socklen_t)sizeof(rep.addr);
+ log_assert(fd != -1);
+ log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
+ msg.msg_name = &rep.addr;
+ msg.msg_namelen = (socklen_t)sizeof(rep.addr);
+ iov[0].iov_base = sldns_buffer_begin(rep.c->buffer);
+ iov[0].iov_len = sldns_buffer_remaining(rep.c->buffer);
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = ancil;
+#ifndef S_SPLINT_S
+ msg.msg_controllen = sizeof(ancil);
+#endif /* S_SPLINT_S */
+ msg.msg_flags = 0;
+ rcv = recvmsg(fd, &msg, 0);
+ if(rcv == -1) {
+ if(errno != EAGAIN && errno != EINTR) {
+ log_err("recvmsg failed: %s", strerror(errno));
+ }
+ return;
+ }
+ rep.addrlen = msg.msg_namelen;
+ sldns_buffer_skip(rep.c->buffer, rcv);
+ sldns_buffer_flip(rep.c->buffer);
+ rep.srctype = 0;
+#ifndef S_SPLINT_S
+ for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+ if( cmsg->cmsg_level == IPPROTO_IPV6 &&
+ cmsg->cmsg_type == IPV6_PKTINFO) {
+ rep.srctype = 6;
+ memmove(&rep.pktinfo.v6info, CMSG_DATA(cmsg),
+ sizeof(struct in6_pktinfo));
+ break;
+#ifdef IP_PKTINFO
+ } else if( cmsg->cmsg_level == IPPROTO_IP &&
+ cmsg->cmsg_type == IP_PKTINFO) {
+ rep.srctype = 4;
+ memmove(&rep.pktinfo.v4info, CMSG_DATA(cmsg),
+ sizeof(struct in_pktinfo));
+ break;
+#elif defined(IP_RECVDSTADDR)
+ } else if( cmsg->cmsg_level == IPPROTO_IP &&
+ cmsg->cmsg_type == IP_RECVDSTADDR) {
+ rep.srctype = 4;
+ memmove(&rep.pktinfo.v4addr, CMSG_DATA(cmsg),
+ sizeof(struct in_addr));
+ break;
+#endif /* IP_PKTINFO or IP_RECVDSTADDR */
+ }
+ }
+ if(verbosity >= VERB_ALGO)
+ p_ancil("receive_udp on interface", &rep);
+#endif /* S_SPLINT_S */
+ fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
+ if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
+ /* send back immediate reply */
+ (void)comm_point_send_udp_msg_if(rep.c, rep.c->buffer,
+ (struct sockaddr*)&rep.addr, rep.addrlen, &rep);
+ }
+ if(rep.c->fd == -1) /* commpoint closed */
+ break;
+ }
+#else
+ (void)fd;
+ (void)event;
+ (void)arg;
+ fatal_exit("recvmsg: No support for IPV6_PKTINFO. "
+ "Please disable interface-automatic");
+#endif /* AF_INET6 && IPV6_PKTINFO && HAVE_RECVMSG */
+}
+
+void
+comm_point_udp_callback(int fd, short event, void* arg)
+{
+ struct comm_reply rep;
+ ssize_t rcv;
+ int i;
+
+ rep.c = (struct comm_point*)arg;
+ log_assert(rep.c->type == comm_udp);
+
+ if(!(event&EV_READ))
+ return;
+ log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);
+ comm_base_now(rep.c->ev->base);
+ for(i=0; i<NUM_UDP_PER_SELECT; i++) {
+ sldns_buffer_clear(rep.c->buffer);
+ rep.addrlen = (socklen_t)sizeof(rep.addr);
+ log_assert(fd != -1);
+ log_assert(sldns_buffer_remaining(rep.c->buffer) > 0);
+ rcv = recvfrom(fd, (void*)sldns_buffer_begin(rep.c->buffer),
+ sldns_buffer_remaining(rep.c->buffer), 0,
+ (struct sockaddr*)&rep.addr, &rep.addrlen);
+ if(rcv == -1) {
+#ifndef USE_WINSOCK
+ if(errno != EAGAIN && errno != EINTR)
+ log_err("recvfrom %d failed: %s",
+ fd, strerror(errno));
+#else
+ if(WSAGetLastError() != WSAEINPROGRESS &&
+ WSAGetLastError() != WSAECONNRESET &&
+ WSAGetLastError()!= WSAEWOULDBLOCK)
+ log_err("recvfrom failed: %s",
+ wsa_strerror(WSAGetLastError()));
+#endif
+ return;
+ }
+ sldns_buffer_skip(rep.c->buffer, rcv);
+ sldns_buffer_flip(rep.c->buffer);
+ rep.srctype = 0;
+ fptr_ok(fptr_whitelist_comm_point(rep.c->callback));
+ if((*rep.c->callback)(rep.c, rep.c->cb_arg, NETEVENT_NOERROR, &rep)) {
+ /* send back immediate reply */
+ (void)comm_point_send_udp_msg(rep.c, rep.c->buffer,
+ (struct sockaddr*)&rep.addr, rep.addrlen);
+ }
+ if(rep.c->fd != fd) /* commpoint closed to -1 or reused for
+ another UDP port. Note rep.c cannot be reused with TCP fd. */
+ break;
+ }
+}
+
+/** Use a new tcp handler for new query fd, set to read query */
+static void
+setup_tcp_handler(struct comm_point* c, int fd)
+{
+ log_assert(c->type == comm_tcp);
+ log_assert(c->fd == -1);
+ sldns_buffer_clear(c->buffer);
+ c->tcp_is_reading = 1;
+ c->tcp_byte_count = 0;
+ comm_point_start_listening(c, fd, TCP_QUERY_TIMEOUT);
+}
+
+void comm_base_handle_slow_accept(int ATTR_UNUSED(fd),
+ short ATTR_UNUSED(event), void* arg)
+{
+ struct comm_base* b = (struct comm_base*)arg;
+ /* timeout for the slow accept, re-enable accepts again */
+ if(b->start_accept) {
+ verbose(VERB_ALGO, "wait is over, slow accept disabled");
+ fptr_ok(fptr_whitelist_start_accept(b->start_accept));
+ (*b->start_accept)(b->cb_arg);
+ b->eb->slow_accept_enabled = 0;
+ }
+}
+
+int comm_point_perform_accept(struct comm_point* c,
+ struct sockaddr_storage* addr, socklen_t* addrlen)
+{
+ int new_fd;
+ *addrlen = (socklen_t)sizeof(*addr);
+ new_fd = accept(c->fd, (struct sockaddr*)addr, addrlen);
+ if(new_fd == -1) {
+#ifndef USE_WINSOCK
+ /* EINTR is signal interrupt. others are closed connection. */
+ if( errno == EINTR || errno == EAGAIN
+#ifdef EWOULDBLOCK
+ || errno == EWOULDBLOCK
+#endif
+#ifdef ECONNABORTED
+ || errno == ECONNABORTED
+#endif
+#ifdef EPROTO
+ || errno == EPROTO
+#endif /* EPROTO */
+ )
+ return -1;
+#if defined(ENFILE) && defined(EMFILE)
+ if(errno == ENFILE || errno == EMFILE) {
+ /* out of file descriptors, likely outside of our
+ * control. stop accept() calls for some time */
+ if(c->ev->base->stop_accept) {
+ struct comm_base* b = c->ev->base;
+ struct timeval tv;
+ verbose(VERB_ALGO, "out of file descriptors: "
+ "slow accept");
+ b->eb->slow_accept_enabled = 1;
+ fptr_ok(fptr_whitelist_stop_accept(
+ b->stop_accept));
+ (*b->stop_accept)(b->cb_arg);
+ /* set timeout, no mallocs */
+ tv.tv_sec = NETEVENT_SLOW_ACCEPT_TIME/1000;
+ tv.tv_usec = NETEVENT_SLOW_ACCEPT_TIME%1000;
+ event_set(&b->eb->slow_accept, -1, EV_TIMEOUT,
+ comm_base_handle_slow_accept, b);
+ if(event_base_set(b->eb->base,
+ &b->eb->slow_accept) != 0) {
+ /* we do not want to log here, because
+ * that would spam the logfiles.
+ * error: "event_base_set failed." */
+ }
+ if(event_add(&b->eb->slow_accept, &tv) != 0) {
+ /* we do not want to log here,
+ * error: "event_add failed." */
+ }
+ }
+ return -1;
+ }
+#endif
+ log_err_addr("accept failed", strerror(errno), addr, *addrlen);
+#else /* USE_WINSOCK */
+ if(WSAGetLastError() == WSAEINPROGRESS ||
+ WSAGetLastError() == WSAECONNRESET)
+ return -1;
+ if(WSAGetLastError() == WSAEWOULDBLOCK) {
+ winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
+ return -1;
+ }
+ log_err_addr("accept failed", wsa_strerror(WSAGetLastError()),
+ addr, *addrlen);
+#endif
+ return -1;
+ }
+ fd_set_nonblock(new_fd);
+ return new_fd;
+}
+
+#ifdef USE_WINSOCK
+static long win_bio_cb(BIO *b, int oper, const char* ATTR_UNUSED(argp),
+ int ATTR_UNUSED(argi), long argl, long retvalue)
+{
+ verbose(VERB_ALGO, "bio_cb %d, %s %s %s", oper,
+ (oper&BIO_CB_RETURN)?"return":"before",
+ (oper&BIO_CB_READ)?"read":((oper&BIO_CB_WRITE)?"write":"other"),
+ WSAGetLastError()==WSAEWOULDBLOCK?"wsawb":"");
+ /* on windows, check if previous operation caused EWOULDBLOCK */
+ if( (oper == (BIO_CB_READ|BIO_CB_RETURN) && argl == 0) ||
+ (oper == (BIO_CB_GETS|BIO_CB_RETURN) && argl == 0)) {
+ if(WSAGetLastError() == WSAEWOULDBLOCK)
+ winsock_tcp_wouldblock((struct event*)
+ BIO_get_callback_arg(b), EV_READ);
+ }
+ if( (oper == (BIO_CB_WRITE|BIO_CB_RETURN) && argl == 0) ||
+ (oper == (BIO_CB_PUTS|BIO_CB_RETURN) && argl == 0)) {
+ if(WSAGetLastError() == WSAEWOULDBLOCK)
+ winsock_tcp_wouldblock((struct event*)
+ BIO_get_callback_arg(b), EV_WRITE);
+ }
+ /* return original return value */
+ return retvalue;
+}
+
+/** set win bio callbacks for nonblocking operations */
+void
+comm_point_tcp_win_bio_cb(struct comm_point* c, void* thessl)
+{
+ SSL* ssl = (SSL*)thessl;
+ /* set them both just in case, but usually they are the same BIO */
+ BIO_set_callback(SSL_get_rbio(ssl), &win_bio_cb);
+ BIO_set_callback_arg(SSL_get_rbio(ssl), (char*)&c->ev->ev);
+ BIO_set_callback(SSL_get_wbio(ssl), &win_bio_cb);
+ BIO_set_callback_arg(SSL_get_wbio(ssl), (char*)&c->ev->ev);
+}
+#endif
+
+void
+comm_point_tcp_accept_callback(int fd, short event, void* arg)
+{
+ struct comm_point* c = (struct comm_point*)arg, *c_hdl;
+ int new_fd;
+ log_assert(c->type == comm_tcp_accept);
+ if(!(event & EV_READ)) {
+ log_info("ignoring tcp accept event %d", (int)event);
+ return;
+ }
+ comm_base_now(c->ev->base);
+ /* find free tcp handler. */
+ if(!c->tcp_free) {
+ log_warn("accepted too many tcp, connections full");
+ return;
+ }
+ /* accept incoming connection. */
+ c_hdl = c->tcp_free;
+ log_assert(fd != -1);
+ new_fd = comm_point_perform_accept(c, &c_hdl->repinfo.addr,
+ &c_hdl->repinfo.addrlen);
+ if(new_fd == -1)
+ return;
+ if(c->ssl) {
+ c_hdl->ssl = incoming_ssl_fd(c->ssl, new_fd);
+ if(!c_hdl->ssl) {
+ c_hdl->fd = new_fd;
+ comm_point_close(c_hdl);
+ return;
+ }
+ c_hdl->ssl_shake_state = comm_ssl_shake_read;
+#ifdef USE_WINSOCK
+ comm_point_tcp_win_bio_cb(c_hdl, c_hdl->ssl);
+#endif
+ }
+
+ /* grab the tcp handler buffers */
+ c->tcp_free = c_hdl->tcp_free;
+ if(!c->tcp_free) {
+ /* stop accepting incoming queries for now. */
+ comm_point_stop_listening(c);
+ }
+ /* addr is dropped. Not needed for tcp reply. */
+ setup_tcp_handler(c_hdl, new_fd);
+}
+
+/** Make tcp handler free for next assignment */
+static void
+reclaim_tcp_handler(struct comm_point* c)
+{
+ log_assert(c->type == comm_tcp);
+ if(c->ssl) {
+#ifdef HAVE_SSL
+ SSL_shutdown(c->ssl);
+ SSL_free(c->ssl);
+ c->ssl = NULL;
+#endif
+ }
+ comm_point_close(c);
+ if(c->tcp_parent) {
+ c->tcp_free = c->tcp_parent->tcp_free;
+ c->tcp_parent->tcp_free = c;
+ if(!c->tcp_free) {
+ /* re-enable listening on accept socket */
+ comm_point_start_listening(c->tcp_parent, -1, -1);
+ }
+ }
+}
+
+/** do the callback when writing is done */
+static void
+tcp_callback_writer(struct comm_point* c)
+{
+ log_assert(c->type == comm_tcp);
+ sldns_buffer_clear(c->buffer);
+ if(c->tcp_do_toggle_rw)
+ c->tcp_is_reading = 1;
+ c->tcp_byte_count = 0;
+ /* switch from listening(write) to listening(read) */
+ comm_point_stop_listening(c);
+ comm_point_start_listening(c, -1, -1);
+}
+
+/** do the callback when reading is done */
+static void
+tcp_callback_reader(struct comm_point* c)
+{
+ log_assert(c->type == comm_tcp || c->type == comm_local);
+ sldns_buffer_flip(c->buffer);
+ if(c->tcp_do_toggle_rw)
+ c->tcp_is_reading = 0;
+ c->tcp_byte_count = 0;
+ if(c->type == comm_tcp)
+ comm_point_stop_listening(c);
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo) ) {
+ comm_point_start_listening(c, -1, TCP_QUERY_TIMEOUT);
+ }
+}
+
+/** continue ssl handshake */
+#ifdef HAVE_SSL
+static int
+ssl_handshake(struct comm_point* c)
+{
+ int r;
+ if(c->ssl_shake_state == comm_ssl_shake_hs_read) {
+ /* read condition satisfied back to writing */
+ comm_point_listen_for_rw(c, 1, 1);
+ c->ssl_shake_state = comm_ssl_shake_none;
+ return 1;
+ }
+ if(c->ssl_shake_state == comm_ssl_shake_hs_write) {
+ /* write condition satisfied, back to reading */
+ comm_point_listen_for_rw(c, 1, 0);
+ c->ssl_shake_state = comm_ssl_shake_none;
+ return 1;
+ }
+
+ ERR_clear_error();
+ r = SSL_do_handshake(c->ssl);
+ if(r != 1) {
+ int want = SSL_get_error(c->ssl, r);
+ if(want == SSL_ERROR_WANT_READ) {
+ if(c->ssl_shake_state == comm_ssl_shake_read)
+ return 1;
+ c->ssl_shake_state = comm_ssl_shake_read;
+ comm_point_listen_for_rw(c, 1, 0);
+ return 1;
+ } else if(want == SSL_ERROR_WANT_WRITE) {
+ if(c->ssl_shake_state == comm_ssl_shake_write)
+ return 1;
+ c->ssl_shake_state = comm_ssl_shake_write;
+ comm_point_listen_for_rw(c, 0, 1);
+ return 1;
+ } else if(r == 0) {
+ return 0; /* closed */
+ } else if(want == SSL_ERROR_SYSCALL) {
+ /* SYSCALL and errno==0 means closed uncleanly */
+ if(errno != 0)
+ log_err("SSL_handshake syscall: %s",
+ strerror(errno));
+ return 0;
+ } else {
+ log_crypto_err("ssl handshake failed");
+ log_addr(1, "ssl handshake failed", &c->repinfo.addr,
+ c->repinfo.addrlen);
+ return 0;
+ }
+ }
+ /* this is where peer verification could take place */
+ log_addr(VERB_ALGO, "SSL DNS connection", &c->repinfo.addr,
+ c->repinfo.addrlen);
+
+ /* setup listen rw correctly */
+ if(c->tcp_is_reading) {
+ if(c->ssl_shake_state != comm_ssl_shake_read)
+ comm_point_listen_for_rw(c, 1, 0);
+ } else {
+ comm_point_listen_for_rw(c, 1, 1);
+ }
+ c->ssl_shake_state = comm_ssl_shake_none;
+ return 1;
+}
+#endif /* HAVE_SSL */
+
+/** ssl read callback on TCP */
+static int
+ssl_handle_read(struct comm_point* c)
+{
+#ifdef HAVE_SSL
+ int r;
+ if(c->ssl_shake_state != comm_ssl_shake_none) {
+ if(!ssl_handshake(c))
+ return 0;
+ if(c->ssl_shake_state != comm_ssl_shake_none)
+ return 1;
+ }
+ if(c->tcp_byte_count < sizeof(uint16_t)) {
+ /* read length bytes */
+ ERR_clear_error();
+ if((r=SSL_read(c->ssl, (void*)sldns_buffer_at(c->buffer,
+ c->tcp_byte_count), (int)(sizeof(uint16_t) -
+ c->tcp_byte_count))) <= 0) {
+ int want = SSL_get_error(c->ssl, r);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ return 0; /* shutdown, closed */
+ } else if(want == SSL_ERROR_WANT_READ) {
+ return 1; /* read more later */
+ } else if(want == SSL_ERROR_WANT_WRITE) {
+ c->ssl_shake_state = comm_ssl_shake_hs_write;
+ comm_point_listen_for_rw(c, 0, 1);
+ return 1;
+ } else if(want == SSL_ERROR_SYSCALL) {
+ if(errno != 0)
+ log_err("SSL_read syscall: %s",
+ strerror(errno));
+ return 0;
+ }
+ log_crypto_err("could not SSL_read");
+ return 0;
+ }
+ c->tcp_byte_count += r;
+ if(c->tcp_byte_count != sizeof(uint16_t))
+ return 1;
+ if(sldns_buffer_read_u16_at(c->buffer, 0) >
+ sldns_buffer_capacity(c->buffer)) {
+ verbose(VERB_QUERY, "ssl: dropped larger than buffer");
+ return 0;
+ }
+ sldns_buffer_set_limit(c->buffer,
+ sldns_buffer_read_u16_at(c->buffer, 0));
+ if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
+ verbose(VERB_QUERY, "ssl: dropped bogus too short.");
+ return 0;
+ }
+ verbose(VERB_ALGO, "Reading ssl tcp query of length %d",
+ (int)sldns_buffer_limit(c->buffer));
+ }
+ log_assert(sldns_buffer_remaining(c->buffer) > 0);
+ ERR_clear_error();
+ r = SSL_read(c->ssl, (void*)sldns_buffer_current(c->buffer),
+ (int)sldns_buffer_remaining(c->buffer));
+ if(r <= 0) {
+ int want = SSL_get_error(c->ssl, r);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ return 0; /* shutdown, closed */
+ } else if(want == SSL_ERROR_WANT_READ) {
+ return 1; /* read more later */
+ } else if(want == SSL_ERROR_WANT_WRITE) {
+ c->ssl_shake_state = comm_ssl_shake_hs_write;
+ comm_point_listen_for_rw(c, 0, 1);
+ return 1;
+ } else if(want == SSL_ERROR_SYSCALL) {
+ if(errno != 0)
+ log_err("SSL_read syscall: %s",
+ strerror(errno));
+ return 0;
+ }
+ log_crypto_err("could not SSL_read");
+ return 0;
+ }
+ sldns_buffer_skip(c->buffer, (ssize_t)r);
+ if(sldns_buffer_remaining(c->buffer) <= 0) {
+ tcp_callback_reader(c);
+ }
+ return 1;
+#else
+ (void)c;
+ return 0;
+#endif /* HAVE_SSL */
+}
+
+/** ssl write callback on TCP */
+static int
+ssl_handle_write(struct comm_point* c)
+{
+#ifdef HAVE_SSL
+ int r;
+ if(c->ssl_shake_state != comm_ssl_shake_none) {
+ if(!ssl_handshake(c))
+ return 0;
+ if(c->ssl_shake_state != comm_ssl_shake_none)
+ return 1;
+ }
+ /* ignore return, if fails we may simply block */
+ (void)SSL_set_mode(c->ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+ if(c->tcp_byte_count < sizeof(uint16_t)) {
+ uint16_t len = htons(sldns_buffer_limit(c->buffer));
+ ERR_clear_error();
+ r = SSL_write(c->ssl,
+ (void*)(((uint8_t*)&len)+c->tcp_byte_count),
+ (int)(sizeof(uint16_t)-c->tcp_byte_count));
+ if(r <= 0) {
+ int want = SSL_get_error(c->ssl, r);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ return 0; /* closed */
+ } else if(want == SSL_ERROR_WANT_READ) {
+ c->ssl_shake_state = comm_ssl_shake_read;
+ comm_point_listen_for_rw(c, 1, 0);
+ return 1; /* wait for read condition */
+ } else if(want == SSL_ERROR_WANT_WRITE) {
+ return 1; /* write more later */
+ } else if(want == SSL_ERROR_SYSCALL) {
+ if(errno != 0)
+ log_err("SSL_write syscall: %s",
+ strerror(errno));
+ return 0;
+ }
+ log_crypto_err("could not SSL_write");
+ return 0;
+ }
+ c->tcp_byte_count += r;
+ if(c->tcp_byte_count < sizeof(uint16_t))
+ return 1;
+ sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
+ sizeof(uint16_t));
+ if(sldns_buffer_remaining(c->buffer) == 0) {
+ tcp_callback_writer(c);
+ return 1;
+ }
+ }
+ log_assert(sldns_buffer_remaining(c->buffer) > 0);
+ ERR_clear_error();
+ r = SSL_write(c->ssl, (void*)sldns_buffer_current(c->buffer),
+ (int)sldns_buffer_remaining(c->buffer));
+ if(r <= 0) {
+ int want = SSL_get_error(c->ssl, r);
+ if(want == SSL_ERROR_ZERO_RETURN) {
+ return 0; /* closed */
+ } else if(want == SSL_ERROR_WANT_READ) {
+ c->ssl_shake_state = comm_ssl_shake_read;
+ comm_point_listen_for_rw(c, 1, 0);
+ return 1; /* wait for read condition */
+ } else if(want == SSL_ERROR_WANT_WRITE) {
+ return 1; /* write more later */
+ } else if(want == SSL_ERROR_SYSCALL) {
+ if(errno != 0)
+ log_err("SSL_write syscall: %s",
+ strerror(errno));
+ return 0;
+ }
+ log_crypto_err("could not SSL_write");
+ return 0;
+ }
+ sldns_buffer_skip(c->buffer, (ssize_t)r);
+
+ if(sldns_buffer_remaining(c->buffer) == 0) {
+ tcp_callback_writer(c);
+ }
+ return 1;
+#else
+ (void)c;
+ return 0;
+#endif /* HAVE_SSL */
+}
+
+/** handle ssl tcp connection with dns contents */
+static int
+ssl_handle_it(struct comm_point* c)
+{
+ if(c->tcp_is_reading)
+ return ssl_handle_read(c);
+ return ssl_handle_write(c);
+}
+
+/** Handle tcp reading callback.
+ * @param fd: file descriptor of socket.
+ * @param c: comm point to read from into buffer.
+ * @param short_ok: if true, very short packets are OK (for comm_local).
+ * @return: 0 on error
+ */
+static int
+comm_point_tcp_handle_read(int fd, struct comm_point* c, int short_ok)
+{
+ ssize_t r;
+ log_assert(c->type == comm_tcp || c->type == comm_local);
+ if(c->ssl)
+ return ssl_handle_it(c);
+ if(!c->tcp_is_reading)
+ return 0;
+
+ log_assert(fd != -1);
+ if(c->tcp_byte_count < sizeof(uint16_t)) {
+ /* read length bytes */
+ r = recv(fd,(void*)sldns_buffer_at(c->buffer,c->tcp_byte_count),
+ sizeof(uint16_t)-c->tcp_byte_count, 0);
+ if(r == 0)
+ return 0;
+ else if(r == -1) {
+#ifndef USE_WINSOCK
+ if(errno == EINTR || errno == EAGAIN)
+ return 1;
+#ifdef ECONNRESET
+ if(errno == ECONNRESET && verbosity < 2)
+ return 0; /* silence reset by peer */
+#endif
+ log_err_addr("read (in tcp s)", strerror(errno),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#else /* USE_WINSOCK */
+ if(WSAGetLastError() == WSAECONNRESET)
+ return 0;
+ if(WSAGetLastError() == WSAEINPROGRESS)
+ return 1;
+ if(WSAGetLastError() == WSAEWOULDBLOCK) {
+ winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
+ return 1;
+ }
+ log_err_addr("read (in tcp s)",
+ wsa_strerror(WSAGetLastError()),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#endif
+ return 0;
+ }
+ c->tcp_byte_count += r;
+ if(c->tcp_byte_count != sizeof(uint16_t))
+ return 1;
+ if(sldns_buffer_read_u16_at(c->buffer, 0) >
+ sldns_buffer_capacity(c->buffer)) {
+ verbose(VERB_QUERY, "tcp: dropped larger than buffer");
+ return 0;
+ }
+ sldns_buffer_set_limit(c->buffer,
+ sldns_buffer_read_u16_at(c->buffer, 0));
+ if(!short_ok &&
+ sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE) {
+ verbose(VERB_QUERY, "tcp: dropped bogus too short.");
+ return 0;
+ }
+ verbose(VERB_ALGO, "Reading tcp query of length %d",
+ (int)sldns_buffer_limit(c->buffer));
+ }
+
+ log_assert(sldns_buffer_remaining(c->buffer) > 0);
+ r = recv(fd, (void*)sldns_buffer_current(c->buffer),
+ sldns_buffer_remaining(c->buffer), 0);
+ if(r == 0) {
+ return 0;
+ } else if(r == -1) {
+#ifndef USE_WINSOCK
+ if(errno == EINTR || errno == EAGAIN)
+ return 1;
+ log_err_addr("read (in tcp r)", strerror(errno),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#else /* USE_WINSOCK */
+ if(WSAGetLastError() == WSAECONNRESET)
+ return 0;
+ if(WSAGetLastError() == WSAEINPROGRESS)
+ return 1;
+ if(WSAGetLastError() == WSAEWOULDBLOCK) {
+ winsock_tcp_wouldblock(&c->ev->ev, EV_READ);
+ return 1;
+ }
+ log_err_addr("read (in tcp r)",
+ wsa_strerror(WSAGetLastError()),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#endif
+ return 0;
+ }
+ sldns_buffer_skip(c->buffer, r);
+ if(sldns_buffer_remaining(c->buffer) <= 0) {
+ tcp_callback_reader(c);
+ }
+ return 1;
+}
+
+/**
+ * Handle tcp writing callback.
+ * @param fd: file descriptor of socket.
+ * @param c: comm point to write buffer out of.
+ * @return: 0 on error
+ */
+static int
+comm_point_tcp_handle_write(int fd, struct comm_point* c)
+{
+ ssize_t r;
+ log_assert(c->type == comm_tcp);
+ if(c->tcp_is_reading && !c->ssl)
+ return 0;
+ log_assert(fd != -1);
+ if(c->tcp_byte_count == 0 && c->tcp_check_nb_connect) {
+ /* check for pending error from nonblocking connect */
+ /* from Stevens, unix network programming, vol1, 3rd ed, p450*/
+ int error = 0;
+ socklen_t len = (socklen_t)sizeof(error);
+ if(getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)&error,
+ &len) < 0){
+#ifndef USE_WINSOCK
+ error = errno; /* on solaris errno is error */
+#else /* USE_WINSOCK */
+ error = WSAGetLastError();
+#endif
+ }
+#ifndef USE_WINSOCK
+#if defined(EINPROGRESS) && defined(EWOULDBLOCK)
+ if(error == EINPROGRESS || error == EWOULDBLOCK)
+ return 1; /* try again later */
+ else
+#endif
+ if(error != 0 && verbosity < 2)
+ return 0; /* silence lots of chatter in the logs */
+ else if(error != 0) {
+ log_err_addr("tcp connect", strerror(error),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#else /* USE_WINSOCK */
+ /* examine error */
+ if(error == WSAEINPROGRESS)
+ return 1;
+ else if(error == WSAEWOULDBLOCK) {
+ winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
+ return 1;
+ } else if(error != 0 && verbosity < 2)
+ return 0;
+ else if(error != 0) {
+ log_err_addr("tcp connect", wsa_strerror(error),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#endif /* USE_WINSOCK */
+ return 0;
+ }
+ }
+ if(c->ssl)
+ return ssl_handle_it(c);
+
+ if(c->tcp_byte_count < sizeof(uint16_t)) {
+ uint16_t len = htons(sldns_buffer_limit(c->buffer));
+#ifdef HAVE_WRITEV
+ struct iovec iov[2];
+ iov[0].iov_base = (uint8_t*)&len + c->tcp_byte_count;
+ iov[0].iov_len = sizeof(uint16_t) - c->tcp_byte_count;
+ iov[1].iov_base = sldns_buffer_begin(c->buffer);
+ iov[1].iov_len = sldns_buffer_limit(c->buffer);
+ log_assert(iov[0].iov_len > 0);
+ log_assert(iov[1].iov_len > 0);
+ r = writev(fd, iov, 2);
+#else /* HAVE_WRITEV */
+ r = send(fd, (void*)(((uint8_t*)&len)+c->tcp_byte_count),
+ sizeof(uint16_t)-c->tcp_byte_count, 0);
+#endif /* HAVE_WRITEV */
+ if(r == -1) {
+#ifndef USE_WINSOCK
+# ifdef EPIPE
+ if(errno == EPIPE && verbosity < 2)
+ return 0; /* silence 'broken pipe' */
+ #endif
+ if(errno == EINTR || errno == EAGAIN)
+ return 1;
+# ifdef HAVE_WRITEV
+ log_err_addr("tcp writev", strerror(errno),
+ &c->repinfo.addr, c->repinfo.addrlen);
+# else /* HAVE_WRITEV */
+ log_err_addr("tcp send s", strerror(errno),
+ &c->repinfo.addr, c->repinfo.addrlen);
+# endif /* HAVE_WRITEV */
+#else
+ if(WSAGetLastError() == WSAENOTCONN)
+ return 1;
+ if(WSAGetLastError() == WSAEINPROGRESS)
+ return 1;
+ if(WSAGetLastError() == WSAEWOULDBLOCK) {
+ winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
+ return 1;
+ }
+ log_err_addr("tcp send s",
+ wsa_strerror(WSAGetLastError()),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#endif
+ return 0;
+ }
+ c->tcp_byte_count += r;
+ if(c->tcp_byte_count < sizeof(uint16_t))
+ return 1;
+ sldns_buffer_set_position(c->buffer, c->tcp_byte_count -
+ sizeof(uint16_t));
+ if(sldns_buffer_remaining(c->buffer) == 0) {
+ tcp_callback_writer(c);
+ return 1;
+ }
+ }
+ log_assert(sldns_buffer_remaining(c->buffer) > 0);
+ r = send(fd, (void*)sldns_buffer_current(c->buffer),
+ sldns_buffer_remaining(c->buffer), 0);
+ if(r == -1) {
+#ifndef USE_WINSOCK
+ if(errno == EINTR || errno == EAGAIN)
+ return 1;
+ log_err_addr("tcp send r", strerror(errno),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#else
+ if(WSAGetLastError() == WSAEINPROGRESS)
+ return 1;
+ if(WSAGetLastError() == WSAEWOULDBLOCK) {
+ winsock_tcp_wouldblock(&c->ev->ev, EV_WRITE);
+ return 1;
+ }
+ log_err_addr("tcp send r", wsa_strerror(WSAGetLastError()),
+ &c->repinfo.addr, c->repinfo.addrlen);
+#endif
+ return 0;
+ }
+ sldns_buffer_skip(c->buffer, r);
+
+ if(sldns_buffer_remaining(c->buffer) == 0) {
+ tcp_callback_writer(c);
+ }
+
+ return 1;
+}
+
+void
+comm_point_tcp_handle_callback(int fd, short event, void* arg)
+{
+ struct comm_point* c = (struct comm_point*)arg;
+ log_assert(c->type == comm_tcp);
+ comm_base_now(c->ev->base);
+
+ if(event&EV_READ) {
+ if(!comm_point_tcp_handle_read(fd, c, 0)) {
+ reclaim_tcp_handler(c);
+ if(!c->tcp_do_close) {
+ fptr_ok(fptr_whitelist_comm_point(
+ c->callback));
+ (void)(*c->callback)(c, c->cb_arg,
+ NETEVENT_CLOSED, NULL);
+ }
+ }
+ return;
+ }
+ if(event&EV_WRITE) {
+ if(!comm_point_tcp_handle_write(fd, c)) {
+ reclaim_tcp_handler(c);
+ if(!c->tcp_do_close) {
+ fptr_ok(fptr_whitelist_comm_point(
+ c->callback));
+ (void)(*c->callback)(c, c->cb_arg,
+ NETEVENT_CLOSED, NULL);
+ }
+ }
+ return;
+ }
+ if(event&EV_TIMEOUT) {
+ verbose(VERB_QUERY, "tcp took too long, dropped");
+ reclaim_tcp_handler(c);
+ if(!c->tcp_do_close) {
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ (void)(*c->callback)(c, c->cb_arg,
+ NETEVENT_TIMEOUT, NULL);
+ }
+ return;
+ }
+ log_err("Ignored event %d for tcphdl.", event);
+}
+
+void comm_point_local_handle_callback(int fd, short event, void* arg)
+{
+ struct comm_point* c = (struct comm_point*)arg;
+ log_assert(c->type == comm_local);
+ comm_base_now(c->ev->base);
+
+ if(event&EV_READ) {
+ if(!comm_point_tcp_handle_read(fd, c, 1)) {
+ fptr_ok(fptr_whitelist_comm_point(c->callback));
+ (void)(*c->callback)(c, c->cb_arg, NETEVENT_CLOSED,
+ NULL);
+ }
+ return;
+ }
+ log_err("Ignored event %d for localhdl.", event);
+}
+
+void comm_point_raw_handle_callback(int ATTR_UNUSED(fd),
+ short event, void* arg)
+{
+ struct comm_point* c = (struct comm_point*)arg;
+ int err = NETEVENT_NOERROR;
+ log_assert(c->type == comm_raw);
+ comm_base_now(c->ev->base);
+
+ if(event&EV_TIMEOUT)
+ err = NETEVENT_TIMEOUT;
+ fptr_ok(fptr_whitelist_comm_point_raw(c->callback));
+ (void)(*c->callback)(c, c->cb_arg, err, NULL);
+}
+
+struct comm_point*
+comm_point_create_udp(struct comm_base *base, int fd, sldns_buffer* buffer,
+ comm_point_callback_t* callback, void* callback_arg)
+{
+ struct comm_point* c = (struct comm_point*)calloc(1,
+ sizeof(struct comm_point));
+ short evbits;
+ if(!c)
+ return NULL;
+ c->ev = (struct internal_event*)calloc(1,
+ sizeof(struct internal_event));
+ if(!c->ev) {
+ free(c);
+ return NULL;
+ }
+ c->ev->base = base;
+ c->fd = fd;
+ c->buffer = buffer;
+ c->timeout = NULL;
+ c->tcp_is_reading = 0;
+ c->tcp_byte_count = 0;
+ c->tcp_parent = NULL;
+ c->max_tcp_count = 0;
+ c->tcp_handlers = NULL;
+ c->tcp_free = NULL;
+ c->type = comm_udp;
+ c->tcp_do_close = 0;
+ c->do_not_close = 0;
+ c->tcp_do_toggle_rw = 0;
+ c->tcp_check_nb_connect = 0;
+ c->inuse = 0;
+ c->callback = callback;
+ c->cb_arg = callback_arg;
+ evbits = EV_READ | EV_PERSIST;
+ /* libevent stuff */
+ event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_callback, c);
+ if(event_base_set(base->eb->base, &c->ev->ev) != 0) {
+ log_err("could not baseset udp event");
+ comm_point_delete(c);
+ return NULL;
+ }
+ if(fd!=-1 && event_add(&c->ev->ev, c->timeout) != 0 ) {
+ log_err("could not add udp event");
+ comm_point_delete(c);
+ return NULL;
+ }
+ return c;
+}
+
+struct comm_point*
+comm_point_create_udp_ancil(struct comm_base *base, int fd,
+ sldns_buffer* buffer,
+ comm_point_callback_t* callback, void* callback_arg)
+{
+ struct comm_point* c = (struct comm_point*)calloc(1,
+ sizeof(struct comm_point));
+ short evbits;
+ if(!c)
+ return NULL;
+ c->ev = (struct internal_event*)calloc(1,
+ sizeof(struct internal_event));
+ if(!c->ev) {
+ free(c);
+ return NULL;
+ }
+ c->ev->base = base;
+ c->fd = fd;
+ c->buffer = buffer;
+ c->timeout = NULL;
+ c->tcp_is_reading = 0;
+ c->tcp_byte_count = 0;
+ c->tcp_parent = NULL;
+ c->max_tcp_count = 0;
+ c->tcp_handlers = NULL;
+ c->tcp_free = NULL;
+ c->type = comm_udp;
+ c->tcp_do_close = 0;
+ c->do_not_close = 0;
+ c->inuse = 0;
+ c->tcp_do_toggle_rw = 0;
+ c->tcp_check_nb_connect = 0;
+ c->callback = callback;
+ c->cb_arg = callback_arg;
+ evbits = EV_READ | EV_PERSIST;
+ /* libevent stuff */
+ event_set(&c->ev->ev, c->fd, evbits, comm_point_udp_ancil_callback, c);
+ if(event_base_set(base->eb->base, &c->ev->ev) != 0) {
+ log_err("could not baseset udp event");
+ comm_point_delete(c);
+ return NULL;
+ }
+ if(fd!=-1 && event_add(&c->ev->ev, c->timeout) != 0 ) {
+ log_err("could not add udp event");
+ comm_point_delete(c);
+ return NULL;
+ }
+ return c;
+}
+
+static struct comm_point*
+comm_point_create_tcp_handler(struct comm_base *base,
+ struct comm_point* parent, size_t bufsize,
+ comm_point_callback_t* callback, void* callback_arg)
+{
+ struct comm_point* c = (struct comm_point*)calloc(1,
+ sizeof(struct comm_point));
+ short evbits;
+ if(!c)
+ return NULL;
+ c->ev = (struct internal_event*)calloc(1,
+ sizeof(struct internal_event));
+ if(!c->ev) {
+ free(c);
+ return NULL;
+ }
+ c->ev->base = base;
+ c->fd = -1;
+ c->buffer = sldns_buffer_new(bufsize);
+ if(!c->buffer) {
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ c->timeout = (struct timeval*)malloc(sizeof(struct timeval));
+ if(!c->timeout) {
+ sldns_buffer_free(c->buffer);
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ c->tcp_is_reading = 0;
+ c->tcp_byte_count = 0;
+ c->tcp_parent = parent;
+ c->max_tcp_count = 0;
+ c->tcp_handlers = NULL;
+ c->tcp_free = NULL;
+ c->type = comm_tcp;
+ c->tcp_do_close = 0;
+ c->do_not_close = 0;
+ c->tcp_do_toggle_rw = 1;
+ c->tcp_check_nb_connect = 0;
+ c->repinfo.c = c;
+ c->callback = callback;
+ c->cb_arg = callback_arg;
+ /* add to parent free list */
+ c->tcp_free = parent->tcp_free;
+ parent->tcp_free = c;
+ /* libevent stuff */
+ evbits = EV_PERSIST | EV_READ | EV_TIMEOUT;
+ event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c);
+ if(event_base_set(base->eb->base, &c->ev->ev) != 0)
+ {
+ log_err("could not basetset tcphdl event");
+ parent->tcp_free = c->tcp_free;
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ return c;
+}
+
+struct comm_point*
+comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize,
+ comm_point_callback_t* callback, void* callback_arg)
+{
+ struct comm_point* c = (struct comm_point*)calloc(1,
+ sizeof(struct comm_point));
+ short evbits;
+ int i;
+ /* first allocate the TCP accept listener */
+ if(!c)
+ return NULL;
+ c->ev = (struct internal_event*)calloc(1,
+ sizeof(struct internal_event));
+ if(!c->ev) {
+ free(c);
+ return NULL;
+ }
+ c->ev->base = base;
+ c->fd = fd;
+ c->buffer = NULL;
+ c->timeout = NULL;
+ c->tcp_is_reading = 0;
+ c->tcp_byte_count = 0;
+ c->tcp_parent = NULL;
+ c->max_tcp_count = num;
+ c->tcp_handlers = (struct comm_point**)calloc((size_t)num,
+ sizeof(struct comm_point*));
+ if(!c->tcp_handlers) {
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ c->tcp_free = NULL;
+ c->type = comm_tcp_accept;
+ c->tcp_do_close = 0;
+ c->do_not_close = 0;
+ c->tcp_do_toggle_rw = 0;
+ c->tcp_check_nb_connect = 0;
+ c->callback = NULL;
+ c->cb_arg = NULL;
+ evbits = EV_READ | EV_PERSIST;
+ /* libevent stuff */
+ event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_accept_callback, c);
+ if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
+ event_add(&c->ev->ev, c->timeout) != 0 )
+ {
+ log_err("could not add tcpacc event");
+ comm_point_delete(c);
+ return NULL;
+ }
+
+ /* now prealloc the tcp handlers */
+ for(i=0; i<num; i++) {
+ c->tcp_handlers[i] = comm_point_create_tcp_handler(base,
+ c, bufsize, callback, callback_arg);
+ if(!c->tcp_handlers[i]) {
+ comm_point_delete(c);
+ return NULL;
+ }
+ }
+
+ return c;
+}
+
+struct comm_point*
+comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
+ comm_point_callback_t* callback, void* callback_arg)
+{
+ struct comm_point* c = (struct comm_point*)calloc(1,
+ sizeof(struct comm_point));
+ short evbits;
+ if(!c)
+ return NULL;
+ c->ev = (struct internal_event*)calloc(1,
+ sizeof(struct internal_event));
+ if(!c->ev) {
+ free(c);
+ return NULL;
+ }
+ c->ev->base = base;
+ c->fd = -1;
+ c->buffer = sldns_buffer_new(bufsize);
+ if(!c->buffer) {
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ c->timeout = NULL;
+ c->tcp_is_reading = 0;
+ c->tcp_byte_count = 0;
+ c->tcp_parent = NULL;
+ c->max_tcp_count = 0;
+ c->tcp_handlers = NULL;
+ c->tcp_free = NULL;
+ c->type = comm_tcp;
+ c->tcp_do_close = 0;
+ c->do_not_close = 0;
+ c->tcp_do_toggle_rw = 1;
+ c->tcp_check_nb_connect = 1;
+ c->repinfo.c = c;
+ c->callback = callback;
+ c->cb_arg = callback_arg;
+ evbits = EV_PERSIST | EV_WRITE;
+ event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c);
+ if(event_base_set(base->eb->base, &c->ev->ev) != 0)
+ {
+ log_err("could not basetset tcpout event");
+ sldns_buffer_free(c->buffer);
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+
+ return c;
+}
+
+struct comm_point*
+comm_point_create_local(struct comm_base *base, int fd, size_t bufsize,
+ comm_point_callback_t* callback, void* callback_arg)
+{
+ struct comm_point* c = (struct comm_point*)calloc(1,
+ sizeof(struct comm_point));
+ short evbits;
+ if(!c)
+ return NULL;
+ c->ev = (struct internal_event*)calloc(1,
+ sizeof(struct internal_event));
+ if(!c->ev) {
+ free(c);
+ return NULL;
+ }
+ c->ev->base = base;
+ c->fd = fd;
+ c->buffer = sldns_buffer_new(bufsize);
+ if(!c->buffer) {
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ c->timeout = NULL;
+ c->tcp_is_reading = 1;
+ c->tcp_byte_count = 0;
+ c->tcp_parent = NULL;
+ c->max_tcp_count = 0;
+ c->tcp_handlers = NULL;
+ c->tcp_free = NULL;
+ c->type = comm_local;
+ c->tcp_do_close = 0;
+ c->do_not_close = 1;
+ c->tcp_do_toggle_rw = 0;
+ c->tcp_check_nb_connect = 0;
+ c->callback = callback;
+ c->cb_arg = callback_arg;
+ /* libevent stuff */
+ evbits = EV_PERSIST | EV_READ;
+ event_set(&c->ev->ev, c->fd, evbits, comm_point_local_handle_callback,
+ c);
+ if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
+ event_add(&c->ev->ev, c->timeout) != 0 )
+ {
+ log_err("could not add localhdl event");
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ return c;
+}
+
+struct comm_point*
+comm_point_create_raw(struct comm_base* base, int fd, int writing,
+ comm_point_callback_t* callback, void* callback_arg)
+{
+ struct comm_point* c = (struct comm_point*)calloc(1,
+ sizeof(struct comm_point));
+ short evbits;
+ if(!c)
+ return NULL;
+ c->ev = (struct internal_event*)calloc(1,
+ sizeof(struct internal_event));
+ if(!c->ev) {
+ free(c);
+ return NULL;
+ }
+ c->ev->base = base;
+ c->fd = fd;
+ c->buffer = NULL;
+ c->timeout = NULL;
+ c->tcp_is_reading = 0;
+ c->tcp_byte_count = 0;
+ c->tcp_parent = NULL;
+ c->max_tcp_count = 0;
+ c->tcp_handlers = NULL;
+ c->tcp_free = NULL;
+ c->type = comm_raw;
+ c->tcp_do_close = 0;
+ c->do_not_close = 1;
+ c->tcp_do_toggle_rw = 0;
+ c->tcp_check_nb_connect = 0;
+ c->callback = callback;
+ c->cb_arg = callback_arg;
+ /* libevent stuff */
+ if(writing)
+ evbits = EV_PERSIST | EV_WRITE;
+ else evbits = EV_PERSIST | EV_READ;
+ event_set(&c->ev->ev, c->fd, evbits, comm_point_raw_handle_callback,
+ c);
+ if(event_base_set(base->eb->base, &c->ev->ev) != 0 ||
+ event_add(&c->ev->ev, c->timeout) != 0 )
+ {
+ log_err("could not add rawhdl event");
+ free(c->ev);
+ free(c);
+ return NULL;
+ }
+ return c;
+}
+
+void
+comm_point_close(struct comm_point* c)
+{
+ if(!c)
+ return;
+ if(c->fd != -1)
+ if(event_del(&c->ev->ev) != 0) {
+ log_err("could not event_del on close");
+ }
+ /* close fd after removing from event lists, or epoll.. is messed up */
+ if(c->fd != -1 && !c->do_not_close) {
+ verbose(VERB_ALGO, "close fd %d", c->fd);
+#ifndef USE_WINSOCK
+ close(c->fd);
+#else
+ closesocket(c->fd);
+#endif
+ }
+ c->fd = -1;
+}
+
+void
+comm_point_delete(struct comm_point* c)
+{
+ if(!c)
+ return;
+ if(c->type == comm_tcp && c->ssl) {
+#ifdef HAVE_SSL
+ SSL_shutdown(c->ssl);
+ SSL_free(c->ssl);
+#endif
+ }
+ comm_point_close(c);
+ if(c->tcp_handlers) {
+ int i;
+ for(i=0; i<c->max_tcp_count; i++)
+ comm_point_delete(c->tcp_handlers[i]);
+ free(c->tcp_handlers);
+ }
+ free(c->timeout);
+ if(c->type == comm_tcp || c->type == comm_local)
+ sldns_buffer_free(c->buffer);
+ free(c->ev);
+ free(c);
+}
+
+void
+comm_point_send_reply(struct comm_reply *repinfo)
+{
+ log_assert(repinfo && repinfo->c);
+ if(repinfo->c->type == comm_udp) {
+ if(repinfo->srctype)
+ comm_point_send_udp_msg_if(repinfo->c,
+ repinfo->c->buffer, (struct sockaddr*)&repinfo->addr,
+ repinfo->addrlen, repinfo);
+ else
+ comm_point_send_udp_msg(repinfo->c, repinfo->c->buffer,
+ (struct sockaddr*)&repinfo->addr, repinfo->addrlen);
+#ifdef USE_DNSTAP
+ if(repinfo->c->dtenv != NULL &&
+ repinfo->c->dtenv->log_client_response_messages)
+ dt_msg_send_client_response(repinfo->c->dtenv,
+ &repinfo->addr, repinfo->c->type, repinfo->c->buffer);
+#endif
+ } else {
+#ifdef USE_DNSTAP
+ if(repinfo->c->tcp_parent->dtenv != NULL &&
+ repinfo->c->tcp_parent->dtenv->log_client_response_messages)
+ dt_msg_send_client_response(repinfo->c->tcp_parent->dtenv,
+ &repinfo->addr, repinfo->c->type, repinfo->c->buffer);
+#endif
+ comm_point_start_listening(repinfo->c, -1, TCP_QUERY_TIMEOUT);
+ }
+}
+
+void
+comm_point_drop_reply(struct comm_reply* repinfo)
+{
+ if(!repinfo)
+ return;
+ log_assert(repinfo && repinfo->c);
+ log_assert(repinfo->c->type != comm_tcp_accept);
+ if(repinfo->c->type == comm_udp)
+ return;
+ reclaim_tcp_handler(repinfo->c);
+}
+
+void
+comm_point_stop_listening(struct comm_point* c)
+{
+ verbose(VERB_ALGO, "comm point stop listening %d", c->fd);
+ if(event_del(&c->ev->ev) != 0) {
+ log_err("event_del error to stoplisten");
+ }
+}
+
+void
+comm_point_start_listening(struct comm_point* c, int newfd, int sec)
+{
+ verbose(VERB_ALGO, "comm point start listening %d",
+ c->fd==-1?newfd:c->fd);
+ if(c->type == comm_tcp_accept && !c->tcp_free) {
+ /* no use to start listening no free slots. */
+ return;
+ }
+ if(sec != -1 && sec != 0) {
+ if(!c->timeout) {
+ c->timeout = (struct timeval*)malloc(sizeof(
+ struct timeval));
+ if(!c->timeout) {
+ log_err("cpsl: malloc failed. No net read.");
+ return;
+ }
+ }
+ c->ev->ev.ev_events |= EV_TIMEOUT;
+#ifndef S_SPLINT_S /* splint fails on struct timeval. */
+ c->timeout->tv_sec = sec;
+ c->timeout->tv_usec = 0;
+#endif /* S_SPLINT_S */
+ }
+ if(c->type == comm_tcp) {
+ c->ev->ev.ev_events &= ~(EV_READ|EV_WRITE);
+ if(c->tcp_is_reading)
+ c->ev->ev.ev_events |= EV_READ;
+ else c->ev->ev.ev_events |= EV_WRITE;
+ }
+ if(newfd != -1) {
+ if(c->fd != -1) {
+#ifndef USE_WINSOCK
+ close(c->fd);
+#else
+ closesocket(c->fd);
+#endif
+ }
+ c->fd = newfd;
+ c->ev->ev.ev_fd = c->fd;
+ }
+ if(event_add(&c->ev->ev, sec==0?NULL:c->timeout) != 0) {
+ log_err("event_add failed. in cpsl.");
+ }
+}
+
+void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr)
+{
+ verbose(VERB_ALGO, "comm point listen_for_rw %d %d", c->fd, wr);
+ if(event_del(&c->ev->ev) != 0) {
+ log_err("event_del error to cplf");
+ }
+ c->ev->ev.ev_events &= ~(EV_READ|EV_WRITE);
+ if(rd) c->ev->ev.ev_events |= EV_READ;
+ if(wr) c->ev->ev.ev_events |= EV_WRITE;
+ if(event_add(&c->ev->ev, c->timeout) != 0) {
+ log_err("event_add failed. in cplf.");
+ }
+}
+
+size_t comm_point_get_mem(struct comm_point* c)
+{
+ size_t s;
+ if(!c)
+ return 0;
+ s = sizeof(*c) + sizeof(*c->ev);
+ if(c->timeout)
+ s += sizeof(*c->timeout);
+ if(c->type == comm_tcp || c->type == comm_local)
+ s += sizeof(*c->buffer) + sldns_buffer_capacity(c->buffer);
+ if(c->type == comm_tcp_accept) {
+ int i;
+ for(i=0; i<c->max_tcp_count; i++)
+ s += comm_point_get_mem(c->tcp_handlers[i]);
+ }
+ return s;
+}
+
+struct comm_timer*
+comm_timer_create(struct comm_base* base, void (*cb)(void*), void* cb_arg)
+{
+ struct comm_timer *tm = (struct comm_timer*)calloc(1,
+ sizeof(struct comm_timer));
+ if(!tm)
+ return NULL;
+ tm->ev_timer = (struct internal_timer*)calloc(1,
+ sizeof(struct internal_timer));
+ if(!tm->ev_timer) {
+ log_err("malloc failed");
+ free(tm);
+ return NULL;
+ }
+ tm->ev_timer->base = base;
+ tm->callback = cb;
+ tm->cb_arg = cb_arg;
+ event_set(&tm->ev_timer->ev, -1, EV_TIMEOUT,
+ comm_timer_callback, tm);
+ if(event_base_set(base->eb->base, &tm->ev_timer->ev) != 0) {
+ log_err("timer_create: event_base_set failed.");
+ free(tm->ev_timer);
+ free(tm);
+ return NULL;
+ }
+ return tm;
+}
+
+void
+comm_timer_disable(struct comm_timer* timer)
+{
+ if(!timer)
+ return;
+ evtimer_del(&timer->ev_timer->ev);
+ timer->ev_timer->enabled = 0;
+}
+
+void
+comm_timer_set(struct comm_timer* timer, struct timeval* tv)
+{
+ log_assert(tv);
+ if(timer->ev_timer->enabled)
+ comm_timer_disable(timer);
+ event_set(&timer->ev_timer->ev, -1, EV_TIMEOUT,
+ comm_timer_callback, timer);
+ if(event_base_set(timer->ev_timer->base->eb->base,
+ &timer->ev_timer->ev) != 0)
+ log_err("comm_timer_set: set_base failed.");
+ if(evtimer_add(&timer->ev_timer->ev, tv) != 0)
+ log_err("comm_timer_set: evtimer_add failed.");
+ timer->ev_timer->enabled = 1;
+}
+
+void
+comm_timer_delete(struct comm_timer* timer)
+{
+ if(!timer)
+ return;
+ comm_timer_disable(timer);
+ free(timer->ev_timer);
+ free(timer);
+}
+
+void
+comm_timer_callback(int ATTR_UNUSED(fd), short event, void* arg)
+{
+ struct comm_timer* tm = (struct comm_timer*)arg;
+ if(!(event&EV_TIMEOUT))
+ return;
+ comm_base_now(tm->ev_timer->base);
+ tm->ev_timer->enabled = 0;
+ fptr_ok(fptr_whitelist_comm_timer(tm->callback));
+ (*tm->callback)(tm->cb_arg);
+}
+
+int
+comm_timer_is_set(struct comm_timer* timer)
+{
+ return (int)timer->ev_timer->enabled;
+}
+
+size_t
+comm_timer_get_mem(struct comm_timer* timer)
+{
+ return sizeof(*timer) + sizeof(struct internal_timer);
+}
+
+struct comm_signal*
+comm_signal_create(struct comm_base* base,
+ void (*callback)(int, void*), void* cb_arg)
+{
+ struct comm_signal* com = (struct comm_signal*)malloc(
+ sizeof(struct comm_signal));
+ if(!com) {
+ log_err("malloc failed");
+ return NULL;
+ }
+ com->base = base;
+ com->callback = callback;
+ com->cb_arg = cb_arg;
+ com->ev_signal = NULL;
+ return com;
+}
+
+void
+comm_signal_callback(int sig, short event, void* arg)
+{
+ struct comm_signal* comsig = (struct comm_signal*)arg;
+ if(!(event & EV_SIGNAL))
+ return;
+ comm_base_now(comsig->base);
+ fptr_ok(fptr_whitelist_comm_signal(comsig->callback));
+ (*comsig->callback)(sig, comsig->cb_arg);
+}
+
+int
+comm_signal_bind(struct comm_signal* comsig, int sig)
+{
+ struct internal_signal* entry = (struct internal_signal*)calloc(1,
+ sizeof(struct internal_signal));
+ if(!entry) {
+ log_err("malloc failed");
+ return 0;
+ }
+ log_assert(comsig);
+ /* add signal event */
+ signal_set(&entry->ev, sig, comm_signal_callback, comsig);
+ if(event_base_set(comsig->base->eb->base, &entry->ev) != 0) {
+ log_err("Could not set signal base");
+ free(entry);
+ return 0;
+ }
+ if(signal_add(&entry->ev, NULL) != 0) {
+ log_err("Could not add signal handler");
+ free(entry);
+ return 0;
+ }
+ /* link into list */
+ entry->next = comsig->ev_signal;
+ comsig->ev_signal = entry;
+ return 1;
+}
+
+void
+comm_signal_delete(struct comm_signal* comsig)
+{
+ struct internal_signal* p, *np;
+ if(!comsig)
+ return;
+ p=comsig->ev_signal;
+ while(p) {
+ np = p->next;
+ signal_del(&p->ev);
+ free(p);
+ p = np;
+ }
+ free(comsig);
+}
diff --git a/external/unbound/util/netevent.h b/external/unbound/util/netevent.h
new file mode 100644
index 000000000..37322ab93
--- /dev/null
+++ b/external/unbound/util/netevent.h
@@ -0,0 +1,703 @@
+/*
+ * util/netevent.h - event notification
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 event notification functions.
+ *
+ * There are three types of communication points
+ * o UDP socket - perthread buffer.
+ * o TCP-accept socket - array of TCP-sockets, socketcount.
+ * o TCP socket - own buffer, parent-TCPaccept, read/write state,
+ * number of bytes read/written, timeout.
+ *
+ * There are sockets aimed towards our clients and towards the internet.
+ * o frontside - aimed towards our clients, queries come in, answers back.
+ * o behind - aimed towards internet, to the authoritative DNS servers.
+ *
+ * Several event types are available:
+ * o comm_base - for thread safety of the comm points, one per thread.
+ * o comm_point - udp and tcp networking, with callbacks.
+ * o comm_timer - a timeout with callback.
+ * o comm_signal - callbacks when signal is caught.
+ * o comm_reply - holds reply info during networking callback.
+ *
+ */
+
+#ifndef NET_EVENT_H
+#define NET_EVENT_H
+
+struct sldns_buffer;
+struct comm_point;
+struct comm_reply;
+struct event_base;
+
+/* internal event notification data storage structure. */
+struct internal_event;
+struct internal_base;
+struct internal_timer;
+
+/** callback from communication point function type */
+typedef int comm_point_callback_t(struct comm_point*, void*, int,
+ struct comm_reply*);
+
+/** to pass no_error to callback function */
+#define NETEVENT_NOERROR 0
+/** to pass closed connection to callback function */
+#define NETEVENT_CLOSED -1
+/** to pass timeout happened to callback function */
+#define NETEVENT_TIMEOUT -2
+/** to pass fallback from capsforID to callback function; 0x20 failed */
+#define NETEVENT_CAPSFAIL -3
+
+/** timeout to slow accept calls when not possible, in msec. */
+#define NETEVENT_SLOW_ACCEPT_TIME 2000
+
+/**
+ * A communication point dispatcher. Thread specific.
+ */
+struct comm_base {
+ /** behind the scenes structure. with say libevent info. alloced */
+ struct internal_base* eb;
+ /** callback to stop listening on accept sockets,
+ * performed when accept() will not function properly */
+ void (*stop_accept)(void*);
+ /** callback to start listening on accept sockets, performed
+ * after stop_accept() then a timeout has passed. */
+ void (*start_accept)(void*);
+ /** user argument for stop_accept and start_accept functions */
+ void* cb_arg;
+};
+
+/**
+ * Reply information for a communication point.
+ */
+struct comm_reply {
+ /** the comm_point with fd to send reply on to. */
+ struct comm_point* c;
+ /** the address (for UDP based communication) */
+ struct sockaddr_storage addr;
+ /** length of address */
+ socklen_t addrlen;
+ /** return type 0 (none), 4(IP4), 6(IP6) */
+ int srctype;
+ /** the return source interface data */
+ union {
+#ifdef IPV6_PKTINFO
+ struct in6_pktinfo v6info;
+#endif
+#ifdef IP_PKTINFO
+ struct in_pktinfo v4info;
+#elif defined(IP_RECVDSTADDR)
+ struct in_addr v4addr;
+#endif
+ }
+ /** variable with return source data */
+ pktinfo;
+};
+
+/**
+ * Communication point to the network
+ * These behaviours can be accomplished by setting the flags
+ * and passing return values from the callback.
+ * udp frontside: called after readdone. sendafter.
+ * tcp frontside: called readdone, sendafter. close.
+ * udp behind: called after readdone. No send after.
+ * tcp behind: write done, read done, then called. No send after.
+ */
+struct comm_point {
+ /** behind the scenes structure, with say libevent info. alloced. */
+ struct internal_event* ev;
+
+ /** file descriptor for communication point */
+ int fd;
+
+ /** timeout (NULL if it does not). Malloced. */
+ struct timeval* timeout;
+
+ /** buffer pointer. Either to perthread, or own buffer or NULL */
+ struct sldns_buffer* buffer;
+
+ /* -------- TCP Handler -------- */
+ /** Read/Write state for TCP */
+ int tcp_is_reading;
+ /** The current read/write count for TCP */
+ size_t tcp_byte_count;
+ /** parent communication point (for TCP sockets) */
+ struct comm_point* tcp_parent;
+ /** sockaddr from peer, for TCP handlers */
+ struct comm_reply repinfo;
+
+ /* -------- TCP Accept -------- */
+ /** the number of TCP handlers for this tcp-accept socket */
+ int max_tcp_count;
+ /** malloced array of tcp handlers for a tcp-accept,
+ of size max_tcp_count. */
+ struct comm_point** tcp_handlers;
+ /** linked list of free tcp_handlers to use for new queries.
+ For tcp_accept the first entry, for tcp_handlers the next one. */
+ struct comm_point* tcp_free;
+
+ /* -------- SSL TCP DNS ------- */
+ /** the SSL object with rw bio (owned) or for commaccept ctx ref */
+ void* ssl;
+ /** handshake state for init and renegotiate */
+ enum {
+ /** no handshake, it has been done */
+ comm_ssl_shake_none = 0,
+ /** ssl initial handshake wants to read */
+ comm_ssl_shake_read,
+ /** ssl initial handshake wants to write */
+ comm_ssl_shake_write,
+ /** ssl_write wants to read */
+ comm_ssl_shake_hs_read,
+ /** ssl_read wants to write */
+ comm_ssl_shake_hs_write
+ } ssl_shake_state;
+
+ /* -------- dnstap ------- */
+ /** the dnstap environment */
+ struct dt_env* dtenv;
+
+ /** is this a UDP, TCP-accept or TCP socket. */
+ enum comm_point_type {
+ /** UDP socket - handle datagrams. */
+ comm_udp,
+ /** TCP accept socket - only creates handlers if readable. */
+ comm_tcp_accept,
+ /** TCP handler socket - handle byteperbyte readwrite. */
+ comm_tcp,
+ /** AF_UNIX socket - for internal commands. */
+ comm_local,
+ /** raw - not DNS format - for pipe readers and writers */
+ comm_raw
+ }
+ /** variable with type of socket, UDP,TCP-accept,TCP,pipe */
+ type;
+
+ /* ---------- Behaviour ----------- */
+ /** if set the connection is NOT closed on delete. */
+ int do_not_close;
+
+ /** if set, the connection is closed on error, on timeout,
+ and after read/write completes. No callback is done. */
+ int tcp_do_close;
+
+ /** if set, read/write completes:
+ read/write state of tcp is toggled.
+ buffer reset/bytecount reset.
+ this flag cleared.
+ So that when that is done the callback is called. */
+ int tcp_do_toggle_rw;
+
+ /** if set, checks for pending error from nonblocking connect() call.*/
+ int tcp_check_nb_connect;
+
+ /** number of queries outstanding on this socket, used by
+ * outside network for udp ports */
+ int inuse;
+
+ /** callback when done.
+ tcp_accept does not get called back, is NULL then.
+ If a timeout happens, callback with timeout=1 is called.
+ If an error happens, callback is called with error set
+ nonzero. If not NETEVENT_NOERROR, it is an errno value.
+ If the connection is closed (by remote end) then the
+ callback is called with error set to NETEVENT_CLOSED=-1.
+ If a timeout happens on the connection, the error is set to
+ NETEVENT_TIMEOUT=-2.
+ The reply_info can be copied if the reply needs to happen at a
+ later time. It consists of a struct with commpoint and address.
+ It can be passed to a msg send routine some time later.
+ Note the reply information is temporary and must be copied.
+ NULL is passed for_reply info, in cases where error happened.
+
+ declare as:
+ int my_callback(struct comm_point* c, void* my_arg, int error,
+ struct comm_reply *reply_info);
+
+ if the routine returns 0, nothing is done.
+ Notzero, the buffer will be sent back to client.
+ For UDP this is done without changing the commpoint.
+ In TCP it sets write state.
+ */
+ comm_point_callback_t* callback;
+ /** argument to pass to callback. */
+ void *cb_arg;
+};
+
+/**
+ * Structure only for making timeout events.
+ */
+struct comm_timer {
+ /** the internal event stuff */
+ struct internal_timer* ev_timer;
+
+ /** callback function, takes user arg only */
+ void (*callback)(void*);
+
+ /** callback user argument */
+ void* cb_arg;
+};
+
+/**
+ * Structure only for signal events.
+ */
+struct comm_signal {
+ /** the communication base */
+ struct comm_base* base;
+
+ /** the internal event stuff */
+ struct internal_signal* ev_signal;
+
+ /** callback function, takes signal number and user arg */
+ void (*callback)(int, void*);
+
+ /** callback user argument */
+ void* cb_arg;
+};
+
+/**
+ * Create a new comm base.
+ * @param sigs: if true it attempts to create a default loop for
+ * signal handling.
+ * @return: the new comm base. NULL on error.
+ */
+struct comm_base* comm_base_create(int sigs);
+
+/**
+ * Create comm base that uses the given event_base (underlying event
+ * mechanism pointer).
+ * @param base: underlying lib event base.
+ * @return: the new comm base. NULL on error.
+ */
+struct comm_base* comm_base_create_event(struct event_base* base);
+
+/**
+ * Delete comm base structure but not the underlying lib event base.
+ * All comm points must have been deleted.
+ * @param b: the base to delete.
+ */
+void comm_base_delete_no_base(struct comm_base* b);
+
+/**
+ * Destroy a comm base.
+ * All comm points must have been deleted.
+ * @param b: the base to delete.
+ */
+void comm_base_delete(struct comm_base* b);
+
+/**
+ * Obtain two pointers. The pointers never change (until base_delete()).
+ * The pointers point to time values that are updated regularly.
+ * @param b: the communication base that will update the time values.
+ * @param tt: pointer to time in seconds is returned.
+ * @param tv: pointer to time in microseconds is returned.
+ */
+void comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv);
+
+/**
+ * Dispatch the comm base events.
+ * @param b: the communication to perform.
+ */
+void comm_base_dispatch(struct comm_base* b);
+
+/**
+ * Exit from dispatch loop.
+ * @param b: the communication base that is in dispatch().
+ */
+void comm_base_exit(struct comm_base* b);
+
+/**
+ * Set the slow_accept mode handlers. You can not provide these if you do
+ * not perform accept() calls.
+ * @param b: comm base
+ * @param stop_accept: function that stops listening to accept fds.
+ * @param start_accept: function that resumes listening to accept fds.
+ * @param arg: callback arg to pass to the functions.
+ */
+void comm_base_set_slow_accept_handlers(struct comm_base* b,
+ void (*stop_accept)(void*), void (*start_accept)(void*), void* arg);
+
+/**
+ * Access internal data structure (for util/tube.c on windows)
+ * @param b: comm base
+ * @return event_base. Could be libevent, or internal event handler.
+ */
+struct event_base* comm_base_internal(struct comm_base* b);
+
+/**
+ * Create an UDP comm point. Calls malloc.
+ * setups the structure with the parameters you provide.
+ * @param base: in which base to alloc the commpoint.
+ * @param fd : file descriptor of open UDP socket.
+ * @param buffer: shared buffer by UDP sockets from this thread.
+ * @param callback: callback function pointer.
+ * @param callback_arg: will be passed to your callback function.
+ * @return: returns the allocated communication point. NULL on error.
+ * Sets timeout to NULL. Turns off TCP options.
+ */
+struct comm_point* comm_point_create_udp(struct comm_base* base,
+ int fd, struct sldns_buffer* buffer,
+ comm_point_callback_t* callback, void* callback_arg);
+
+/**
+ * Create an UDP with ancillary data comm point. Calls malloc.
+ * Uses recvmsg instead of recv to get udp message.
+ * setups the structure with the parameters you provide.
+ * @param base: in which base to alloc the commpoint.
+ * @param fd : file descriptor of open UDP socket.
+ * @param buffer: shared buffer by UDP sockets from this thread.
+ * @param callback: callback function pointer.
+ * @param callback_arg: will be passed to your callback function.
+ * @return: returns the allocated communication point. NULL on error.
+ * Sets timeout to NULL. Turns off TCP options.
+ */
+struct comm_point* comm_point_create_udp_ancil(struct comm_base* base,
+ int fd, struct sldns_buffer* buffer,
+ comm_point_callback_t* callback, void* callback_arg);
+
+/**
+ * Create a TCP listener comm point. Calls malloc.
+ * Setups the structure with the parameters you provide.
+ * Also Creates TCP Handlers, pre allocated for you.
+ * Uses the parameters you provide.
+ * @param base: in which base to alloc the commpoint.
+ * @param fd: file descriptor of open TCP socket set to listen nonblocking.
+ * @param num: becomes max_tcp_count, the routine allocates that
+ * many tcp handler commpoints.
+ * @param bufsize: size of buffer to create for handlers.
+ * @param callback: callback function pointer for TCP handlers.
+ * @param callback_arg: will be passed to your callback function.
+ * @return: returns the TCP listener commpoint. You can find the
+ * TCP handlers in the array inside the listener commpoint.
+ * returns NULL on error.
+ * Inits timeout to NULL. All handlers are on the free list.
+ */
+struct comm_point* comm_point_create_tcp(struct comm_base* base,
+ int fd, int num, size_t bufsize,
+ comm_point_callback_t* callback, void* callback_arg);
+
+/**
+ * Create an outgoing TCP commpoint. No file descriptor is opened, left at -1.
+ * @param base: in which base to alloc the commpoint.
+ * @param bufsize: size of buffer to create for handlers.
+ * @param callback: callback function pointer for the handler.
+ * @param callback_arg: will be passed to your callback function.
+ * @return: the commpoint or NULL on error.
+ */
+struct comm_point* comm_point_create_tcp_out(struct comm_base* base,
+ size_t bufsize, comm_point_callback_t* callback, void* callback_arg);
+
+/**
+ * Create commpoint to listen to a local domain file descriptor.
+ * @param base: in which base to alloc the commpoint.
+ * @param fd: file descriptor of open AF_UNIX socket set to listen nonblocking.
+ * @param bufsize: size of buffer to create for handlers.
+ * @param callback: callback function pointer for the handler.
+ * @param callback_arg: will be passed to your callback function.
+ * @return: the commpoint or NULL on error.
+ */
+struct comm_point* comm_point_create_local(struct comm_base* base,
+ int fd, size_t bufsize,
+ comm_point_callback_t* callback, void* callback_arg);
+
+/**
+ * Create commpoint to listen to a local domain pipe descriptor.
+ * @param base: in which base to alloc the commpoint.
+ * @param fd: file descriptor.
+ * @param writing: true if you want to listen to writes, false for reads.
+ * @param callback: callback function pointer for the handler.
+ * @param callback_arg: will be passed to your callback function.
+ * @return: the commpoint or NULL on error.
+ */
+struct comm_point* comm_point_create_raw(struct comm_base* base,
+ int fd, int writing,
+ comm_point_callback_t* callback, void* callback_arg);
+
+/**
+ * Close a comm point fd.
+ * @param c: comm point to close.
+ */
+void comm_point_close(struct comm_point* c);
+
+/**
+ * Close and deallocate (free) the comm point. If the comm point is
+ * a tcp-accept point, also its tcp-handler points are deleted.
+ * @param c: comm point to delete.
+ */
+void comm_point_delete(struct comm_point* c);
+
+/**
+ * Send reply. Put message into commpoint buffer.
+ * @param repinfo: The reply info copied from a commpoint callback call.
+ */
+void comm_point_send_reply(struct comm_reply* repinfo);
+
+/**
+ * Drop reply. Cleans up.
+ * @param repinfo: The reply info copied from a commpoint callback call.
+ */
+void comm_point_drop_reply(struct comm_reply* repinfo);
+
+/**
+ * Send an udp message over a commpoint.
+ * @param c: commpoint to send it from.
+ * @param packet: what to send.
+ * @param addr: where to send it to.
+ * @param addrlen: length of addr.
+ * @return: false on a failure.
+ */
+int comm_point_send_udp_msg(struct comm_point* c, struct sldns_buffer* packet,
+ struct sockaddr* addr, socklen_t addrlen);
+
+/**
+ * Stop listening for input on the commpoint. No callbacks will happen.
+ * @param c: commpoint to disable. The fd is not closed.
+ */
+void comm_point_stop_listening(struct comm_point* c);
+
+/**
+ * Start listening again for input on the comm point.
+ * @param c: commpoint to enable again.
+ * @param newfd: new fd, or -1 to leave fd be.
+ * @param sec: timeout in seconds, or -1 for no (change to the) timeout.
+ */
+void comm_point_start_listening(struct comm_point* c, int newfd, int sec);
+
+/**
+ * Stop listening and start listening again for reading or writing.
+ * @param c: commpoint
+ * @param rd: if true, listens for reading.
+ * @param wr: if true, listens for writing.
+ */
+void comm_point_listen_for_rw(struct comm_point* c, int rd, int wr);
+
+/**
+ * Get size of memory used by comm point.
+ * For TCP handlers this includes subhandlers.
+ * For UDP handlers, this does not include the (shared) UDP buffer.
+ * @param c: commpoint.
+ * @return size in bytes.
+ */
+size_t comm_point_get_mem(struct comm_point* c);
+
+/**
+ * create timer. Not active upon creation.
+ * @param base: event handling base.
+ * @param cb: callback function: void myfunc(void* myarg);
+ * @param cb_arg: user callback argument.
+ * @return: the new timer or NULL on error.
+ */
+struct comm_timer* comm_timer_create(struct comm_base* base,
+ void (*cb)(void*), void* cb_arg);
+
+/**
+ * disable timer. Stops callbacks from happening.
+ * @param timer: to disable.
+ */
+void comm_timer_disable(struct comm_timer* timer);
+
+/**
+ * reset timevalue for timer.
+ * @param timer: timer to (re)set.
+ * @param tv: when the timer should activate. if NULL timer is disabled.
+ */
+void comm_timer_set(struct comm_timer* timer, struct timeval* tv);
+
+/**
+ * delete timer.
+ * @param timer: to delete.
+ */
+void comm_timer_delete(struct comm_timer* timer);
+
+/**
+ * see if timeout has been set to a value.
+ * @param timer: the timer to examine.
+ * @return: false if disabled or not set.
+ */
+int comm_timer_is_set(struct comm_timer* timer);
+
+/**
+ * Get size of memory used by comm timer.
+ * @param timer: the timer to examine.
+ * @return size in bytes.
+ */
+size_t comm_timer_get_mem(struct comm_timer* timer);
+
+/**
+ * Create a signal handler. Call signal_bind() later to bind to a signal.
+ * @param base: communication base to use.
+ * @param callback: called when signal is caught.
+ * @param cb_arg: user argument to callback
+ * @return: the signal struct or NULL on error.
+ */
+struct comm_signal* comm_signal_create(struct comm_base* base,
+ void (*callback)(int, void*), void* cb_arg);
+
+/**
+ * Bind signal struct to catch a signal. A signle comm_signal can be bound
+ * to multiple signals, calling comm_signal_bind multiple times.
+ * @param comsig: the communication point, with callback information.
+ * @param sig: signal number.
+ * @return: true on success. false on error.
+ */
+int comm_signal_bind(struct comm_signal* comsig, int sig);
+
+/**
+ * Delete the signal communication point.
+ * @param comsig: to delete.
+ */
+void comm_signal_delete(struct comm_signal* comsig);
+
+/**
+ * perform accept(2) with error checking.
+ * @param c: commpoint with accept fd.
+ * @param addr: remote end returned here.
+ * @param addrlen: length of remote end returned here.
+ * @return new fd, or -1 on error.
+ * if -1, error message has been printed if necessary, simply drop
+ * out of the reading handler.
+ */
+int comm_point_perform_accept(struct comm_point* c,
+ struct sockaddr_storage* addr, socklen_t* addrlen);
+
+/**** internal routines ****/
+
+/**
+ * This routine is published for checks and tests, and is only used internally.
+ * handle libevent callback for udp comm point.
+ * @param fd: file descriptor.
+ * @param event: event bits from libevent:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ * @param arg: the comm_point structure.
+ */
+void comm_point_udp_callback(int fd, short event, void* arg);
+
+/**
+ * This routine is published for checks and tests, and is only used internally.
+ * handle libevent callback for udp ancillary data comm point.
+ * @param fd: file descriptor.
+ * @param event: event bits from libevent:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ * @param arg: the comm_point structure.
+ */
+void comm_point_udp_ancil_callback(int fd, short event, void* arg);
+
+/**
+ * This routine is published for checks and tests, and is only used internally.
+ * handle libevent callback for tcp accept comm point
+ * @param fd: file descriptor.
+ * @param event: event bits from libevent:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ * @param arg: the comm_point structure.
+ */
+void comm_point_tcp_accept_callback(int fd, short event, void* arg);
+
+/**
+ * This routine is published for checks and tests, and is only used internally.
+ * handle libevent callback for tcp data comm point
+ * @param fd: file descriptor.
+ * @param event: event bits from libevent:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ * @param arg: the comm_point structure.
+ */
+void comm_point_tcp_handle_callback(int fd, short event, void* arg);
+
+/**
+ * This routine is published for checks and tests, and is only used internally.
+ * handle libevent callback for timer comm.
+ * @param fd: file descriptor (always -1).
+ * @param event: event bits from libevent:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ * @param arg: the comm_timer structure.
+ */
+void comm_timer_callback(int fd, short event, void* arg);
+
+/**
+ * This routine is published for checks and tests, and is only used internally.
+ * handle libevent callback for signal comm.
+ * @param fd: file descriptor (used for the signal number).
+ * @param event: event bits from libevent:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ * @param arg: the internal commsignal structure.
+ */
+void comm_signal_callback(int fd, short event, void* arg);
+
+/**
+ * This routine is published for checks and tests, and is only used internally.
+ * libevent callback for AF_UNIX fds
+ * @param fd: file descriptor.
+ * @param event: event bits from libevent:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ * @param arg: the comm_point structure.
+ */
+void comm_point_local_handle_callback(int fd, short event, void* arg);
+
+/**
+ * This routine is published for checks and tests, and is only used internally.
+ * libevent callback for raw fd access.
+ * @param fd: file descriptor.
+ * @param event: event bits from libevent:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ * @param arg: the comm_point structure.
+ */
+void comm_point_raw_handle_callback(int fd, short event, void* arg);
+
+/**
+ * This routine is published for checks and tests, and is only used internally.
+ * libevent callback for timeout on slow accept.
+ * @param fd: file descriptor.
+ * @param event: event bits from libevent:
+ * EV_READ, EV_WRITE, EV_SIGNAL, EV_TIMEOUT.
+ * @param arg: the comm_point structure.
+ */
+void comm_base_handle_slow_accept(int fd, short event, void* arg);
+
+#ifdef USE_WINSOCK
+/**
+ * Callback for openssl BIO to on windows detect WSAEWOULDBLOCK and notify
+ * the winsock_event of this for proper TCP nonblocking implementation.
+ * @param c: comm_point, fd must be set its struct event is registered.
+ * @param ssl: openssl SSL, fd must be set so it has a bio.
+ */
+void comm_point_tcp_win_bio_cb(struct comm_point* c, void* ssl);
+#endif
+
+/** see if errno for tcp connect has to be logged or not. This uses errno */
+int tcp_connect_errno_needs_log(struct sockaddr* addr, socklen_t addrlen);
+
+#endif /* NET_EVENT_H */
diff --git a/external/unbound/util/random.c b/external/unbound/util/random.c
new file mode 100644
index 000000000..71f0ba53e
--- /dev/null
+++ b/external/unbound/util/random.c
@@ -0,0 +1,166 @@
+/*
+ * util/random.c - thread safe random generator, which is reasonably secure.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ * Thread safe random functions. Similar to arc4random() with an explicit
+ * initialisation routine.
+ *
+ * The code in this file is based on arc4random from
+ * openssh-4.0p1/openbsd-compat/bsd-arc4random.c
+ * That code is also BSD licensed. Here is their statement:
+ *
+ * Copyright (c) 1996, David Mazieres <dm@uun.org>
+ * Copyright (c) 2008, Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "config.h"
+#include "util/random.h"
+#include "util/log.h"
+#include <time.h>
+
+#ifdef HAVE_NSS
+/* nspr4 */
+#include "prerror.h"
+/* nss3 */
+#include "secport.h"
+#include "pk11pub.h"
+#endif
+
+/**
+ * Max random value. Similar to RAND_MAX, but more portable
+ * (mingw uses only 15 bits random).
+ */
+#define MAX_VALUE 0x7fffffff
+
+#ifndef HAVE_NSS
+void
+ub_systemseed(unsigned int ATTR_UNUSED(seed))
+{
+ /* arc4random_uniform does not need seeds, it gets kernel entropy */
+}
+
+struct ub_randstate*
+ub_initstate(unsigned int ATTR_UNUSED(seed),
+ struct ub_randstate* ATTR_UNUSED(from))
+{
+ struct ub_randstate* s = (struct ub_randstate*)malloc(1);
+ if(!s) {
+ log_err("malloc failure in random init");
+ return NULL;
+ }
+ return s;
+}
+
+long int
+ub_random(struct ub_randstate* ATTR_UNUSED(s))
+{
+ /* This relies on MAX_VALUE being 0x7fffffff. */
+ return (long)arc4random() & MAX_VALUE;
+}
+
+long int
+ub_random_max(struct ub_randstate* state, long int x)
+{
+ (void)state;
+ /* on OpenBSD, this does not need _seed(), or _stir() calls */
+ return (long)arc4random_uniform((uint32_t)x);
+}
+
+#else
+
+/* not much to remember for NSS since we use its pk11_random, placeholder */
+struct ub_randstate {
+ int ready;
+};
+
+void ub_systemseed(unsigned int ATTR_UNUSED(seed))
+{
+}
+
+struct ub_randstate* ub_initstate(unsigned int ATTR_UNUSED(seed),
+ struct ub_randstate* ATTR_UNUSED(from))
+{
+ struct ub_randstate* s = (struct ub_randstate*)calloc(1, sizeof(*s));
+ if(!s) {
+ log_err("malloc failure in random init");
+ return NULL;
+ }
+ return s;
+}
+
+long int ub_random(struct ub_randstate* ATTR_UNUSED(state))
+{
+ long int x;
+ /* random 31 bit value. */
+ SECStatus s = PK11_GenerateRandom((unsigned char*)&x, (int)sizeof(x));
+ if(s != SECSuccess) {
+ log_err("PK11_GenerateRandom error: %s",
+ PORT_ErrorToString(PORT_GetError()));
+ }
+ return x & MAX_VALUE;
+}
+
+long int
+ub_random_max(struct ub_randstate* state, long int x)
+{
+ /* make sure we fetch in a range that is divisible by x. ignore
+ * values from d .. MAX_VALUE, instead draw a new number */
+ long int d = MAX_VALUE - (MAX_VALUE % x); /* d is divisible by x */
+ long int v = ub_random(state);
+ while(d <= v)
+ v = ub_random(state);
+ return (v % x);
+}
+#endif /* HAVE_NSS */
+
+void
+ub_randfree(struct ub_randstate* s)
+{
+ if(s)
+ free(s);
+ /* user app must do RAND_cleanup(); */
+}
diff --git a/external/unbound/util/random.h b/external/unbound/util/random.h
new file mode 100644
index 000000000..a05a994a3
--- /dev/null
+++ b/external/unbound/util/random.h
@@ -0,0 +1,93 @@
+/*
+ * util/random.h - thread safe random generator, which is reasonably secure.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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.
+ */
+
+#ifndef UTIL_RANDOM_H
+#define UTIL_RANDOM_H
+
+/**
+ * \file
+ * Thread safe random functions. Similar to arc4random() with an explicit
+ * initialisation routine.
+ */
+
+/**
+ * random state structure.
+ */
+struct ub_randstate;
+
+/**
+ * Initialize the system randomness. Obtains entropy from the system
+ * before a chroot or privilege makes it unavailable.
+ * You do not have to call this, otherwise ub_initstate does so.
+ * @param seed: seed value to create state (if no good entropy is found).
+ */
+void ub_systemseed(unsigned int seed);
+
+/**
+ * Initialize a random generator state for use
+ * @param seed: seed value to create state contents.
+ * (ignored for arc4random).
+ * @param from: if not NULL, the seed is taken from this random structure.
+ * can be used to seed random states via a parent-random-state that
+ * is itself seeded with entropy.
+ * @return new state or NULL alloc failure.
+ */
+struct ub_randstate* ub_initstate(unsigned int seed,
+ struct ub_randstate* from);
+
+/**
+ * Generate next random number from the state passed along.
+ * Thread safe, so random numbers are repeatable.
+ * @param state: must have been initialised with ub_initstate.
+ * @return: random 31 bit value.
+ */
+long int ub_random(struct ub_randstate* state);
+
+/**
+ * Generate random number between 0 and x-1. No modulo bias.
+ * @param state: must have been initialised with ub_initstate.
+ * @param x: an upper limit. not (negative or zero). must be smaller than 2**31.
+ * @return: random value between 0..x-1. Possibly more than one
+ * random number is picked from the random stream to satisfy this.
+ */
+long int ub_random_max(struct ub_randstate* state, long int x);
+
+/**
+ * Delete the random state.
+ * @param state: to delete.
+ */
+void ub_randfree(struct ub_randstate* state);
+
+#endif /* UTIL_RANDOM_H */
diff --git a/external/unbound/util/rbtree.c b/external/unbound/util/rbtree.c
new file mode 100644
index 000000000..a898f13f0
--- /dev/null
+++ b/external/unbound/util/rbtree.c
@@ -0,0 +1,620 @@
+/*
+ * rbtree.c -- generic red black tree
+ *
+ * Copyright (c) 2001-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 COPYRIGHT
+ * HOLDER 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
+ * Implementation of a redblack tree.
+ */
+
+#include "config.h"
+#include "log.h"
+#include "fptr_wlist.h"
+#include "util/rbtree.h"
+
+/** Node colour black */
+#define BLACK 0
+/** Node colour red */
+#define RED 1
+
+/** the NULL node, global alloc */
+rbnode_t rbtree_null_node = {
+ RBTREE_NULL, /* Parent. */
+ RBTREE_NULL, /* Left. */
+ RBTREE_NULL, /* Right. */
+ NULL, /* Key. */
+ BLACK /* Color. */
+};
+
+/** rotate subtree left (to preserve redblack property) */
+static void rbtree_rotate_left(rbtree_t *rbtree, rbnode_t *node);
+/** rotate subtree right (to preserve redblack property) */
+static void rbtree_rotate_right(rbtree_t *rbtree, rbnode_t *node);
+/** Fixup node colours when insert happened */
+static void rbtree_insert_fixup(rbtree_t *rbtree, rbnode_t *node);
+/** Fixup node colours when delete happened */
+static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* child_parent);
+
+/*
+ * Creates a new red black tree, intializes and returns a pointer to it.
+ *
+ * Return NULL on failure.
+ *
+ */
+rbtree_t *
+rbtree_create (int (*cmpf)(const void *, const void *))
+{
+ rbtree_t *rbtree;
+
+ /* Allocate memory for it */
+ rbtree = (rbtree_t *) malloc(sizeof(rbtree_t));
+ if (!rbtree) {
+ return NULL;
+ }
+
+ /* Initialize it */
+ rbtree_init(rbtree, cmpf);
+
+ return rbtree;
+}
+
+void
+rbtree_init(rbtree_t *rbtree, int (*cmpf)(const void *, const void *))
+{
+ /* Initialize it */
+ rbtree->root = RBTREE_NULL;
+ rbtree->count = 0;
+ rbtree->cmp = cmpf;
+}
+
+/*
+ * Rotates the node to the left.
+ *
+ */
+static void
+rbtree_rotate_left(rbtree_t *rbtree, rbnode_t *node)
+{
+ rbnode_t *right = node->right;
+ node->right = right->left;
+ if (right->left != RBTREE_NULL)
+ right->left->parent = node;
+
+ right->parent = node->parent;
+
+ if (node->parent != RBTREE_NULL) {
+ if (node == node->parent->left) {
+ node->parent->left = right;
+ } else {
+ node->parent->right = right;
+ }
+ } else {
+ rbtree->root = right;
+ }
+ right->left = node;
+ node->parent = right;
+}
+
+/*
+ * Rotates the node to the right.
+ *
+ */
+static void
+rbtree_rotate_right(rbtree_t *rbtree, rbnode_t *node)
+{
+ rbnode_t *left = node->left;
+ node->left = left->right;
+ if (left->right != RBTREE_NULL)
+ left->right->parent = node;
+
+ left->parent = node->parent;
+
+ if (node->parent != RBTREE_NULL) {
+ if (node == node->parent->right) {
+ node->parent->right = left;
+ } else {
+ node->parent->left = left;
+ }
+ } else {
+ rbtree->root = left;
+ }
+ left->right = node;
+ node->parent = left;
+}
+
+static void
+rbtree_insert_fixup(rbtree_t *rbtree, rbnode_t *node)
+{
+ rbnode_t *uncle;
+
+ /* While not at the root and need fixing... */
+ while (node != rbtree->root && node->parent->color == RED) {
+ /* If our parent is left child of our grandparent... */
+ if (node->parent == node->parent->parent->left) {
+ uncle = node->parent->parent->right;
+
+ /* If our uncle is red... */
+ if (uncle->color == RED) {
+ /* Paint the parent and the uncle black... */
+ node->parent->color = BLACK;
+ uncle->color = BLACK;
+
+ /* And the grandparent red... */
+ node->parent->parent->color = RED;
+
+ /* And continue fixing the grandparent */
+ node = node->parent->parent;
+ } else { /* Our uncle is black... */
+ /* Are we the right child? */
+ if (node == node->parent->right) {
+ node = node->parent;
+ rbtree_rotate_left(rbtree, node);
+ }
+ /* Now we're the left child, repaint and rotate... */
+ node->parent->color = BLACK;
+ node->parent->parent->color = RED;
+ rbtree_rotate_right(rbtree, node->parent->parent);
+ }
+ } else {
+ uncle = node->parent->parent->left;
+
+ /* If our uncle is red... */
+ if (uncle->color == RED) {
+ /* Paint the parent and the uncle black... */
+ node->parent->color = BLACK;
+ uncle->color = BLACK;
+
+ /* And the grandparent red... */
+ node->parent->parent->color = RED;
+
+ /* And continue fixing the grandparent */
+ node = node->parent->parent;
+ } else { /* Our uncle is black... */
+ /* Are we the right child? */
+ if (node == node->parent->left) {
+ node = node->parent;
+ rbtree_rotate_right(rbtree, node);
+ }
+ /* Now we're the right child, repaint and rotate... */
+ node->parent->color = BLACK;
+ node->parent->parent->color = RED;
+ rbtree_rotate_left(rbtree, node->parent->parent);
+ }
+ }
+ }
+ rbtree->root->color = BLACK;
+}
+
+
+/*
+ * Inserts a node into a red black tree.
+ *
+ * Returns NULL on failure or the pointer to the newly added node
+ * otherwise.
+ */
+rbnode_t *
+rbtree_insert (rbtree_t *rbtree, rbnode_t *data)
+{
+ /* XXX Not necessary, but keeps compiler quiet... */
+ int r = 0;
+
+ /* We start at the root of the tree */
+ rbnode_t *node = rbtree->root;
+ rbnode_t *parent = RBTREE_NULL;
+
+ fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp));
+ /* Lets find the new parent... */
+ while (node != RBTREE_NULL) {
+ /* Compare two keys, do we have a duplicate? */
+ if ((r = rbtree->cmp(data->key, node->key)) == 0) {
+ return NULL;
+ }
+ parent = node;
+
+ if (r < 0) {
+ node = node->left;
+ } else {
+ node = node->right;
+ }
+ }
+
+ /* Initialize the new node */
+ data->parent = parent;
+ data->left = data->right = RBTREE_NULL;
+ data->color = RED;
+ rbtree->count++;
+
+ /* Insert it into the tree... */
+ if (parent != RBTREE_NULL) {
+ if (r < 0) {
+ parent->left = data;
+ } else {
+ parent->right = data;
+ }
+ } else {
+ rbtree->root = data;
+ }
+
+ /* Fix up the red-black properties... */
+ rbtree_insert_fixup(rbtree, data);
+
+ return data;
+}
+
+/*
+ * Searches the red black tree, returns the data if key is found or NULL otherwise.
+ *
+ */
+rbnode_t *
+rbtree_search (rbtree_t *rbtree, const void *key)
+{
+ rbnode_t *node;
+
+ if (rbtree_find_less_equal(rbtree, key, &node)) {
+ return node;
+ } else {
+ return NULL;
+ }
+}
+
+/** helpers for delete: swap node colours */
+static void swap_int8(uint8_t* x, uint8_t* y)
+{
+ uint8_t t = *x; *x = *y; *y = t;
+}
+
+/** helpers for delete: swap node pointers */
+static void swap_np(rbnode_t** x, rbnode_t** y)
+{
+ rbnode_t* t = *x; *x = *y; *y = t;
+}
+
+/** Update parent pointers of child trees of 'parent' */
+static void change_parent_ptr(rbtree_t* rbtree, rbnode_t* parent, rbnode_t* old, rbnode_t* new)
+{
+ if(parent == RBTREE_NULL)
+ {
+ log_assert(rbtree->root == old);
+ if(rbtree->root == old) rbtree->root = new;
+ return;
+ }
+ log_assert(parent->left == old || parent->right == old
+ || parent->left == new || parent->right == new);
+ if(parent->left == old) parent->left = new;
+ if(parent->right == old) parent->right = new;
+}
+/** Update parent pointer of a node 'child' */
+static void change_child_ptr(rbnode_t* child, rbnode_t* old, rbnode_t* new)
+{
+ if(child == RBTREE_NULL) return;
+ log_assert(child->parent == old || child->parent == new);
+ if(child->parent == old) child->parent = new;
+}
+
+rbnode_t*
+rbtree_delete(rbtree_t *rbtree, const void *key)
+{
+ rbnode_t *to_delete;
+ rbnode_t *child;
+ if((to_delete = rbtree_search(rbtree, key)) == 0) return 0;
+ rbtree->count--;
+
+ /* make sure we have at most one non-leaf child */
+ if(to_delete->left != RBTREE_NULL && to_delete->right != RBTREE_NULL)
+ {
+ /* swap with smallest from right subtree (or largest from left) */
+ rbnode_t *smright = to_delete->right;
+ while(smright->left != RBTREE_NULL)
+ smright = smright->left;
+ /* swap the smright and to_delete elements in the tree,
+ * but the rbnode_t is first part of user data struct
+ * so cannot just swap the keys and data pointers. Instead
+ * readjust the pointers left,right,parent */
+
+ /* swap colors - colors are tied to the position in the tree */
+ swap_int8(&to_delete->color, &smright->color);
+
+ /* swap child pointers in parents of smright/to_delete */
+ change_parent_ptr(rbtree, to_delete->parent, to_delete, smright);
+ if(to_delete->right != smright)
+ change_parent_ptr(rbtree, smright->parent, smright, to_delete);
+
+ /* swap parent pointers in children of smright/to_delete */
+ change_child_ptr(smright->left, smright, to_delete);
+ change_child_ptr(smright->left, smright, to_delete);
+ change_child_ptr(smright->right, smright, to_delete);
+ change_child_ptr(smright->right, smright, to_delete);
+ change_child_ptr(to_delete->left, to_delete, smright);
+ if(to_delete->right != smright)
+ change_child_ptr(to_delete->right, to_delete, smright);
+ if(to_delete->right == smright)
+ {
+ /* set up so after swap they work */
+ to_delete->right = to_delete;
+ smright->parent = smright;
+ }
+
+ /* swap pointers in to_delete/smright nodes */
+ swap_np(&to_delete->parent, &smright->parent);
+ swap_np(&to_delete->left, &smright->left);
+ swap_np(&to_delete->right, &smright->right);
+
+ /* now delete to_delete (which is at the location where the smright previously was) */
+ }
+ log_assert(to_delete->left == RBTREE_NULL || to_delete->right == RBTREE_NULL);
+
+ if(to_delete->left != RBTREE_NULL) child = to_delete->left;
+ else child = to_delete->right;
+
+ /* unlink to_delete from the tree, replace to_delete with child */
+ change_parent_ptr(rbtree, to_delete->parent, to_delete, child);
+ change_child_ptr(child, to_delete, to_delete->parent);
+
+ if(to_delete->color == RED)
+ {
+ /* if node is red then the child (black) can be swapped in */
+ }
+ else if(child->color == RED)
+ {
+ /* change child to BLACK, removing a RED node is no problem */
+ if(child!=RBTREE_NULL) child->color = BLACK;
+ }
+ else rbtree_delete_fixup(rbtree, child, to_delete->parent);
+
+ /* unlink completely */
+ to_delete->parent = RBTREE_NULL;
+ to_delete->left = RBTREE_NULL;
+ to_delete->right = RBTREE_NULL;
+ to_delete->color = BLACK;
+ return to_delete;
+}
+
+static void rbtree_delete_fixup(rbtree_t* rbtree, rbnode_t* child, rbnode_t* child_parent)
+{
+ rbnode_t* sibling;
+ int go_up = 1;
+
+ /* determine sibling to the node that is one-black short */
+ if(child_parent->right == child) sibling = child_parent->left;
+ else sibling = child_parent->right;
+
+ while(go_up)
+ {
+ if(child_parent == RBTREE_NULL)
+ {
+ /* removed parent==black from root, every path, so ok */
+ return;
+ }
+
+ if(sibling->color == RED)
+ { /* rotate to get a black sibling */
+ child_parent->color = RED;
+ sibling->color = BLACK;
+ if(child_parent->right == child)
+ rbtree_rotate_right(rbtree, child_parent);
+ else rbtree_rotate_left(rbtree, child_parent);
+ /* new sibling after rotation */
+ if(child_parent->right == child) sibling = child_parent->left;
+ else sibling = child_parent->right;
+ }
+
+ if(child_parent->color == BLACK
+ && sibling->color == BLACK
+ && sibling->left->color == BLACK
+ && sibling->right->color == BLACK)
+ { /* fixup local with recolor of sibling */
+ if(sibling != RBTREE_NULL)
+ sibling->color = RED;
+
+ child = child_parent;
+ child_parent = child_parent->parent;
+ /* prepare to go up, new sibling */
+ if(child_parent->right == child) sibling = child_parent->left;
+ else sibling = child_parent->right;
+ }
+ else go_up = 0;
+ }
+
+ if(child_parent->color == RED
+ && sibling->color == BLACK
+ && sibling->left->color == BLACK
+ && sibling->right->color == BLACK)
+ {
+ /* move red to sibling to rebalance */
+ if(sibling != RBTREE_NULL)
+ sibling->color = RED;
+ child_parent->color = BLACK;
+ return;
+ }
+ log_assert(sibling != RBTREE_NULL);
+
+ /* get a new sibling, by rotating at sibling. See which child
+ of sibling is red */
+ if(child_parent->right == child
+ && sibling->color == BLACK
+ && sibling->right->color == RED
+ && sibling->left->color == BLACK)
+ {
+ sibling->color = RED;
+ sibling->right->color = BLACK;
+ rbtree_rotate_left(rbtree, sibling);
+ /* new sibling after rotation */
+ if(child_parent->right == child) sibling = child_parent->left;
+ else sibling = child_parent->right;
+ }
+ else if(child_parent->left == child
+ && sibling->color == BLACK
+ && sibling->left->color == RED
+ && sibling->right->color == BLACK)
+ {
+ sibling->color = RED;
+ sibling->left->color = BLACK;
+ rbtree_rotate_right(rbtree, sibling);
+ /* new sibling after rotation */
+ if(child_parent->right == child) sibling = child_parent->left;
+ else sibling = child_parent->right;
+ }
+
+ /* now we have a black sibling with a red child. rotate and exchange colors. */
+ sibling->color = child_parent->color;
+ child_parent->color = BLACK;
+ if(child_parent->right == child)
+ {
+ log_assert(sibling->left->color == RED);
+ sibling->left->color = BLACK;
+ rbtree_rotate_right(rbtree, child_parent);
+ }
+ else
+ {
+ log_assert(sibling->right->color == RED);
+ sibling->right->color = BLACK;
+ rbtree_rotate_left(rbtree, child_parent);
+ }
+}
+
+int
+rbtree_find_less_equal(rbtree_t *rbtree, const void *key, rbnode_t **result)
+{
+ int r;
+ rbnode_t *node;
+
+ log_assert(result);
+
+ /* We start at root... */
+ node = rbtree->root;
+
+ *result = NULL;
+ fptr_ok(fptr_whitelist_rbtree_cmp(rbtree->cmp));
+
+ /* While there are children... */
+ while (node != RBTREE_NULL) {
+ r = rbtree->cmp(key, node->key);
+ if (r == 0) {
+ /* Exact match */
+ *result = node;
+ return 1;
+ }
+ if (r < 0) {
+ node = node->left;
+ } else {
+ /* Temporary match */
+ *result = node;
+ node = node->right;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Finds the first element in the red black tree
+ *
+ */
+rbnode_t *
+rbtree_first (rbtree_t *rbtree)
+{
+ rbnode_t *node;
+
+ for (node = rbtree->root; node->left != RBTREE_NULL; node = node->left);
+ return node;
+}
+
+rbnode_t *
+rbtree_last (rbtree_t *rbtree)
+{
+ rbnode_t *node;
+
+ for (node = rbtree->root; node->right != RBTREE_NULL; node = node->right);
+ return node;
+}
+
+/*
+ * Returns the next node...
+ *
+ */
+rbnode_t *
+rbtree_next (rbnode_t *node)
+{
+ rbnode_t *parent;
+
+ if (node->right != RBTREE_NULL) {
+ /* One right, then keep on going left... */
+ for (node = node->right; node->left != RBTREE_NULL; node = node->left);
+ } else {
+ parent = node->parent;
+ while (parent != RBTREE_NULL && node == parent->right) {
+ node = parent;
+ parent = parent->parent;
+ }
+ node = parent;
+ }
+ return node;
+}
+
+rbnode_t *
+rbtree_previous(rbnode_t *node)
+{
+ rbnode_t *parent;
+
+ if (node->left != RBTREE_NULL) {
+ /* One left, then keep on going right... */
+ for (node = node->left; node->right != RBTREE_NULL; node = node->right);
+ } else {
+ parent = node->parent;
+ while (parent != RBTREE_NULL && node == parent->left) {
+ node = parent;
+ parent = parent->parent;
+ }
+ node = parent;
+ }
+ return node;
+}
+
+/** recursive descent traverse */
+static void
+traverse_post(void (*func)(rbnode_t*, void*), void* arg, rbnode_t* node)
+{
+ if(!node || node == RBTREE_NULL)
+ return;
+ /* recurse */
+ traverse_post(func, arg, node->left);
+ traverse_post(func, arg, node->right);
+ /* call user func */
+ (*func)(node, arg);
+}
+
+void
+traverse_postorder(rbtree_t* tree, void (*func)(rbnode_t*, void*), void* arg)
+{
+ traverse_post(func, arg, tree->root);
+}
diff --git a/external/unbound/util/rbtree.h b/external/unbound/util/rbtree.h
new file mode 100644
index 000000000..50c84bbab
--- /dev/null
+++ b/external/unbound/util/rbtree.h
@@ -0,0 +1,192 @@
+/*
+ * rbtree.h -- generic red-black tree
+ *
+ * Copyright (c) 2001-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 COPYRIGHT
+ * HOLDER 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
+ * Red black tree. Implementation taken from NSD 3.0.5, adjusted for use
+ * in unbound (memory allocation, logging and so on).
+ */
+
+#ifndef UTIL_RBTREE_H_
+#define UTIL_RBTREE_H_
+
+/**
+ * This structure must be the first member of the data structure in
+ * the rbtree. This allows easy casting between an rbnode_t and the
+ * user data (poor man's inheritance).
+ */
+typedef struct rbnode_t rbnode_t;
+/**
+ * The rbnode_t struct definition.
+ */
+struct rbnode_t {
+ /** parent in rbtree, RBTREE_NULL for root */
+ rbnode_t *parent;
+ /** left node (smaller items) */
+ rbnode_t *left;
+ /** right node (larger items) */
+ rbnode_t *right;
+ /** pointer to sorting key */
+ const void *key;
+ /** colour of this node */
+ uint8_t color;
+};
+
+/** The nullpointer, points to empty node */
+#define RBTREE_NULL &rbtree_null_node
+/** the global empty node */
+extern rbnode_t rbtree_null_node;
+
+/** An entire red black tree */
+typedef struct rbtree_t rbtree_t;
+/** definition for tree struct */
+struct rbtree_t {
+ /** The root of the red-black tree */
+ rbnode_t *root;
+
+ /** The number of the nodes in the tree */
+ size_t count;
+
+ /**
+ * Key compare function. <0,0,>0 like strcmp.
+ * Return 0 on two NULL ptrs.
+ */
+ int (*cmp) (const void *, const void *);
+};
+
+/**
+ * Create new tree (malloced) with given key compare function.
+ * @param cmpf: compare function (like strcmp) takes pointers to two keys.
+ * @return: new tree, empty.
+ */
+rbtree_t *rbtree_create(int (*cmpf)(const void *, const void *));
+
+/**
+ * Init a new tree (malloced by caller) with given key compare function.
+ * @param rbtree: uninitialised memory for new tree, returned empty.
+ * @param cmpf: compare function (like strcmp) takes pointers to two keys.
+ */
+void rbtree_init(rbtree_t *rbtree, int (*cmpf)(const void *, const void *));
+
+/**
+ * Insert data into the tree.
+ * @param rbtree: tree to insert to.
+ * @param data: element to insert.
+ * @return: data ptr or NULL if key already present.
+ */
+rbnode_t *rbtree_insert(rbtree_t *rbtree, rbnode_t *data);
+
+/**
+ * Delete element from tree.
+ * @param rbtree: tree to delete from.
+ * @param key: key of item to delete.
+ * @return: node that is now unlinked from the tree. User to delete it.
+ * returns 0 if node not present
+ */
+rbnode_t *rbtree_delete(rbtree_t *rbtree, const void *key);
+
+/**
+ * Find key in tree. Returns NULL if not found.
+ * @param rbtree: tree to find in.
+ * @param key: key that must match.
+ * @return: node that fits or NULL.
+ */
+rbnode_t *rbtree_search(rbtree_t *rbtree, const void *key);
+
+/**
+ * Find, but match does not have to be exact.
+ * @param rbtree: tree to find in.
+ * @param key: key to find position of.
+ * @param result: set to the exact node if present, otherwise to element that
+ * precedes the position of key in the tree. NULL if no smaller element.
+ * @return: true if exact match in result. Else result points to <= element,
+ * or NULL if key is smaller than the smallest key.
+ */
+int rbtree_find_less_equal(rbtree_t *rbtree, const void *key,
+ rbnode_t **result);
+
+/**
+ * Returns first (smallest) node in the tree
+ * @param rbtree: tree
+ * @return: smallest element or NULL if tree empty.
+ */
+rbnode_t *rbtree_first(rbtree_t *rbtree);
+
+/**
+ * Returns last (largest) node in the tree
+ * @param rbtree: tree
+ * @return: largest element or NULL if tree empty.
+ */
+rbnode_t *rbtree_last(rbtree_t *rbtree);
+
+/**
+ * Returns next larger node in the tree
+ * @param rbtree: tree
+ * @return: next larger element or NULL if no larger in tree.
+ */
+rbnode_t *rbtree_next(rbnode_t *rbtree);
+
+/**
+ * Returns previous smaller node in the tree
+ * @param rbtree: tree
+ * @return: previous smaller element or NULL if no previous in tree.
+ */
+rbnode_t *rbtree_previous(rbnode_t *rbtree);
+
+/**
+ * Call with node=variable of struct* with rbnode_t as first element.
+ * with type is the type of a pointer to that struct.
+ */
+#define RBTREE_FOR(node, type, rbtree) \
+ for(node=(type)rbtree_first(rbtree); \
+ (rbnode_t*)node != RBTREE_NULL; \
+ node = (type)rbtree_next((rbnode_t*)node))
+
+/**
+ * Call function for all elements in the redblack tree, such that
+ * leaf elements are called before parent elements. So that all
+ * elements can be safely free()d.
+ * Note that your function must not remove the nodes from the tree.
+ * Since that may trigger rebalances of the rbtree.
+ * @param tree: the tree
+ * @param func: function called with element and user arg.
+ * The function must not alter the rbtree.
+ * @param arg: user argument.
+ */
+void traverse_postorder(rbtree_t* tree, void (*func)(rbnode_t*, void*),
+ void* arg);
+
+#endif /* UTIL_RBTREE_H_ */
diff --git a/external/unbound/util/regional.c b/external/unbound/util/regional.c
new file mode 100644
index 000000000..899a54edb
--- /dev/null
+++ b/external/unbound/util/regional.c
@@ -0,0 +1,223 @@
+/*
+ * regional.c -- region based memory allocator.
+ *
+ * Copyright (c) 2001-2006, NLnet Labs. All rights reserved.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ * Regional allocator. Allocates small portions of of larger chunks.
+ */
+
+#include "config.h"
+#include "util/log.h"
+#include "util/regional.h"
+
+#ifdef ALIGNMENT
+# undef ALIGNMENT
+#endif
+/** increase size until it fits alignment of s bytes */
+#define ALIGN_UP(x, s) (((x) + s - 1) & (~(s - 1)))
+/** what size to align on; make sure a char* fits in it. */
+#define ALIGNMENT (sizeof(uint64_t))
+
+/** Default reasonable size for chunks */
+#define REGIONAL_CHUNK_SIZE 8192
+#ifdef UNBOUND_ALLOC_NONREGIONAL
+/** All objects allocated outside of chunks, for debug */
+#define REGIONAL_LARGE_OBJECT_SIZE 0
+#else
+/** Default size for large objects - allocated outside of chunks. */
+#define REGIONAL_LARGE_OBJECT_SIZE 2048
+#endif
+
+struct regional*
+regional_create(void)
+{
+ return regional_create_custom(REGIONAL_CHUNK_SIZE);
+}
+
+/** init regional struct with first block */
+static void
+regional_init(struct regional* r)
+{
+ size_t a = ALIGN_UP(sizeof(struct regional), ALIGNMENT);
+ r->data = (char*)r + a;
+ r->available = r->first_size - a;
+ r->next = NULL;
+ r->large_list = NULL;
+ r->total_large = 0;
+}
+
+struct regional*
+regional_create_custom(size_t size)
+{
+ struct regional* r = (struct regional*)malloc(size);
+ log_assert(sizeof(struct regional) <= size);
+ if(!r) return NULL;
+ r->first_size = size;
+ regional_init(r);
+ return r;
+}
+
+void
+regional_free_all(struct regional *r)
+{
+ char* p = r->next, *np;
+ while(p) {
+ np = *(char**)p;
+ free(p);
+ p = np;
+ }
+ p = r->large_list;
+ while(p) {
+ np = *(char**)p;
+ free(p);
+ p = np;
+ }
+ regional_init(r);
+}
+
+void
+regional_destroy(struct regional *r)
+{
+ if(!r) return;
+ regional_free_all(r);
+ free(r);
+}
+
+void *
+regional_alloc(struct regional *r, size_t size)
+{
+ size_t a = ALIGN_UP(size, ALIGNMENT);
+ void *s;
+ /* large objects */
+ if(a > REGIONAL_LARGE_OBJECT_SIZE) {
+ s = malloc(ALIGNMENT + size);
+ if(!s) return NULL;
+ r->total_large += ALIGNMENT+size;
+ *(char**)s = r->large_list;
+ r->large_list = (char*)s;
+ return (char*)s+ALIGNMENT;
+ }
+ /* create a new chunk */
+ if(a > r->available) {
+ s = malloc(REGIONAL_CHUNK_SIZE);
+ if(!s) return NULL;
+ *(char**)s = r->next;
+ r->next = (char*)s;
+ r->data = (char*)s + ALIGNMENT;
+ r->available = REGIONAL_CHUNK_SIZE - ALIGNMENT;
+ }
+ /* put in this chunk */
+ r->available -= a;
+ s = r->data;
+ r->data += a;
+ return s;
+}
+
+void *
+regional_alloc_init(struct regional* r, const void *init, size_t size)
+{
+ void *s = regional_alloc(r, size);
+ if(!s) return NULL;
+ memcpy(s, init, size);
+ return s;
+}
+
+void *
+regional_alloc_zero(struct regional *r, size_t size)
+{
+ void *s = regional_alloc(r, size);
+ if(!s) return NULL;
+ memset(s, 0, size);
+ return s;
+}
+
+char *
+regional_strdup(struct regional *r, const char *string)
+{
+ return (char*)regional_alloc_init(r, string, strlen(string)+1);
+}
+
+/**
+ * reasonably slow, but stats and get_mem are not supposed to be fast
+ * count the number of chunks in use
+ */
+static size_t
+count_chunks(struct regional* r)
+{
+ size_t c = 1;
+ char* p = r->next;
+ while(p) {
+ c++;
+ p = *(char**)p;
+ }
+ return c;
+}
+
+/**
+ * also reasonably slow, counts the number of large objects
+ */
+static size_t
+count_large(struct regional* r)
+{
+ size_t c = 0;
+ char* p = r->large_list;
+ while(p) {
+ c++;
+ p = *(char**)p;
+ }
+ return c;
+}
+
+void
+regional_log_stats(struct regional *r)
+{
+ /* some basic assertions put here (non time critical code) */
+ log_assert(ALIGNMENT >= sizeof(char*));
+ log_assert(REGIONAL_CHUNK_SIZE > ALIGNMENT);
+ log_assert(REGIONAL_CHUNK_SIZE-ALIGNMENT > REGIONAL_LARGE_OBJECT_SIZE);
+ log_assert(REGIONAL_CHUNK_SIZE >= sizeof(struct regional));
+ /* debug print */
+ log_info("regional %u chunks, %u large",
+ (unsigned)count_chunks(r), (unsigned)count_large(r));
+}
+
+size_t
+regional_get_mem(struct regional* r)
+{
+ return r->first_size + (count_chunks(r)-1)*REGIONAL_CHUNK_SIZE
+ + r->total_large;
+}
diff --git a/external/unbound/util/regional.h b/external/unbound/util/regional.h
new file mode 100644
index 000000000..e8b2cb8d0
--- /dev/null
+++ b/external/unbound/util/regional.h
@@ -0,0 +1,150 @@
+/*
+ * regional.h -- region based memory allocator.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ * Regional allocator. Allocates small portions of of larger chunks.
+ * Based on region-allocator from NSD, but rewritten to be light.
+ *
+ * Different from (nsd) region-allocator.h
+ * o does not have recycle bin
+ * o does not collect stats; just enough to answer get_mem() in use.
+ * o does not keep cleanup list
+ * o does not have function pointers to setup
+ * o allocs the regional struct inside the first block.
+ * o can take a block to create regional from.
+ * o blocks and large allocations are kept on singly linked lists.
+ */
+
+#ifndef UTIL_REGIONAL_H_
+#define UTIL_REGIONAL_H_
+
+/**
+ * the regional* is the first block*.
+ * every block has a ptr to the next in first bytes.
+ * and so does the regional struct, which is the first block.
+ */
+struct regional
+{
+ /**
+ * next chunk. NULL if first chunk is the only chunk.
+ * first inside that chunk is the char* next pointer.
+ * When regional_free_all() has been called this value is NULL.
+ */
+ char* next;
+ /** first large object, cast to char** to obtain next ptr */
+ char* large_list;
+ /** total large size */
+ size_t total_large;
+ /** initial chunk size */
+ size_t first_size;
+ /** number of bytes available in the current chunk. */
+ size_t available;
+ /** current chunk data position. */
+ char* data;
+};
+
+/**
+ * Create a new regional.
+ * @return: newly allocated regional.
+ */
+struct regional* regional_create(void);
+
+/**
+ * Create a new region, with custom settings.
+ * @param size: length of first block.
+ * @return: newly allocated regional.
+ */
+struct regional* regional_create_custom(size_t size);
+
+/**
+ * Free all memory associated with regional. Only keeps the first block with
+ * the regional inside it.
+ * @param r: the region.
+ */
+void regional_free_all(struct regional *r);
+
+/**
+ * Destroy regional. All memory associated with regional is freed as if
+ * regional_free_all was called, as well as destroying the regional struct.
+ * @param r: to delete.
+ */
+void regional_destroy(struct regional *r);
+
+/**
+ * Allocate size bytes of memory inside regional. The memory is
+ * deallocated when region_free_all is called for this region.
+ * @param r: the region.
+ * @param size: number of bytes.
+ * @return: pointer to memory allocated.
+ */
+void *regional_alloc(struct regional *r, size_t size);
+
+/**
+ * Allocate size bytes of memory inside regional and copy INIT into it.
+ * The memory is deallocated when region_free_all is called for this
+ * region.
+ * @param r: the region.
+ * @param init: to copy.
+ * @param size: number of bytes.
+ * @return: pointer to memory allocated.
+ */
+void *regional_alloc_init(struct regional* r, const void *init, size_t size);
+
+/**
+ * Allocate size bytes of memory inside regional that are initialized to
+ * 0. The memory is deallocated when region_free_all is called for
+ * this region.
+ * @param r: the region.
+ * @param size: number of bytes.
+ * @return: pointer to memory allocated.
+ */
+void *regional_alloc_zero(struct regional *r, size_t size);
+
+/**
+ * Duplicate string and allocate the result in regional.
+ * @param r: the region.
+ * @param string: null terminated string.
+ * @return: pointer to memory allocated.
+ */
+char *regional_strdup(struct regional *r, const char *string);
+
+/** Debug print regional statistics to log */
+void regional_log_stats(struct regional *r);
+
+/** get total memory size in use by region */
+size_t regional_get_mem(struct regional* r);
+
+#endif /* UTIL_REGIONAL_H_ */
diff --git a/external/unbound/util/rtt.c b/external/unbound/util/rtt.c
new file mode 100644
index 000000000..4b44fca50
--- /dev/null
+++ b/external/unbound/util/rtt.c
@@ -0,0 +1,119 @@
+/*
+ * util/rtt.c - UDP round trip time estimator for resend timeouts.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 a data type and functions to help estimate good
+ * round trip times for UDP resend timeout values.
+ */
+#include "config.h"
+#include "util/rtt.h"
+
+/** calculate RTO from rtt information */
+static int
+calc_rto(const struct rtt_info* rtt)
+{
+ /* From Stevens, Unix Network Programming, Vol1, 3rd ed., p.598 */
+ int rto = rtt->srtt + 4*rtt->rttvar;
+ if(rto < RTT_MIN_TIMEOUT)
+ rto = RTT_MIN_TIMEOUT;
+ if(rto > RTT_MAX_TIMEOUT)
+ rto = RTT_MAX_TIMEOUT;
+ return rto;
+}
+
+void
+rtt_init(struct rtt_info* rtt)
+{
+ rtt->srtt = 0;
+ rtt->rttvar = 94;
+ rtt->rto = calc_rto(rtt);
+ /* default value from the book is 0 + 4*0.75 = 3 seconds */
+ /* first RTO is 0 + 4*0.094 = 0.376 seconds */
+}
+
+int
+rtt_timeout(const struct rtt_info* rtt)
+{
+ return rtt->rto;
+}
+
+int
+rtt_unclamped(const struct rtt_info* rtt)
+{
+ if(calc_rto(rtt) != rtt->rto) {
+ /* timeout fallback has happened */
+ return rtt->rto;
+ }
+ /* return unclamped value */
+ return rtt->srtt + 4*rtt->rttvar;
+}
+
+void
+rtt_update(struct rtt_info* rtt, int ms)
+{
+ int delta = ms - rtt->srtt;
+ rtt->srtt += delta / 8; /* g = 1/8 */
+ if(delta < 0)
+ delta = -delta; /* |delta| */
+ rtt->rttvar += (delta - rtt->rttvar) / 4; /* h = 1/4 */
+ rtt->rto = calc_rto(rtt);
+}
+
+void
+rtt_lost(struct rtt_info* rtt, int orig)
+{
+ /* exponential backoff */
+
+ /* if a query succeeded and put down the rto meanwhile, ignore this */
+ if(rtt->rto < orig)
+ return;
+
+ /* the original rto is doubled, not the current one to make sure
+ * that the values in the cache are not increased by lots of
+ * queries simultaneously as they time out at the same time */
+ orig *= 2;
+ if(rtt->rto <= orig) {
+ rtt->rto = orig;
+ if(rtt->rto > RTT_MAX_TIMEOUT)
+ rtt->rto = RTT_MAX_TIMEOUT;
+ }
+}
+
+int rtt_notimeout(const struct rtt_info* rtt)
+{
+ return calc_rto(rtt);
+}
diff --git a/external/unbound/util/rtt.h b/external/unbound/util/rtt.h
new file mode 100644
index 000000000..57e904d14
--- /dev/null
+++ b/external/unbound/util/rtt.h
@@ -0,0 +1,107 @@
+/*
+ * util/rtt.h - UDP round trip time estimator for resend timeouts.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 a data type and functions to help estimate good
+ * round trip times for UDP resend timeout values.
+ */
+
+#ifndef UTIL_RTT_H
+#define UTIL_RTT_H
+
+/**
+ * RTT information. Keeps packet Round Trip Time.
+ */
+struct rtt_info {
+ /** smoothed rtt estimator, in milliseconds */
+ int srtt;
+ /** smoothed mean deviation, in milliseconds */
+ int rttvar;
+ /** current RTO in use, in milliseconds */
+ int rto;
+};
+
+/** min retransmit timeout value, in milliseconds */
+#define RTT_MIN_TIMEOUT 50
+/** max retransmit timeout value, in milliseconds */
+#define RTT_MAX_TIMEOUT 120000
+
+/**
+ * Initialize RTT estimators.
+ * @param rtt: The structure. Caller is responsible for allocation of it.
+ */
+void rtt_init(struct rtt_info* rtt);
+
+/**
+ * Get timeout to use for sending a UDP packet.
+ * @param rtt: round trip statistics structure.
+ * @return: timeout to use in milliseconds. Relative time value.
+ */
+int rtt_timeout(const struct rtt_info* rtt);
+
+/**
+ * Get unclamped timeout to use for server selection.
+ * Recent timeouts are reflected in the returned value.
+ * @param rtt: round trip statistics structure.
+ * @return: value to use in milliseconds.
+ */
+int rtt_unclamped(const struct rtt_info* rtt);
+
+/**
+ * RTT for valid responses. Without timeouts.
+ * @param rtt: round trip statistics structure.
+ * @return: value in msec.
+ */
+int rtt_notimeout(const struct rtt_info* rtt);
+
+/**
+ * Update the statistics with a new roundtrip estimate observation.
+ * @param rtt: round trip statistics structure.
+ * @param ms: estimate of roundtrip time in milliseconds.
+ */
+void rtt_update(struct rtt_info* rtt, int ms);
+
+/**
+ * Update the statistics with a new timout expired observation.
+ * @param rtt: round trip statistics structure.
+ * @param orig: original rtt time given for the query that timed out.
+ * Used to calculate the maximum responsible backed off time that
+ * can reasonably be applied.
+ */
+void rtt_lost(struct rtt_info* rtt, int orig);
+
+#endif /* UTIL_RTT_H */
diff --git a/external/unbound/util/storage/dnstree.c b/external/unbound/util/storage/dnstree.c
new file mode 100644
index 000000000..0df490ee5
--- /dev/null
+++ b/external/unbound/util/storage/dnstree.c
@@ -0,0 +1,282 @@
+/*
+ * util/storage/dnstree.c - support for rbtree types suitable for DNS code.
+ *
+ * Copyright (c) 2008, 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 COPYRIGHT
+ * HOLDER 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 structures combining types and functions to
+ * manipulate those structures that help building DNS lookup trees.
+ */
+#include "config.h"
+#include "util/storage/dnstree.h"
+#include "util/data/dname.h"
+#include "util/net_help.h"
+
+int name_tree_compare(const void* k1, const void* k2)
+{
+ struct name_tree_node* x = (struct name_tree_node*)k1;
+ struct name_tree_node* y = (struct name_tree_node*)k2;
+ int m;
+ if(x->dclass != y->dclass) {
+ if(x->dclass < y->dclass)
+ return -1;
+ return 1;
+ }
+ return dname_lab_cmp(x->name, x->labs, y->name, y->labs, &m);
+}
+
+int addr_tree_compare(const void* k1, const void* k2)
+{
+ struct addr_tree_node* n1 = (struct addr_tree_node*)k1;
+ struct addr_tree_node* n2 = (struct addr_tree_node*)k2;
+ int r = sockaddr_cmp_addr(&n1->addr, n1->addrlen, &n2->addr,
+ n2->addrlen);
+ if(r != 0) return r;
+ if(n1->net < n2->net)
+ return -1;
+ if(n1->net > n2->net)
+ return 1;
+ return 0;
+}
+
+void name_tree_init(rbtree_t* tree)
+{
+ rbtree_init(tree, &name_tree_compare);
+}
+
+void addr_tree_init(rbtree_t* tree)
+{
+ rbtree_init(tree, &addr_tree_compare);
+}
+
+int name_tree_insert(rbtree_t* tree, struct name_tree_node* node,
+ uint8_t* name, size_t len, int labs, uint16_t dclass)
+{
+ node->node.key = node;
+ node->name = name;
+ node->len = len;
+ node->labs = labs;
+ node->dclass = dclass;
+ node->parent = NULL;
+ return rbtree_insert(tree, &node->node) != NULL;
+}
+
+int addr_tree_insert(rbtree_t* tree, struct addr_tree_node* node,
+ struct sockaddr_storage* addr, socklen_t addrlen, int net)
+{
+ node->node.key = node;
+ memcpy(&node->addr, addr, addrlen);
+ node->addrlen = addrlen;
+ node->net = net;
+ node->parent = NULL;
+ return rbtree_insert(tree, &node->node) != NULL;
+}
+
+void addr_tree_init_parents(rbtree_t* tree)
+{
+ struct addr_tree_node* node, *prev = NULL, *p;
+ int m;
+ RBTREE_FOR(node, struct addr_tree_node*, tree) {
+ node->parent = NULL;
+ if(!prev || prev->addrlen != node->addrlen) {
+ prev = node;
+ continue;
+ }
+ m = addr_in_common(&prev->addr, prev->net, &node->addr,
+ node->net, node->addrlen);
+ /* sort order like: ::/0, 1::/2, 1::/4, ... 2::/2 */
+ /* find the previous, or parent-parent-parent */
+ for(p = prev; p; p = p->parent)
+ if(p->net <= m) {
+ /* ==: since prev matched m, this is closest*/
+ /* <: prev matches more, but is not a parent,
+ * this one is a (grand)parent */
+ node->parent = p;
+ break;
+ }
+ prev = node;
+ }
+}
+
+void name_tree_init_parents(rbtree_t* tree)
+{
+ struct name_tree_node* node, *prev = NULL, *p;
+ int m;
+ RBTREE_FOR(node, struct name_tree_node*, tree) {
+ node->parent = NULL;
+ if(!prev || prev->dclass != node->dclass) {
+ prev = node;
+ continue;
+ }
+ (void)dname_lab_cmp(prev->name, prev->labs, node->name,
+ node->labs, &m); /* we know prev is smaller */
+ /* sort order like: . com. bla.com. zwb.com. net. */
+ /* find the previous, or parent-parent-parent */
+ for(p = prev; p; p = p->parent)
+ if(p->labs <= m) {
+ /* ==: since prev matched m, this is closest*/
+ /* <: prev matches more, but is not a parent,
+ * this one is a (grand)parent */
+ node->parent = p;
+ break;
+ }
+ prev = node;
+ }
+}
+
+struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name,
+ size_t len, int labs, uint16_t dclass)
+{
+ struct name_tree_node key;
+ key.node.key = &key;
+ key.name = name;
+ key.len = len;
+ key.labs = labs;
+ key.dclass = dclass;
+ return (struct name_tree_node*)rbtree_search(tree, &key);
+}
+
+struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name,
+ size_t len, int labs, uint16_t dclass)
+{
+ rbnode_t* res = NULL;
+ struct name_tree_node *result;
+ struct name_tree_node key;
+ key.node.key = &key;
+ key.name = name;
+ key.len = len;
+ key.labs = labs;
+ key.dclass = dclass;
+ if(rbtree_find_less_equal(tree, &key, &res)) {
+ /* exact */
+ result = (struct name_tree_node*)res;
+ } else {
+ /* smaller element (or no element) */
+ int m;
+ result = (struct name_tree_node*)res;
+ if(!result || result->dclass != dclass)
+ return NULL;
+ /* count number of labels matched */
+ (void)dname_lab_cmp(result->name, result->labs, key.name,
+ key.labs, &m);
+ while(result) { /* go up until qname is subdomain of stub */
+ if(result->labs <= m)
+ break;
+ result = result->parent;
+ }
+ }
+ return result;
+}
+
+struct addr_tree_node* addr_tree_lookup(rbtree_t* tree,
+ struct sockaddr_storage* addr, socklen_t addrlen)
+{
+ rbnode_t* res = NULL;
+ struct addr_tree_node* result;
+ struct addr_tree_node key;
+ key.node.key = &key;
+ memcpy(&key.addr, addr, addrlen);
+ key.addrlen = addrlen;
+ key.net = (addr_is_ip6(addr, addrlen)?128:32);
+ if(rbtree_find_less_equal(tree, &key, &res)) {
+ /* exact */
+ return (struct addr_tree_node*)res;
+ } else {
+ /* smaller element (or no element) */
+ int m;
+ result = (struct addr_tree_node*)res;
+ if(!result || result->addrlen != addrlen)
+ return 0;
+ /* count number of bits matched */
+ m = addr_in_common(&result->addr, result->net, addr,
+ key.net, addrlen);
+ while(result) { /* go up until addr is inside netblock */
+ if(result->net <= m)
+ break;
+ result = result->parent;
+ }
+ }
+ return result;
+}
+
+int
+name_tree_next_root(rbtree_t* tree, uint16_t* dclass)
+{
+ struct name_tree_node key;
+ rbnode_t* n;
+ struct name_tree_node* p;
+ if(*dclass == 0) {
+ /* first root item is first item in tree */
+ n = rbtree_first(tree);
+ if(n == RBTREE_NULL)
+ return 0;
+ p = (struct name_tree_node*)n;
+ if(dname_is_root(p->name)) {
+ *dclass = p->dclass;
+ return 1;
+ }
+ /* root not first item? search for higher items */
+ *dclass = p->dclass + 1;
+ return name_tree_next_root(tree, dclass);
+ }
+ /* find class n in tree, we may get a direct hit, or if we don't
+ * this is the last item of the previous class so rbtree_next() takes
+ * us to the next root (if any) */
+ key.node.key = &key;
+ key.name = (uint8_t*)"\000";
+ key.len = 1;
+ key.labs = 0;
+ key.dclass = *dclass;
+ n = NULL;
+ if(rbtree_find_less_equal(tree, &key, &n)) {
+ /* exact */
+ return 1;
+ } else {
+ /* smaller element */
+ if(!n || n == RBTREE_NULL)
+ return 0; /* nothing found */
+ n = rbtree_next(n);
+ if(n == RBTREE_NULL)
+ return 0; /* no higher */
+ p = (struct name_tree_node*)n;
+ if(dname_is_root(p->name)) {
+ *dclass = p->dclass;
+ return 1;
+ }
+ /* not a root node, return next higher item */
+ *dclass = p->dclass+1;
+ return name_tree_next_root(tree, dclass);
+ }
+}
diff --git a/external/unbound/util/storage/dnstree.h b/external/unbound/util/storage/dnstree.h
new file mode 100644
index 000000000..ec8189100
--- /dev/null
+++ b/external/unbound/util/storage/dnstree.h
@@ -0,0 +1,192 @@
+/*
+ * util/storage/dnstree.h - support for rbtree types suitable for DNS code.
+ *
+ * Copyright (c) 2008, 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 COPYRIGHT
+ * HOLDER 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 structures combining types and functions to
+ * manipulate those structures that help building DNS lookup trees.
+ */
+
+#ifndef UTIL_STORAGE_DNSTREE_H
+#define UTIL_STORAGE_DNSTREE_H
+#include "util/rbtree.h"
+
+/**
+ * Tree of domain names. Sorted first by class then by name.
+ * This is not sorted canonically, but fast.
+ * This can be looked up to obtain a closest encloser parent name.
+ *
+ * The tree itself is a rbtree_t.
+ * This is the element node put as first entry in the client structure.
+ */
+struct name_tree_node {
+ /** rbtree node, key is this struct : dclass and name */
+ rbnode_t node;
+ /** parent in tree */
+ struct name_tree_node* parent;
+ /** name in uncompressed wireformat */
+ uint8_t* name;
+ /** length of name */
+ size_t len;
+ /** labels in name */
+ int labs;
+ /** the class of the name (host order) */
+ uint16_t dclass;
+};
+
+/**
+ * Tree of IP addresses. Sorted first by protocol, then by bits.
+ * This can be looked up to obtain the enclosing subnet.
+ *
+ * The tree itself is a rbtree_t.
+ * This is the element node put as first entry in the client structure.
+ */
+struct addr_tree_node {
+ /** rbtree node, key is this struct : proto and subnet */
+ rbnode_t node;
+ /** parent in tree */
+ struct addr_tree_node* parent;
+ /** address */
+ struct sockaddr_storage addr;
+ /** length of addr */
+ socklen_t addrlen;
+ /** netblock size */
+ int net;
+};
+
+/**
+ * Init a name tree to be empty
+ * @param tree: to init.
+ */
+void name_tree_init(rbtree_t* tree);
+
+/**
+ * insert element into name tree.
+ * @param tree: name tree
+ * @param node: node element (at start of a structure that caller
+ * has allocated).
+ * @param name: name to insert (wireformat)
+ * this node has been allocated by the caller and it itself inserted.
+ * @param len: length of name
+ * @param labs: labels in name
+ * @param dclass: class of name
+ * @return false on error (duplicate element).
+ */
+int name_tree_insert(rbtree_t* tree, struct name_tree_node* node,
+ uint8_t* name, size_t len, int labs, uint16_t dclass);
+
+/**
+ * Initialize parent pointers in name tree.
+ * Should be performed after insertions are done, before lookups
+ * @param tree: name tree
+ */
+void name_tree_init_parents(rbtree_t* tree);
+
+/**
+ * Lookup exact match in name tree
+ * @param tree: name tree
+ * @param name: wireformat name
+ * @param len: length of name
+ * @param labs: labels in name
+ * @param dclass: class of name
+ * @return node or NULL if not found.
+ */
+struct name_tree_node* name_tree_find(rbtree_t* tree, uint8_t* name,
+ size_t len, int labs, uint16_t dclass);
+
+/**
+ * Lookup closest encloser in name tree.
+ * @param tree: name tree
+ * @param name: wireformat name
+ * @param len: length of name
+ * @param labs: labels in name
+ * @param dclass: class of name
+ * @return closest enclosing node (could be equal) or NULL if not found.
+ */
+struct name_tree_node* name_tree_lookup(rbtree_t* tree, uint8_t* name,
+ size_t len, int labs, uint16_t dclass);
+
+/**
+ * Find next root item in name tree.
+ * @param tree: the nametree.
+ * @param dclass: the class to look for next (or higher).
+ * @return false if no classes found, true means class put into c.
+ */
+int name_tree_next_root(rbtree_t* tree, uint16_t* dclass);
+
+/**
+ * Init addr tree to be empty.
+ * @param tree: to init.
+ */
+void addr_tree_init(rbtree_t* tree);
+
+/**
+ * insert element into addr tree.
+ * @param tree: addr tree
+ * @param node: node element (at start of a structure that caller
+ * has allocated).
+ * @param addr: to insert (copied).
+ * @param addrlen: length of addr
+ * @param net: size of subnet.
+ * @return false on error (duplicate element).
+ */
+int addr_tree_insert(rbtree_t* tree, struct addr_tree_node* node,
+ struct sockaddr_storage* addr, socklen_t addrlen, int net);
+
+/**
+ * Initialize parent pointers in addr tree.
+ * Should be performed after insertions are done, before lookups
+ * @param tree: addr tree
+ */
+void addr_tree_init_parents(rbtree_t* tree);
+
+/**
+ * Lookup closest encloser in addr tree.
+ * @param tree: addr tree
+ * @param addr: to lookup.
+ * @param addrlen: length of addr
+ * @return closest enclosing node (could be equal) or NULL if not found.
+ */
+struct addr_tree_node* addr_tree_lookup(rbtree_t* tree,
+ struct sockaddr_storage* addr, socklen_t addrlen);
+
+/** compare name tree nodes */
+int name_tree_compare(const void* k1, const void* k2);
+
+/** compare addr tree nodes */
+int addr_tree_compare(const void* k1, const void* k2);
+
+#endif /* UTIL_STORAGE_DNSTREE_H */
diff --git a/external/unbound/util/storage/lookup3.c b/external/unbound/util/storage/lookup3.c
new file mode 100644
index 000000000..de288587b
--- /dev/null
+++ b/external/unbound/util/storage/lookup3.c
@@ -0,0 +1,1032 @@
+/*
+ February 2013(Wouter) patch defines for BSD endianness, from Brad Smith.
+ January 2012(Wouter) added randomised initial value, fallout from 28c3.
+ March 2007(Wouter) adapted from lookup3.c original, add config.h include.
+ added #ifdef VALGRIND to remove 298,384,660 'unused variable k8' warnings.
+ added include of lookup3.h to check definitions match declarations.
+ removed include of stdint - config.h takes care of platform independence.
+ url http://burtleburtle.net/bob/hash/index.html.
+*/
+/*
+-------------------------------------------------------------------------------
+lookup3.c, by Bob Jenkins, May 2006, Public Domain.
+
+These are functions for producing 32-bit hashes for hash table lookup.
+hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+are externally useful functions. Routines to test the hash are included
+if SELF_TEST is defined. You can use this free for any purpose. It's in
+the public domain. It has no warranty.
+
+You probably want to use hashlittle(). hashlittle() and hashbig()
+hash byte arrays. hashlittle() is is faster than hashbig() on
+little-endian machines. Intel and AMD are little-endian machines.
+On second thought, you probably want hashlittle2(), which is identical to
+hashlittle() except it returns two 32-bit hashes for the price of one.
+You could implement hashbig2() if you wanted but I haven't bothered here.
+
+If you want to find a hash of, say, exactly 7 integers, do
+ a = i1; b = i2; c = i3;
+ mix(a,b,c);
+ a += i4; b += i5; c += i6;
+ mix(a,b,c);
+ a += i7;
+ final(a,b,c);
+then use c as the hash value. If you have a variable length array of
+4-byte integers to hash, use hashword(). If you have a byte array (like
+a character string), use hashlittle(). If you have several byte arrays, or
+a mix of things, see the comments above hashlittle().
+
+Why is this so big? I read 12 bytes at a time into 3 4-byte integers,
+then mix those integers. This is fast (you can do a lot more thorough
+mixing with 12*3 instructions on 3 integers than you can with 3 instructions
+on 1 byte), but shoehorning those bytes into integers efficiently is messy.
+-------------------------------------------------------------------------------
+*/
+/*#define SELF_TEST 1*/
+
+#include "config.h"
+#include "util/storage/lookup3.h"
+#include <stdio.h> /* defines printf for tests */
+#include <time.h> /* defines time_t for timings in the test */
+/*#include <stdint.h> defines uint32_t etc (from config.h) */
+#include <sys/param.h> /* attempt to define endianness */
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h> /* attempt to define endianness (solaris) */
+#endif
+#if defined(linux) || defined(__OpenBSD__)
+# ifdef HAVE_ENDIAN_H
+# include <endian.h> /* attempt to define endianness */
+# else
+# include <machine/endian.h> /* on older OpenBSD */
+# endif
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+#include <sys/endian.h> /* attempt to define endianness */
+#endif
+
+/* random initial value */
+static uint32_t raninit = (uint32_t)0xdeadbeef;
+
+void
+hash_set_raninit(uint32_t v)
+{
+ raninit = v;
+}
+
+/*
+ * My best guess at if you are big-endian or little-endian. This may
+ * need adjustment.
+ */
+#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \
+ __BYTE_ORDER == __LITTLE_ENDIAN) || \
+ (defined(i386) || defined(__i386__) || defined(__i486__) || \
+ defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL) || defined(__x86))
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \
+ __BYTE_ORDER == __BIG_ENDIAN) || \
+ (defined(sparc) || defined(__sparc) || defined(__sparc__) || defined(POWERPC) || defined(mc68000) || defined(sel))
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+#elif defined(_MACHINE_ENDIAN_H_)
+/* test for machine_endian_h protects failure if some are empty strings */
+# if defined(_BYTE_ORDER) && defined(_BIG_ENDIAN) && _BYTE_ORDER == _BIG_ENDIAN
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 1
+# endif
+# if defined(_BYTE_ORDER) && defined(_LITTLE_ENDIAN) && _BYTE_ORDER == _LITTLE_ENDIAN
+# define HASH_LITTLE_ENDIAN 1
+# define HASH_BIG_ENDIAN 0
+# endif /* _MACHINE_ENDIAN_H_ */
+#else
+# define HASH_LITTLE_ENDIAN 0
+# define HASH_BIG_ENDIAN 0
+#endif
+
+#define hashsize(n) ((uint32_t)1<<(n))
+#define hashmask(n) (hashsize(n)-1)
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+
+/*
+-------------------------------------------------------------------------------
+mix -- mix 3 32-bit values reversibly.
+
+This is reversible, so any information in (a,b,c) before mix() is
+still in (a,b,c) after mix().
+
+If four pairs of (a,b,c) inputs are run through mix(), or through
+mix() in reverse, there are at least 32 bits of the output that
+are sometimes the same for one pair and different for another pair.
+This was tested for:
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that
+satisfy this are
+ 4 6 8 16 19 4
+ 9 15 3 18 27 15
+ 14 9 3 7 17 3
+Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing
+for "differ" defined as + with a one-bit base and a two-bit delta. I
+used http://burtleburtle.net/bob/hash/avalanche.html to choose
+the operations, constants, and arrangements of the variables.
+
+This does not achieve avalanche. There are input bits of (a,b,c)
+that fail to affect some output bits of (a,b,c), especially of a. The
+most thoroughly mixed value is c, but it doesn't really even achieve
+avalanche in c.
+
+This allows some parallelism. Read-after-writes are good at doubling
+the number of bits affected, so the goal of mixing pulls in the opposite
+direction as the goal of parallelism. I did what I could. Rotates
+seem to cost as much as shifts on every machine I could lay my hands
+on, and rotates are much kinder to the top and bottom bits, so I used
+rotates.
+-------------------------------------------------------------------------------
+*/
+#define mix(a,b,c) \
+{ \
+ a -= c; a ^= rot(c, 4); c += b; \
+ b -= a; b ^= rot(a, 6); a += c; \
+ c -= b; c ^= rot(b, 8); b += a; \
+ a -= c; a ^= rot(c,16); c += b; \
+ b -= a; b ^= rot(a,19); a += c; \
+ c -= b; c ^= rot(b, 4); b += a; \
+}
+
+/*
+-------------------------------------------------------------------------------
+final -- final mixing of 3 32-bit values (a,b,c) into c
+
+Pairs of (a,b,c) values differing in only a few bits will usually
+produce values of c that look totally different. This was tested for
+* pairs that differed by one bit, by two bits, in any combination
+ of top bits of (a,b,c), or in any combination of bottom bits of
+ (a,b,c).
+* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed
+ the output delta to a Gray code (a^(a>>1)) so a string of 1's (as
+ is commonly produced by subtraction) look like a single 1-bit
+ difference.
+* the base values were pseudorandom, all zero but one bit set, or
+ all zero plus a counter that starts at zero.
+
+These constants passed:
+ 14 11 25 16 4 14 24
+ 12 14 25 16 4 14 24
+and these came close:
+ 4 8 15 26 3 22 24
+ 10 8 15 26 3 22 24
+ 11 8 15 26 3 22 24
+-------------------------------------------------------------------------------
+*/
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+
+/*
+--------------------------------------------------------------------
+ This works on all machines. To be useful, it requires
+ -- that the key be an array of uint32_t's, and
+ -- that the length be the number of uint32_t's in the key
+
+ The function hashword() is identical to hashlittle() on little-endian
+ machines, and identical to hashbig() on big-endian machines,
+ except that the length has to be measured in uint32_ts rather than in
+ bytes. hashlittle() is more complicated than hashword() only because
+ hashlittle() has to dance around fitting the key bytes into registers.
+--------------------------------------------------------------------
+*/
+uint32_t hashword(
+const uint32_t *k, /* the key, an array of uint32_t values */
+size_t length, /* the length of the key, in uint32_ts */
+uint32_t initval) /* the previous hash, or an arbitrary value */
+{
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = raninit + (((uint32_t)length)<<2) + initval;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 uint32_t's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ case 2 : b+=k[1];
+ case 1 : a+=k[0];
+ final(a,b,c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ return c;
+}
+
+
+#ifdef SELF_TEST
+
+/*
+--------------------------------------------------------------------
+hashword2() -- same as hashword(), but take two seeds and return two
+32-bit values. pc and pb must both be nonnull, and *pc and *pb must
+both be initialized with seeds. If you pass in (*pb)==0, the output
+(*pc) will be the same as the return value from hashword().
+--------------------------------------------------------------------
+*/
+void hashword2 (
+const uint32_t *k, /* the key, an array of uint32_t values */
+size_t length, /* the length of the key, in uint32_ts */
+uint32_t *pc, /* IN: seed OUT: primary hash value */
+uint32_t *pb) /* IN: more seed OUT: secondary hash value */
+{
+ uint32_t a,b,c;
+
+ /* Set up the internal state */
+ a = b = c = raninit + ((uint32_t)(length<<2)) + *pc;
+ c += *pb;
+
+ /*------------------------------------------------- handle most of the key */
+ while (length > 3)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 3;
+ k += 3;
+ }
+
+ /*------------------------------------------- handle the last 3 uint32_t's */
+ switch(length) /* all the case statements fall through */
+ {
+ case 3 : c+=k[2];
+ case 2 : b+=k[1];
+ case 1 : a+=k[0];
+ final(a,b,c);
+ case 0: /* case 0: nothing left to add */
+ break;
+ }
+ /*------------------------------------------------------ report the result */
+ *pc=c; *pb=b;
+}
+
+#endif /* SELF_TEST */
+
+/*
+-------------------------------------------------------------------------------
+hashlittle() -- hash a variable-length key into a 32-bit value
+ k : the key (the unaligned variable-length array of bytes)
+ length : the length of the key, counting by bytes
+ initval : can be any 4-byte value
+Returns a 32-bit value. Every bit of the key affects every bit of
+the return value. Two keys differing by one or two bits will have
+totally different hash values.
+
+The best hash table sizes are powers of 2. There is no need to do
+mod a prime (mod is sooo slow!). If you need less than 32 bits,
+use a bitmask. For example, if you need only 10 bits, do
+ h = (h & hashmask(10));
+In which case, the hash table should have hashsize(10) elements.
+
+If you are hashing n strings (uint8_t **)k, do it like this:
+ for (i=0, h=0; i<n; ++i) h = hashlittle( k[i], len[i], h);
+
+By Bob Jenkins, 2006. bob_jenkins@burtleburtle.net. You may use this
+code any way you wish, private, educational, or commercial. It's free.
+
+Use for hash table lookup, or anything where one collision in 2^^32 is
+acceptable. Do NOT use for cryptographic purposes.
+-------------------------------------------------------------------------------
+*/
+
+uint32_t hashlittle( const void *key, size_t length, uint32_t initval)
+{
+ uint32_t a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = raninit + ((uint32_t)length) + initval;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+#ifdef VALGRIND
+ const uint8_t *k8;
+#endif
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : return c;
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : return c; /* zero length requires no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((uint32_t)k[11])<<24;
+ case 11: c+=((uint32_t)k[10])<<16;
+ case 10: c+=((uint32_t)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t)k[7])<<24;
+ case 7 : b+=((uint32_t)k[6])<<16;
+ case 6 : b+=((uint32_t)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3])<<24;
+ case 3 : a+=((uint32_t)k[2])<<16;
+ case 2 : a+=((uint32_t)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
+
+#ifdef SELF_TEST
+
+/*
+ * hashlittle2: return 2 32-bit hash values
+ *
+ * This is identical to hashlittle(), except it returns two 32-bit hash
+ * values instead of just one. This is good enough for hash table
+ * lookup with 2^^64 buckets, or if you want a second hash if you're not
+ * happy with the first, or if you want a probably-unique 64-bit ID for
+ * the key. *pc is better mixed than *pb, so use *pc first. If you want
+ * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)".
+ */
+void hashlittle2(
+ const void *key, /* the key to hash */
+ size_t length, /* length of the key */
+ uint32_t *pc, /* IN: primary initval, OUT: primary hash */
+ uint32_t *pb) /* IN: secondary initval, OUT: secondary hash */
+{
+ uint32_t a,b,c; /* internal state */
+ union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
+
+ /* Set up the internal state */
+ a = b = c = raninit + ((uint32_t)length) + *pc;
+ c += *pb;
+
+ u.ptr = key;
+ if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+#ifdef VALGRIND
+ const uint8_t *k8;
+#endif
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]&0xffffff" actually reads beyond the end of the string, but
+ * then masks off the part it's not allowed to read. Because the
+ * string is aligned, the masked-off tail is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff; break;
+ case 2 : a+=k[0]&0xffff; break;
+ case 1 : a+=k[0]&0xff; break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<8; /* fall through */
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */
+ case 1 : a+=k8[0]; break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+#endif /* !valgrind */
+
+ } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) {
+ const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */
+ const uint8_t *k8;
+
+ /*--------------- all but last block: aligned reads and different mixing */
+ while (length > 12)
+ {
+ a += k[0] + (((uint32_t)k[1])<<16);
+ b += k[2] + (((uint32_t)k[3])<<16);
+ c += k[4] + (((uint32_t)k[5])<<16);
+ mix(a,b,c);
+ length -= 12;
+ k += 6;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ k8 = (const uint8_t *)k;
+ switch(length)
+ {
+ case 12: c+=k[4]+(((uint32_t)k[5])<<16);
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 11: c+=((uint32_t)k8[10])<<16; /* fall through */
+ case 10: c+=k[4];
+ b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 9 : c+=k8[8]; /* fall through */
+ case 8 : b+=k[2]+(((uint32_t)k[3])<<16);
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */
+ case 6 : b+=k[2];
+ a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 5 : b+=k8[4]; /* fall through */
+ case 4 : a+=k[0]+(((uint32_t)k[1])<<16);
+ break;
+ case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */
+ case 2 : a+=k[0];
+ break;
+ case 1 : a+=k8[0];
+ break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ a += ((uint32_t)k[1])<<8;
+ a += ((uint32_t)k[2])<<16;
+ a += ((uint32_t)k[3])<<24;
+ b += k[4];
+ b += ((uint32_t)k[5])<<8;
+ b += ((uint32_t)k[6])<<16;
+ b += ((uint32_t)k[7])<<24;
+ c += k[8];
+ c += ((uint32_t)k[9])<<8;
+ c += ((uint32_t)k[10])<<16;
+ c += ((uint32_t)k[11])<<24;
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=((uint32_t)k[11])<<24;
+ case 11: c+=((uint32_t)k[10])<<16;
+ case 10: c+=((uint32_t)k[9])<<8;
+ case 9 : c+=k[8];
+ case 8 : b+=((uint32_t)k[7])<<24;
+ case 7 : b+=((uint32_t)k[6])<<16;
+ case 6 : b+=((uint32_t)k[5])<<8;
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3])<<24;
+ case 3 : a+=((uint32_t)k[2])<<16;
+ case 2 : a+=((uint32_t)k[1])<<8;
+ case 1 : a+=k[0];
+ break;
+ case 0 : *pc=c; *pb=b; return; /* zero length strings require no mixing */
+ }
+ }
+
+ final(a,b,c);
+ *pc=c; *pb=b;
+}
+
+#endif /* SELF_TEST */
+
+#if 0 /* currently not used */
+
+/*
+ * hashbig():
+ * This is the same as hashword() on big-endian machines. It is different
+ * from hashlittle() on all machines. hashbig() takes advantage of
+ * big-endian byte ordering.
+ */
+uint32_t hashbig( const void *key, size_t length, uint32_t initval)
+{
+ uint32_t a,b,c;
+ union { const void *ptr; size_t i; } u; /* to cast key to (size_t) happily */
+
+ /* Set up the internal state */
+ a = b = c = raninit + ((uint32_t)length) + initval;
+
+ u.ptr = key;
+ if (HASH_BIG_ENDIAN && ((u.i & 0x3) == 0)) {
+ const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */
+#ifdef VALGRIND
+ const uint8_t *k8;
+#endif
+
+ /*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += k[0];
+ b += k[1];
+ c += k[2];
+ mix(a,b,c);
+ length -= 12;
+ k += 3;
+ }
+
+ /*----------------------------- handle the last (probably partial) block */
+ /*
+ * "k[2]<<8" actually reads beyond the end of the string, but
+ * then shifts out the part it's not allowed to read. Because the
+ * string is aligned, the illegal read is in the same word as the
+ * rest of the string. Every machine with memory protection I've seen
+ * does it on word boundaries, so is OK with this. But VALGRIND will
+ * still catch it and complain. The masking trick does make the hash
+ * noticably faster for short strings (like English words).
+ */
+#ifndef VALGRIND
+
+ switch(length)
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=k[2]&0xffffff00; b+=k[1]; a+=k[0]; break;
+ case 10: c+=k[2]&0xffff0000; b+=k[1]; a+=k[0]; break;
+ case 9 : c+=k[2]&0xff000000; b+=k[1]; a+=k[0]; break;
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=k[1]&0xffffff00; a+=k[0]; break;
+ case 6 : b+=k[1]&0xffff0000; a+=k[0]; break;
+ case 5 : b+=k[1]&0xff000000; a+=k[0]; break;
+ case 4 : a+=k[0]; break;
+ case 3 : a+=k[0]&0xffffff00; break;
+ case 2 : a+=k[0]&0xffff0000; break;
+ case 1 : a+=k[0]&0xff000000; break;
+ case 0 : return c; /* zero length strings require no mixing */
+ }
+
+#else /* make valgrind happy */
+
+ k8 = (const uint8_t *)k;
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
+ case 11: c+=((uint32_t)k8[10])<<8; /* fall through */
+ case 10: c+=((uint32_t)k8[9])<<16; /* fall through */
+ case 9 : c+=((uint32_t)k8[8])<<24; /* fall through */
+ case 8 : b+=k[1]; a+=k[0]; break;
+ case 7 : b+=((uint32_t)k8[6])<<8; /* fall through */
+ case 6 : b+=((uint32_t)k8[5])<<16; /* fall through */
+ case 5 : b+=((uint32_t)k8[4])<<24; /* fall through */
+ case 4 : a+=k[0]; break;
+ case 3 : a+=((uint32_t)k8[2])<<8; /* fall through */
+ case 2 : a+=((uint32_t)k8[1])<<16; /* fall through */
+ case 1 : a+=((uint32_t)k8[0])<<24; break;
+ case 0 : return c;
+ }
+
+#endif /* !VALGRIND */
+
+ } else { /* need to read the key one byte at a time */
+ const uint8_t *k = (const uint8_t *)key;
+
+ /*--------------- all but the last block: affect some 32 bits of (a,b,c) */
+ while (length > 12)
+ {
+ a += ((uint32_t)k[0])<<24;
+ a += ((uint32_t)k[1])<<16;
+ a += ((uint32_t)k[2])<<8;
+ a += ((uint32_t)k[3]);
+ b += ((uint32_t)k[4])<<24;
+ b += ((uint32_t)k[5])<<16;
+ b += ((uint32_t)k[6])<<8;
+ b += ((uint32_t)k[7]);
+ c += ((uint32_t)k[8])<<24;
+ c += ((uint32_t)k[9])<<16;
+ c += ((uint32_t)k[10])<<8;
+ c += ((uint32_t)k[11]);
+ mix(a,b,c);
+ length -= 12;
+ k += 12;
+ }
+
+ /*-------------------------------- last block: affect all 32 bits of (c) */
+ switch(length) /* all the case statements fall through */
+ {
+ case 12: c+=k[11];
+ case 11: c+=((uint32_t)k[10])<<8;
+ case 10: c+=((uint32_t)k[9])<<16;
+ case 9 : c+=((uint32_t)k[8])<<24;
+ case 8 : b+=k[7];
+ case 7 : b+=((uint32_t)k[6])<<8;
+ case 6 : b+=((uint32_t)k[5])<<16;
+ case 5 : b+=((uint32_t)k[4])<<24;
+ case 4 : a+=k[3];
+ case 3 : a+=((uint32_t)k[2])<<8;
+ case 2 : a+=((uint32_t)k[1])<<16;
+ case 1 : a+=((uint32_t)k[0])<<24;
+ break;
+ case 0 : return c;
+ }
+ }
+
+ final(a,b,c);
+ return c;
+}
+
+#endif /* 0 == currently not used */
+
+#ifdef SELF_TEST
+
+/* used for timings */
+void driver1()
+{
+ uint8_t buf[256];
+ uint32_t i;
+ uint32_t h=0;
+ time_t a,z;
+
+ time(&a);
+ for (i=0; i<256; ++i) buf[i] = 'x';
+ for (i=0; i<1; ++i)
+ {
+ h = hashlittle(&buf[0],1,h);
+ }
+ time(&z);
+ if (z-a > 0) printf("time %d %.8x\n", z-a, h);
+}
+
+/* check that every input bit changes every output bit half the time */
+#define HASHSTATE 1
+#define HASHLEN 1
+#define MAXPAIR 60
+#define MAXLEN 70
+void driver2()
+{
+ uint8_t qa[MAXLEN+1], qb[MAXLEN+2], *a = &qa[0], *b = &qb[1];
+ uint32_t c[HASHSTATE], d[HASHSTATE], i=0, j=0, k, l, m=0, z;
+ uint32_t e[HASHSTATE],f[HASHSTATE],g[HASHSTATE],h[HASHSTATE];
+ uint32_t x[HASHSTATE],y[HASHSTATE];
+ uint32_t hlen;
+
+ printf("No more than %d trials should ever be needed \n",MAXPAIR/2);
+ for (hlen=0; hlen < MAXLEN; ++hlen)
+ {
+ z=0;
+ for (i=0; i<hlen; ++i) /*----------------------- for each input byte, */
+ {
+ for (j=0; j<8; ++j) /*------------------------ for each input bit, */
+ {
+ for (m=1; m<8; ++m) /*------------ for serveral possible initvals, */
+ {
+ for (l=0; l<HASHSTATE; ++l)
+ e[l]=f[l]=g[l]=h[l]=x[l]=y[l]=~((uint32_t)0);
+
+ /*---- check that every output bit is affected by that input bit */
+ for (k=0; k<MAXPAIR; k+=2)
+ {
+ uint32_t finished=1;
+ /* keys have one bit different */
+ for (l=0; l<hlen+1; ++l) {a[l] = b[l] = (uint8_t)0;}
+ /* have a and b be two keys differing in only one bit */
+ a[i] ^= (k<<j);
+ a[i] ^= (k>>(8-j));
+ c[0] = hashlittle(a, hlen, m);
+ b[i] ^= ((k+1)<<j);
+ b[i] ^= ((k+1)>>(8-j));
+ d[0] = hashlittle(b, hlen, m);
+ /* check every bit is 1, 0, set, and not set at least once */
+ for (l=0; l<HASHSTATE; ++l)
+ {
+ e[l] &= (c[l]^d[l]);
+ f[l] &= ~(c[l]^d[l]);
+ g[l] &= c[l];
+ h[l] &= ~c[l];
+ x[l] &= d[l];
+ y[l] &= ~d[l];
+ if (e[l]|f[l]|g[l]|h[l]|x[l]|y[l]) finished=0;
+ }
+ if (finished) break;
+ }
+ if (k>z) z=k;
+ if (k==MAXPAIR)
+ {
+ printf("Some bit didn't change: ");
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x ",
+ e[0],f[0],g[0],h[0],x[0],y[0]);
+ printf("i %d j %d m %d len %d\n", i, j, m, hlen);
+ }
+ if (z==MAXPAIR) goto done;
+ }
+ }
+ }
+ done:
+ if (z < MAXPAIR)
+ {
+ printf("Mix success %2d bytes %2d initvals ",i,m);
+ printf("required %d trials\n", z/2);
+ }
+ }
+ printf("\n");
+}
+
+/* Check for reading beyond the end of the buffer and alignment problems */
+void driver3()
+{
+ uint8_t buf[MAXLEN+20], *b;
+ uint32_t len;
+ uint8_t q[] = "This is the time for all good men to come to the aid of their country...";
+ uint32_t h;
+ uint8_t qq[] = "xThis is the time for all good men to come to the aid of their country...";
+ uint32_t i;
+ uint8_t qqq[] = "xxThis is the time for all good men to come to the aid of their country...";
+ uint32_t j;
+ uint8_t qqqq[] = "xxxThis is the time for all good men to come to the aid of their country...";
+ uint32_t ref,x,y;
+ uint8_t *p;
+
+ printf("Endianness. These lines should all be the same (for values filled in):\n");
+ printf("%.8x %.8x %.8x\n",
+ hashword((const uint32_t *)q, (sizeof(q)-1)/4, 13),
+ hashword((const uint32_t *)q, (sizeof(q)-5)/4, 13),
+ hashword((const uint32_t *)q, (sizeof(q)-9)/4, 13));
+ p = q;
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qq[1];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qqq[2];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ p = &qqqq[3];
+ printf("%.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x %.8x\n",
+ hashlittle(p, sizeof(q)-1, 13), hashlittle(p, sizeof(q)-2, 13),
+ hashlittle(p, sizeof(q)-3, 13), hashlittle(p, sizeof(q)-4, 13),
+ hashlittle(p, sizeof(q)-5, 13), hashlittle(p, sizeof(q)-6, 13),
+ hashlittle(p, sizeof(q)-7, 13), hashlittle(p, sizeof(q)-8, 13),
+ hashlittle(p, sizeof(q)-9, 13), hashlittle(p, sizeof(q)-10, 13),
+ hashlittle(p, sizeof(q)-11, 13), hashlittle(p, sizeof(q)-12, 13));
+ printf("\n");
+
+ /* check that hashlittle2 and hashlittle produce the same results */
+ i=47; j=0;
+ hashlittle2(q, sizeof(q), &i, &j);
+ if (hashlittle(q, sizeof(q), 47) != i)
+ printf("hashlittle2 and hashlittle mismatch\n");
+
+ /* check that hashword2 and hashword produce the same results */
+ len = raninit;
+ i=47, j=0;
+ hashword2(&len, 1, &i, &j);
+ if (hashword(&len, 1, 47) != i)
+ printf("hashword2 and hashword mismatch %x %x\n",
+ i, hashword(&len, 1, 47));
+
+ /* check hashlittle doesn't read before or after the ends of the string */
+ for (h=0, b=buf+1; h<8; ++h, ++b)
+ {
+ for (i=0; i<MAXLEN; ++i)
+ {
+ len = i;
+ for (j=0; j<i; ++j) *(b+j)=0;
+
+ /* these should all be equal */
+ ref = hashlittle(b, len, (uint32_t)1);
+ *(b+i)=(uint8_t)~0;
+ *(b-1)=(uint8_t)~0;
+ x = hashlittle(b, len, (uint32_t)1);
+ y = hashlittle(b, len, (uint32_t)1);
+ if ((ref != x) || (ref != y))
+ {
+ printf("alignment error: %.8x %.8x %.8x %d %d\n",ref,x,y,
+ h, i);
+ }
+ }
+ }
+}
+
+/* check for problems with nulls */
+ void driver4()
+{
+ uint8_t buf[1];
+ uint32_t h,i,state[HASHSTATE];
+
+
+ buf[0] = ~0;
+ for (i=0; i<HASHSTATE; ++i) state[i] = 1;
+ printf("These should all be different\n");
+ for (i=0, h=0; i<8; ++i)
+ {
+ h = hashlittle(buf, 0, h);
+ printf("%2ld 0-byte strings, hash is %.8x\n", i, h);
+ }
+}
+
+
+int main()
+{
+ driver1(); /* test that the key is hashed: used for timings */
+ driver2(); /* test that whole key is hashed thoroughly */
+ driver3(); /* test that nothing but the key is hashed */
+ driver4(); /* test hashing multiple buffers (all buffers are null) */
+ return 1;
+}
+
+#endif /* SELF_TEST */
diff --git a/external/unbound/util/storage/lookup3.h b/external/unbound/util/storage/lookup3.h
new file mode 100644
index 000000000..59dad7c48
--- /dev/null
+++ b/external/unbound/util/storage/lookup3.h
@@ -0,0 +1,71 @@
+/*
+ * util/storage/lookup3.h - header file for hashing functions.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 header definitions for the hash functions we use.
+ * The hash functions are public domain (see lookup3.c).
+ */
+
+#ifndef UTIL_STORAGE_LOOKUP3_H
+#define UTIL_STORAGE_LOOKUP3_H
+
+/**
+ * Hash key made of 4byte chunks.
+ * @param k: the key, an array of uint32_t values
+ * @param length: the length of the key, in uint32_ts
+ * @param initval: the previous hash, or an arbitrary value
+ * @return: hash value.
+ */
+uint32_t hashword(const uint32_t *k, size_t length, uint32_t initval);
+
+/**
+ * Hash key data.
+ * @param k: the key, array of uint8_t
+ * @param length: the length of the key, in uint8_ts
+ * @param initval: the previous hash, or an arbitrary value
+ * @return: hash value.
+ */
+uint32_t hashlittle(const void *k, size_t length, uint32_t initval);
+
+/**
+ * Set the randomisation initial value, set this before threads start,
+ * and before hashing stuff (because it changes subsequent results).
+ * @param v: value
+ */
+void hash_set_raninit(uint32_t v);
+
+#endif /* UTIL_STORAGE_LOOKUP3_H */
diff --git a/external/unbound/util/storage/lruhash.c b/external/unbound/util/storage/lruhash.c
new file mode 100644
index 000000000..2c987a2e5
--- /dev/null
+++ b/external/unbound/util/storage/lruhash.c
@@ -0,0 +1,544 @@
+/*
+ * util/storage/lruhash.c - hashtable, hash function, LRU keeping.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 a hashtable with LRU keeping of entries.
+ *
+ */
+
+#include "config.h"
+#include "util/storage/lruhash.h"
+#include "util/fptr_wlist.h"
+
+void
+bin_init(struct lruhash_bin* array, size_t size)
+{
+ size_t i;
+#ifdef THREADS_DISABLED
+ (void)array;
+#endif
+ for(i=0; i<size; i++) {
+ lock_quick_init(&array[i].lock);
+ lock_protect(&array[i].lock, &array[i],
+ sizeof(struct lruhash_bin));
+ }
+}
+
+struct lruhash*
+lruhash_create(size_t start_size, size_t maxmem, lruhash_sizefunc_t sizefunc,
+ lruhash_compfunc_t compfunc, lruhash_delkeyfunc_t delkeyfunc,
+ lruhash_deldatafunc_t deldatafunc, void* arg)
+{
+ struct lruhash* table = (struct lruhash*)calloc(1,
+ sizeof(struct lruhash));
+ if(!table)
+ return NULL;
+ lock_quick_init(&table->lock);
+ table->sizefunc = sizefunc;
+ table->compfunc = compfunc;
+ table->delkeyfunc = delkeyfunc;
+ table->deldatafunc = deldatafunc;
+ table->cb_arg = arg;
+ table->size = start_size;
+ table->size_mask = (int)(start_size-1);
+ table->lru_start = NULL;
+ table->lru_end = NULL;
+ table->num = 0;
+ table->space_used = 0;
+ table->space_max = maxmem;
+ table->array = calloc(table->size, sizeof(struct lruhash_bin));
+ if(!table->array) {
+ lock_quick_destroy(&table->lock);
+ free(table);
+ return NULL;
+ }
+ bin_init(table->array, table->size);
+ lock_protect(&table->lock, table, sizeof(*table));
+ lock_protect(&table->lock, table->array,
+ table->size*sizeof(struct lruhash_bin));
+ return table;
+}
+
+void
+bin_delete(struct lruhash* table, struct lruhash_bin* bin)
+{
+ struct lruhash_entry* p, *np;
+ void *d;
+ if(!bin)
+ return;
+ lock_quick_destroy(&bin->lock);
+ p = bin->overflow_list;
+ bin->overflow_list = NULL;
+ while(p) {
+ np = p->overflow_next;
+ d = p->data;
+ (*table->delkeyfunc)(p->key, table->cb_arg);
+ (*table->deldatafunc)(d, table->cb_arg);
+ p = np;
+ }
+}
+
+void
+bin_split(struct lruhash* table, struct lruhash_bin* newa,
+ int newmask)
+{
+ size_t i;
+ struct lruhash_entry *p, *np;
+ struct lruhash_bin* newbin;
+ /* move entries to new table. Notice that since hash x is mapped to
+ * bin x & mask, and new mask uses one more bit, so all entries in
+ * one bin will go into the old bin or bin | newbit */
+#ifndef THREADS_DISABLED
+ int newbit = newmask - table->size_mask;
+#endif
+ /* so, really, this task could also be threaded, per bin. */
+ /* LRU list is not changed */
+ for(i=0; i<table->size; i++)
+ {
+ lock_quick_lock(&table->array[i].lock);
+ p = table->array[i].overflow_list;
+ /* lock both destination bins */
+ lock_quick_lock(&newa[i].lock);
+ lock_quick_lock(&newa[newbit|i].lock);
+ while(p) {
+ np = p->overflow_next;
+ /* link into correct new bin */
+ newbin = &newa[p->hash & newmask];
+ p->overflow_next = newbin->overflow_list;
+ newbin->overflow_list = p;
+ p=np;
+ }
+ lock_quick_unlock(&newa[i].lock);
+ lock_quick_unlock(&newa[newbit|i].lock);
+ lock_quick_unlock(&table->array[i].lock);
+ }
+}
+
+void
+lruhash_delete(struct lruhash* table)
+{
+ size_t i;
+ if(!table)
+ return;
+ /* delete lock on hashtable to force check its OK */
+ lock_quick_destroy(&table->lock);
+ for(i=0; i<table->size; i++)
+ bin_delete(table, &table->array[i]);
+ free(table->array);
+ free(table);
+}
+
+void
+bin_overflow_remove(struct lruhash_bin* bin, struct lruhash_entry* entry)
+{
+ struct lruhash_entry* p = bin->overflow_list;
+ struct lruhash_entry** prevp = &bin->overflow_list;
+ while(p) {
+ if(p == entry) {
+ *prevp = p->overflow_next;
+ return;
+ }
+ prevp = &p->overflow_next;
+ p = p->overflow_next;
+ }
+}
+
+void
+reclaim_space(struct lruhash* table, struct lruhash_entry** list)
+{
+ struct lruhash_entry* d;
+ struct lruhash_bin* bin;
+ log_assert(table);
+ /* does not delete MRU entry, so table will not be empty. */
+ while(table->num > 1 && table->space_used > table->space_max) {
+ /* notice that since we hold the hashtable lock, nobody
+ can change the lru chain. So it cannot be deleted underneath
+ us. We still need the hashbin and entry write lock to make
+ sure we flush all users away from the entry.
+ which is unlikely, since it is LRU, if someone got a rdlock
+ it would be moved to front, but to be sure. */
+ d = table->lru_end;
+ /* specialised, delete from end of double linked list,
+ and we know num>1, so there is a previous lru entry. */
+ log_assert(d && d->lru_prev);
+ table->lru_end = d->lru_prev;
+ d->lru_prev->lru_next = NULL;
+ /* schedule entry for deletion */
+ bin = &table->array[d->hash & table->size_mask];
+ table->num --;
+ lock_quick_lock(&bin->lock);
+ bin_overflow_remove(bin, d);
+ d->overflow_next = *list;
+ *list = d;
+ lock_rw_wrlock(&d->lock);
+ table->space_used -= table->sizefunc(d->key, d->data);
+ if(table->markdelfunc)
+ (*table->markdelfunc)(d->key);
+ lock_rw_unlock(&d->lock);
+ lock_quick_unlock(&bin->lock);
+ }
+}
+
+struct lruhash_entry*
+bin_find_entry(struct lruhash* table,
+ struct lruhash_bin* bin, hashvalue_t hash, void* key)
+{
+ struct lruhash_entry* p = bin->overflow_list;
+ while(p) {
+ if(p->hash == hash && table->compfunc(p->key, key) == 0)
+ return p;
+ p = p->overflow_next;
+ }
+ return NULL;
+}
+
+void
+table_grow(struct lruhash* table)
+{
+ struct lruhash_bin* newa;
+ int newmask;
+ size_t i;
+ if(table->size_mask == (int)(((size_t)-1)>>1)) {
+ log_err("hash array malloc: size_t too small");
+ return;
+ }
+ /* try to allocate new array, if not fail */
+ newa = calloc(table->size*2, sizeof(struct lruhash_bin));
+ if(!newa) {
+ log_err("hash grow: malloc failed");
+ /* continue with smaller array. Though its slower. */
+ return;
+ }
+ bin_init(newa, table->size*2);
+ newmask = (table->size_mask << 1) | 1;
+ bin_split(table, newa, newmask);
+ /* delete the old bins */
+ lock_unprotect(&table->lock, table->array);
+ for(i=0; i<table->size; i++) {
+ lock_quick_destroy(&table->array[i].lock);
+ }
+ free(table->array);
+
+ table->size *= 2;
+ table->size_mask = newmask;
+ table->array = newa;
+ lock_protect(&table->lock, table->array,
+ table->size*sizeof(struct lruhash_bin));
+ return;
+}
+
+void
+lru_front(struct lruhash* table, struct lruhash_entry* entry)
+{
+ entry->lru_prev = NULL;
+ entry->lru_next = table->lru_start;
+ if(!table->lru_start)
+ table->lru_end = entry;
+ else table->lru_start->lru_prev = entry;
+ table->lru_start = entry;
+}
+
+void
+lru_remove(struct lruhash* table, struct lruhash_entry* entry)
+{
+ if(entry->lru_prev)
+ entry->lru_prev->lru_next = entry->lru_next;
+ else table->lru_start = entry->lru_next;
+ if(entry->lru_next)
+ entry->lru_next->lru_prev = entry->lru_prev;
+ else table->lru_end = entry->lru_prev;
+}
+
+void
+lru_touch(struct lruhash* table, struct lruhash_entry* entry)
+{
+ log_assert(table && entry);
+ if(entry == table->lru_start)
+ return; /* nothing to do */
+ /* remove from current lru position */
+ lru_remove(table, entry);
+ /* add at front */
+ lru_front(table, entry);
+}
+
+void
+lruhash_insert(struct lruhash* table, hashvalue_t hash,
+ struct lruhash_entry* entry, void* data, void* cb_arg)
+{
+ struct lruhash_bin* bin;
+ struct lruhash_entry* found, *reclaimlist=NULL;
+ size_t need_size;
+ fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
+ fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
+ fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
+ fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
+ fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
+ need_size = table->sizefunc(entry->key, data);
+ if(cb_arg == NULL) cb_arg = table->cb_arg;
+
+ /* find bin */
+ lock_quick_lock(&table->lock);
+ bin = &table->array[hash & table->size_mask];
+ lock_quick_lock(&bin->lock);
+
+ /* see if entry exists already */
+ if(!(found=bin_find_entry(table, bin, hash, entry->key))) {
+ /* if not: add to bin */
+ entry->overflow_next = bin->overflow_list;
+ bin->overflow_list = entry;
+ lru_front(table, entry);
+ table->num++;
+ table->space_used += need_size;
+ } else {
+ /* if so: update data - needs a writelock */
+ table->space_used += need_size -
+ (*table->sizefunc)(found->key, found->data);
+ (*table->delkeyfunc)(entry->key, cb_arg);
+ lru_touch(table, found);
+ lock_rw_wrlock(&found->lock);
+ (*table->deldatafunc)(found->data, cb_arg);
+ found->data = data;
+ lock_rw_unlock(&found->lock);
+ }
+ lock_quick_unlock(&bin->lock);
+ if(table->space_used > table->space_max)
+ reclaim_space(table, &reclaimlist);
+ if(table->num >= table->size)
+ table_grow(table);
+ lock_quick_unlock(&table->lock);
+
+ /* finish reclaim if any (outside of critical region) */
+ while(reclaimlist) {
+ struct lruhash_entry* n = reclaimlist->overflow_next;
+ void* d = reclaimlist->data;
+ (*table->delkeyfunc)(reclaimlist->key, cb_arg);
+ (*table->deldatafunc)(d, cb_arg);
+ reclaimlist = n;
+ }
+}
+
+struct lruhash_entry*
+lruhash_lookup(struct lruhash* table, hashvalue_t hash, void* key, int wr)
+{
+ struct lruhash_entry* entry;
+ struct lruhash_bin* bin;
+ fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
+
+ lock_quick_lock(&table->lock);
+ bin = &table->array[hash & table->size_mask];
+ lock_quick_lock(&bin->lock);
+ if((entry=bin_find_entry(table, bin, hash, key)))
+ lru_touch(table, entry);
+ lock_quick_unlock(&table->lock);
+
+ if(entry) {
+ if(wr) { lock_rw_wrlock(&entry->lock); }
+ else { lock_rw_rdlock(&entry->lock); }
+ }
+ lock_quick_unlock(&bin->lock);
+ return entry;
+}
+
+void
+lruhash_remove(struct lruhash* table, hashvalue_t hash, void* key)
+{
+ struct lruhash_entry* entry;
+ struct lruhash_bin* bin;
+ void *d;
+ fptr_ok(fptr_whitelist_hash_sizefunc(table->sizefunc));
+ fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
+ fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
+ fptr_ok(fptr_whitelist_hash_compfunc(table->compfunc));
+ fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
+
+ lock_quick_lock(&table->lock);
+ bin = &table->array[hash & table->size_mask];
+ lock_quick_lock(&bin->lock);
+ if((entry=bin_find_entry(table, bin, hash, key))) {
+ bin_overflow_remove(bin, entry);
+ lru_remove(table, entry);
+ } else {
+ lock_quick_unlock(&table->lock);
+ lock_quick_unlock(&bin->lock);
+ return;
+ }
+ table->num--;
+ table->space_used -= (*table->sizefunc)(entry->key, entry->data);
+ lock_quick_unlock(&table->lock);
+ lock_rw_wrlock(&entry->lock);
+ if(table->markdelfunc)
+ (*table->markdelfunc)(entry->key);
+ lock_rw_unlock(&entry->lock);
+ lock_quick_unlock(&bin->lock);
+ /* finish removal */
+ d = entry->data;
+ (*table->delkeyfunc)(entry->key, table->cb_arg);
+ (*table->deldatafunc)(d, table->cb_arg);
+}
+
+/** clear bin, respecting locks, does not do space, LRU */
+static void
+bin_clear(struct lruhash* table, struct lruhash_bin* bin)
+{
+ struct lruhash_entry* p, *np;
+ void *d;
+ lock_quick_lock(&bin->lock);
+ p = bin->overflow_list;
+ while(p) {
+ lock_rw_wrlock(&p->lock);
+ np = p->overflow_next;
+ d = p->data;
+ if(table->markdelfunc)
+ (*table->markdelfunc)(p->key);
+ lock_rw_unlock(&p->lock);
+ (*table->delkeyfunc)(p->key, table->cb_arg);
+ (*table->deldatafunc)(d, table->cb_arg);
+ p = np;
+ }
+ bin->overflow_list = NULL;
+ lock_quick_unlock(&bin->lock);
+}
+
+void
+lruhash_clear(struct lruhash* table)
+{
+ size_t i;
+ if(!table)
+ return;
+ fptr_ok(fptr_whitelist_hash_delkeyfunc(table->delkeyfunc));
+ fptr_ok(fptr_whitelist_hash_deldatafunc(table->deldatafunc));
+ fptr_ok(fptr_whitelist_hash_markdelfunc(table->markdelfunc));
+
+ lock_quick_lock(&table->lock);
+ for(i=0; i<table->size; i++) {
+ bin_clear(table, &table->array[i]);
+ }
+ table->lru_start = NULL;
+ table->lru_end = NULL;
+ table->num = 0;
+ table->space_used = 0;
+ lock_quick_unlock(&table->lock);
+}
+
+void
+lruhash_status(struct lruhash* table, const char* id, int extended)
+{
+ lock_quick_lock(&table->lock);
+ log_info("%s: %u entries, memory %u / %u",
+ id, (unsigned)table->num, (unsigned)table->space_used,
+ (unsigned)table->space_max);
+ log_info(" itemsize %u, array %u, mask %d",
+ (unsigned)(table->num? table->space_used/table->num : 0),
+ (unsigned)table->size, table->size_mask);
+ if(extended) {
+ size_t i;
+ int min=(int)table->size*2, max=-2;
+ for(i=0; i<table->size; i++) {
+ int here = 0;
+ struct lruhash_entry *en;
+ lock_quick_lock(&table->array[i].lock);
+ en = table->array[i].overflow_list;
+ while(en) {
+ here ++;
+ en = en->overflow_next;
+ }
+ lock_quick_unlock(&table->array[i].lock);
+ if(extended >= 2)
+ log_info("bin[%d] %d", (int)i, here);
+ if(here > max) max = here;
+ if(here < min) min = here;
+ }
+ log_info(" bin min %d, avg %.2lf, max %d", min,
+ (double)table->num/(double)table->size, max);
+ }
+ lock_quick_unlock(&table->lock);
+}
+
+size_t
+lruhash_get_mem(struct lruhash* table)
+{
+ size_t s;
+ lock_quick_lock(&table->lock);
+ s = sizeof(struct lruhash) + table->space_used;
+#ifdef USE_THREAD_DEBUG
+ if(table->size != 0) {
+ size_t i;
+ for(i=0; i<table->size; i++)
+ s += sizeof(struct lruhash_bin) +
+ lock_get_mem(&table->array[i].lock);
+ }
+#else /* no THREAD_DEBUG */
+ if(table->size != 0)
+ s += (table->size)*(sizeof(struct lruhash_bin) +
+ lock_get_mem(&table->array[0].lock));
+#endif
+ lock_quick_unlock(&table->lock);
+ s += lock_get_mem(&table->lock);
+ return s;
+}
+
+void
+lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_t md)
+{
+ lock_quick_lock(&table->lock);
+ table->markdelfunc = md;
+ lock_quick_unlock(&table->lock);
+}
+
+void
+lruhash_traverse(struct lruhash* h, int wr,
+ void (*func)(struct lruhash_entry*, void*), void* arg)
+{
+ size_t i;
+ struct lruhash_entry* e;
+
+ lock_quick_lock(&h->lock);
+ for(i=0; i<h->size; i++) {
+ lock_quick_lock(&h->array[i].lock);
+ for(e = h->array[i].overflow_list; e; e = e->overflow_next) {
+ if(wr) {
+ lock_rw_wrlock(&e->lock);
+ } else {
+ lock_rw_rdlock(&e->lock);
+ }
+ (*func)(e, arg);
+ lock_rw_unlock(&e->lock);
+ }
+ lock_quick_unlock(&h->array[i].lock);
+ }
+ lock_quick_unlock(&h->lock);
+}
diff --git a/external/unbound/util/storage/lruhash.h b/external/unbound/util/storage/lruhash.h
new file mode 100644
index 000000000..30377d8e7
--- /dev/null
+++ b/external/unbound/util/storage/lruhash.h
@@ -0,0 +1,414 @@
+/*
+ * util/storage/lruhash.h - hashtable, hash function, LRU keeping.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 a hashtable with LRU keeping of entries.
+ *
+ * The hash table keeps a maximum memory size. Old entries are removed
+ * to make space for new entries.
+ *
+ * The locking strategy is as follows:
+ * o since (almost) every read also implies a LRU update, the
+ * hashtable lock is a spinlock, not rwlock.
+ * o the idea is to move every thread through the hash lock quickly,
+ * so that the next thread can access the lookup table.
+ * o User performs hash function.
+ *
+ * For read:
+ * o lock hashtable.
+ * o lookup hash bin.
+ * o lock hash bin.
+ * o find entry (if failed, unlock hash, unl bin, exit).
+ * o swizzle pointers for LRU update.
+ * o unlock hashtable.
+ * o lock entry (rwlock).
+ * o unlock hash bin.
+ * o work on entry.
+ * o unlock entry.
+ *
+ * To update an entry, gain writelock and change the entry.
+ * (the entry must keep the same hashvalue, so a data update.)
+ * (you cannot upgrade a readlock to a writelock, because the item may
+ * be deleted, it would cause race conditions. So instead, unlock and
+ * relookup it in the hashtable.)
+ *
+ * To delete an entry:
+ * o unlock the entry if you hold the lock already.
+ * o lock hashtable.
+ * o lookup hash bin.
+ * o lock hash bin.
+ * o find entry (if failed, unlock hash, unl bin, exit).
+ * o remove entry from hashtable bin overflow chain.
+ * o unlock hashtable.
+ * o lock entry (writelock).
+ * o unlock hash bin.
+ * o unlock entry (nobody else should be waiting for this lock,
+ * since you removed it from hashtable, and you got writelock while
+ * holding the hashbinlock so you are the only one.)
+ * Note you are only allowed to obtain a lock while holding hashbinlock.
+ * o delete entry.
+ *
+ * The above sequence is:
+ * o race free, works with read, write and delete.
+ * o but has a queue, imagine someone needing a writelock on an item.
+ * but there are still readlocks. The writelocker waits, but holds
+ * the hashbinlock. The next thread that comes in and needs the same
+ * hashbin will wait for the lock while holding the hashtable lock.
+ * thus halting the entire system on hashtable.
+ * This is because of the delete protection.
+ * Readlocks will be easier on the rwlock on entries.
+ * While the writer is holding writelock, similar problems happen with
+ * a reader or writer needing the same item.
+ * the scenario requires more than three threads.
+ * o so the queue length is 3 threads in a bad situation. The fourth is
+ * unable to use the hashtable.
+ *
+ * If you need to acquire locks on multiple items from the hashtable.
+ * o you MUST release all locks on items from the hashtable before
+ * doing the next lookup/insert/delete/whatever.
+ * o To acquire multiple items you should use a special routine that
+ * obtains the locks on those multiple items in one go.
+ */
+
+#ifndef UTIL_STORAGE_LRUHASH_H
+#define UTIL_STORAGE_LRUHASH_H
+#include "util/locks.h"
+struct lruhash_bin;
+struct lruhash_entry;
+
+/** default start size for hash arrays */
+#define HASH_DEFAULT_STARTARRAY 1024 /* entries in array */
+/** default max memory for hash arrays */
+#define HASH_DEFAULT_MAXMEM 4*1024*1024 /* bytes */
+
+/** the type of a hash value */
+typedef uint32_t hashvalue_t;
+
+/**
+ * Type of function that calculates the size of an entry.
+ * Result must include the size of struct lruhash_entry.
+ * Keys that are identical must also calculate to the same size.
+ * size = func(key, data).
+ */
+typedef size_t (*lruhash_sizefunc_t)(void*, void*);
+
+/** type of function that compares two keys. return 0 if equal. */
+typedef int (*lruhash_compfunc_t)(void*, void*);
+
+/** old keys are deleted.
+ * The RRset type has to revoke its ID number, markdel() is used first.
+ * This function is called: func(key, userarg) */
+typedef void (*lruhash_delkeyfunc_t)(void*, void*);
+
+/** old data is deleted. This function is called: func(data, userarg). */
+typedef void (*lruhash_deldatafunc_t)(void*, void*);
+
+/** mark a key as pending to be deleted (and not to be used by anyone).
+ * called: func(key) */
+typedef void (*lruhash_markdelfunc_t)(void*);
+
+/**
+ * Hash table that keeps LRU list of entries.
+ */
+struct lruhash {
+ /** lock for exclusive access, to the lookup array */
+ lock_quick_t lock;
+ /** the size function for entries in this table */
+ lruhash_sizefunc_t sizefunc;
+ /** the compare function for entries in this table. */
+ lruhash_compfunc_t compfunc;
+ /** how to delete keys. */
+ lruhash_delkeyfunc_t delkeyfunc;
+ /** how to delete data. */
+ lruhash_deldatafunc_t deldatafunc;
+ /** how to mark a key pending deletion */
+ lruhash_markdelfunc_t markdelfunc;
+ /** user argument for user functions */
+ void* cb_arg;
+
+ /** the size of the lookup array */
+ size_t size;
+ /** size bitmask - since size is a power of 2 */
+ int size_mask;
+ /** lookup array of bins */
+ struct lruhash_bin* array;
+
+ /** the lru list, start and end, noncyclical double linked list. */
+ struct lruhash_entry* lru_start;
+ /** lru list end item (least recently used) */
+ struct lruhash_entry* lru_end;
+
+ /** the number of entries in the hash table. */
+ size_t num;
+ /** the amount of space used, roughly the number of bytes in use. */
+ size_t space_used;
+ /** the amount of space the hash table is maximally allowed to use. */
+ size_t space_max;
+};
+
+/**
+ * A single bin with a linked list of entries in it.
+ */
+struct lruhash_bin {
+ /**
+ * Lock for exclusive access to the linked list
+ * This lock makes deletion of items safe in this overflow list.
+ */
+ lock_quick_t lock;
+ /** linked list of overflow entries */
+ struct lruhash_entry* overflow_list;
+};
+
+/**
+ * An entry into the hash table.
+ * To change overflow_next you need to hold the bin lock.
+ * To change the lru items you need to hold the hashtable lock.
+ * This structure is designed as part of key struct. And key pointer helps
+ * to get the surrounding structure. Data should be allocated on its own.
+ */
+struct lruhash_entry {
+ /**
+ * rwlock for access to the contents of the entry
+ * Note that it does _not_ cover the lru_ and overflow_ ptrs.
+ * Even with a writelock, you cannot change hash and key.
+ * You need to delete it to change hash or key.
+ */
+ lock_rw_t lock;
+ /** next entry in overflow chain. Covered by hashlock and binlock. */
+ struct lruhash_entry* overflow_next;
+ /** next entry in lru chain. covered by hashlock. */
+ struct lruhash_entry* lru_next;
+ /** prev entry in lru chain. covered by hashlock. */
+ struct lruhash_entry* lru_prev;
+ /** hash value of the key. It may not change, until entry deleted. */
+ hashvalue_t hash;
+ /** key */
+ void* key;
+ /** data */
+ void* data;
+};
+
+/**
+ * Create new hash table.
+ * @param start_size: size of hashtable array at start, must be power of 2.
+ * @param maxmem: maximum amount of memory this table is allowed to use.
+ * @param sizefunc: calculates memory usage of entries.
+ * @param compfunc: compares entries, 0 on equality.
+ * @param delkeyfunc: deletes key.
+ * Calling both delkey and deldata will also free the struct lruhash_entry.
+ * Make it part of the key structure and delete it in delkeyfunc.
+ * @param deldatafunc: deletes data.
+ * @param arg: user argument that is passed to user function calls.
+ * @return: new hash table or NULL on malloc failure.
+ */
+struct lruhash* lruhash_create(size_t start_size, size_t maxmem,
+ lruhash_sizefunc_t sizefunc, lruhash_compfunc_t compfunc,
+ lruhash_delkeyfunc_t delkeyfunc, lruhash_deldatafunc_t deldatafunc,
+ void* arg);
+
+/**
+ * Delete hash table. Entries are all deleted.
+ * @param table: to delete.
+ */
+void lruhash_delete(struct lruhash* table);
+
+/**
+ * Clear hash table. Entries are all deleted, while locking them before
+ * doing so. At end the table is empty.
+ * @param table: to make empty.
+ */
+void lruhash_clear(struct lruhash* table);
+
+/**
+ * Insert a new element into the hashtable.
+ * If key is already present data pointer in that entry is updated.
+ * The space calculation function is called with the key, data.
+ * If necessary the least recently used entries are deleted to make space.
+ * If necessary the hash array is grown up.
+ *
+ * @param table: hash table.
+ * @param hash: hash value. User calculates the hash.
+ * @param entry: identifies the entry.
+ * If key already present, this entry->key is deleted immediately.
+ * But entry->data is set to NULL before deletion, and put into
+ * the existing entry. The data is then freed.
+ * @param data: the data.
+ * @param cb_override: if not null overrides the cb_arg for the deletefunc.
+ */
+void lruhash_insert(struct lruhash* table, hashvalue_t hash,
+ struct lruhash_entry* entry, void* data, void* cb_override);
+
+/**
+ * Lookup an entry in the hashtable.
+ * At the end of the function you hold a (read/write)lock on the entry.
+ * The LRU is updated for the entry (if found).
+ * @param table: hash table.
+ * @param hash: hash of key.
+ * @param key: what to look for, compared against entries in overflow chain.
+ * the hash value must be set, and must work with compare function.
+ * @param wr: set to true if you desire a writelock on the entry.
+ * with a writelock you can update the data part.
+ * @return: pointer to the entry or NULL. The entry is locked.
+ * The user must unlock the entry when done.
+ */
+struct lruhash_entry* lruhash_lookup(struct lruhash* table, hashvalue_t hash,
+ void* key, int wr);
+
+/**
+ * Touch entry, so it becomes the most recently used in the LRU list.
+ * Caller must hold hash table lock. The entry must be inserted already.
+ * @param table: hash table.
+ * @param entry: entry to make first in LRU.
+ */
+void lru_touch(struct lruhash* table, struct lruhash_entry* entry);
+
+/**
+ * Set the markdelfunction (or NULL)
+ */
+void lruhash_setmarkdel(struct lruhash* table, lruhash_markdelfunc_t md);
+
+/************************* Internal functions ************************/
+/*** these are only exposed for unit tests. ***/
+
+/**
+ * Remove entry from hashtable. Does nothing if not found in hashtable.
+ * Delfunc is called for the entry.
+ * @param table: hash table.
+ * @param hash: hash of key.
+ * @param key: what to look for.
+ */
+void lruhash_remove(struct lruhash* table, hashvalue_t hash, void* key);
+
+/** init the hash bins for the table */
+void bin_init(struct lruhash_bin* array, size_t size);
+
+/** delete the hash bin and entries inside it */
+void bin_delete(struct lruhash* table, struct lruhash_bin* bin);
+
+/**
+ * Find entry in hash bin. You must have locked the bin.
+ * @param table: hash table with function pointers.
+ * @param bin: hash bin to look into.
+ * @param hash: hash value to look for.
+ * @param key: key to look for.
+ * @return: the entry or NULL if not found.
+ */
+struct lruhash_entry* bin_find_entry(struct lruhash* table,
+ struct lruhash_bin* bin, hashvalue_t hash, void* key);
+
+/**
+ * Remove entry from bin overflow chain.
+ * You must have locked the bin.
+ * @param bin: hash bin to look into.
+ * @param entry: entry ptr that needs removal.
+ */
+void bin_overflow_remove(struct lruhash_bin* bin,
+ struct lruhash_entry* entry);
+
+/**
+ * Split hash bin into two new ones. Based on increased size_mask.
+ * Caller must hold hash table lock.
+ * At the end the routine acquires all hashbin locks (in the old array).
+ * This makes it wait for other threads to finish with the bins.
+ * So the bins are ready to be deleted after this function.
+ * @param table: hash table with function pointers.
+ * @param newa: new increased array.
+ * @param newmask: new lookup mask.
+ */
+void bin_split(struct lruhash* table, struct lruhash_bin* newa,
+ int newmask);
+
+/**
+ * Try to make space available by deleting old entries.
+ * Assumes that the lock on the hashtable is being held by caller.
+ * Caller must not hold bin locks.
+ * @param table: hash table.
+ * @param list: list of entries that are to be deleted later.
+ * Entries have been removed from the hash table and writelock is held.
+ */
+void reclaim_space(struct lruhash* table, struct lruhash_entry** list);
+
+/**
+ * Grow the table lookup array. Becomes twice as large.
+ * Caller must hold the hash table lock. Must not hold any bin locks.
+ * Tries to grow, on malloc failure, nothing happened.
+ * @param table: hash table.
+ */
+void table_grow(struct lruhash* table);
+
+/**
+ * Put entry at front of lru. entry must be unlinked from lru.
+ * Caller must hold hash table lock.
+ * @param table: hash table with lru head and tail.
+ * @param entry: entry to make most recently used.
+ */
+void lru_front(struct lruhash* table, struct lruhash_entry* entry);
+
+/**
+ * Remove entry from lru list.
+ * Caller must hold hash table lock.
+ * @param table: hash table with lru head and tail.
+ * @param entry: entry to remove from lru.
+ */
+void lru_remove(struct lruhash* table, struct lruhash_entry* entry);
+
+/**
+ * Output debug info to the log as to state of the hash table.
+ * @param table: hash table.
+ * @param id: string printed with table to identify the hash table.
+ * @param extended: set to true to print statistics on overflow bin lengths.
+ */
+void lruhash_status(struct lruhash* table, const char* id, int extended);
+
+/**
+ * Get memory in use now by the lruhash table.
+ * @param table: hash table. Will be locked before use. And unlocked after.
+ * @return size in bytes.
+ */
+size_t lruhash_get_mem(struct lruhash* table);
+
+/**
+ * Traverse a lruhash. Call back for every element in the table.
+ * @param h: hash table. Locked before use.
+ * @param wr: if true writelock is obtained on element, otherwise readlock.
+ * @param func: function for every element. Do not lock or unlock elements.
+ * @param arg: user argument to func.
+ */
+void lruhash_traverse(struct lruhash* h, int wr,
+ void (*func)(struct lruhash_entry*, void*), void* arg);
+
+#endif /* UTIL_STORAGE_LRUHASH_H */
diff --git a/external/unbound/util/storage/slabhash.c b/external/unbound/util/storage/slabhash.c
new file mode 100644
index 000000000..0618b4c72
--- /dev/null
+++ b/external/unbound/util/storage/slabhash.c
@@ -0,0 +1,231 @@
+/*
+ * util/storage/slabhash.c - hashtable consisting of several smaller tables.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ *
+ * Implementation of hash table that consists of smaller hash tables.
+ * This results in a partitioned lruhash table.
+ * It cannot grow, but that gives it the ability to have multiple
+ * locks. Also this means there are multiple LRU lists.
+ */
+
+#include "config.h"
+#include "util/storage/slabhash.h"
+
+struct slabhash* slabhash_create(size_t numtables, size_t start_size,
+ size_t maxmem, lruhash_sizefunc_t sizefunc,
+ lruhash_compfunc_t compfunc, lruhash_delkeyfunc_t delkeyfunc,
+ lruhash_deldatafunc_t deldatafunc, void* arg)
+{
+ size_t i;
+ struct slabhash* sl = (struct slabhash*)calloc(1,
+ sizeof(struct slabhash));
+ if(!sl) return NULL;
+ sl->size = numtables;
+ log_assert(sl->size > 0);
+ sl->array = (struct lruhash**)calloc(sl->size, sizeof(struct lruhash*));
+ if(!sl->array) {
+ free(sl);
+ return NULL;
+ }
+ sl->mask = (uint32_t)(sl->size - 1);
+ if(sl->mask == 0) {
+ sl->shift = 0;
+ } else {
+ log_assert( (sl->size & sl->mask) == 0
+ /* size must be power of 2 */ );
+ sl->shift = 0;
+ while(!(sl->mask & 0x80000000)) {
+ sl->mask <<= 1;
+ sl->shift ++;
+ }
+ }
+ for(i=0; i<sl->size; i++) {
+ sl->array[i] = lruhash_create(start_size, maxmem / sl->size,
+ sizefunc, compfunc, delkeyfunc, deldatafunc, arg);
+ if(!sl->array[i]) {
+ slabhash_delete(sl);
+ return NULL;
+ }
+ }
+ return sl;
+}
+
+void slabhash_delete(struct slabhash* sl)
+{
+ if(!sl)
+ return;
+ if(sl->array) {
+ size_t i;
+ for(i=0; i<sl->size; i++)
+ lruhash_delete(sl->array[i]);
+ free(sl->array);
+ }
+ free(sl);
+}
+
+void slabhash_clear(struct slabhash* sl)
+{
+ size_t i;
+ if(!sl)
+ return;
+ for(i=0; i<sl->size; i++)
+ lruhash_clear(sl->array[i]);
+}
+
+/** helper routine to calculate the slabhash index */
+static unsigned int
+slab_idx(struct slabhash* sl, hashvalue_t hash)
+{
+ return ((hash & sl->mask) >> sl->shift);
+}
+
+void slabhash_insert(struct slabhash* sl, hashvalue_t hash,
+ struct lruhash_entry* entry, void* data, void* arg)
+{
+ lruhash_insert(sl->array[slab_idx(sl, hash)], hash, entry, data, arg);
+}
+
+struct lruhash_entry* slabhash_lookup(struct slabhash* sl,
+ hashvalue_t hash, void* key, int wr)
+{
+ return lruhash_lookup(sl->array[slab_idx(sl, hash)], hash, key, wr);
+}
+
+void slabhash_remove(struct slabhash* sl, hashvalue_t hash, void* key)
+{
+ lruhash_remove(sl->array[slab_idx(sl, hash)], hash, key);
+}
+
+void slabhash_status(struct slabhash* sl, const char* id, int extended)
+{
+ size_t i;
+ char num[17];
+ log_info("Slabhash %s: %u tables mask=%x shift=%d",
+ id, (unsigned)sl->size, (unsigned)sl->mask, sl->shift);
+ for(i=0; i<sl->size; i++) {
+ snprintf(num, sizeof(num), "table %u", (unsigned)i);
+ lruhash_status(sl->array[i], num, extended);
+ }
+}
+
+size_t slabhash_get_size(struct slabhash* sl)
+{
+ size_t i, total = 0;
+ for(i=0; i<sl->size; i++) {
+ lock_quick_lock(&sl->array[i]->lock);
+ total += sl->array[i]->space_max;
+ lock_quick_unlock(&sl->array[i]->lock);
+ }
+ return total;
+}
+
+size_t slabhash_get_mem(struct slabhash* sl)
+{
+ size_t i, total = sizeof(*sl);
+ total += sizeof(struct lruhash*)*sl->size;
+ for(i=0; i<sl->size; i++) {
+ total += lruhash_get_mem(sl->array[i]);
+ }
+ return total;
+}
+
+struct lruhash* slabhash_gettable(struct slabhash* sl, hashvalue_t hash)
+{
+ return sl->array[slab_idx(sl, hash)];
+}
+
+/* test code, here to avoid linking problems with fptr_wlist */
+/** delete key */
+static void delkey(struct slabhash_testkey* k) {
+ lock_rw_destroy(&k->entry.lock); free(k);}
+/** delete data */
+static void deldata(struct slabhash_testdata* d) {free(d);}
+
+size_t test_slabhash_sizefunc(void* ATTR_UNUSED(key), void* ATTR_UNUSED(data))
+{
+ return sizeof(struct slabhash_testkey) +
+ sizeof(struct slabhash_testdata);
+}
+
+int test_slabhash_compfunc(void* key1, void* key2)
+{
+ struct slabhash_testkey* k1 = (struct slabhash_testkey*)key1;
+ struct slabhash_testkey* k2 = (struct slabhash_testkey*)key2;
+ if(k1->id == k2->id)
+ return 0;
+ if(k1->id > k2->id)
+ return 1;
+ return -1;
+}
+
+void test_slabhash_delkey(void* key, void* ATTR_UNUSED(arg))
+{
+ delkey((struct slabhash_testkey*)key);
+}
+
+void test_slabhash_deldata(void* data, void* ATTR_UNUSED(arg))
+{
+ deldata((struct slabhash_testdata*)data);
+}
+
+void slabhash_setmarkdel(struct slabhash* sl, lruhash_markdelfunc_t md)
+{
+ size_t i;
+ for(i=0; i<sl->size; i++) {
+ lruhash_setmarkdel(sl->array[i], md);
+ }
+}
+
+void slabhash_traverse(struct slabhash* sh, int wr,
+ void (*func)(struct lruhash_entry*, void*), void* arg)
+{
+ size_t i;
+ for(i=0; i<sh->size; i++)
+ lruhash_traverse(sh->array[i], wr, func, arg);
+}
+
+size_t count_slabhash_entries(struct slabhash* sh)
+{
+ size_t slab, cnt = 0;
+
+ for(slab=0; slab<sh->size; slab++) {
+ lock_quick_lock(&sh->array[slab]->lock);
+ cnt += sh->array[slab]->num;
+ lock_quick_unlock(&sh->array[slab]->lock);
+ }
+ return cnt;
+}
diff --git a/external/unbound/util/storage/slabhash.h b/external/unbound/util/storage/slabhash.h
new file mode 100644
index 000000000..031a9da0f
--- /dev/null
+++ b/external/unbound/util/storage/slabhash.h
@@ -0,0 +1,218 @@
+/*
+ * util/storage/slabhash.h - hashtable consisting of several smaller tables.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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
+ *
+ * Hash table that consists of smaller hash tables.
+ * It cannot grow, but that gives it the ability to have multiple
+ * locks. Also this means there are multiple LRU lists.
+ */
+
+#ifndef UTIL_STORAGE_SLABHASH_H
+#define UTIL_STORAGE_SLABHASH_H
+#include "util/storage/lruhash.h"
+
+/** default number of slabs */
+#define HASH_DEFAULT_SLABS 4
+
+/**
+ * Hash table formed from several smaller ones.
+ * This results in a partitioned lruhash table, a 'slashtable'.
+ * None of the data inside the slabhash may be altered.
+ * Therefore, no locks are needed to access the structure.
+ */
+struct slabhash {
+ /** the size of the array - must be power of 2 */
+ size_t size;
+ /** size bitmask - uses high bits. */
+ uint32_t mask;
+ /** shift right this many bits to get index into array. */
+ unsigned int shift;
+ /** lookup array of hash tables */
+ struct lruhash** array;
+};
+
+/**
+ * Create new slabbed hash table.
+ * @param numtables: number of hash tables to use, other parameters used to
+ * initialize these smaller hashtables.
+ * @param start_size: size of hashtable array at start, must be power of 2.
+ * @param maxmem: maximum amount of memory this table is allowed to use.
+ * so every table gets maxmem/numtables to use for itself.
+ * @param sizefunc: calculates memory usage of entries.
+ * @param compfunc: compares entries, 0 on equality.
+ * @param delkeyfunc: deletes key.
+ * @param deldatafunc: deletes data.
+ * @param arg: user argument that is passed to user function calls.
+ * @return: new hash table or NULL on malloc failure.
+ */
+struct slabhash* slabhash_create(size_t numtables, size_t start_size,
+ size_t maxmem, lruhash_sizefunc_t sizefunc,
+ lruhash_compfunc_t compfunc, lruhash_delkeyfunc_t delkeyfunc,
+ lruhash_deldatafunc_t deldatafunc, void* arg);
+
+/**
+ * Delete hash table. Entries are all deleted.
+ * @param table: to delete.
+ */
+void slabhash_delete(struct slabhash* table);
+
+/**
+ * Clear hash table. Entries are all deleted.
+ * @param table: to make empty.
+ */
+void slabhash_clear(struct slabhash* table);
+
+/**
+ * Insert a new element into the hashtable, uses lruhash_insert.
+ * If key is already present data pointer in that entry is updated.
+ *
+ * @param table: hash table.
+ * @param hash: hash value. User calculates the hash.
+ * @param entry: identifies the entry.
+ * If key already present, this entry->key is deleted immediately.
+ * But entry->data is set to NULL before deletion, and put into
+ * the existing entry. The data is then freed.
+ * @param data: the data.
+ * @param cb_override: if not NULL overrides the cb_arg for deletfunc.
+ */
+void slabhash_insert(struct slabhash* table, hashvalue_t hash,
+ struct lruhash_entry* entry, void* data, void* cb_override);
+
+/**
+ * Lookup an entry in the hashtable. Uses lruhash_lookup.
+ * At the end of the function you hold a (read/write)lock on the entry.
+ * The LRU is updated for the entry (if found).
+ * @param table: hash table.
+ * @param hash: hash of key.
+ * @param key: what to look for, compared against entries in overflow chain.
+ * the hash value must be set, and must work with compare function.
+ * @param wr: set to true if you desire a writelock on the entry.
+ * with a writelock you can update the data part.
+ * @return: pointer to the entry or NULL. The entry is locked.
+ * The user must unlock the entry when done.
+ */
+struct lruhash_entry* slabhash_lookup(struct slabhash* table,
+ hashvalue_t hash, void* key, int wr);
+
+/**
+ * Remove entry from hashtable. Does nothing if not found in hashtable.
+ * Delfunc is called for the entry. Uses lruhash_remove.
+ * @param table: hash table.
+ * @param hash: hash of key.
+ * @param key: what to look for.
+ */
+void slabhash_remove(struct slabhash* table, hashvalue_t hash, void* key);
+
+/**
+ * Output debug info to the log as to state of the hash table.
+ * @param table: hash table.
+ * @param id: string printed with table to identify the hash table.
+ * @param extended: set to true to print statistics on overflow bin lengths.
+ */
+void slabhash_status(struct slabhash* table, const char* id, int extended);
+
+/**
+ * Retrieve slab hash total size.
+ * @param table: hash table.
+ * @return size configured as max.
+ */
+size_t slabhash_get_size(struct slabhash* table);
+
+/**
+ * Retrieve slab hash current memory use.
+ * @param table: hash table.
+ * @return memory in use.
+ */
+size_t slabhash_get_mem(struct slabhash* table);
+
+/**
+ * Get lruhash table for a given hash value
+ * @param table: slabbed hash table.
+ * @param hash: hash value.
+ * @return the lru hash table.
+ */
+struct lruhash* slabhash_gettable(struct slabhash* table, hashvalue_t hash);
+
+/**
+ * Set markdel function
+ * @param table: slabbed hash table.
+ * @param md: markdel function ptr.
+ */
+void slabhash_setmarkdel(struct slabhash* table, lruhash_markdelfunc_t md);
+
+/**
+ * Traverse a slabhash.
+ * @param table: slabbed hash table.
+ * @param wr: if true, writelock is obtained, otherwise readlock.
+ * @param func: function to call for every element.
+ * @param arg: user argument to function.
+ */
+void slabhash_traverse(struct slabhash* table, int wr,
+ void (*func)(struct lruhash_entry*, void*), void* arg);
+
+/*
+ * Count entries in slabhash.
+ * @param table: slabbed hash table;
+ * @return the number of items
+ */
+size_t count_slabhash_entries(struct slabhash* table);
+
+/* --- test representation --- */
+/** test structure contains test key */
+struct slabhash_testkey {
+ /** the key id */
+ int id;
+ /** the entry */
+ struct lruhash_entry entry;
+};
+/** test structure contains test data */
+struct slabhash_testdata {
+ /** data value */
+ int data;
+};
+
+/** test sizefunc for lruhash */
+size_t test_slabhash_sizefunc(void*, void*);
+/** test comparefunc for lruhash */
+int test_slabhash_compfunc(void*, void*);
+/** test delkey for lruhash */
+void test_slabhash_delkey(void*, void*);
+/** test deldata for lruhash */
+void test_slabhash_deldata(void*, void*);
+/* --- end test representation --- */
+
+#endif /* UTIL_STORAGE_SLABHASH_H */
diff --git a/external/unbound/util/timehist.c b/external/unbound/util/timehist.c
new file mode 100644
index 000000000..dbf5b9841
--- /dev/null
+++ b/external/unbound/util/timehist.c
@@ -0,0 +1,247 @@
+/*
+ * util/timehist.c - make histogram of time values.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 make a histogram of time values.
+ */
+#include "config.h"
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include <sys/time.h>
+#include <sys/types.h>
+#include "util/timehist.h"
+#include "util/log.h"
+
+/** special timestwo operation for time values in histogram setup */
+static void
+timestwo(struct timeval* v)
+{
+#ifndef S_SPLINT_S
+ if(v->tv_sec == 0 && v->tv_usec == 0) {
+ v->tv_usec = 1;
+ return;
+ }
+ v->tv_sec *= 2;
+ v->tv_usec *= 2;
+ if(v->tv_usec == 1024*1024) {
+ /* nice values and easy to compute */
+ v->tv_sec = 1;
+ v->tv_usec = 0;
+ }
+#endif
+}
+
+/** do setup exponentially */
+static void
+dosetup(struct timehist* hist)
+{
+ struct timeval last;
+ size_t i;
+ memset(&last, 0, sizeof(last));
+ for(i=0; i<hist->num; i++) {
+ hist->buckets[i].lower = last;
+ timestwo(&last);
+ hist->buckets[i].upper = last;
+ hist->buckets[i].count = 0;
+ }
+}
+
+struct timehist* timehist_setup(void)
+{
+ struct timehist* hist = (struct timehist*)calloc(1,
+ sizeof(struct timehist));
+ if(!hist)
+ return NULL;
+ hist->num = NUM_BUCKETS_HIST;
+ hist->buckets = (struct th_buck*)calloc(hist->num,
+ sizeof(struct th_buck));
+ if(!hist->buckets) {
+ free(hist);
+ return NULL;
+ }
+ /* setup the buckets */
+ dosetup(hist);
+ return hist;
+}
+
+void timehist_delete(struct timehist* hist)
+{
+ if(!hist)
+ return;
+ free(hist->buckets);
+ free(hist);
+}
+
+void timehist_clear(struct timehist* hist)
+{
+ size_t i;
+ for(i=0; i<hist->num; i++)
+ hist->buckets[i].count = 0;
+}
+
+/** histogram compare of time values */
+static int
+timeval_smaller(const struct timeval* x, const struct timeval* y)
+{
+#ifndef S_SPLINT_S
+ if(x->tv_sec < y->tv_sec)
+ return 1;
+ else if(x->tv_sec == y->tv_sec) {
+ if(x->tv_usec <= y->tv_usec)
+ return 1;
+ else return 0;
+ }
+ else return 0;
+#endif
+}
+
+
+void timehist_insert(struct timehist* hist, struct timeval* tv)
+{
+ size_t i;
+ for(i=0; i<hist->num; i++) {
+ if(timeval_smaller(tv, &hist->buckets[i].upper)) {
+ hist->buckets[i].count++;
+ return;
+ }
+ }
+ /* dump in last bucket */
+ hist->buckets[hist->num-1].count++;
+}
+
+void timehist_print(struct timehist* hist)
+{
+#ifndef S_SPLINT_S
+ size_t i;
+ for(i=0; i<hist->num; i++) {
+ if(hist->buckets[i].count != 0) {
+ printf("%4d.%6.6d %4d.%6.6d %u\n",
+ (int)hist->buckets[i].lower.tv_sec,
+ (int)hist->buckets[i].lower.tv_usec,
+ (int)hist->buckets[i].upper.tv_sec,
+ (int)hist->buckets[i].upper.tv_usec,
+ (unsigned)hist->buckets[i].count);
+ }
+ }
+#endif
+}
+
+void timehist_log(struct timehist* hist, const char* name)
+{
+#ifndef S_SPLINT_S
+ size_t i;
+ log_info("[25%%]=%g median[50%%]=%g [75%%]=%g",
+ timehist_quartile(hist, 0.25),
+ timehist_quartile(hist, 0.50),
+ timehist_quartile(hist, 0.75));
+ /* 0000.000000 0000.000000 0 */
+ log_info("lower(secs) upper(secs) %s", name);
+ for(i=0; i<hist->num; i++) {
+ if(hist->buckets[i].count != 0) {
+ log_info("%4d.%6.6d %4d.%6.6d %u",
+ (int)hist->buckets[i].lower.tv_sec,
+ (int)hist->buckets[i].lower.tv_usec,
+ (int)hist->buckets[i].upper.tv_sec,
+ (int)hist->buckets[i].upper.tv_usec,
+ (unsigned)hist->buckets[i].count);
+ }
+ }
+#endif
+}
+
+/** total number in histogram */
+static size_t
+timehist_count(struct timehist* hist)
+{
+ size_t i, res = 0;
+ for(i=0; i<hist->num; i++)
+ res += hist->buckets[i].count;
+ return res;
+}
+
+double
+timehist_quartile(struct timehist* hist, double q)
+{
+ double lookfor, passed, res;
+ double low = 0, up = 0;
+ size_t i;
+ if(!hist || hist->num == 0)
+ return 0.;
+ /* look for i'th element, interpolated */
+ lookfor = (double)timehist_count(hist);
+ if(lookfor < 4)
+ return 0.; /* not enough elements for a good estimate */
+ lookfor *= q;
+ passed = 0;
+ i = 0;
+ while(i+1 < hist->num &&
+ passed+(double)hist->buckets[i].count < lookfor) {
+ passed += (double)hist->buckets[i++].count;
+ }
+ /* got the right bucket */
+#ifndef S_SPLINT_S
+ low = (double)hist->buckets[i].lower.tv_sec +
+ (double)hist->buckets[i].lower.tv_usec/1000000.;
+ up = (double)hist->buckets[i].upper.tv_sec +
+ (double)hist->buckets[i].upper.tv_usec/1000000.;
+#endif
+ res = (lookfor - passed)*(up-low)/((double)hist->buckets[i].count);
+ return low+res;
+}
+
+void
+timehist_export(struct timehist* hist, size_t* array, size_t sz)
+{
+ size_t i;
+ if(!hist) return;
+ if(sz > hist->num)
+ sz = hist->num;
+ for(i=0; i<sz; i++)
+ array[i] = hist->buckets[i].count;
+}
+
+void
+timehist_import(struct timehist* hist, size_t* array, size_t sz)
+{
+ size_t i;
+ if(!hist) return;
+ if(sz > hist->num)
+ sz = hist->num;
+ for(i=0; i<sz; i++)
+ hist->buckets[i].count = array[i];
+}
diff --git a/external/unbound/util/timehist.h b/external/unbound/util/timehist.h
new file mode 100644
index 000000000..5c65048b9
--- /dev/null
+++ b/external/unbound/util/timehist.h
@@ -0,0 +1,134 @@
+/*
+ * util/timehist.h - make histogram of time values.
+ *
+ * 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 COPYRIGHT
+ * HOLDER 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 make a histogram of time values.
+ */
+
+#ifndef UTIL_TIMEHIST_H
+#define UTIL_TIMEHIST_H
+
+/** Number of buckets in a histogram */
+#define NUM_BUCKETS_HIST 40
+
+/**
+ * Bucket of time history information
+ */
+struct th_buck {
+ /** lower bound */
+ struct timeval lower;
+ /** upper bound */
+ struct timeval upper;
+ /** number of items */
+ size_t count;
+};
+
+/**
+ * Keep histogram of time values.
+ */
+struct timehist {
+ /** number of buckets */
+ size_t num;
+ /** bucket array */
+ struct th_buck* buckets;
+};
+
+/**
+ * Setup a histogram, default
+ * @return histogram or NULL on malloc failure.
+ */
+struct timehist* timehist_setup(void);
+
+/**
+ * Delete histogram
+ * @param hist: to delete
+ */
+void timehist_delete(struct timehist* hist);
+
+/**
+ * Clear histogram
+ * @param hist: to clear all data from
+ */
+void timehist_clear(struct timehist* hist);
+
+/**
+ * Add time value to histogram.
+ * @param hist: histogram
+ * @param tv: time value
+ */
+void timehist_insert(struct timehist* hist, struct timeval* tv);
+
+/**
+ * Find time value for given quartile, such as 0.25, 0.50, 0.75.
+ * The looks up the value for the i-th element in the sorted list of time
+ * values, as approximated using the histogram.
+ * @param hist: histogram. Interpolated information is used from it.
+ * @param q: quartile, 0.50 results in the median. Must be >0 and <1.
+ * @return: the time in seconds for that percentage.
+ */
+double timehist_quartile(struct timehist* hist, double q);
+
+/**
+ * Printout histogram
+ * @param hist: histogram
+ */
+void timehist_print(struct timehist* hist);
+
+/**
+ * Log histogram, print it to the logfile.
+ * @param hist: histogram
+ * @param name: the name of the value column
+ */
+void timehist_log(struct timehist* hist, const char* name);
+
+/**
+ * Export histogram to an array.
+ * @param hist: histogram
+ * @param array: the array to export to.
+ * @param sz: number of items in array.
+ */
+void timehist_export(struct timehist* hist, size_t* array, size_t sz);
+
+/**
+ * Import histogram from an array.
+ * @param hist: histogram
+ * @param array: the array to import from.
+ * @param sz: number of items in array.
+ */
+void timehist_import(struct timehist* hist, size_t* array, size_t sz);
+
+#endif /* UTIL_TIMEHIST_H */
diff --git a/external/unbound/util/tube.c b/external/unbound/util/tube.c
new file mode 100644
index 000000000..2106a078c
--- /dev/null
+++ b/external/unbound/util/tube.c
@@ -0,0 +1,727 @@
+/*
+ * util/tube.c - pipe service
+ *
+ * Copyright (c) 2008, 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 COPYRIGHT
+ * HOLDER 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 pipe service functions.
+ */
+#include "config.h"
+#include "util/tube.h"
+#include "util/log.h"
+#include "util/net_help.h"
+#include "util/netevent.h"
+#include "util/fptr_wlist.h"
+
+#ifndef USE_WINSOCK
+/* on unix */
+
+#ifndef HAVE_SOCKETPAIR
+/** no socketpair() available, like on Minix 3.1.7, use pipe */
+#define socketpair(f, t, p, sv) pipe(sv)
+#endif /* HAVE_SOCKETPAIR */
+
+struct tube* tube_create(void)
+{
+ struct tube* tube = (struct tube*)calloc(1, sizeof(*tube));
+ int sv[2];
+ if(!tube) {
+ int err = errno;
+ log_err("tube_create: out of memory");
+ errno = err;
+ return NULL;
+ }
+ tube->sr = -1;
+ tube->sw = -1;
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, sv) == -1) {
+ int err = errno;
+ log_err("socketpair: %s", strerror(errno));
+ free(tube);
+ errno = err;
+ return NULL;
+ }
+ tube->sr = sv[0];
+ tube->sw = sv[1];
+ if(!fd_set_nonblock(tube->sr) || !fd_set_nonblock(tube->sw)) {
+ int err = errno;
+ log_err("tube: cannot set nonblocking");
+ tube_delete(tube);
+ errno = err;
+ return NULL;
+ }
+ return tube;
+}
+
+void tube_delete(struct tube* tube)
+{
+ if(!tube) return;
+ tube_remove_bg_listen(tube);
+ tube_remove_bg_write(tube);
+ /* close fds after deleting commpoints, to be sure.
+ * Also epoll does not like closing fd before event_del */
+ tube_close_read(tube);
+ tube_close_write(tube);
+ free(tube);
+}
+
+void tube_close_read(struct tube* tube)
+{
+ if(tube->sr != -1) {
+ close(tube->sr);
+ tube->sr = -1;
+ }
+}
+
+void tube_close_write(struct tube* tube)
+{
+ if(tube->sw != -1) {
+ close(tube->sw);
+ tube->sw = -1;
+ }
+}
+
+void tube_remove_bg_listen(struct tube* tube)
+{
+ if(tube->listen_com) {
+ comm_point_delete(tube->listen_com);
+ tube->listen_com = NULL;
+ }
+ if(tube->cmd_msg) {
+ free(tube->cmd_msg);
+ tube->cmd_msg = NULL;
+ }
+}
+
+void tube_remove_bg_write(struct tube* tube)
+{
+ if(tube->res_com) {
+ comm_point_delete(tube->res_com);
+ tube->res_com = NULL;
+ }
+ if(tube->res_list) {
+ struct tube_res_list* np, *p = tube->res_list;
+ tube->res_list = NULL;
+ tube->res_last = NULL;
+ while(p) {
+ np = p->next;
+ free(p->buf);
+ free(p);
+ p = np;
+ }
+ }
+}
+
+int
+tube_handle_listen(struct comm_point* c, void* arg, int error,
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ struct tube* tube = (struct tube*)arg;
+ ssize_t r;
+ if(error != NETEVENT_NOERROR) {
+ fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb));
+ (*tube->listen_cb)(tube, NULL, 0, error, tube->listen_arg);
+ return 0;
+ }
+
+ if(tube->cmd_read < sizeof(tube->cmd_len)) {
+ /* complete reading the length of control msg */
+ r = read(c->fd, ((uint8_t*)&tube->cmd_len) + tube->cmd_read,
+ sizeof(tube->cmd_len) - tube->cmd_read);
+ if(r==0) {
+ /* error has happened or */
+ /* parent closed pipe, must have exited somehow */
+ fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb));
+ (*tube->listen_cb)(tube, NULL, 0, NETEVENT_CLOSED,
+ tube->listen_arg);
+ return 0;
+ }
+ if(r==-1) {
+ if(errno != EAGAIN && errno != EINTR) {
+ log_err("rpipe error: %s", strerror(errno));
+ }
+ /* nothing to read now, try later */
+ return 0;
+ }
+ tube->cmd_read += r;
+ if(tube->cmd_read < sizeof(tube->cmd_len)) {
+ /* not complete, try later */
+ return 0;
+ }
+ tube->cmd_msg = (uint8_t*)calloc(1, tube->cmd_len);
+ if(!tube->cmd_msg) {
+ log_err("malloc failure");
+ tube->cmd_read = 0;
+ return 0;
+ }
+ }
+ /* cmd_len has been read, read remainder */
+ r = read(c->fd, tube->cmd_msg+tube->cmd_read-sizeof(tube->cmd_len),
+ tube->cmd_len - (tube->cmd_read - sizeof(tube->cmd_len)));
+ if(r==0) {
+ /* error has happened or */
+ /* parent closed pipe, must have exited somehow */
+ fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb));
+ (*tube->listen_cb)(tube, NULL, 0, NETEVENT_CLOSED,
+ tube->listen_arg);
+ return 0;
+ }
+ if(r==-1) {
+ /* nothing to read now, try later */
+ if(errno != EAGAIN && errno != EINTR) {
+ log_err("rpipe error: %s", strerror(errno));
+ }
+ return 0;
+ }
+ tube->cmd_read += r;
+ if(tube->cmd_read < sizeof(tube->cmd_len) + tube->cmd_len) {
+ /* not complete, try later */
+ return 0;
+ }
+ tube->cmd_read = 0;
+
+ fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb));
+ (*tube->listen_cb)(tube, tube->cmd_msg, tube->cmd_len,
+ NETEVENT_NOERROR, tube->listen_arg);
+ /* also frees the buf */
+ tube->cmd_msg = NULL;
+ return 0;
+}
+
+int
+tube_handle_write(struct comm_point* c, void* arg, int error,
+ struct comm_reply* ATTR_UNUSED(reply_info))
+{
+ struct tube* tube = (struct tube*)arg;
+ struct tube_res_list* item = tube->res_list;
+ ssize_t r;
+ if(error != NETEVENT_NOERROR) {
+ log_err("tube_handle_write net error %d", error);
+ return 0;
+ }
+
+ if(!item) {
+ comm_point_stop_listening(c);
+ return 0;
+ }
+
+ if(tube->res_write < sizeof(item->len)) {
+ r = write(c->fd, ((uint8_t*)&item->len) + tube->res_write,
+ sizeof(item->len) - tube->res_write);
+ if(r == -1) {
+ if(errno != EAGAIN && errno != EINTR) {
+ log_err("wpipe error: %s", strerror(errno));
+ }
+ return 0; /* try again later */
+ }
+ if(r == 0) {
+ /* error on pipe, must have exited somehow */
+ /* cannot signal this to pipe user */
+ return 0;
+ }
+ tube->res_write += r;
+ if(tube->res_write < sizeof(item->len))
+ return 0;
+ }
+ r = write(c->fd, item->buf + tube->res_write - sizeof(item->len),
+ item->len - (tube->res_write - sizeof(item->len)));
+ if(r == -1) {
+ if(errno != EAGAIN && errno != EINTR) {
+ log_err("wpipe error: %s", strerror(errno));
+ }
+ return 0; /* try again later */
+ }
+ if(r == 0) {
+ /* error on pipe, must have exited somehow */
+ /* cannot signal this to pipe user */
+ return 0;
+ }
+ tube->res_write += r;
+ if(tube->res_write < sizeof(item->len) + item->len)
+ return 0;
+ /* done this result, remove it */
+ free(item->buf);
+ item->buf = NULL;
+ tube->res_list = tube->res_list->next;
+ free(item);
+ if(!tube->res_list) {
+ tube->res_last = NULL;
+ comm_point_stop_listening(c);
+ }
+ tube->res_write = 0;
+ return 0;
+}
+
+int tube_write_msg(struct tube* tube, uint8_t* buf, uint32_t len,
+ int nonblock)
+{
+ ssize_t r, d;
+ int fd = tube->sw;
+
+ /* test */
+ if(nonblock) {
+ r = write(fd, &len, sizeof(len));
+ if(r == -1) {
+ if(errno==EINTR || errno==EAGAIN)
+ return -1;
+ log_err("tube msg write failed: %s", strerror(errno));
+ return -1; /* can still continue, perhaps */
+ }
+ } else r = 0;
+ if(!fd_set_block(fd))
+ return 0;
+ /* write remainder */
+ d = r;
+ while(d != (ssize_t)sizeof(len)) {
+ if((r=write(fd, ((char*)&len)+d, sizeof(len)-d)) == -1) {
+ log_err("tube msg write failed: %s", strerror(errno));
+ (void)fd_set_nonblock(fd);
+ return 0;
+ }
+ d += r;
+ }
+ d = 0;
+ while(d != (ssize_t)len) {
+ if((r=write(fd, buf+d, len-d)) == -1) {
+ log_err("tube msg write failed: %s", strerror(errno));
+ (void)fd_set_nonblock(fd);
+ return 0;
+ }
+ d += r;
+ }
+ if(!fd_set_nonblock(fd))
+ return 0;
+ return 1;
+}
+
+int tube_read_msg(struct tube* tube, uint8_t** buf, uint32_t* len,
+ int nonblock)
+{
+ ssize_t r, d;
+ int fd = tube->sr;
+
+ /* test */
+ *len = 0;
+ if(nonblock) {
+ r = read(fd, len, sizeof(*len));
+ if(r == -1) {
+ if(errno==EINTR || errno==EAGAIN)
+ return -1;
+ log_err("tube msg read failed: %s", strerror(errno));
+ return -1; /* we can still continue, perhaps */
+ }
+ if(r == 0) /* EOF */
+ return 0;
+ } else r = 0;
+ if(!fd_set_block(fd))
+ return 0;
+ /* read remainder */
+ d = r;
+ while(d != (ssize_t)sizeof(*len)) {
+ if((r=read(fd, ((char*)len)+d, sizeof(*len)-d)) == -1) {
+ log_err("tube msg read failed: %s", strerror(errno));
+ (void)fd_set_nonblock(fd);
+ return 0;
+ }
+ if(r == 0) /* EOF */ {
+ (void)fd_set_nonblock(fd);
+ return 0;
+ }
+ d += r;
+ }
+ log_assert(*len < 65536*2);
+ *buf = (uint8_t*)malloc(*len);
+ if(!*buf) {
+ log_err("tube read out of memory");
+ (void)fd_set_nonblock(fd);
+ return 0;
+ }
+ d = 0;
+ while(d < (ssize_t)*len) {
+ if((r=read(fd, (*buf)+d, (size_t)((ssize_t)*len)-d)) == -1) {
+ log_err("tube msg read failed: %s", strerror(errno));
+ (void)fd_set_nonblock(fd);
+ free(*buf);
+ return 0;
+ }
+ if(r == 0) { /* EOF */
+ (void)fd_set_nonblock(fd);
+ free(*buf);
+ return 0;
+ }
+ d += r;
+ }
+ if(!fd_set_nonblock(fd)) {
+ free(*buf);
+ return 0;
+ }
+ return 1;
+}
+
+/** perform a select() on the fd */
+static int
+pollit(int fd, struct timeval* t)
+{
+ fd_set r;
+#ifndef S_SPLINT_S
+ FD_ZERO(&r);
+ FD_SET(FD_SET_T fd, &r);
+#endif
+ if(select(fd+1, &r, NULL, NULL, t) == -1) {
+ return 0;
+ }
+ errno = 0;
+ return (int)(FD_ISSET(fd, &r));
+}
+
+int tube_poll(struct tube* tube)
+{
+ struct timeval t;
+ memset(&t, 0, sizeof(t));
+ return pollit(tube->sr, &t);
+}
+
+int tube_wait(struct tube* tube)
+{
+ return pollit(tube->sr, NULL);
+}
+
+int tube_read_fd(struct tube* tube)
+{
+ return tube->sr;
+}
+
+int tube_setup_bg_listen(struct tube* tube, struct comm_base* base,
+ tube_callback_t* cb, void* arg)
+{
+ tube->listen_cb = cb;
+ tube->listen_arg = arg;
+ if(!(tube->listen_com = comm_point_create_raw(base, tube->sr,
+ 0, tube_handle_listen, tube))) {
+ int err = errno;
+ log_err("tube_setup_bg_l: commpoint creation failed");
+ errno = err;
+ return 0;
+ }
+ return 1;
+}
+
+int tube_setup_bg_write(struct tube* tube, struct comm_base* base)
+{
+ if(!(tube->res_com = comm_point_create_raw(base, tube->sw,
+ 1, tube_handle_write, tube))) {
+ int err = errno;
+ log_err("tube_setup_bg_w: commpoint creation failed");
+ errno = err;
+ return 0;
+ }
+ return 1;
+}
+
+int tube_queue_item(struct tube* tube, uint8_t* msg, size_t len)
+{
+ struct tube_res_list* item =
+ (struct tube_res_list*)malloc(sizeof(*item));
+ if(!item) {
+ free(msg);
+ log_err("out of memory for async answer");
+ return 0;
+ }
+ item->buf = msg;
+ item->len = len;
+ item->next = NULL;
+ /* add at back of list, since the first one may be partially written */
+ if(tube->res_last)
+ tube->res_last->next = item;
+ else tube->res_list = item;
+ tube->res_last = item;
+ if(tube->res_list == tube->res_last) {
+ /* first added item, start the write process */
+ comm_point_start_listening(tube->res_com, -1, -1);
+ }
+ return 1;
+}
+
+void tube_handle_signal(int ATTR_UNUSED(fd), short ATTR_UNUSED(events),
+ void* ATTR_UNUSED(arg))
+{
+ log_assert(0);
+}
+
+#else /* USE_WINSOCK */
+/* on windows */
+
+
+struct tube* tube_create(void)
+{
+ /* windows does not have forks like unix, so we only support
+ * threads on windows. And thus the pipe need only connect
+ * threads. We use a mutex and a list of datagrams. */
+ struct tube* tube = (struct tube*)calloc(1, sizeof(*tube));
+ if(!tube) {
+ int err = errno;
+ log_err("tube_create: out of memory");
+ errno = err;
+ return NULL;
+ }
+ tube->event = WSACreateEvent();
+ if(tube->event == WSA_INVALID_EVENT) {
+ free(tube);
+ log_err("WSACreateEvent: %s", wsa_strerror(WSAGetLastError()));
+ }
+ if(!WSAResetEvent(tube->event)) {
+ log_err("WSAResetEvent: %s", wsa_strerror(WSAGetLastError()));
+ }
+ lock_basic_init(&tube->res_lock);
+ verbose(VERB_ALGO, "tube created");
+ return tube;
+}
+
+void tube_delete(struct tube* tube)
+{
+ if(!tube) return;
+ tube_remove_bg_listen(tube);
+ tube_remove_bg_write(tube);
+ tube_close_read(tube);
+ tube_close_write(tube);
+ if(!WSACloseEvent(tube->event))
+ log_err("WSACloseEvent: %s", wsa_strerror(WSAGetLastError()));
+ lock_basic_destroy(&tube->res_lock);
+ verbose(VERB_ALGO, "tube deleted");
+ free(tube);
+}
+
+void tube_close_read(struct tube* ATTR_UNUSED(tube))
+{
+ verbose(VERB_ALGO, "tube close_read");
+}
+
+void tube_close_write(struct tube* ATTR_UNUSED(tube))
+{
+ verbose(VERB_ALGO, "tube close_write");
+ /* wake up waiting reader with an empty queue */
+ if(!WSASetEvent(tube->event)) {
+ log_err("WSASetEvent: %s", wsa_strerror(WSAGetLastError()));
+ }
+}
+
+void tube_remove_bg_listen(struct tube* tube)
+{
+ verbose(VERB_ALGO, "tube remove_bg_listen");
+ winsock_unregister_wsaevent(&tube->ev_listen);
+}
+
+void tube_remove_bg_write(struct tube* tube)
+{
+ verbose(VERB_ALGO, "tube remove_bg_write");
+ if(tube->res_list) {
+ struct tube_res_list* np, *p = tube->res_list;
+ tube->res_list = NULL;
+ tube->res_last = NULL;
+ while(p) {
+ np = p->next;
+ free(p->buf);
+ free(p);
+ p = np;
+ }
+ }
+}
+
+int tube_write_msg(struct tube* tube, uint8_t* buf, uint32_t len,
+ int ATTR_UNUSED(nonblock))
+{
+ uint8_t* a;
+ verbose(VERB_ALGO, "tube write_msg len %d", (int)len);
+ a = (uint8_t*)memdup(buf, len);
+ if(!a) {
+ log_err("out of memory in tube_write_msg");
+ return 0;
+ }
+ /* always nonblocking, this pipe cannot get full */
+ return tube_queue_item(tube, a, len);
+}
+
+int tube_read_msg(struct tube* tube, uint8_t** buf, uint32_t* len,
+ int nonblock)
+{
+ struct tube_res_list* item = NULL;
+ verbose(VERB_ALGO, "tube read_msg %s", nonblock?"nonblock":"blocking");
+ *buf = NULL;
+ if(!tube_poll(tube)) {
+ verbose(VERB_ALGO, "tube read_msg nodata");
+ /* nothing ready right now, wait if we want to */
+ if(nonblock)
+ return -1; /* would block waiting for items */
+ if(!tube_wait(tube))
+ return 0;
+ }
+ lock_basic_lock(&tube->res_lock);
+ if(tube->res_list) {
+ item = tube->res_list;
+ tube->res_list = item->next;
+ if(tube->res_last == item) {
+ /* the list is now empty */
+ tube->res_last = NULL;
+ verbose(VERB_ALGO, "tube read_msg lastdata");
+ if(!WSAResetEvent(tube->event)) {
+ log_err("WSAResetEvent: %s",
+ wsa_strerror(WSAGetLastError()));
+ }
+ }
+ }
+ lock_basic_unlock(&tube->res_lock);
+ if(!item)
+ return 0; /* would block waiting for items */
+ *buf = item->buf;
+ *len = item->len;
+ free(item);
+ verbose(VERB_ALGO, "tube read_msg len %d", (int)*len);
+ return 1;
+}
+
+int tube_poll(struct tube* tube)
+{
+ struct tube_res_list* item = NULL;
+ lock_basic_lock(&tube->res_lock);
+ item = tube->res_list;
+ lock_basic_unlock(&tube->res_lock);
+ if(item)
+ return 1;
+ return 0;
+}
+
+int tube_wait(struct tube* tube)
+{
+ /* block on eventhandle */
+ DWORD res = WSAWaitForMultipleEvents(
+ 1 /* one event in array */,
+ &tube->event /* the event to wait for, our pipe signal */,
+ 0 /* wait for all events is false */,
+ WSA_INFINITE /* wait, no timeout */,
+ 0 /* we are not alertable for IO completion routines */
+ );
+ if(res == WSA_WAIT_TIMEOUT) {
+ return 0;
+ }
+ if(res == WSA_WAIT_IO_COMPLETION) {
+ /* a bit unexpected, since we were not alertable */
+ return 0;
+ }
+ return 1;
+}
+
+int tube_read_fd(struct tube* ATTR_UNUSED(tube))
+{
+ /* nothing sensible on Windows */
+ return -1;
+}
+
+int
+tube_handle_listen(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
+tube_handle_write(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 tube_setup_bg_listen(struct tube* tube, struct comm_base* base,
+ tube_callback_t* cb, void* arg)
+{
+ tube->listen_cb = cb;
+ tube->listen_arg = arg;
+ if(!comm_base_internal(base))
+ return 1; /* ignore when no comm base - testing */
+ return winsock_register_wsaevent(comm_base_internal(base),
+ &tube->ev_listen, tube->event, &tube_handle_signal, tube);
+}
+
+int tube_setup_bg_write(struct tube* ATTR_UNUSED(tube),
+ struct comm_base* ATTR_UNUSED(base))
+{
+ /* the queue item routine performs the signaling */
+ return 1;
+}
+
+int tube_queue_item(struct tube* tube, uint8_t* msg, size_t len)
+{
+ struct tube_res_list* item =
+ (struct tube_res_list*)malloc(sizeof(*item));
+ verbose(VERB_ALGO, "tube queue_item len %d", (int)len);
+ if(!item) {
+ free(msg);
+ log_err("out of memory for async answer");
+ return 0;
+ }
+ item->buf = msg;
+ item->len = len;
+ item->next = NULL;
+ lock_basic_lock(&tube->res_lock);
+ /* add at back of list, since the first one may be partially written */
+ if(tube->res_last)
+ tube->res_last->next = item;
+ else tube->res_list = item;
+ tube->res_last = item;
+ /* signal the eventhandle */
+ if(!WSASetEvent(tube->event)) {
+ log_err("WSASetEvent: %s", wsa_strerror(WSAGetLastError()));
+ }
+ lock_basic_unlock(&tube->res_lock);
+ return 1;
+}
+
+void tube_handle_signal(int ATTR_UNUSED(fd), short ATTR_UNUSED(events),
+ void* arg)
+{
+ struct tube* tube = (struct tube*)arg;
+ uint8_t* buf;
+ uint32_t len = 0;
+ verbose(VERB_ALGO, "tube handle_signal");
+ while(tube_poll(tube)) {
+ if(tube_read_msg(tube, &buf, &len, 1)) {
+ fptr_ok(fptr_whitelist_tube_listen(tube->listen_cb));
+ (*tube->listen_cb)(tube, buf, len, NETEVENT_NOERROR,
+ tube->listen_arg);
+ }
+ }
+}
+
+#endif /* USE_WINSOCK */
diff --git a/external/unbound/util/tube.h b/external/unbound/util/tube.h
new file mode 100644
index 000000000..9ec50af38
--- /dev/null
+++ b/external/unbound/util/tube.h
@@ -0,0 +1,273 @@
+/*
+ * util/tube.h - pipe service
+ *
+ * Copyright (c) 2008, 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 COPYRIGHT
+ * HOLDER 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 pipe service functions.
+ */
+
+#ifndef UTIL_TUBE_H
+#define UTIL_TUBE_H
+struct comm_reply;
+struct comm_point;
+struct comm_base;
+struct tube;
+struct tube_res_list;
+#ifdef USE_WINSOCK
+#include "util/locks.h"
+#include "util/winsock_event.h"
+#endif
+
+/**
+ * Callback from pipe listen function
+ * void mycallback(tube, msg, len, error, user_argument);
+ * if error is true (NETEVENT_*), msg is probably NULL.
+ */
+typedef void tube_callback_t(struct tube*, uint8_t*, size_t, int, void*);
+
+/**
+ * A pipe
+ */
+struct tube {
+#ifndef USE_WINSOCK
+ /** pipe end to read from */
+ int sr;
+ /** pipe end to write on */
+ int sw;
+
+ /** listen commpoint */
+ struct comm_point* listen_com;
+ /** listen callback */
+ tube_callback_t* listen_cb;
+ /** listen callback user arg */
+ void* listen_arg;
+ /** are we currently reading a command, 0 if not, else bytecount */
+ size_t cmd_read;
+ /** size of current read command, may be partially read */
+ uint32_t cmd_len;
+ /** the current read command content, malloced, can be partially read*/
+ uint8_t* cmd_msg;
+
+ /** background write queue, commpoint to write results back */
+ struct comm_point* res_com;
+ /** are we curently writing a result, 0 if not, else bytecount into
+ * the res_list first entry. */
+ size_t res_write;
+ /** list of outstanding results to be written back */
+ struct tube_res_list* res_list;
+ /** last in list */
+ struct tube_res_list* res_last;
+
+#else /* USE_WINSOCK */
+ /** listen callback */
+ tube_callback_t* listen_cb;
+ /** listen callback user arg */
+ void* listen_arg;
+ /** the windows sockets event (signaled if items in pipe) */
+ WSAEVENT event;
+ /** winsock event storage when registered with event base */
+ struct event ev_listen;
+
+ /** lock on the list of outstanding items */
+ lock_basic_t res_lock;
+ /** list of outstanding results on pipe */
+ struct tube_res_list* res_list;
+ /** last in list */
+ struct tube_res_list* res_last;
+#endif /* USE_WINSOCK */
+};
+
+/**
+ * List of results (arbitrary command serializations) to write back
+ */
+struct tube_res_list {
+ /** next in list */
+ struct tube_res_list* next;
+ /** serialized buffer to write */
+ uint8_t* buf;
+ /** length to write */
+ uint32_t len;
+};
+
+/**
+ * Create a pipe
+ * @return: new tube struct or NULL on error.
+ */
+struct tube* tube_create(void);
+
+/**
+ * Delete and destroy a pipe
+ * @param tube: to delete
+ */
+void tube_delete(struct tube* tube);
+
+/**
+ * Write length bytes followed by message.
+ * @param tube: the tube to write on.
+ * If that tube is a pipe, its write fd is used as
+ * the socket to write on. Is nonblocking.
+ * Set to blocking by the function,
+ * and back to non-blocking at exit of function.
+ * @param buf: the message.
+ * @param len: length of message.
+ * @param nonblock: if set to true, the first write is nonblocking.
+ * If the first write fails the function returns -1.
+ * If set false, the first write is blocking.
+ * @return: all remainder writes are nonblocking.
+ * return 0 on error, in that case blocking/nonblocking of socket is
+ * unknown.
+ * return 1 if all OK.
+ */
+int tube_write_msg(struct tube* tube, uint8_t* buf, uint32_t len,
+ int nonblock);
+
+/**
+ * Read length bytes followed by message.
+ * @param tube: The tube to read on.
+ * If that tube is a pipe, its read fd is used as
+ * the socket to read on. Is nonblocking.
+ * Set to blocking by the function,
+ * and back to non-blocking at exit of function.
+ * @param buf: the message, malloced.
+ * @param len: length of message, returned.
+ * @param nonblock: if set to true, the first read is nonblocking.
+ * If the first read fails the function returns -1.
+ * If set false, the first read is blocking.
+ * @return: all remainder reads are nonblocking.
+ * return 0 on error, in that case blocking/nonblocking of socket is
+ * unknown. On EOF 0 is returned.
+ * return 1 if all OK.
+ */
+int tube_read_msg(struct tube* tube, uint8_t** buf, uint32_t* len,
+ int nonblock);
+
+/**
+ * Close read part of the pipe.
+ * The tube can no longer be read from.
+ * @param tube: tube to operate on.
+ */
+void tube_close_read(struct tube* tube);
+
+/**
+ * Close write part of the pipe.
+ * The tube can no longer be written to.
+ * @param tube: tube to operate on.
+ */
+void tube_close_write(struct tube* tube);
+
+/**
+ * See if data is ready for reading on the tube without blocking.
+ * @param tube: tube to check for readable items
+ * @return true if readable items are present. False if not (or error).
+ * true on pipe_closed.
+ */
+int tube_poll(struct tube* tube);
+
+/**
+ * Wait for data to be ready for reading on the tube. is blocking.
+ * No timeout.
+ * @param tube: the tube to wait on.
+ * @return: if there was something to read (false on error).
+ * true on pipe_closed.
+ */
+int tube_wait(struct tube* tube);
+
+/**
+ * Get FD that is readable when new information arrives.
+ * @param tube
+ * @return file descriptor.
+ */
+int tube_read_fd(struct tube* tube);
+
+/**
+ * Start listening for information over the pipe.
+ * Background registration of a read listener, callback when read completed.
+ * Do not mix with tube_read_msg style direct reads from the pipe.
+ * @param tube: tube to listen on
+ * @param base: what base to register event callback.
+ * @param cb: callback routine.
+ * @param arg: user argument for callback routine.
+ * @return true if successful, false on error.
+ */
+int tube_setup_bg_listen(struct tube* tube, struct comm_base* base,
+ tube_callback_t* cb, void* arg);
+
+/**
+ * Remove bg listen setup from event base.
+ * @param tube: what tube to cleanup
+ */
+void tube_remove_bg_listen(struct tube* tube);
+
+/**
+ * Start background write handler for the pipe.
+ * Do not mix with tube_write_msg style direct writes to the pipe.
+ * @param tube: tube to write on
+ * @param base: what base to register event handler on.
+ * @return true if successful, false on error.
+ */
+int tube_setup_bg_write(struct tube* tube, struct comm_base* base);
+
+/**
+ * Remove bg write setup from event base.
+ * @param tube: what tube to cleanup
+ */
+void tube_remove_bg_write(struct tube* tube);
+
+
+/**
+ * Append data item to background list of writes.
+ * Mallocs a list entry behind the scenes.
+ * Not locked behind the scenes, call from one thread or lock on outside.
+ * @param tube: what tube to queue on.
+ * @param msg: memory message to send. Is free()d after use.
+ * Put at the end of the to-send queue.
+ * @param len: length of item.
+ * @return 0 on failure (msg freed).
+ */
+int tube_queue_item(struct tube* tube, uint8_t* msg, size_t len);
+
+/** for fptr wlist, callback function */
+int tube_handle_listen(struct comm_point* c, void* arg, int error,
+ struct comm_reply* reply_info);
+
+/** for fptr wlist, callback function */
+int tube_handle_write(struct comm_point* c, void* arg, int error,
+ struct comm_reply* reply_info);
+
+/** for fptr wlist, winsock signal event callback function */
+void tube_handle_signal(int fd, short events, void* arg);
+
+#endif /* UTIL_TUBE_H */
diff --git a/external/unbound/util/winsock_event.c b/external/unbound/util/winsock_event.c
new file mode 100644
index 000000000..38661a5e1
--- /dev/null
+++ b/external/unbound/util/winsock_event.c
@@ -0,0 +1,696 @@
+/*
+ * util/winsock_event.c - implementation of the unbound winsock event handler.
+ *
+ * Copyright (c) 2008, 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 COPYRIGHT
+ * HOLDER 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
+ * Implementation of the unbound WinSock2 API event notification handler
+ * for the Windows port.
+ */
+
+#include "config.h"
+#ifdef USE_WINSOCK
+#include <signal.h>
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#include <sys/time.h>
+#include "util/winsock_event.h"
+#include "util/fptr_wlist.h"
+
+int mini_ev_cmp(const void* a, const void* b)
+{
+ const struct event *e = (const struct event*)a;
+ const struct event *f = (const struct event*)b;
+ if(e->ev_timeout.tv_sec < f->ev_timeout.tv_sec)
+ return -1;
+ if(e->ev_timeout.tv_sec > f->ev_timeout.tv_sec)
+ return 1;
+ if(e->ev_timeout.tv_usec < f->ev_timeout.tv_usec)
+ return -1;
+ if(e->ev_timeout.tv_usec > f->ev_timeout.tv_usec)
+ return 1;
+ if(e < f)
+ return -1;
+ if(e > f)
+ return 1;
+ return 0;
+}
+
+/** set time */
+static int
+settime(struct event_base* base)
+{
+ if(gettimeofday(base->time_tv, NULL) < 0) {
+ return -1;
+ }
+#ifndef S_SPLINT_S
+ *base->time_secs = (time_t)base->time_tv->tv_sec;
+#endif
+ return 0;
+}
+
+#ifdef UNBOUND_DEBUG
+/**
+ * Find a fd in the list of items.
+ * Note that not all items have a fd associated (those are -1).
+ * Signals are stored separately, and not searched.
+ * @param base: event base to look in.
+ * @param fd: what socket to look for.
+ * @return the index in the array, or -1 on failure.
+ */
+static int
+find_fd(struct event_base* base, int fd)
+{
+ int i;
+ for(i=0; i<base->max; i++) {
+ if(base->items[i]->ev_fd == fd)
+ return i;
+ }
+ return -1;
+}
+#endif
+
+/** Find ptr in base array */
+static void
+zero_waitfor(WSAEVENT waitfor[], WSAEVENT x)
+{
+ int i;
+ for(i=0; i<WSK_MAX_ITEMS; i++) {
+ if(waitfor[i] == x)
+ waitfor[i] = 0;
+ }
+}
+
+void *event_init(time_t* time_secs, struct timeval* time_tv)
+{
+ struct event_base* base = (struct event_base*)malloc(
+ sizeof(struct event_base));
+ if(!base)
+ return NULL;
+ memset(base, 0, sizeof(*base));
+ base->time_secs = time_secs;
+ base->time_tv = time_tv;
+ if(settime(base) < 0) {
+ event_base_free(base);
+ return NULL;
+ }
+ base->items = (struct event**)calloc(WSK_MAX_ITEMS,
+ sizeof(struct event*));
+ if(!base->items) {
+ event_base_free(base);
+ return NULL;
+ }
+ base->cap = WSK_MAX_ITEMS;
+ base->max = 0;
+ base->times = rbtree_create(mini_ev_cmp);
+ if(!base->times) {
+ event_base_free(base);
+ return NULL;
+ }
+ base->signals = (struct event**)calloc(MAX_SIG, sizeof(struct event*));
+ if(!base->signals) {
+ event_base_free(base);
+ return NULL;
+ }
+ base->tcp_stickies = 0;
+ base->tcp_reinvigorated = 0;
+ verbose(VERB_CLIENT, "winsock_event inited");
+ return base;
+}
+
+const char *event_get_version(void)
+{
+ return "winsock-event-"PACKAGE_VERSION;
+}
+
+const char *event_get_method(void)
+{
+ return "WSAWaitForMultipleEvents";
+}
+
+/** call timeouts handlers, and return how long to wait for next one or -1 */
+static void handle_timeouts(struct event_base* base, struct timeval* now,
+ struct timeval* wait)
+{
+ struct event* p;
+#ifndef S_SPLINT_S
+ wait->tv_sec = (time_t)-1;
+#endif
+ verbose(VERB_CLIENT, "winsock_event handle_timeouts");
+
+ while((rbnode_t*)(p = (struct event*)rbtree_first(base->times))
+ !=RBTREE_NULL) {
+#ifndef S_SPLINT_S
+ if(p->ev_timeout.tv_sec > now->tv_sec ||
+ (p->ev_timeout.tv_sec==now->tv_sec &&
+ p->ev_timeout.tv_usec > now->tv_usec)) {
+ /* there is a next larger timeout. wait for it */
+ wait->tv_sec = p->ev_timeout.tv_sec - now->tv_sec;
+ if(now->tv_usec > p->ev_timeout.tv_usec) {
+ wait->tv_sec--;
+ wait->tv_usec = 1000000 - (now->tv_usec -
+ p->ev_timeout.tv_usec);
+ } else {
+ wait->tv_usec = p->ev_timeout.tv_usec
+ - now->tv_usec;
+ }
+ verbose(VERB_CLIENT, "winsock_event wait=" ARG_LL "d.%6.6d",
+ (long long)wait->tv_sec, (int)wait->tv_usec);
+ return;
+ }
+#endif
+ /* event times out, remove it */
+ (void)rbtree_delete(base->times, p);
+ p->ev_events &= ~EV_TIMEOUT;
+ fptr_ok(fptr_whitelist_event(p->ev_callback));
+ (*p->ev_callback)(p->ev_fd, EV_TIMEOUT, p->ev_arg);
+ }
+ verbose(VERB_CLIENT, "winsock_event wait=(-1)");
+}
+
+/** handle is_signal events and see if signalled */
+static void handle_signal(struct event* ev)
+{
+ DWORD ret;
+ log_assert(ev->is_signal && ev->hEvent);
+ /* see if the event is signalled */
+ ret = WSAWaitForMultipleEvents(1, &ev->hEvent, 0 /* any object */,
+ 0 /* return immediately */, 0 /* not alertable for IOcomple*/);
+ if(ret == WSA_WAIT_IO_COMPLETION || ret == WSA_WAIT_FAILED) {
+ log_err("WSAWaitForMultipleEvents(signal) failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ return;
+ }
+ if(ret == WSA_WAIT_TIMEOUT) {
+ /* not signalled */
+ return;
+ }
+
+ /* reset the signal */
+ if(!WSAResetEvent(ev->hEvent))
+ log_err("WSAResetEvent failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ /* do the callback (which may set the signal again) */
+ fptr_ok(fptr_whitelist_event(ev->ev_callback));
+ (*ev->ev_callback)(ev->ev_fd, ev->ev_events, ev->ev_arg);
+}
+
+/** call select and callbacks for that */
+static int handle_select(struct event_base* base, struct timeval* wait)
+{
+ DWORD timeout = 0; /* in milliseconds */
+ DWORD ret;
+ struct event* eventlist[WSK_MAX_ITEMS];
+ WSANETWORKEVENTS netev;
+ int i, numwait = 0, startidx = 0, was_timeout = 0;
+ int newstickies = 0;
+ struct timeval nultm;
+
+ verbose(VERB_CLIENT, "winsock_event handle_select");
+
+#ifndef S_SPLINT_S
+ if(wait->tv_sec==(time_t)-1)
+ wait = NULL;
+ if(wait)
+ timeout = wait->tv_sec*1000 + wait->tv_usec/1000;
+ if(base->tcp_stickies) {
+ wait = &nultm;
+ nultm.tv_sec = 0;
+ nultm.tv_usec = 0;
+ timeout = 0; /* no waiting, we have sticky events */
+ }
+#endif
+
+ /* prepare event array */
+ for(i=0; i<base->max; i++) {
+ if(base->items[i]->ev_fd == -1 && !base->items[i]->is_signal)
+ continue; /* skip timer only events */
+ eventlist[numwait] = base->items[i];
+ base->waitfor[numwait++] = base->items[i]->hEvent;
+ if(numwait == WSK_MAX_ITEMS)
+ break; /* sanity check */
+ }
+ log_assert(numwait <= WSA_MAXIMUM_WAIT_EVENTS);
+ verbose(VERB_CLIENT, "winsock_event bmax=%d numwait=%d wait=%x "
+ "timeout=%d", base->max, numwait, (int)wait, (int)timeout);
+
+ /* do the wait */
+ if(numwait == 0) {
+ /* WSAWaitFor.. doesn't like 0 event objects */
+ if(wait) {
+ Sleep(timeout);
+ }
+ was_timeout = 1;
+ } else {
+ ret = WSAWaitForMultipleEvents(numwait, base->waitfor,
+ 0 /* do not wait for all, just one will do */,
+ wait?timeout:WSA_INFINITE,
+ 0); /* we are not alertable (IO completion events) */
+ if(ret == WSA_WAIT_IO_COMPLETION) {
+ log_err("WSAWaitForMultipleEvents failed: WSA_WAIT_IO_COMPLETION");
+ return -1;
+ } else if(ret == WSA_WAIT_FAILED) {
+ log_err("WSAWaitForMultipleEvents failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ return -1;
+ } else if(ret == WSA_WAIT_TIMEOUT) {
+ was_timeout = 1;
+ } else
+ startidx = ret - WSA_WAIT_EVENT_0;
+ }
+ verbose(VERB_CLIENT, "winsock_event wake was_timeout=%d startidx=%d",
+ was_timeout, startidx);
+
+ /* get new time after wait */
+ if(settime(base) < 0)
+ return -1;
+
+ /* callbacks */
+ if(base->tcp_stickies)
+ startidx = 0; /* process all events, some are sticky */
+ for(i=startidx; i<numwait; i++)
+ eventlist[i]->just_checked = 1;
+
+ verbose(VERB_CLIENT, "winsock_event signals");
+ for(i=startidx; i<numwait; i++) {
+ if(!base->waitfor[i])
+ continue; /* was deleted */
+ if(eventlist[i]->is_signal) {
+ eventlist[i]->just_checked = 0;
+ handle_signal(eventlist[i]);
+ }
+ }
+ /* early exit - do not process network, exit quickly */
+ if(base->need_to_exit)
+ return 0;
+
+ verbose(VERB_CLIENT, "winsock_event net");
+ for(i=startidx; i<numwait; i++) {
+ short bits = 0;
+ /* eventlist[i] fired */
+ /* see if eventlist[i] is still valid and just checked from
+ * WSAWaitForEvents */
+ if(!base->waitfor[i])
+ continue; /* was deleted */
+ if(!eventlist[i]->just_checked)
+ continue; /* added by other callback */
+ if(eventlist[i]->is_signal)
+ continue; /* not a network event at all */
+ eventlist[i]->just_checked = 0;
+
+ if(WSAEnumNetworkEvents(eventlist[i]->ev_fd,
+ base->waitfor[i], /* reset the event handle */
+ /*NULL,*/ /* do not reset the event handle */
+ &netev) != 0) {
+ log_err("WSAEnumNetworkEvents failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ return -1;
+ }
+ if((netev.lNetworkEvents & FD_READ)) {
+ if(netev.iErrorCode[FD_READ_BIT] != 0)
+ verbose(VERB_ALGO, "FD_READ_BIT error: %s",
+ wsa_strerror(netev.iErrorCode[FD_READ_BIT]));
+ bits |= EV_READ;
+ }
+ if((netev.lNetworkEvents & FD_WRITE)) {
+ if(netev.iErrorCode[FD_WRITE_BIT] != 0)
+ verbose(VERB_ALGO, "FD_WRITE_BIT error: %s",
+ wsa_strerror(netev.iErrorCode[FD_WRITE_BIT]));
+ bits |= EV_WRITE;
+ }
+ if((netev.lNetworkEvents & FD_CONNECT)) {
+ if(netev.iErrorCode[FD_CONNECT_BIT] != 0)
+ verbose(VERB_ALGO, "FD_CONNECT_BIT error: %s",
+ wsa_strerror(netev.iErrorCode[FD_CONNECT_BIT]));
+ bits |= EV_READ;
+ bits |= EV_WRITE;
+ }
+ if((netev.lNetworkEvents & FD_ACCEPT)) {
+ if(netev.iErrorCode[FD_ACCEPT_BIT] != 0)
+ verbose(VERB_ALGO, "FD_ACCEPT_BIT error: %s",
+ wsa_strerror(netev.iErrorCode[FD_ACCEPT_BIT]));
+ bits |= EV_READ;
+ }
+ if((netev.lNetworkEvents & FD_CLOSE)) {
+ if(netev.iErrorCode[FD_CLOSE_BIT] != 0)
+ verbose(VERB_ALGO, "FD_CLOSE_BIT error: %s",
+ wsa_strerror(netev.iErrorCode[FD_CLOSE_BIT]));
+ bits |= EV_READ;
+ bits |= EV_WRITE;
+ }
+ if(eventlist[i]->is_tcp && eventlist[i]->stick_events) {
+ verbose(VERB_ALGO, "winsock %d pass sticky %s%s",
+ eventlist[i]->ev_fd,
+ (eventlist[i]->old_events&EV_READ)?"EV_READ":"",
+ (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
+ bits |= eventlist[i]->old_events;
+ }
+ if(eventlist[i]->is_tcp && bits) {
+ eventlist[i]->old_events = bits;
+ eventlist[i]->stick_events = 1;
+ if((eventlist[i]->ev_events & bits)) {
+ newstickies = 1;
+ }
+ verbose(VERB_ALGO, "winsock %d store sticky %s%s",
+ eventlist[i]->ev_fd,
+ (eventlist[i]->old_events&EV_READ)?"EV_READ":"",
+ (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
+ }
+ if((bits & eventlist[i]->ev_events)) {
+ verbose(VERB_ALGO, "winsock event callback %p fd=%d "
+ "%s%s%s%s%s ; %s%s%s",
+ eventlist[i], eventlist[i]->ev_fd,
+ (netev.lNetworkEvents&FD_READ)?" FD_READ":"",
+ (netev.lNetworkEvents&FD_WRITE)?" FD_WRITE":"",
+ (netev.lNetworkEvents&FD_CONNECT)?
+ " FD_CONNECT":"",
+ (netev.lNetworkEvents&FD_ACCEPT)?
+ " FD_ACCEPT":"",
+ (netev.lNetworkEvents&FD_CLOSE)?" FD_CLOSE":"",
+ (bits&EV_READ)?" EV_READ":"",
+ (bits&EV_WRITE)?" EV_WRITE":"",
+ (bits&EV_TIMEOUT)?" EV_TIMEOUT":"");
+
+ fptr_ok(fptr_whitelist_event(
+ eventlist[i]->ev_callback));
+ (*eventlist[i]->ev_callback)(eventlist[i]->ev_fd,
+ bits & eventlist[i]->ev_events,
+ eventlist[i]->ev_arg);
+ }
+ if(eventlist[i]->is_tcp && bits)
+ verbose(VERB_ALGO, "winsock %d got sticky %s%s",
+ eventlist[i]->ev_fd,
+ (eventlist[i]->old_events&EV_READ)?"EV_READ":"",
+ (eventlist[i]->old_events&EV_WRITE)?"EV_WRITE":"");
+ }
+ verbose(VERB_CLIENT, "winsock_event net");
+ if(base->tcp_reinvigorated) {
+ verbose(VERB_CLIENT, "winsock_event reinvigorated");
+ base->tcp_reinvigorated = 0;
+ newstickies = 1;
+ }
+ base->tcp_stickies = newstickies;
+ verbose(VERB_CLIENT, "winsock_event handle_select end");
+ return 0;
+}
+
+int event_base_dispatch(struct event_base *base)
+{
+ struct timeval wait;
+ if(settime(base) < 0)
+ return -1;
+ while(!base->need_to_exit)
+ {
+ /* see if timeouts need handling */
+ handle_timeouts(base, base->time_tv, &wait);
+ if(base->need_to_exit)
+ return 0;
+ /* do select */
+ if(handle_select(base, &wait) < 0) {
+ if(base->need_to_exit)
+ return 0;
+ return -1;
+ }
+ }
+ return 0;
+}
+
+int event_base_loopexit(struct event_base *base,
+ struct timeval * ATTR_UNUSED(tv))
+{
+ verbose(VERB_CLIENT, "winsock_event loopexit");
+ base->need_to_exit = 1;
+ return 0;
+}
+
+void event_base_free(struct event_base *base)
+{
+ verbose(VERB_CLIENT, "winsock_event event_base_free");
+ if(!base)
+ return;
+ if(base->items)
+ free(base->items);
+ if(base->times)
+ free(base->times);
+ if(base->signals)
+ free(base->signals);
+ free(base);
+}
+
+void event_set(struct event *ev, int fd, short bits,
+ void (*cb)(int, short, void *), void *arg)
+{
+ ev->node.key = ev;
+ ev->ev_fd = fd;
+ ev->ev_events = bits;
+ ev->ev_callback = cb;
+ fptr_ok(fptr_whitelist_event(ev->ev_callback));
+ ev->ev_arg = arg;
+ ev->just_checked = 0;
+ ev->added = 0;
+}
+
+int event_base_set(struct event_base *base, struct event *ev)
+{
+ ev->ev_base = base;
+ ev->old_events = 0;
+ ev->stick_events = 0;
+ ev->added = 0;
+ return 0;
+}
+
+int event_add(struct event *ev, struct timeval *tv)
+{
+ verbose(VERB_ALGO, "event_add %p added=%d fd=%d tv=" ARG_LL "d %s%s%s",
+ ev, ev->added, ev->ev_fd,
+ (tv?(long long)tv->tv_sec*1000+(long long)tv->tv_usec/1000:-1),
+ (ev->ev_events&EV_READ)?" EV_READ":"",
+ (ev->ev_events&EV_WRITE)?" EV_WRITE":"",
+ (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
+ if(ev->added)
+ event_del(ev);
+ log_assert(ev->ev_fd==-1 || find_fd(ev->ev_base, ev->ev_fd) == -1);
+ ev->is_tcp = 0;
+ ev->is_signal = 0;
+ ev->just_checked = 0;
+
+ if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
+ BOOL b=0;
+ int t, l;
+ long events = 0;
+
+ if(ev->ev_base->max == ev->ev_base->cap)
+ return -1;
+ ev->idx = ev->ev_base->max++;
+ ev->ev_base->items[ev->idx] = ev;
+
+ if( (ev->ev_events&EV_READ) )
+ events |= FD_READ;
+ if( (ev->ev_events&EV_WRITE) )
+ events |= FD_WRITE;
+ l = sizeof(t);
+ if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_TYPE,
+ (void*)&t, &l) != 0)
+ log_err("getsockopt(SO_TYPE) failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ if(t == SOCK_STREAM) {
+ /* TCP socket */
+ ev->is_tcp = 1;
+ events |= FD_CLOSE;
+ if( (ev->ev_events&EV_WRITE) )
+ events |= FD_CONNECT;
+ l = sizeof(b);
+ if(getsockopt(ev->ev_fd, SOL_SOCKET, SO_ACCEPTCONN,
+ (void*)&b, &l) != 0)
+ log_err("getsockopt(SO_ACCEPTCONN) failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ if(b) /* TCP accept socket */
+ events |= FD_ACCEPT;
+ }
+ ev->hEvent = WSACreateEvent();
+ if(ev->hEvent == WSA_INVALID_EVENT)
+ log_err("WSACreateEvent failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ /* automatically sets fd to nonblocking mode.
+ * nonblocking cannot be disabled, until wsaES(fd, NULL, 0) */
+ if(WSAEventSelect(ev->ev_fd, ev->hEvent, events) != 0) {
+ log_err("WSAEventSelect failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ }
+ if(ev->is_tcp && ev->stick_events &&
+ (ev->ev_events & ev->old_events)) {
+ /* go to processing the sticky event right away */
+ ev->ev_base->tcp_reinvigorated = 1;
+ }
+ }
+
+ if(tv && (ev->ev_events&EV_TIMEOUT)) {
+#ifndef S_SPLINT_S
+ struct timeval *now = ev->ev_base->time_tv;
+ ev->ev_timeout.tv_sec = tv->tv_sec + now->tv_sec;
+ ev->ev_timeout.tv_usec = tv->tv_usec + now->tv_usec;
+ while(ev->ev_timeout.tv_usec > 1000000) {
+ ev->ev_timeout.tv_usec -= 1000000;
+ ev->ev_timeout.tv_sec++;
+ }
+#endif
+ (void)rbtree_insert(ev->ev_base->times, &ev->node);
+ }
+ ev->added = 1;
+ return 0;
+}
+
+int event_del(struct event *ev)
+{
+ verbose(VERB_ALGO, "event_del %p added=%d fd=%d tv=" ARG_LL "d %s%s%s",
+ ev, ev->added, ev->ev_fd,
+ (ev->ev_events&EV_TIMEOUT)?(long long)ev->ev_timeout.tv_sec*1000+
+ (long long)ev->ev_timeout.tv_usec/1000:-1,
+ (ev->ev_events&EV_READ)?" EV_READ":"",
+ (ev->ev_events&EV_WRITE)?" EV_WRITE":"",
+ (ev->ev_events&EV_TIMEOUT)?" EV_TIMEOUT":"");
+ if(!ev->added)
+ return 0;
+ log_assert(ev->added);
+ if((ev->ev_events&EV_TIMEOUT))
+ (void)rbtree_delete(ev->ev_base->times, &ev->node);
+ if((ev->ev_events&(EV_READ|EV_WRITE)) && ev->ev_fd != -1) {
+ log_assert(ev->ev_base->max > 0);
+ /* remove item and compact the list */
+ ev->ev_base->items[ev->idx] =
+ ev->ev_base->items[ev->ev_base->max-1];
+ ev->ev_base->items[ev->ev_base->max-1] = NULL;
+ ev->ev_base->max--;
+ if(ev->idx < ev->ev_base->max)
+ ev->ev_base->items[ev->idx]->idx = ev->idx;
+ zero_waitfor(ev->ev_base->waitfor, ev->hEvent);
+
+ if(WSAEventSelect(ev->ev_fd, ev->hEvent, 0) != 0)
+ log_err("WSAEventSelect(disable) failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ if(!WSACloseEvent(ev->hEvent))
+ log_err("WSACloseEvent failed: %s",
+ wsa_strerror(WSAGetLastError()));
+ }
+ ev->just_checked = 0;
+ ev->added = 0;
+ return 0;
+}
+
+/** which base gets to handle signals */
+static struct event_base* signal_base = NULL;
+/** signal handler */
+static RETSIGTYPE sigh(int sig)
+{
+ struct event* ev;
+ if(!signal_base || sig < 0 || sig >= MAX_SIG)
+ return;
+ ev = signal_base->signals[sig];
+ if(!ev)
+ return;
+ fptr_ok(fptr_whitelist_event(ev->ev_callback));
+ (*ev->ev_callback)(sig, EV_SIGNAL, ev->ev_arg);
+}
+
+int signal_add(struct event *ev, struct timeval * ATTR_UNUSED(tv))
+{
+ if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
+ return -1;
+ signal_base = ev->ev_base;
+ ev->ev_base->signals[ev->ev_fd] = ev;
+ ev->added = 1;
+ if(signal(ev->ev_fd, sigh) == SIG_ERR) {
+ return -1;
+ }
+ return 0;
+}
+
+int signal_del(struct event *ev)
+{
+ if(ev->ev_fd == -1 || ev->ev_fd >= MAX_SIG)
+ return -1;
+ ev->ev_base->signals[ev->ev_fd] = NULL;
+ ev->added = 0;
+ return 0;
+}
+
+void winsock_tcp_wouldblock(struct event* ev, int eventbits)
+{
+ verbose(VERB_ALGO, "winsock: tcp wouldblock %s",
+ eventbits==EV_READ?"EV_READ":"EV_WRITE");
+ ev->old_events &= (~eventbits);
+ if(ev->old_events == 0)
+ ev->stick_events = 0;
+ /* in case this is the last sticky event, we could
+ * possibly run an empty handler loop to reset the base
+ * tcp_stickies variable
+ */
+}
+
+int winsock_register_wsaevent(struct event_base* base, struct event* ev,
+ WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg)
+{
+ if(base->max == base->cap)
+ return 0;
+ memset(ev, 0, sizeof(*ev));
+ ev->ev_fd = -1;
+ ev->ev_events = EV_READ;
+ ev->ev_callback = cb;
+ ev->ev_arg = arg;
+ ev->is_signal = 1;
+ ev->hEvent = wsaevent;
+ ev->added = 1;
+ ev->ev_base = base;
+ ev->idx = ev->ev_base->max++;
+ ev->ev_base->items[ev->idx] = ev;
+ return 1;
+}
+
+void winsock_unregister_wsaevent(struct event* ev)
+{
+ if(!ev || !ev->added) return;
+ log_assert(ev->added && ev->ev_base->max > 0)
+ /* remove item and compact the list */
+ ev->ev_base->items[ev->idx] = ev->ev_base->items[ev->ev_base->max-1];
+ ev->ev_base->items[ev->ev_base->max-1] = NULL;
+ ev->ev_base->max--;
+ if(ev->idx < ev->ev_base->max)
+ ev->ev_base->items[ev->idx]->idx = ev->idx;
+ ev->added = 0;
+}
+
+#else /* USE_WINSOCK */
+/** symbol so this codefile defines symbols. pleasing ranlib on OSX 10.5 */
+int winsock_unused_symbol = 1;
+#endif /* USE_WINSOCK */
diff --git a/external/unbound/util/winsock_event.h b/external/unbound/util/winsock_event.h
new file mode 100644
index 000000000..40892c14b
--- /dev/null
+++ b/external/unbound/util/winsock_event.h
@@ -0,0 +1,264 @@
+/*
+ * util/winsock_event.h - unbound event handling for winsock on windows
+ *
+ * Copyright (c) 2008, 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 COPYRIGHT
+ * HOLDER 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 interface functions with the WinSock2 API on Windows.
+ * It uses the winsock WSAWaitForMultipleEvents interface on a number of
+ * sockets.
+ *
+ * Note that windows can only wait for max 64 events at one time.
+ *
+ * Also, file descriptors cannot be waited for.
+ *
+ * Named pipes are not easily available (and are not usable in select() ).
+ * For interprocess communication, it is possible to wait for a hEvent to
+ * be signaled by another thread.
+ *
+ * When a socket becomes readable, then it will not be flagged as
+ * readable again until you have gotten WOULDBLOCK from a recv routine.
+ * That means the event handler must store the readability (edge notify)
+ * and process the incoming data until it blocks.
+ * The function performing recv then has to inform the event handler that
+ * the socket has blocked, and the event handler can mark it as such.
+ * Thus, this file transforms the edge notify from windows to a level notify
+ * that is compatible with UNIX.
+ * The WSAEventSelect page says that it does do level notify, as long
+ * as you call a recv/write/accept at least once when it is signalled.
+ * This last bit is not true, even though documented in server2008 api docs
+ * from microsoft, it does not happen at all. Instead you have to test for
+ * WSAEWOULDBLOCK on a tcp stream, and only then retest the socket.
+ * And before that remember the previous result as still valid.
+ *
+ * To stay 'fair', instead of emptying a socket completely, the event handler
+ * can test the other (marked as blocking) sockets for new events.
+ *
+ * Additionally, TCP accept sockets get special event support.
+ *
+ * Socket numbers are not starting small, they can be any number (say 33060).
+ * Therefore, bitmaps are not used, but arrays.
+ *
+ * on winsock, you must use recv() and send() for TCP reads and writes,
+ * not read() and write(), those work only on files.
+ *
+ * Also fseek and fseeko do not work if a FILE is not fopen-ed in binary mode.
+ *
+ * When under a high load windows gives out lots of errors, from recvfrom
+ * on udp sockets for example (WSAECONNRESET). Even though the udp socket
+ * has no connection per se.
+ */
+
+#ifndef UTIL_WINSOCK_EVENT_H
+#define UTIL_WINSOCK_EVENT_H
+
+#ifdef USE_WINSOCK
+
+#ifndef HAVE_EVENT_BASE_FREE
+#define HAVE_EVENT_BASE_FREE
+#endif
+
+/** event timeout */
+#define EV_TIMEOUT 0x01
+/** event fd readable */
+#define EV_READ 0x02
+/** event fd writable */
+#define EV_WRITE 0x04
+/** event signal */
+#define EV_SIGNAL 0x08
+/** event must persist */
+#define EV_PERSIST 0x10
+
+/* needs our redblack tree */
+#include "rbtree.h"
+
+/** max number of signals to support */
+#define MAX_SIG 32
+
+/** The number of items that the winsock event handler can service.
+ * Windows cannot handle more anyway */
+#define WSK_MAX_ITEMS 64
+
+/**
+ * event base for winsock event handler
+ */
+struct event_base
+{
+ /** sorted by timeout (absolute), ptr */
+ rbtree_t* times;
+ /** array (first part in use) of handles to work on */
+ struct event** items;
+ /** number of items in use in array */
+ int max;
+ /** capacity of array, size of array in items */
+ int cap;
+ /** array of 0 - maxsig of ptr to event for it */
+ struct event** signals;
+ /** if we need to exit */
+ int need_to_exit;
+ /** where to store time in seconds */
+ time_t* time_secs;
+ /** where to store time in microseconds */
+ struct timeval* time_tv;
+ /**
+ * TCP streams have sticky events to them, these are not
+ * reported by the windows event system anymore, we have to
+ * keep reporting those events as present until wouldblock() is
+ * signalled by the handler back to use.
+ */
+ int tcp_stickies;
+ /**
+ * should next cycle process reinvigorated stickies,
+ * these are stickies that have been stored, but due to a new
+ * event_add a sudden interest in the event has incepted.
+ */
+ int tcp_reinvigorated;
+ /** The list of events that is currently being processed. */
+ WSAEVENT waitfor[WSK_MAX_ITEMS];
+};
+
+/**
+ * Event structure. Has some of the event elements.
+ */
+struct event {
+ /** node in timeout rbtree */
+ rbnode_t node;
+ /** is event already added */
+ int added;
+
+ /** event base it belongs to */
+ struct event_base *ev_base;
+ /** fd to poll or -1 for timeouts. signal number for sigs. */
+ int ev_fd;
+ /** what events this event is interested in, see EV_.. above. */
+ short ev_events;
+ /** timeout value */
+ struct timeval ev_timeout;
+
+ /** callback to call: fd, eventbits, userarg */
+ void (*ev_callback)(int, short, void *);
+ /** callback user arg */
+ void *ev_arg;
+
+ /* ----- nonpublic part, for winsock_event only ----- */
+ /** index of this event in the items array (if added) */
+ int idx;
+ /** the event handle to wait for new events to become ready */
+ WSAEVENT hEvent;
+ /** true if this filedes is a TCP socket and needs special attention */
+ int is_tcp;
+ /** remembered EV_ values */
+ short old_events;
+ /** should remembered EV_ values be used for TCP streams.
+ * Reset after WOULDBLOCK is signaled using the function. */
+ int stick_events;
+
+ /** true if this event is a signaling WSAEvent by the user.
+ * User created and user closed WSAEvent. Only signaled/unsigneled,
+ * no read/write/distinctions needed. */
+ int is_signal;
+ /** used during callbacks to see which events were just checked */
+ int just_checked;
+};
+
+/** create event base */
+void *event_init(time_t* time_secs, struct timeval* time_tv);
+/** get version */
+const char *event_get_version(void);
+/** get polling method (select,epoll) */
+const char *event_get_method(void);
+/** run select in a loop */
+int event_base_dispatch(struct event_base *);
+/** exit that loop */
+int event_base_loopexit(struct event_base *, struct timeval *);
+/** free event base. Free events yourself */
+void event_base_free(struct event_base *);
+/** set content of event */
+void event_set(struct event *, int, short, void (*)(int, short, void *), void *);
+
+/** add event to a base. You *must* call this for every event. */
+int event_base_set(struct event_base *, struct event *);
+/** add event to make it active. You may not change it with event_set anymore */
+int event_add(struct event *, struct timeval *);
+/** remove event. You may change it again */
+int event_del(struct event *);
+
+#define evtimer_add(ev, tv) event_add(ev, tv)
+#define evtimer_del(ev) event_del(ev)
+
+/* uses different implementation. Cannot mix fd/timeouts and signals inside
+ * the same struct event. create several event structs for that. */
+/** install signal handler */
+int signal_add(struct event *, struct timeval *);
+/** set signal event contents */
+#define signal_set(ev, x, cb, arg) \
+ event_set(ev, x, EV_SIGNAL|EV_PERSIST, cb, arg)
+/** remove signal handler */
+int signal_del(struct event *);
+
+/** compare events in tree, based on timevalue, ptr for uniqueness */
+int mini_ev_cmp(const void* a, const void* b);
+
+/**
+ * Routine for windows only, where the handling layer can signal that
+ * a TCP stream encountered WSAEWOULDBLOCK for a stream and thus needs
+ * retesting the event.
+ * Pass if EV_READ or EV_WRITE gave wouldblock.
+ */
+void winsock_tcp_wouldblock(struct event* ev, int eventbit);
+
+/**
+ * Routine for windows only. where you pass a signal WSAEvent that
+ * you wait for. When the event is signaled, the callback gets called.
+ * The callback has to WSAResetEvent to disable the signal.
+ * @param base: the event base.
+ * @param ev: the event structure for data storage
+ * can be passed uninitialised.
+ * @param wsaevent: the WSAEvent that gets signaled.
+ * @param cb: callback routine.
+ * @param arg: user argument to callback routine.
+ * @return false on error.
+ */
+int winsock_register_wsaevent(struct event_base* base, struct event* ev,
+ WSAEVENT wsaevent, void (*cb)(int, short, void*), void* arg);
+
+/**
+ * Unregister a wsaevent. User has to close the WSAEVENT itself.
+ * @param ev: event data storage.
+ */
+void winsock_unregister_wsaevent(struct event* ev);
+
+#endif /* USE_WINSOCK */
+#endif /* UTIL_WINSOCK_EVENT_H */