diff options
Diffstat (limited to 'external/unbound/testcode')
36 files changed, 0 insertions, 16999 deletions
diff --git a/external/unbound/testcode/asynclook.c b/external/unbound/testcode/asynclook.c deleted file mode 100644 index a2bdb6213..000000000 --- a/external/unbound/testcode/asynclook.c +++ /dev/null @@ -1,528 +0,0 @@ -/* - * testcode/asynclook.c - debug program perform async libunbound queries. - * - * 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 program shows the results from several background lookups, - * while printing time in the foreground. - */ - -#include "config.h" -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#include "libunbound/unbound.h" -#include "libunbound/context.h" -#include "util/locks.h" -#include "util/log.h" -#include "sldns/rrdef.h" -#ifdef UNBOUND_ALLOC_LITE -#undef malloc -#undef calloc -#undef realloc -#undef free -#undef strdup -#endif - -/** keeping track of the async ids */ -struct track_id { - /** the id to pass to libunbound to cancel */ - int id; - /** true if cancelled */ - int cancel; - /** a lock on this structure for thread safety */ - lock_basic_type lock; -}; - -/** - * result list for the lookups - */ -struct lookinfo { - /** name to look up */ - char* name; - /** tracking number that can be used to cancel the query */ - int async_id; - /** error code from libunbound */ - int err; - /** result from lookup */ - struct ub_result* result; -}; - -/** global variable to see how many queries we have left */ -static int num_wait = 0; - -/** usage information for asynclook */ -static void usage(char* argv[]) -{ - printf("usage: %s [options] name ...\n", argv[0]); - printf("names are looked up at the same time, asynchronously.\n"); - printf(" -b : use blocking requests\n"); - printf(" -c : cancel the requests\n"); - printf(" -d : enable debug output\n"); - printf(" -f addr : use addr, forward to that server\n"); - printf(" -h : this help message\n"); - printf(" -H fname : read hosts from fname\n"); - printf(" -r fname : read resolv.conf from fname\n"); - printf(" -t : use a resolver thread instead of forking a process\n"); - printf(" -x : perform extended threaded test\n"); - exit(1); -} - -/** print result from lookup nicely */ -static void -print_result(struct lookinfo* info) -{ - char buf[100]; - if(info->err) /* error (from libunbound) */ - printf("%s: error %s\n", info->name, - ub_strerror(info->err)); - else if(!info->result) - printf("%s: cancelled\n", info->name); - else if(info->result->havedata) - printf("%s: %s\n", info->name, - inet_ntop(AF_INET, info->result->data[0], - buf, (socklen_t)sizeof(buf))); - else { - /* there is no data, why that? */ - if(info->result->rcode == 0 /*noerror*/ || - info->result->nxdomain) - printf("%s: no data %s\n", info->name, - info->result->nxdomain?"(no such host)": - "(no IP4 address)"); - else /* some error (from the server) */ - printf("%s: DNS error %d\n", info->name, - info->result->rcode); - } -} - -/** this is a function of type ub_callback_t */ -static void -lookup_is_done(void* mydata, int err, struct ub_result* result) -{ - /* cast mydata back to the correct type */ - struct lookinfo* info = (struct lookinfo*)mydata; - fprintf(stderr, "name %s resolved\n", info->name); - info->err = err; - info->result = result; - /* one less to wait for */ - num_wait--; -} - -/** check error, if bad, exit with error message */ -static void -checkerr(const char* desc, int err) -{ - if(err != 0) { - printf("%s error: %s\n", desc, ub_strerror(err)); - exit(1); - } -} - -#ifdef THREADS_DISABLED -/** only one process can communicate with async worker */ -#define NUMTHR 1 -#else /* have threads */ -/** number of threads to make in extended test */ -#define NUMTHR 10 -#endif - -/** struct for extended thread info */ -struct ext_thr_info { - /** thread num for debug */ - int thread_num; - /** thread id */ - ub_thread_type tid; - /** context */ - struct ub_ctx* ctx; - /** size of array to query */ - int argc; - /** array of names to query */ - char** argv; - /** number of queries to do */ - int numq; -}; - -/** if true, we are testing against 'localhost' and extra checking is done */ -static int q_is_localhost = 0; - -/** check result structure for the 'correct' answer */ -static void -ext_check_result(const char* desc, int err, struct ub_result* result) -{ - checkerr(desc, err); - if(result == NULL) { - printf("%s: error result is NULL.\n", desc); - exit(1); - } - if(q_is_localhost) { - if(strcmp(result->qname, "localhost") != 0) { - printf("%s: error result has wrong qname.\n", desc); - exit(1); - } - if(result->qtype != LDNS_RR_TYPE_A) { - printf("%s: error result has wrong qtype.\n", desc); - exit(1); - } - if(result->qclass != LDNS_RR_CLASS_IN) { - printf("%s: error result has wrong qclass.\n", desc); - exit(1); - } - if(result->data == NULL) { - printf("%s: error result->data is NULL.\n", desc); - exit(1); - } - if(result->len == NULL) { - printf("%s: error result->len is NULL.\n", desc); - exit(1); - } - if(result->rcode != 0) { - printf("%s: error result->rcode is set.\n", desc); - exit(1); - } - if(result->havedata == 0) { - printf("%s: error result->havedata is unset.\n", desc); - exit(1); - } - if(result->nxdomain != 0) { - printf("%s: error result->nxdomain is set.\n", desc); - exit(1); - } - if(result->secure || result->bogus) { - printf("%s: error result->secure or bogus is set.\n", - desc); - exit(1); - } - if(result->data[0] == NULL) { - printf("%s: error result->data[0] is NULL.\n", desc); - exit(1); - } - if(result->len[0] != 4) { - printf("%s: error result->len[0] is wrong.\n", desc); - exit(1); - } - if(result->len[1] != 0 || result->data[1] != NULL) { - printf("%s: error result->data[1] or len[1] is " - "wrong.\n", desc); - exit(1); - } - if(result->answer_packet == NULL) { - printf("%s: error result->answer_packet is NULL.\n", - desc); - exit(1); - } - if(result->answer_len != 54) { - printf("%s: error result->answer_len is wrong.\n", - desc); - exit(1); - } - } -} - -/** extended bg result callback, this function is ub_callback_t */ -static void -ext_callback(void* mydata, int err, struct ub_result* result) -{ - struct track_id* my_id = (struct track_id*)mydata; - int doprint = 0; - if(my_id) { - /* I have an id, make sure we are not cancelled */ - lock_basic_lock(&my_id->lock); - if(doprint) - printf("cb %d: ", my_id->id); - if(my_id->cancel) { - printf("error: query id=%d returned, but was cancelled\n", - my_id->id); - abort(); - exit(1); - } - lock_basic_unlock(&my_id->lock); - } - ext_check_result("ext_callback", err, result); - log_assert(result); - if(doprint) { - struct lookinfo pi; - pi.name = result?result->qname:"noname"; - pi.result = result; - pi.err = 0; - print_result(&pi); - } - ub_resolve_free(result); -} - -/** extended thread worker */ -static void* -ext_thread(void* arg) -{ - struct ext_thr_info* inf = (struct ext_thr_info*)arg; - int i, r; - struct ub_result* result; - struct track_id* async_ids = NULL; - log_thread_set(&inf->thread_num); - if(inf->thread_num > NUMTHR*2/3) { - async_ids = (struct track_id*)calloc((size_t)inf->numq, sizeof(struct track_id)); - if(!async_ids) { - printf("out of memory\n"); - exit(1); - } - for(i=0; i<inf->numq; i++) { - lock_basic_init(&async_ids[i].lock); - } - } - for(i=0; i<inf->numq; i++) { - if(async_ids) { - r = ub_resolve_async(inf->ctx, - inf->argv[i%inf->argc], LDNS_RR_TYPE_A, - LDNS_RR_CLASS_IN, &async_ids[i], ext_callback, - &async_ids[i].id); - checkerr("ub_resolve_async", r); - if(i > 100) { - lock_basic_lock(&async_ids[i-100].lock); - r = ub_cancel(inf->ctx, async_ids[i-100].id); - if(r != UB_NOID) - async_ids[i-100].cancel=1; - lock_basic_unlock(&async_ids[i-100].lock); - if(r != UB_NOID) - checkerr("ub_cancel", r); - } - } else if(inf->thread_num > NUMTHR/2) { - /* async */ - r = ub_resolve_async(inf->ctx, - inf->argv[i%inf->argc], LDNS_RR_TYPE_A, - LDNS_RR_CLASS_IN, NULL, ext_callback, NULL); - checkerr("ub_resolve_async", r); - } else { - /* blocking */ - r = ub_resolve(inf->ctx, inf->argv[i%inf->argc], - LDNS_RR_TYPE_A, LDNS_RR_CLASS_IN, &result); - ext_check_result("ub_resolve", r, result); - ub_resolve_free(result); - } - } - if(inf->thread_num > NUMTHR/2) { - r = ub_wait(inf->ctx); - checkerr("ub_ctx_wait", r); - } - /* if these locks are destroyed, or if the async_ids is freed, then - a use-after-free happens in another thread. - The allocation is only part of this test, though. */ - /* - if(async_ids) { - for(i=0; i<inf->numq; i++) { - lock_basic_destroy(&async_ids[i].lock); - } - } - free(async_ids); - */ - - return NULL; -} - -/** perform extended threaded test */ -static int -ext_test(struct ub_ctx* ctx, int argc, char** argv) -{ - struct ext_thr_info inf[NUMTHR]; - int i; - if(argc == 1 && strcmp(argv[0], "localhost") == 0) - q_is_localhost = 1; - printf("extended test start (%d threads)\n", NUMTHR); - for(i=0; i<NUMTHR; i++) { - /* 0 = this, 1 = library bg worker */ - inf[i].thread_num = i+2; - inf[i].ctx = ctx; - inf[i].argc = argc; - inf[i].argv = argv; - inf[i].numq = 100; - ub_thread_create(&inf[i].tid, ext_thread, &inf[i]); - } - /* the work happens here */ - for(i=0; i<NUMTHR; i++) { - ub_thread_join(inf[i].tid); - } - printf("extended test end\n"); - ub_ctx_delete(ctx); - checklock_stop(); - return 0; -} - -/** getopt global, in case header files fail to declare it. */ -extern int optind; -/** getopt global, in case header files fail to declare it. */ -extern char* optarg; - -/** main program for asynclook */ -int main(int argc, char** argv) -{ - int c; - struct ub_ctx* ctx; - struct lookinfo* lookups; - int i, r, cancel=0, blocking=0, ext=0; - - /* init log now because solaris thr_key_create() is not threadsafe */ - log_init(0,0,0); - /* lock debug start (if any) */ - checklock_start(); - - /* create context */ - ctx = ub_ctx_create(); - if(!ctx) { - printf("could not create context, %s\n", strerror(errno)); - return 1; - } - - /* command line options */ - if(argc == 1) { - usage(argv); - } - while( (c=getopt(argc, argv, "bcdf:hH:r:tx")) != -1) { - switch(c) { - case 'd': - r = ub_ctx_debuglevel(ctx, 3); - checkerr("ub_ctx_debuglevel", r); - break; - case 't': - r = ub_ctx_async(ctx, 1); - checkerr("ub_ctx_async", r); - break; - case 'c': - cancel = 1; - break; - case 'b': - blocking = 1; - break; - case 'r': - r = ub_ctx_resolvconf(ctx, optarg); - if(r != 0) { - printf("ub_ctx_resolvconf " - "error: %s : %s\n", - ub_strerror(r), - strerror(errno)); - return 1; - } - break; - case 'H': - r = ub_ctx_hosts(ctx, optarg); - if(r != 0) { - printf("ub_ctx_hosts " - "error: %s : %s\n", - ub_strerror(r), - strerror(errno)); - return 1; - } - break; - case 'f': - r = ub_ctx_set_fwd(ctx, optarg); - checkerr("ub_ctx_set_fwd", r); - break; - case 'x': - ext = 1; - break; - case 'h': - case '?': - default: - usage(argv); - } - } - argc -= optind; - argv += optind; - - if(ext) - return ext_test(ctx, argc, argv); - - /* allocate array for results. */ - lookups = (struct lookinfo*)calloc((size_t)argc, - sizeof(struct lookinfo)); - if(!lookups) { - printf("out of memory\n"); - return 1; - } - - /* perform asynchronous calls */ - num_wait = argc; - for(i=0; i<argc; i++) { - lookups[i].name = argv[i]; - if(blocking) { - fprintf(stderr, "lookup %s\n", argv[i]); - r = ub_resolve(ctx, argv[i], LDNS_RR_TYPE_A, - LDNS_RR_CLASS_IN, &lookups[i].result); - checkerr("ub_resolve", r); - } else { - fprintf(stderr, "start async lookup %s\n", argv[i]); - r = ub_resolve_async(ctx, argv[i], LDNS_RR_TYPE_A, - LDNS_RR_CLASS_IN, &lookups[i], &lookup_is_done, - &lookups[i].async_id); - checkerr("ub_resolve_async", r); - } - } - if(blocking) - num_wait = 0; - else if(cancel) { - for(i=0; i<argc; i++) { - fprintf(stderr, "cancel %s\n", argv[i]); - r = ub_cancel(ctx, lookups[i].async_id); - if(r != UB_NOID) - checkerr("ub_cancel", r); - } - num_wait = 0; - } - - /* wait while the hostnames are looked up. Do something useful here */ - if(num_wait > 0) - for(i=0; i<1000; i++) { - usleep(100000); - fprintf(stderr, "%g seconds passed\n", 0.1*(double)i); - r = ub_process(ctx); - checkerr("ub_process", r); - if(num_wait == 0) - break; - } - if(i>=999) { - printf("timed out\n"); - return 0; - } - printf("lookup complete\n"); - - /* print lookup results */ - for(i=0; i<argc; i++) { - print_result(&lookups[i]); - ub_resolve_free(lookups[i].result); - } - - ub_ctx_delete(ctx); - free(lookups); - checklock_stop(); - return 0; -} diff --git a/external/unbound/testcode/checklocks.c b/external/unbound/testcode/checklocks.c deleted file mode 100644 index 7e6f0bb5d..000000000 --- a/external/unbound/testcode/checklocks.c +++ /dev/null @@ -1,859 +0,0 @@ -/** - * testcode/checklocks.c - wrapper on locks that checks access. - * - * 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 <signal.h> -#include "util/locks.h" /* include before checklocks.h */ -#include "testcode/checklocks.h" - -/** - * \file - * Locks that are checked. - * - * Ugly hack: uses the fact that workers start with an int thread_num, and - * are passed to thread_create to make the thread numbers here the same as - * those used for logging which is nice. - * - * Todo: - * - debug status print, of thread lock stacks, and current waiting. - */ -#ifdef USE_THREAD_DEBUG - -/** How long to wait before lock attempt is a failure. */ -#define CHECK_LOCK_TIMEOUT 120 /* seconds */ -/** How long to wait before join attempt is a failure. */ -#define CHECK_JOIN_TIMEOUT 120 /* seconds */ - -/** if key has been created */ -static int key_created = 0; -/** if the key was deleted, i.e. we have quit */ -static int key_deleted = 0; -/** we hide the thread debug info with this key. */ -static ub_thread_key_type thr_debug_key; -/** the list of threads, so all threads can be examined. NULL if unused. */ -static struct thr_check* thread_infos[THRDEBUG_MAX_THREADS]; -/** do we check locking order */ -int check_locking_order = 1; -/** the pid of this runset, reasonably unique. */ -static pid_t check_lock_pid; - -/** print all possible debug info on the state of the system */ -static void total_debug_info(void); - -/** print pretty lock error and exit */ -static void lock_error(struct checked_lock* lock, - const char* func, const char* file, int line, const char* err) -{ - log_err("lock error (description follows)"); - log_err("Created at %s %s:%d", lock->create_func, - lock->create_file, lock->create_line); - if(lock->holder_func && lock->holder_file) - log_err("Previously %s %s:%d", lock->holder_func, - lock->holder_file, lock->holder_line); - log_err("At %s %s:%d", func, file, line); - log_err("Error for %s lock: %s", - (lock->type==check_lock_mutex)?"mutex": ( - (lock->type==check_lock_spinlock)?"spinlock": ( - (lock->type==check_lock_rwlock)?"rwlock": "badtype")), err); - log_err("complete status display:"); - total_debug_info(); - fatal_exit("bailing out"); -} - -/** - * Obtain lock on debug lock structure. This could be a deadlock by the caller. - * The debug code itself does not deadlock. Anyway, check with timeouts. - * @param lock: on what to acquire lock. - * @param func: user level caller identification. - * @param file: user level caller identification. - * @param line: user level caller identification. - */ -static void -acquire_locklock(struct checked_lock* lock, - const char* func, const char* file, int line) -{ - struct timespec to; - int err; - int contend = 0; - /* first try; inc contention counter if not immediately */ - if((err = pthread_mutex_trylock(&lock->lock))) { - if(err==EBUSY) - contend++; - else fatal_exit("error in mutex_trylock: %s", strerror(err)); - } - if(!err) - return; /* immediate success */ - to.tv_sec = time(NULL) + CHECK_LOCK_TIMEOUT; - to.tv_nsec = 0; - err = pthread_mutex_timedlock(&lock->lock, &to); - if(err) { - log_err("in acquiring locklock: %s", strerror(err)); - lock_error(lock, func, file, line, "acquire locklock"); - } - /* since we hold the lock, we can edit the contention_count */ - lock->contention_count += contend; -} - -/** add protected region */ -void -lock_protect(void *p, void* area, size_t size) -{ - struct checked_lock* lock = *(struct checked_lock**)p; - struct protected_area* e = (struct protected_area*)malloc( - sizeof(struct protected_area)); - if(!e) - fatal_exit("lock_protect: out of memory"); - e->region = area; - e->size = size; - e->hold = malloc(size); - if(!e->hold) - fatal_exit("lock_protect: out of memory"); - memcpy(e->hold, e->region, e->size); - - acquire_locklock(lock, __func__, __FILE__, __LINE__); - e->next = lock->prot; - lock->prot = e; - LOCKRET(pthread_mutex_unlock(&lock->lock)); -} - -/** remove protected region */ -void -lock_unprotect(void* mangled, void* area) -{ - struct checked_lock* lock = *(struct checked_lock**)mangled; - struct protected_area* p, **prevp; - if(!lock) - return; - acquire_locklock(lock, __func__, __FILE__, __LINE__); - p = lock->prot; - prevp = &lock->prot; - while(p) { - if(p->region == area) { - *prevp = p->next; - free(p->hold); - free(p); - LOCKRET(pthread_mutex_unlock(&lock->lock)); - return; - } - prevp = &p->next; - p = p->next; - } - LOCKRET(pthread_mutex_unlock(&lock->lock)); -} - -/** - * Check protected memory region. Memory compare. Exit on error. - * @param lock: which lock to check. - * @param func: location we are now (when failure is detected). - * @param file: location we are now (when failure is detected). - * @param line: location we are now (when failure is detected). - */ -static void -prot_check(struct checked_lock* lock, - const char* func, const char* file, int line) -{ - struct protected_area* p = lock->prot; - while(p) { - if(memcmp(p->hold, p->region, p->size) != 0) { - log_hex("memory prev", p->hold, p->size); - log_hex("memory here", p->region, p->size); - lock_error(lock, func, file, line, - "protected area modified"); - } - p = p->next; - } -} - -/** Copy protected memory region */ -static void -prot_store(struct checked_lock* lock) -{ - struct protected_area* p = lock->prot; - while(p) { - memcpy(p->hold, p->region, p->size); - p = p->next; - } -} - -/** get memory held by lock */ -size_t -lock_get_mem(void* pp) -{ - size_t s; - struct checked_lock* lock = *(struct checked_lock**)pp; - struct protected_area* p; - s = sizeof(struct checked_lock); - acquire_locklock(lock, __func__, __FILE__, __LINE__); - for(p = lock->prot; p; p = p->next) { - s += sizeof(struct protected_area); - s += p->size; - } - LOCKRET(pthread_mutex_unlock(&lock->lock)); - return s; -} - -/** write lock trace info to file, while you hold those locks */ -static void -ordercheck_locklock(struct thr_check* thr, struct checked_lock* lock) -{ - int info[4]; - if(!check_locking_order) return; - if(!thr->holding_first) return; /* no older lock, no info */ - /* write: <lock id held> <lock id new> <file> <line> */ - info[0] = thr->holding_first->create_thread; - info[1] = thr->holding_first->create_instance; - info[2] = lock->create_thread; - info[3] = lock->create_instance; - if(fwrite(info, 4*sizeof(int), 1, thr->order_info) != 1 || - fwrite(lock->holder_file, strlen(lock->holder_file)+1, 1, - thr->order_info) != 1 || - fwrite(&lock->holder_line, sizeof(int), 1, - thr->order_info) != 1) - log_err("fwrite: %s", strerror(errno)); -} - -/** write ordercheck lock creation details to file */ -static void -ordercheck_lockcreate(struct thr_check* thr, struct checked_lock* lock) -{ - /* write: <ffff = create> <lock id> <file> <line> */ - int cmd = -1; - if(!check_locking_order) return; - - if( fwrite(&cmd, sizeof(int), 1, thr->order_info) != 1 || - fwrite(&lock->create_thread, sizeof(int), 1, - thr->order_info) != 1 || - fwrite(&lock->create_instance, sizeof(int), 1, - thr->order_info) != 1 || - fwrite(lock->create_file, strlen(lock->create_file)+1, 1, - thr->order_info) != 1 || - fwrite(&lock->create_line, sizeof(int), 1, - thr->order_info) != 1) - log_err("fwrite: %s", strerror(errno)); -} - -/** alloc struct, init lock empty */ -void -checklock_init(enum check_lock_type type, struct checked_lock** lock, - const char* func, const char* file, int line) -{ - struct checked_lock* e = (struct checked_lock*)calloc(1, - sizeof(struct checked_lock)); - struct thr_check *thr = (struct thr_check*)pthread_getspecific( - thr_debug_key); - if(!e) - fatal_exit("%s %s %d: out of memory", func, file, line); - if(!thr) { - /* this is called when log_init() calls lock_init() - * functions, and the test check code has not yet - * been initialised. But luckily, the checklock_start() - * routine can be called multiple times without ill effect. - */ - checklock_start(); - thr = (struct thr_check*)pthread_getspecific(thr_debug_key); - } - if(!thr) - fatal_exit("%s %s %d: lock_init no thread info", func, file, - line); - *lock = e; - e->type = type; - e->create_func = func; - e->create_file = file; - e->create_line = line; - e->create_thread = thr->num; - e->create_instance = thr->locks_created++; - ordercheck_lockcreate(thr, e); - LOCKRET(pthread_mutex_init(&e->lock, NULL)); - switch(e->type) { - case check_lock_mutex: - LOCKRET(pthread_mutex_init(&e->u.mutex, NULL)); - break; - case check_lock_spinlock: - LOCKRET(pthread_spin_init(&e->u.spinlock, PTHREAD_PROCESS_PRIVATE)); - break; - case check_lock_rwlock: - LOCKRET(pthread_rwlock_init(&e->u.rwlock, NULL)); - break; - default: - log_assert(0); - } -} - -/** delete prot items */ -static void -prot_clear(struct checked_lock* lock) -{ - struct protected_area* p=lock->prot, *np; - while(p) { - np = p->next; - free(p->hold); - free(p); - p = np; - } -} - -/** check if type is OK for the lock given */ -static void -checktype(enum check_lock_type type, struct checked_lock* lock, - const char* func, const char* file, int line) -{ - if(!lock) - fatal_exit("use of null/deleted lock at %s %s:%d", - func, file, line); - if(type != lock->type) { - lock_error(lock, func, file, line, "wrong lock type"); - } -} - -/** check if OK, free struct */ -void -checklock_destroy(enum check_lock_type type, struct checked_lock** lock, - const char* func, const char* file, int line) -{ - const size_t contention_interest = 1; /* promille contented locks */ - struct checked_lock* e; - if(!lock) - return; - e = *lock; - if(!e) - return; - checktype(type, e, func, file, line); - - /* check if delete is OK */ - acquire_locklock(e, func, file, line); - if(e->hold_count != 0) - lock_error(e, func, file, line, "delete while locked."); - if(e->wait_count != 0) - lock_error(e, func, file, line, "delete while waited on."); - prot_check(e, func, file, line); - *lock = NULL; /* use after free will fail */ - LOCKRET(pthread_mutex_unlock(&e->lock)); - - /* contention, look at fraction in trouble. */ - if(e->history_count > 1 && - 1000*e->contention_count/e->history_count > contention_interest) { - log_info("lock created %s %s %d has contention %u of %u (%d%%)", - e->create_func, e->create_file, e->create_line, - (unsigned int)e->contention_count, - (unsigned int)e->history_count, - (int)(100*e->contention_count/e->history_count)); - } - - /* delete it */ - LOCKRET(pthread_mutex_destroy(&e->lock)); - prot_clear(e); - /* since nobody holds the lock - see check above, no need to unlink - * from the thread-held locks list. */ - switch(e->type) { - case check_lock_mutex: - LOCKRET(pthread_mutex_destroy(&e->u.mutex)); - break; - case check_lock_spinlock: - LOCKRET(pthread_spin_destroy(&e->u.spinlock)); - break; - case check_lock_rwlock: - LOCKRET(pthread_rwlock_destroy(&e->u.rwlock)); - break; - default: - log_assert(0); - } - memset(e, 0, sizeof(struct checked_lock)); - free(e); -} - -/** finish acquiring lock, shared between _(rd|wr||)lock() routines */ -static void -finish_acquire_lock(struct thr_check* thr, struct checked_lock* lock, - const char* func, const char* file, int line) -{ - thr->waiting = NULL; - lock->wait_count --; - lock->holder = thr; - lock->hold_count ++; - lock->holder_func = func; - lock->holder_file = file; - lock->holder_line = line; - ordercheck_locklock(thr, lock); - - /* insert in thread lock list, as first */ - lock->prev_held_lock[thr->num] = NULL; - lock->next_held_lock[thr->num] = thr->holding_first; - if(thr->holding_first) - /* no need to lock it, since this thread already holds the - * lock (since it is on this list) and we only edit thr->num - * member in array. So it is safe. */ - thr->holding_first->prev_held_lock[thr->num] = lock; - else thr->holding_last = lock; - thr->holding_first = lock; -} - -/** - * Locking routine. - * @param type: as passed by user. - * @param lock: as passed by user. - * @param func: caller location. - * @param file: caller location. - * @param line: caller location. - * @param tryfunc: the pthread_mutex_trylock or similar function. - * @param timedfunc: the pthread_mutex_timedlock or similar function. - * Uses absolute timeout value. - * @param arg: what to pass to tryfunc and timedlock. - * @param exclusive: if lock must be exclusive (only one allowed). - * @param getwr: if attempts to get writelock (or readlock) for rwlocks. - */ -static void -checklock_lockit(enum check_lock_type type, struct checked_lock* lock, - const char* func, const char* file, int line, - int (*tryfunc)(void*), int (*timedfunc)(void*, struct timespec*), - void* arg, int exclusive, int getwr) -{ - int err; - int contend = 0; - struct thr_check *thr = (struct thr_check*)pthread_getspecific( - thr_debug_key); - checktype(type, lock, func, file, line); - if(!thr) lock_error(lock, func, file, line, "no thread info"); - - acquire_locklock(lock, func, file, line); - lock->wait_count ++; - thr->waiting = lock; - if(exclusive && lock->hold_count > 0 && lock->holder == thr) - lock_error(lock, func, file, line, "thread already owns lock"); - if(type==check_lock_rwlock && getwr && lock->writeholder == thr) - lock_error(lock, func, file, line, "thread already has wrlock"); - LOCKRET(pthread_mutex_unlock(&lock->lock)); - - /* first try; if busy increase contention counter */ - if((err=tryfunc(arg))) { - struct timespec to; - if(err != EBUSY) log_err("trylock: %s", strerror(err)); - to.tv_sec = time(NULL) + CHECK_LOCK_TIMEOUT; - to.tv_nsec = 0; - if((err=timedfunc(arg, &to))) { - if(err == ETIMEDOUT) - lock_error(lock, func, file, line, - "timeout possible deadlock"); - log_err("timedlock: %s", strerror(err)); - } - contend ++; - } - /* got the lock */ - - acquire_locklock(lock, func, file, line); - lock->contention_count += contend; - lock->history_count++; - if(exclusive && lock->hold_count > 0) - lock_error(lock, func, file, line, "got nonexclusive lock"); - if(type==check_lock_rwlock && getwr && lock->writeholder) - lock_error(lock, func, file, line, "got nonexclusive wrlock"); - if(type==check_lock_rwlock && getwr) - lock->writeholder = thr; - /* check the memory areas for unauthorized changes, - * between last unlock time and current lock time. - * we check while holding the lock (threadsafe). - */ - if(getwr || exclusive) - prot_check(lock, func, file, line); - finish_acquire_lock(thr, lock, func, file, line); - LOCKRET(pthread_mutex_unlock(&lock->lock)); -} - -/** helper for rdlock: try */ -static int try_rd(void* arg) -{ return pthread_rwlock_tryrdlock((pthread_rwlock_t*)arg); } -/** helper for rdlock: timed */ -static int timed_rd(void* arg, struct timespec* to) -{ return pthread_rwlock_timedrdlock((pthread_rwlock_t*)arg, to); } - -/** check if OK, lock */ -void -checklock_rdlock(enum check_lock_type type, struct checked_lock* lock, - const char* func, const char* file, int line) -{ - if(key_deleted) - return; - - log_assert(type == check_lock_rwlock); - checklock_lockit(type, lock, func, file, line, - try_rd, timed_rd, &lock->u.rwlock, 0, 0); -} - -/** helper for wrlock: try */ -static int try_wr(void* arg) -{ return pthread_rwlock_trywrlock((pthread_rwlock_t*)arg); } -/** helper for wrlock: timed */ -static int timed_wr(void* arg, struct timespec* to) -{ return pthread_rwlock_timedwrlock((pthread_rwlock_t*)arg, to); } - -/** check if OK, lock */ -void -checklock_wrlock(enum check_lock_type type, struct checked_lock* lock, - const char* func, const char* file, int line) -{ - if(key_deleted) - return; - log_assert(type == check_lock_rwlock); - checklock_lockit(type, lock, func, file, line, - try_wr, timed_wr, &lock->u.rwlock, 0, 1); -} - -/** helper for lock mutex: try */ -static int try_mutex(void* arg) -{ return pthread_mutex_trylock((pthread_mutex_t*)arg); } -/** helper for lock mutex: timed */ -static int timed_mutex(void* arg, struct timespec* to) -{ return pthread_mutex_timedlock((pthread_mutex_t*)arg, to); } - -/** helper for lock spinlock: try */ -static int try_spinlock(void* arg) -{ return pthread_spin_trylock((pthread_spinlock_t*)arg); } -/** helper for lock spinlock: timed */ -static int timed_spinlock(void* arg, struct timespec* to) -{ - int err; - /* spin for 5 seconds. (ouch for the CPU, but it beats forever) */ - while( (err=try_spinlock(arg)) == EBUSY) { -#ifndef S_SPLINT_S - if(time(NULL) >= to->tv_sec) - return ETIMEDOUT; - usleep(1000); /* in 1/1000000s of a second */ -#endif - } - return err; -} - -/** check if OK, lock */ -void -checklock_lock(enum check_lock_type type, struct checked_lock* lock, - const char* func, const char* file, int line) -{ - if(key_deleted) - return; - log_assert(type != check_lock_rwlock); - switch(type) { - case check_lock_mutex: - checklock_lockit(type, lock, func, file, line, - try_mutex, timed_mutex, &lock->u.mutex, 1, 0); - break; - case check_lock_spinlock: - /* void* cast needed because 'volatile' on some OS */ - checklock_lockit(type, lock, func, file, line, - try_spinlock, timed_spinlock, - (void*)&lock->u.spinlock, 1, 0); - break; - default: - log_assert(0); - } -} - -/** check if OK, unlock */ -void -checklock_unlock(enum check_lock_type type, struct checked_lock* lock, - const char* func, const char* file, int line) -{ - struct thr_check *thr; - if(key_deleted) - return; - thr = (struct thr_check*)pthread_getspecific(thr_debug_key); - checktype(type, lock, func, file, line); - if(!thr) lock_error(lock, func, file, line, "no thread info"); - - acquire_locklock(lock, func, file, line); - /* was this thread even holding this lock? */ - if(thr->holding_first != lock && - lock->prev_held_lock[thr->num] == NULL) { - lock_error(lock, func, file, line, "unlock nonlocked lock"); - } - if(lock->hold_count <= 0) - lock_error(lock, func, file, line, "too many unlocks"); - - /* store this point as last touched by */ - lock->holder = thr; - lock->hold_count --; - lock->holder_func = func; - lock->holder_file = file; - lock->holder_line = line; - - /* delete from thread holder list */ - /* no need to lock other lockstructs, because they are all on the - * held-locks list, and this thread holds their locks. - * we only touch the thr->num members, so it is safe. */ - if(thr->holding_first == lock) - thr->holding_first = lock->next_held_lock[thr->num]; - if(thr->holding_last == lock) - thr->holding_last = lock->prev_held_lock[thr->num]; - if(lock->next_held_lock[thr->num]) - lock->next_held_lock[thr->num]->prev_held_lock[thr->num] = - lock->prev_held_lock[thr->num]; - if(lock->prev_held_lock[thr->num]) - lock->prev_held_lock[thr->num]->next_held_lock[thr->num] = - lock->next_held_lock[thr->num]; - lock->next_held_lock[thr->num] = NULL; - lock->prev_held_lock[thr->num] = NULL; - - if(type==check_lock_rwlock && lock->writeholder == thr) { - lock->writeholder = NULL; - prot_store(lock); - } else if(type != check_lock_rwlock) { - /* store memory areas that are protected, for later checks */ - prot_store(lock); - } - LOCKRET(pthread_mutex_unlock(&lock->lock)); - - /* unlock it */ - switch(type) { - case check_lock_mutex: - LOCKRET(pthread_mutex_unlock(&lock->u.mutex)); - break; - case check_lock_spinlock: - LOCKRET(pthread_spin_unlock(&lock->u.spinlock)); - break; - case check_lock_rwlock: - LOCKRET(pthread_rwlock_unlock(&lock->u.rwlock)); - break; - default: - log_assert(0); - } -} - -/** open order info debug file, thr->num must be valid */ -static void -open_lockorder(struct thr_check* thr) -{ - char buf[24]; - time_t t; - snprintf(buf, sizeof(buf), "ublocktrace.%d", thr->num); - thr->order_info = fopen(buf, "w"); - if(!thr->order_info) - fatal_exit("could not open %s: %s", buf, strerror(errno)); - thr->locks_created = 0; - t = time(NULL); - /* write: <time_stamp> <runpid> <thread_num> */ - if(fwrite(&t, sizeof(t), 1, thr->order_info) != 1 || - fwrite(&thr->num, sizeof(thr->num), 1, thr->order_info) != 1 || - fwrite(&check_lock_pid, sizeof(check_lock_pid), 1, - thr->order_info) != 1) - log_err("fwrite: %s", strerror(errno)); -} - -/** checklock thread main, Inits thread structure */ -static void* checklock_main(void* arg) -{ - struct thr_check* thr = (struct thr_check*)arg; - void* ret; - thr->id = pthread_self(); - /* Hack to get same numbers as in log file */ - thr->num = *(int*)(thr->arg); - log_assert(thr->num < THRDEBUG_MAX_THREADS); - /* as an aside, due to this, won't work for libunbound bg thread */ - if(thread_infos[thr->num] != NULL) - log_warn("thread warning, thr->num %d not NULL", thr->num); - thread_infos[thr->num] = thr; - LOCKRET(pthread_setspecific(thr_debug_key, thr)); - if(check_locking_order) - open_lockorder(thr); - ret = thr->func(thr->arg); - thread_infos[thr->num] = NULL; - if(check_locking_order) - fclose(thr->order_info); - free(thr); - return ret; -} - -/** init the main thread */ -void checklock_start(void) -{ - if(key_deleted) - return; - if(!key_created) { - struct thr_check* thisthr = (struct thr_check*)calloc(1, - sizeof(struct thr_check)); - if(!thisthr) - fatal_exit("thrcreate: out of memory"); - key_created = 1; - check_lock_pid = getpid(); - LOCKRET(pthread_key_create(&thr_debug_key, NULL)); - LOCKRET(pthread_setspecific(thr_debug_key, thisthr)); - thread_infos[0] = thisthr; - if(check_locking_order) - open_lockorder(thisthr); - } -} - -/** stop checklocks */ -void checklock_stop(void) -{ - if(key_created) { - int i; - key_deleted = 1; - if(check_locking_order) - fclose(thread_infos[0]->order_info); - free(thread_infos[0]); - thread_infos[0] = NULL; - for(i = 0; i < THRDEBUG_MAX_THREADS; i++) - log_assert(thread_infos[i] == NULL); - /* should have been cleaned up. */ - LOCKRET(pthread_key_delete(thr_debug_key)); - key_created = 0; - } -} - -/** allocate debug info and create thread */ -void -checklock_thrcreate(pthread_t* id, void* (*func)(void*), void* arg) -{ - struct thr_check* thr = (struct thr_check*)calloc(1, - sizeof(struct thr_check)); - if(!thr) - fatal_exit("thrcreate: out of memory"); - if(!key_created) { - checklock_start(); - } - thr->func = func; - thr->arg = arg; - LOCKRET(pthread_create(id, NULL, checklock_main, thr)); -} - -/** count number of thread infos */ -static int -count_thread_infos(void) -{ - int cnt = 0; - int i; - for(i=0; i<THRDEBUG_MAX_THREADS; i++) - if(thread_infos[i]) - cnt++; - return cnt; -} - -/** print lots of info on a lock */ -static void -lock_debug_info(struct checked_lock* lock) -{ - if(!lock) return; - log_info("+++ Lock %llx, %d %d create %s %s %d", - (unsigned long long)(size_t)lock, - lock->create_thread, lock->create_instance, - lock->create_func, lock->create_file, lock->create_line); - log_info("lock type: %s", - (lock->type==check_lock_mutex)?"mutex": ( - (lock->type==check_lock_spinlock)?"spinlock": ( - (lock->type==check_lock_rwlock)?"rwlock": "badtype"))); - log_info("lock contention %u, history:%u, hold:%d, wait:%d", - (unsigned)lock->contention_count, (unsigned)lock->history_count, - lock->hold_count, lock->wait_count); - log_info("last touch %s %s %d", lock->holder_func, lock->holder_file, - lock->holder_line); - log_info("holder thread %d, writeholder thread %d", - lock->holder?lock->holder->num:-1, - lock->writeholder?lock->writeholder->num:-1); -} - -/** print debug locks held by a thread */ -static void -held_debug_info(struct thr_check* thr, struct checked_lock* lock) -{ - if(!lock) return; - lock_debug_info(lock); - held_debug_info(thr, lock->next_held_lock[thr->num]); -} - -/** print debug info for a thread */ -static void -thread_debug_info(struct thr_check* thr) -{ - struct checked_lock* w = NULL; - struct checked_lock* f = NULL; - struct checked_lock* l = NULL; - if(!thr) return; - log_info("pthread id is %x", (int)thr->id); - log_info("thread func is %llx", (unsigned long long)(size_t)thr->func); - log_info("thread arg is %llx (%d)", - (unsigned long long)(size_t)thr->arg, - (thr->arg?*(int*)thr->arg:0)); - log_info("thread num is %d", thr->num); - log_info("locks created %d", thr->locks_created); - log_info("open file for lockinfo: %s", - thr->order_info?"yes, flushing":"no"); - fflush(thr->order_info); - w = thr->waiting; - f = thr->holding_first; - l = thr->holding_last; - log_info("thread waiting for a lock: %s %llx", w?"yes":"no", - (unsigned long long)(size_t)w); - lock_debug_info(w); - log_info("thread holding first: %s, last: %s", f?"yes":"no", - l?"yes":"no"); - held_debug_info(thr, f); -} - -static void -total_debug_info(void) -{ - int i; - log_info("checklocks: supervising %d threads.", - count_thread_infos()); - if(!key_created) { - log_info("No thread debug key created yet"); - } - for(i=0; i<THRDEBUG_MAX_THREADS; i++) { - if(thread_infos[i]) { - log_info("*** Thread %d information: ***", i); - thread_debug_info(thread_infos[i]); - } - } -} - -/** signal handler for join timeout, Exits */ -static RETSIGTYPE joinalarm(int ATTR_UNUSED(sig)) -{ - log_err("join thread timeout. hangup or deadlock. Info follows."); - total_debug_info(); - fatal_exit("join thread timeout. hangup or deadlock."); -} - -/** wait for thread with a timeout */ -void -checklock_thrjoin(pthread_t thread) -{ - /* wait with a timeout */ - if(signal(SIGALRM, joinalarm) == SIG_ERR) - fatal_exit("signal(): %s", strerror(errno)); - (void)alarm(CHECK_JOIN_TIMEOUT); - LOCKRET(pthread_join(thread, NULL)); - (void)alarm(0); -} - -#endif /* USE_THREAD_DEBUG */ diff --git a/external/unbound/testcode/checklocks.h b/external/unbound/testcode/checklocks.h deleted file mode 100644 index 182a93858..000000000 --- a/external/unbound/testcode/checklocks.h +++ /dev/null @@ -1,343 +0,0 @@ -/** - * testcode/checklocks.h - wrapper on locks that checks access. - * - * 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 TESTCODE_CHECK_LOCKS_H -#define TESTCODE_CHECK_LOCKS_H - -/** - * \file - * Locks that are checked. - * - * Holds information per lock and per thread. - * That information is protected by a mutex (unchecked). - * - * Checks: - * o which func, file, line created the lock. - * o contention count, measures amount of contention on the lock. - * o the memory region(s) that the lock protects are - * memcmp'ed to ascertain no race conditions. - * o checks that locks are unlocked properly (before deletion). - * keeps which func, file, line that locked it. - * o checks deadlocks with timeout so it can print errors for them. - * - * Limitations: - * o Detects unprotected memory access when the lock is locked or freed, - * which detects races only if they happen, and only if in protected - * memory areas. - * o Detects deadlocks by timeout, so approximately, as they happen. - * o Does not check order of locking. - * o Uses a lot of memory. - * o The checks use locks themselves, changing scheduling, - * thus changing what races you see. - */ - -#ifdef USE_THREAD_DEBUG -#ifndef HAVE_PTHREAD -/* we need the *timed*lock() routines to use for deadlock detection. */ -#error "Need pthreads for checked locks" -#endif -/******************* THREAD DEBUG ************************/ -#include <pthread.h> - -/** How many threads to allocate for */ -#define THRDEBUG_MAX_THREADS 32 /* threads */ -/** do we check locking order */ -extern int check_locking_order; - -/** - * Protection memory area. - * It is copied to a holding buffer to compare against later. - * Note that it may encompass the lock structure. - */ -struct protected_area { - /** where the memory region starts */ - void* region; - /** size of the region */ - size_t size; - /** backbuffer that holds a copy, of same size. */ - void* hold; - /** next protected area in list */ - struct protected_area* next; -}; - -/** - * Per thread information for locking debug wrappers. - */ -struct thr_check { - /** thread id */ - pthread_t id; - /** real thread func */ - void* (*func)(void*); - /** func user arg */ - void* arg; - /** number of thread in list structure */ - int num; - /** instance number - how many locks have been created by thread */ - int locks_created; - /** file to write locking order information to */ - FILE* order_info; - /** - * List of locks that this thread is holding, double - * linked list. The first element is the most recent lock acquired. - * So it represents the stack of locks acquired. (of all types). - */ - struct checked_lock *holding_first, *holding_last; - /** if the thread is currently waiting for a lock, which one */ - struct checked_lock* waiting; -}; - -/** - * One structure for all types of locks. - */ -struct checked_lock { - /** mutex for exclusive access to this structure */ - pthread_mutex_t lock; - /** list of memory regions protected by this checked lock */ - struct protected_area* prot; - /** where was this lock created */ - const char* create_func, *create_file; - /** where was this lock created */ - int create_line; - /** unique instance identifier */ - int create_thread, create_instance; - /** contention count */ - size_t contention_count; - /** number of times locked, ever */ - size_t history_count; - /** hold count (how many threads are holding this lock) */ - int hold_count; - /** how many threads are waiting for this lock */ - int wait_count; - /** who touched it last */ - const char* holder_func, *holder_file; - /** who touched it last */ - int holder_line; - /** who owns the lock now */ - struct thr_check* holder; - /** for rwlocks, the writelock holder */ - struct thr_check* writeholder; - - /** next lock a thread is holding (less recent) */ - struct checked_lock* next_held_lock[THRDEBUG_MAX_THREADS]; - /** prev lock a thread is holding (more recent) */ - struct checked_lock* prev_held_lock[THRDEBUG_MAX_THREADS]; - - /** type of lock */ - enum check_lock_type { - /** basic mutex */ - check_lock_mutex, - /** fast spinlock */ - check_lock_spinlock, - /** rwlock */ - check_lock_rwlock - } type; - /** the lock itself, see type to disambiguate the union */ - union { - /** mutex */ - pthread_mutex_t mutex; - /** spinlock */ - pthread_spinlock_t spinlock; - /** rwlock */ - pthread_rwlock_t rwlock; - } u; -}; - -/** - * Additional call for the user to specify what areas are protected - * @param lock: the lock that protects the area. It can be inside the area. - * The lock must be inited. Call with user lock. (any type). - * It demangles the lock itself (struct checked_lock**). - * @param area: ptr to mem. - * @param size: length of area. - * You can call it multiple times with the same lock to give several areas. - * Call it when you are done initialising the area, since it will be copied - * at this time and protected right away against unauthorised changes until - * the next lock() call is done. - */ -void lock_protect(void* lock, void* area, size_t size); - -/** - * Remove protected area from lock. - * No need to call this when deleting the lock. - * @param lock: the lock, any type, (struct checked_lock**). - * @param area: pointer to memory. - */ -void lock_unprotect(void* lock, void* area); - -/** - * Get memory associated with a checked lock - * @param lock: the checked lock, any type. (struct checked_lock**). - * @return: in bytes, including protected areas. - */ -size_t lock_get_mem(void* lock); - -/** - * Initialise checklock. Sets up internal debug structures. - */ -void checklock_start(void); - -/** - * Cleanup internal debug state. - */ -void checklock_stop(void); - -/** - * Init locks. - * @param type: what type of lock this is. - * @param lock: ptr to user alloced ptr structure. This is inited. - * So an alloc is done and the ptr is stored as result. - * @param func: caller function name. - * @param file: caller file name. - * @param line: caller line number. - */ -void checklock_init(enum check_lock_type type, struct checked_lock** lock, - const char* func, const char* file, int line); - -/** - * Destroy locks. Free the structure. - * @param type: what type of lock this is. - * @param lock: ptr to user alloced structure. This is destroyed. - * @param func: caller function name. - * @param file: caller file name. - * @param line: caller line number. - */ -void checklock_destroy(enum check_lock_type type, struct checked_lock** lock, - const char* func, const char* file, int line); - -/** - * Acquire readlock. - * @param type: what type of lock this is. Had better be a rwlock. - * @param lock: ptr to lock. - * @param func: caller function name. - * @param file: caller file name. - * @param line: caller line number. - */ -void checklock_rdlock(enum check_lock_type type, struct checked_lock* lock, - const char* func, const char* file, int line); - -/** - * Acquire writelock. - * @param type: what type of lock this is. Had better be a rwlock. - * @param lock: ptr to lock. - * @param func: caller function name. - * @param file: caller file name. - * @param line: caller line number. - */ -void checklock_wrlock(enum check_lock_type type, struct checked_lock* lock, - const char* func, const char* file, int line); - -/** - * Locks. - * @param type: what type of lock this is. Had better be mutex or spinlock. - * @param lock: the lock. - * @param func: caller function name. - * @param file: caller file name. - * @param line: caller line number. - */ -void checklock_lock(enum check_lock_type type, struct checked_lock* lock, - const char* func, const char* file, int line); - -/** - * Unlocks. - * @param type: what type of lock this is. - * @param lock: the lock. - * @param func: caller function name. - * @param file: caller file name. - * @param line: caller line number. - */ -void checklock_unlock(enum check_lock_type type, struct checked_lock* lock, - const char* func, const char* file, int line); - -/** - * Create thread. - * @param thr: Thread id, where to store result. - * @param func: thread start function. - * @param arg: user argument. - */ -void checklock_thrcreate(pthread_t* thr, void* (*func)(void*), void* arg); - -/** - * Wait for thread to exit. Returns thread return value. - * @param thread: thread to wait for. - */ -void checklock_thrjoin(pthread_t thread); - -/** structures to enable compiler type checking on the locks. - * Also the pointer makes it so that the lock can be part of the protected - * region without any possible problem (since the ptr will stay the same.) - * i.e. there can be contention and readlocks stored in checked_lock, while - * the protected area stays the same, even though it contains (ptr to) lock. - */ -struct checked_lock_rw { struct checked_lock* c_rw; }; -/** structures to enable compiler type checking on the locks. */ -struct checked_lock_mutex { struct checked_lock* c_m; }; -/** structures to enable compiler type checking on the locks. */ -struct checked_lock_spl { struct checked_lock* c_spl; }; - -/** debugging rwlock */ -typedef struct checked_lock_rw lock_rw_type; -#define lock_rw_init(lock) checklock_init(check_lock_rwlock, &((lock)->c_rw), __func__, __FILE__, __LINE__) -#define lock_rw_destroy(lock) checklock_destroy(check_lock_rwlock, &((lock)->c_rw), __func__, __FILE__, __LINE__) -#define lock_rw_rdlock(lock) checklock_rdlock(check_lock_rwlock, (lock)->c_rw, __func__, __FILE__, __LINE__) -#define lock_rw_wrlock(lock) checklock_wrlock(check_lock_rwlock, (lock)->c_rw, __func__, __FILE__, __LINE__) -#define lock_rw_unlock(lock) checklock_unlock(check_lock_rwlock, (lock)->c_rw, __func__, __FILE__, __LINE__) - -/** debugging mutex */ -typedef struct checked_lock_mutex lock_basic_type; -#define lock_basic_init(lock) checklock_init(check_lock_mutex, &((lock)->c_m), __func__, __FILE__, __LINE__) -#define lock_basic_destroy(lock) checklock_destroy(check_lock_mutex, &((lock)->c_m), __func__, __FILE__, __LINE__) -#define lock_basic_lock(lock) checklock_lock(check_lock_mutex, (lock)->c_m, __func__, __FILE__, __LINE__) -#define lock_basic_unlock(lock) checklock_unlock(check_lock_mutex, (lock)->c_m, __func__, __FILE__, __LINE__) - -/** debugging spinlock */ -typedef struct checked_lock_spl lock_quick_type; -#define lock_quick_init(lock) checklock_init(check_lock_spinlock, &((lock)->c_spl), __func__, __FILE__, __LINE__) -#define lock_quick_destroy(lock) checklock_destroy(check_lock_spinlock, &((lock)->c_spl), __func__, __FILE__, __LINE__) -#define lock_quick_lock(lock) checklock_lock(check_lock_spinlock, (lock)->c_spl, __func__, __FILE__, __LINE__) -#define lock_quick_unlock(lock) checklock_unlock(check_lock_spinlock, (lock)->c_spl, __func__, __FILE__, __LINE__) - -/** we use the pthread id, our thr_check structure is kept behind the scenes */ -typedef pthread_t ub_thread_type; -#define ub_thread_create(thr, func, arg) checklock_thrcreate(thr, func, arg) -#define ub_thread_self() pthread_self() -#define ub_thread_join(thread) checklock_thrjoin(thread) - -typedef pthread_key_t ub_thread_key_type; -#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) - -#endif /* USE_THREAD_DEBUG */ -#endif /* TESTCODE_CHECK_LOCKS_H */ diff --git a/external/unbound/testcode/delayer.c b/external/unbound/testcode/delayer.c deleted file mode 100644 index 5489b591e..000000000 --- a/external/unbound/testcode/delayer.c +++ /dev/null @@ -1,1185 +0,0 @@ -/* - * testcode/delayer.c - debug program that delays queries to a server. - * - * 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 program delays queries made. It performs as a proxy to another - * server and delays queries to it. - */ - -#include "config.h" -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#include <sys/time.h> -#include "util/net_help.h" -#include "util/config_file.h" -#include "sldns/sbuffer.h" -#include <signal.h> - -/** number of reads per select for delayer */ -#define TRIES_PER_SELECT 100 - -/** - * The ring buffer - */ -struct ringbuf { - /** base of buffer */ - uint8_t* buf; - /** size of buffer */ - size_t size; - /** low mark, items start here */ - size_t low; - /** high mark, items end here */ - size_t high; -}; - -/** - * List of proxy fds that return replies from the server to our clients. - */ -struct proxy { - /** the fd to listen for replies from server */ - int s; - /** last time this was used */ - struct timeval lastuse; - /** remote address */ - struct sockaddr_storage addr; - /** length of addr */ - socklen_t addr_len; - /** number of queries waiting (in total) */ - size_t numwait; - /** number of queries sent to server (in total) */ - size_t numsent; - /** numberof answers returned to client (in total) */ - size_t numreturn; - /** how many times repurposed */ - size_t numreuse; - /** next in proxylist */ - struct proxy* next; -}; - -/** - * An item that has to be TCP relayed - */ -struct tcp_send_list { - /** the data item */ - uint8_t* item; - /** size of item */ - size_t len; - /** time when the item can be transmitted on */ - struct timeval wait; - /** how much of the item has already been transmitted */ - size_t done; - /** next in list */ - struct tcp_send_list* next; -}; - -/** - * List of TCP proxy fd pairs to TCP connect client to server - */ -struct tcp_proxy { - /** the fd to listen for client query */ - int client_s; - /** the fd to listen for server answer */ - int server_s; - - /** remote client address */ - struct sockaddr_storage addr; - /** length of address */ - socklen_t addr_len; - /** timeout on this entry */ - struct timeval timeout; - - /** list of query items to send to server */ - struct tcp_send_list* querylist; - /** last in query list */ - struct tcp_send_list* querylast; - /** list of answer items to send to client */ - struct tcp_send_list* answerlist; - /** last in answerlist */ - struct tcp_send_list* answerlast; - - /** next in list */ - struct tcp_proxy* next; -}; - -/** usage information for delayer */ -static void usage(char* argv[]) -{ - printf("usage: %s [options]\n", argv[0]); - printf(" -f addr : use addr, forward to that server, @port.\n"); - printf(" -b addr : bind to this address to listen.\n"); - printf(" -p port : bind to this port (use 0 for random).\n"); - printf(" -m mem : use this much memory for waiting queries.\n"); - printf(" -d delay: UDP queries are delayed n milliseconds.\n"); - printf(" TCP is delayed twice (on send, on recv).\n"); - printf(" -h : this help message\n"); - exit(1); -} - -/** timeval compare, t1 < t2 */ -static int -dl_tv_smaller(struct timeval* t1, const struct timeval* t2) -{ -#ifndef S_SPLINT_S - if(t1->tv_sec < t2->tv_sec) - return 1; - if(t1->tv_sec == t2->tv_sec && - t1->tv_usec < t2->tv_usec) - return 1; -#endif - return 0; -} - -/** timeval add, t1 += t2 */ -static void -dl_tv_add(struct timeval* t1, const struct timeval* t2) -{ -#ifndef S_SPLINT_S - t1->tv_sec += t2->tv_sec; - t1->tv_usec += t2->tv_usec; - while(t1->tv_usec > 1000000) { - t1->tv_usec -= 1000000; - t1->tv_sec++; - } -#endif -} - -/** timeval subtract, t1 -= t2 */ -static void -dl_tv_subtract(struct timeval* t1, const struct timeval* t2) -{ -#ifndef S_SPLINT_S - t1->tv_sec -= t2->tv_sec; - if(t1->tv_usec >= t2->tv_usec) { - t1->tv_usec -= t2->tv_usec; - } else { - t1->tv_sec--; - t1->tv_usec = 1000000-(t2->tv_usec-t1->tv_usec); - } -#endif -} - - -/** create new ring buffer */ -static struct ringbuf* -ring_create(size_t sz) -{ - struct ringbuf* r = (struct ringbuf*)calloc(1, sizeof(*r)); - if(!r) fatal_exit("out of memory"); - r->buf = (uint8_t*)malloc(sz); - if(!r->buf) fatal_exit("out of memory"); - r->size = sz; - r->low = 0; - r->high = 0; - return r; -} - -/** delete ring buffer */ -static void -ring_delete(struct ringbuf* r) -{ - if(!r) return; - free(r->buf); - free(r); -} - -/** add entry to ringbuffer */ -static void -ring_add(struct ringbuf* r, sldns_buffer* pkt, struct timeval* now, - struct timeval* delay, struct proxy* p) -{ - /* time -- proxy* -- 16bitlen -- message */ - uint16_t len = (uint16_t)sldns_buffer_limit(pkt); - struct timeval when; - size_t needed; - uint8_t* where = NULL; - log_assert(sldns_buffer_limit(pkt) <= 65535); - needed = sizeof(when) + sizeof(p) + sizeof(len) + len; - /* put item into ringbuffer */ - if(r->low < r->high) { - /* used part is in the middle */ - if(r->size - r->high >= needed) { - where = r->buf + r->high; - r->high += needed; - } else if(r->low > needed) { - /* wrap around ringbuffer */ - /* make sure r->low == r->high means empty */ - /* so r->low == r->high cannot be used to signify - * a completely full ringbuf */ - if(r->size - r->high > sizeof(when)+sizeof(p)) { - /* zero entry at end of buffer */ - memset(r->buf+r->high, 0, - sizeof(when)+sizeof(p)); - } - where = r->buf; - r->high = needed; - } else { - /* drop message */ - log_warn("warning: mem full, dropped message"); - return; - } - } else { - /* empty */ - if(r->high == r->low) { - where = r->buf; - r->low = 0; - r->high = needed; - /* unused part is in the middle */ - /* so ringbuffer has wrapped around */ - } else if(r->low - r->high > needed) { - where = r->buf + r->high; - r->high += needed; - } else { - log_warn("warning: mem full, dropped message"); - return; - } - } - when = *now; - dl_tv_add(&when, delay); - /* copy it at where part */ - log_assert(where != NULL); - memmove(where, &when, sizeof(when)); - memmove(where+sizeof(when), &p, sizeof(p)); - memmove(where+sizeof(when)+sizeof(p), &len, sizeof(len)); - memmove(where+sizeof(when)+sizeof(p)+sizeof(len), - sldns_buffer_begin(pkt), len); -} - -/** see if the ringbuffer is empty */ -static int -ring_empty(struct ringbuf* r) -{ - return (r->low == r->high); -} - -/** peek at timevalue for next item in ring */ -static struct timeval* -ring_peek_time(struct ringbuf* r) -{ - if(ring_empty(r)) - return NULL; - return (struct timeval*)&r->buf[r->low]; -} - -/** get entry from ringbuffer */ -static int -ring_pop(struct ringbuf* r, sldns_buffer* pkt, struct timeval* tv, - struct proxy** p) -{ - /* time -- proxy* -- 16bitlen -- message */ - uint16_t len; - uint8_t* where = NULL; - size_t done; - if(r->low == r->high) - return 0; - where = r->buf + r->low; - memmove(tv, where, sizeof(*tv)); - memmove(p, where+sizeof(*tv), sizeof(*p)); - memmove(&len, where+sizeof(*tv)+sizeof(*p), sizeof(len)); - memmove(sldns_buffer_begin(pkt), - where+sizeof(*tv)+sizeof(*p)+sizeof(len), len); - sldns_buffer_set_limit(pkt, (size_t)len); - done = sizeof(*tv)+sizeof(*p)+sizeof(len)+len; - /* move lowmark */ - if(r->low < r->high) { - /* used part in middle */ - log_assert(r->high - r->low >= done); - r->low += done; - } else { - /* unused part in middle */ - log_assert(r->size - r->low >= done); - r->low += done; - if(r->size - r->low > sizeof(*tv)+sizeof(*p)) { - /* see if it is zeroed; means end of buffer */ - struct proxy* pz; - memmove(&pz, r->buf+r->low+sizeof(*tv), sizeof(pz)); - if(pz == NULL) - r->low = 0; - } else r->low = 0; - } - if(r->low == r->high) { - r->low = 0; /* reset if empty */ - r->high = 0; - } - return 1; -} - -/** signal handler global info */ -static volatile int do_quit = 0; - -/** signal handler for user quit */ -static RETSIGTYPE delayer_sigh(int sig) -{ - printf("exit on signal %d\n", sig); - do_quit = 1; -} - -/** send out waiting packets */ -static void -service_send(struct ringbuf* ring, struct timeval* now, sldns_buffer* pkt, - struct sockaddr_storage* srv_addr, socklen_t srv_len) -{ - struct proxy* p; - struct timeval tv; - ssize_t sent; - while(!ring_empty(ring) && - dl_tv_smaller(ring_peek_time(ring), now)) { - /* this items needs to be sent out */ - if(!ring_pop(ring, pkt, &tv, &p)) - fatal_exit("ringbuf error: pop failed"); - verbose(1, "send out query %d.%6.6d", - (unsigned)tv.tv_sec, (unsigned)tv.tv_usec); - log_addr(1, "from client", &p->addr, p->addr_len); - /* send it */ - sent = sendto(p->s, (void*)sldns_buffer_begin(pkt), - sldns_buffer_limit(pkt), 0, - (struct sockaddr*)srv_addr, srv_len); - if(sent == -1) { -#ifndef USE_WINSOCK - log_err("sendto: %s", strerror(errno)); -#else - log_err("sendto: %s", wsa_strerror(WSAGetLastError())); -#endif - } else if(sent != (ssize_t)sldns_buffer_limit(pkt)) { - log_err("sendto: partial send"); - } - p->lastuse = *now; - p->numsent++; - } -} - -/** do proxy for one readable client */ -static void -do_proxy(struct proxy* p, int retsock, sldns_buffer* pkt) -{ - int i; - ssize_t r; - for(i=0; i<TRIES_PER_SELECT; i++) { - r = recv(p->s, (void*)sldns_buffer_begin(pkt), - sldns_buffer_capacity(pkt), 0); - if(r == -1) { -#ifndef USE_WINSOCK - if(errno == EAGAIN || errno == EINTR) - return; - log_err("recv: %s", strerror(errno)); -#else - if(WSAGetLastError() == WSAEINPROGRESS || - WSAGetLastError() == WSAEWOULDBLOCK) - return; - log_err("recv: %s", wsa_strerror(WSAGetLastError())); -#endif - return; - } - sldns_buffer_set_limit(pkt, (size_t)r); - log_addr(1, "return reply to client", &p->addr, p->addr_len); - /* send reply back to the real client */ - p->numreturn++; - r = sendto(retsock, (void*)sldns_buffer_begin(pkt), (size_t)r, - 0, (struct sockaddr*)&p->addr, p->addr_len); - if(r == -1) { -#ifndef USE_WINSOCK - log_err("sendto: %s", strerror(errno)); -#else - log_err("sendto: %s", wsa_strerror(WSAGetLastError())); -#endif - } - } -} - -/** proxy return replies to clients */ -static void -service_proxy(fd_set* rset, int retsock, struct proxy* proxies, - sldns_buffer* pkt, struct timeval* now) -{ - struct proxy* p; - for(p = proxies; p; p = p->next) { - if(FD_ISSET(p->s, rset)) { - p->lastuse = *now; - do_proxy(p, retsock, pkt); - } - } -} - -/** find or else create proxy for this remote client */ -static struct proxy* -find_create_proxy(struct sockaddr_storage* from, socklen_t from_len, - fd_set* rorig, int* max, struct proxy** proxies, int serv_ip6, - struct timeval* now, struct timeval* reuse_timeout) -{ - struct proxy* p; - struct timeval t; - for(p = *proxies; p; p = p->next) { - if(sockaddr_cmp(from, from_len, &p->addr, p->addr_len)==0) - return p; - } - /* possibly: reuse lapsed entries */ - for(p = *proxies; p; p = p->next) { - if(p->numwait > p->numsent || p->numsent > p->numreturn) - continue; - t = *now; - dl_tv_subtract(&t, &p->lastuse); - if(dl_tv_smaller(&t, reuse_timeout)) - continue; - /* yes! */ - verbose(1, "reuse existing entry"); - memmove(&p->addr, from, from_len); - p->addr_len = from_len; - p->numreuse++; - return p; - } - /* create new */ - p = (struct proxy*)calloc(1, sizeof(*p)); - if(!p) fatal_exit("out of memory"); - p->s = socket(serv_ip6?AF_INET6:AF_INET, SOCK_DGRAM, 0); - if(p->s == -1) { -#ifndef USE_WINSOCK - fatal_exit("socket: %s", strerror(errno)); -#else - fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); -#endif - } - fd_set_nonblock(p->s); - memmove(&p->addr, from, from_len); - p->addr_len = from_len; - p->next = *proxies; - *proxies = p; - FD_SET(FD_SET_T p->s, rorig); - if(p->s+1 > *max) - *max = p->s+1; - return p; -} - -/** recv new waiting packets */ -static void -service_recv(int s, struct ringbuf* ring, sldns_buffer* pkt, - fd_set* rorig, int* max, struct proxy** proxies, - struct sockaddr_storage* srv_addr, socklen_t srv_len, - struct timeval* now, struct timeval* delay, struct timeval* reuse) -{ - int i; - struct sockaddr_storage from; - socklen_t from_len; - ssize_t len; - struct proxy* p; - for(i=0; i<TRIES_PER_SELECT; i++) { - from_len = (socklen_t)sizeof(from); - len = recvfrom(s, (void*)sldns_buffer_begin(pkt), - sldns_buffer_capacity(pkt), 0, - (struct sockaddr*)&from, &from_len); - if(len < 0) { -#ifndef USE_WINSOCK - if(errno == EAGAIN || errno == EINTR) - return; - fatal_exit("recvfrom: %s", strerror(errno)); -#else - if(WSAGetLastError() == WSAEWOULDBLOCK || - WSAGetLastError() == WSAEINPROGRESS) - return; - fatal_exit("recvfrom: %s", - wsa_strerror(WSAGetLastError())); -#endif - } - sldns_buffer_set_limit(pkt, (size_t)len); - /* find its proxy element */ - p = find_create_proxy(&from, from_len, rorig, max, proxies, - addr_is_ip6(srv_addr, srv_len), now, reuse); - if(!p) fatal_exit("error: cannot find or create proxy"); - p->lastuse = *now; - ring_add(ring, pkt, now, delay, p); - p->numwait++; - log_addr(1, "recv from client", &p->addr, p->addr_len); - } -} - -/** delete tcp proxy */ -static void -tcp_proxy_delete(struct tcp_proxy* p) -{ - struct tcp_send_list* s, *sn; - if(!p) - return; - log_addr(1, "delete tcp proxy", &p->addr, p->addr_len); - s = p->querylist; - while(s) { - sn = s->next; - free(s->item); - free(s); - s = sn; - } - s = p->answerlist; - while(s) { - sn = s->next; - free(s->item); - free(s); - s = sn; - } -#ifndef USE_WINSOCK - close(p->client_s); - if(p->server_s != -1) - close(p->server_s); -#else - closesocket(p->client_s); - if(p->server_s != -1) - closesocket(p->server_s); -#endif - free(p); -} - -/** accept new TCP connections, and set them up */ -static void -service_tcp_listen(int s, fd_set* rorig, int* max, struct tcp_proxy** proxies, - struct sockaddr_storage* srv_addr, socklen_t srv_len, - struct timeval* now, struct timeval* tcp_timeout) -{ - int newfd; - struct sockaddr_storage addr; - struct tcp_proxy* p; - socklen_t addr_len; - newfd = accept(s, (struct sockaddr*)&addr, &addr_len); - if(newfd == -1) { -#ifndef USE_WINSOCK - if(errno == EAGAIN || errno == EINTR) - return; - fatal_exit("accept: %s", strerror(errno)); -#else - if(WSAGetLastError() == WSAEWOULDBLOCK || - WSAGetLastError() == WSAEINPROGRESS || - WSAGetLastError() == WSAECONNRESET) - return; - fatal_exit("accept: %s", wsa_strerror(WSAGetLastError())); -#endif - } - p = (struct tcp_proxy*)calloc(1, sizeof(*p)); - if(!p) fatal_exit("out of memory"); - memmove(&p->addr, &addr, addr_len); - p->addr_len = addr_len; - log_addr(1, "new tcp proxy", &p->addr, p->addr_len); - p->client_s = newfd; - p->server_s = socket(addr_is_ip6(srv_addr, srv_len)?AF_INET6:AF_INET, - SOCK_STREAM, 0); - if(p->server_s == -1) { -#ifndef USE_WINSOCK - fatal_exit("tcp socket: %s", strerror(errno)); -#else - fatal_exit("tcp socket: %s", wsa_strerror(WSAGetLastError())); -#endif - } - fd_set_nonblock(p->client_s); - fd_set_nonblock(p->server_s); - if(connect(p->server_s, (struct sockaddr*)srv_addr, srv_len) == -1) { -#ifndef USE_WINSOCK - if(errno != EINPROGRESS) { - log_err("tcp connect: %s", strerror(errno)); - close(p->server_s); - close(p->client_s); -#else - if(WSAGetLastError() != WSAEWOULDBLOCK && - WSAGetLastError() != WSAEINPROGRESS) { - log_err("tcp connect: %s", - wsa_strerror(WSAGetLastError())); - closesocket(p->server_s); - closesocket(p->client_s); -#endif - free(p); - return; - } - } - p->timeout = *now; - dl_tv_add(&p->timeout, tcp_timeout); - - /* listen to client and server */ - FD_SET(FD_SET_T p->client_s, rorig); - FD_SET(FD_SET_T p->server_s, rorig); - if(p->client_s+1 > *max) - *max = p->client_s+1; - if(p->server_s+1 > *max) - *max = p->server_s+1; - - /* add into proxy list */ - p->next = *proxies; - *proxies = p; -} - -/** relay TCP, read a part */ -static int -tcp_relay_read(int s, struct tcp_send_list** first, - struct tcp_send_list** last, struct timeval* now, - struct timeval* delay, sldns_buffer* pkt) -{ - struct tcp_send_list* item; - ssize_t r = recv(s, (void*)sldns_buffer_begin(pkt), - sldns_buffer_capacity(pkt), 0); - if(r == -1) { -#ifndef USE_WINSOCK - if(errno == EINTR || errno == EAGAIN) - return 1; - log_err("tcp read: %s", strerror(errno)); -#else - if(WSAGetLastError() == WSAEINPROGRESS || - WSAGetLastError() == WSAEWOULDBLOCK) - return 1; - log_err("tcp read: %s", wsa_strerror(WSAGetLastError())); -#endif - return 0; - } else if(r == 0) { - /* connection closed */ - return 0; - } - item = (struct tcp_send_list*)malloc(sizeof(*item)); - if(!item) { - log_err("out of memory"); - return 0; - } - verbose(1, "read item len %d", (int)r); - item->len = (size_t)r; - item->item = memdup(sldns_buffer_begin(pkt), item->len); - if(!item->item) { - free(item); - log_err("out of memory"); - return 0; - } - item->done = 0; - item->wait = *now; - dl_tv_add(&item->wait, delay); - item->next = NULL; - - /* link in */ - if(*first) { - (*last)->next = item; - } else { - *first = item; - } - *last = item; - return 1; -} - -/** relay TCP, write a part */ -static int -tcp_relay_write(int s, struct tcp_send_list** first, - struct tcp_send_list** last, struct timeval* now) -{ - ssize_t r; - struct tcp_send_list* p; - while(*first) { - p = *first; - /* is the item ready? */ - if(!dl_tv_smaller(&p->wait, now)) - return 1; - /* write it */ - r = send(s, (void*)(p->item + p->done), p->len - p->done, 0); - if(r == -1) { -#ifndef USE_WINSOCK - if(errno == EAGAIN || errno == EINTR) - return 1; - log_err("tcp write: %s", strerror(errno)); -#else - if(WSAGetLastError() == WSAEWOULDBLOCK || - WSAGetLastError() == WSAEINPROGRESS) - return 1; - log_err("tcp write: %s", - wsa_strerror(WSAGetLastError())); -#endif - return 0; - } else if(r == 0) { - /* closed */ - return 0; - } - /* account it */ - p->done += (size_t)r; - verbose(1, "write item %d of %d", (int)p->done, (int)p->len); - if(p->done >= p->len) { - free(p->item); - *first = p->next; - if(!*first) - *last = NULL; - free(p); - } else { - /* partial write */ - return 1; - } - } - return 1; -} - -/** perform TCP relaying */ -static void -service_tcp_relay(struct tcp_proxy** tcp_proxies, struct timeval* now, - struct timeval* delay, struct timeval* tcp_timeout, sldns_buffer* pkt, - fd_set* rset, fd_set* rorig, fd_set* worig) -{ - struct tcp_proxy* p, **prev; - struct timeval tout; - int delete_it; - p = *tcp_proxies; - prev = tcp_proxies; - tout = *now; - dl_tv_add(&tout, tcp_timeout); - - while(p) { - delete_it = 0; - /* can we receive further queries? */ - if(!delete_it && FD_ISSET(p->client_s, rset)) { - p->timeout = tout; - log_addr(1, "read tcp query", &p->addr, p->addr_len); - if(!tcp_relay_read(p->client_s, &p->querylist, - &p->querylast, now, delay, pkt)) - delete_it = 1; - } - /* can we receive further answers? */ - if(!delete_it && p->server_s != -1 && - FD_ISSET(p->server_s, rset)) { - p->timeout = tout; - log_addr(1, "read tcp answer", &p->addr, p->addr_len); - if(!tcp_relay_read(p->server_s, &p->answerlist, - &p->answerlast, now, delay, pkt)) { -#ifndef USE_WINSOCK - close(p->server_s); -#else - closesocket(p->server_s); -#endif - FD_CLR(FD_SET_T p->server_s, worig); - FD_CLR(FD_SET_T p->server_s, rorig); - p->server_s = -1; - } - } - /* can we send on further queries */ - if(!delete_it && p->querylist && p->server_s != -1) { - p->timeout = tout; - if(dl_tv_smaller(&p->querylist->wait, now)) - log_addr(1, "write tcp query", - &p->addr, p->addr_len); - if(!tcp_relay_write(p->server_s, &p->querylist, - &p->querylast, now)) - delete_it = 1; - if(p->querylist && p->server_s != -1 && - dl_tv_smaller(&p->querylist->wait, now)) - FD_SET(FD_SET_T p->server_s, worig); - else FD_CLR(FD_SET_T p->server_s, worig); - } - - /* can we send on further answers */ - if(!delete_it && p->answerlist) { - p->timeout = tout; - if(dl_tv_smaller(&p->answerlist->wait, now)) - log_addr(1, "write tcp answer", - &p->addr, p->addr_len); - if(!tcp_relay_write(p->client_s, &p->answerlist, - &p->answerlast, now)) - delete_it = 1; - if(p->answerlist && dl_tv_smaller(&p->answerlist->wait, - now)) - FD_SET(FD_SET_T p->client_s, worig); - else FD_CLR(FD_SET_T p->client_s, worig); - if(!p->answerlist && p->server_s == -1) - delete_it = 1; - } - - /* does this entry timeout? (unused too long) */ - if(dl_tv_smaller(&p->timeout, now)) { - delete_it = 1; - } - if(delete_it) { - struct tcp_proxy* np = p->next; - *prev = np; - FD_CLR(FD_SET_T p->client_s, rorig); - FD_CLR(FD_SET_T p->client_s, worig); - if(p->server_s != -1) { - FD_CLR(FD_SET_T p->server_s, rorig); - FD_CLR(FD_SET_T p->server_s, worig); - } - tcp_proxy_delete(p); - p = np; - continue; - } - - prev = &p->next; - p = p->next; - } -} - -/** find waiting time */ -static int -service_findwait(struct timeval* now, struct timeval* wait, - struct ringbuf* ring, struct tcp_proxy* tcplist) -{ - /* first item is the time to wait */ - struct timeval* peek = ring_peek_time(ring); - struct timeval tcv; - int have_tcpval = 0; - struct tcp_proxy* p; - - /* also for TCP list the first in sendlists is the time to wait */ - for(p=tcplist; p; p=p->next) { - if(!have_tcpval) - tcv = p->timeout; - have_tcpval = 1; - if(dl_tv_smaller(&p->timeout, &tcv)) - tcv = p->timeout; - if(p->querylist && dl_tv_smaller(&p->querylist->wait, &tcv)) - tcv = p->querylist->wait; - if(p->answerlist && dl_tv_smaller(&p->answerlist->wait, &tcv)) - tcv = p->answerlist->wait; - } - if(peek) { - /* peek can be unaligned */ - /* use wait as a temp variable */ - memmove(wait, peek, sizeof(*wait)); - if(!have_tcpval) - tcv = *wait; - else if(dl_tv_smaller(wait, &tcv)) - tcv = *wait; - have_tcpval = 1; - } - if(have_tcpval) { - *wait = tcv; - dl_tv_subtract(wait, now); - return 1; - } - /* nothing, block */ - return 0; -} - -/** clear proxy list */ -static void -proxy_list_clear(struct proxy* p) -{ - char from[109]; - struct proxy* np; - int i=0, port; - while(p) { - np = p->next; - port = (int)ntohs(((struct sockaddr_in*)&p->addr)->sin_port); - if(addr_is_ip6(&p->addr, p->addr_len)) { - if(inet_ntop(AF_INET6, - &((struct sockaddr_in6*)&p->addr)->sin6_addr, - from, (socklen_t)sizeof(from)) == 0) - (void)strlcpy(from, "err", sizeof(from)); - } else { - if(inet_ntop(AF_INET, - &((struct sockaddr_in*)&p->addr)->sin_addr, - from, (socklen_t)sizeof(from)) == 0) - (void)strlcpy(from, "err", sizeof(from)); - } - printf("client[%d]: last %s@%d of %d : %u in, %u out, " - "%u returned\n", i++, from, port, (int)p->numreuse+1, - (unsigned)p->numwait, (unsigned)p->numsent, - (unsigned)p->numreturn); -#ifndef USE_WINSOCK - close(p->s); -#else - closesocket(p->s); -#endif - free(p); - p = np; - } -} - -/** clear TCP proxy list */ -static void -tcp_proxy_list_clear(struct tcp_proxy* p) -{ - struct tcp_proxy* np; - while(p) { - np = p->next; - tcp_proxy_delete(p); - p = np; - } -} - -/** delayer service loop */ -static void -service_loop(int udp_s, int listen_s, struct ringbuf* ring, - struct timeval* delay, struct timeval* reuse, - struct sockaddr_storage* srv_addr, socklen_t srv_len, - sldns_buffer* pkt) -{ - fd_set rset, rorig; - fd_set wset, worig; - struct timeval now, wait; - int max, have_wait = 0; - struct proxy* proxies = NULL; - struct tcp_proxy* tcp_proxies = NULL; - struct timeval tcp_timeout; - tcp_timeout.tv_sec = 120; - tcp_timeout.tv_usec = 0; -#ifndef S_SPLINT_S - FD_ZERO(&rorig); - FD_ZERO(&worig); - FD_SET(FD_SET_T udp_s, &rorig); - FD_SET(FD_SET_T listen_s, &rorig); -#endif - max = udp_s + 1; - if(listen_s + 1 > max) max = listen_s + 1; - while(!do_quit) { - /* wait for events */ - rset = rorig; - wset = worig; - if(have_wait) - verbose(1, "wait for %d.%6.6d", - (unsigned)wait.tv_sec, (unsigned)wait.tv_usec); - else verbose(1, "wait"); - if(select(max, &rset, &wset, NULL, have_wait?&wait:NULL) < 0) { - if(errno == EAGAIN || errno == EINTR) - continue; - fatal_exit("select: %s", strerror(errno)); - } - /* get current time */ - if(gettimeofday(&now, NULL) < 0) { - if(errno == EAGAIN || errno == EINTR) - continue; - fatal_exit("gettimeofday: %s", strerror(errno)); - } - verbose(1, "process at %u.%6.6u\n", - (unsigned)now.tv_sec, (unsigned)now.tv_usec); - /* sendout delayed queries to master server (frees up buffer)*/ - service_send(ring, &now, pkt, srv_addr, srv_len); - /* proxy return replies */ - service_proxy(&rset, udp_s, proxies, pkt, &now); - /* see what can be received to start waiting */ - service_recv(udp_s, ring, pkt, &rorig, &max, &proxies, - srv_addr, srv_len, &now, delay, reuse); - /* see if there are new tcp connections */ - service_tcp_listen(listen_s, &rorig, &max, &tcp_proxies, - srv_addr, srv_len, &now, &tcp_timeout); - /* service tcp connections */ - service_tcp_relay(&tcp_proxies, &now, delay, &tcp_timeout, - pkt, &rset, &rorig, &worig); - /* see what next timeout is (if any) */ - have_wait = service_findwait(&now, &wait, ring, tcp_proxies); - } - proxy_list_clear(proxies); - tcp_proxy_list_clear(tcp_proxies); -} - -/** delayer main service routine */ -static void -service(const char* bind_str, int bindport, const char* serv_str, - size_t memsize, int delay_msec) -{ - struct sockaddr_storage bind_addr, srv_addr; - socklen_t bind_len, srv_len; - struct ringbuf* ring = ring_create(memsize); - struct timeval delay, reuse; - sldns_buffer* pkt; - int i, s, listen_s; -#ifndef S_SPLINT_S - delay.tv_sec = delay_msec / 1000; - delay.tv_usec = (delay_msec % 1000)*1000; -#endif - reuse = delay; /* reuse is max(4*delay, 1 second) */ - dl_tv_add(&reuse, &delay); - dl_tv_add(&reuse, &delay); - dl_tv_add(&reuse, &delay); - if(reuse.tv_sec == 0) - reuse.tv_sec = 1; - if(!extstrtoaddr(serv_str, &srv_addr, &srv_len)) { - printf("cannot parse forward address: %s\n", serv_str); - exit(1); - } - pkt = sldns_buffer_new(65535); - if(!pkt) - fatal_exit("out of memory"); - if( signal(SIGINT, delayer_sigh) == SIG_ERR || -#ifdef SIGHUP - signal(SIGHUP, delayer_sigh) == SIG_ERR || -#endif -#ifdef SIGQUIT - signal(SIGQUIT, delayer_sigh) == SIG_ERR || -#endif -#ifdef SIGBREAK - signal(SIGBREAK, delayer_sigh) == SIG_ERR || -#endif -#ifdef SIGALRM - signal(SIGALRM, delayer_sigh) == SIG_ERR || -#endif - signal(SIGTERM, delayer_sigh) == SIG_ERR) - fatal_exit("could not bind to signal"); - /* bind UDP port */ - if((s = socket(str_is_ip6(bind_str)?AF_INET6:AF_INET, - SOCK_DGRAM, 0)) == -1) { -#ifndef USE_WINSOCK - fatal_exit("socket: %s", strerror(errno)); -#else - fatal_exit("socket: %s", wsa_strerror(WSAGetLastError())); -#endif - } - i=0; - if(bindport == 0) { - bindport = 1024 + arc4random()%64000; - i = 100; - } - while(1) { - if(!ipstrtoaddr(bind_str, bindport, &bind_addr, &bind_len)) { - printf("cannot parse listen address: %s\n", bind_str); - exit(1); - } - if(bind(s, (struct sockaddr*)&bind_addr, bind_len) == -1) { -#ifndef USE_WINSOCK - log_err("bind: %s", strerror(errno)); -#else - log_err("bind: %s", wsa_strerror(WSAGetLastError())); -#endif - if(i--==0) - fatal_exit("cannot bind any port"); - bindport = 1024 + arc4random()%64000; - } else break; - } - fd_set_nonblock(s); - /* and TCP port */ - if((listen_s = socket(str_is_ip6(bind_str)?AF_INET6:AF_INET, - SOCK_STREAM, 0)) == -1) { -#ifndef USE_WINSOCK - fatal_exit("tcp socket: %s", strerror(errno)); -#else - fatal_exit("tcp socket: %s", wsa_strerror(WSAGetLastError())); -#endif - } -#ifdef SO_REUSEADDR - if(1) { - int on = 1; - if(setsockopt(listen_s, SOL_SOCKET, SO_REUSEADDR, (void*)&on, - (socklen_t)sizeof(on)) < 0) -#ifndef USE_WINSOCK - fatal_exit("setsockopt(.. SO_REUSEADDR ..) failed: %s", - strerror(errno)); -#else - fatal_exit("setsockopt(.. SO_REUSEADDR ..) failed: %s", - wsa_strerror(WSAGetLastError())); -#endif - } -#endif - if(bind(listen_s, (struct sockaddr*)&bind_addr, bind_len) == -1) { -#ifndef USE_WINSOCK - fatal_exit("tcp bind: %s", strerror(errno)); -#else - fatal_exit("tcp bind: %s", wsa_strerror(WSAGetLastError())); -#endif - } - if(listen(listen_s, 5) == -1) { -#ifndef USE_WINSOCK - fatal_exit("tcp listen: %s", strerror(errno)); -#else - fatal_exit("tcp listen: %s", wsa_strerror(WSAGetLastError())); -#endif - } - fd_set_nonblock(listen_s); - printf("listening on port: %d\n", bindport); - - /* process loop */ - do_quit = 0; - service_loop(s, listen_s, ring, &delay, &reuse, &srv_addr, srv_len, - pkt); - - /* cleanup */ - verbose(1, "cleanup"); -#ifndef USE_WINSOCK - close(s); - close(listen_s); -#else - closesocket(s); - closesocket(listen_s); -#endif - sldns_buffer_free(pkt); - ring_delete(ring); -} - -/** getopt global, in case header files fail to declare it. */ -extern int optind; -/** getopt global, in case header files fail to declare it. */ -extern char* optarg; - -/** main program for delayer */ -int main(int argc, char** argv) -{ - int c; /* defaults */ - const char* server = "127.0.0.1@53"; - const char* bindto = "0.0.0.0"; - int bindport = 0; - size_t memsize = 10*1024*1024; - int delay = 100; - - verbosity = 0; - log_init(0, 0, 0); - log_ident_set("delayer"); - if(argc == 1) usage(argv); - while( (c=getopt(argc, argv, "b:d:f:hm:p:")) != -1) { - switch(c) { - case 'b': - bindto = optarg; - break; - case 'd': - if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) { - printf("bad delay: %s\n", optarg); - return 1; - } - delay = atoi(optarg); - break; - case 'f': - server = optarg; - break; - case 'm': - if(!cfg_parse_memsize(optarg, &memsize)) { - printf("bad memsize: %s\n", optarg); - return 1; - } - break; - case 'p': - if(atoi(optarg)==0 && strcmp(optarg,"0")!=0) { - printf("bad port nr: %s\n", optarg); - return 1; - } - bindport = atoi(optarg); - break; - case 'h': - case '?': - default: - usage(argv); - } - } - argc -= optind; - argv += optind; - if(argc != 0) - usage(argv); - - printf("bind to %s @ %d and forward to %s after %d msec\n", - bindto, bindport, server, delay); - service(bindto, bindport, server, memsize, delay); - return 0; -} diff --git a/external/unbound/testcode/do-tests.sh b/external/unbound/testcode/do-tests.sh deleted file mode 100755 index e356d4fc3..000000000 --- a/external/unbound/testcode/do-tests.sh +++ /dev/null @@ -1,63 +0,0 @@ -#!/usr/bin/env bash -. testdata/common.sh - -NEED_SPLINT='00-lint.tpkg' -NEED_DOXYGEN='01-doc.tpkg' -NEED_XXD='fwd_compress_c00c.tpkg fwd_zero.tpkg' -NEED_NC='fwd_compress_c00c.tpkg fwd_zero.tpkg' -NEED_CURL='06-ianaports.tpkg root_anchor.tpkg' -NEED_WHOAMI='07-confroot.tpkg' -NEED_IPV6='fwd_ancil.tpkg fwd_tcp_tc6.tpkg stub_udp6.tpkg edns_cache.tpkg' -NEED_NOMINGW='tcp_sigpipe.tpkg 07-confroot.tpkg 08-host-lib.tpkg fwd_ancil.tpkg' -NEED_DNSCRYPT_PROXY='dnscrypt_queries.tpkg' - -# test if dig and ldns-testns are available. -test_tool_avail "dig" -test_tool_avail "ldns-testns" - -# test for ipv6, uses streamtcp peculiarity. -if ./streamtcp -f ::1 2>&1 | grep "not supported" >/dev/null 2>&1; then - HAVE_IPV6=no -else - HAVE_IPV6=yes -fi - -# test mingw. no signals and so on. -if uname | grep MINGW >/dev/null; then - HAVE_MINGW=yes -else - HAVE_MINGW=no -fi - -cd testdata; -sh ../testcode/mini_tpkg.sh clean -rm -f .perfstats.txt -for test in `ls *.tpkg`; do - SKIP=0 - skip_if_in_list $test "$NEED_SPLINT" "splint" - skip_if_in_list $test "$NEED_DOXYGEN" "doxygen" - skip_if_in_list $test "$NEED_CURL" "curl" - skip_if_in_list $test "$NEED_XXD" "xxd" - skip_if_in_list $test "$NEED_NC" "nc" - skip_if_in_list $test "$NEED_WHOAMI" "whoami" - skip_if_in_list $test "$NEED_DNSCRYPT_PROXY" "dnscrypt-proxy" - - if echo $NEED_IPV6 | grep $test >/dev/null; then - if test "$HAVE_IPV6" = no; then - SKIP=1; - fi - fi - if echo $NEED_NOMINGW | grep $test >/dev/null; then - if test "$HAVE_MINGW" = yes; then - SKIP=1; - fi - fi - if test $SKIP -eq 0; then - echo $test - sh ../testcode/mini_tpkg.sh -a ../.. exe $test - else - echo "skip $test" - fi -done -sh ../testcode/mini_tpkg.sh report -cat .perfstats.txt diff --git a/external/unbound/testcode/fake_event.c b/external/unbound/testcode/fake_event.c deleted file mode 100644 index 154013a8c..000000000 --- a/external/unbound/testcode/fake_event.c +++ /dev/null @@ -1,1423 +0,0 @@ -/* - * testcode/fake_event.c - fake event handling that replays existing scenario. - * - * 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 - * Event service that replays a scenario. - * This implements the same exported symbols as the files: - * util/netevent.c - * services/listen_dnsport.c - * services/outside_network.c - * But these do not actually access the network or events, instead - * the scenario is played. - */ - -#include "config.h" -#include "testcode/fake_event.h" -#include "util/netevent.h" -#include "util/net_help.h" -#include "util/data/msgparse.h" -#include "util/data/msgreply.h" -#include "util/data/msgencode.h" -#include "util/data/dname.h" -#include "util/config_file.h" -#include "services/listen_dnsport.h" -#include "services/outside_network.h" -#include "services/cache/infra.h" -#include "testcode/replay.h" -#include "testcode/testpkts.h" -#include "util/log.h" -#include "util/fptr_wlist.h" -#include "sldns/sbuffer.h" -#include "sldns/wire2str.h" -#include "sldns/str2wire.h" -#include <signal.h> -struct worker; -struct daemon_remote; - -/** Global variable: the scenario. Saved here for when event_init is done. */ -static struct replay_scenario* saved_scenario = NULL; - -/** add timers and the values do not overflow or become negative */ -static void -timeval_add(struct timeval* d, const struct timeval* add) -{ -#ifndef S_SPLINT_S - d->tv_sec += add->tv_sec; - d->tv_usec += add->tv_usec; - if(d->tv_usec > 1000000) { - d->tv_usec -= 1000000; - d->tv_sec++; - } -#endif -} - -void -fake_temp_file(const char* adj, const char* id, char* buf, size_t len) -{ -#ifdef USE_WINSOCK - snprintf(buf, len, "testbound_%u%s%s.tmp", - (unsigned)getpid(), adj, id); -#else - snprintf(buf, len, "/tmp/testbound_%u%s%s.tmp", - (unsigned)getpid(), adj, id); -#endif -} - -void -fake_event_init(struct replay_scenario* scen) -{ - saved_scenario = scen; -} - -void -fake_event_cleanup(void) -{ - replay_scenario_delete(saved_scenario); - saved_scenario = NULL; -} - -/** helper function that logs a sldns_pkt packet to logfile */ -static void -log_pkt(const char* desc, uint8_t* pkt, size_t len) -{ - char* str = sldns_wire2str_pkt(pkt, len); - if(!str) - fatal_exit("%s: (failed out of memory wire2str_pkt)", desc); - else { - log_info("%s%s", desc, str); - free(str); - } -} - -/** - * Returns a string describing the event type. - */ -static const char* -repevt_string(enum replay_event_type t) -{ - switch(t) { - case repevt_nothing: return "NOTHING"; - case repevt_front_query: return "QUERY"; - case repevt_front_reply: return "CHECK_ANSWER"; - case repevt_timeout: return "TIMEOUT"; - case repevt_time_passes: return "TIME_PASSES"; - case repevt_back_reply: return "REPLY"; - case repevt_back_query: return "CHECK_OUT_QUERY"; - case repevt_autotrust_check: return "CHECK_AUTOTRUST"; - case repevt_error: return "ERROR"; - case repevt_assign: return "ASSIGN"; - case repevt_traffic: return "TRAFFIC"; - case repevt_infra_rtt: return "INFRA_RTT"; - default: return "UNKNOWN"; - } -} - -/** delete a fake pending */ -static void -delete_fake_pending(struct fake_pending* pend) -{ - if(!pend) - return; - free(pend->zone); - sldns_buffer_free(pend->buffer); - free(pend->pkt); - free(pend); -} - -/** delete a replay answer */ -static void -delete_replay_answer(struct replay_answer* a) -{ - if(!a) - return; - if(a->repinfo.c) { - sldns_buffer_free(a->repinfo.c->buffer); - free(a->repinfo.c); - } - free(a->pkt); - free(a); -} - -/** - * return: true if pending query matches the now event. - */ -static int -pending_matches_current(struct replay_runtime* runtime, - struct entry** entry, struct fake_pending **pend) -{ - struct fake_pending* p; - struct entry* e; - if(!runtime->now || runtime->now->evt_type != repevt_back_query - || !runtime->pending_list) - return 0; - /* see if any of the pending queries matches */ - for(p = runtime->pending_list; p; p = p->next) { - if(runtime->now->addrlen != 0 && - sockaddr_cmp(&p->addr, p->addrlen, &runtime->now->addr, - runtime->now->addrlen) != 0) - continue; - if((e=find_match(runtime->now->match, p->pkt, p->pkt_len, - p->transport))) { - *entry = e; - *pend = p; - return 1; - } - } - return 0; -} - -/** - * Find the range that matches this pending message. - * @param runtime: runtime with current moment, and range list. - * @param entry: returns the pointer to entry that matches. - * @param pend: the pending that the entry must match. - * @return: true if a match is found. - */ -static int -pending_find_match(struct replay_runtime* runtime, struct entry** entry, - struct fake_pending* pend) -{ - int timenow = runtime->now->time_step; - struct replay_range* p = runtime->scenario->range_list; - while(p) { - if(p->start_step <= timenow && timenow <= p->end_step && - (p->addrlen == 0 || sockaddr_cmp(&p->addr, p->addrlen, - &pend->addr, pend->addrlen) == 0) && - (*entry = find_match(p->match, pend->pkt, pend->pkt_len, - pend->transport))) { - log_info("matched query time %d in range [%d, %d] " - "with entry line %d", timenow, - p->start_step, p->end_step, (*entry)->lineno); - if(p->addrlen != 0) - log_addr(0, "matched ip", &p->addr, p->addrlen); - log_pkt("matched pkt: ", - (*entry)->reply_list->reply_pkt, - (*entry)->reply_list->reply_len); - return 1; - } - p = p->next_range; - } - return 0; -} - -/** - * See if outgoing pending query matches an entry. - * @param runtime: runtime. - * @param entry: if true, the entry that matches is returned. - * @param pend: if true, the outgoing message that matches is returned. - * @return: true if pending query matches the now event. - */ -static int -pending_matches_range(struct replay_runtime* runtime, - struct entry** entry, struct fake_pending** pend) -{ - struct fake_pending* p = runtime->pending_list; - /* slow, O(N*N), but it works as advertised with weird matching */ - while(p) { - log_info("check of pending"); - if(pending_find_match(runtime, entry, p)) { - *pend = p; - return 1; - } - p = p->next; - } - return 0; -} - -/** - * Remove the item from the pending list. - */ -static void -pending_list_delete(struct replay_runtime* runtime, struct fake_pending* pend) -{ - struct fake_pending** prev = &runtime->pending_list; - struct fake_pending* p = runtime->pending_list; - - while(p) { - if(p == pend) { - *prev = p->next; - delete_fake_pending(pend); - return; - } - - prev = &p->next; - p = p->next; - } -} - -/** - * Fill buffer with reply from the entry. - */ -static void -fill_buffer_with_reply(sldns_buffer* buffer, struct entry* entry, uint8_t* q, - size_t qlen) -{ - uint8_t* c; - size_t clen; - log_assert(entry && entry->reply_list); - sldns_buffer_clear(buffer); - if(entry->reply_list->reply_from_hex) { - c = sldns_buffer_begin(entry->reply_list->reply_from_hex); - clen = sldns_buffer_limit(entry->reply_list->reply_from_hex); - if(!c) fatal_exit("out of memory"); - } else { - c = entry->reply_list->reply_pkt; - clen = entry->reply_list->reply_len; - } - if(c) { - if(q) adjust_packet(entry, &c, &clen, q, qlen); - sldns_buffer_write(buffer, c, clen); - if(q) free(c); - } - sldns_buffer_flip(buffer); -} - -/** - * Perform range entry on pending message. - * @param runtime: runtime buffer size preference. - * @param entry: entry that codes for the reply to do. - * @param pend: pending query that is answered, callback called. - */ -static void -answer_callback_from_entry(struct replay_runtime* runtime, - struct entry* entry, struct fake_pending* pend) -{ - struct comm_point c; - struct comm_reply repinfo; - void* cb_arg = pend->cb_arg; - comm_point_callback_type* cb = pend->callback; - - memset(&c, 0, sizeof(c)); - c.fd = -1; - c.buffer = sldns_buffer_new(runtime->bufsize); - c.type = comm_udp; - if(pend->transport == transport_tcp) - c.type = comm_tcp; - fill_buffer_with_reply(c.buffer, entry, pend->pkt, pend->pkt_len); - repinfo.c = &c; - repinfo.addrlen = pend->addrlen; - memcpy(&repinfo.addr, &pend->addr, pend->addrlen); - if(!pend->serviced) - pending_list_delete(runtime, pend); - if((*cb)(&c, cb_arg, NETEVENT_NOERROR, &repinfo)) { - fatal_exit("testbound: unexpected: callback returned 1"); - } - sldns_buffer_free(c.buffer); -} - -/** Check the now moment answer check event */ -static void -answer_check_it(struct replay_runtime* runtime) -{ - struct replay_answer* ans = runtime->answer_list, - *prev = NULL; - log_assert(runtime && runtime->now && - runtime->now->evt_type == repevt_front_reply); - while(ans) { - enum transport_type tr = transport_tcp; - if(ans->repinfo.c->type == comm_udp) - tr = transport_udp; - if((runtime->now->addrlen == 0 || sockaddr_cmp( - &runtime->now->addr, runtime->now->addrlen, - &ans->repinfo.addr, ans->repinfo.addrlen) == 0) && - find_match(runtime->now->match, ans->pkt, - ans->pkt_len, tr)) { - log_info("testbound matched event entry from line %d", - runtime->now->match->lineno); - log_info("testbound: do STEP %d %s", - runtime->now->time_step, - repevt_string(runtime->now->evt_type)); - if(prev) - prev->next = ans->next; - else runtime->answer_list = ans->next; - if(!ans->next) - runtime->answer_last = prev; - delete_replay_answer(ans); - return; - } else { - prev = ans; - ans = ans->next; - } - } - log_info("testbound: do STEP %d %s", runtime->now->time_step, - repevt_string(runtime->now->evt_type)); - fatal_exit("testbound: not matched"); -} - -/** - * Create commpoint (as return address) for a fake incoming query. - */ -static void -fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo) -{ - struct comm_reply repinfo; - memset(&repinfo, 0, sizeof(repinfo)); - repinfo.c = (struct comm_point*)calloc(1, sizeof(struct comm_point)); - repinfo.addrlen = (socklen_t)sizeof(struct sockaddr_in); - if(todo->addrlen != 0) { - repinfo.addrlen = todo->addrlen; - memcpy(&repinfo.addr, &todo->addr, todo->addrlen); - } - repinfo.c->fd = -1; - repinfo.c->ev = (struct internal_event*)runtime; - repinfo.c->buffer = sldns_buffer_new(runtime->bufsize); - if(todo->match->match_transport == transport_tcp) - repinfo.c->type = comm_tcp; - else repinfo.c->type = comm_udp; - fill_buffer_with_reply(repinfo.c->buffer, todo->match, NULL, 0); - log_info("testbound: incoming QUERY"); - log_pkt("query pkt", todo->match->reply_list->reply_pkt, - todo->match->reply_list->reply_len); - /* call the callback for incoming queries */ - if((*runtime->callback_query)(repinfo.c, runtime->cb_arg, - NETEVENT_NOERROR, &repinfo)) { - /* send immediate reply */ - comm_point_send_reply(&repinfo); - } - /* clear it again, in case copy not done properly */ - memset(&repinfo, 0, sizeof(repinfo)); -} - -/** - * Perform callback for fake pending message. - */ -static void -fake_pending_callback(struct replay_runtime* runtime, - struct replay_moment* todo, int error) -{ - struct fake_pending* p = runtime->pending_list; - struct comm_reply repinfo; - struct comm_point c; - void* cb_arg; - comm_point_callback_type* cb; - - memset(&c, 0, sizeof(c)); - if(!p) fatal_exit("No pending queries."); - cb_arg = p->cb_arg; - cb = p->callback; - c.buffer = sldns_buffer_new(runtime->bufsize); - c.type = comm_udp; - if(p->transport == transport_tcp) - c.type = comm_tcp; - if(todo->evt_type == repevt_back_reply && todo->match) { - fill_buffer_with_reply(c.buffer, todo->match, p->pkt, - p->pkt_len); - } - repinfo.c = &c; - repinfo.addrlen = p->addrlen; - memcpy(&repinfo.addr, &p->addr, p->addrlen); - if(!p->serviced) - pending_list_delete(runtime, p); - if((*cb)(&c, cb_arg, error, &repinfo)) { - fatal_exit("unexpected: pending callback returned 1"); - } - /* delete the pending item. */ - sldns_buffer_free(c.buffer); -} - -/** pass time */ -static void -moment_assign(struct replay_runtime* runtime, struct replay_moment* mom) -{ - char* value = macro_process(runtime->vars, runtime, mom->string); - if(!value) - fatal_exit("could not process macro step %d", mom->time_step); - log_info("assign %s = %s", mom->variable, value); - if(!macro_assign(runtime->vars, mom->variable, value)) - fatal_exit("out of memory storing macro"); - free(value); - if(verbosity >= VERB_ALGO) - macro_print_debug(runtime->vars); -} - -/** pass time */ -static void -time_passes(struct replay_runtime* runtime, struct replay_moment* mom) -{ - struct fake_timer *t; - struct timeval tv = mom->elapse; - if(mom->string) { - char* xp = macro_process(runtime->vars, runtime, mom->string); - double sec; - if(!xp) fatal_exit("could not macro expand %s", mom->string); - verbose(VERB_ALGO, "EVAL %s", mom->string); - sec = atof(xp); - free(xp); -#ifndef S_SPLINT_S - tv.tv_sec = sec; - tv.tv_usec = (int)((sec - (double)tv.tv_sec) *1000000. + 0.5); -#endif - } - timeval_add(&runtime->now_tv, &tv); - runtime->now_secs = (time_t)runtime->now_tv.tv_sec; -#ifndef S_SPLINT_S - log_info("elapsed %d.%6.6d now %d.%6.6d", - (int)tv.tv_sec, (int)tv.tv_usec, - (int)runtime->now_tv.tv_sec, (int)runtime->now_tv.tv_usec); -#endif - /* see if any timers have fired; and run them */ - while( (t=replay_get_oldest_timer(runtime)) ) { - t->enabled = 0; - log_info("fake_timer callback"); - fptr_ok(fptr_whitelist_comm_timer(t->cb)); - (*t->cb)(t->cb_arg); - } -} - -/** check autotrust file contents */ -static void -autotrust_check(struct replay_runtime* runtime, struct replay_moment* mom) -{ - char name[1024], line[1024]; - FILE *in; - int lineno = 0, oke=1; - char* expanded; - struct config_strlist* p; - line[sizeof(line)-1] = 0; - log_assert(mom->autotrust_id); - fake_temp_file("_auto_", mom->autotrust_id, name, sizeof(name)); - in = fopen(name, "r"); - if(!in) fatal_exit("could not open %s: %s", name, strerror(errno)); - for(p=mom->file_content; p; p=p->next) { - lineno++; - if(!fgets(line, (int)sizeof(line)-1, in)) { - log_err("autotrust check failed, could not read line"); - log_err("file %s, line %d", name, lineno); - log_err("should be: %s", p->str); - fatal_exit("autotrust_check failed"); - } - if(line[0]) line[strlen(line)-1] = 0; /* remove newline */ - expanded = macro_process(runtime->vars, runtime, p->str); - if(!expanded) - fatal_exit("could not expand macro line %d", lineno); - if(verbosity >= 7 && strcmp(p->str, expanded) != 0) - log_info("expanded '%s' to '%s'", p->str, expanded); - if(strcmp(expanded, line) != 0) { - log_err("mismatch in file %s, line %d", name, lineno); - log_err("file has : %s", line); - log_err("should be: %s", expanded); - free(expanded); - oke = 0; - continue; - } - free(expanded); - fprintf(stderr, "%s:%2d ok : %s\n", name, lineno, line); - } - if(fgets(line, (int)sizeof(line)-1, in)) { - log_err("autotrust check failed, extra lines in %s after %d", - name, lineno); - do { - fprintf(stderr, "file has: %s", line); - } while(fgets(line, (int)sizeof(line)-1, in)); - oke = 0; - } - fclose(in); - if(!oke) - fatal_exit("autotrust_check STEP %d failed", mom->time_step); - log_info("autotrust %s is OK", mom->autotrust_id); -} - -/** Store RTT in infra cache */ -static void -do_infra_rtt(struct replay_runtime* runtime) -{ - struct replay_moment* now = runtime->now; - int rto; - size_t dplen = 0; - uint8_t* dp = sldns_str2wire_dname(now->variable, &dplen); - if(!dp) fatal_exit("cannot parse %s", now->variable); - rto = infra_rtt_update(runtime->infra, &now->addr, now->addrlen, - dp, dplen, LDNS_RR_TYPE_A, atoi(now->string), - -1, runtime->now_secs); - log_addr(0, "INFRA_RTT for", &now->addr, now->addrlen); - log_info("INFRA_RTT(%s roundtrip %d): rto of %d", now->variable, - atoi(now->string), rto); - if(rto == 0) fatal_exit("infra_rtt_update failed"); - free(dp); -} - -/** perform exponential backoff on the timeout */ -static void -expon_timeout_backoff(struct replay_runtime* runtime) -{ - struct fake_pending* p = runtime->pending_list; - int rtt, vs; - uint8_t edns_lame_known; - int last_rtt, rto; - if(!p) return; /* no pending packet to backoff */ - if(!infra_host(runtime->infra, &p->addr, p->addrlen, p->zone, - p->zonelen, runtime->now_secs, &vs, &edns_lame_known, &rtt)) - return; - last_rtt = rtt; - rto = infra_rtt_update(runtime->infra, &p->addr, p->addrlen, p->zone, - p->zonelen, p->qtype, -1, last_rtt, runtime->now_secs); - log_info("infra_rtt_update returned rto %d", rto); -} - -/** - * Advance to the next moment. - */ -static void -advance_moment(struct replay_runtime* runtime) -{ - if(!runtime->now) - runtime->now = runtime->scenario->mom_first; - else runtime->now = runtime->now->mom_next; -} - -/** - * Perform actions or checks determined by the moment. - * Also advances the time by one step. - * @param runtime: scenario runtime information. - */ -static void -do_moment_and_advance(struct replay_runtime* runtime) -{ - struct replay_moment* mom; - if(!runtime->now) { - advance_moment(runtime); - return; - } - log_info("testbound: do STEP %d %s", runtime->now->time_step, - repevt_string(runtime->now->evt_type)); - switch(runtime->now->evt_type) { - case repevt_nothing: - advance_moment(runtime); - break; - case repevt_front_query: - /* advance moment before doing the step, so that the next - moment which may check some result of the mom step - can catch those results. */ - mom = runtime->now; - advance_moment(runtime); - fake_front_query(runtime, mom); - break; - case repevt_front_reply: - if(runtime->answer_list) - log_err("testbound: There are unmatched answers."); - fatal_exit("testbound: query answer not matched"); - break; - case repevt_timeout: - mom = runtime->now; - advance_moment(runtime); - expon_timeout_backoff(runtime); - fake_pending_callback(runtime, mom, NETEVENT_TIMEOUT); - break; - case repevt_back_reply: - mom = runtime->now; - advance_moment(runtime); - fake_pending_callback(runtime, mom, NETEVENT_NOERROR); - break; - case repevt_back_query: - /* Back queries are matched when they are sent out. */ - log_err("No query matching the current moment was sent."); - fatal_exit("testbound: back query not matched"); - break; - case repevt_error: - mom = runtime->now; - advance_moment(runtime); - fake_pending_callback(runtime, mom, NETEVENT_CLOSED); - break; - case repevt_time_passes: - time_passes(runtime, runtime->now); - advance_moment(runtime); - break; - case repevt_autotrust_check: - autotrust_check(runtime, runtime->now); - advance_moment(runtime); - break; - case repevt_assign: - moment_assign(runtime, runtime->now); - advance_moment(runtime); - break; - case repevt_traffic: - advance_moment(runtime); - break; - case repevt_infra_rtt: - do_infra_rtt(runtime); - advance_moment(runtime); - break; - default: - fatal_exit("testbound: unknown event type %d", - runtime->now->evt_type); - } -} - -/** run the scenario in event callbacks */ -static void -run_scenario(struct replay_runtime* runtime) -{ - struct entry* entry = NULL; - struct fake_pending* pending = NULL; - int max_rounds = 5000; - int rounds = 0; - runtime->now = runtime->scenario->mom_first; - log_info("testbound: entering fake runloop"); - do { - /* if moment matches pending query do it. */ - /* else if moment matches given answer, do it */ - /* else if precoded_range matches pending, do it */ - /* else do the current moment */ - if(pending_matches_current(runtime, &entry, &pending)) { - log_info("testbound: do STEP %d CHECK_OUT_QUERY", - runtime->now->time_step); - advance_moment(runtime); - if(entry->copy_id) - answer_callback_from_entry(runtime, entry, - pending); - } else if(runtime->answer_list && runtime->now && - runtime->now->evt_type == repevt_front_reply) { - answer_check_it(runtime); - advance_moment(runtime); - } else if(pending_matches_range(runtime, &entry, &pending)) { - answer_callback_from_entry(runtime, entry, pending); - } else { - do_moment_and_advance(runtime); - } - log_info("testbound: end of event stage"); - rounds++; - if(rounds > max_rounds) - fatal_exit("testbound: too many rounds, it loops."); - } while(runtime->now); - - if(runtime->pending_list) { - struct fake_pending* p; - log_err("testbound: there are still messages pending."); - for(p = runtime->pending_list; p; p=p->next) { - log_pkt("pending msg", p->pkt, p->pkt_len); - log_addr(0, "pending to", &p->addr, p->addrlen); - } - fatal_exit("testbound: there are still messages pending."); - } - if(runtime->answer_list) { - fatal_exit("testbound: there are unmatched answers."); - } - log_info("testbound: exiting fake runloop."); - runtime->exit_cleanly = 1; -} - -/*********** Dummy routines ***********/ - -struct listen_dnsport* -listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports), - size_t bufsize, int ATTR_UNUSED(tcp_accept_count), - void* ATTR_UNUSED(sslctx), struct dt_env* ATTR_UNUSED(dtenv), - comm_point_callback_type* cb, void* cb_arg) -{ - struct replay_runtime* runtime = (struct replay_runtime*)base; - struct listen_dnsport* l= calloc(1, sizeof(struct listen_dnsport)); - if(!l) - return NULL; - l->base = base; - l->udp_buff = sldns_buffer_new(bufsize); - if(!l->udp_buff) { - free(l); - return NULL; - } - runtime->callback_query = cb; - runtime->cb_arg = cb_arg; - runtime->bufsize = bufsize; - return l; -} - -void -listen_delete(struct listen_dnsport* listen) -{ - if(!listen) - return; - sldns_buffer_free(listen->udp_buff); - free(listen); -} - -struct comm_base* -comm_base_create(int ATTR_UNUSED(sigs)) -{ - /* we return the runtime structure instead. */ - struct replay_runtime* runtime = (struct replay_runtime*) - calloc(1, sizeof(struct replay_runtime)); - runtime->scenario = saved_scenario; - runtime->vars = macro_store_create(); - if(!runtime->vars) fatal_exit("out of memory"); - return (struct comm_base*)runtime; -} - -void -comm_base_delete(struct comm_base* b) -{ - struct replay_runtime* runtime = (struct replay_runtime*)b; - struct fake_pending* p, *np; - struct replay_answer* a, *na; - struct fake_timer* t, *nt; - if(!runtime) - return; - runtime->scenario= NULL; - p = runtime->pending_list; - while(p) { - np = p->next; - delete_fake_pending(p); - p = np; - } - a = runtime->answer_list; - while(a) { - na = a->next; - delete_replay_answer(a); - a = na; - } - t = runtime->timer_list; - while(t) { - nt = t->next; - free(t); - t = nt; - } - macro_store_delete(runtime->vars); - free(runtime); -} - -void -comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv) -{ - struct replay_runtime* runtime = (struct replay_runtime*)b; - *tt = &runtime->now_secs; - *tv = &runtime->now_tv; -} - -void -comm_base_dispatch(struct comm_base* b) -{ - struct replay_runtime* runtime = (struct replay_runtime*)b; - run_scenario(runtime); - if(runtime->sig_cb) - (*runtime->sig_cb)(SIGTERM, runtime->sig_cb_arg); - else exit(0); /* OK exit when LIBEVENT_SIGNAL_PROBLEM exists */ -} - -void -comm_base_exit(struct comm_base* b) -{ - struct replay_runtime* runtime = (struct replay_runtime*)b; - if(!runtime->exit_cleanly) { - /* some sort of failure */ - fatal_exit("testbound: comm_base_exit was called."); - } -} - -struct comm_signal* -comm_signal_create(struct comm_base* base, - void (*callback)(int, void*), void* cb_arg) -{ - struct replay_runtime* runtime = (struct replay_runtime*)base; - runtime->sig_cb = callback; - runtime->sig_cb_arg = cb_arg; - return calloc(1, sizeof(struct comm_signal)); -} - -int -comm_signal_bind(struct comm_signal* ATTR_UNUSED(comsig), int - ATTR_UNUSED(sig)) -{ - return 1; -} - -void -comm_signal_delete(struct comm_signal* comsig) -{ - free(comsig); -} - -void -comm_point_send_reply(struct comm_reply* repinfo) -{ - struct replay_answer* ans = (struct replay_answer*)calloc(1, - sizeof(struct replay_answer)); - struct replay_runtime* runtime = (struct replay_runtime*)repinfo->c->ev; - log_info("testbound: comm_point_send_reply fake"); - /* dump it into the todo list */ - log_assert(ans); - memcpy(&ans->repinfo, repinfo, sizeof(struct comm_reply)); - ans->next = NULL; - if(runtime->answer_last) - runtime->answer_last->next = ans; - else runtime->answer_list = ans; - runtime->answer_last = ans; - - /* try to parse packet */ - ans->pkt = memdup(sldns_buffer_begin(ans->repinfo.c->buffer), - sldns_buffer_limit(ans->repinfo.c->buffer)); - ans->pkt_len = sldns_buffer_limit(ans->repinfo.c->buffer); - if(!ans->pkt) fatal_exit("out of memory"); - log_pkt("reply pkt: ", ans->pkt, ans->pkt_len); -} - -void -comm_point_drop_reply(struct comm_reply* repinfo) -{ - log_info("comm_point_drop_reply fake"); - if(repinfo->c) { - sldns_buffer_free(repinfo->c->buffer); - free(repinfo->c); - } -} - -struct outside_network* -outside_network_create(struct comm_base* base, size_t bufsize, - size_t ATTR_UNUSED(num_ports), char** ATTR_UNUSED(ifs), - int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4), - int ATTR_UNUSED(do_ip6), size_t ATTR_UNUSED(num_tcp), - struct infra_cache* infra, - struct ub_randstate* ATTR_UNUSED(rnd), - int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports), - int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold), - int ATTR_UNUSED(outgoing_tcp_mss), - void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param), - int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx), - int ATTR_UNUSED(delayclose), struct dt_env* ATTR_UNUSED(dtenv)) -{ - struct replay_runtime* runtime = (struct replay_runtime*)base; - struct outside_network* outnet = calloc(1, - sizeof(struct outside_network)); - (void)unwanted_action; - if(!outnet) - return NULL; - runtime->infra = infra; - outnet->base = base; - outnet->udp_buff = sldns_buffer_new(bufsize); - if(!outnet->udp_buff) { - free(outnet); - return NULL; - } - return outnet; -} - -void -outside_network_delete(struct outside_network* outnet) -{ - if(!outnet) - return; - sldns_buffer_free(outnet->udp_buff); - free(outnet); -} - -void -outside_network_quit_prepare(struct outside_network* ATTR_UNUSED(outnet)) -{ -} - -struct pending* -pending_udp_query(struct serviced_query* sq, sldns_buffer* packet, - int timeout, comm_point_callback_type* callback, void* callback_arg) -{ - struct replay_runtime* runtime = (struct replay_runtime*) - sq->outnet->base; - struct fake_pending* pend = (struct fake_pending*)calloc(1, - sizeof(struct fake_pending)); - log_assert(pend); - pend->buffer = sldns_buffer_new(sldns_buffer_capacity(packet)); - log_assert(pend->buffer); - sldns_buffer_write(pend->buffer, sldns_buffer_begin(packet), - sldns_buffer_limit(packet)); - sldns_buffer_flip(pend->buffer); - memcpy(&pend->addr, &sq->addr, sq->addrlen); - pend->addrlen = sq->addrlen; - pend->callback = callback; - pend->cb_arg = callback_arg; - pend->timeout = timeout/1000; - pend->transport = transport_udp; - pend->pkt = NULL; - pend->zone = NULL; - pend->serviced = 0; - pend->runtime = runtime; - pend->pkt_len = sldns_buffer_limit(packet); - pend->pkt = memdup(sldns_buffer_begin(packet), pend->pkt_len); - if(!pend->pkt) fatal_exit("out of memory"); - log_pkt("pending udp pkt: ", pend->pkt, pend->pkt_len); - - /* see if it matches the current moment */ - if(runtime->now && runtime->now->evt_type == repevt_back_query && - (runtime->now->addrlen == 0 || sockaddr_cmp( - &runtime->now->addr, runtime->now->addrlen, - &pend->addr, pend->addrlen) == 0) && - find_match(runtime->now->match, pend->pkt, pend->pkt_len, - pend->transport)) { - log_info("testbound: matched pending to event. " - "advance time between events."); - log_info("testbound: do STEP %d %s", runtime->now->time_step, - repevt_string(runtime->now->evt_type)); - advance_moment(runtime); - /* still create the pending, because we need it to callback */ - } - log_info("testbound: created fake pending"); - /* add to list */ - pend->next = runtime->pending_list; - runtime->pending_list = pend; - return (struct pending*)pend; -} - -struct waiting_tcp* -pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet, - int timeout, comm_point_callback_type* callback, void* callback_arg) -{ - struct replay_runtime* runtime = (struct replay_runtime*) - sq->outnet->base; - struct fake_pending* pend = (struct fake_pending*)calloc(1, - sizeof(struct fake_pending)); - log_assert(pend); - pend->buffer = sldns_buffer_new(sldns_buffer_capacity(packet)); - log_assert(pend->buffer); - sldns_buffer_write(pend->buffer, sldns_buffer_begin(packet), - sldns_buffer_limit(packet)); - sldns_buffer_flip(pend->buffer); - memcpy(&pend->addr, &sq->addr, sq->addrlen); - pend->addrlen = sq->addrlen; - pend->callback = callback; - pend->cb_arg = callback_arg; - pend->timeout = timeout; - pend->transport = transport_tcp; - pend->pkt = NULL; - pend->zone = NULL; - pend->runtime = runtime; - pend->serviced = 0; - pend->pkt_len = sldns_buffer_limit(packet); - pend->pkt = memdup(sldns_buffer_begin(packet), pend->pkt_len); - if(!pend->pkt) fatal_exit("out of memory"); - log_pkt("pending tcp pkt: ", pend->pkt, pend->pkt_len); - - /* see if it matches the current moment */ - if(runtime->now && runtime->now->evt_type == repevt_back_query && - (runtime->now->addrlen == 0 || sockaddr_cmp( - &runtime->now->addr, runtime->now->addrlen, - &pend->addr, pend->addrlen) == 0) && - find_match(runtime->now->match, pend->pkt, pend->pkt_len, - pend->transport)) { - log_info("testbound: matched pending to event. " - "advance time between events."); - log_info("testbound: do STEP %d %s", runtime->now->time_step, - repevt_string(runtime->now->evt_type)); - advance_moment(runtime); - /* still create the pending, because we need it to callback */ - } - log_info("testbound: created fake pending"); - /* add to list */ - pend->next = runtime->pending_list; - runtime->pending_list = pend; - return (struct waiting_tcp*)pend; -} - -struct serviced_query* outnet_serviced_query(struct outside_network* outnet, - struct query_info* qinfo, uint16_t flags, int dnssec, - int ATTR_UNUSED(want_dnssec), int ATTR_UNUSED(nocaps), - int ATTR_UNUSED(tcp_upstream), int ATTR_UNUSED(ssl_upstream), - struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, struct module_qstate* qstate, - comm_point_callback_type* callback, void* callback_arg, - sldns_buffer* ATTR_UNUSED(buff), struct module_env* ATTR_UNUSED(env)) -{ - struct replay_runtime* runtime = (struct replay_runtime*)outnet->base; - struct fake_pending* pend = (struct fake_pending*)calloc(1, - sizeof(struct fake_pending)); - char z[256]; - log_assert(pend); - log_nametypeclass(VERB_OPS, "pending serviced query", - qinfo->qname, qinfo->qtype, qinfo->qclass); - dname_str(zone, z); - verbose(VERB_OPS, "pending serviced query zone %s flags%s%s%s%s", - z, (flags&BIT_RD)?" RD":"", (flags&BIT_CD)?" CD":"", - (flags&~(BIT_RD|BIT_CD))?" MORE":"", (dnssec)?" DO":""); - - /* create packet with EDNS */ - pend->buffer = sldns_buffer_new(512); - log_assert(pend->buffer); - sldns_buffer_write_u16(pend->buffer, 0); /* id */ - sldns_buffer_write_u16(pend->buffer, flags); - sldns_buffer_write_u16(pend->buffer, 1); /* qdcount */ - sldns_buffer_write_u16(pend->buffer, 0); /* ancount */ - sldns_buffer_write_u16(pend->buffer, 0); /* nscount */ - sldns_buffer_write_u16(pend->buffer, 0); /* arcount */ - sldns_buffer_write(pend->buffer, qinfo->qname, qinfo->qname_len); - sldns_buffer_write_u16(pend->buffer, qinfo->qtype); - sldns_buffer_write_u16(pend->buffer, qinfo->qclass); - sldns_buffer_flip(pend->buffer); - if(1) { - struct edns_data edns; - if(!inplace_cb_query_call(env, qinfo, flags, addr, addrlen, - zone, zonelen, qstate, qstate->region)) { - free(pend); - return NULL; - } - /* add edns */ - edns.edns_present = 1; - edns.ext_rcode = 0; - edns.edns_version = EDNS_ADVERTISED_VERSION; - edns.udp_size = EDNS_ADVERTISED_SIZE; - edns.bits = 0; - edns.opt_list = qstate->edns_opts_back_out; - if(dnssec) - edns.bits = EDNS_DO; - attach_edns_record(pend->buffer, &edns); - } - memcpy(&pend->addr, addr, addrlen); - pend->addrlen = addrlen; - pend->zone = memdup(zone, zonelen); - pend->zonelen = zonelen; - pend->qtype = (int)qinfo->qtype; - log_assert(pend->zone); - pend->callback = callback; - pend->cb_arg = callback_arg; - pend->timeout = UDP_AUTH_QUERY_TIMEOUT; - pend->transport = transport_udp; /* pretend UDP */ - pend->pkt = NULL; - pend->runtime = runtime; - pend->serviced = 1; - pend->pkt_len = sldns_buffer_limit(pend->buffer); - pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len); - if(!pend->pkt) fatal_exit("out of memory"); - /*log_pkt("pending serviced query: ", pend->pkt, pend->pkt_len);*/ - - /* see if it matches the current moment */ - if(runtime->now && runtime->now->evt_type == repevt_back_query && - (runtime->now->addrlen == 0 || sockaddr_cmp( - &runtime->now->addr, runtime->now->addrlen, - &pend->addr, pend->addrlen) == 0) && - find_match(runtime->now->match, pend->pkt, pend->pkt_len, - pend->transport)) { - log_info("testbound: matched pending to event. " - "advance time between events."); - log_info("testbound: do STEP %d %s", runtime->now->time_step, - repevt_string(runtime->now->evt_type)); - advance_moment(runtime); - /* still create the pending, because we need it to callback */ - } - log_info("testbound: created fake pending"); - /* add to list */ - pend->next = runtime->pending_list; - runtime->pending_list = pend; - return (struct serviced_query*)pend; -} - -void outnet_serviced_query_stop(struct serviced_query* sq, void* cb_arg) -{ - struct fake_pending* pend = (struct fake_pending*)sq; - struct replay_runtime* runtime = pend->runtime; - /* delete from the list */ - struct fake_pending* p = runtime->pending_list, *prev=NULL; - while(p) { - if(p == pend) { - log_assert(p->cb_arg == cb_arg); - (void)cb_arg; - log_info("serviced pending delete"); - if(prev) - prev->next = p->next; - else runtime->pending_list = p->next; - sldns_buffer_free(p->buffer); - free(p->pkt); - free(p->zone); - free(p); - return; - } - prev = p; - p = p->next; - } - log_info("double delete of pending serviced query"); -} - -struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg), - int* ATTR_UNUSED(reuseport)) -{ - return calloc(1, 1); -} - -void listening_ports_free(struct listen_port* list) -{ - free(list); -} - -struct comm_point* comm_point_create_local(struct comm_base* ATTR_UNUSED(base), - int ATTR_UNUSED(fd), size_t ATTR_UNUSED(bufsize), - comm_point_callback_type* ATTR_UNUSED(callback), - void* ATTR_UNUSED(callback_arg)) -{ - return calloc(1, 1); -} - -struct comm_point* comm_point_create_raw(struct comm_base* ATTR_UNUSED(base), - int ATTR_UNUSED(fd), int ATTR_UNUSED(writing), - comm_point_callback_type* ATTR_UNUSED(callback), - void* ATTR_UNUSED(callback_arg)) -{ - /* no pipe comm possible */ - return calloc(1, 1); -} - -void comm_point_start_listening(struct comm_point* ATTR_UNUSED(c), - int ATTR_UNUSED(newfd), int ATTR_UNUSED(sec)) -{ - /* no bg write pipe comm possible */ -} - -void comm_point_stop_listening(struct comm_point* ATTR_UNUSED(c)) -{ - /* no bg write pipe comm possible */ -} - -/* only cmd com _local gets deleted */ -void comm_point_delete(struct comm_point* c) -{ - free(c); -} - -size_t listen_get_mem(struct listen_dnsport* ATTR_UNUSED(listen)) -{ - return 0; -} - -size_t outnet_get_mem(struct outside_network* ATTR_UNUSED(outnet)) -{ - return 0; -} - -size_t comm_point_get_mem(struct comm_point* ATTR_UNUSED(c)) -{ - return 0; -} - -size_t serviced_get_mem(struct serviced_query* ATTR_UNUSED(c)) -{ - return 0; -} - -/* fake for fptr wlist */ -int outnet_udp_cb(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 outnet_tcp_cb(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; -} - -void pending_udp_timer_cb(void *ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void pending_udp_timer_delay_cb(void *ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void outnet_tcptimer(void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void comm_point_udp_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event), - void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void comm_point_udp_ancil_callback(int ATTR_UNUSED(fd), - short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void comm_point_tcp_accept_callback(int ATTR_UNUSED(fd), - short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void comm_point_tcp_handle_callback(int ATTR_UNUSED(fd), - short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void comm_timer_callback(int ATTR_UNUSED(fd), - short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void comm_signal_callback(int ATTR_UNUSED(fd), - short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void comm_point_local_handle_callback(int ATTR_UNUSED(fd), - short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void comm_point_raw_handle_callback(int ATTR_UNUSED(fd), - short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void comm_base_handle_slow_accept(int ATTR_UNUSED(fd), - short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -int serviced_udp_callback(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 serviced_tcp_callback(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 pending_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) -{ - log_assert(0); - return 0; -} - -int serviced_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) -{ - log_assert(0); - return 0; -} - -/* timers in testbound for autotrust. statistics tested in tpkg. */ -struct comm_timer* comm_timer_create(struct comm_base* base, - void (*cb)(void*), void* cb_arg) -{ - struct replay_runtime* runtime = (struct replay_runtime*)base; - struct fake_timer* t = (struct fake_timer*)calloc(1, sizeof(*t)); - t->cb = cb; - t->cb_arg = cb_arg; - fptr_ok(fptr_whitelist_comm_timer(t->cb)); /* check in advance */ - t->runtime = runtime; - t->next = runtime->timer_list; - runtime->timer_list = t; - return (struct comm_timer*)t; -} - -void comm_timer_disable(struct comm_timer* timer) -{ - struct fake_timer* t = (struct fake_timer*)timer; - log_info("fake timer disabled"); - t->enabled = 0; -} - -void comm_timer_set(struct comm_timer* timer, struct timeval* tv) -{ - struct fake_timer* t = (struct fake_timer*)timer; - t->enabled = 1; - t->tv = *tv; - log_info("fake timer set %d.%6.6d", - (int)t->tv.tv_sec, (int)t->tv.tv_usec); - timeval_add(&t->tv, &t->runtime->now_tv); -} - -void comm_timer_delete(struct comm_timer* timer) -{ - struct fake_timer* t = (struct fake_timer*)timer; - struct fake_timer** pp, *p; - if(!t) return; - - /* remove from linked list */ - pp = &t->runtime->timer_list; - p = t->runtime->timer_list; - while(p) { - if(p == t) { - /* snip from list */ - *pp = p->next; - break; - } - pp = &p->next; - p = p->next; - } - - free(timer); -} - -void comm_base_set_slow_accept_handlers(struct comm_base* ATTR_UNUSED(b), - void (*stop_acc)(void*), void (*start_acc)(void*), - void* ATTR_UNUSED(arg)) -{ - /* ignore this */ - (void)stop_acc; - (void)start_acc; -} - -struct ub_event_base* comm_base_internal(struct comm_base* ATTR_UNUSED(b)) -{ - /* no pipe comm possible in testbound */ - return NULL; -} - -void daemon_remote_exec(struct worker* ATTR_UNUSED(worker)) -{ -} - -void listen_start_accept(struct listen_dnsport* ATTR_UNUSED(listen)) -{ -} - -void listen_stop_accept(struct listen_dnsport* ATTR_UNUSED(listen)) -{ -} - -void daemon_remote_start_accept(struct daemon_remote* ATTR_UNUSED(rc)) -{ -} - -void daemon_remote_stop_accept(struct daemon_remote* ATTR_UNUSED(rc)) -{ -} - -/*********** End of Dummy routines ***********/ diff --git a/external/unbound/testcode/fake_event.h b/external/unbound/testcode/fake_event.h deleted file mode 100644 index 97ebb41cb..000000000 --- a/external/unbound/testcode/fake_event.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * testcode/fake_event.h - fake event handling that replays existing scenario. - * - * 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 - * Event service that replays a scenario. - * This implements the same exported symbols as the files: - * util/netevent.c - * services/listen_dnsport.c - * services/outside_network.c - * But these do not actually access the network or events, instead - * the scenario is played. - */ - -#ifndef TESTCODE_FAKE_EVENT_H -#define TESTCODE_FAKE_EVENT_H -struct replay_scenario; - -/** - * Initialise fake event services. - * - * The fake event services will automatically start when the main program - * calls netevent.h functions, such as comm_base_dispatch(). - * - * @param scen: Set the scenario to use for upcoming event handling. - */ -void fake_event_init(struct replay_scenario* scen); - -/** - * Deinit fake event services. - */ -void fake_event_cleanup(void); - -/** - * Get filename to store temporary config stuff. The pid is added. in /tmp. - * @param adj: adjective, like "_cfg_", "_auto_" - * @param id: identifier, like "example.com". - * @param buf: where to store. - * @param len: length of buf. - */ -void fake_temp_file(const char* adj, const char* id, char* buf, size_t len); - -#endif /* TESTCODE_FAKE_EVENT_H */ diff --git a/external/unbound/testcode/lock_verify.c b/external/unbound/testcode/lock_verify.c deleted file mode 100644 index 666a7029d..000000000 --- a/external/unbound/testcode/lock_verify.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * testcode/lock_verify.c - verifier program for lock traces, checks order. - * - * 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 checks the lock traces generated by checklock.c. - * Checks if locks are consistently locked in the same order. - * If not, this can lead to deadlock if threads execute the different - * ordering at the same time. - * - */ - -#include "config.h" -#ifdef HAVE_TIME_H -#include <time.h> -#endif -#include "util/log.h" -#include "util/rbtree.h" -#include "util/locks.h" -#include "util/fptr_wlist.h" - -/* --- data structures --- */ -struct lock_ref; - -/** keep track of lock id in lock-verify application - * Also defined in smallapp/worker_cb.c for fptr_wlist encapsulation - * breakage (the security tests break encapsulation for this test app) */ -struct order_id { - /** the thread id that created it */ - int thr; - /** the instance number of creation */ - int instance; -}; - -/** a lock */ -struct order_lock { - /** rbnode in all tree */ - rbnode_type node; - /** lock id */ - struct order_id id; - /** the creation file */ - char* create_file; - /** creation line */ - int create_line; - /** set of all locks that are smaller than this one (locked earlier) */ - rbtree_type* smaller; - /** during depthfirstsearch, this is a linked list of the stack - * of locks. points to the next lock bigger than this one. */ - struct lock_ref* dfs_next; - /** if lock has been visited (all smaller locks have been compared to - * this lock), only need to compare this with all unvisited(bigger) - * locks */ - int visited; -}; - -/** reference to a lock in a rbtree set */ -struct lock_ref { - /** rbnode, key is an order_id ptr */ - rbnode_type node; - /** the lock referenced */ - struct order_lock* lock; - /** why is this ref */ - char* file; - /** line number */ - int line; -}; - -/** count of errors detected */ -static int errors_detected = 0; -/** verbose? */ -static int verb = 0; - -/** print program usage help */ -static void -usage(void) -{ - printf("lock_verify <trace files>\n"); -} - -/** read header entry. - * @param in: file to read header of. - * @return: False if it does not belong to the rest. */ -static int -read_header(FILE* in) -{ - time_t t; - pid_t p; - int thrno; - static int have_values = 0; - static time_t the_time; - static pid_t the_pid; - static int threads[256]; - - if(fread(&t, sizeof(t), 1, in) != 1 || - fread(&thrno, sizeof(thrno), 1, in) != 1 || - fread(&p, sizeof(p), 1, in) != 1) { - fatal_exit("fread failed"); - } - /* check these values are sorta OK */ - if(!have_values) { - the_time = t; - the_pid = p; - memset(threads, 0, 256*sizeof(int)); - if(thrno >= 256) { - fatal_exit("Thread number too big. %d", thrno); - } - threads[thrno] = 1; - have_values = 1; - printf(" trace %d from pid %u on %s", thrno, - (unsigned)p, ctime(&t)); - } else { - if(the_pid != p) { - printf(" has pid %u, not %u. Skipped.\n", - (unsigned)p, (unsigned)the_pid); - return 0; - } - if(threads[thrno]) - fatal_exit("same threadno in two files"); - threads[thrno] = 1; - if( abs((int)(the_time - t)) > 3600) - fatal_exit("input files from different times: %u %u", - (unsigned)the_time, (unsigned)t); - printf(" trace of thread %u:%d\n", (unsigned)p, thrno); - } - return 1; -} - -/** max length of strings: filenames and function names. */ -#define STRMAX 1024 -/** read a string from file, false on error */ -static int readup_str(char** str, FILE* in) -{ - char buf[STRMAX]; - int len = 0; - int c; - /* ends in zero */ - while( (c = fgetc(in)) != 0) { - if(c == EOF) - fatal_exit("eof in readstr, file too short"); - buf[len++] = c; - if(len == STRMAX) { - fatal_exit("string too long, bad file format"); - } - } - buf[len] = 0; - *str = strdup(buf); - return 1; -} - -/** read creation entry */ -static void read_create(rbtree_type* all, FILE* in) -{ - struct order_lock* o = calloc(1, sizeof(struct order_lock)); - if(!o) fatal_exit("malloc failure"); - if(fread(&o->id.thr, sizeof(int), 1, in) != 1 || - fread(&o->id.instance, sizeof(int), 1, in) != 1 || - !readup_str(&o->create_file, in) || - fread(&o->create_line, sizeof(int), 1, in) != 1) - fatal_exit("fread failed"); - o->smaller = rbtree_create(order_lock_cmp); - o->node.key = &o->id; - if(!rbtree_insert(all, &o->node)) { - /* already inserted */ - struct order_lock* a = (struct order_lock*)rbtree_search(all, - &o->id); - log_assert(a); - a->create_file = o->create_file; - a->create_line = o->create_line; - free(o->smaller); - free(o); - o = a; - } - if(verb) printf("read create %u %u %s %d\n", - (unsigned)o->id.thr, (unsigned)o->id.instance, - o->create_file, o->create_line); -} - -/** insert lock entry (empty) into list */ -static struct order_lock* -insert_lock(rbtree_type* all, struct order_id* id) -{ - struct order_lock* o = calloc(1, sizeof(struct order_lock)); - if(!o) fatal_exit("malloc failure"); - o->smaller = rbtree_create(order_lock_cmp); - o->id = *id; - o->node.key = &o->id; - if(!rbtree_insert(all, &o->node)) - fatal_exit("insert fail should not happen"); - return o; -} - -/** read lock entry */ -static void read_lock(rbtree_type* all, FILE* in, int val) -{ - struct order_id prev_id, now_id; - struct lock_ref* ref; - struct order_lock* prev, *now; - ref = (struct lock_ref*)calloc(1, sizeof(struct lock_ref)); - if(!ref) fatal_exit("malloc failure"); - prev_id.thr = val; - if(fread(&prev_id.instance, sizeof(int), 1, in) != 1 || - fread(&now_id.thr, sizeof(int), 1, in) != 1 || - fread(&now_id.instance, sizeof(int), 1, in) != 1 || - !readup_str(&ref->file, in) || - fread(&ref->line, sizeof(int), 1, in) != 1) - fatal_exit("fread failed"); - if(verb) printf("read lock %u %u %u %u %s %d\n", - (unsigned)prev_id.thr, (unsigned)prev_id.instance, - (unsigned)now_id.thr, (unsigned)now_id.instance, - ref->file, ref->line); - /* find the two locks involved */ - prev = (struct order_lock*)rbtree_search(all, &prev_id); - now = (struct order_lock*)rbtree_search(all, &now_id); - /* if not there - insert 'em */ - if(!prev) prev = insert_lock(all, &prev_id); - if(!now) now = insert_lock(all, &now_id); - ref->lock = prev; - ref->node.key = &prev->id; - if(!rbtree_insert(now->smaller, &ref->node)) { - free(ref->file); - free(ref); - } -} - -/** read input file */ -static void readinput(rbtree_type* all, char* file) -{ - FILE *in = fopen(file, "r"); - int fst; - if(!in) { - perror(file); - exit(1); - } - printf("file %s", file); - if(!read_header(in)) { - fclose(in); - return; - } - while(fread(&fst, sizeof(fst), 1, in) == 1) { - if(fst == -1) - read_create(all, in); - else read_lock(all, in, fst); - } - fclose(in); -} - -/** print cycle message */ -static void found_cycle(struct lock_ref* visit, int level) -{ - struct lock_ref* p; - int i = 0; - errors_detected++; - printf("Found inconsistent locking order of length %d\n", level); - printf("for lock %d %d created %s %d\n", - visit->lock->id.thr, visit->lock->id.instance, - visit->lock->create_file, visit->lock->create_line); - printf("sequence is:\n"); - p = visit; - while(p) { - struct order_lock* next = - p->lock->dfs_next?p->lock->dfs_next->lock:visit->lock; - printf("[%d] is locked at line %s %d before lock %d %d\n", - i, p->file, p->line, next->id.thr, next->id.instance); - printf("[%d] lock %d %d is created at %s %d\n", - i, next->id.thr, next->id.instance, - next->create_file, next->create_line); - i++; - p = p->lock->dfs_next; - if(p && p->lock == visit->lock) - break; - } -} - -/** Detect cycle by comparing visited now with all (unvisited) bigger nodes */ -static int detect_cycle(struct lock_ref* visit, struct lock_ref* from) -{ - struct lock_ref* p = from; - while(p) { - if(p->lock == visit->lock) - return 1; - p = p->lock->dfs_next; - } - return 0; -} - -/** recursive function to depth first search for cycles. - * @param visit: the lock visited at this step. - * its dfs_next pointer gives the visited lock up in recursion. - * same as lookfor at level 0. - * @param level: depth of recursion. 0 is start. - * @param from: search for matches from unvisited node upwards. - */ -static void search_cycle(struct lock_ref* visit, int level, - struct lock_ref* from) -{ - struct lock_ref* ref; - /* check for cycle */ - if(detect_cycle(visit, from) && level != 0) { - found_cycle(visit, level); - fatal_exit("found lock order cycle"); - } - /* recurse */ - if(!visit->lock->visited) - from = visit; - if(verb > 1) fprintf(stderr, "[%d] visit lock %u %u %s %d\n", level, - (unsigned)visit->lock->id.thr, - (unsigned)visit->lock->id.instance, - visit->lock->create_file, visit->lock->create_line); - RBTREE_FOR(ref, struct lock_ref*, visit->lock->smaller) { - ref->lock->dfs_next = visit; - search_cycle(ref, level+1, from); - } - visit->lock->visited = 1; -} - -/** Check ordering of one lock */ -static void check_order_lock(struct order_lock* lock) -{ - struct lock_ref start; - if(lock->visited) return; - - start.node.key = &lock->id; - start.lock = lock; - start.file = lock->create_file; - start.line = lock->create_line; - - if(!lock->create_file) - log_err("lock %u %u does not have create info", - (unsigned)lock->id.thr, (unsigned)lock->id.instance); - - /* depth first search to find cycle with this lock at head */ - lock->dfs_next = NULL; - search_cycle(&start, 0, &start); -} - -/** Check ordering of locks */ -static void check_order(rbtree_type* all_locks) -{ - /* check each lock */ - struct order_lock* lock; - int i=0; - RBTREE_FOR(lock, struct order_lock*, all_locks) { - if(verb) - printf("[%d/%d] Checking lock %d %d %s %d\n", - i, (int)all_locks->count, - lock->id.thr, lock->id.instance, - lock->create_file, lock->create_line); - else if (i % ((all_locks->count/75)<1?1:all_locks->count/75) - == 0) - fprintf(stderr, "."); - i++; - check_order_lock(lock); - } - fprintf(stderr, "\n"); -} - -/** main program to verify all traces passed */ -int -main(int argc, char* argv[]) -{ - rbtree_type* all_locks; - int i; - time_t starttime = time(NULL); -#ifdef USE_THREAD_DEBUG - /* do not overwrite the ublocktrace files with the ones generated - * by this program (i.e. when the log code creates a lock) */ - check_locking_order = 0; -#endif - if(argc <= 1) { - usage(); - return 1; - } - log_init(NULL, 0, NULL); - log_ident_set("lock-verify"); - /* init */ - all_locks = rbtree_create(order_lock_cmp); - errors_detected = 0; - - /* read the input files */ - for(i=1; i<argc; i++) { - readinput(all_locks, argv[i]); - } - - /* check ordering */ - check_order(all_locks); - - /* do not free a thing, OS will do it */ - printf("checked %d locks in %d seconds with %d errors.\n", - (int)all_locks->count, (int)(time(NULL)-starttime), - errors_detected); - if(errors_detected) return 1; - return 0; -} diff --git a/external/unbound/testcode/memstats.c b/external/unbound/testcode/memstats.c deleted file mode 100644 index dc29058ad..000000000 --- a/external/unbound/testcode/memstats.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * testcode/memstats.c - debug tool to show memory allocation statistics. - * - * 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 program reads a log file and prints the memory allocation summed - * up. - */ -#include "config.h" -#include "util/log.h" -#include "util/rbtree.h" -#include "util/locks.h" -#include "util/fptr_wlist.h" -#include <sys/stat.h> - -/** - * The allocation statistics block - */ -struct codeline { - /** rbtree node */ - rbnode_type node; - /** the name of the file:linenumber */ - char* codeline; - /** the name of the function */ - char* func; - /** number of bytes allocated */ - uint64_t alloc; - /** number of bytes freed */ - uint64_t free; - /** number allocations and frees */ - uint64_t calls; -}; - -/** print usage and exit */ -static void -usage(void) -{ - printf("usage: memstats <logfile>\n"); - printf("statistics are printed on stdout.\n"); - exit(1); -} - -/** match logfile line to see if it needs accounting processing */ -static int -match(char* line) -{ - /* f.e.: - * [1187340064] unbound[24604:0] info: ul/rb.c:81 r_create malloc(12) - * 0123456789 123456789 123456789 123456789 - * But now also: - * Sep 16 15:18:20 unbound[1:0] info: ul/nh.c:143 memdup malloc(11) - */ - if(strlen(line) < 32) /* up to 'info: ' */ - return 0; - if(!strstr(line, " info: ")) - return 0; - if(strstr(line, "info: stat ")) - return 0; /* skip the hex dumps */ - if(strstr(line+30, "malloc(")) - return 1; - else if(strstr(line+30, "calloc(")) - return 1; - /* skip reallocs */ - return 0; -} - -/** find or alloc codeline in tree */ -static struct codeline* -get_codeline(rbtree_type* tree, char* key, char* func) -{ - struct codeline* cl = (struct codeline*)rbtree_search(tree, key); - if(!cl) { - cl = calloc(1, sizeof(*cl)); - if(!cl) return 0; - cl->codeline = strdup(key); - if(!cl->codeline) return 0; - cl->func = strdup(func); - if(!cl->func) return 0; - cl->alloc = 0; - cl->node.key = cl->codeline; - (void)rbtree_insert(tree, &cl->node); - } - return cl; -} - -/** read up the malloc stats */ -static void -read_malloc_stat(char* line, rbtree_type* tree) -{ - char codeline[10240]; - char name[10240]; - int skip = 0; - long num = 0; - struct codeline* cl = 0; - line = strstr(line, "info: ")+6; - if(sscanf(line, "%s %s %n", codeline, name, &skip) != 2) { - printf("%s\n", line); - fatal_exit("unhandled malloc"); - } - if(sscanf(line+skip+7, "%ld", &num) != 1) { - printf("%s\n%s\n", line, line+skip+7); - fatal_exit("unhandled malloc"); - } - cl = get_codeline(tree, codeline, name); - if(!cl) - fatal_exit("alloc failure"); - cl->alloc += num; - cl->calls ++; -} - -/** read up the calloc stats */ -static void -read_calloc_stat(char* line, rbtree_type* tree) -{ - char codeline[10240]; - char name[10240]; - int skip = 0; - long num = 0, sz = 0; - struct codeline* cl = 0; - line = strstr(line, "info: ")+6; - if(sscanf(line, "%s %s %n", codeline, name, &skip) != 2) { - printf("%s\n", line); - fatal_exit("unhandled calloc"); - } - if(sscanf(line+skip+7, "%ld, %ld", &num, &sz) != 2) { - printf("%s\n%s\n", line, line+skip+7); - fatal_exit("unhandled calloc"); - } - - cl = get_codeline(tree, codeline, name); - if(!cl) - fatal_exit("alloc failure"); - cl->alloc += num*sz; - cl->calls ++; -} - -/** get size of file */ -static off_t -get_file_size(const char* fname) -{ - struct stat s; - if(stat(fname, &s) < 0) { - fatal_exit("could not stat %s: %s", fname, strerror(errno)); - } - return s.st_size; -} - -/** read the logfile */ -static void -readfile(rbtree_type* tree, const char* fname) -{ - off_t total = get_file_size(fname); - off_t done = (off_t)0; - int report = 0; - FILE* in = fopen(fname, "r"); - char buf[102400]; - if(!in) - fatal_exit("could not open %s: %s", fname, strerror(errno)); - printf("Reading %s of size " ARG_LL "d\n", fname, (long long)total); - while(fgets(buf, 102400, in)) { - buf[102400-1] = 0; - done += (off_t)strlen(buf); - /* progress count */ - if((int)(((double)done / (double)total)*100.) > report) { - report = (int)(((double)done / (double)total)*100.); - fprintf(stderr, " %d%%", report); - } - - if(!match(buf)) - continue; - else if(strstr(buf+30, "malloc(")) - read_malloc_stat(buf, tree); - else if(strstr(buf+30, "calloc(")) - read_calloc_stat(buf, tree); - else { - printf("%s\n", buf); - fatal_exit("unhandled input"); - } - } - fprintf(stderr, " done\n"); - fclose(in); -} - -/** print memory stats */ -static void -printstats(rbtree_type* tree) -{ - struct codeline* cl; - uint64_t total = 0, tcalls = 0; - RBTREE_FOR(cl, struct codeline*, tree) { - printf("%12lld / %8lld in %s %s\n", (long long)cl->alloc, - (long long)cl->calls, cl->codeline, cl->func); - total += cl->alloc; - tcalls += cl->calls; - } - printf("------------\n"); - printf("%12lld / %8lld total in %ld code lines\n", (long long)total, - (long long)tcalls, (long)tree->count); - printf("\n"); -} - -/** main program */ -int main(int argc, const char* argv[]) -{ - rbtree_type* tree = 0; - log_init(NULL, 0, 0); - if(argc != 2) { - usage(); - } - tree = rbtree_create(codeline_cmp); - if(!tree) - fatal_exit("alloc failure"); - readfile(tree, argv[1]); - printstats(tree); - return 0; -} diff --git a/external/unbound/testcode/mini_tpkg.sh b/external/unbound/testcode/mini_tpkg.sh deleted file mode 100755 index ebf27a7d4..000000000 --- a/external/unbound/testcode/mini_tpkg.sh +++ /dev/null @@ -1,128 +0,0 @@ -# tpkg that only exes the files. -args="../.." -if test "$1" = "-a"; then - args=$2 - shift - shift -fi - -if test "$1" = "clean"; then - echo "rm -f result.* .done* .tpkg.var.master .tpkg.var.test" - rm -f result.* .done* .tpkg.var.master .tpkg.var.test - exit 0 -fi -if test "$1" = "fake"; then - echo "minitpkg fake $2" - echo "fake" > .done-`basename $2 .tpkg` - exit 0 -fi -if test "$1" = "report" || test "$2" = "report"; then - echo "Minitpkg Report" - for result in *.tpkg; do - name=`basename $result .tpkg` - if test -f ".done-$name"; then - if test "$1" != "-q"; then - echo "** PASSED ** : $name" - fi - else - if test -f "result.$name"; then - echo "!! FAILED !! : $name" - else - echo ">> SKIPPED<< : $name" - fi - fi - done - exit 0 -fi - -if test "$1" != 'exe'; then - # usage - echo "mini tpkg. Reduced functionality for old shells." - echo " tpkg exe <file>" - echo " tpkg fake <file>" - echo " tpkg clean" - echo " tpkg [-q] report" - exit 1 -fi -shift - -# do not execute if the disk is too full -#DISKLIMIT=100000 -# This check is not portable (to Solaris 10). -#avail=`df . | tail -1 | awk '{print $4}'` -#if test "$avail" -lt "$DISKLIMIT"; then - #echo "minitpkg: The disk is too full! Only $avail." - #exit 1 -#fi - -name=`basename $1 .tpkg` -dir=$name.$$ -result=result.$name -done=.done-$name -success="no" -if test -x "`which bash`"; then - shell="bash" -else - shell="sh" -fi - -# check already done -if test -f .done-$name; then - echo "minitpkg .done-$name exists. skip test." - exit 0 -fi - -# Extract -echo "minitpkg extract $1 to $dir" -mkdir $dir -gzip -cd $name.tpkg | (cd $dir; tar xf -) -cd $dir -mv $name.dir/* . - -# EXE -echo "minitpkg exe $name" > $result -grep "Description:" $name.dsc >> $result 2>&1 -echo "DateRunStart: "`date "+%s" 2>/dev/null` >> $result -if test -f $name.pre; then - echo "minitpkg exe $name.pre" - echo "minitpkg exe $name.pre" >> $result - $shell $name.pre $args >> $result - if test $? -ne 0; then - echo "Warning: $name.pre did not exit successfully" - fi -fi -if test -f $name.test; then - echo "minitpkg exe $name.test" - echo "minitpkg exe $name.test" >> $result - $shell $name.test $args >>$result 2>&1 - if test $? -ne 0; then - echo "$name: FAILED" >> $result - echo "$name: FAILED" - success="no" - else - echo "$name: PASSED" >> $result - echo "$name: PASSED" > ../.done-$name - echo "$name: PASSED" - success="yes" - fi -fi -if test -f $name.post; then - echo "minitpkg exe $name.post" - echo "minitpkg exe $name.post" >> $result - $shell $name.post $args >> $result - if test $? -ne 0; then - echo "Warning: $name.post did not exit successfully" - fi -fi -echo "DateRunEnd: "`date "+%s" 2>/dev/null` >> $result - -mv $result .. -cd .. -rm -rf $dir -# compat for windows where deletion may not succeed initially (files locked -# by processes that still have to exit). -if test $? -eq 1; then - echo "minitpkg waiting for processes to terminate" - sleep 2 # some time to exit, and try again - rm -rf $dir -fi diff --git a/external/unbound/testcode/perf.c b/external/unbound/testcode/perf.c deleted file mode 100644 index d11357c4a..000000000 --- a/external/unbound/testcode/perf.c +++ /dev/null @@ -1,654 +0,0 @@ -/* - * testcode/perf.c - debug program to estimate name server performance. - * - * 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 program estimates DNS name server performance. - */ - -#include "config.h" -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#include <signal.h> -#include "util/log.h" -#include "util/locks.h" -#include "util/net_help.h" -#include "util/data/msgencode.h" -#include "util/data/msgreply.h" -#include "util/data/msgparse.h" -#include "sldns/sbuffer.h" -#include "sldns/wire2str.h" -#include "sldns/str2wire.h" -#include <sys/time.h> - -/** usage information for perf */ -static void usage(char* nm) -{ - printf("usage: %s [options] server\n", nm); - printf("server: ip address of server, IP4 or IP6.\n"); - printf(" If not on port %d add @port.\n", UNBOUND_DNS_PORT); - printf("-d sec duration of test in whole seconds (0: wait for ^C)\n"); - printf("-a str query to ask, interpreted as a line from qfile\n"); - printf("-f fnm query list to read from file\n"); - printf(" every line has format: qname qclass qtype [+-]{E}\n"); - printf(" where + means RD set, E means EDNS enabled\n"); - printf("-q quiet mode, print only final qps\n"); - exit(1); -} - -struct perfinfo; -struct perfio; - -/** Global info for perf */ -struct perfinfo { - /** need to exit */ - volatile int exit; - /** all purpose buffer (for UDP send and receive) */ - sldns_buffer* buf; - - /** destination */ - struct sockaddr_storage dest; - /** length of dest socket addr */ - socklen_t destlen; - - /** when did this time slice start */ - struct timeval since; - /** number of queries received in that time */ - size_t numrecv; - /** number of queries sent out in that time */ - size_t numsent; - - /** duration of test in seconds */ - int duration; - /** quiet mode? */ - int quiet; - - /** when did the total test start */ - struct timeval start; - /** total number recvd */ - size_t total_recv; - /** total number sent */ - size_t total_sent; - /** numbers by rcode */ - size_t by_rcode[32]; - - /** number of I/O ports */ - size_t io_num; - /** I/O ports array */ - struct perfio* io; - /** max fd value in io ports */ - int maxfd; - /** readset */ - fd_set rset; - - /** size of querylist */ - size_t qlist_size; - /** allocated size of qlist array */ - size_t qlist_capacity; - /** list of query packets (data) */ - uint8_t** qlist_data; - /** list of query packets (length of a packet) */ - size_t* qlist_len; - /** index into querylist, for walking the list */ - size_t qlist_idx; -}; - -/** I/O port for perf */ -struct perfio { - /** id number */ - size_t id; - /** file descriptor of socket */ - int fd; - /** timeout value */ - struct timeval timeout; - /** ptr back to perfinfo */ - struct perfinfo* info; -}; - -/** number of msec between starting io ports */ -#define START_IO_INTERVAL 10 -/** number of msec timeout on io ports */ -#define IO_TIMEOUT 10 - -/** signal handler global info */ -static struct perfinfo* sig_info; - -/** signal handler for user quit */ -static RETSIGTYPE perf_sigh(int sig) -{ - log_assert(sig_info); - if(!sig_info->quiet) - printf("exit on signal %d\n", sig); - sig_info->exit = 1; -} - -/** timeval compare, t1 < t2 */ -static int -perf_tv_smaller(struct timeval* t1, struct timeval* t2) -{ -#ifndef S_SPLINT_S - if(t1->tv_sec < t2->tv_sec) - return 1; - if(t1->tv_sec == t2->tv_sec && - t1->tv_usec < t2->tv_usec) - return 1; -#endif - return 0; -} - -/** timeval add, t1 += t2 */ -static void -perf_tv_add(struct timeval* t1, struct timeval* t2) -{ -#ifndef S_SPLINT_S - t1->tv_sec += t2->tv_sec; - t1->tv_usec += t2->tv_usec; - while(t1->tv_usec > 1000000) { - t1->tv_usec -= 1000000; - t1->tv_sec++; - } -#endif -} - -/** timeval subtract, t1 -= t2 */ -static void -perf_tv_subtract(struct timeval* t1, struct timeval* t2) -{ -#ifndef S_SPLINT_S - t1->tv_sec -= t2->tv_sec; - if(t1->tv_usec >= t2->tv_usec) { - t1->tv_usec -= t2->tv_usec; - } else { - t1->tv_sec--; - t1->tv_usec = 1000000-(t2->tv_usec-t1->tv_usec); - } -#endif -} - - -/** setup perf test environment */ -static void -perfsetup(struct perfinfo* info) -{ - size_t i; - if(gettimeofday(&info->start, NULL) < 0) - fatal_exit("gettimeofday: %s", strerror(errno)); - sig_info = info; - if( signal(SIGINT, perf_sigh) == SIG_ERR || -#ifdef SIGQUIT - signal(SIGQUIT, perf_sigh) == SIG_ERR || -#endif -#ifdef SIGHUP - signal(SIGHUP, perf_sigh) == SIG_ERR || -#endif -#ifdef SIGBREAK - signal(SIGBREAK, perf_sigh) == SIG_ERR || -#endif - signal(SIGTERM, perf_sigh) == SIG_ERR) - fatal_exit("could not bind to signal"); - info->io = (struct perfio*)calloc(sizeof(struct perfio), info->io_num); - if(!info->io) fatal_exit("out of memory"); -#ifndef S_SPLINT_S - FD_ZERO(&info->rset); -#endif - info->since = info->start; - for(i=0; i<info->io_num; i++) { - info->io[i].id = i; - info->io[i].info = info; - info->io[i].fd = socket( - addr_is_ip6(&info->dest, info->destlen)? - AF_INET6:AF_INET, SOCK_DGRAM, 0); - if(info->io[i].fd == -1) { -#ifndef USE_WINSOCK - fatal_exit("socket: %s", strerror(errno)); -#else - fatal_exit("socket: %s", - wsa_strerror(WSAGetLastError())); -#endif - } - if(info->io[i].fd > info->maxfd) - info->maxfd = info->io[i].fd; -#ifndef S_SPLINT_S - FD_SET(FD_SET_T info->io[i].fd, &info->rset); - info->io[i].timeout.tv_usec = ((START_IO_INTERVAL*i)%1000) - *1000; - info->io[i].timeout.tv_sec = (START_IO_INTERVAL*i)/1000; - perf_tv_add(&info->io[i].timeout, &info->since); -#endif - } -} - -/** cleanup perf test environment */ -static void -perffree(struct perfinfo* info) -{ - size_t i; - if(!info) return; - if(info->io) { - for(i=0; i<info->io_num; i++) { -#ifndef USE_WINSOCK - close(info->io[i].fd); -#else - closesocket(info->io[i].fd); -#endif - } - free(info->io); - } - for(i=0; i<info->qlist_size; i++) - free(info->qlist_data[i]); - free(info->qlist_data); - free(info->qlist_len); -} - -/** send new query for io */ -static void -perfsend(struct perfinfo* info, size_t n, struct timeval* now) -{ - ssize_t r; - r = sendto(info->io[n].fd, (void*)info->qlist_data[info->qlist_idx], - info->qlist_len[info->qlist_idx], 0, - (struct sockaddr*)&info->dest, info->destlen); - /*log_hex("send", info->qlist_data[info->qlist_idx], - info->qlist_len[info->qlist_idx]);*/ - if(r == -1) { -#ifndef USE_WINSOCK - log_err("sendto: %s", strerror(errno)); -#else - log_err("sendto: %s", wsa_strerror(WSAGetLastError())); -#endif - } else if(r != (ssize_t)info->qlist_len[info->qlist_idx]) { - log_err("partial sendto"); - } - info->qlist_idx = (info->qlist_idx+1) % info->qlist_size; - info->numsent++; - - info->io[n].timeout.tv_sec = IO_TIMEOUT/1000; - info->io[n].timeout.tv_usec = (IO_TIMEOUT%1000)*1000; - perf_tv_add(&info->io[n].timeout, now); -} - -/** got reply for io */ -static void -perfreply(struct perfinfo* info, size_t n, struct timeval* now) -{ - ssize_t r; - r = recv(info->io[n].fd, (void*)sldns_buffer_begin(info->buf), - sldns_buffer_capacity(info->buf), 0); - if(r == -1) { -#ifndef USE_WINSOCK - log_err("recv: %s", strerror(errno)); -#else - log_err("recv: %s", wsa_strerror(WSAGetLastError())); -#endif - } else { - info->by_rcode[LDNS_RCODE_WIRE(sldns_buffer_begin( - info->buf))]++; - info->numrecv++; - } - /*sldns_buffer_set_limit(info->buf, r); - log_buf(0, "reply", info->buf);*/ - perfsend(info, n, now); -} - -/** got timeout for io */ -static void -perftimeout(struct perfinfo* info, size_t n, struct timeval* now) -{ - /* may not be a dropped packet, this is also used to start - * up the sending IOs */ - perfsend(info, n, now); -} - -/** print nice stats about qps */ -static void -stat_printout(struct perfinfo* info, struct timeval* now, - struct timeval* elapsed) -{ - /* calculate qps */ - double dt, qps = 0; -#ifndef S_SPLINT_S - dt = (double)(elapsed->tv_sec*1000000 + elapsed->tv_usec) / 1000000; -#endif - if(dt > 0.001) - qps = (double)(info->numrecv) / dt; - if(!info->quiet) - printf("qps: %g\n", qps); - /* setup next slice */ - info->since = *now; - info->total_sent += info->numsent; - info->total_recv += info->numrecv; - info->numrecv = 0; - info->numsent = 0; -} - -/** wait for new events for performance test */ -static void -perfselect(struct perfinfo* info) -{ - fd_set rset = info->rset; - struct timeval timeout, now; - int num; - size_t i; - if(gettimeofday(&now, NULL) < 0) - fatal_exit("gettimeofday: %s", strerror(errno)); - /* time to exit? */ - if(info->duration > 0) { - timeout = now; - perf_tv_subtract(&timeout, &info->start); - if((int)timeout.tv_sec >= info->duration) { - info->exit = 1; - return; - } - } - /* time for stats printout? */ - timeout = now; - perf_tv_subtract(&timeout, &info->since); - if(timeout.tv_sec > 0) { - stat_printout(info, &now, &timeout); - } - /* see what is closest port to timeout; or if there is a timeout */ - timeout = info->io[0].timeout; - for(i=0; i<info->io_num; i++) { - if(perf_tv_smaller(&info->io[i].timeout, &now)) { - perftimeout(info, i, &now); - return; - } - if(perf_tv_smaller(&info->io[i].timeout, &timeout)) { - timeout = info->io[i].timeout; - } - } - perf_tv_subtract(&timeout, &now); - - num = select(info->maxfd+1, &rset, NULL, NULL, &timeout); - if(num == -1) { - if(errno == EAGAIN || errno == EINTR) - return; - log_err("select: %s", strerror(errno)); - } - - /* handle new events */ - for(i=0; num && i<info->io_num; i++) { - if(FD_ISSET(info->io[i].fd, &rset)) { - perfreply(info, i, &now); - num--; - } - } -} - -/** show end stats */ -static void -perfendstats(struct perfinfo* info) -{ - double dt, qps; - struct timeval timeout, now; - int i, lost; - if(gettimeofday(&now, NULL) < 0) - fatal_exit("gettimeofday: %s", strerror(errno)); - timeout = now; - perf_tv_subtract(&timeout, &info->since); - stat_printout(info, &now, &timeout); - - timeout = now; - perf_tv_subtract(&timeout, &info->start); - dt = (double)(timeout.tv_sec*1000000 + timeout.tv_usec) / 1000000.0; - qps = (double)(info->total_recv) / dt; - lost = (int)(info->total_sent - info->total_recv) - (int)info->io_num; - if(!info->quiet) { - printf("overall time: %g sec\n", - (double)timeout.tv_sec + - (double)timeout.tv_usec/1000000.); - if(lost > 0) - printf("Packets lost: %d\n", (int)lost); - - for(i=0; i<(int)(sizeof(info->by_rcode)/sizeof(size_t)); i++) - { - if(info->by_rcode[i] > 0) { - char rc[16]; - sldns_wire2str_rcode_buf(i, rc, sizeof(rc)); - printf("%d(%5s): %u replies\n", - i, rc, (unsigned)info->by_rcode[i]); - } - } - } - printf("average qps: %g\n", qps); -} - -/** perform the performance test */ -static void -perfmain(struct perfinfo* info) -{ - perfsetup(info); - while(!info->exit) { - perfselect(info); - } - perfendstats(info); - perffree(info); -} - -/** parse a query line to a packet into buffer */ -static int -qlist_parse_line(sldns_buffer* buf, char* p) -{ - char nm[1024], cl[1024], tp[1024], fl[1024]; - int r; - int rec = 1, edns = 0; - struct query_info qinfo; - nm[0] = 0; cl[0] = 0; tp[0] = 0; fl[0] = 0; - r = sscanf(p, " %1023s %1023s %1023s %1023s", nm, cl, tp, fl); - if(r != 3 && r != 4) - return 0; - /*printf("nm='%s', cl='%s', tp='%s', fl='%s'\n", nm, cl, tp, fl);*/ - if(strcmp(tp, "IN") == 0 || strcmp(tp, "CH") == 0) { - qinfo.qtype = sldns_get_rr_type_by_name(cl); - qinfo.qclass = sldns_get_rr_class_by_name(tp); - } else { - qinfo.qtype = sldns_get_rr_type_by_name(tp); - qinfo.qclass = sldns_get_rr_class_by_name(cl); - } - if(fl[0] == '+') rec = 1; - else if(fl[0] == '-') rec = 0; - else if(fl[0] == 'E') edns = 1; - if((fl[0] == '+' || fl[0] == '-') && fl[1] == 'E') - edns = 1; - qinfo.qname = sldns_str2wire_dname(nm, &qinfo.qname_len); - if(!qinfo.qname) - return 0; - qinfo.local_alias = NULL; - qinfo_query_encode(buf, &qinfo); - sldns_buffer_write_u16_at(buf, 0, 0); /* zero ID */ - if(rec) LDNS_RD_SET(sldns_buffer_begin(buf)); - if(edns) { - struct edns_data ed; - memset(&ed, 0, sizeof(ed)); - ed.edns_present = 1; - ed.udp_size = EDNS_ADVERTISED_SIZE; - /* Set DO bit in all EDNS datagrams ... */ - ed.bits = EDNS_DO; - attach_edns_record(buf, &ed); - } - free(qinfo.qname); - return 1; -} - -/** grow query list capacity */ -static void -qlist_grow_capacity(struct perfinfo* info) -{ - size_t newcap = (size_t)((info->qlist_capacity==0)?16: - info->qlist_capacity*2); - uint8_t** d = (uint8_t**)calloc(sizeof(uint8_t*), newcap); - size_t* l = (size_t*)calloc(sizeof(size_t), newcap); - if(!d || !l) fatal_exit("out of memory"); - memcpy(d, info->qlist_data, sizeof(uint8_t*)* - info->qlist_capacity); - memcpy(l, info->qlist_len, sizeof(size_t)* - info->qlist_capacity); - free(info->qlist_data); - free(info->qlist_len); - info->qlist_data = d; - info->qlist_len = l; - info->qlist_capacity = newcap; -} - -/** setup query list in info */ -static void -qlist_add_line(struct perfinfo* info, char* line, int no) -{ - if(!qlist_parse_line(info->buf, line)) { - printf("error parsing query %d: %s\n", no, line); - exit(1); - } - sldns_buffer_write_u16_at(info->buf, 0, (uint16_t)info->qlist_size); - if(info->qlist_size + 1 > info->qlist_capacity) { - qlist_grow_capacity(info); - } - info->qlist_len[info->qlist_size] = sldns_buffer_limit(info->buf); - info->qlist_data[info->qlist_size] = memdup( - sldns_buffer_begin(info->buf), sldns_buffer_limit(info->buf)); - if(!info->qlist_data[info->qlist_size]) - fatal_exit("out of memory"); - info->qlist_size ++; -} - -/** setup query list in info */ -static void -qlist_read_file(struct perfinfo* info, char* fname) -{ - char buf[1024]; - char *p; - FILE* in = fopen(fname, "r"); - int lineno = 0; - if(!in) { - perror(fname); - exit(1); - } - while(fgets(buf, (int)sizeof(buf), in)) { - lineno++; - buf[sizeof(buf)-1] = 0; - p = buf; - while(*p == ' ' || *p == '\t') - p++; - if(p[0] == 0 || p[0] == '\n' || p[0] == ';' || p[0] == '#') - continue; - qlist_add_line(info, p, lineno); - } - printf("Read %s, got %u queries\n", fname, (unsigned)info->qlist_size); - fclose(in); -} - -/** getopt global, in case header files fail to declare it. */ -extern int optind; -/** getopt global, in case header files fail to declare it. */ -extern char* optarg; - -/** main program for perf */ -int main(int argc, char* argv[]) -{ - char* nm = argv[0]; - int c; - struct perfinfo info; -#ifdef USE_WINSOCK - int r; - WSADATA wsa_data; -#endif - - /* defaults */ - memset(&info, 0, sizeof(info)); - info.io_num = 16; - - log_init(NULL, 0, NULL); - log_ident_set("perf"); - checklock_start(); -#ifdef USE_WINSOCK - if((r = WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) - fatal_exit("WSAStartup failed: %s", wsa_strerror(r)); -#endif - - info.buf = sldns_buffer_new(65553); - if(!info.buf) fatal_exit("out of memory"); - - /* parse the options */ - while( (c=getopt(argc, argv, "d:ha:f:q")) != -1) { - switch(c) { - case 'q': - info.quiet = 1; - break; - case 'd': - if(atoi(optarg)==0 && strcmp(optarg, "0")!=0) { - printf("-d not a number %s", optarg); - return 1; - } - info.duration = atoi(optarg); - break; - case 'a': - qlist_add_line(&info, optarg, 0); - break; - case 'f': - qlist_read_file(&info, optarg); - break; - case '?': - case 'h': - default: - usage(nm); - } - } - argc -= optind; - argv += optind; - - if(argc != 1) { - printf("error: pass server IP address on commandline.\n"); - usage(nm); - } - if(!extstrtoaddr(argv[0], &info.dest, &info.destlen)) { - printf("Could not parse ip: %s\n", argv[0]); - return 1; - } - if(info.qlist_size == 0) { - printf("No queries to make, use -f or -a.\n"); - return 1; - } - - /* do the performance test */ - perfmain(&info); - - sldns_buffer_free(info.buf); -#ifdef USE_WINSOCK - WSACleanup(); -#endif - checklock_stop(); - return 0; -} diff --git a/external/unbound/testcode/petal.c b/external/unbound/testcode/petal.c deleted file mode 100644 index b30549365..000000000 --- a/external/unbound/testcode/petal.c +++ /dev/null @@ -1,669 +0,0 @@ -/* - * petal.c - https daemon that is small and beautiful. - * - * Copyright (c) 2010, 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 - * - * HTTP1.1/SSL server. - */ - -#include "config.h" -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#ifdef HAVE_OPENSSL_SSL_H -#include <openssl/ssl.h> -#endif -#ifdef HAVE_OPENSSL_ERR_H -#include <openssl/err.h> -#endif -#ifdef HAVE_OPENSSL_RAND_H -#include <openssl/rand.h> -#endif -#include <openssl/x509.h> -#include <openssl/pem.h> -#include <ctype.h> -#include <signal.h> -#if defined(UNBOUND_ALLOC_LITE) || defined(UNBOUND_ALLOC_STATS) -#ifdef malloc -#undef malloc -#endif -#ifdef free -#undef free -#endif -#endif /* alloc lite or alloc stats */ - -/** verbosity for this application */ -static int verb = 0; - -/** Give petal usage, and exit (1). */ -static void -usage(void) -{ - printf("Usage: petal [opts]\n"); - printf(" https daemon serves files from ./'host'/filename\n"); - printf(" (no hostname: from the 'default' directory)\n"); - printf("-a addr bind to this address, 127.0.0.1\n"); - printf("-p port port number, default 443\n"); - printf("-k keyfile SSL private key file (PEM), petal.key\n"); - printf("-c certfile SSL certificate file (PEM), petal.pem\n"); - printf("-v more verbose\n"); - printf("-h show this usage help\n"); - printf("Version %s\n", PACKAGE_VERSION); - printf("BSD licensed, see LICENSE in source package for details.\n"); - printf("Report bugs to %s\n", PACKAGE_BUGREPORT); - exit(1); -} - -/** fatal exit */ -static void print_exit(const char* str) {printf("error %s\n", str); exit(1);} -/** print errno */ -static void log_errno(const char* str) -{printf("error %s: %s\n", str, strerror(errno));} - -/** parse a text IP address into a sockaddr */ -static int -parse_ip_addr(char* str, int port, struct sockaddr_storage* ret, socklen_t* l) -{ - socklen_t len = 0; - struct sockaddr_storage* addr = NULL; - struct sockaddr_in6 a6; - struct sockaddr_in a; - uint16_t p = (uint16_t)port; - int fam = 0; - memset(&a6, 0, sizeof(a6)); - memset(&a, 0, sizeof(a)); - - if(inet_pton(AF_INET6, str, &a6.sin6_addr) > 0) { - /* it is an IPv6 */ - fam = AF_INET6; - a6.sin6_family = AF_INET6; - a6.sin6_port = (in_port_t)htons(p); - addr = (struct sockaddr_storage*)&a6; - len = (socklen_t)sizeof(struct sockaddr_in6); - } - if(inet_pton(AF_INET, str, &a.sin_addr) > 0) { - /* it is an IPv4 */ - fam = AF_INET; - a.sin_family = AF_INET; - a.sin_port = (in_port_t)htons(p); - addr = (struct sockaddr_storage*)&a; - len = (socklen_t)sizeof(struct sockaddr_in); - } - if(!len) print_exit("cannot parse addr"); - *l = len; - memmove(ret, addr, len); - return fam; -} - -/** close the fd */ -static void -fd_close(int fd) -{ -#ifndef USE_WINSOCK - close(fd); -#else - closesocket(fd); -#endif -} - -/** - * Read one line from SSL - * zero terminates. - * skips "\r\n" (but not copied to buf). - * @param ssl: the SSL connection to read from (blocking). - * @param buf: buffer to return line in. - * @param len: size of the buffer. - * @return 0 on error, 1 on success. - */ -static int -read_ssl_line(SSL* ssl, char* buf, size_t len) -{ - size_t n = 0; - int r; - int endnl = 0; - while(1) { - if(n >= len) { - if(verb) printf("line too long\n"); - return 0; - } - if((r = SSL_read(ssl, buf+n, 1)) <= 0) { - if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) { - /* EOF */ - break; - } - if(verb) printf("could not SSL_read\n"); - return 0; - } - if(endnl && buf[n] == '\n') { - break; - } else if(endnl) { - /* bad data */ - if(verb) printf("error: stray linefeeds\n"); - return 0; - } else if(buf[n] == '\r') { - /* skip \r, and also \n on the wire */ - endnl = 1; - continue; - } else if(buf[n] == '\n') { - /* skip the \n, we are done */ - break; - } else n++; - } - buf[n] = 0; - return 1; -} - -/** process one http header */ -static int -process_one_header(char* buf, char* file, size_t flen, char* host, size_t hlen, - int* vs) -{ - if(strncasecmp(buf, "GET ", 4) == 0) { - char* e = strstr(buf, " HTTP/1.1"); - if(!e) e = strstr(buf, " http/1.1"); - if(!e) { - e = strstr(buf, " HTTP/1.0"); - if(!e) e = strstr(buf, " http/1.0"); - if(!e) e = strrchr(buf, ' '); - if(!e) e = strrchr(buf, '\t'); - if(e) *vs = 10; - } - if(e) *e = 0; - if(strlen(buf) < 4) return 0; - (void)strlcpy(file, buf+4, flen); - } else if(strncasecmp(buf, "Host: ", 6) == 0) { - (void)strlcpy(host, buf+6, hlen); - } - return 1; -} - -/** read http headers and process them */ -static int -read_http_headers(SSL* ssl, char* file, size_t flen, char* host, size_t hlen, - int* vs) -{ - char buf[1024]; - file[0] = 0; - host[0] = 0; - while(read_ssl_line(ssl, buf, sizeof(buf))) { - if(verb>=2) printf("read: %s\n", buf); - if(buf[0] == 0) - return 1; - if(!process_one_header(buf, file, flen, host, hlen, vs)) - return 0; - } - return 0; -} - -/** setup SSL context */ -static SSL_CTX* -setup_ctx(char* key, char* cert) -{ - SSL_CTX* ctx = SSL_CTX_new(SSLv23_server_method()); - if(!ctx) print_exit("out of memory"); - (void)SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); - (void)SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3); - if(!SSL_CTX_use_certificate_chain_file(ctx, cert)) - print_exit("cannot read cert"); - if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) - print_exit("cannot read key"); - if(!SSL_CTX_check_private_key(ctx)) - print_exit("private key is not correct"); -#if HAVE_DECL_SSL_CTX_SET_ECDH_AUTO - if (!SSL_CTX_set_ecdh_auto(ctx,1)) - if(verb>=1) printf("failed to set_ecdh_auto, not enabling ECDHE\n"); -#elif defined(USE_ECDSA) - if(1) { - EC_KEY *ecdh = EC_KEY_new_by_curve_name (NID_X9_62_prime256v1); - if (!ecdh) { - if(verb>=1) printf("could not find p256, not enabling ECDHE\n"); - } else { - if (1 != SSL_CTX_set_tmp_ecdh (ctx, ecdh)) { - if(verb>=1) printf("Error in SSL_CTX_set_tmp_ecdh, not enabling ECDHE\n"); - } - EC_KEY_free(ecdh); - } - } -#endif - if(!SSL_CTX_load_verify_locations(ctx, cert, NULL)) - print_exit("cannot load cert verify locations"); - return ctx; -} - -/** setup listening TCP */ -static int -setup_fd(char* addr, int port) -{ - struct sockaddr_storage ad; - socklen_t len; - int fd; - int c = 1; - int fam = parse_ip_addr(addr, port, &ad, &len); - fd = socket(fam, SOCK_STREAM, 0); - if(fd == -1) { - log_errno("socket"); - return -1; - } - if(setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, - (void*)&c, (socklen_t) sizeof(int)) < 0) { - log_errno("setsockopt(SOL_SOCKET, SO_REUSEADDR)"); - } - if(bind(fd, (struct sockaddr*)&ad, len) == -1) { - log_errno("bind"); - fd_close(fd); - return -1; - } - if(listen(fd, 5) == -1) { - log_errno("listen"); - fd_close(fd); - return -1; - } - return fd; -} - -/** setup SSL connection to the client */ -static SSL* -setup_ssl(int s, SSL_CTX* ctx) -{ - SSL* ssl = SSL_new(ctx); - if(!ssl) return NULL; - SSL_set_accept_state(ssl); - (void)SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); - if(!SSL_set_fd(ssl, s)) { - SSL_free(ssl); - return NULL; - } - return ssl; -} - -/** check a file name for safety */ -static int -file_name_is_safe(char* s) -{ - size_t l = strlen(s); - if(s[0] != '/') - return 0; /* must start with / */ - if(strstr(s, "/../")) - return 0; /* no updirs in URL */ - if(l>=3 && s[l-1]=='.' && s[l-2]=='.' && s[l-3]=='/') - return 0; /* ends with /.. */ - return 1; -} - -/** adjust host and filename */ -static void -adjust_host_file(char* host, char* file) -{ - size_t i, len; - /* remove a port number if present */ - if(strrchr(host, ':')) - *strrchr(host, ':') = 0; - /* lowercase */ - len = strlen(host); - for(i=0; i<len; i++) - host[i] = tolower((unsigned char)host[i]); - len = strlen(file); - for(i=0; i<len; i++) - file[i] = tolower((unsigned char)file[i]); -} - -/** check a host name for safety */ -static int -host_name_is_safe(char* s) -{ - if(strchr(s, '/')) - return 0; - if(strcmp(s, "..") == 0) - return 0; - if(strcmp(s, ".") == 0) - return 0; - return 1; -} - -/** provide file in whole transfer */ -static void -provide_file_10(SSL* ssl, char* fname) -{ - char* buf, *at; - size_t len, avail, header_reserve=1024; - FILE* in = fopen(fname, -#ifndef USE_WINSOCK - "r" -#else - "rb" -#endif - ); - size_t r; - const char* rcode = "200 OK"; - if(!in) { - char hdr[1024]; - rcode = "404 File not found"; - snprintf(hdr, sizeof(hdr), "HTTP/1.1 %s\r\n\r\n", rcode); - r = strlen(hdr); - if(SSL_write(ssl, hdr, (int)r) <= 0) { - /* write failure */ - } - return; - } - fseek(in, 0, SEEK_END); - len = (size_t)ftell(in); - fseek(in, 0, SEEK_SET); - /* plus some space for the header */ - buf = (char*)malloc(len+header_reserve); - if(!buf) { - fclose(in); - return; - } - avail = len+header_reserve; - at = buf; - snprintf(at, avail, "HTTP/1.1 %s\r\n", rcode); - r = strlen(at); - at += r; - avail -= r; - snprintf(at, avail, "Server: petal/%s\r\n", PACKAGE_VERSION); - r = strlen(at); - at += r; - avail -= r; - snprintf(at, avail, "Content-Length: %u\r\n", (unsigned)len); - r = strlen(at); - at += r; - avail -= r; - snprintf(at, avail, "\r\n"); - r = strlen(at); - at += r; - avail -= r; - if(avail < len) { /* robust */ - free(buf); - fclose(in); - return; - } - if(fread(at, 1, len, in) != len) { - free(buf); - fclose(in); - return; - } - fclose(in); - at += len; - avail -= len; - if(SSL_write(ssl, buf, at-buf) <= 0) { - /* write failure */ - } - free(buf); -} - -/** provide file over SSL, chunked encoding */ -static void -provide_file_chunked(SSL* ssl, char* fname) -{ - char buf[16384]; - char* tmpbuf = NULL; - char* at = buf; - size_t avail = sizeof(buf); - size_t r; - FILE* in = fopen(fname, -#ifndef USE_WINSOCK - "r" -#else - "rb" -#endif - ); - const char* rcode = "200 OK"; - if(!in) { - rcode = "404 File not found"; - } - - /* print headers */ - snprintf(at, avail, "HTTP/1.1 %s\r\n", rcode); - r = strlen(at); - at += r; - avail -= r; - snprintf(at, avail, "Server: petal/%s\r\n", PACKAGE_VERSION); - r = strlen(at); - at += r; - avail -= r; - snprintf(at, avail, "Transfer-Encoding: chunked\r\n"); - r = strlen(at); - at += r; - avail -= r; - snprintf(at, avail, "Connection: close\r\n"); - r = strlen(at); - at += r; - avail -= r; - snprintf(at, avail, "\r\n"); - r = strlen(at); - at += r; - avail -= r; - if(avail < 16) { /* robust */ - if(in) fclose(in); - return; - } - - do { - size_t red; - free(tmpbuf); - tmpbuf = malloc(avail-16); - if(!tmpbuf) - break; - /* read chunk; space-16 for xxxxCRLF..CRLF0CRLFCRLF (3 spare)*/ - red = in?fread(tmpbuf, 1, avail-16, in):0; - /* prepare chunk */ - snprintf(at, avail, "%x\r\n", (unsigned)red); - r = strlen(at); - if(verb >= 3) - {printf("chunk len %x\n", (unsigned)red); fflush(stdout);} - at += r; - avail -= r; - if(red != 0) { - if(red > avail) break; /* robust */ - memmove(at, tmpbuf, red); - at += red; - avail -= red; - snprintf(at, avail, "\r\n"); - r = strlen(at); - at += r; - avail -= r; - } - if(in && feof(in) && red != 0) { - snprintf(at, avail, "0\r\n"); - r = strlen(at); - at += r; - avail -= r; - } - if(!in || feof(in)) { - snprintf(at, avail, "\r\n"); - r = strlen(at); - at += r; - avail -= r; - } - /* send chunk */ - if(SSL_write(ssl, buf, at-buf) <= 0) { - /* SSL error */ - break; - } - - /* setup for next chunk */ - at = buf; - avail = sizeof(buf); - } while(in && !feof(in) && !ferror(in)); - - free(tmpbuf); - if(in) fclose(in); -} - -/** provide service to the ssl descriptor */ -static void -service_ssl(SSL* ssl, struct sockaddr_storage* from, socklen_t falen) -{ - char file[1024]; - char host[1024]; - char combined[2048]; - int vs = 11; - if(!read_http_headers(ssl, file, sizeof(file), host, sizeof(host), - &vs)) - return; - adjust_host_file(host, file); - if(host[0] == 0 || !host_name_is_safe(host)) - (void)strlcpy(host, "default", sizeof(host)); - if(!file_name_is_safe(file)) { - return; - } - snprintf(combined, sizeof(combined), "%s%s", host, file); - if(verb) { - char out[100]; - void* a = &((struct sockaddr_in*)from)->sin_addr; - if(falen != (socklen_t)sizeof(struct sockaddr_in)) - a = &((struct sockaddr_in6*)from)->sin6_addr; - out[0]=0; - (void)inet_ntop((int)((struct sockaddr_in*)from)->sin_family, - a, out, (socklen_t)sizeof(out)); - printf("%s requests %s\n", out, combined); - fflush(stdout); - } - if(vs == 10) - provide_file_10(ssl, combined); - else provide_file_chunked(ssl, combined); -} - -/** provide ssl service */ -static void -do_service(char* addr, int port, char* key, char* cert) -{ - SSL_CTX* sslctx = setup_ctx(key, cert); - int fd = setup_fd(addr, port); - int go = 1; - if(fd == -1) print_exit("could not setup sockets"); - if(verb) {printf("petal start\n"); fflush(stdout);} - while(go) { - struct sockaddr_storage from; - socklen_t flen = (socklen_t)sizeof(from); - int s = accept(fd, (struct sockaddr*)&from, &flen); - if(verb) fflush(stdout); - if(s != -1) { - SSL* ssl = setup_ssl(s, sslctx); - if(verb) fflush(stdout); - if(ssl) { - service_ssl(ssl, &from, flen); - if(verb) fflush(stdout); - SSL_shutdown(ssl); - SSL_free(ssl); - } - fd_close(s); - } else if (verb >=2) log_errno("accept"); - if(verb) fflush(stdout); - } - /* if we get a kill signal, the process dies and the OS reaps us */ - if(verb) printf("petal end\n"); - fd_close(fd); - SSL_CTX_free(sslctx); -} - -/** getopt global, in case header files fail to declare it. */ -extern int optind; -/** getopt global, in case header files fail to declare it. */ -extern char* optarg; - -/** Main routine for petal */ -int main(int argc, char* argv[]) -{ - int c; - int port = 443; - char* addr = "127.0.0.1", *key = "petal.key", *cert = "petal.pem"; -#ifdef USE_WINSOCK - WSADATA wsa_data; - if((c=WSAStartup(MAKEWORD(2,2), &wsa_data)) != 0) - { printf("WSAStartup failed\n"); exit(1); } - atexit((void (*)(void))WSACleanup); -#endif - - /* parse the options */ - while( (c=getopt(argc, argv, "a:c:k:hp:v")) != -1) { - switch(c) { - case 'a': - addr = optarg; - break; - case 'c': - cert = optarg; - break; - case 'k': - key = optarg; - break; - case 'p': - port = atoi(optarg); - break; - case 'v': - verb++; - break; - case '?': - case 'h': - default: - usage(); - } - } - argc -= optind; - argv += optind; - if(argc != 0) - usage(); - -#ifdef SIGPIPE - (void)signal(SIGPIPE, SIG_IGN); -#endif -#ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS - ERR_load_crypto_strings(); -#endif - ERR_load_SSL_strings(); -#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) - OpenSSL_add_all_algorithms(); -#else - OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS - | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); -#endif -#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) - (void)SSL_library_init(); -#else - (void)OPENSSL_init_ssl(0, NULL); -#endif - - do_service(addr, port, key, cert); - -#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA - CRYPTO_cleanup_all_ex_data(); -#endif -#ifdef HAVE_ERR_FREE_STRINGS - ERR_free_strings(); -#endif - return 0; -} diff --git a/external/unbound/testcode/pktview.c b/external/unbound/testcode/pktview.c deleted file mode 100644 index 12e0d8edb..000000000 --- a/external/unbound/testcode/pktview.c +++ /dev/null @@ -1,202 +0,0 @@ -/* - * testcode/pktview.c - debug program to disassemble a DNS packet. - * - * 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 program shows a dns packet wire format. - */ - -#include "config.h" -#include "util/log.h" -#include "util/data/dname.h" -#include "util/data/msgparse.h" -#include "testcode/unitmain.h" -#include "testcode/readhex.h" -#include "sldns/sbuffer.h" -#include "sldns/parseutil.h" - -/** usage information for pktview */ -static void usage(char* argv[]) -{ - printf("usage: %s\n", argv[0]); - printf("present hex packet on stdin.\n"); - exit(1); -} - -/** read hex input */ -static void read_input(sldns_buffer* pkt, FILE* in) -{ - char buf[102400]; - char* np = buf; - while(fgets(np, (int)sizeof(buf) - (np-buf), in)) { - if(buf[0] == ';') /* comment */ - continue; - np = &np[strlen(np)]; - } - hex_to_buf(pkt, buf); -} - -/** analyze domain name in packet, possibly compressed */ -static void analyze_dname(sldns_buffer* pkt) -{ - size_t oldpos = sldns_buffer_position(pkt); - size_t len; - printf("[pos %d] dname: ", (int)oldpos); - dname_print(stdout, pkt, sldns_buffer_current(pkt)); - len = pkt_dname_len(pkt); - printf(" len=%d", (int)len); - if(sldns_buffer_position(pkt)-oldpos != len) - printf(" comprlen=%d\n", - (int)(sldns_buffer_position(pkt)-oldpos)); - else printf("\n"); -} - -/** analyze rdata in packet */ -static void analyze_rdata(sldns_buffer*pkt, const sldns_rr_descriptor* desc, - uint16_t rdlen) -{ - int rdf = 0; - int count = (int)desc->_dname_count; - size_t len, oldpos; - while(rdlen > 0 && count) { - switch(desc->_wireformat[rdf]) { - case LDNS_RDF_TYPE_DNAME: - oldpos = sldns_buffer_position(pkt); - analyze_dname(pkt); - rdlen -= 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]); - } - if(len) { - printf(" wf[%d]", (int)len); - sldns_buffer_skip(pkt, (ssize_t)len); - rdlen -= len; - } - rdf++; - } - if(rdlen) { - size_t i; - printf(" remain[%d]\n", (int)rdlen); - for(i=0; i<rdlen; i++) - printf(" %2.2X", (unsigned)sldns_buffer_current(pkt)[i]); - printf("\n"); - } - else printf("\n"); - sldns_buffer_skip(pkt, (ssize_t)rdlen); -} - -/** analyze rr in packet */ -static void analyze_rr(sldns_buffer* pkt, int q) -{ - uint16_t type, dclass, len; - uint32_t ttl; - analyze_dname(pkt); - type = sldns_buffer_read_u16(pkt); - dclass = sldns_buffer_read_u16(pkt); - printf("type %s(%d)", sldns_rr_descript(type)? - sldns_rr_descript(type)->_name: "??" , (int)type); - printf(" class %s(%d) ", sldns_lookup_by_id(sldns_rr_classes, - (int)dclass)?sldns_lookup_by_id(sldns_rr_classes, - (int)dclass)->name:"??", (int)dclass); - if(q) { - printf("\n"); - } else { - ttl = sldns_buffer_read_u32(pkt); - printf(" ttl %d (0x%x)", (int)ttl, (unsigned)ttl); - len = sldns_buffer_read_u16(pkt); - printf(" rdata len %d:\n", (int)len); - if(sldns_rr_descript(type)) - analyze_rdata(pkt, sldns_rr_descript(type), len); - else sldns_buffer_skip(pkt, (ssize_t)len); - } -} - -/** analyse pkt */ -static void analyze(sldns_buffer* pkt) -{ - uint16_t i, f, qd, an, ns, ar; - int rrnum = 0; - printf("packet length %d\n", (int)sldns_buffer_limit(pkt)); - if(sldns_buffer_limit(pkt) < 12) return; - - i = sldns_buffer_read_u16(pkt); - printf("id (hostorder): %d (0x%x)\n", (int)i, (unsigned)i); - f = sldns_buffer_read_u16(pkt); - printf("flags: 0x%x\n", (unsigned)f); - qd = sldns_buffer_read_u16(pkt); - printf("qdcount: %d\n", (int)qd); - an = sldns_buffer_read_u16(pkt); - printf("ancount: %d\n", (int)an); - ns = sldns_buffer_read_u16(pkt); - printf("nscount: %d\n", (int)ns); - ar = sldns_buffer_read_u16(pkt); - printf("arcount: %d\n", (int)ar); - - printf(";-- query section\n"); - while(sldns_buffer_remaining(pkt) > 0) { - if(rrnum == (int)qd) - printf(";-- answer section\n"); - if(rrnum == (int)qd+(int)an) - printf(";-- authority section\n"); - if(rrnum == (int)qd+(int)an+(int)ns) - printf(";-- additional section\n"); - printf("rr %d ", rrnum); - analyze_rr(pkt, rrnum < (int)qd); - rrnum++; - } -} - -/** main program for pktview */ -int main(int argc, char* argv[]) -{ - sldns_buffer* pkt = sldns_buffer_new(65553); - if(argc != 1) { - usage(argv); - } - if(!pkt) fatal_exit("out of memory"); - - read_input(pkt, stdin); - analyze(pkt); - - sldns_buffer_free(pkt); - return 0; -} diff --git a/external/unbound/testcode/readhex.c b/external/unbound/testcode/readhex.c deleted file mode 100644 index e871def0e..000000000 --- a/external/unbound/testcode/readhex.c +++ /dev/null @@ -1,85 +0,0 @@ -/* - * testcode/readhex.c - read hex 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 - * Declarations useful for the unit tests. - */ -#include "config.h" -#include <ctype.h> -#include "testcode/readhex.h" -#include "util/log.h" -#include "sldns/sbuffer.h" -#include "sldns/parseutil.h" - -/** skip whitespace */ -static void -skip_whites(const char** p) -{ - while(1) { - while(isspace((unsigned char)**p)) - (*p)++; - if(**p == ';') { - /* comment, skip until newline */ - while(**p && **p != '\n') - (*p)++; - if(**p == '\n') - (*p)++; - } else return; - } -} - -/* takes a hex string and puts into buffer */ -void hex_to_buf(sldns_buffer* pkt, const char* hex) -{ - const char* p = hex; - int val; - sldns_buffer_clear(pkt); - while(*p) { - skip_whites(&p); - if(sldns_buffer_position(pkt) == sldns_buffer_limit(pkt)) - fatal_exit("hex_to_buf: buffer too small"); - if(!isalnum((unsigned char)*p)) - break; - val = sldns_hexdigit_to_int(*p++) << 4; - skip_whites(&p); - log_assert(*p && isalnum((unsigned char)*p)); - val |= sldns_hexdigit_to_int(*p++); - sldns_buffer_write_u8(pkt, (uint8_t)val); - skip_whites(&p); - } - sldns_buffer_flip(pkt); -} - diff --git a/external/unbound/testcode/readhex.h b/external/unbound/testcode/readhex.h deleted file mode 100644 index be6424539..000000000 --- a/external/unbound/testcode/readhex.h +++ /dev/null @@ -1,52 +0,0 @@ -/* - * testcode/readhex.h - read hex 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 - * Declarations useful for the unit tests. - */ - -#ifndef TESTCODE_READHEX_H -#define TESTCODE_READHEX_H -struct sldns_buffer; - -/** - * Helper to convert hex string to packet buffer. - * @param pkt: buffer to put result in. - * @param hex: string of hex data. Spaces and ';...' comments are skipped. - */ -void hex_to_buf(struct sldns_buffer* pkt, const char* hex); - -#endif /* TESTCODE_READHEX_H */ diff --git a/external/unbound/testcode/replay.c b/external/unbound/testcode/replay.c deleted file mode 100644 index b45bde806..000000000 --- a/external/unbound/testcode/replay.c +++ /dev/null @@ -1,1034 +0,0 @@ -/* - * testcode/replay.c - store and use a replay of events for the DNS resolver. - * - * 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 - * Store and use a replay of events for the DNS resolver. - * Used to test known scenarios to get known outcomes. - */ - -#include "config.h" -/* for strtod prototype */ -#include <math.h> -#include <ctype.h> -#include <time.h> -#include "util/log.h" -#include "util/net_help.h" -#include "util/config_file.h" -#include "testcode/replay.h" -#include "testcode/testpkts.h" -#include "testcode/fake_event.h" -#include "sldns/str2wire.h" - -/** max length of lines in file */ -#define MAX_LINE_LEN 10240 - -/** - * Expand a macro - * @param store: value storage - * @param runtime: replay runtime for other stuff. - * @param text: the macro text, after the ${, Updated to after the } when - * done (successfully). - * @return expanded text, malloced. NULL on failure. - */ -static char* macro_expand(rbtree_type* store, - struct replay_runtime* runtime, char** text); - -/** 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 -} - -/** parse keyword in string. - * @param line: if found, the line is advanced to after the keyword. - * @param keyword: string. - * @return: true if found, false if not. - */ -static int -parse_keyword(char** line, const char* keyword) -{ - size_t len = (size_t)strlen(keyword); - if(strncmp(*line, keyword, len) == 0) { - *line += len; - return 1; - } - return 0; -} - -/** delete moment */ -static void -replay_moment_delete(struct replay_moment* mom) -{ - if(!mom) - return; - if(mom->match) { - delete_entry(mom->match); - } - free(mom->autotrust_id); - free(mom->string); - free(mom->variable); - config_delstrlist(mom->file_content); - free(mom); -} - -/** delete range */ -static void -replay_range_delete(struct replay_range* rng) -{ - if(!rng) - return; - delete_entry(rng->match); - free(rng); -} - -/** strip whitespace from end of string */ -static void -strip_end_white(char* p) -{ - size_t i; - for(i = strlen(p); i > 0; i--) { - if(isspace((unsigned char)p[i-1])) - p[i-1] = 0; - else return; - } -} - -/** - * Read a range from file. - * @param remain: Rest of line (after RANGE keyword). - * @param in: file to read from. - * @param name: name to print in errors. - * @param pstate: read state structure with - * with lineno : incremented as lines are read. - * ttl, origin, prev for readentry. - * @param line: line buffer. - * @return: range object to add to list, or NULL on error. - */ -static struct replay_range* -replay_range_read(char* remain, FILE* in, const char* name, - struct sldns_file_parse_state* pstate, char* line) -{ - struct replay_range* rng = (struct replay_range*)malloc( - sizeof(struct replay_range)); - off_t pos; - char *parse; - struct entry* entry, *last = NULL; - if(!rng) - return NULL; - memset(rng, 0, sizeof(*rng)); - /* read time range */ - if(sscanf(remain, " %d %d", &rng->start_step, &rng->end_step)!=2) { - log_err("Could not read time range: %s", line); - free(rng); - return NULL; - } - /* read entries */ - pos = ftello(in); - while(fgets(line, MAX_LINE_LEN-1, in)) { - pstate->lineno++; - parse = line; - while(isspace((unsigned char)*parse)) - parse++; - if(!*parse || *parse == ';') { - pos = ftello(in); - continue; - } - if(parse_keyword(&parse, "ADDRESS")) { - while(isspace((unsigned char)*parse)) - parse++; - strip_end_white(parse); - if(!extstrtoaddr(parse, &rng->addr, &rng->addrlen)) { - log_err("Line %d: could not read ADDRESS: %s", - pstate->lineno, parse); - free(rng); - return NULL; - } - pos = ftello(in); - continue; - } - if(parse_keyword(&parse, "RANGE_END")) { - return rng; - } - /* set position before line; read entry */ - pstate->lineno--; - fseeko(in, pos, SEEK_SET); - entry = read_entry(in, name, pstate, 1); - if(!entry) - fatal_exit("%d: bad entry", pstate->lineno); - entry->next = NULL; - if(last) - last->next = entry; - else rng->match = entry; - last = entry; - - pos = ftello(in); - } - replay_range_delete(rng); - return NULL; -} - -/** Read FILE match content */ -static void -read_file_content(FILE* in, int* lineno, struct replay_moment* mom) -{ - char line[MAX_LINE_LEN]; - char* remain = line; - struct config_strlist** last = &mom->file_content; - line[MAX_LINE_LEN-1]=0; - if(!fgets(line, MAX_LINE_LEN-1, in)) - fatal_exit("FILE_BEGIN expected at line %d", *lineno); - if(!parse_keyword(&remain, "FILE_BEGIN")) - fatal_exit("FILE_BEGIN expected at line %d", *lineno); - while(fgets(line, MAX_LINE_LEN-1, in)) { - (*lineno)++; - if(strncmp(line, "FILE_END", 8) == 0) { - return; - } - if(line[0]) line[strlen(line)-1] = 0; /* remove newline */ - if(!cfg_strlist_insert(last, strdup(line))) - fatal_exit("malloc failure"); - last = &( (*last)->next ); - } - fatal_exit("no FILE_END in input file"); -} - -/** read assign step info */ -static void -read_assign_step(char* remain, struct replay_moment* mom) -{ - char buf[1024]; - char eq; - int skip; - buf[sizeof(buf)-1]=0; - if(sscanf(remain, " %1023s %c %n", buf, &eq, &skip) != 2) - fatal_exit("cannot parse assign: %s", remain); - mom->variable = strdup(buf); - if(eq != '=') - fatal_exit("no '=' in assign: %s", remain); - remain += skip; - if(remain[0]) remain[strlen(remain)-1]=0; /* remove newline */ - mom->string = strdup(remain); - if(!mom->variable || !mom->string) - fatal_exit("out of memory"); -} - -/** - * Read a replay moment 'STEP' from file. - * @param remain: Rest of line (after STEP keyword). - * @param in: file to read from. - * @param name: name to print in errors. - * @param pstate: with lineno, ttl, origin, prev for parse state. - * lineno is incremented. - * @return: range object to add to list, or NULL on error. - */ -static struct replay_moment* -replay_moment_read(char* remain, FILE* in, const char* name, - struct sldns_file_parse_state* pstate) -{ - struct replay_moment* mom = (struct replay_moment*)malloc( - sizeof(struct replay_moment)); - int skip = 0; - int readentry = 0; - if(!mom) - return NULL; - memset(mom, 0, sizeof(*mom)); - if(sscanf(remain, " %d%n", &mom->time_step, &skip) != 1) { - log_err("%d: cannot read number: %s", pstate->lineno, remain); - free(mom); - return NULL; - } - remain += skip; - while(isspace((unsigned char)*remain)) - remain++; - if(parse_keyword(&remain, "NOTHING")) { - mom->evt_type = repevt_nothing; - } else if(parse_keyword(&remain, "QUERY")) { - mom->evt_type = repevt_front_query; - readentry = 1; - if(!extstrtoaddr("127.0.0.1", &mom->addr, &mom->addrlen)) - fatal_exit("internal error"); - } else if(parse_keyword(&remain, "CHECK_ANSWER")) { - mom->evt_type = repevt_front_reply; - readentry = 1; - } else if(parse_keyword(&remain, "CHECK_OUT_QUERY")) { - mom->evt_type = repevt_back_query; - readentry = 1; - } else if(parse_keyword(&remain, "REPLY")) { - mom->evt_type = repevt_back_reply; - readentry = 1; - } else if(parse_keyword(&remain, "TIMEOUT")) { - mom->evt_type = repevt_timeout; - } else if(parse_keyword(&remain, "TIME_PASSES")) { - mom->evt_type = repevt_time_passes; - while(isspace((unsigned char)*remain)) - remain++; - if(parse_keyword(&remain, "EVAL")) { - while(isspace((unsigned char)*remain)) - remain++; - mom->string = strdup(remain); - if(!mom->string) fatal_exit("out of memory"); - if(strlen(mom->string)>0) - mom->string[strlen(mom->string)-1]=0; - remain += strlen(mom->string); - } - } else if(parse_keyword(&remain, "CHECK_AUTOTRUST")) { - mom->evt_type = repevt_autotrust_check; - while(isspace((unsigned char)*remain)) - remain++; - if(strlen(remain)>0 && remain[strlen(remain)-1]=='\n') - remain[strlen(remain)-1] = 0; - mom->autotrust_id = strdup(remain); - if(!mom->autotrust_id) fatal_exit("out of memory"); - read_file_content(in, &pstate->lineno, mom); - } else if(parse_keyword(&remain, "ERROR")) { - mom->evt_type = repevt_error; - } else if(parse_keyword(&remain, "TRAFFIC")) { - mom->evt_type = repevt_traffic; - } else if(parse_keyword(&remain, "ASSIGN")) { - mom->evt_type = repevt_assign; - read_assign_step(remain, mom); - } else if(parse_keyword(&remain, "INFRA_RTT")) { - char *s, *m; - mom->evt_type = repevt_infra_rtt; - while(isspace((unsigned char)*remain)) - remain++; - s = remain; - remain = strchr(s, ' '); - if(!remain) fatal_exit("expected three args for INFRA_RTT"); - remain[0] = 0; - remain++; - while(isspace((unsigned char)*remain)) - remain++; - m = strchr(remain, ' '); - if(!m) fatal_exit("expected three args for INFRA_RTT"); - m[0] = 0; - m++; - while(isspace((unsigned char)*m)) - m++; - if(!extstrtoaddr(s, &mom->addr, &mom->addrlen)) - fatal_exit("bad infra_rtt address %s", s); - if(strlen(m)>0 && m[strlen(m)-1]=='\n') - m[strlen(m)-1] = 0; - mom->variable = strdup(remain); - mom->string = strdup(m); - if(!mom->string) fatal_exit("out of memory"); - if(!mom->variable) fatal_exit("out of memory"); - } else { - log_err("%d: unknown event type %s", pstate->lineno, remain); - free(mom); - return NULL; - } - while(isspace((unsigned char)*remain)) - remain++; - if(parse_keyword(&remain, "ADDRESS")) { - while(isspace((unsigned char)*remain)) - remain++; - if(strlen(remain) > 0) /* remove \n */ - remain[strlen(remain)-1] = 0; - if(!extstrtoaddr(remain, &mom->addr, &mom->addrlen)) { - log_err("line %d: could not parse ADDRESS: %s", - pstate->lineno, remain); - free(mom); - return NULL; - } - } - if(parse_keyword(&remain, "ELAPSE")) { - double sec; - errno = 0; - sec = strtod(remain, &remain); - if(sec == 0. && errno != 0) { - log_err("line %d: could not parse ELAPSE: %s (%s)", - pstate->lineno, remain, strerror(errno)); - free(mom); - return NULL; - } -#ifndef S_SPLINT_S - mom->elapse.tv_sec = (int)sec; - mom->elapse.tv_usec = (int)((sec - (double)mom->elapse.tv_sec) - *1000000. + 0.5); -#endif - } - - if(readentry) { - mom->match = read_entry(in, name, pstate, 1); - if(!mom->match) { - free(mom); - return NULL; - } - } - - return mom; -} - -/** makes scenario with title on rest of line */ -static struct replay_scenario* -make_scenario(char* line) -{ - struct replay_scenario* scen; - while(isspace((unsigned char)*line)) - line++; - if(!*line) { - log_err("scenario: no title given"); - return NULL; - } - scen = (struct replay_scenario*)malloc(sizeof(struct replay_scenario)); - if(!scen) - return NULL; - memset(scen, 0, sizeof(*scen)); - scen->title = strdup(line); - if(!scen->title) { - free(scen); - return NULL; - } - return scen; -} - -struct replay_scenario* -replay_scenario_read(FILE* in, const char* name, int* lineno) -{ - char line[MAX_LINE_LEN]; - char *parse; - struct replay_scenario* scen = NULL; - struct sldns_file_parse_state pstate; - line[MAX_LINE_LEN-1]=0; - memset(&pstate, 0, sizeof(pstate)); - pstate.default_ttl = 3600; - pstate.lineno = *lineno; - - while(fgets(line, MAX_LINE_LEN-1, in)) { - parse=line; - pstate.lineno++; - (*lineno)++; - while(isspace((unsigned char)*parse)) - parse++; - if(!*parse) - continue; /* empty line */ - if(parse_keyword(&parse, ";")) - continue; /* comment */ - if(parse_keyword(&parse, "SCENARIO_BEGIN")) { - scen = make_scenario(parse); - if(!scen) - fatal_exit("%d: could not make scen", *lineno); - continue; - } - if(!scen) - fatal_exit("%d: expected SCENARIO", *lineno); - if(parse_keyword(&parse, "RANGE_BEGIN")) { - struct replay_range* newr = replay_range_read(parse, - in, name, &pstate, line); - if(!newr) - fatal_exit("%d: bad range", pstate.lineno); - *lineno = pstate.lineno; - newr->next_range = scen->range_list; - scen->range_list = newr; - } else if(parse_keyword(&parse, "STEP")) { - struct replay_moment* mom = replay_moment_read(parse, - in, name, &pstate); - if(!mom) - fatal_exit("%d: bad moment", pstate.lineno); - *lineno = pstate.lineno; - if(scen->mom_last && - scen->mom_last->time_step >= mom->time_step) - fatal_exit("%d: time goes backwards", *lineno); - if(scen->mom_last) - scen->mom_last->mom_next = mom; - else scen->mom_first = mom; - scen->mom_last = mom; - } else if(parse_keyword(&parse, "SCENARIO_END")) { - struct replay_moment *p = scen->mom_first; - int num = 0; - while(p) { - num++; - p = p->mom_next; - } - log_info("Scenario has %d steps", num); - return scen; - } - } - replay_scenario_delete(scen); - return NULL; -} - -void -replay_scenario_delete(struct replay_scenario* scen) -{ - struct replay_moment* mom, *momn; - struct replay_range* rng, *rngn; - if(!scen) - return; - free(scen->title); - mom = scen->mom_first; - while(mom) { - momn = mom->mom_next; - replay_moment_delete(mom); - mom = momn; - } - rng = scen->range_list; - while(rng) { - rngn = rng->next_range; - replay_range_delete(rng); - rng = rngn; - } - free(scen); -} - -/** fetch oldest timer in list that is enabled */ -static struct fake_timer* -first_timer(struct replay_runtime* runtime) -{ - struct fake_timer* p, *res = NULL; - for(p=runtime->timer_list; p; p=p->next) { - if(!p->enabled) - continue; - if(!res) - res = p; - else if(timeval_smaller(&p->tv, &res->tv)) - res = p; - } - return res; -} - -struct fake_timer* -replay_get_oldest_timer(struct replay_runtime* runtime) -{ - struct fake_timer* t = first_timer(runtime); - if(t && timeval_smaller(&t->tv, &runtime->now_tv)) - return t; - return NULL; -} - -int -replay_var_compare(const void* a, const void* b) -{ - struct replay_var* x = (struct replay_var*)a; - struct replay_var* y = (struct replay_var*)b; - return strcmp(x->name, y->name); -} - -rbtree_type* -macro_store_create(void) -{ - return rbtree_create(&replay_var_compare); -} - -/** helper function to delete macro values */ -static void -del_macro(rbnode_type* x, void* ATTR_UNUSED(arg)) -{ - struct replay_var* v = (struct replay_var*)x; - free(v->name); - free(v->value); - free(v); -} - -void -macro_store_delete(rbtree_type* store) -{ - if(!store) - return; - traverse_postorder(store, del_macro, NULL); - free(store); -} - -/** return length of macro */ -static size_t -macro_length(char* text) -{ - /* we are after ${, looking for } */ - int depth = 0; - size_t len = 0; - while(*text) { - len++; - if(*text == '}') { - if(depth == 0) - break; - depth--; - } else if(text[0] == '$' && text[1] == '{') { - depth++; - } - text++; - } - return len; -} - -/** insert new stuff at start of buffer */ -static int -do_buf_insert(char* buf, size_t remain, char* after, char* inserted) -{ - char* save = strdup(after); - size_t len; - if(!save) return 0; - if(strlen(inserted) > remain) { - free(save); - return 0; - } - len = strlcpy(buf, inserted, remain); - buf += len; - remain -= len; - (void)strlcpy(buf, save, remain); - free(save); - return 1; -} - -/** do macro recursion */ -static char* -do_macro_recursion(rbtree_type* store, struct replay_runtime* runtime, - char* at, size_t remain) -{ - char* after = at+2; - char* expand = macro_expand(store, runtime, &after); - if(!expand) - return NULL; /* expansion failed */ - if(!do_buf_insert(at, remain, after, expand)) { - free(expand); - return NULL; - } - free(expand); - return at; /* and parse over the expanded text to see if again */ -} - -/** get var from store */ -static struct replay_var* -macro_getvar(rbtree_type* store, char* name) -{ - struct replay_var k; - k.node.key = &k; - k.name = name; - return (struct replay_var*)rbtree_search(store, &k); -} - -/** do macro variable */ -static char* -do_macro_variable(rbtree_type* store, char* buf, size_t remain) -{ - struct replay_var* v; - char* at = buf+1; - char* name = at; - char sv; - if(at[0]==0) - return NULL; /* no variable name after $ */ - while(*at && (isalnum((unsigned char)*at) || *at=='_')) { - at++; - } - /* terminator, we are working in macro_expand() buffer */ - sv = *at; - *at = 0; - v = macro_getvar(store, name); - *at = sv; - - if(!v) { - log_err("variable is not defined: $%s", name); - return NULL; /* variable undefined is error for now */ - } - - /* insert the variable contents */ - if(!do_buf_insert(buf, remain, at, v->value)) - return NULL; - return buf; /* and expand the variable contents */ -} - -/** do ctime macro on argument */ -static char* -do_macro_ctime(char* arg) -{ - char buf[32]; - time_t tt = (time_t)atoi(arg); - if(tt == 0 && strcmp(arg, "0") != 0) { - log_err("macro ctime: expected number, not: %s", arg); - return NULL; - } - ctime_r(&tt, buf); - if(buf[0]) buf[strlen(buf)-1]=0; /* remove trailing newline */ - return strdup(buf); -} - -/** perform arithmetic operator */ -static double -perform_arith(double x, char op, double y, double* res) -{ - switch(op) { - case '+': - *res = x+y; - break; - case '-': - *res = x-y; - break; - case '/': - *res = x/y; - break; - case '*': - *res = x*y; - break; - default: - return 0; - } - - return 1; -} - -/** do macro arithmetic on two numbers and operand */ -static char* -do_macro_arith(char* orig, size_t remain, char** arithstart) -{ - double x, y, result; - char operator; - int skip; - char buf[32]; - char* at; - /* not yet done? we want number operand number expanded first. */ - if(!*arithstart) { - /* remember start pos of expr, skip the first number */ - at = orig; - *arithstart = at; - while(*at && (isdigit((unsigned char)*at) || *at == '.')) - at++; - return at; - } - /* move back to start */ - remain += (size_t)(orig - *arithstart); - at = *arithstart; - - /* parse operands */ - if(sscanf(at, " %lf %c %lf%n", &x, &operator, &y, &skip) != 3) { - *arithstart = NULL; - return do_macro_arith(orig, remain, arithstart); - } - if(isdigit((unsigned char)operator)) { - *arithstart = orig; - return at+skip; /* do nothing, but setup for later number */ - } - - /* calculate result */ - if(!perform_arith(x, operator, y, &result)) { - log_err("unknown operator: %s", at); - return NULL; - } - - /* put result back in buffer */ - snprintf(buf, sizeof(buf), "%.12g", result); - if(!do_buf_insert(at, remain, at+skip, buf)) - return NULL; - - /* the result can be part of another expression, restart that */ - *arithstart = NULL; - return at; -} - -/** Do range macro on expanded buffer */ -static char* -do_macro_range(char* buf) -{ - double x, y, z; - if(sscanf(buf, " %lf %lf %lf", &x, &y, &z) != 3) { - log_err("range func requires 3 args: %s", buf); - return NULL; - } - if(x <= y && y <= z) { - char res[1024]; - snprintf(res, sizeof(res), "%.24g", y); - return strdup(res); - } - fatal_exit("value %.24g not in range [%.24g, %.24g]", y, x, z); - return NULL; -} - -static char* -macro_expand(rbtree_type* store, struct replay_runtime* runtime, char** text) -{ - char buf[10240]; - char* at = *text; - size_t len = macro_length(at); - int dofunc = 0; - char* arithstart = NULL; - if(len >= sizeof(buf)) - return NULL; /* too long */ - buf[0] = 0; - (void)strlcpy(buf, at, len+1-1); /* do not copy last '}' character */ - at = buf; - - /* check for functions */ - if(strcmp(buf, "time") == 0) { - snprintf(buf, sizeof(buf), ARG_LL "d", (long long)runtime->now_secs); - *text += len; - return strdup(buf); - } else if(strcmp(buf, "timeout") == 0) { - time_t res = 0; - struct fake_timer* t = first_timer(runtime); - if(t && (time_t)t->tv.tv_sec >= runtime->now_secs) - res = (time_t)t->tv.tv_sec - runtime->now_secs; - snprintf(buf, sizeof(buf), ARG_LL "d", (long long)res); - *text += len; - return strdup(buf); - } else if(strncmp(buf, "ctime ", 6) == 0 || - strncmp(buf, "ctime\t", 6) == 0) { - at += 6; - dofunc = 1; - } else if(strncmp(buf, "range ", 6) == 0 || - strncmp(buf, "range\t", 6) == 0) { - at += 6; - dofunc = 1; - } - - /* actual macro text expansion */ - while(*at) { - size_t remain = sizeof(buf)-strlen(buf); - if(strncmp(at, "${", 2) == 0) { - at = do_macro_recursion(store, runtime, at, remain); - } else if(*at == '$') { - at = do_macro_variable(store, at, remain); - } else if(isdigit((unsigned char)*at)) { - at = do_macro_arith(at, remain, &arithstart); - } else { - /* copy until whitespace or operator */ - if(*at && (isalnum((unsigned char)*at) || *at=='_')) { - at++; - while(*at && (isalnum((unsigned char)*at) || *at=='_')) - at++; - } else at++; - } - if(!at) return NULL; /* failure */ - } - *text += len; - if(dofunc) { - /* post process functions, buf has the argument(s) */ - if(strncmp(buf, "ctime", 5) == 0) { - return do_macro_ctime(buf+6); - } else if(strncmp(buf, "range", 5) == 0) { - return do_macro_range(buf+6); - } - } - return strdup(buf); -} - -char* -macro_process(rbtree_type* store, struct replay_runtime* runtime, char* text) -{ - char buf[10240]; - char* next, *expand; - char* at = text; - if(!strstr(text, "${")) - return strdup(text); /* no macros */ - buf[0] = 0; - buf[sizeof(buf)-1]=0; - while( (next=strstr(at, "${")) ) { - /* copy text before next macro */ - if((size_t)(next-at) >= sizeof(buf)-strlen(buf)) - return NULL; /* string too long */ - (void)strlcpy(buf+strlen(buf), at, (size_t)(next-at+1)); - /* process the macro itself */ - next += 2; - expand = macro_expand(store, runtime, &next); - if(!expand) return NULL; /* expansion failed */ - (void)strlcpy(buf+strlen(buf), expand, sizeof(buf)-strlen(buf)); - free(expand); - at = next; - } - /* copy remainder fixed text */ - (void)strlcpy(buf+strlen(buf), at, sizeof(buf)-strlen(buf)); - return strdup(buf); -} - -char* -macro_lookup(rbtree_type* store, char* name) -{ - struct replay_var* x = macro_getvar(store, name); - if(!x) return strdup(""); - return strdup(x->value); -} - -void macro_print_debug(rbtree_type* store) -{ - struct replay_var* x; - RBTREE_FOR(x, struct replay_var*, store) { - log_info("%s = %s", x->name, x->value); - } -} - -int -macro_assign(rbtree_type* store, char* name, char* value) -{ - struct replay_var* x = macro_getvar(store, name); - if(x) { - free(x->value); - } else { - x = (struct replay_var*)malloc(sizeof(*x)); - if(!x) return 0; - x->node.key = x; - x->name = strdup(name); - if(!x->name) { - free(x); - return 0; - } - (void)rbtree_insert(store, &x->node); - } - x->value = strdup(value); - return x->value != NULL; -} - -/* testbound assert function for selftest. counts the number of tests */ -#define tb_assert(x) \ - do { if(!(x)) fatal_exit("%s:%d: %s: assertion %s failed", \ - __FILE__, __LINE__, __func__, #x); \ - num_asserts++; \ - } while(0); - -void testbound_selftest(void) -{ - /* test the macro store */ - rbtree_type* store = macro_store_create(); - char* v; - int r; - int num_asserts = 0; - tb_assert(store); - - v = macro_lookup(store, "bla"); - tb_assert(strcmp(v, "") == 0); - free(v); - - v = macro_lookup(store, "vlerk"); - tb_assert(strcmp(v, "") == 0); - free(v); - - r = macro_assign(store, "bla", "waarde1"); - tb_assert(r); - - v = macro_lookup(store, "vlerk"); - tb_assert(strcmp(v, "") == 0); - free(v); - - v = macro_lookup(store, "bla"); - tb_assert(strcmp(v, "waarde1") == 0); - free(v); - - r = macro_assign(store, "vlerk", "kanteel"); - tb_assert(r); - - v = macro_lookup(store, "bla"); - tb_assert(strcmp(v, "waarde1") == 0); - free(v); - - v = macro_lookup(store, "vlerk"); - tb_assert(strcmp(v, "kanteel") == 0); - free(v); - - r = macro_assign(store, "bla", "ww"); - tb_assert(r); - - v = macro_lookup(store, "bla"); - tb_assert(strcmp(v, "ww") == 0); - free(v); - - tb_assert( macro_length("}") == 1); - tb_assert( macro_length("blabla}") == 7); - tb_assert( macro_length("bla${zoink}bla}") == 7+8); - tb_assert( macro_length("bla${zoink}${bla}bla}") == 7+8+6); - - v = macro_process(store, NULL, ""); - tb_assert( v && strcmp(v, "") == 0); - free(v); - - v = macro_process(store, NULL, "${}"); - tb_assert( v && strcmp(v, "") == 0); - free(v); - - v = macro_process(store, NULL, "blabla ${} dinges"); - tb_assert( v && strcmp(v, "blabla dinges") == 0); - free(v); - - v = macro_process(store, NULL, "1${$bla}2${$bla}3"); - tb_assert( v && strcmp(v, "1ww2ww3") == 0); - free(v); - - v = macro_process(store, NULL, "it is ${ctime 123456}"); - tb_assert( v && strcmp(v, "it is Fri Jan 2 10:17:36 1970") == 0); - free(v); - - r = macro_assign(store, "t1", "123456"); - tb_assert(r); - v = macro_process(store, NULL, "it is ${ctime ${$t1}}"); - tb_assert( v && strcmp(v, "it is Fri Jan 2 10:17:36 1970") == 0); - free(v); - - v = macro_process(store, NULL, "it is ${ctime $t1}"); - tb_assert( v && strcmp(v, "it is Fri Jan 2 10:17:36 1970") == 0); - free(v); - - r = macro_assign(store, "x", "1"); - tb_assert(r); - r = macro_assign(store, "y", "2"); - tb_assert(r); - v = macro_process(store, NULL, "${$x + $x}"); - tb_assert( v && strcmp(v, "2") == 0); - free(v); - v = macro_process(store, NULL, "${$x - $x}"); - tb_assert( v && strcmp(v, "0") == 0); - free(v); - v = macro_process(store, NULL, "${$y * $y}"); - tb_assert( v && strcmp(v, "4") == 0); - free(v); - v = macro_process(store, NULL, "${32 / $y + $x + $y}"); - tb_assert( v && strcmp(v, "19") == 0); - free(v); - - v = macro_process(store, NULL, "${32 / ${$y+$y} + ${${100*3}/3}}"); - tb_assert( v && strcmp(v, "108") == 0); - free(v); - - v = macro_process(store, NULL, "${1 2 33 2 1}"); - tb_assert( v && strcmp(v, "1 2 33 2 1") == 0); - free(v); - - v = macro_process(store, NULL, "${123 3 + 5}"); - tb_assert( v && strcmp(v, "123 8") == 0); - free(v); - - v = macro_process(store, NULL, "${123 glug 3 + 5}"); - tb_assert( v && strcmp(v, "123 glug 8") == 0); - free(v); - - macro_store_delete(store); - printf("selftest successful (%d checks).\n", num_asserts); -} diff --git a/external/unbound/testcode/replay.h b/external/unbound/testcode/replay.h deleted file mode 100644 index b33950304..000000000 --- a/external/unbound/testcode/replay.h +++ /dev/null @@ -1,458 +0,0 @@ -/* - * testcode/replay.h - store and use a replay of events for the DNS resolver. - * - * 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 - * Store and use a replay of events for the DNS resolver. - * Used to test known scenarios to get known outcomes. - * - * <pre> - * File format for replay files. - * - * ; unbound.conf options. - * ; ... - * ; additional commandline options to pass to unbound - * COMMANDLINE cmdline_option - * ; autotrust key file contents, also adds auto-trust-anchor-file: "x" to cfg - * AUTOTRUST_FILE id - * ; contents of that file - * AUTOTRUST_END - * CONFIG_END - * ; comment line. - * SCENARIO_BEGIN name_of_scenario - * RANGE_BEGIN start_time end_time - * ; give ip of the virtual server, it matches any ip if not present. - * ADDRESS ip_address - * match_entries - * RANGE_END - * ; more RANGE items. - * ; go to the next moment - * STEP time_step event_type [ADDRESS ip_address] - * ; event_type can be: - * o NOTHING - nothing - * o QUERY - followed by entry - * o CHECK_ANSWER - followed by entry - * o CHECK_OUT_QUERY - followed by entry (if copy-id it is also reply). - * o REPLY - followed by entry - * o TIMEOUT - * o TIME_PASSES ELAPSE [seconds] - increase 'now' time counter, can be - * a floating point number. - * TIME_PASSES EVAL [macro] - expanded for seconds to move time. - * o TRAFFIC - like CHECK_ANSWER, causes traffic to flow. - * actually the traffic flows before this step is taken. - * the step waits for traffic to stop. - * o CHECK_AUTOTRUST [id] - followed by FILE_BEGIN [to match] FILE_END. - * The file contents is macro expanded before match. - * o INFRA_RTT [ip] [dp] [rtt] - update infra cache entry with rtt. - * o ERROR - * ; following entry starts on the next line, ENTRY_BEGIN. - * ; more STEP items - * SCENARIO_END - * - * Calculations, a macro-like system: ${$myvar + 3600} - * STEP 10 ASSIGN myvar = 3600 - * ; ASSIGN event. '=' is syntactic sugar here. 3600 is some expression. - * ${..} is macro expanded from its expression. Text substitution. - * o $var replaced with its value. var is identifier [azAZ09_]* - * o number is that number. - * o ${variables and arithmetic } - * o +, -, / and *. Note, evaluated left-to-right. Use ${} for brackets. - * So again, no precedence rules, so 2+3*4 == ${2+3}*4 = 20. - * Do 2+${3*4} to get 24. - * o ${function params} - * o ${time} is the current time for the simulated unbound. - * o ${ctime value} is the text ctime(value), Fri 3 Aug 2009, ... - * o ${timeout} is the time until next timeout in comm_timer list. - * o ${range lower value upper} checks if lower<=value<=upper - * returns value if check succeeds. - * - * ; Example file - * SCENARIO_BEGIN Example scenario - * RANGE_BEGIN 0 100 - * ENTRY_BEGIN - * ; precoded answers to queries. - * ENTRY_END - * END_RANGE - * STEP 0 QUERY - * ENTRY_BEGIN - * ; query - * ENTRY_END - * ; a query is sent out to the network by resolver. - * ; precoded answer from range is returned. - * ; algorithm will do precoded answers from RANGE immediately, except if - * ; the next step specifically checks for that OUT_QUERY. - * ; or if none of the precoded answers match. - * STEP 1 CHECK_ANSWER - * ENTRY_BEGIN - * ; what the reply should look like - * ENTRY_END - * ; successful termination. (if the answer was OK). - * ; also, all answers must have been checked with CHECK_ANSWER. - * ; and, no more pending out_queries (that have not been checked). - * SCENARIO_END - * - * </pre> - */ - -#ifndef TESTCODE_REPLAY_H -#define TESTCODE_REPLAY_H -#include "util/netevent.h" -#include "testcode/testpkts.h" -#include "util/rbtree.h" -struct replay_answer; -struct replay_moment; -struct replay_range; -struct fake_pending; -struct fake_timer; -struct replay_var; -struct infra_cache; -struct sldns_buffer; - -/** - * A replay scenario. - */ -struct replay_scenario { - /** name of replay scenario. malloced string. */ - char* title; - - /** The list of replay moments. Linked list. Time increases in list. */ - struct replay_moment* mom_first; - /** The last element in list of replay moments. */ - struct replay_moment* mom_last; - - /** - * List of matching answers. This is to ease replay scenario - * creation. It lists queries (to the network) and what answer - * should be returned. The matching answers are valid for a range - * of time steps. - * So: timestep, parts of query, destination --> answer. - */ - struct replay_range* range_list; -}; - -/** - * A replay moment. - * Basically, it consists of events to a fake select() call. - * This is a recording of an event that happens. - * And if output is presented, what is done with that. - */ -struct replay_moment { - /** - * The replay time step number. Starts at 0, time is incremented - * every time the fake select() is run. - */ - int time_step; - /** Next replay moment in list of replay moments. */ - struct replay_moment* mom_next; - - /** what happens this moment? */ - enum replay_event_type { - /** nothing happens, as if this event is not there. */ - repevt_nothing, - /** incoming query */ - repevt_front_query, - /** test fails if reply to query does not match */ - repevt_front_reply, - /** timeout */ - repevt_timeout, - /** time passes */ - repevt_time_passes, - /** reply arrives from the network */ - repevt_back_reply, - /** test fails if query to the network does not match */ - repevt_back_query, - /** check autotrust key file */ - repevt_autotrust_check, - /** an error happens to outbound query */ - repevt_error, - /** assignment to a variable */ - repevt_assign, - /** store infra rtt cache entry: addr and string (int) */ - repevt_infra_rtt, - /** cause traffic to flow */ - repevt_traffic - } - /** variable with what is to happen this moment */ - evt_type; - - /** The sent packet must match this. Incoming events, the data. */ - struct entry* match; - - /** the amount of time that passes */ - struct timeval elapse; - - /** address that must be matched, or packet remote host address. */ - struct sockaddr_storage addr; - /** length of addr, if 0, then any address will do */ - socklen_t addrlen; - - /** macro name, for assign. */ - char* variable; - /** string argument, for assign. */ - char* string; - - /** the autotrust file id to check */ - char* autotrust_id; - /** file contents to match, one string per line */ - struct config_strlist* file_content; -}; - -/** - * Range of timesteps, and canned replies to matching queries. - */ -struct replay_range { - /** time range when this is valid. Including start and end step. */ - int start_step; - /** end step of time range. */ - int end_step; - /** address of where this range is served. */ - struct sockaddr_storage addr; - /** length of addr, if 0, then any address will do */ - socklen_t addrlen; - - /** Matching list */ - struct entry* match; - - /** next in list of time ranges. */ - struct replay_range* next_range; -}; - -/** - * Replay storage of runtime information. - */ -struct replay_runtime { - /** - * The scenario - */ - struct replay_scenario* scenario; - /** - * Current moment. - */ - struct replay_moment* now; - - /** - * List of pending queries in order they were sent out. First - * one has been sent out most recently. Last one in list is oldest. - */ - struct fake_pending* pending_list; - - /** - * List of answers to queries from clients. These need to be checked. - */ - struct replay_answer* answer_list; - - /** last element in answer list. */ - struct replay_answer* answer_last; - - /** list of fake timer callbacks that are pending */ - struct fake_timer* timer_list; - - /** callback to call for incoming queries */ - comm_point_callback_type* callback_query; - /** user argument for incoming query callback */ - void *cb_arg; - - /** ref the infra cache (was passed to outside_network_create) */ - struct infra_cache* infra; - - /** the current time in seconds */ - time_t now_secs; - /** the current time in microseconds */ - struct timeval now_tv; - - /** signal handler callback */ - void (*sig_cb)(int, void*); - /** signal handler user arg */ - void *sig_cb_arg; - /** time to exit cleanly */ - int exit_cleanly; - - /** size of buffers */ - size_t bufsize; - - /** - * Tree of macro values. Of type replay_var - */ - rbtree_type* vars; -}; - -/** - * Pending queries to network, fake replay version. - */ -struct fake_pending { - /** what is important only that we remember the query, copied here. */ - struct sldns_buffer* buffer; - /** and to what address this is sent to. */ - struct sockaddr_storage addr; - /** len of addr */ - socklen_t addrlen; - /** zone name, uncompressed wire format (as used when sent) */ - uint8_t* zone; - /** length of zone name */ - size_t zonelen; - /** qtype */ - int qtype; - /** The callback function to call when answer arrives (or timeout) */ - comm_point_callback_type* callback; - /** callback user argument */ - void* cb_arg; - /** original timeout in seconds from 'then' */ - int timeout; - - /** next in pending list */ - struct fake_pending* next; - /** the buffer parsed into a sldns_pkt */ - uint8_t* pkt; - size_t pkt_len; - /** by what transport was the query sent out */ - enum transport_type transport; - /** if this is a serviced query */ - int serviced; - /** the runtime structure this is part of */ - struct replay_runtime* runtime; -}; - -/** - * An answer that is pending to happen. - */ -struct replay_answer { - /** Next in list */ - struct replay_answer* next; - /** reply information */ - struct comm_reply repinfo; - /** the answer preparsed as ldns pkt */ - uint8_t* pkt; - size_t pkt_len; -}; - -/** - * Timers with callbacks, fake replay version. - */ -struct fake_timer { - /** next in list */ - struct fake_timer* next; - /** the runtime structure this is part of */ - struct replay_runtime* runtime; - /** the callback to call */ - void (*cb)(void*); - /** the callback user argument */ - void* cb_arg; - /** if timer is enabled */ - int enabled; - /** when the timer expires */ - struct timeval tv; -}; - -/** - * Replay macro variable. And its value. - */ -struct replay_var { - /** rbtree node. Key is this structure. Sorted by name. */ - rbnode_type node; - /** the variable name */ - char* name; - /** the variable value */ - char* value; -}; - -/** - * Read a replay scenario from the file. - * @param in: file to read from. - * @param name: name to print in errors. - * @param lineno: incremented for every line read. - * @return: Scenario. NULL if no scenario read. - */ -struct replay_scenario* replay_scenario_read(FILE* in, const char* name, - int* lineno); - -/** - * Delete scenario. - * @param scen: to delete. - */ -void replay_scenario_delete(struct replay_scenario* scen); - -/** compare two replay_vars */ -int replay_var_compare(const void* a, const void* b); - -/** get oldest enabled fake timer */ -struct fake_timer* replay_get_oldest_timer(struct replay_runtime* runtime); - -/** - * Create variable storage - * @return new or NULL on failure. - */ -rbtree_type* macro_store_create(void); - -/** - * Delete variable storage - * @param store: the macro storage to free up. - */ -void macro_store_delete(rbtree_type* store); - -/** - * Apply macro substitution to string. - * @param store: variable store. - * @param runtime: the runtime to look up values as needed. - * @param text: string to work on. - * @return newly malloced string with result. - */ -char* macro_process(rbtree_type* store, struct replay_runtime* runtime, - char* text); - -/** - * Look up a macro value. Like calling ${$name}. - * @param store: variable store - * @param name: macro name - * @return newly malloced string with result or strdup("") if not found. - * or NULL on malloc failure. - */ -char* macro_lookup(rbtree_type* store, char* name); - -/** - * Set macro value. - * @param store: variable store - * @param name: macro name - * @param value: text to set it to. Not expanded. - * @return false on failure. - */ -int macro_assign(rbtree_type* store, char* name, char* value); - -/** Print macro variables stored as debug info */ -void macro_print_debug(rbtree_type* store); - -/** testbounds self test */ -void testbound_selftest(void); - -#endif /* TESTCODE_REPLAY_H */ diff --git a/external/unbound/testcode/run_vm.sh b/external/unbound/testcode/run_vm.sh deleted file mode 100644 index 78649f07a..000000000 --- a/external/unbound/testcode/run_vm.sh +++ /dev/null @@ -1,78 +0,0 @@ -#!/usr/local/bin/bash -# run tpkg tests from within a VM. Looks for loopback addr. -# if run not from within a VM, runs the tests as usual. -# with one argument: run that tpkg, otherwise, run all tpkgs. - -get_lo0_ip4() { - if test -x /sbin/ifconfig - then - LO0_IP4=`/sbin/ifconfig lo0 | grep '[^0-9]127\.' | sed -e 's/^[^1]*\(127\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*\)[^0-9]*.*$/\1/g'` - if ( echo $LO0_IP4 | grep '^127\.[0-9][0-9]*\.[0-9][0-9]*\.[0-9][0-9]*$' > /dev/null ) - then - return - fi - fi - LO0_IP4=127.0.0.1 -} -get_lo0_ip4 -export LO0_IP4 -if test "x$LO0_IP4" = "x127.0.0.1" -then - ALT_LOOPBACK=false -else - ALT_LOOPBACK=true -fi -cd testdata -TPKG=../testcode/mini_tpkg.sh -#RUNLIST=`(ls -1 *.tpkg|grep -v '^0[016]')` -RUNLIST=`(ls -1 *.tpkg)` -if test "$#" = "1"; then RUNLIST="$1"; fi - -# fix up tpkg that was edited on keyboard interrupt. -cleanup() { - echo cleanup - if test -f "$t.bak"; then mv "$t.bak" "$t"; fi - exit 0 -} -trap cleanup SIGINT - -for t in $RUNLIST -do - if ! $ALT_LOOPBACK - then - $TPKG exe $t - continue - fi - # We have alternative 127.0.0.1 number - if ( echo $t | grep '6\.tpkg$' ) # skip IPv6 tests - then - continue - elif test "$t" = "edns_cache.tpkg" # This one is IPv6 too! - then - continue - fi - cp -p "$t" "$t.bak" - tar xzf $t - find "${t%.tpkg}.dir" -type f \ - -exec grep -q -e '127\.0\.0\.1' -e '@localhost' {} \; -print | { - while read f - do - sed "s/127\.0\.0\.1/${LO0_IP4}/g" "$f" > "$f._" - mv "$f._" "$f" - sed "s/@localhost/@${LO0_IP4}/g" "$f" > "$f._" - mv "$f._" "$f" - done - } - find "${t%.tpkg}.dir" -type d -name "127.0.0.1" -print | { - while read d - do - mv -v "$d" "${d%127.0.0.1}${LO0_IP4}" - done - } - tar czf $t "${t%.tpkg}.dir" - rm -fr "${t%.tpkg}.dir" - $TPKG exe $t - mv "$t.bak" "$t" -done -# get out of testdata/ -cd .. diff --git a/external/unbound/testcode/signit.c b/external/unbound/testcode/signit.c deleted file mode 100644 index 0eca0e088..000000000 --- a/external/unbound/testcode/signit.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * testcode/signit.c - debug tool to sign rrsets with given keys. - * - * 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 program signs rrsets with the given keys. It can be used to - * construct input to test the validator with. - */ -#include "config.h" -#include <ldns/ldns.h> -#include <assert.h> - -#define DNSKEY_BIT_ZSK 0x0100 - -/** - * Key settings - */ -struct keysets { - /** signature inception */ - uint32_t incep; - /** signature expiration */ - uint32_t expi; - /** owner name */ - char* owner; - /** keytag */ - uint16_t keytag; - /** DNSKEY flags */ - uint16_t flags; -}; - -/** print usage and exit */ -static void -usage(void) -{ - printf("usage: signit expi ince keytag owner keyfile\n"); - printf("present rrset data on stdin.\n"); - printf("signed data is printed to stdout.\n"); - printf("\n"); - printf("Or use: signit NSEC3PARAM hash flags iter salt\n"); - printf("present names on stdin, hashed names are printed to stdout.\n"); - exit(1); -} - -static time_t -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 = ldns_mktime_from_utc(&tm); - return t; -} - -static void fatal_exit(const char* format, ...) -{ - va_list args; - va_start(args, format); - printf("fatal exit: "); - vprintf(format, args); - va_end(args); - exit(1); -} - -/** read expi ince keytag owner from cmdline */ -static void -parse_cmdline(char *argv[], struct keysets* s) -{ - s->expi = convert_timeval(argv[1]); - s->incep = convert_timeval(argv[2]); - s->keytag = (uint16_t)atoi(argv[3]); - s->owner = argv[4]; - s->flags = DNSKEY_BIT_ZSK; /* to enforce signing */ -} - -/** read all key files, exit on error */ -static ldns_key_list* -read_keys(int num, char* names[], struct keysets* set) -{ - int i; - ldns_key_list* keys = ldns_key_list_new(); - ldns_key* k; - ldns_rdf* rdf; - ldns_status s; - int b; - FILE* in; - - if(!keys) fatal_exit("alloc failure"); - for(i=0; i<num; i++) { - printf("read keyfile %s\n", names[i]); - in = fopen(names[i], "r"); - if(!in) fatal_exit("could not open %s: %s", names[i], - strerror(errno)); - s = ldns_key_new_frm_fp(&k, in); - fclose(in); - if(s != LDNS_STATUS_OK) - fatal_exit("bad keyfile %s: %s", names[i], - ldns_get_errorstr_by_id(s)); - ldns_key_set_expiration(k, set->expi); - ldns_key_set_inception(k, set->incep); - s = ldns_str2rdf_dname(&rdf, set->owner); - if(s != LDNS_STATUS_OK) - fatal_exit("bad owner name %s: %s", set->owner, - ldns_get_errorstr_by_id(s)); - ldns_key_set_pubkey_owner(k, rdf); - ldns_key_set_flags(k, set->flags); - ldns_key_set_keytag(k, set->keytag); - b = ldns_key_list_push_key(keys, k); - assert(b); - } - return keys; -} - -/** read list of rrs from the file */ -static ldns_rr_list* -read_rrs(FILE* in) -{ - uint32_t my_ttl = 3600; - ldns_rdf *my_origin = NULL; - ldns_rdf *my_prev = NULL; - ldns_status s; - int line_nr = 1; - int b; - - ldns_rr_list* list; - ldns_rr *rr; - - list = ldns_rr_list_new(); - if(!list) fatal_exit("alloc error"); - - while(!feof(in)) { - s = ldns_rr_new_frm_fp_l(&rr, in, &my_ttl, &my_origin, - &my_prev, &line_nr); - if(s == LDNS_STATUS_SYNTAX_TTL || - s == LDNS_STATUS_SYNTAX_ORIGIN || - s == LDNS_STATUS_SYNTAX_EMPTY) - continue; - else if(s != LDNS_STATUS_OK) - fatal_exit("parse error in line %d: %s", line_nr, - ldns_get_errorstr_by_id(s)); - b = ldns_rr_list_push_rr(list, rr); - assert(b); - } - printf("read %d lines\n", line_nr); - - return list; -} - -/** sign the rrs with the keys */ -static void -signit(ldns_rr_list* rrs, ldns_key_list* keys) -{ - ldns_rr_list* rrset; - ldns_rr_list* sigs; - - while(ldns_rr_list_rr_count(rrs) > 0) { - rrset = ldns_rr_list_pop_rrset(rrs); - if(!rrset) fatal_exit("copy alloc failure"); - sigs = ldns_sign_public(rrset, keys); - if(!sigs) fatal_exit("failed to sign"); - ldns_rr_list_print(stdout, rrset); - ldns_rr_list_print(stdout, sigs); - printf("\n"); - ldns_rr_list_free(rrset); - ldns_rr_list_free(sigs); - } -} - -/** process keys and signit */ -static void -process_keys(int argc, char* argv[]) -{ - ldns_rr_list* rrs; - ldns_key_list* keys; - struct keysets settings; - assert(argc == 6); - - parse_cmdline(argv, &settings); - keys = read_keys(1, argv+5, &settings); - rrs = read_rrs(stdin); - signit(rrs, keys); - - ldns_rr_list_deep_free(rrs); - ldns_key_list_free(keys); -} - -/** process nsec3 params and perform hashing */ -static void -process_nsec3(int argc, char* argv[]) -{ - char line[10240]; - ldns_rdf* salt; - ldns_rdf* in, *out; - ldns_status status; - status = ldns_str2rdf_nsec3_salt(&salt, argv[5]); - if(status != LDNS_STATUS_OK) - fatal_exit("Could not parse salt %s: %s", argv[5], - ldns_get_errorstr_by_id(status)); - assert(argc == 6); - while(fgets(line, (int)sizeof(line), stdin)) { - if(strlen(line) > 0) - line[strlen(line)-1] = 0; /* remove trailing newline */ - if(line[0]==0) - continue; - status = ldns_str2rdf_dname(&in, line); - if(status != LDNS_STATUS_OK) - fatal_exit("Could not parse name %s: %s", line, - ldns_get_errorstr_by_id(status)); - ldns_rdf_print(stdout, in); - printf(" -> "); - /* arg 3 is flags, unused */ - out = ldns_nsec3_hash_name(in, (uint8_t)atoi(argv[2]), - (uint16_t)atoi(argv[4]), - ldns_rdf_data(salt)[0], ldns_rdf_data(salt)+1); - if(!out) - fatal_exit("Could not hash %s", line); - ldns_rdf_print(stdout, out); - printf("\n"); - ldns_rdf_deep_free(in); - ldns_rdf_deep_free(out); - } - ldns_rdf_deep_free(salt); -} - -/** main program */ -int main(int argc, char* argv[]) -{ - if(argc != 6) { - usage(); - } - if(strcmp(argv[1], "NSEC3PARAM") == 0) { - process_nsec3(argc, argv); - return 0; - } - process_keys(argc, argv); - return 0; -} diff --git a/external/unbound/testcode/streamtcp.1 b/external/unbound/testcode/streamtcp.1 deleted file mode 100644 index 7c738d9d2..000000000 --- a/external/unbound/testcode/streamtcp.1 +++ /dev/null @@ -1,66 +0,0 @@ -.TH "unbound\-streamtcp" "1" "Mar 21, 2013" "NLnet Labs" "unbound" -.\" -.\" unbound-streamtcp.1 -- unbound DNS lookup utility -.\" -.SH "NAME" -.LP -.B unbound\-streamtcp -\- unbound DNS lookup utility -.SH "SYNOPSIS" -.LP -.B unbound\-streamtcp -.RB [ \-unsh ] -.RB [ \-f -.IR ipaddr[@port] ] -.I name -.I type -.I class -.SH "DESCRIPTION" -.LP -.B unbound\-streamtcp -sends a DNS Query of the given \fBtype\fR and \fBclass\fR for the given \fBname\fR -to the DNS server over TCP and displays the response. -.P -If the server to query is not given using the \fB\-f\fR option then localhost -(127.0.0.1) is used. More queries can be given on one commandline, they -are resolved in sequence. -.P -The available options are: -.TP -.I name -This name is resolved (looked up in the DNS). -.TP -.I type -Specify the type of data to lookup. -.TP -.I class -Specify the class to lookup for. -.TP -.B \-u -Use UDP instead of TCP. No retries are attempted. -.TP -.B \-n -Do not wait for the answer. -.TP -.B \-s -Use SSL. -.TP -.B \-h -Print program usage. -.TP -.B \-f \fIipaddr[@port] -Specify the server to send the queries to. If not specified localhost (127.0.0.1) is used. -.SH "EXAMPLES" -.LP -Some examples of use. -.P -$ unbound\-streamtcp www.example.com A IN -.P -$ unbound\-streamtcp \-f 192.168.1.1 www.example.com SOA IN -.P -$ unbound\-streamtcp \-f 192.168.1.1@1234 153.1.168.192.in\-addr.arpa. PTR IN -.SH "EXIT CODE" -The unbound\-streamtcp program exits with status code 1 on error, -0 on no error. -.SH "AUTHOR" -This manual page was written by Tomas Hozza <thozza@redhat.com>. diff --git a/external/unbound/testcode/streamtcp.c b/external/unbound/testcode/streamtcp.c deleted file mode 100644 index 34b5c0281..000000000 --- a/external/unbound/testcode/streamtcp.c +++ /dev/null @@ -1,431 +0,0 @@ -/* - * testcode/streamtcp.c - debug program perform multiple DNS queries on tcp. - * - * 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 program performs multiple DNS queries on a TCP stream. - */ - -#include "config.h" -#ifdef HAVE_GETOPT_H -#include <getopt.h> -#endif -#include <signal.h> -#include "util/locks.h" -#include "util/log.h" -#include "util/net_help.h" -#include "util/data/msgencode.h" -#include "util/data/msgparse.h" -#include "util/data/msgreply.h" -#include "util/data/dname.h" -#include "sldns/sbuffer.h" -#include "sldns/str2wire.h" -#include "sldns/wire2str.h" -#include <openssl/ssl.h> -#include <openssl/rand.h> -#include <openssl/err.h> - -#ifndef PF_INET6 -/** define in case streamtcp is compiled on legacy systems */ -#define PF_INET6 10 -#endif - -/** usage information for streamtcp */ -static void usage(char* argv[]) -{ - printf("usage: %s [options] name type class ...\n", argv[0]); - printf(" sends the name-type-class queries over TCP.\n"); - printf("-f server what ipaddr@portnr to send the queries to\n"); - printf("-u use UDP. No retries are attempted.\n"); - printf("-n do not wait for an answer.\n"); - printf("-s use ssl\n"); - printf("-h this help text\n"); - exit(1); -} - -/** open TCP socket to svr */ -static int -open_svr(const char* svr, int udp) -{ - struct sockaddr_storage addr; - socklen_t addrlen; - int fd = -1; - /* svr can be ip@port */ - memset(&addr, 0, sizeof(addr)); - if(!extstrtoaddr(svr, &addr, &addrlen)) { - printf("fatal: bad server specs '%s'\n", svr); - exit(1); - } - fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET, - udp?SOCK_DGRAM:SOCK_STREAM, 0); - if(fd == -1) { -#ifndef USE_WINSOCK - perror("socket() error"); -#else - printf("socket: %s\n", wsa_strerror(WSAGetLastError())); -#endif - exit(1); - } - if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) { -#ifndef USE_WINSOCK - perror("connect() error"); -#else - printf("connect: %s\n", wsa_strerror(WSAGetLastError())); -#endif - exit(1); - } - return fd; -} - -/** write a query over the TCP fd */ -static void -write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id, - const char* strname, const char* strtype, const char* strclass) -{ - struct query_info qinfo; - uint16_t len; - /* qname */ - qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len); - if(!qinfo.qname) { - printf("cannot parse query name: '%s'\n", strname); - exit(1); - } - - /* qtype and qclass */ - qinfo.qtype = sldns_get_rr_type_by_name(strtype); - qinfo.qclass = sldns_get_rr_class_by_name(strclass); - - /* clear local alias */ - qinfo.local_alias = NULL; - - /* make query */ - qinfo_query_encode(buf, &qinfo); - sldns_buffer_write_u16_at(buf, 0, id); - sldns_buffer_write_u16_at(buf, 2, BIT_RD); - - if(1) { - /* add EDNS DO */ - struct edns_data edns; - memset(&edns, 0, sizeof(edns)); - edns.edns_present = 1; - edns.bits = EDNS_DO; - edns.udp_size = 4096; - attach_edns_record(buf, &edns); - } - - /* send it */ - if(!udp) { - len = (uint16_t)sldns_buffer_limit(buf); - len = htons(len); - if(ssl) { - if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) { - log_crypto_err("cannot SSL_write"); - exit(1); - } - } else { - if(send(fd, (void*)&len, sizeof(len), 0) < - (ssize_t)sizeof(len)){ -#ifndef USE_WINSOCK - perror("send() len failed"); -#else - printf("send len: %s\n", - wsa_strerror(WSAGetLastError())); -#endif - exit(1); - } - } - } - if(ssl) { - if(SSL_write(ssl, (void*)sldns_buffer_begin(buf), - (int)sldns_buffer_limit(buf)) <= 0) { - log_crypto_err("cannot SSL_write"); - exit(1); - } - } else { - if(send(fd, (void*)sldns_buffer_begin(buf), - sldns_buffer_limit(buf), 0) < - (ssize_t)sldns_buffer_limit(buf)) { -#ifndef USE_WINSOCK - perror("send() data failed"); -#else - printf("send data: %s\n", wsa_strerror(WSAGetLastError())); -#endif - exit(1); - } - } - - free(qinfo.qname); -} - -/** receive DNS datagram over TCP and print it */ -static void -recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf) -{ - char* pktstr; - uint16_t len; - if(!udp) { - if(ssl) { - if(SSL_read(ssl, (void*)&len, (int)sizeof(len)) <= 0) { - log_crypto_err("could not SSL_read"); - exit(1); - } - } else { - if(recv(fd, (void*)&len, sizeof(len), 0) < - (ssize_t)sizeof(len)) { -#ifndef USE_WINSOCK - perror("read() len failed"); -#else - printf("read len: %s\n", - wsa_strerror(WSAGetLastError())); -#endif - exit(1); - } - } - len = ntohs(len); - sldns_buffer_clear(buf); - sldns_buffer_set_limit(buf, len); - if(ssl) { - int r = SSL_read(ssl, (void*)sldns_buffer_begin(buf), - (int)len); - if(r <= 0) { - log_crypto_err("could not SSL_read"); - exit(1); - } - if(r != (int)len) - fatal_exit("ssl_read %d of %d", r, len); - } else { - if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) < - (ssize_t)len) { -#ifndef USE_WINSOCK - perror("read() data failed"); -#else - printf("read data: %s\n", - wsa_strerror(WSAGetLastError())); -#endif - exit(1); - } - } - } else { - ssize_t l; - sldns_buffer_clear(buf); - if((l=recv(fd, (void*)sldns_buffer_begin(buf), - sldns_buffer_capacity(buf), 0)) < 0) { -#ifndef USE_WINSOCK - perror("read() data failed"); -#else - printf("read data: %s\n", - wsa_strerror(WSAGetLastError())); -#endif - exit(1); - } - sldns_buffer_set_limit(buf, (size_t)l); - len = (size_t)l; - } - printf("\nnext received packet\n"); - log_buf(0, "data", buf); - - pktstr = sldns_wire2str_pkt(sldns_buffer_begin(buf), len); - printf("%s", pktstr); - free(pktstr); -} - -static int get_random(void) -{ - int r; - if (RAND_bytes((unsigned char*)&r, (int)sizeof(r)) == 1) { - return r; - } - return arc4random(); -} - -/** send the TCP queries and print answers */ -static void -send_em(const char* svr, int udp, int usessl, int noanswer, int num, char** qs) -{ - sldns_buffer* buf = sldns_buffer_new(65553); - int fd = open_svr(svr, udp); - int i; - SSL_CTX* ctx = NULL; - SSL* ssl = NULL; - if(!buf) fatal_exit("out of memory"); - if(usessl) { - ctx = connect_sslctx_create(NULL, NULL, NULL); - if(!ctx) fatal_exit("cannot create ssl ctx"); - ssl = outgoing_ssl_fd(ctx, fd); - if(!ssl) fatal_exit("cannot create ssl"); - while(1) { - int r; - ERR_clear_error(); - if( (r=SSL_do_handshake(ssl)) == 1) - break; - r = SSL_get_error(ssl, r); - if(r != SSL_ERROR_WANT_READ && - r != SSL_ERROR_WANT_WRITE) { - log_crypto_err("could not ssl_handshake"); - exit(1); - } - } - if(1) { - X509* x = SSL_get_peer_certificate(ssl); - if(!x) printf("SSL: no peer certificate\n"); - else { - X509_print_fp(stdout, x); - X509_free(x); - } - } - } - for(i=0; i<num; i+=3) { - printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]); - write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i], - qs[i+1], qs[i+2]); - /* print at least one result */ - if(!noanswer) - recv_one(fd, udp, ssl, buf); - } - - if(usessl) { - SSL_shutdown(ssl); - SSL_free(ssl); - SSL_CTX_free(ctx); - } -#ifndef USE_WINSOCK - close(fd); -#else - closesocket(fd); -#endif - sldns_buffer_free(buf); - printf("orderly exit\n"); -} - -#ifdef SIGPIPE -/** SIGPIPE handler */ -static RETSIGTYPE sigh(int sig) -{ - if(sig == SIGPIPE) { - printf("got SIGPIPE, remote connection gone\n"); - exit(1); - } - printf("Got unhandled signal %d\n", sig); - exit(1); -} -#endif /* SIGPIPE */ - -/** getopt global, in case header files fail to declare it. */ -extern int optind; -/** getopt global, in case header files fail to declare it. */ -extern char* optarg; - -/** main program for streamtcp */ -int main(int argc, char** argv) -{ - int c; - const char* svr = "127.0.0.1"; - int udp = 0; - int noanswer = 0; - int usessl = 0; - -#ifdef USE_WINSOCK - WSADATA wsa_data; - if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) { - printf("WSAStartup failed\n"); - return 1; - } -#endif - - /* lock debug start (if any) */ - log_init(0, 0, 0); - checklock_start(); - -#ifdef SIGPIPE - if(signal(SIGPIPE, &sigh) == SIG_ERR) { - perror("could not install signal handler"); - return 1; - } -#endif - - /* command line options */ - if(argc == 1) { - usage(argv); - } - while( (c=getopt(argc, argv, "f:hnsu")) != -1) { - switch(c) { - case 'f': - svr = optarg; - break; - case 'n': - noanswer = 1; - break; - case 'u': - udp = 1; - break; - case 's': - usessl = 1; - break; - case 'h': - case '?': - default: - usage(argv); - } - } - argc -= optind; - argv += optind; - - if(argc % 3 != 0) { - printf("queries must be multiples of name,type,class\n"); - return 1; - } - if(usessl) { - ERR_load_SSL_strings(); -#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO) - OpenSSL_add_all_algorithms(); -#else - OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS - | OPENSSL_INIT_ADD_ALL_DIGESTS - | OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL); -#endif -#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL) - (void)SSL_library_init(); -#else - (void)OPENSSL_init_ssl(0, NULL); -#endif - } - send_em(svr, udp, usessl, noanswer, argc, argv); - checklock_stop(); -#ifdef USE_WINSOCK - WSACleanup(); -#endif - return 0; -} diff --git a/external/unbound/testcode/testbound.c b/external/unbound/testcode/testbound.c deleted file mode 100644 index 180b2c256..000000000 --- a/external/unbound/testcode/testbound.c +++ /dev/null @@ -1,470 +0,0 @@ -/* - * testcode/testbound.c - test program 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 - * Exits with code 1 on a failure. 0 if all unit tests are successful. - */ - -#include "config.h" -#ifdef HAVE_TIME_H -# include <time.h> -#endif -#include "testcode/testpkts.h" -#include "testcode/replay.h" -#include "testcode/fake_event.h" -#include "daemon/remote.h" -#include "util/config_file.h" -#include "sldns/keyraw.h" -#include <ctype.h> - -/** signal that this is a testbound compile */ -#define unbound_testbound 1 -/** - * include the main program from the unbound daemon. - * rename main to daemon_main to call it - */ -#define main daemon_main -#include "daemon/unbound.c" -#undef main - -/** maximum line length for lines in the replay file. */ -#define MAX_LINE_LEN 1024 -/** config files (removed at exit) */ -static struct config_strlist* cfgfiles = NULL; - -/** give commandline usage for testbound. */ -static void -testbound_usage(void) -{ - printf("usage: testbound [options]\n"); - printf("\ttest the unbound daemon.\n"); - printf("-h this help\n"); - printf("-p file playback text file\n"); - printf("-1 detect SHA1 support (exit code 0 or 1)\n"); - printf("-2 detect SHA256 support (exit code 0 or 1)\n"); - printf("-g detect GOST support (exit code 0 or 1)\n"); - printf("-e detect ECDSA support (exit code 0 or 1)\n"); - printf("-c detect CLIENT_SUBNET support (exit code 0 or 1)\n"); - printf("-s testbound self-test - unit test of testbound parts.\n"); - printf("-o str unbound commandline options separated by spaces.\n"); - printf("Version %s\n", PACKAGE_VERSION); - printf("BSD licensed, see LICENSE file in source package.\n"); - printf("Report bugs to %s.\n", PACKAGE_BUGREPORT); -} - -/** Max number of arguments to pass to unbound. */ -#define MAXARG 100 - -/** - * Add options from string to passed argc. splits on whitespace. - * @param args: the option argument, "-v -p 12345" or so. - * @param pass_argc: ptr to the argc for unbound. Modified. - * @param pass_argv: the argv to pass to unbound. Modified. - */ -static void -add_opts(const char* args, int* pass_argc, char* pass_argv[]) -{ - const char *p = args, *np; - size_t len; - while(p && isspace((unsigned char)*p)) - p++; - while(p && *p) { - /* find location of next string and length of this one */ - if((np = strchr(p, ' '))) - len = (size_t)(np-p); - else len = strlen(p); - /* allocate and copy option */ - if(*pass_argc >= MAXARG-1) - fatal_exit("too many arguments: '%s'", p); - pass_argv[*pass_argc] = (char*)malloc(len+1); - if(!pass_argv[*pass_argc]) - fatal_exit("add_opts: out of memory"); - memcpy(pass_argv[*pass_argc], p, len); - pass_argv[*pass_argc][len] = 0; - (*pass_argc)++; - /* go to next option */ - p = np; - while(p && isspace((unsigned char)*p)) - p++; - } -} - -/** pretty print commandline for unbound in this test */ -static void -echo_cmdline(int argc, char* argv[]) -{ - int i; - fprintf(stderr, "testbound is starting:"); - for(i=0; i<argc; i++) { - fprintf(stderr, " [%s]", argv[i]); - } - fprintf(stderr, "\n"); -} - -/** spool autotrust file */ -static void -spool_auto_file(FILE* in, int* lineno, FILE* cfg, char* id) -{ - char line[MAX_LINE_LEN]; - char* parse; - FILE* spool; - /* find filename for new file */ - while(isspace((unsigned char)*id)) - id++; - if(*id == '\0') - fatal_exit("AUTROTRUST_FILE must have id, line %d", *lineno); - id[strlen(id)-1]=0; /* remove newline */ - fake_temp_file("_auto_", id, line, sizeof(line)); - /* add option for the file */ - fprintf(cfg, "server: auto-trust-anchor-file: \"%s\"\n", line); - /* open file and spool to it */ - spool = fopen(line, "w"); - if(!spool) fatal_exit("could not open %s: %s", line, strerror(errno)); - fprintf(stderr, "testbound is spooling key file: %s\n", line); - if(!cfg_strlist_insert(&cfgfiles, strdup(line))) - fatal_exit("out of memory"); - line[sizeof(line)-1] = 0; - while(fgets(line, MAX_LINE_LEN-1, in)) { - parse = line; - (*lineno)++; - while(isspace((unsigned char)*parse)) - parse++; - if(strncmp(parse, "AUTOTRUST_END", 13) == 0) { - fclose(spool); - return; - } - fputs(line, spool); - } - fatal_exit("no AUTOTRUST_END in input file"); -} - -/** process config elements */ -static void -setup_config(FILE* in, int* lineno, int* pass_argc, char* pass_argv[]) -{ - char configfile[MAX_LINE_LEN]; - char line[MAX_LINE_LEN]; - char* parse; - FILE* cfg; - fake_temp_file("_cfg", "", configfile, sizeof(configfile)); - add_opts("-c", pass_argc, pass_argv); - add_opts(configfile, pass_argc, pass_argv); - cfg = fopen(configfile, "w"); - if(!cfg) fatal_exit("could not open %s: %s", - configfile, strerror(errno)); - if(!cfg_strlist_insert(&cfgfiles, strdup(configfile))) - fatal_exit("out of memory"); - line[sizeof(line)-1] = 0; - /* some basic settings to not pollute the host system */ - fprintf(cfg, "server: use-syslog: no\n"); - fprintf(cfg, " directory: \"\"\n"); - fprintf(cfg, " chroot: \"\"\n"); - fprintf(cfg, " username: \"\"\n"); - fprintf(cfg, " pidfile: \"\"\n"); - fprintf(cfg, " val-log-level: 2\n"); - fprintf(cfg, "remote-control: control-enable: no\n"); - while(fgets(line, MAX_LINE_LEN-1, in)) { - parse = line; - (*lineno)++; - while(isspace((unsigned char)*parse)) - parse++; - if(!*parse || parse[0] == ';') - continue; - if(strncmp(parse, "COMMANDLINE", 11) == 0) { - parse[strlen(parse)-1] = 0; /* strip off \n */ - add_opts(parse+11, pass_argc, pass_argv); - continue; - } - if(strncmp(parse, "AUTOTRUST_FILE", 14) == 0) { - spool_auto_file(in, lineno, cfg, parse+14); - continue; - } - if(strncmp(parse, "CONFIG_END", 10) == 0) { - fclose(cfg); - return; - } - fputs(line, cfg); - } - fatal_exit("No CONFIG_END in input file"); - -} - -/** read playback file */ -static struct replay_scenario* -setup_playback(const char* filename, int* pass_argc, char* pass_argv[]) -{ - struct replay_scenario* scen = NULL; - int lineno = 0; - - if(filename) { - FILE *in = fopen(filename, "rb"); - if(!in) { - perror(filename); - exit(1); - } - setup_config(in, &lineno, pass_argc, pass_argv); - scen = replay_scenario_read(in, filename, &lineno); - fclose(in); - if(!scen) - fatal_exit("Could not read: %s", filename); - } - else fatal_exit("need a playback file (-p)"); - log_info("Scenario: %s", scen->title); - return scen; -} - -/** remove config file at exit */ -void remove_configfile(void) -{ - struct config_strlist* p; - for(p=cfgfiles; p; p=p->next) - unlink(p->str); - config_delstrlist(cfgfiles); - cfgfiles = NULL; -} - -/** - * Main fake event test program. Setup, teardown and report errors. - * @param argc: arg count. - * @param argv: array of commandline arguments. - * @return program failure if test fails. - */ -int -main(int argc, char* argv[]) -{ - int c, res; - int pass_argc = 0; - char* pass_argv[MAXARG]; - char* playback_file = NULL; - int init_optind = optind; - char* init_optarg = optarg; - struct replay_scenario* scen = NULL; - - /* we do not want the test to depend on the timezone */ - (void)putenv("TZ=UTC"); - - log_init(NULL, 0, NULL); - /* determine commandline options for the daemon */ - pass_argc = 1; - pass_argv[0] = "unbound"; - add_opts("-d", &pass_argc, pass_argv); - while( (c=getopt(argc, argv, "12egho:p:s")) != -1) { - switch(c) { - case 's': - free(pass_argv[1]); - testbound_selftest(); - exit(0); - case '1': -#ifdef USE_SHA1 - printf("SHA1 supported\n"); - exit(0); -#else - printf("SHA1 not supported\n"); - exit(1); -#endif - break; - case '2': -#if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2) - printf("SHA256 supported\n"); - exit(0); -#else - printf("SHA256 not supported\n"); - exit(1); -#endif - break; - case 'e': -#if defined(USE_ECDSA) - printf("ECDSA supported\n"); - exit(0); -#else - printf("ECDSA not supported\n"); - exit(1); -#endif - break; - case 'g': -#ifdef USE_GOST - if(sldns_key_EVP_load_gost_id()) { - printf("GOST supported\n"); - exit(0); - } else { - printf("GOST not supported\n"); - exit(1); - } -#else - printf("GOST not supported\n"); - exit(1); -#endif - break; - case 'c': -#ifdef CLIENT_SUBNET - printf("CLIENT_SUBNET supported\n"); - exit(0); -#else - printf("CLIENT_SUBNET not supported\n"); - exit(1); -#endif - break; - case 'p': - playback_file = optarg; - break; - case 'o': - add_opts(optarg, &pass_argc, pass_argv); - break; - case '?': - case 'h': - default: - testbound_usage(); - return 1; - } - } - argc -= optind; - argv += optind; - if(argc != 0) { - testbound_usage(); - return 1; - } - log_info("Start of %s testbound program.", PACKAGE_STRING); - if(atexit(&remove_configfile) != 0) - fatal_exit("atexit() failed: %s", strerror(errno)); - - /* setup test environment */ - scen = setup_playback(playback_file, &pass_argc, pass_argv); - /* init fake event backend */ - fake_event_init(scen); - - pass_argv[pass_argc] = NULL; - echo_cmdline(pass_argc, pass_argv); - - /* reset getopt processing */ - optind = init_optind; - optarg = init_optarg; - - /* run the normal daemon */ - res = daemon_main(pass_argc, pass_argv); - - fake_event_cleanup(); - for(c=1; c<pass_argc; c++) - free(pass_argv[c]); - if(res == 0) { - log_info("Testbound Exit Success"); -#ifdef HAVE_PTHREAD - /* dlopen frees its thread state (dlopen of gost engine) */ - pthread_exit(NULL); -#endif - } - return res; -} - -/* fake remote control */ -struct listen_port* daemon_remote_open_ports(struct config_file* - ATTR_UNUSED(cfg)) -{ - return NULL; -} - -struct daemon_remote* daemon_remote_create(struct config_file* ATTR_UNUSED(cfg)) -{ - return (struct daemon_remote*)calloc(1,1); -} - -void daemon_remote_delete(struct daemon_remote* rc) -{ - free(rc); -} - -void daemon_remote_clear(struct daemon_remote* ATTR_UNUSED(rc)) -{ - /* nothing */ -} - -int daemon_remote_open_accept(struct daemon_remote* ATTR_UNUSED(rc), - struct listen_port* ATTR_UNUSED(ports), - struct worker* ATTR_UNUSED(worker)) -{ - return 1; -} - -int remote_accept_callback(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(repinfo)) -{ - log_assert(0); - return 0; -} - -int remote_control_callback(struct comm_point* ATTR_UNUSED(c), - void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), - struct comm_reply* ATTR_UNUSED(repinfo)) -{ - log_assert(0); - return 0; -} - -void remote_get_opt_ssl(char* ATTR_UNUSED(str), void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void wsvc_command_option(const char* ATTR_UNUSED(wopt), - const char* ATTR_UNUSED(cfgfile), int ATTR_UNUSED(v), - int ATTR_UNUSED(c)) -{ - log_assert(0); -} - -void wsvc_setup_worker(struct worker* ATTR_UNUSED(worker)) -{ - /* do nothing */ -} - -void wsvc_desetup_worker(struct worker* ATTR_UNUSED(worker)) -{ - /* do nothing */ -} - -#ifdef UB_ON_WINDOWS -void worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), - void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} - -void wsvc_cron_cb(void* ATTR_UNUSED(arg)) -{ - log_assert(0); -} -#endif /* UB_ON_WINDOWS */ - diff --git a/external/unbound/testcode/testpkts.c b/external/unbound/testcode/testpkts.c deleted file mode 100644 index e1a7768ab..000000000 --- a/external/unbound/testcode/testpkts.c +++ /dev/null @@ -1,1697 +0,0 @@ -/* - * testpkts. Data file parse for test packets, and query matching. - * - * Data storage for specially crafted replies for testing purposes. - * - * (c) NLnet Labs, 2005, 2006, 2007, 2008 - * See the file LICENSE for the license - */ - -/** - * \file - * This is a debugging aid. It is not efficient, especially - * with a long config file, but it can give any reply to any query. - * This can help the developer pre-script replies for queries. - * - * You can specify a packet RR by RR with header flags to return. - * - * Missing features: - * - matching content different from reply content. - * - find way to adjust mangled packets? - */ - -#include "config.h" -struct sockaddr_storage; -#include <errno.h> -#include <stdarg.h> -#include <ctype.h> -#include "testcode/testpkts.h" -#include "util/net_help.h" -#include "sldns/sbuffer.h" -#include "sldns/rrdef.h" -#include "sldns/pkthdr.h" -#include "sldns/str2wire.h" -#include "sldns/wire2str.h" - -/** max size of a packet */ -#define MAX_PACKETLEN 65536 -/** max line length */ -#define MAX_LINE 10240 -/** string to show in warnings and errors */ -static const char* prog_name = "testpkts"; - -#ifndef UTIL_LOG_H -/** verbosity definition for compat */ -enum verbosity_value { NO_VERBOSE=0 }; -#endif -/** logging routine, provided by caller */ -void verbose(enum verbosity_value lvl, const char* msg, ...) ATTR_FORMAT(printf, 2, 3); - -/** print error and exit */ -static void error(const char* msg, ...) -{ - va_list args; - va_start(args, msg); - fprintf(stderr, "%s error: ", prog_name); - vfprintf(stderr, msg, args); - fprintf(stderr, "\n"); - fflush(stderr); - va_end(args); - exit(EXIT_FAILURE); -} - -/** return if string is empty or comment */ -static int isendline(char c) -{ - if(c == ';' || c == '#' - || c == '\n' || c == 0) - return 1; - return 0; -} - -/** true if the string starts with the keyword given. Moves the str ahead. - * @param str: before keyword, afterwards after keyword and spaces. - * @param keyword: the keyword to match - * @return: true if keyword present. False otherwise, and str unchanged. -*/ -static int str_keyword(char** str, const char* keyword) -{ - size_t len = strlen(keyword); - assert(str && keyword); - if(strncmp(*str, keyword, len) != 0) - return 0; - *str += len; - while(isspace((unsigned char)**str)) - (*str)++; - return 1; -} - -/** Add reply packet to entry */ -static struct reply_packet* -entry_add_reply(struct entry* entry) -{ - struct reply_packet* pkt = (struct reply_packet*)malloc( - sizeof(struct reply_packet)); - struct reply_packet ** p = &entry->reply_list; - if(!pkt) error("out of memory"); - pkt->next = NULL; - pkt->packet_sleep = 0; - pkt->reply_pkt = NULL; - pkt->reply_from_hex = NULL; - pkt->raw_ednsdata = NULL; - /* link at end */ - while(*p) - p = &((*p)->next); - *p = pkt; - return pkt; -} - -/** parse MATCH line */ -static void matchline(char* line, struct entry* e) -{ - char* parse = line; - while(*parse) { - if(isendline(*parse)) - return; - if(str_keyword(&parse, "opcode")) { - e->match_opcode = 1; - } else if(str_keyword(&parse, "qtype")) { - e->match_qtype = 1; - } else if(str_keyword(&parse, "qname")) { - e->match_qname = 1; - } else if(str_keyword(&parse, "rcode")) { - e->match_rcode = 1; - } else if(str_keyword(&parse, "question")) { - e->match_question = 1; - } else if(str_keyword(&parse, "answer")) { - e->match_answer = 1; - } else if(str_keyword(&parse, "subdomain")) { - e->match_subdomain = 1; - } else if(str_keyword(&parse, "all")) { - e->match_all = 1; - } else if(str_keyword(&parse, "ttl")) { - e->match_ttl = 1; - } else if(str_keyword(&parse, "DO")) { - e->match_do = 1; - } else if(str_keyword(&parse, "noedns")) { - e->match_noedns = 1; - } else if(str_keyword(&parse, "ednsdata")) { - e->match_ednsdata_raw = 1; - } else if(str_keyword(&parse, "UDP")) { - e->match_transport = transport_udp; - } else if(str_keyword(&parse, "TCP")) { - e->match_transport = transport_tcp; - } else if(str_keyword(&parse, "serial")) { - e->match_serial = 1; - if(*parse != '=' && *parse != ':') - error("expected = or : in MATCH: %s", line); - parse++; - e->ixfr_soa_serial = (uint32_t)strtol(parse, (char**)&parse, 10); - while(isspace((unsigned char)*parse)) - parse++; - } else { - error("could not parse MATCH: '%s'", parse); - } - } -} - -/** parse REPLY line */ -static void replyline(char* line, uint8_t* reply, size_t reply_len, - int* do_flag) -{ - char* parse = line; - if(reply_len < LDNS_HEADER_SIZE) error("packet too short for header"); - while(*parse) { - if(isendline(*parse)) - return; - /* opcodes */ - if(str_keyword(&parse, "QUERY")) { - LDNS_OPCODE_SET(reply, LDNS_PACKET_QUERY); - } else if(str_keyword(&parse, "IQUERY")) { - LDNS_OPCODE_SET(reply, LDNS_PACKET_IQUERY); - } else if(str_keyword(&parse, "STATUS")) { - LDNS_OPCODE_SET(reply, LDNS_PACKET_STATUS); - } else if(str_keyword(&parse, "NOTIFY")) { - LDNS_OPCODE_SET(reply, LDNS_PACKET_NOTIFY); - } else if(str_keyword(&parse, "UPDATE")) { - LDNS_OPCODE_SET(reply, LDNS_PACKET_UPDATE); - /* rcodes */ - } else if(str_keyword(&parse, "NOERROR")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_NOERROR); - } else if(str_keyword(&parse, "FORMERR")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_FORMERR); - } else if(str_keyword(&parse, "SERVFAIL")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_SERVFAIL); - } else if(str_keyword(&parse, "NXDOMAIN")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_NXDOMAIN); - } else if(str_keyword(&parse, "NOTIMPL")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_NOTIMPL); - } else if(str_keyword(&parse, "REFUSED")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_REFUSED); - } else if(str_keyword(&parse, "YXDOMAIN")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_YXDOMAIN); - } else if(str_keyword(&parse, "YXRRSET")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_YXRRSET); - } else if(str_keyword(&parse, "NXRRSET")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_NXRRSET); - } else if(str_keyword(&parse, "NOTAUTH")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_NOTAUTH); - } else if(str_keyword(&parse, "NOTZONE")) { - LDNS_RCODE_SET(reply, LDNS_RCODE_NOTZONE); - /* flags */ - } else if(str_keyword(&parse, "QR")) { - LDNS_QR_SET(reply); - } else if(str_keyword(&parse, "AA")) { - LDNS_AA_SET(reply); - } else if(str_keyword(&parse, "TC")) { - LDNS_TC_SET(reply); - } else if(str_keyword(&parse, "RD")) { - LDNS_RD_SET(reply); - } else if(str_keyword(&parse, "CD")) { - LDNS_CD_SET(reply); - } else if(str_keyword(&parse, "RA")) { - LDNS_RA_SET(reply); - } else if(str_keyword(&parse, "AD")) { - LDNS_AD_SET(reply); - } else if(str_keyword(&parse, "DO")) { - *do_flag = 1; - } else { - error("could not parse REPLY: '%s'", parse); - } - } -} - -/** parse ADJUST line */ -static void adjustline(char* line, struct entry* e, - struct reply_packet* pkt) -{ - char* parse = line; - while(*parse) { - if(isendline(*parse)) - return; - if(str_keyword(&parse, "copy_id")) { - e->copy_id = 1; - } else if(str_keyword(&parse, "copy_query")) { - e->copy_query = 1; - } else if(str_keyword(&parse, "copy_ednsdata_assume_clientsubnet")) { - e->copy_ednsdata_assume_clientsubnet = 1; - } else if(str_keyword(&parse, "sleep=")) { - e->sleeptime = (unsigned int) strtol(parse, (char**)&parse, 10); - while(isspace((unsigned char)*parse)) - parse++; - } else if(str_keyword(&parse, "packet_sleep=")) { - pkt->packet_sleep = (unsigned int) strtol(parse, (char**)&parse, 10); - while(isspace((unsigned char)*parse)) - parse++; - } else { - error("could not parse ADJUST: '%s'", parse); - } - } -} - -/** create new entry */ -static struct entry* new_entry(void) -{ - struct entry* e = (struct entry*)malloc(sizeof(struct entry)); - if(!e) error("out of memory"); - memset(e, 0, sizeof(*e)); - e->match_opcode = 0; - e->match_qtype = 0; - e->match_qname = 0; - e->match_rcode = 0; - e->match_question = 0; - e->match_answer = 0; - e->match_subdomain = 0; - e->match_all = 0; - e->match_ttl = 0; - e->match_do = 0; - e->match_noedns = 0; - e->match_serial = 0; - e->ixfr_soa_serial = 0; - e->match_transport = transport_any; - e->reply_list = NULL; - e->copy_id = 0; - e->copy_query = 0; - e->copy_ednsdata_assume_clientsubnet = 0; - e->sleeptime = 0; - e->next = NULL; - return e; -} - -/** - * Converts a hex string to binary data - * @param hexstr: string of hex. - * @param len: is the length of the string - * @param buf: is the buffer to store the result in - * @param offset: is the starting position in the result buffer - * @param buf_len: is the length of buf. - * @return This function returns the length of the result - */ -static size_t -hexstr2bin(char *hexstr, int len, uint8_t *buf, size_t offset, size_t buf_len) -{ - char c; - int i; - uint8_t int8 = 0; - int sec = 0; - size_t bufpos = 0; - - if (len % 2 != 0) { - return 0; - } - - for (i=0; i<len; i++) { - c = hexstr[i]; - - /* case insensitive, skip spaces */ - if (c != ' ') { - if (c >= '0' && c <= '9') { - int8 += c & 0x0f; - } else if (c >= 'a' && c <= 'z') { - int8 += (c & 0x0f) + 9; - } else if (c >= 'A' && c <= 'Z') { - int8 += (c & 0x0f) + 9; - } else { - return 0; - } - - if (sec == 0) { - int8 = int8 << 4; - sec = 1; - } else { - if (bufpos + offset + 1 <= buf_len) { - buf[bufpos+offset] = int8; - int8 = 0; - sec = 0; - bufpos++; - } else { - fprintf(stderr, "Buffer too small in hexstr2bin"); - } - } - } - } - return bufpos; -} - -/** convert hex buffer to binary buffer */ -static sldns_buffer * -hex_buffer2wire(sldns_buffer *data_buffer) -{ - sldns_buffer *wire_buffer = NULL; - int c; - - /* stat hack - * 0 = normal - * 1 = comment (skip to end of line) - * 2 = unprintable character found, read binary data directly - */ - size_t data_buf_pos = 0; - int state = 0; - uint8_t *hexbuf; - int hexbufpos = 0; - size_t wirelen; - uint8_t *data_wire = (uint8_t *) sldns_buffer_begin(data_buffer); - uint8_t *wire = (uint8_t*)malloc(MAX_PACKETLEN); - if(!wire) error("out of memory"); - - hexbuf = (uint8_t*)malloc(MAX_PACKETLEN); - if(!hexbuf) error("out of memory"); - for (data_buf_pos = 0; data_buf_pos < sldns_buffer_position(data_buffer); data_buf_pos++) { - c = (int) data_wire[data_buf_pos]; - - if (state < 2 && !isascii((unsigned char)c)) { - /*verbose("non ascii character found in file: (%d) switching to raw mode\n", c);*/ - state = 2; - } - switch (state) { - case 0: - if ( (c >= '0' && c <= '9') || - (c >= 'a' && c <= 'f') || - (c >= 'A' && c <= 'F') ) - { - if (hexbufpos >= MAX_PACKETLEN) { - error("buffer overflow"); - free(hexbuf); - return 0; - - } - hexbuf[hexbufpos] = (uint8_t) c; - hexbufpos++; - } else if (c == ';') { - state = 1; - } else if (c == ' ' || c == '\t' || c == '\n') { - /* skip whitespace */ - } - break; - case 1: - if (c == '\n' || c == EOF) { - state = 0; - } - break; - case 2: - if (hexbufpos >= MAX_PACKETLEN) { - error("buffer overflow"); - free(hexbuf); - return 0; - } - hexbuf[hexbufpos] = (uint8_t) c; - hexbufpos++; - break; - } - } - - if (hexbufpos >= MAX_PACKETLEN) { - /*verbose("packet size reached\n");*/ - } - - /* lenient mode: length must be multiple of 2 */ - if (hexbufpos % 2 != 0) { - if (hexbufpos >= MAX_PACKETLEN) { - error("buffer overflow"); - free(hexbuf); - return 0; - } - hexbuf[hexbufpos] = (uint8_t) '0'; - hexbufpos++; - } - - if (state < 2) { - wirelen = hexstr2bin((char *) hexbuf, hexbufpos, wire, 0, MAX_PACKETLEN); - wire_buffer = sldns_buffer_new(wirelen); - sldns_buffer_new_frm_data(wire_buffer, wire, wirelen); - } else { - error("Incomplete hex data, not at byte boundary\n"); - } - free(wire); - free(hexbuf); - return wire_buffer; -} - -/** parse ORIGIN */ -static void -get_origin(const char* name, struct sldns_file_parse_state* pstate, char* parse) -{ - /* snip off rest of the text so as to make the parse work in ldns */ - char* end; - char store; - int status; - - end=parse; - while(!isspace((unsigned char)*end) && !isendline(*end)) - end++; - store = *end; - *end = 0; - verbose(3, "parsing '%s'\n", parse); - status = sldns_str2wire_dname_buf(parse, pstate->origin, - &pstate->origin_len); - *end = store; - if(status != 0) - error("%s line %d:\n\t%s: %s", name, pstate->lineno, - sldns_get_errorstr_parse(status), parse); -} - -/** add RR to packet */ -static void add_rr(char* rrstr, uint8_t* pktbuf, size_t pktsize, - size_t* pktlen, struct sldns_file_parse_state* pstate, - sldns_pkt_section add_section, const char* fname) -{ - /* it must be a RR, parse and add to packet. */ - size_t rr_len = pktsize - *pktlen; - size_t dname_len = 0; - int status; - uint8_t* origin = pstate->origin_len?pstate->origin:0; - uint8_t* prev = pstate->prev_rr_len?pstate->prev_rr:0; - if(*pktlen > pktsize || *pktlen < LDNS_HEADER_SIZE) - error("packet overflow"); - - /* parse RR */ - if(add_section == LDNS_SECTION_QUESTION) - status = sldns_str2wire_rr_question_buf(rrstr, pktbuf+*pktlen, - &rr_len, &dname_len, origin, pstate->origin_len, - prev, pstate->prev_rr_len); - else status = sldns_str2wire_rr_buf(rrstr, pktbuf+*pktlen, &rr_len, - &dname_len, pstate->default_ttl, origin, - pstate->origin_len, prev, pstate->prev_rr_len); - if(status != 0) - error("%s line %d:%d %s\n\t%s", fname, pstate->lineno, - LDNS_WIREPARSE_OFFSET(status), - sldns_get_errorstr_parse(status), rrstr); - *pktlen += rr_len; - - /* increase RR count */ - if(add_section == LDNS_SECTION_QUESTION) - sldns_write_uint16(pktbuf+4, LDNS_QDCOUNT(pktbuf)+1); - else if(add_section == LDNS_SECTION_ANSWER) - sldns_write_uint16(pktbuf+6, LDNS_ANCOUNT(pktbuf)+1); - else if(add_section == LDNS_SECTION_AUTHORITY) - sldns_write_uint16(pktbuf+8, LDNS_NSCOUNT(pktbuf)+1); - else if(add_section == LDNS_SECTION_ADDITIONAL) - sldns_write_uint16(pktbuf+10, LDNS_ARCOUNT(pktbuf)+1); - else error("internal error bad section %d", (int)add_section); -} - -/* add EDNS 4096 opt record */ -static void -add_edns(uint8_t* pktbuf, size_t pktsize, int do_flag, uint8_t *ednsdata, - uint16_t ednslen, size_t* pktlen) -{ - uint8_t edns[] = {0x00, /* root label */ - 0x00, LDNS_RR_TYPE_OPT, /* type */ - 0x10, 0x00, /* class is UDPSIZE 4096 */ - 0x00, /* TTL[0] is ext rcode */ - 0x00, /* TTL[1] is edns version */ - (uint8_t)(do_flag?0x80:0x00), 0x00, /* TTL[2-3] is edns flags, DO */ - (uint8_t)((ednslen >> 8) & 0xff), - (uint8_t)(ednslen & 0xff), /* rdatalength */ - }; - if(*pktlen < LDNS_HEADER_SIZE) - return; - if(*pktlen + sizeof(edns) + ednslen > pktsize) - error("not enough space for EDNS OPT record"); - memmove(pktbuf+*pktlen, edns, sizeof(edns)); - memmove(pktbuf+*pktlen+sizeof(edns), ednsdata, ednslen); - sldns_write_uint16(pktbuf+10, LDNS_ARCOUNT(pktbuf)+1); - *pktlen += (sizeof(edns) + ednslen); -} - -/* Reads one entry from file. Returns entry or NULL on error. */ -struct entry* -read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate, - int skip_whitespace) -{ - struct entry* current = NULL; - char line[MAX_LINE]; - char* parse; - sldns_pkt_section add_section = LDNS_SECTION_QUESTION; - struct reply_packet *cur_reply = NULL; - int reading_hex = 0; - int reading_hex_ednsdata = 0; - sldns_buffer* hex_data_buffer = NULL; - sldns_buffer* hex_ednsdata_buffer = NULL; - uint8_t pktbuf[MAX_PACKETLEN]; - size_t pktlen = LDNS_HEADER_SIZE; - int do_flag = 0; /* DO flag in EDNS */ - memset(pktbuf, 0, pktlen); /* ID = 0, FLAGS="", and rr counts 0 */ - - while(fgets(line, (int)sizeof(line), in) != NULL) { - line[MAX_LINE-1] = 0; - parse = line; - pstate->lineno++; - - while(isspace((unsigned char)*parse)) - parse++; - /* test for keywords */ - if(isendline(*parse)) - continue; /* skip comment and empty lines */ - if(str_keyword(&parse, "ENTRY_BEGIN")) { - if(current) { - error("%s line %d: previous entry does not ENTRY_END", - name, pstate->lineno); - } - current = new_entry(); - current->lineno = pstate->lineno; - cur_reply = entry_add_reply(current); - continue; - } else if(str_keyword(&parse, "$ORIGIN")) { - get_origin(name, pstate, parse); - continue; - } else if(str_keyword(&parse, "$TTL")) { - pstate->default_ttl = (uint32_t)atoi(parse); - continue; - } - - /* working inside an entry */ - if(!current) { - error("%s line %d: expected ENTRY_BEGIN but got %s", - name, pstate->lineno, line); - } - if(str_keyword(&parse, "MATCH")) { - matchline(parse, current); - } else if(str_keyword(&parse, "REPLY")) { - replyline(parse, pktbuf, pktlen, &do_flag); - } else if(str_keyword(&parse, "ADJUST")) { - adjustline(parse, current, cur_reply); - } else if(str_keyword(&parse, "EXTRA_PACKET")) { - cur_reply = entry_add_reply(current); - } else if(str_keyword(&parse, "SECTION")) { - if(str_keyword(&parse, "QUESTION")) - add_section = LDNS_SECTION_QUESTION; - else if(str_keyword(&parse, "ANSWER")) - add_section = LDNS_SECTION_ANSWER; - else if(str_keyword(&parse, "AUTHORITY")) - add_section = LDNS_SECTION_AUTHORITY; - else if(str_keyword(&parse, "ADDITIONAL")) - add_section = LDNS_SECTION_ADDITIONAL; - else error("%s line %d: bad section %s", name, pstate->lineno, parse); - } else if(str_keyword(&parse, "HEX_ANSWER_BEGIN")) { - hex_data_buffer = sldns_buffer_new(MAX_PACKETLEN); - reading_hex = 1; - } else if(str_keyword(&parse, "HEX_ANSWER_END")) { - if(!reading_hex) { - error("%s line %d: HEX_ANSWER_END read but no HEX_ANSWER_BEGIN keyword seen", name, pstate->lineno); - } - reading_hex = 0; - cur_reply->reply_from_hex = hex_buffer2wire(hex_data_buffer); - sldns_buffer_free(hex_data_buffer); - hex_data_buffer = NULL; - } else if(reading_hex) { - sldns_buffer_printf(hex_data_buffer, "%s", line); - } else if(str_keyword(&parse, "HEX_EDNSDATA_BEGIN")) { - hex_ednsdata_buffer = sldns_buffer_new(MAX_PACKETLEN); - reading_hex_ednsdata = 1; - } else if(str_keyword(&parse, "HEX_EDNSDATA_END")) { - if (!reading_hex_ednsdata) { - error("%s line %d: HEX_EDNSDATA_END read but no" - "HEX_EDNSDATA_BEGIN keyword seen", name, pstate->lineno); - } - reading_hex_ednsdata = 0; - cur_reply->raw_ednsdata = hex_buffer2wire(hex_ednsdata_buffer); - sldns_buffer_free(hex_ednsdata_buffer); - hex_ednsdata_buffer = NULL; - } else if(reading_hex_ednsdata) { - sldns_buffer_printf(hex_ednsdata_buffer, "%s", line); - } else if(str_keyword(&parse, "ENTRY_END")) { - if(hex_data_buffer) - sldns_buffer_free(hex_data_buffer); - if(hex_ednsdata_buffer) - sldns_buffer_free(hex_ednsdata_buffer); - if(pktlen != 0) { - if(do_flag || cur_reply->raw_ednsdata) { - if(cur_reply->raw_ednsdata && - sldns_buffer_limit(cur_reply->raw_ednsdata)) - add_edns(pktbuf, sizeof(pktbuf), do_flag, - sldns_buffer_begin(cur_reply->raw_ednsdata), - (uint16_t)sldns_buffer_limit(cur_reply->raw_ednsdata), - &pktlen); - else - add_edns(pktbuf, sizeof(pktbuf), do_flag, - NULL, 0, &pktlen); - } - cur_reply->reply_pkt = memdup(pktbuf, pktlen); - cur_reply->reply_len = pktlen; - if(!cur_reply->reply_pkt) - error("out of memory"); - } - return current; - } else { - add_rr(skip_whitespace?parse:line, pktbuf, - sizeof(pktbuf), &pktlen, pstate, add_section, - name); - } - - } - if(reading_hex) { - error("%s: End of file reached while still reading hex, " - "missing HEX_ANSWER_END\n", name); - } - if(reading_hex_ednsdata) { - error("%s: End of file reached while still reading edns data, " - "missing HEX_EDNSDATA_END\n", name); - } - if(current) { - error("%s: End of file reached while reading entry. " - "missing ENTRY_END\n", name); - } - return 0; -} - -/* reads the canned reply file and returns a list of structs */ -struct entry* -read_datafile(const char* name, int skip_whitespace) -{ - struct entry* list = NULL; - struct entry* last = NULL; - struct entry* current = NULL; - FILE *in; - struct sldns_file_parse_state pstate; - int entry_num = 0; - memset(&pstate, 0, sizeof(pstate)); - - if((in=fopen(name, "r")) == NULL) { - error("could not open file %s: %s", name, strerror(errno)); - } - - while((current = read_entry(in, name, &pstate, skip_whitespace))) - { - if(last) - last->next = current; - else list = current; - last = current; - entry_num ++; - } - verbose(1, "%s: Read %d entries\n", prog_name, entry_num); - - fclose(in); - return list; -} - -/** get qtype from packet */ -static sldns_rr_type get_qtype(uint8_t* pkt, size_t pktlen) -{ - uint8_t* d; - size_t dl, sl=0; - char* snull = NULL; - if(pktlen < LDNS_HEADER_SIZE) - return 0; - if(LDNS_QDCOUNT(pkt) == 0) - return 0; - /* skip over dname with dname-scan routine */ - d = pkt+LDNS_HEADER_SIZE; - dl = pktlen-LDNS_HEADER_SIZE; - (void)sldns_wire2str_dname_scan(&d, &dl, &snull, &sl, pkt, pktlen); - if(dl < 2) - return 0; - return sldns_read_uint16(d); -} - -/** get qtype from packet */ -static size_t get_qname_len(uint8_t* pkt, size_t pktlen) -{ - uint8_t* d; - size_t dl, sl=0; - char* snull = NULL; - if(pktlen < LDNS_HEADER_SIZE) - return 0; - if(LDNS_QDCOUNT(pkt) == 0) - return 0; - /* skip over dname with dname-scan routine */ - d = pkt+LDNS_HEADER_SIZE; - dl = pktlen-LDNS_HEADER_SIZE; - (void)sldns_wire2str_dname_scan(&d, &dl, &snull, &sl, pkt, pktlen); - return pktlen-dl-LDNS_HEADER_SIZE; -} - -/** returns owner from packet */ -static uint8_t* get_qname(uint8_t* pkt, size_t pktlen) -{ - if(pktlen < LDNS_HEADER_SIZE) - return NULL; - if(LDNS_QDCOUNT(pkt) == 0) - return NULL; - return pkt+LDNS_HEADER_SIZE; -} - -/** returns opcode from packet */ -static int get_opcode(uint8_t* pkt, size_t pktlen) -{ - if(pktlen < LDNS_HEADER_SIZE) - return 0; - return (int)LDNS_OPCODE_WIRE(pkt); -} - -/** returns rcode from packet */ -static int get_rcode(uint8_t* pkt, size_t pktlen) -{ - if(pktlen < LDNS_HEADER_SIZE) - return 0; - return (int)LDNS_RCODE_WIRE(pkt); -} - -/** get authority section SOA serial value */ -static uint32_t get_serial(uint8_t* p, size_t plen) -{ - uint8_t* walk = p; - size_t walk_len = plen, sl=0; - char* snull = NULL; - uint16_t i; - - if(walk_len < LDNS_HEADER_SIZE) - return 0; - walk += LDNS_HEADER_SIZE; - walk_len -= LDNS_HEADER_SIZE; - - /* skip other records with wire2str_scan */ - for(i=0; i < LDNS_QDCOUNT(p); i++) - (void)sldns_wire2str_rrquestion_scan(&walk, &walk_len, - &snull, &sl, p, plen); - for(i=0; i < LDNS_ANCOUNT(p); i++) - (void)sldns_wire2str_rr_scan(&walk, &walk_len, &snull, &sl, - p, plen); - - /* walk through authority section */ - for(i=0; i < LDNS_NSCOUNT(p); i++) { - /* if this is SOA then get serial, skip compressed dname */ - uint8_t* dstart = walk; - size_t dlen = walk_len; - (void)sldns_wire2str_dname_scan(&dstart, &dlen, &snull, &sl, - p, plen); - if(dlen >= 2 && sldns_read_uint16(dstart) == LDNS_RR_TYPE_SOA) { - /* skip type, class, TTL, rdatalen */ - if(dlen < 10) - return 0; - if(dlen < 10 + (size_t)sldns_read_uint16(dstart+8)) - return 0; - dstart += 10; - dlen -= 10; - /* check third rdf */ - (void)sldns_wire2str_dname_scan(&dstart, &dlen, &snull, - &sl, p, plen); - (void)sldns_wire2str_dname_scan(&dstart, &dlen, &snull, - &sl, p, plen); - if(dlen < 4) - return 0; - verbose(3, "found serial %u in msg. ", - (int)sldns_read_uint32(dstart)); - return sldns_read_uint32(dstart); - } - /* move to next RR */ - (void)sldns_wire2str_rr_scan(&walk, &walk_len, &snull, &sl, - p, plen); - } - return 0; -} - -/** get ptr to EDNS OPT record (and remaining length); behind the type u16 */ -static int -pkt_find_edns_opt(uint8_t** p, size_t* plen) -{ - /* walk over the packet with scan routines */ - uint8_t* w = *p; - size_t wlen = *plen, sl=0; - char* snull = NULL; - uint16_t i; - - if(wlen < LDNS_HEADER_SIZE) - return 0; - w += LDNS_HEADER_SIZE; - wlen -= LDNS_HEADER_SIZE; - - /* skip other records with wire2str_scan */ - for(i=0; i < LDNS_QDCOUNT(*p); i++) - (void)sldns_wire2str_rrquestion_scan(&w, &wlen, &snull, &sl, - *p, *plen); - for(i=0; i < LDNS_ANCOUNT(*p); i++) - (void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen); - for(i=0; i < LDNS_NSCOUNT(*p); i++) - (void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen); - - /* walk through additional section */ - for(i=0; i < LDNS_ARCOUNT(*p); i++) { - /* if this is OPT then done */ - uint8_t* dstart = w; - size_t dlen = wlen; - (void)sldns_wire2str_dname_scan(&dstart, &dlen, &snull, &sl, - *p, *plen); - if(dlen >= 2 && sldns_read_uint16(dstart) == LDNS_RR_TYPE_OPT) { - *p = dstart+2; - *plen = dlen-2; - return 1; - } - /* move to next RR */ - (void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen); - } - return 0; -} - -/** return true if the packet has EDNS OPT record */ -static int -get_has_edns(uint8_t* pkt, size_t len) -{ - /* use arguments as temporary variables */ - return pkt_find_edns_opt(&pkt, &len); -} - -/** return true if the DO flag is set */ -static int -get_do_flag(uint8_t* pkt, size_t len) -{ - uint16_t edns_bits; - uint8_t* walk = pkt; - size_t walk_len = len; - if(!pkt_find_edns_opt(&walk, &walk_len)) { - return 0; - } - if(walk_len < 6) - return 0; /* malformed */ - edns_bits = sldns_read_uint16(walk+4); - return (int)(edns_bits&LDNS_EDNS_MASK_DO_BIT); -} - -/** zero TTLs in packet */ -static void -zerottls(uint8_t* pkt, size_t pktlen) -{ - uint8_t* walk = pkt; - size_t walk_len = pktlen, sl=0; - char* snull = NULL; - uint16_t i; - uint16_t num = LDNS_ANCOUNT(pkt)+LDNS_NSCOUNT(pkt)+LDNS_ARCOUNT(pkt); - if(walk_len < LDNS_HEADER_SIZE) - return; - walk += LDNS_HEADER_SIZE; - walk_len -= LDNS_HEADER_SIZE; - for(i=0; i < LDNS_QDCOUNT(pkt); i++) - (void)sldns_wire2str_rrquestion_scan(&walk, &walk_len, - &snull, &sl, pkt, pktlen); - for(i=0; i < num; i++) { - /* wipe TTL */ - uint8_t* dstart = walk; - size_t dlen = walk_len; - (void)sldns_wire2str_dname_scan(&dstart, &dlen, &snull, &sl, - pkt, pktlen); - if(dlen < 8) - return; - sldns_write_uint32(dstart+4, 0); - /* go to next RR */ - (void)sldns_wire2str_rr_scan(&walk, &walk_len, &snull, &sl, - pkt, pktlen); - } -} - -/** get one line (\n) from a string, move next to after the \n, zero \n */ -static int -get_line(char** s, char** n) -{ - /* at end of string? end */ - if(*n == NULL || **n == 0) - return 0; - /* result starts at next string */ - *s = *n; - /* find \n after that */ - *n = strchr(*s, '\n'); - if(*n && **n != 0) { - /* terminate line */ - (*n)[0] = 0; - (*n)++; - } - return 1; -} - -/** match two RR sections without ordering */ -static int -match_noloc_section(char** q, char** nq, char** p, char** np, uint16_t num) -{ - /* for max number of RRs in packet */ - const uint16_t numarray = 3000; - char* qlines[numarray], *plines[numarray]; - uint16_t i, j, numq=0, nump=0; - if(num > numarray) fatal_exit("too many RRs"); - /* gather lines */ - for(i=0; i<num; i++) { - get_line(q, nq); - get_line(p, np); - qlines[numq++] = *q; - plines[nump++] = *p; - } - /* see if they are all present in the other */ - for(i=0; i<num; i++) { - int found = 0; - for(j=0; j<num; j++) { - if(strcmp(qlines[i], plines[j]) == 0) { - found = 1; - break; - } - } - if(!found) { - verbose(3, "comparenoloc: failed for %s", qlines[i]); - return 0; - } - } - return 1; -} - -/** match two strings for unordered equality of RRs and everything else */ -static int -match_noloc(char* q, char* p, uint8_t* q_pkt, size_t q_pkt_len, - uint8_t* p_pkt, size_t p_pkt_len) -{ - char* nq = q, *np = p; - /* if no header, compare bytes */ - if(p_pkt_len < LDNS_HEADER_SIZE || q_pkt_len < LDNS_HEADER_SIZE) { - if(p_pkt_len != q_pkt_len) return 0; - return memcmp(p, q, p_pkt_len); - } - /* compare RR counts */ - if(LDNS_QDCOUNT(p_pkt) != LDNS_QDCOUNT(q_pkt)) - return 0; - if(LDNS_ANCOUNT(p_pkt) != LDNS_ANCOUNT(q_pkt)) - return 0; - if(LDNS_NSCOUNT(p_pkt) != LDNS_NSCOUNT(q_pkt)) - return 0; - if(LDNS_ARCOUNT(p_pkt) != LDNS_ARCOUNT(q_pkt)) - return 0; - /* get a line from both; compare; at sections do section */ - get_line(&q, &nq); - get_line(&p, &np); - if(strcmp(q, p) != 0) { - /* header line opcode, rcode, id */ - return 0; - } - get_line(&q, &nq); - get_line(&p, &np); - if(strcmp(q, p) != 0) { - /* header flags, rr counts */ - return 0; - } - /* ;; QUESTION SECTION */ - get_line(&q, &nq); - get_line(&p, &np); - if(strcmp(q, p) != 0) return 0; - if(!match_noloc_section(&q, &nq, &p, &np, LDNS_QDCOUNT(p_pkt))) - return 0; - - /* empty line and ;; ANSWER SECTION */ - get_line(&q, &nq); - get_line(&p, &np); - if(strcmp(q, p) != 0) return 0; - get_line(&q, &nq); - get_line(&p, &np); - if(strcmp(q, p) != 0) return 0; - if(!match_noloc_section(&q, &nq, &p, &np, LDNS_ANCOUNT(p_pkt))) - return 0; - - /* empty line and ;; AUTHORITY SECTION */ - get_line(&q, &nq); - get_line(&p, &np); - if(strcmp(q, p) != 0) return 0; - get_line(&q, &nq); - get_line(&p, &np); - if(strcmp(q, p) != 0) return 0; - if(!match_noloc_section(&q, &nq, &p, &np, LDNS_NSCOUNT(p_pkt))) - return 0; - - /* empty line and ;; ADDITIONAL SECTION */ - get_line(&q, &nq); - get_line(&p, &np); - if(strcmp(q, p) != 0) return 0; - get_line(&q, &nq); - get_line(&p, &np); - if(strcmp(q, p) != 0) return 0; - if(!match_noloc_section(&q, &nq, &p, &np, LDNS_ARCOUNT(p_pkt))) - return 0; - - return 1; -} - -/** lowercase domain name - does not follow compression pointers */ -static void lowercase_dname(uint8_t** p, size_t* remain) -{ - unsigned i, llen; - if(*remain == 0) return; - while(**p != 0) { - /* compressed? */ - if((**p & 0xc0) == 0xc0) { - *p += 2; - *remain -= 2; - return; - } - llen = (unsigned int)**p; - *p += 1; - *remain -= 1; - if(*remain < llen) - llen = (unsigned int)*remain; - for(i=0; i<llen; i++) { - (*p)[i] = (uint8_t)tolower((int)(*p)[i]); - } - *p += llen; - *remain -= llen; - if(*remain == 0) return; - } - /* skip root label */ - *p += 1; - *remain -= 1; -} - -/** lowercase rdata of type */ -static void lowercase_rdata(uint8_t** p, size_t* remain, - uint16_t rdatalen, uint16_t t) -{ - const sldns_rr_descriptor *desc = sldns_rr_descript(t); - uint8_t dname_count = 0; - size_t i = 0; - size_t rdataremain = rdatalen; - if(!desc) { - /* unknown type */ - *p += rdatalen; - *remain -= rdatalen; - return; - } - while(dname_count < desc->_dname_count) { - sldns_rdf_type f = sldns_rr_descriptor_field_type(desc, i++); - if(f == LDNS_RDF_TYPE_DNAME) { - lowercase_dname(p, &rdataremain); - dname_count++; - } else if(f == LDNS_RDF_TYPE_STR) { - uint8_t len; - if(rdataremain == 0) return; - len = **p; - *p += len+1; - rdataremain -= len+1; - } else { - int len = 0; - switch(f) { - case LDNS_RDF_TYPE_CLASS: - case LDNS_RDF_TYPE_ALG: - case LDNS_RDF_TYPE_INT8: - len = 1; - break; - case LDNS_RDF_TYPE_INT16: - case LDNS_RDF_TYPE_TYPE: - case LDNS_RDF_TYPE_CERT_ALG: - len = 2; - break; - case LDNS_RDF_TYPE_INT32: - case LDNS_RDF_TYPE_TIME: - case LDNS_RDF_TYPE_A: - case LDNS_RDF_TYPE_PERIOD: - len = 4; - break; - case LDNS_RDF_TYPE_TSIGTIME: - len = 6; - break; - case LDNS_RDF_TYPE_AAAA: - len = 16; - break; - default: error("bad rdf type in lowercase %d", (int)f); - } - *p += len; - rdataremain -= len; - } - } - /* skip remainder of rdata */ - *p += rdataremain; - *remain -= rdatalen; -} - -/** lowercase all names in the message */ -static void lowercase_pkt(uint8_t* pkt, size_t pktlen) -{ - uint16_t i; - uint8_t* p = pkt; - size_t remain = pktlen; - uint16_t t, rdatalen; - if(pktlen < LDNS_HEADER_SIZE) - return; - p += LDNS_HEADER_SIZE; - remain -= LDNS_HEADER_SIZE; - for(i=0; i<LDNS_QDCOUNT(pkt); i++) { - lowercase_dname(&p, &remain); - if(remain < 4) return; - p += 4; - remain -= 4; - } - for(i=0; i<LDNS_ANCOUNT(pkt)+LDNS_NSCOUNT(pkt)+LDNS_ARCOUNT(pkt); i++) { - lowercase_dname(&p, &remain); - if(remain < 10) return; - t = sldns_read_uint16(p); - rdatalen = sldns_read_uint16(p+8); - p += 10; - remain -= 10; - if(remain < rdatalen) return; - lowercase_rdata(&p, &remain, rdatalen, t); - } -} - -/** match question section of packet */ -static int -match_question(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl) -{ - char* qstr, *pstr, *s, *qcmpstr, *pcmpstr; - uint8_t* qb = q, *pb = p; - int r; - /* zero TTLs */ - qb = memdup(q, qlen); - pb = memdup(p, plen); - if(!qb || !pb) error("out of memory"); - if(!mttl) { - zerottls(qb, qlen); - zerottls(pb, plen); - } - lowercase_pkt(qb, qlen); - lowercase_pkt(pb, plen); - qstr = sldns_wire2str_pkt(qb, qlen); - pstr = sldns_wire2str_pkt(pb, plen); - if(!qstr || !pstr) error("cannot pkt2string"); - - /* remove before ;; QUESTION */ - s = strstr(qstr, ";; QUESTION SECTION"); - qcmpstr = s; - s = strstr(pstr, ";; QUESTION SECTION"); - pcmpstr = s; - if(!qcmpstr && !pcmpstr) { - free(qstr); - free(pstr); - free(qb); - free(pb); - return 1; - } - if(!qcmpstr || !pcmpstr) { - free(qstr); - free(pstr); - free(qb); - free(pb); - return 0; - } - - /* remove after answer section, (;; AUTH, ;; ADD, ;; MSG size ..) */ - s = strstr(qcmpstr, ";; ANSWER SECTION"); - if(!s) s = strstr(qcmpstr, ";; AUTHORITY SECTION"); - if(!s) s = strstr(qcmpstr, ";; ADDITIONAL SECTION"); - if(!s) s = strstr(qcmpstr, ";; MSG SIZE"); - if(s) *s = 0; - s = strstr(pcmpstr, ";; ANSWER SECTION"); - if(!s) s = strstr(pcmpstr, ";; AUTHORITY SECTION"); - if(!s) s = strstr(pcmpstr, ";; ADDITIONAL SECTION"); - if(!s) s = strstr(pcmpstr, ";; MSG SIZE"); - if(s) *s = 0; - - r = (strcmp(qcmpstr, pcmpstr) == 0); - - if(!r) { - verbose(3, "mismatch question section '%s' and '%s'", - qcmpstr, pcmpstr); - } - - free(qstr); - free(pstr); - free(qb); - free(pb); - return r; -} - -/** match answer section of packet */ -static int -match_answer(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl) -{ - char* qstr, *pstr, *s, *qcmpstr, *pcmpstr; - uint8_t* qb = q, *pb = p; - int r; - /* zero TTLs */ - qb = memdup(q, qlen); - pb = memdup(p, plen); - if(!qb || !pb) error("out of memory"); - if(!mttl) { - zerottls(qb, qlen); - zerottls(pb, plen); - } - lowercase_pkt(qb, qlen); - lowercase_pkt(pb, plen); - qstr = sldns_wire2str_pkt(qb, qlen); - pstr = sldns_wire2str_pkt(pb, plen); - if(!qstr || !pstr) error("cannot pkt2string"); - - /* remove before ;; ANSWER */ - s = strstr(qstr, ";; ANSWER SECTION"); - qcmpstr = s; - s = strstr(pstr, ";; ANSWER SECTION"); - pcmpstr = s; - if(!qcmpstr && !pcmpstr) { - free(qstr); - free(pstr); - free(qb); - free(pb); - return 1; - } - if(!qcmpstr || !pcmpstr) { - free(qstr); - free(pstr); - free(qb); - free(pb); - return 0; - } - - /* remove after answer section, (;; AUTH, ;; ADD, ;; MSG size ..) */ - s = strstr(qcmpstr, ";; AUTHORITY SECTION"); - if(!s) s = strstr(qcmpstr, ";; ADDITIONAL SECTION"); - if(!s) s = strstr(qcmpstr, ";; MSG SIZE"); - if(s) *s = 0; - s = strstr(pcmpstr, ";; AUTHORITY SECTION"); - if(!s) s = strstr(pcmpstr, ";; ADDITIONAL SECTION"); - if(!s) s = strstr(pcmpstr, ";; MSG SIZE"); - if(s) *s = 0; - - r = (strcmp(qcmpstr, pcmpstr) == 0); - - if(!r) { - verbose(3, "mismatch answer section '%s' and '%s'", - qcmpstr, pcmpstr); - } - - free(qstr); - free(pstr); - free(qb); - free(pb); - return r; -} - -/** match all of the packet */ -int -match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl, - int noloc) -{ - char* qstr, *pstr; - uint8_t* qb = q, *pb = p; - int r; - /* zero TTLs */ - qb = memdup(q, qlen); - pb = memdup(p, plen); - if(!qb || !pb) error("out of memory"); - if(!mttl) { - zerottls(qb, qlen); - zerottls(pb, plen); - } - lowercase_pkt(qb, qlen); - lowercase_pkt(pb, plen); - qstr = sldns_wire2str_pkt(qb, qlen); - pstr = sldns_wire2str_pkt(pb, plen); - if(!qstr || !pstr) error("cannot pkt2string"); - r = (strcmp(qstr, pstr) == 0); - if(!r) { - /* remove ;; MSG SIZE (at end of string) */ - char* s = strstr(qstr, ";; MSG SIZE"); - if(s) *s=0; - s = strstr(pstr, ";; MSG SIZE"); - if(s) *s=0; - r = (strcmp(qstr, pstr) == 0); - if(!r && !noloc) { - /* we are going to fail see if it is because of EDNS */ - char* a = strstr(qstr, "; EDNS"); - char* b = strstr(pstr, "; EDNS"); - if( (a&&!b) || (b&&!a) ) { - verbose(3, "mismatch in EDNS\n"); - } - } - } - if(!r && noloc) { - /* check for reordered sections */ - r = match_noloc(qstr, pstr, q, qlen, p, plen); - } - if(!r) { - verbose(3, "mismatch pkt '%s' and '%s'", qstr, pstr); - } - free(qstr); - free(pstr); - free(qb); - free(pb); - return r; -} - -/** see if domain names are equal */ -static int equal_dname(uint8_t* q, size_t qlen, uint8_t* p, size_t plen) -{ - uint8_t* qn = get_qname(q, qlen); - uint8_t* pn = get_qname(p, plen); - char qs[512], ps[512]; - size_t qslen = sizeof(qs), pslen = sizeof(ps); - char* qss = qs, *pss = ps; - if(!qn || !pn) - return 0; - (void)sldns_wire2str_dname_scan(&qn, &qlen, &qss, &qslen, q, qlen); - (void)sldns_wire2str_dname_scan(&pn, &plen, &pss, &pslen, p, plen); - return (strcmp(qs, ps) == 0); -} - -/** see if domain names are subdomain q of p */ -static int subdomain_dname(uint8_t* q, size_t qlen, uint8_t* p, size_t plen) -{ - /* we use the tostring routines so as to test unbound's routines - * with something else */ - uint8_t* qn = get_qname(q, qlen); - uint8_t* pn = get_qname(p, plen); - char qs[5120], ps[5120]; - size_t qslen = sizeof(qs), pslen = sizeof(ps); - char* qss = qs, *pss = ps; - if(!qn || !pn) - return 0; - /* decompresses domain names */ - (void)sldns_wire2str_dname_scan(&qn, &qlen, &qss, &qslen, q, qlen); - (void)sldns_wire2str_dname_scan(&pn, &plen, &pss, &pslen, p, plen); - /* same: false, (strict subdomain check)??? */ - if(strcmp(qs, ps) == 0) - return 1; - /* qs must end in ps, at a dot, without \ in front */ - qslen = strlen(qs); - pslen = strlen(ps); - if(qslen > pslen && strcmp(qs + (qslen-pslen), ps) == 0 && - qslen + 2 >= pslen && /* space for label and dot */ - qs[qslen-pslen-1] == '.') { - unsigned int slashcount = 0; - size_t i = qslen-pslen-2; - while(i>0 && qs[i]=='\\') { - i++; - slashcount++; - } - if(slashcount%1 == 1) return 0; /* . preceded by \ */ - return 1; - } - return 0; -} - -/** Match OPT RDATA (not the EDNS payload size or flags) */ -static int -match_ednsdata(uint8_t* q, size_t qlen, uint8_t* p, size_t plen) -{ - uint8_t* walk_q = q; - size_t walk_qlen = qlen; - uint8_t* walk_p = p; - size_t walk_plen = plen; - - if(!pkt_find_edns_opt(&walk_q, &walk_qlen)) - walk_qlen = 0; - if(!pkt_find_edns_opt(&walk_p, &walk_plen)) - walk_plen = 0; - - /* class + ttl + rdlen = 8 */ - if(walk_qlen <= 8 && walk_plen <= 8) { - verbose(3, "NO edns opt, move on"); - return 1; - } - if(walk_qlen != walk_plen) - return 0; - - return (memcmp(walk_p+8, walk_q+8, walk_qlen-8) == 0); -} - -/* finds entry in list, or returns NULL */ -struct entry* -find_match(struct entry* entries, uint8_t* query_pkt, size_t len, - enum transport_type transport) -{ - struct entry* p = entries; - uint8_t* reply; - size_t rlen; - for(p=entries; p; p=p->next) { - verbose(3, "comparepkt: "); - reply = p->reply_list->reply_pkt; - rlen = p->reply_list->reply_len; - if(p->match_opcode && get_opcode(query_pkt, len) != - get_opcode(reply, rlen)) { - verbose(3, "bad opcode\n"); - continue; - } - if(p->match_qtype && get_qtype(query_pkt, len) != - get_qtype(reply, rlen)) { - verbose(3, "bad qtype %d %d\n", get_qtype(query_pkt, len), get_qtype(reply, rlen)); - continue; - } - if(p->match_qname) { - if(!equal_dname(query_pkt, len, reply, rlen)) { - verbose(3, "bad qname\n"); - continue; - } - } - if(p->match_rcode) { - if(get_rcode(query_pkt, len) != get_rcode(reply, rlen)) { - char *r1 = sldns_wire2str_rcode(get_rcode(query_pkt, len)); - char *r2 = sldns_wire2str_rcode(get_rcode(reply, rlen)); - verbose(3, "bad rcode %s instead of %s\n", - r1, r2); - free(r1); - free(r2); - continue; - } - } - if(p->match_question) { - if(!match_question(query_pkt, len, reply, rlen, - (int)p->match_ttl)) { - verbose(3, "bad question section\n"); - continue; - } - } - if(p->match_answer) { - if(!match_answer(query_pkt, len, reply, rlen, - (int)p->match_ttl)) { - verbose(3, "bad answer section\n"); - continue; - } - } - if(p->match_subdomain) { - if(!subdomain_dname(query_pkt, len, reply, rlen)) { - verbose(3, "bad subdomain\n"); - continue; - } - } - if(p->match_serial && get_serial(query_pkt, len) != p->ixfr_soa_serial) { - verbose(3, "bad serial\n"); - continue; - } - if(p->match_do && !get_do_flag(query_pkt, len)) { - verbose(3, "no DO bit set\n"); - continue; - } - if(p->match_noedns && get_has_edns(query_pkt, len)) { - verbose(3, "bad; EDNS OPT present\n"); - continue; - } - if(p->match_ednsdata_raw && - !match_ednsdata(query_pkt, len, reply, rlen)) { - verbose(3, "bad EDNS data match.\n"); - continue; - } - if(p->match_transport != transport_any && p->match_transport != transport) { - verbose(3, "bad transport\n"); - continue; - } - if(p->match_all && !match_all(query_pkt, len, reply, rlen, - (int)p->match_ttl, 0)) { - verbose(3, "bad allmatch\n"); - continue; - } - verbose(3, "match!\n"); - return p; - } - return NULL; -} - -void -adjust_packet(struct entry* match, uint8_t** answer_pkt, size_t *answer_len, - uint8_t* query_pkt, size_t query_len) -{ - uint8_t* orig = *answer_pkt; - size_t origlen = *answer_len; - uint8_t* res; - size_t reslen; - - /* perform the copy; if possible; must be uncompressed */ - if(match->copy_query && origlen >= LDNS_HEADER_SIZE && - query_len >= LDNS_HEADER_SIZE && LDNS_QDCOUNT(query_pkt)!=0 - && LDNS_QDCOUNT(orig)==0) { - /* no qname in output packet, insert it */ - size_t dlen = get_qname_len(query_pkt, query_len); - reslen = origlen + dlen + 4; - res = (uint8_t*)malloc(reslen); - if(!res) { - verbose(1, "out of memory; send without adjust\n"); - return; - } - /* copy the header, query, remainder */ - memcpy(res, orig, LDNS_HEADER_SIZE); - memmove(res+LDNS_HEADER_SIZE, query_pkt+LDNS_HEADER_SIZE, - dlen+4); - memmove(res+LDNS_HEADER_SIZE+dlen+4, orig+LDNS_HEADER_SIZE, - reslen-(LDNS_HEADER_SIZE+dlen+4)); - /* set QDCOUNT */ - sldns_write_uint16(res+4, 1); - } else if(match->copy_query && origlen >= LDNS_HEADER_SIZE && - query_len >= LDNS_HEADER_SIZE && LDNS_QDCOUNT(query_pkt)!=0 - && get_qname_len(orig, origlen) == 0) { - /* QDCOUNT(orig)!=0 but qlen == 0, therefore, an error */ - verbose(1, "error: malformed qname; send without adjust\n"); - res = memdup(orig, origlen); - reslen = origlen; - } else if(match->copy_query && origlen >= LDNS_HEADER_SIZE && - query_len >= LDNS_HEADER_SIZE && LDNS_QDCOUNT(query_pkt)!=0 - && LDNS_QDCOUNT(orig)!=0) { - /* in this case olen != 0 and QDCOUNT(orig)!=0 */ - /* copy query section */ - size_t dlen = get_qname_len(query_pkt, query_len); - size_t olen = get_qname_len(orig, origlen); - reslen = origlen + dlen - olen; - res = (uint8_t*)malloc(reslen); - if(!res) { - verbose(1, "out of memory; send without adjust\n"); - return; - } - /* copy the header, query, remainder */ - memcpy(res, orig, LDNS_HEADER_SIZE); - memmove(res+LDNS_HEADER_SIZE, query_pkt+LDNS_HEADER_SIZE, - dlen+4); - memmove(res+LDNS_HEADER_SIZE+dlen+4, - orig+LDNS_HEADER_SIZE+olen+4, - reslen-(LDNS_HEADER_SIZE+dlen+4)); - } else { - res = memdup(orig, origlen); - reslen = origlen; - } - if(!res) { - verbose(1, "out of memory; send without adjust\n"); - return; - } - /* copy the ID */ - if(match->copy_id && reslen >= 2) - res[1] = orig[1]; - if(match->copy_id && reslen >= 1) - res[0] = orig[0]; - - if(match->copy_ednsdata_assume_clientsubnet) { - /** Assume there is only one EDNS option, which is ECS. - * Copy source mask from query to scope mask in reply. Assume - * rest of ECS data in response (eg address) matches the query. - */ - uint8_t* walk_q = orig; - size_t walk_qlen = origlen; - uint8_t* walk_p = res; - size_t walk_plen = reslen; - - if(!pkt_find_edns_opt(&walk_q, &walk_qlen)) { - walk_qlen = 0; - } - if(!pkt_find_edns_opt(&walk_p, &walk_plen)) { - walk_plen = 0; - } - /* class + ttl + rdlen + optcode + optlen + ecs fam + ecs source - * + ecs scope = index 15 */ - if(walk_qlen >= 15 && walk_plen >= 15) { - walk_p[15] = walk_q[14]; - } - } - - if(match->sleeptime > 0) { - verbose(3, "sleeping for %d seconds\n", match->sleeptime); -#ifdef HAVE_SLEEP - sleep(match->sleeptime); -#else - Sleep(match->sleeptime * 1000); -#endif - } - *answer_pkt = res; - *answer_len = reslen; -} - -/* - * Parses data buffer to a query, finds the correct answer - * and calls the given function for every packet to send. - */ -void -handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries, int* count, - enum transport_type transport, void (*sendfunc)(uint8_t*, size_t, void*), - void* userdata, FILE* verbose_out) -{ - struct reply_packet *p; - uint8_t *outbuf = NULL; - size_t outlen = 0; - struct entry* entry = NULL; - - verbose(1, "query %d: id %d: %s %d bytes: ", ++(*count), - (int)(inlen>=2?LDNS_ID_WIRE(inbuf):0), - (transport==transport_tcp)?"TCP":"UDP", (int)inlen); - if(verbose_out) { - char* out = sldns_wire2str_pkt(inbuf, (size_t)inlen); - printf("%s\n", out); - free(out); - } - - /* fill up answer packet */ - entry = find_match(entries, inbuf, (size_t)inlen, transport); - if(!entry || !entry->reply_list) { - verbose(1, "no answer packet for this query, no reply.\n"); - return; - } - for(p = entry->reply_list; p; p = p->next) - { - verbose(3, "Answer pkt:\n"); - if (p->reply_from_hex) { - /* try to adjust the hex packet, if it can be - * parsed, we can use adjust rules. if not, - * send packet literally */ - /* still try to adjust ID if others fail */ - outlen = sldns_buffer_limit(p->reply_from_hex); - outbuf = sldns_buffer_begin(p->reply_from_hex); - } else { - outbuf = p->reply_pkt; - outlen = p->reply_len; - } - if(!outbuf) { - verbose(1, "out of memory\n"); - return; - } - /* copies outbuf in memory allocation */ - adjust_packet(entry, &outbuf, &outlen, inbuf, (size_t)inlen); - verbose(1, "Answer packet size: %u bytes.\n", (unsigned int)outlen); - if(verbose_out) { - char* out = sldns_wire2str_pkt(outbuf, outlen); - printf("%s\n", out); - free(out); - } - if(p->packet_sleep) { - verbose(3, "sleeping for next packet %d secs\n", - p->packet_sleep); -#ifdef HAVE_SLEEP - sleep(p->packet_sleep); -#else - Sleep(p->packet_sleep * 1000); -#endif - verbose(3, "wakeup for next packet " - "(slept %d secs)\n", p->packet_sleep); - } - sendfunc(outbuf, outlen, userdata); - free(outbuf); - outbuf = NULL; - outlen = 0; - } -} - -/** delete the list of reply packets */ -void delete_replylist(struct reply_packet* replist) -{ - struct reply_packet *p=replist, *np; - while(p) { - np = p->next; - free(p->reply_pkt); - sldns_buffer_free(p->reply_from_hex); - sldns_buffer_free(p->raw_ednsdata); - free(p); - p=np; - } -} - -void delete_entry(struct entry* list) -{ - struct entry *p=list, *np; - while(p) { - np = p->next; - delete_replylist(p->reply_list); - free(p); - p = np; - } -} diff --git a/external/unbound/testcode/testpkts.h b/external/unbound/testcode/testpkts.h deleted file mode 100644 index b175cab06..000000000 --- a/external/unbound/testcode/testpkts.h +++ /dev/null @@ -1,290 +0,0 @@ -/* - * testpkts. Data file parse for test packets, and query matching. - * - * Data storage for specially crafted replies for testing purposes. - * - * (c) NLnet Labs, 2005, 2006, 2007 - * See the file LICENSE for the license - */ - -#ifndef TESTPKTS_H -#define TESTPKTS_H -struct sldns_buffer; -struct sldns_file_parse_state; - -/** - * \file - * - * This is a debugging aid. It is not efficient, especially - * with a long config file, but it can give any reply to any query. - * This can help the developer pre-script replies for queries. - * - * You can specify a packet RR by RR with header flags to return. - * - * Missing features: - * - matching content different from reply content. - * - find way to adjust mangled packets? - * - */ - - /* - The data file format is as follows: - - ; comment. - ; a number of entries, these are processed first to last. - ; a line based format. - - $ORIGIN origin - $TTL default_ttl - - ENTRY_BEGIN - ; first give MATCH lines, that say what queries are matched - ; by this entry. - ; 'opcode' makes the query match the opcode from the reply - ; if you leave it out, any opcode matches this entry. - ; 'qtype' makes the query match the qtype from the reply - ; 'qname' makes the query match the qname from the reply - ; 'subdomain' makes the query match subdomains of qname from the reply - ; 'serial=1023' makes the query match if ixfr serial is 1023. - ; 'all' has to match header byte for byte and all rrs in packet. - ; 'ttl' used with all, rrs in packet must also have matching TTLs. - ; 'DO' will match only queries with DO bit set. - ; 'noedns' matches queries without EDNS OPT records. - ; 'rcode' makes the query match the rcode from the reply - ; 'question' makes the query match the question section - ; 'answer' makes the query match the answer section - ; 'ednsdata' matches queries to HEX_EDNS section. - MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl] - MATCH [UDP|TCP] DO - MATCH ... - ; Then the REPLY header is specified. - REPLY opcode, rcode or flags. - (opcode) QUERY IQUERY STATUS NOTIFY UPDATE - (rcode) NOERROR FORMERR SERVFAIL NXDOMAIN NOTIMPL YXDOMAIN - YXRRSET NXRRSET NOTAUTH NOTZONE - (flags) QR AA TC RD CD RA AD DO - REPLY ... - ; any additional actions to do. - ; 'copy_id' copies the ID from the query to the answer. - ADJUST copy_id - ; 'copy_query' copies the query name, type and class to the answer. - ADJUST copy_query - ; 'sleep=10' sleeps for 10 seconds before giving the answer (TCP is open) - ADJUST [sleep=<num>] ; sleep before giving any reply - ADJUST [packet_sleep=<num>] ; sleep before this packet in sequence - SECTION QUESTION - <RRs, one per line> ; the RRcount is determined automatically. - SECTION ANSWER - <RRs, one per line> - SECTION AUTHORITY - <RRs, one per line> - SECTION ADDITIONAL - <RRs, one per line> - EXTRA_PACKET ; follow with SECTION, REPLY for more packets. - HEX_ANSWER_BEGIN ; follow with hex data - ; this replaces any answer packet constructed - ; with the SECTION keywords (only SECTION QUERY - ; is used to match queries). If the data cannot - ; be parsed, ADJUST rules for the answer packet - ; are ignored. Only copy_id is done. - HEX_ANSWER_END - HEX_EDNS_BEGIN ; follow with hex data. - ; Raw EDNS data to match against. It must be an - ; exact match (all options are matched) and will be - ; evaluated only when 'MATCH ednsdata' given. - HEX_EDNS_END - ENTRY_END - - - Example data file: -$ORIGIN nlnetlabs.nl -$TTL 3600 - -ENTRY_BEGIN -MATCH qname -REPLY NOERROR -ADJUST copy_id -SECTION QUESTION -www.nlnetlabs.nl. IN A -SECTION ANSWER -www.nlnetlabs.nl. IN A 195.169.215.155 -SECTION AUTHORITY -nlnetlabs.nl. IN NS www.nlnetlabs.nl. -ENTRY_END - -ENTRY_BEGIN -MATCH qname -REPLY NOERROR -ADJUST copy_id -SECTION QUESTION -www2.nlnetlabs.nl. IN A -HEX_ANSWER_BEGIN -; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 -;-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- - 00 bf 81 80 00 01 00 01 00 02 00 02 03 77 77 77 0b 6b 61 6e ; 1- 20 - 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 00 01 03 77 77 ; 21- 40 - 77 0b 6b 61 6e 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 01 ; 41- 60 - 00 01 00 01 50 8b 00 04 52 5e ed 32 0b 6b 61 6e 61 72 69 65 ; 61- 80 - 70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 8b 00 11 03 ; 81- 100 - 6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 0b 6b 61 6e ; 101- 120 - 61 72 69 65 70 69 65 74 03 63 6f 6d 00 00 02 00 01 00 01 50 ; 121- 140 - 8b 00 11 03 6e 73 32 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 ; 141- 160 - 03 6e 73 31 08 68 65 78 6f 6e 2d 69 73 02 6e 6c 00 00 01 00 ; 161- 180 - 01 00 00 46 53 00 04 52 5e ed 02 03 6e 73 32 08 68 65 78 6f ; 181- 200 - 6e 2d 69 73 02 6e 6c 00 00 01 00 01 00 00 46 53 00 04 d4 cc ; 201- 220 - db 5b -HEX_ANSWER_END -ENTRY_END - - - - note that this file will link with your - void verbose(int level, char* format, ...); output function. -*/ - -/** Type of transport, since some entries match based on UDP or TCP of query */ -enum transport_type {transport_any = 0, transport_udp, transport_tcp }; - -/** struct to keep a linked list of reply packets for a query */ -struct reply_packet { - /** next in list of reply packets, for TCP multiple pkts on wire */ - struct reply_packet* next; - /** the reply pkt */ - uint8_t* reply_pkt; - /** length of reply pkt */ - size_t reply_len; - /** Additional EDNS data for matching queries. */ - struct sldns_buffer* raw_ednsdata; - /** or reply pkt in hex if not parsable */ - struct sldns_buffer* reply_from_hex; - /** seconds to sleep before giving packet */ - unsigned int packet_sleep; -}; - -/** data structure to keep the canned queries in. - format is the 'matching query' and the 'canned answer' */ -struct entry { - /* match */ - /* How to match an incoming query with this canned reply */ - /** match query opcode with answer opcode */ - uint8_t match_opcode; - /** match qtype with answer qtype */ - uint8_t match_qtype; - /** match qname with answer qname */ - uint8_t match_qname; - /** match rcode with answer rcode */ - uint8_t match_rcode; - /** match question section */ - uint8_t match_question; - /** match answer section */ - uint8_t match_answer; - /** match qname as subdomain of answer qname */ - uint8_t match_subdomain; - /** match SOA serial number, from auth section */ - uint8_t match_serial; - /** match all of the packet */ - uint8_t match_all; - /** match ttls in the packet */ - uint8_t match_ttl; - /** match DO bit */ - uint8_t match_do; - /** match absence of EDNS OPT record in query */ - uint8_t match_noedns; - /** match edns data field given in hex */ - uint8_t match_ednsdata_raw; - /** match query serial with this value. */ - uint32_t ixfr_soa_serial; - /** match on UDP/TCP */ - enum transport_type match_transport; - - /** pre canned reply */ - struct reply_packet *reply_list; - - /** how to adjust the reply packet */ - /** copy over the ID from the query into the answer */ - uint8_t copy_id; - /** copy the query nametypeclass from query into the answer */ - uint8_t copy_query; - /** copy ednsdata to reply, assume it is clientsubnet and - * adjust scopemask to match sourcemask */ - uint8_t copy_ednsdata_assume_clientsubnet; - /** in seconds */ - unsigned int sleeptime; - - /** some number that names this entry, line number in file or so */ - int lineno; - - /** next in list */ - struct entry* next; -}; - -/** - * reads the canned reply file and returns a list of structs - * does an exit on error. - * @param name: name of the file to read. - * @param skip_whitespace: skip leftside whitespace. - */ -struct entry* read_datafile(const char* name, int skip_whitespace); - -/** - * Delete linked list of entries. - */ -void delete_entry(struct entry* list); - -/** - * Read one entry from the data file. - * @param in: file to read from. Filepos must be at the start of a new line. - * @param name: name of the file for prettier errors. - * @param pstate: file parse state with lineno, default_ttl, - * origin and prev_rr name. - * @param skip_whitespace: skip leftside whitespace. - * @return: The entry read (malloced) or NULL if no entry could be read. - */ -struct entry* read_entry(FILE* in, const char* name, - struct sldns_file_parse_state* pstate, int skip_whitespace); - -/** - * finds entry in list, or returns NULL. - */ -struct entry* find_match(struct entry* entries, uint8_t* query_pkt, - size_t query_pkt_len, enum transport_type transport); - -/** - * match two packets, all must match - * @param q: packet 1 - * @param qlen: length of q. - * @param p: packet 2 - * @param plen: length of p. - * @param mttl: if true, ttls must match, if false, ttls do not need to match - * @param noloc: if true, rrs may be reordered in their packet-section. - * rrs are then matches without location of the rr being important. - * @return true if matched. - */ -int match_all(uint8_t* q, size_t qlen, uint8_t* p, size_t plen, int mttl, - int noloc); - -/** - * copy & adjust packet, mallocs a copy. - */ -void adjust_packet(struct entry* match, uint8_t** answer_pkt, - size_t* answer_pkt_len, uint8_t* query_pkt, size_t query_pkt_len); - -/** - * Parses data buffer to a query, finds the correct answer - * and calls the given function for every packet to send. - * if verbose_out filename is given, packets are dumped there. - * @param inbuf: the packet that came in - * @param inlen: length of packet. - * @param entries: entries read in from datafile. - * @param count: is increased to count number of queries answered. - * @param transport: set to UDP or TCP to match some types of entries. - * @param sendfunc: called to send answer (buffer, size, userarg). - * @param userdata: userarg to give to sendfunc. - * @param verbose_out: if not NULL, verbose messages are printed there. - */ -void handle_query(uint8_t* inbuf, ssize_t inlen, struct entry* entries, - int* count, enum transport_type transport, - void (*sendfunc)(uint8_t*, size_t, void*), void* userdata, - FILE* verbose_out); - -#endif /* TESTPKTS_H */ diff --git a/external/unbound/testcode/unitanchor.c b/external/unbound/testcode/unitanchor.c deleted file mode 100644 index 8819c5ab6..000000000 --- a/external/unbound/testcode/unitanchor.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * testcode/unitanchor.c - unit test for trust anchor storage. - * - * 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 - * Calls trust anchor unit tests. Exits with code 1 on a failure. - */ - -#include "config.h" -#include "util/log.h" -#include "util/data/dname.h" -#include "testcode/unitmain.h" -#include "validator/val_anchor.h" -#include "sldns/sbuffer.h" -#include "sldns/rrdef.h" - -/** test empty set */ -static void -test_anchor_empty(struct val_anchors* a) -{ - uint16_t c = LDNS_RR_CLASS_IN; - unit_assert(anchors_lookup(a, (uint8_t*)"\000", 1, c) == NULL); - unit_assert(anchors_lookup(a, (uint8_t*)"\003com\000", 5, c) == NULL); - unit_assert(anchors_lookup(a, - (uint8_t*)"\007example\003com\000", 11, c) == NULL); - unit_assert(anchors_lookup(a, (uint8_t*)"\002nl\000", 4, c) == NULL); - unit_assert(anchors_lookup(a, - (uint8_t*)"\004labs\002nl\000", 9, c) == NULL); - unit_assert(anchors_lookup(a, - (uint8_t*)"\004fabs\002nl\000", 9, c) == NULL); -} - -/** test set of one anchor */ -static void -test_anchor_one(sldns_buffer* buff, struct val_anchors* a) -{ - struct trust_anchor* ta; - uint16_t c = LDNS_RR_CLASS_IN; - unit_assert(anchor_store_str(a, buff, - "nl. DS 42860 5 1 14D739EB566D2B1A5E216A0BA4D17FA9B038BE4A")); - unit_assert(anchors_lookup(a, (uint8_t*)"\000", 1, c) == NULL); - unit_assert(anchors_lookup(a, (uint8_t*)"\003com\000", 5, c) == NULL); - unit_assert(anchors_lookup(a, - (uint8_t*)"\007example\003com\000", 11, c) == NULL); - - unit_assert((ta=anchors_lookup(a, - (uint8_t*)"\002nl\000", 4, c)) != NULL); - lock_basic_unlock(&ta->lock); - - unit_assert((ta=anchors_lookup(a, - (uint8_t*)"\004labs\002nl\000", 9, c)) != NULL); - lock_basic_unlock(&ta->lock); - - unit_assert((ta=anchors_lookup(a, - (uint8_t*)"\004fabs\002nl\000", 9, c)) != NULL); - lock_basic_unlock(&ta->lock); - - unit_assert(anchors_lookup(a, (uint8_t*)"\002oo\000", 4, c) == NULL); -} - -/** test with several anchors */ -static void -test_anchors(sldns_buffer* buff, struct val_anchors* a) -{ - struct trust_anchor* ta; - uint16_t c = LDNS_RR_CLASS_IN; - unit_assert(anchor_store_str(a, buff, - "labs.nl. DS 42860 5 1 14D739EB566D2B1A5E216A0BA4D17FA9B038BE4A")); - unit_assert(anchors_lookup(a, (uint8_t*)"\000", 1, c) == NULL); - unit_assert(anchors_lookup(a, (uint8_t*)"\003com\000", 5, c) == NULL); - unit_assert(anchors_lookup(a, - (uint8_t*)"\007example\003com\000", 11, c) == NULL); - - unit_assert(ta = anchors_lookup(a, (uint8_t*)"\002nl\000", 4, c)); - unit_assert(query_dname_compare(ta->name, (uint8_t*)"\002nl\000")==0); - lock_basic_unlock(&ta->lock); - - unit_assert(ta = anchors_lookup(a, - (uint8_t*)"\004labs\002nl\000", 9, c)); - unit_assert(query_dname_compare(ta->name, - (uint8_t*)"\004labs\002nl\000") == 0); - lock_basic_unlock(&ta->lock); - - unit_assert(ta = anchors_lookup(a, - (uint8_t*)"\004fabs\002nl\000", 9, c)); - unit_assert(query_dname_compare(ta->name, - (uint8_t*)"\002nl\000") == 0); - lock_basic_unlock(&ta->lock); - - unit_assert(anchors_lookup(a, (uint8_t*)"\002oo\000", 4, c) == NULL); -} - -void anchors_test(void) -{ - sldns_buffer* buff = sldns_buffer_new(65800); - struct val_anchors* a; - unit_show_feature("trust anchor store"); - unit_assert(a = anchors_create()); - sldns_buffer_flip(buff); - test_anchor_empty(a); - test_anchor_one(buff, a); - test_anchors(buff, a); - anchors_delete(a); - sldns_buffer_free(buff); -} diff --git a/external/unbound/testcode/unitdname.c b/external/unbound/testcode/unitdname.c deleted file mode 100644 index 238c3edf7..000000000 --- a/external/unbound/testcode/unitdname.c +++ /dev/null @@ -1,861 +0,0 @@ -/* - * testcode/unitdname.c - unit test for dname 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 - * Calls dname unit tests. Exits with code 1 on a failure. - */ - -#include "config.h" -#include "util/log.h" -#include "testcode/unitmain.h" -#include "util/data/dname.h" -#include "sldns/sbuffer.h" -#include "sldns/str2wire.h" - -/** put dname into buffer */ -static sldns_buffer* -dname_to_buf(sldns_buffer* b, const char* str) -{ - int e; - size_t len = sldns_buffer_capacity(b); - sldns_buffer_clear(b); - e = sldns_str2wire_dname_buf(str, sldns_buffer_begin(b), &len); - if(e != 0) - fatal_exit("%s ldns: %s", __func__, - sldns_get_errorstr_parse(e)); - sldns_buffer_set_position(b, len); - sldns_buffer_flip(b); - return b; -} - -/** test query_dname_len function */ -static void -dname_test_qdl(sldns_buffer* buff) -{ - unit_show_func("util/data/dname.c", "query_dname_len"); - unit_assert( query_dname_len(buff) == 0); - unit_assert( query_dname_len(dname_to_buf(buff, ".")) == 1 ); - unit_assert( query_dname_len(dname_to_buf(buff, "bla.foo.")) == 9 ); - unit_assert( query_dname_len(dname_to_buf(buff, "x.y.z.example.com." - )) == 19 ); -} - -/** test query_dname_tolower */ -static void -dname_test_qdtl(sldns_buffer* buff) -{ - unit_show_func("util/data/dname.c", "query_dname_tolower"); - sldns_buffer_write_at(buff, 0, "\012abCDeaBCde\003cOm\000", 16); - query_dname_tolower(sldns_buffer_begin(buff)); - unit_assert( memcmp(sldns_buffer_begin(buff), - "\012abcdeabcde\003com\000", 16) == 0); - - sldns_buffer_write_at(buff, 0, "\001+\012abC{e-ZYXe\003NET\000", 18); - query_dname_tolower(sldns_buffer_begin(buff)); - unit_assert( memcmp(sldns_buffer_begin(buff), - "\001+\012abc{e-zyxe\003net\000", 18) == 0); - - sldns_buffer_write_at(buff, 0, "\000", 1); - query_dname_tolower(sldns_buffer_begin(buff)); - unit_assert( memcmp(sldns_buffer_begin(buff), "\000", 1) == 0); - - sldns_buffer_write_at(buff, 0, "\002NL\000", 4); - query_dname_tolower(sldns_buffer_begin(buff)); - unit_assert( memcmp(sldns_buffer_begin(buff), "\002nl\000", 4) == 0); -} - -/** test query_dname_compare */ -static void -dname_test_query_dname_compare(void) -{ - unit_show_func("util/data/dname.c", "query_dname_compare"); - unit_assert(query_dname_compare((uint8_t*)"", (uint8_t*)"") == 0); - unit_assert(query_dname_compare((uint8_t*)"\001a", - (uint8_t*)"\001a") == 0); - unit_assert(query_dname_compare((uint8_t*)"\003abc\001a", - (uint8_t*)"\003abc\001a") == 0); - unit_assert(query_dname_compare((uint8_t*)"\003aBc\001a", - (uint8_t*)"\003AbC\001A") == 0); - unit_assert(query_dname_compare((uint8_t*)"\003abc", - (uint8_t*)"\003abc\001a") == -1); - unit_assert(query_dname_compare((uint8_t*)"\003abc\001a", - (uint8_t*)"\003abc") == +1); - unit_assert(query_dname_compare((uint8_t*)"\003abc\001a", - (uint8_t*)"") == +1); - unit_assert(query_dname_compare((uint8_t*)"", - (uint8_t*)"\003abc\001a") == -1); - unit_assert(query_dname_compare((uint8_t*)"\003abc\001a", - (uint8_t*)"\003xxx\001a") == -1); - unit_assert(query_dname_compare((uint8_t*)"\003axx\001a", - (uint8_t*)"\003abc\001a") == 1); - unit_assert(query_dname_compare((uint8_t*)"\003abc\001a", - (uint8_t*)"\003abc\001Z") == -1); - unit_assert(query_dname_compare((uint8_t*)"\003abc\001Z", - (uint8_t*)"\003abc\001a") == 1); -} - -/** test dname_count_labels */ -static void -dname_test_count_labels(void) -{ - unit_show_func("util/data/dname.c", "dname_count_labels"); - unit_assert(dname_count_labels((uint8_t*)"") == 1); - unit_assert(dname_count_labels((uint8_t*)"\003com") == 2); - unit_assert(dname_count_labels((uint8_t*)"\003org") == 2); - unit_assert(dname_count_labels((uint8_t*)"\007example\003com") == 3); - unit_assert(dname_count_labels((uint8_t*)"\003bla\007example\003com") - == 4); -} - -/** test dname_count_size_labels */ -static void -dname_test_count_size_labels(void) -{ - size_t sz = 0; - unit_show_func("util/data/dname.c", "dname_count_size_labels"); - unit_assert(dname_count_size_labels((uint8_t*)"", &sz) == 1); - unit_assert(sz == 1); - unit_assert(dname_count_size_labels((uint8_t*)"\003com", &sz) == 2); - unit_assert(sz == 5); - unit_assert(dname_count_size_labels((uint8_t*)"\003org", &sz) == 2); - unit_assert(sz == 5); - unit_assert(dname_count_size_labels((uint8_t*)"\007example\003com", - &sz) == 3); - unit_assert(sz == 13); - unit_assert(dname_count_size_labels((uint8_t*)"\003bla\007example" - "\003com", &sz) == 4); - unit_assert(sz == 17); -} - - -/** test pkt_dname_len */ -static void -dname_test_pkt_dname_len(sldns_buffer* buff) -{ - unit_show_func("util/data/dname.c", "pkt_dname_len"); - sldns_buffer_clear(buff); - sldns_buffer_write(buff, "\000", 1); - sldns_buffer_flip(buff); - unit_assert( pkt_dname_len(buff) == 1 ); - unit_assert( sldns_buffer_position(buff) == 1); - - sldns_buffer_clear(buff); - sldns_buffer_write(buff, "\003org\000", 5); - sldns_buffer_flip(buff); - unit_assert( pkt_dname_len(buff) == 5 ); - unit_assert( sldns_buffer_position(buff) == 5); - - sldns_buffer_clear(buff); - sldns_buffer_write(buff, "\002os\007example\003org\000", 16); - sldns_buffer_flip(buff); - unit_assert( pkt_dname_len(buff) == 16 ); - unit_assert( sldns_buffer_position(buff) == 16); - - /* invalid compression pointer: to self */ - sldns_buffer_clear(buff); - sldns_buffer_write(buff, "\300\000os\007example\003org\000", 17); - sldns_buffer_flip(buff); - unit_assert( pkt_dname_len(buff) == 0 ); - - /* valid compression pointer */ - sldns_buffer_clear(buff); - sldns_buffer_write(buff, "\003com\000\040\300\000", 8); - sldns_buffer_flip(buff); - sldns_buffer_set_position(buff, 6); - unit_assert( pkt_dname_len(buff) == 5 ); - unit_assert( sldns_buffer_position(buff) == 8); - - /* unknown label type */ - sldns_buffer_clear(buff); - sldns_buffer_write(buff, "\002os\107example\003org\000", 16); - sldns_buffer_flip(buff); - unit_assert( pkt_dname_len(buff) == 0 ); - - /* label too long */ - sldns_buffer_clear(buff); - sldns_buffer_write(buff, "\002os\047example\003org\000", 16); - sldns_buffer_flip(buff); - unit_assert( pkt_dname_len(buff) == 0 ); - - /* label exceeds packet */ - sldns_buffer_clear(buff); - sldns_buffer_write(buff, "\002os\007example\007org\004", 16); - sldns_buffer_flip(buff); - unit_assert( pkt_dname_len(buff) == 0 ); - - /* name very long */ - sldns_buffer_clear(buff); - sldns_buffer_write(buff, - "\020a1cdef5555544444" - "\020a2cdef5555544444" - "\020a3cdef5555544444" - "\020a4cdef5555544444" - "\020a5cdef5555544444" - "\020a6cdef5555544444" - "\020a7cdef5555544444" - "\020a8cdef5555544444" - "\020a9cdef5555544444" - "\020aAcdef5555544444" - "\020aBcdef5555544444" - "\020aCcdef5555544444" - "\020aDcdef5555544444" - "\020aEcdef5555544444" /* 238 up to here */ - "\007aabbccd" /* 246 up to here */ - "\007example\000" /* 255 to here */ - , 255); - sldns_buffer_flip(buff); - unit_assert( pkt_dname_len(buff) == 255 ); - unit_assert( sldns_buffer_position(buff) == 255); - - /* name too long */ - sldns_buffer_clear(buff); - sldns_buffer_write(buff, - "\020a1cdef5555544444" - "\020a2cdef5555544444" - "\020a3cdef5555544444" - "\020a4cdef5555544444" - "\020a5cdef5555544444" - "\020a6cdef5555544444" - "\020a7cdef5555544444" - "\020a8cdef5555544444" - "\020a9cdef5555544444" - "\020aAcdef5555544444" - "\020aBcdef5555544444" - "\020aCcdef5555544444" - "\020aXcdef5555544444" - "\020aXcdef5555544444" - "\020aXcdef5555544444" - "\020aDcdef5555544444" - "\020aEcdef5555544444" /* 238 up to here */ - "\007aabbccd" /* 246 up to here */ - "\007example\000" /* 255 to here */ - , 255); - sldns_buffer_flip(buff); - unit_assert( pkt_dname_len(buff) == 0 ); -} - -/** test dname_lab_cmp */ -static void -dname_test_dname_lab_cmp(void) -{ - int ml = 0; /* number of labels that matched exactly */ - unit_show_func("util/data/dname.c", "dname_lab_cmp"); - - /* test for equality succeeds */ - unit_assert(dname_lab_cmp((uint8_t*)"", 1, (uint8_t*)"", 1, &ml) == 0); - unit_assert(ml == 1); - unit_assert(dname_lab_cmp( - (uint8_t*)"\003net", 2, - (uint8_t*)"\003net", 2, - &ml) == 0); - unit_assert(ml == 2); - unit_assert(dname_lab_cmp( - (uint8_t*)"\007example\003net", 3, - (uint8_t*)"\007example\003net", 3, - &ml) == 0); - unit_assert(ml == 3); - unit_assert(dname_lab_cmp( - (uint8_t*)"\004test\007example\003net", 4, - (uint8_t*)"\004test\007example\003net", 4, - &ml) == 0); - unit_assert(ml == 4); - - /* root is smaller than anything else */ - unit_assert(dname_lab_cmp( - (uint8_t*)"", 1, - (uint8_t*)"\003net", 2, - &ml) == -1); - unit_assert(ml == 1); - unit_assert(dname_lab_cmp( - (uint8_t*)"\003net", 2, - (uint8_t*)"", 1, - &ml) == 1); - unit_assert(ml == 1); - unit_assert(dname_lab_cmp( - (uint8_t*)"", 1, - (uint8_t*)"\007example\003net", 3, - &ml) == -1); - unit_assert(ml == 1); - unit_assert(dname_lab_cmp( - (uint8_t*)"\007example\003net", 3, - (uint8_t*)"", 1, - &ml) == 1); - unit_assert(ml == 1); - - /* label length makes a difference */ - unit_assert(dname_lab_cmp( - (uint8_t*)"\004neta", 2, - (uint8_t*)"\003net", 2, - &ml) != 0); - unit_assert(ml == 1); - unit_assert(dname_lab_cmp( - (uint8_t*)"\002ne", 2, - (uint8_t*)"\004neta", 2, - &ml) != 0); - unit_assert(ml == 1); - - /* contents follow the zone apex */ - unit_assert(dname_lab_cmp( - (uint8_t*)"\003bla\007example\003net", 4, - (uint8_t*)"\007example\003net", 3, - &ml) == 1); - unit_assert(ml == 3); - unit_assert(dname_lab_cmp( - (uint8_t*)"\007example\003net", 3, - (uint8_t*)"\003bla\007example\003net", 4, - &ml) == -1); - unit_assert(ml == 3); - - /* label content makes a difference */ - unit_assert(dname_lab_cmp( - (uint8_t*)"\003aag\007example\003net", 4, - (uint8_t*)"\003bla\007example\003net", 4, - &ml) == -1); - unit_assert(ml == 3); - unit_assert(dname_lab_cmp( - (uint8_t*)"\003aag\007example\003net", 4, - (uint8_t*)"\003bla\007example\003net", 4, - &ml) == -1); - unit_assert(ml == 3); - unit_assert(dname_lab_cmp( - (uint8_t*)"\003bla\003aag\007example\003net", 5, - (uint8_t*)"\003aag\003bla\007example\003net", 5, - &ml) == -1); - unit_assert(ml == 3); - unit_assert(dname_lab_cmp( - (uint8_t*)"\02sn\003opt\003aag\007example\003net", 6, - (uint8_t*)"\02sn\003opt\003bla\007example\003net", 6, - &ml) == -1); - unit_assert(ml == 3); - - /* but lowercase/uppercase does not make a difference. */ - unit_assert(dname_lab_cmp( - (uint8_t*)"\003bLa\007examPLe\003net", 4, - (uint8_t*)"\003bla\007eXAmple\003nET", 4, - &ml) == 0); - unit_assert(ml == 4); -} - -/** test dname_subdomain_c */ -static void -dname_test_subdomain(void) -{ - unit_show_func("util/data/dname.c", "dname_subdomain"); - unit_assert(dname_subdomain_c( - (uint8_t*)"", - (uint8_t*)"")); - unit_assert(dname_subdomain_c( - (uint8_t*)"\003com", - (uint8_t*)"")); - unit_assert(!dname_subdomain_c( - (uint8_t*)"", - (uint8_t*)"\003com")); - unit_assert(dname_subdomain_c( - (uint8_t*)"\007example\003com", - (uint8_t*)"\003com")); - unit_assert(!dname_subdomain_c( - (uint8_t*)"\003com", - (uint8_t*)"\007example\003com")); - unit_assert(dname_subdomain_c( - (uint8_t*)"\007example\003com", - (uint8_t*)"")); - unit_assert(!dname_subdomain_c( - (uint8_t*)"\003net", - (uint8_t*)"\003com")); - unit_assert(!dname_subdomain_c( - (uint8_t*)"\003net", - (uint8_t*)"\003org")); - unit_assert(!dname_subdomain_c( - (uint8_t*)"\007example\003net", - (uint8_t*)"\003org")); - unit_assert(!dname_subdomain_c( - (uint8_t*)"\003net", - (uint8_t*)"\007example\003org")); -} - -/** test dname_strict_subdomain */ -static void -dname_test_strict_subdomain(void) -{ - unit_show_func("util/data/dname.c", "dname_strict_subdomain"); - unit_assert(!dname_strict_subdomain( - (uint8_t*)"", 1, - (uint8_t*)"", 1)); - unit_assert(dname_strict_subdomain( - (uint8_t*)"\003com", 2, - (uint8_t*)"", 1)); - unit_assert(!dname_strict_subdomain( - (uint8_t*)"", 1, - (uint8_t*)"\003com", 2)); - unit_assert(dname_strict_subdomain( - (uint8_t*)"\007example\003com", 3, - (uint8_t*)"\003com", 2)); - unit_assert(!dname_strict_subdomain( - (uint8_t*)"\003com", 2, - (uint8_t*)"\007example\003com", 3)); - unit_assert(dname_strict_subdomain( - (uint8_t*)"\007example\003com", 3, - (uint8_t*)"", 1)); - unit_assert(!dname_strict_subdomain( - (uint8_t*)"\003net", 2, - (uint8_t*)"\003com", 2)); - unit_assert(!dname_strict_subdomain( - (uint8_t*)"\003net", 2, - (uint8_t*)"\003org", 2)); - unit_assert(!dname_strict_subdomain( - (uint8_t*)"\007example\003net", 3, - (uint8_t*)"\003org", 2)); - unit_assert(!dname_strict_subdomain( - (uint8_t*)"\003net", 2, - (uint8_t*)"\007example\003org", 3)); -} - -/** test dname_is_root */ -static void -dname_test_isroot(void) -{ - unit_show_func("util/data/dname.c", "dname_isroot"); - unit_assert(dname_is_root((uint8_t*)"\000")); - unit_assert(!dname_is_root((uint8_t*)"\001a\000")); - unit_assert(!dname_is_root((uint8_t*)"\005abvcd\003com\000")); - /* malformed dname in this test, but should work */ - unit_assert(!dname_is_root((uint8_t*)"\077a\000")); - unit_assert(dname_is_root((uint8_t*)"\000")); -} - -/** test dname_remove_label */ -static void -dname_test_removelabel(void) -{ - uint8_t* orig = (uint8_t*)"\007example\003com\000"; - uint8_t* n = orig; - size_t l = 13; - unit_show_func("util/data/dname.c", "dname_remove_label"); - dname_remove_label(&n, &l); - unit_assert( n == orig+8 ); - unit_assert( l == 5 ); - dname_remove_label(&n, &l); - unit_assert( n == orig+12 ); - unit_assert( l == 1 ); - dname_remove_label(&n, &l); - unit_assert( n == orig+12 ); - unit_assert( l == 1 ); -} - -/** test dname_signame_label_count */ -static void -dname_test_sigcount(void) -{ - unit_show_func("util/data/dname.c", "dname_signame_label_count"); - unit_assert(dname_signame_label_count((uint8_t*)"\000") == 0); - unit_assert(dname_signame_label_count((uint8_t*)"\001*\000") == 0); - unit_assert(dname_signame_label_count((uint8_t*)"\003xom\000") == 1); - unit_assert(dname_signame_label_count( - (uint8_t*)"\001*\003xom\000") == 1); - unit_assert(dname_signame_label_count( - (uint8_t*)"\007example\003xom\000") == 2); - unit_assert(dname_signame_label_count( - (uint8_t*)"\001*\007example\003xom\000") == 2); - unit_assert(dname_signame_label_count( - (uint8_t*)"\003www\007example\003xom\000") == 3); - unit_assert(dname_signame_label_count( - (uint8_t*)"\001*\003www\007example\003xom\000") == 3); -} - -/** test dname_is_wild routine */ -static void -dname_test_iswild(void) -{ - unit_show_func("util/data/dname.c", "dname_iswild"); - unit_assert( !dname_is_wild((uint8_t*)"\000") ); - unit_assert( dname_is_wild((uint8_t*)"\001*\000") ); - unit_assert( !dname_is_wild((uint8_t*)"\003net\000") ); - unit_assert( dname_is_wild((uint8_t*)"\001*\003net\000") ); -} - -/** test dname_canonical_compare */ -static void -dname_test_canoncmp(void) -{ - unit_show_func("util/data/dname.c", "dname_canonical_compare"); - /* equality */ - unit_assert( dname_canonical_compare( - (uint8_t*)"\000", - (uint8_t*)"\000" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\003net\000", - (uint8_t*)"\003net\000" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\007example\003net\000", - (uint8_t*)"\007example\003net\000" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\004test\007example\003net\000", - (uint8_t*)"\004test\007example\003net\000" - ) == 0); - - /* subdomains */ - unit_assert( dname_canonical_compare( - (uint8_t*)"\003com", - (uint8_t*)"\000" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\000", - (uint8_t*)"\003com" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\007example\003com", - (uint8_t*)"\003com" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\003com", - (uint8_t*)"\007example\003com" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\007example\003com", - (uint8_t*)"\000" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\000", - (uint8_t*)"\007example\003com" - ) == -1); - - /* compare rightmost label */ - unit_assert( dname_canonical_compare( - (uint8_t*)"\003com", - (uint8_t*)"\003net" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\003net", - (uint8_t*)"\003com" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\003net", - (uint8_t*)"\003org" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\007example\003net", - (uint8_t*)"\003org" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\003org", - (uint8_t*)"\007example\003net" - ) == 1); - - /* label length makes a difference; but only if rest is equal */ - unit_assert( dname_canonical_compare( - (uint8_t*)"\004neta", - (uint8_t*)"\003net" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\002ne", - (uint8_t*)"\004neta" - ) == -1); - - /* label content */ - unit_assert( dname_canonical_compare( - (uint8_t*)"\003aag\007example\003net", - (uint8_t*)"\003bla\007example\003net" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\003bla\007example\003net", - (uint8_t*)"\003aag\007example\003net" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\003bla\003aag\007example\003net", - (uint8_t*)"\003aag\003bla\007example\003net" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\02sn\003opt\003aag\007example\003net", - (uint8_t*)"\02sn\003opt\003bla\007example\003net" - ) == -1); - - /* lowercase during compare */ - unit_assert( dname_canonical_compare( - (uint8_t*)"\003bLa\007examPLe\003net", - (uint8_t*)"\003bla\007eXAmple\003nET" - ) == 0); - - /* example from 4034 */ - /* example a.example yljkjljk.a.example Z.a.example zABC.a.EXAMPLE - z.example \001.z.example *.z.example \200.z.example */ - unit_assert( dname_canonical_compare( - (uint8_t*)"", - (uint8_t*)"\007example" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\007example", - (uint8_t*)"\001a\007example" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001a\007example", - (uint8_t*)"\010yljkjljk\001a\007example" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\010yljkjljk\001a\007example", - (uint8_t*)"\001Z\001a\007example" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001Z\001a\007example", - (uint8_t*)"\004zABC\001a\007EXAMPLE" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\004zABC\001a\007EXAMPLE", - (uint8_t*)"\001z\007example" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001z\007example", - (uint8_t*)"\001\001\001z\007example" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001\001\001z\007example", - (uint8_t*)"\001*\001z\007example" - ) == -1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001*\001z\007example", - (uint8_t*)"\001\200\001z\007example" - ) == -1); - /* same example in reverse */ - unit_assert( dname_canonical_compare( - (uint8_t*)"\007example", - (uint8_t*)"" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001a\007example", - (uint8_t*)"\007example" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\010yljkjljk\001a\007example", - (uint8_t*)"\001a\007example" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001Z\001a\007example", - (uint8_t*)"\010yljkjljk\001a\007example" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\004zABC\001a\007EXAMPLE", - (uint8_t*)"\001Z\001a\007example" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001z\007example", - (uint8_t*)"\004zABC\001a\007EXAMPLE" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001\001\001z\007example", - (uint8_t*)"\001z\007example" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001*\001z\007example", - (uint8_t*)"\001\001\001z\007example" - ) == 1); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001\200\001z\007example", - (uint8_t*)"\001*\001z\007example" - ) == 1); - /* same example for equality */ - unit_assert( dname_canonical_compare( - (uint8_t*)"\007example", - (uint8_t*)"\007example" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001a\007example", - (uint8_t*)"\001a\007example" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\010yljkjljk\001a\007example", - (uint8_t*)"\010yljkjljk\001a\007example" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001Z\001a\007example", - (uint8_t*)"\001Z\001a\007example" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\004zABC\001a\007EXAMPLE", - (uint8_t*)"\004zABC\001a\007EXAMPLE" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001z\007example", - (uint8_t*)"\001z\007example" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001\001\001z\007example", - (uint8_t*)"\001\001\001z\007example" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001*\001z\007example", - (uint8_t*)"\001*\001z\007example" - ) == 0); - unit_assert( dname_canonical_compare( - (uint8_t*)"\001\200\001z\007example", - (uint8_t*)"\001\200\001z\007example" - ) == 0); -} - -/** Test dname_get_shared_topdomain */ -static void -dname_test_topdomain(void) -{ - unit_show_func("util/data/dname.c", "dname_get_shared_topdomain"); - unit_assert( query_dname_compare( - dname_get_shared_topdomain( - (uint8_t*)"", - (uint8_t*)""), - (uint8_t*)"") == 0); - unit_assert( query_dname_compare( - dname_get_shared_topdomain( - (uint8_t*)"\003www\007example\003com", - (uint8_t*)"\003www\007example\003com"), - (uint8_t*)"\003www\007example\003com") == 0); - unit_assert( query_dname_compare( - dname_get_shared_topdomain( - (uint8_t*)"\003www\007example\003com", - (uint8_t*)"\003bla\007example\003com"), - (uint8_t*)"\007example\003com") == 0); -} - -/** Test dname_valid */ -static void -dname_test_valid(void) -{ - unit_show_func("util/data/dname.c", "dname_valid"); - unit_assert( dname_valid( - (uint8_t*)"\003www\007example\003com", 255) == 17); - unit_assert( dname_valid((uint8_t*)"", 255) == 1); - unit_assert( dname_valid( (uint8_t*) - "\020a1cdef5555544444" - "\020a2cdef5555544444" - "\020a3cdef5555544444" - "\020a4cdef5555544444" - "\020a5cdef5555544444" - "\020a6cdef5555544444" - "\020a7cdef5555544444" - "\020a8cdef5555544444" - "\020a9cdef5555544444" - "\020aAcdef5555544444" - "\020aBcdef5555544444" - "\020aCcdef5555544444" - "\020aDcdef5555544444" - "\020aEcdef5555544444" /* 238 up to here */ - "\007aabbccd" /* 246 up to here */ - "\007example\000" /* 255 to here */ - , 255) == 255); - unit_assert( dname_valid( (uint8_t*) - "\020a1cdef5555544444" - "\020a2cdef5555544444" - "\020a3cdef5555544444" - "\020a4cdef5555544444" - "\020a5cdef5555544444" - "\020a6cdef5555544444" - "\020a7cdef5555544444" - "\020a8cdef5555544444" - "\020a9cdef5555544444" - "\020aAcdef5555544444" - "\020aBcdef5555544444" - "\020aCcdef5555544444" - "\020aDcdef5555544444" - "\020aEcdef5555544444" /* 238 up to here */ - "\007aabbccd" /* 246 up to here */ - "\010exampleX\000" /* 256 to here */ - , 4096) == 0); -} - -/** test pkt_dname_tolower */ -static void -dname_test_pdtl(sldns_buffer* loopbuf, sldns_buffer* boundbuf) -{ - unit_show_func("util/data/dname.c", "pkt_dname_tolower"); - pkt_dname_tolower(loopbuf, sldns_buffer_at(loopbuf, 12)); - pkt_dname_tolower(boundbuf, sldns_buffer_at(boundbuf, 12)); -} - -/** setup looped dname and out-of-bounds dname ptr */ -static void -dname_setup_bufs(sldns_buffer* loopbuf, sldns_buffer* boundbuf) -{ - sldns_buffer_write_u16(loopbuf, 0xd54d); /* id */ - sldns_buffer_write_u16(loopbuf, 0x12); /* flags */ - sldns_buffer_write_u16(loopbuf, 1); /* qdcount */ - sldns_buffer_write_u16(loopbuf, 0); /* ancount */ - sldns_buffer_write_u16(loopbuf, 0); /* nscount */ - sldns_buffer_write_u16(loopbuf, 0); /* arcount */ - sldns_buffer_write_u8(loopbuf, 0xc0); /* PTR back at itself */ - sldns_buffer_write_u8(loopbuf, 0x0c); - sldns_buffer_flip(loopbuf); - - sldns_buffer_write_u16(boundbuf, 0xd54d); /* id */ - sldns_buffer_write_u16(boundbuf, 0x12); /* flags */ - sldns_buffer_write_u16(boundbuf, 1); /* qdcount */ - sldns_buffer_write_u16(boundbuf, 0); /* ancount */ - sldns_buffer_write_u16(boundbuf, 0); /* nscount */ - sldns_buffer_write_u16(boundbuf, 0); /* arcount */ - sldns_buffer_write_u8(boundbuf, 0x01); /* len=1 */ - sldns_buffer_write_u8(boundbuf, (uint8_t)'A'); /* A. label */ - sldns_buffer_write_u8(boundbuf, 0xc0); /* PTR out of bounds */ - sldns_buffer_write_u8(boundbuf, 0xcc); - sldns_buffer_flip(boundbuf); -} - -void dname_test(void) -{ - sldns_buffer* loopbuf = sldns_buffer_new(14); - sldns_buffer* boundbuf = sldns_buffer_new(16); - sldns_buffer* buff = sldns_buffer_new(65800); - unit_assert(loopbuf && boundbuf && buff); - sldns_buffer_flip(buff); - dname_setup_bufs(loopbuf, boundbuf); - dname_test_qdl(buff); - dname_test_qdtl(buff); - dname_test_pdtl(loopbuf, boundbuf); - dname_test_query_dname_compare(); - dname_test_count_labels(); - dname_test_count_size_labels(); - dname_test_dname_lab_cmp(); - dname_test_pkt_dname_len(buff); - dname_test_strict_subdomain(); - dname_test_subdomain(); - dname_test_isroot(); - dname_test_removelabel(); - dname_test_sigcount(); - dname_test_iswild(); - dname_test_canoncmp(); - dname_test_topdomain(); - dname_test_valid(); - sldns_buffer_free(buff); - sldns_buffer_free(loopbuf); - sldns_buffer_free(boundbuf); -} diff --git a/external/unbound/testcode/unitecs.c b/external/unbound/testcode/unitecs.c deleted file mode 100644 index 3584b0f98..000000000 --- a/external/unbound/testcode/unitecs.c +++ /dev/null @@ -1,284 +0,0 @@ -/* - * testcode/unitecs.c - unit test for ecs routines. - * - * Copyright (c) 2013, NLnet Labs. All rights reserved. - * - * This software is open source. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * Neither the name of the NLNET LABS nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - * - */ - -/** - * \file - * Calls ecs related unit tests. Exits with code 1 on a failure. - */ - -#include "config.h" - -#ifdef CLIENT_SUBNET - -#include "util/log.h" -#include "util/module.h" -#include "testcode/unitmain.h" -#include "edns-subnet/addrtree.h" -#include "edns-subnet/subnetmod.h" - -/* - void printkey(addrkey_t *k, addrlen_t bits) - { - int byte; - int bytes = bits/8 + ((bits%8)>0); - char msk = 0xFF; - for (byte = 0; byte < bytes; byte++) { - //~ if (byte+1 == bytes) - //~ msk = 0xFF<<(8-bits%8); - printf("%02x ", k[byte]&msk); - } - } - - void print_tree(struct addrnode* node, int indent, int maxdepth) - { - struct addredge* edge; - int i, s, byte; - if (indent == 0) printf("-----Tree-----\n"); - if (indent > maxdepth) { - printf("\n"); - return; - } - printf("[node elem:%d] (%d)\n", node->elem != NULL, node); - for (i = 0; i<2; i++) { - if (node->edge[i]) { - for (s = 0; s < indent; s++) printf(" "); - printkey(node->edge[i]->str, node->edge[i]->len); - printf("(len %d bits, %d bytes) ", node->edge[i]->len, - node->edge[i]->len/8 + ((node->edge[i]->len%8)>0)); - print_tree(node->edge[i]->node, indent+1, maxdepth); - } - } - if (indent == 0) printf("-----Tree-----"); - } -*/ - -/* what should we check? - * X - is it balanced? (a node with 1 child shoudl not have - * a node with 1 child MUST have elem - * child must be sub of parent - * edge must be longer than parent edge - * */ -static int addrtree_inconsistent_subtree(struct addrtree* tree, - struct addredge* parent_edge, addrlen_t depth) -{ - struct addredge* edge; - struct addrnode* node = parent_edge->node; - int childcount, i, r; - if (depth > tree->max_depth) return 15; - childcount = (node->edge[0] != NULL) + (node->edge[1] != NULL); - /* Only nodes with 2 children should possibly have no element. */ - if (childcount < 2 && !node->elem) return 10; - for (i = 0; i<2; i++) { - edge = node->edge[i]; - if (!edge) continue; - if (!edge->node) return 11; - if (!edge->str) return 12; - if (edge->len <= parent_edge->len) return 13; - if (!unittest_wrapper_addrtree_issub(parent_edge->str, - parent_edge->len, edge->str, edge->len, 0)) - return 14; - if ((r = addrtree_inconsistent_subtree(tree, edge, depth+1)) != 0) - return 100+r; - } - return 0; -} - -static int addrtree_inconsistent(struct addrtree* tree) -{ - struct addredge* edge; - int i, r; - - if (!tree) return 0; - if (!tree->root) return 1; - - for (i = 0; i<2; i++) { - edge = tree->root->edge[i]; - if (!edge) continue; - if (!edge->node) return 3; - if (!edge->str) return 4; - if ((r = addrtree_inconsistent_subtree(tree, edge, 1)) != 0) - return r; - } - return 0; -} - -static addrlen_t randomkey(addrkey_t **k, int maxlen) -{ - int byte; - int bits = rand() % maxlen; - int bytes = bits/8 + (bits%8>0); /*ceil*/ - *k = (addrkey_t *) malloc(bytes * sizeof(addrkey_t)); - for (byte = 0; byte < bytes; byte++) { - (*k)[byte] = (addrkey_t)(rand() & 0xFF); - } - return (addrlen_t)bits; -} - -static void elemfree(void *envptr, void *elemptr) -{ - struct reply_info *elem = (struct reply_info *)elemptr; - (void)envptr; - free(elem); -} - -static void consistency_test(void) -{ - addrlen_t l; - time_t i; - unsigned int count; - addrkey_t *k; - struct addrtree* t; - struct module_env env; - struct reply_info *elem; - time_t timenow = 0; - unit_show_func("edns-subnet/addrtree.h", "Tree consistency check"); - srand(9195); /* just some value for reproducibility */ - - t = addrtree_create(100, &elemfree, &unittest_wrapper_subnetmod_sizefunc, &env, 0); - count = t->node_count; - unit_assert(count == 0); - for (i = 0; i < 1000; i++) { - l = randomkey(&k, 128); - elem = (struct reply_info *) calloc(1, sizeof(struct reply_info)); - addrtree_insert(t, k, l, 64, elem, timenow + 10, timenow); - /* This should always hold because no items ever expire. They - * could be overwritten, though. */ - unit_assert( count <= t->node_count ); - count = t->node_count; - free(k); - unit_assert( !addrtree_inconsistent(t) ); - } - addrtree_delete(t); - - unit_show_func("edns-subnet/addrtree.h", "Tree consistency with purge"); - t = addrtree_create(8, &elemfree, &unittest_wrapper_subnetmod_sizefunc, &env, 0); - unit_assert(t->node_count == 0); - for (i = 0; i < 1000; i++) { - l = randomkey(&k, 128); - elem = (struct reply_info *) calloc(1, sizeof(struct reply_info)); - addrtree_insert(t, k, l, 64, elem, i + 10, i); - free(k); - unit_assert( !addrtree_inconsistent(t) ); - } - addrtree_delete(t); - - unit_show_func("edns-subnet/addrtree.h", "Tree consistency with limit"); - t = addrtree_create(8, &elemfree, &unittest_wrapper_subnetmod_sizefunc, &env, 27); - unit_assert(t->node_count == 0); - for (i = 0; i < 1000; i++) { - l = randomkey(&k, 128); - elem = (struct reply_info *) calloc(1, sizeof(struct reply_info)); - addrtree_insert(t, k, l, 64, elem, i + 10, i); - unit_assert( t->node_count <= 27); - free(k); - unit_assert( !addrtree_inconsistent(t) ); - } - addrtree_delete(t); -} - -static void issub_test(void) -{ - addrkey_t k1[] = {0x55, 0x55, 0x5A}; - addrkey_t k2[] = {0x55, 0x5D, 0x5A}; - unit_show_func("edns-subnet/addrtree.h", "issub"); - unit_assert( !unittest_wrapper_addrtree_issub(k1, 24, k2, 24, 0) ); - unit_assert( unittest_wrapper_addrtree_issub(k1, 8, k2, 16, 0) ); - unit_assert( unittest_wrapper_addrtree_issub(k2, 12, k1, 13, 0) ); - unit_assert( !unittest_wrapper_addrtree_issub(k1, 16, k2, 12, 0) ); - unit_assert( unittest_wrapper_addrtree_issub(k1, 12, k2, 12, 0) ); - unit_assert( !unittest_wrapper_addrtree_issub(k1, 13, k2, 13, 0) ); - unit_assert( unittest_wrapper_addrtree_issub(k1, 24, k2, 24, 13) ); - unit_assert( !unittest_wrapper_addrtree_issub(k1, 24, k2, 20, 13) ); - unit_assert( unittest_wrapper_addrtree_issub(k1, 20, k2, 24, 13) ); -} - -static void getbit_test(void) -{ - addrkey_t k1[] = {0x55, 0x55, 0x5A}; - int i; - unit_show_func("edns-subnet/addrtree.h", "getbit"); - for(i = 0; i<20; i++) { - unit_assert( unittest_wrapper_addrtree_getbit(k1, 20, (addrlen_t)i) == (i&1) ); - } -} - -static void bits_common_test(void) -{ - addrkey_t k1[] = {0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0}; - addrkey_t k2[] = {0,0,0,0,0,0,0,0}; - addrlen_t i; - - unit_show_func("edns-subnet/addrtree.h", "bits_common"); - for(i = 0; i<64; i++) { - unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k1, 64, i) == 64 ); - } - for(i = 0; i<8; i++) { - k2[i] = k1[i]^(1<<i); - } - unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 0) == 0*8+7 ); - unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 8) == 1*8+6 ); - unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 16) == 2*8+5 ); - unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 24) == 3*8+4 ); - unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 32) == 4*8+3 ); - unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 40) == 5*8+2 ); - unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 48) == 6*8+1 ); - unit_assert( unittest_wrapper_addrtree_bits_common(k1, 64, k2, 64, 56) == 7*8+0 ); -} - -static void cmpbit_test(void) -{ - addrkey_t k1[] = {0xA5, 0x0F}; - addrkey_t k2[] = {0x5A, 0xF0}; - addrlen_t i; - - unit_show_func("edns-subnet/addrtree.h", "cmpbit"); - for(i = 0; i<16; i++) { - unit_assert( !unittest_wrapper_addrtree_cmpbit(k1,k1,i) ); - unit_assert( unittest_wrapper_addrtree_cmpbit(k1,k2,i) ); - } -} - -void ecs_test(void) -{ - unit_show_feature("ecs"); - cmpbit_test(); - bits_common_test(); - getbit_test(); - issub_test(); - consistency_test(); -} -#endif /* CLIENT_SUBNET */ - diff --git a/external/unbound/testcode/unitldns.c b/external/unbound/testcode/unitldns.c deleted file mode 100644 index e27e46eaa..000000000 --- a/external/unbound/testcode/unitldns.c +++ /dev/null @@ -1,218 +0,0 @@ -/* - * testcode/unitldns.c - unit test for ldns routines. - * - * Copyright (c) 2014, 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 - * Calls ldns unit tests. Exits with code 1 on a failure. - */ - -#include "config.h" -#include "util/log.h" -#include "testcode/unitmain.h" -#include "sldns/sbuffer.h" -#include "sldns/str2wire.h" -#include "sldns/wire2str.h" - -/** verbose this unit test */ -static int vbmp = 0; - -/** print buffer to hex into string */ -static void -buf_to_hex(uint8_t* b, size_t blen, char* s, size_t slen) -{ - const char* h = "0123456789ABCDEF"; - size_t i; - if(slen < blen*2+2 && vbmp) printf("hexstring buffer too small\n"); - unit_assert(slen >= blen*2+2); - for(i=0; i<blen; i++) { - s[i*2] = h[(b[i]&0xf0)>>4]; - s[i*2+1] = h[b[i]&0x0f]; - } - s[blen*2] = '\n'; - s[blen*2+1] = 0; -} - -/** Transform input. - * @param txt_in: input text format. - * @param wire1: output wireformat in hex (txt_in converted to wire). - * @param txt_out: output text format (converted from wire_out). - * @param wire2: output wireformat in hex, txt_out converted back to wireformat. - * @param bufs: size of the text buffers. - */ -static void -rr_transform(char* txt_in, char* wire1, char* txt_out, char* wire2, - size_t bufs) -{ - uint8_t b[65536]; - size_t len; - int err; - - len = sizeof(b); - err = sldns_str2wire_rr_buf(txt_in, b, &len, NULL, 3600, - NULL, 0, NULL, 0); - if(err != 0) { - if(vbmp) printf("sldns_str2wire_rr_buf, pos %d: %s\n", - LDNS_WIREPARSE_OFFSET(err), - sldns_get_errorstr_parse(err)); - } - unit_assert(err == 0); - buf_to_hex(b, len, wire1, bufs); - if(vbmp) printf("wire1: %s", wire1); - - err = sldns_wire2str_rr_buf(b, len, txt_out, bufs); - unit_assert(err < (int)bufs && err > 0); - if(vbmp) printf("txt: %s", txt_out); - - len = sizeof(b); - err = sldns_str2wire_rr_buf(txt_out, b, &len, NULL, 3600, - NULL, 0, NULL, 0); - if(err != 0) { - if(vbmp) printf("sldns_str2wire_rr_buf-2, pos %d: %s\n", - LDNS_WIREPARSE_OFFSET(err), - sldns_get_errorstr_parse(err)); - } - unit_assert(err == 0); - buf_to_hex(b, len, wire2, bufs); - if(vbmp) printf("wire2: %s", wire2); -} - -/** Check if results are correct */ -static void -rr_checks(char* wire_chk, char* txt_chk, char* txt_out, char* wire_out, - char* back) -{ -#ifdef __APPLE__ - /* the wiretostr on ipv6 is weird on apple, we cannot check it. - * skip AAAA on OSX */ - if(strstr(txt_out, "IN AAAA")) - txt_out = txt_chk; /* skip this test, but test wirefmt */ - /* so we know that txt_out back to wire is the same */ -#endif - - if(strcmp(txt_chk, txt_out) != 0 && vbmp) - printf("txt different\n"); - if(strcmp(wire_chk, wire_out) != 0 && vbmp) - printf("wire1 different\n"); - if(strcmp(wire_chk, back) != 0 && vbmp) - printf("wire2 different\n"); - - unit_assert(strcmp(txt_chk, txt_out) == 0); - unit_assert(strcmp(wire_chk, wire_out) == 0); - unit_assert(strcmp(wire_chk, back) == 0); -} - -/** read rrs to and from string, and wireformat - * Skips empty lines and comments. - * @param input: input file with text format. - * @param check: check file with hex and then textformat - */ -static void -rr_test_file(const char* input, const char* check) -{ - size_t bufs = 131072; - FILE* inf, *chf, *of; - int lineno = 0, chlineno = 0; - char* txt_in = (char*)malloc(bufs); - char* txt_out = (char*)malloc(bufs); - char* txt_chk = (char*)malloc(bufs); - char* wire_out = (char*)malloc(bufs); - char* wire_chk = (char*)malloc(bufs); - char* back = (char*)malloc(bufs); - if(!txt_in || !txt_out || !txt_chk || !wire_out || !wire_chk || !back) - fatal_exit("malloc failure"); - inf = fopen(input, "r"); - if(!inf) fatal_exit("cannot open %s: %s", input, strerror(errno)); - chf = fopen(check, "r"); - if(!chf) fatal_exit("cannot open %s: %s", check, strerror(errno)); - - of = NULL; - if(0) { - /* debug: create check file */ - of = fopen("outputfile", "w"); - if(!of) fatal_exit("cannot write output: %s", strerror(errno)); - } - - while(fgets(txt_in, (int)bufs, inf)) { - lineno++; - if(vbmp) printf("\n%s:%d %s", input, lineno, txt_in); - /* skip empty lines and comments */ - if(txt_in[0] == 0 || txt_in[0] == '\n' || txt_in[0] == ';') - continue; - /* read check lines */ - if(!fgets(wire_chk, (int)bufs, chf)) - printf("%s too short\n", check); - if(!fgets(txt_chk, (int)bufs, chf)) - printf("%s too short\n", check); - chlineno += 2; - if(vbmp) printf("%s:%d %s", check, chlineno-1, wire_chk); - if(vbmp) printf("%s:%d %s", check, chlineno, txt_chk); - /* generate results */ - rr_transform(txt_in, wire_out, txt_out, back, bufs); - /* checks */ - if(of) { - fprintf(of, "%s%s", wire_out, txt_out); - } else { - rr_checks(wire_chk, txt_chk, txt_out, wire_out, back); - } - } - - if(of) fclose(of); - fclose(inf); - fclose(chf); - free(txt_in); - free(txt_out); - free(txt_chk); - free(wire_out); - free(wire_chk); - free(back); -} - -/** read rrs to and from string, to and from wireformat */ -static void -rr_tests(void) -{ - rr_test_file("testdata/test_ldnsrr.1", "testdata/test_ldnsrr.c1"); - rr_test_file("testdata/test_ldnsrr.2", "testdata/test_ldnsrr.c2"); - rr_test_file("testdata/test_ldnsrr.3", "testdata/test_ldnsrr.c3"); - rr_test_file("testdata/test_ldnsrr.4", "testdata/test_ldnsrr.c4"); - rr_test_file("testdata/test_ldnsrr.5", "testdata/test_ldnsrr.c5"); -} - -void -ldns_test(void) -{ - unit_show_feature("sldns"); - rr_tests(); -} diff --git a/external/unbound/testcode/unitlruhash.c b/external/unbound/testcode/unitlruhash.c deleted file mode 100644 index e196f0b63..000000000 --- a/external/unbound/testcode/unitlruhash.c +++ /dev/null @@ -1,499 +0,0 @@ -/* - * testcode/unitlruhash.c - unit test for lruhash table. - * - * 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 - * Tests the locking LRU keeping hash table implementation. - */ - -#include "config.h" -#include "testcode/unitmain.h" -#include "util/log.h" -#include "util/storage/lruhash.h" -#include "util/storage/slabhash.h" /* for the test structures */ - -/** use this type for the lruhash test key */ -typedef struct slabhash_testkey testkey_type; -/** use this type for the lruhash test data */ -typedef struct slabhash_testdata testdata_type; - -/** 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);} - -/** hash func, very bad to improve collisions */ -static hashvalue_type myhash(int id) {return (hashvalue_type)id & 0x0f;} -/** allocate new key, fill in hash */ -static testkey_type* newkey(int id) { - testkey_type* k = (testkey_type*)calloc(1, sizeof(testkey_type)); - if(!k) fatal_exit("out of memory"); - k->id = id; - k->entry.hash = myhash(id); - k->entry.key = k; - lock_rw_init(&k->entry.lock); - return k; -} -/** new data el */ -static testdata_type* newdata(int val) { - testdata_type* d = (testdata_type*)calloc(1, - sizeof(testdata_type)); - if(!d) fatal_exit("out of memory"); - d->data = val; - return d; -} - -/** test bin_find_entry function and bin_overflow_remove */ -static void -test_bin_find_entry(struct lruhash* table) -{ - testkey_type* k = newkey(12); - testdata_type* d = newdata(128); - testkey_type* k2 = newkey(12 + 1024); - testkey_type* k3 = newkey(14); - testkey_type* k4 = newkey(12 + 1024*2); - hashvalue_type h = myhash(12); - struct lruhash_bin bin; - memset(&bin, 0, sizeof(bin)); - bin_init(&bin, 1); - - /* remove from empty list */ - bin_overflow_remove(&bin, &k->entry); - - /* find in empty list */ - unit_assert( bin_find_entry(table, &bin, h, k) == NULL ); - - /* insert */ - lock_quick_lock(&bin.lock); - bin.overflow_list = &k->entry; - lock_quick_unlock(&bin.lock); - - /* find, hash not OK. */ - unit_assert( bin_find_entry(table, &bin, myhash(13), k) == NULL ); - - /* find, hash OK, but cmp not */ - unit_assert( k->entry.hash == k2->entry.hash ); - unit_assert( bin_find_entry(table, &bin, h, k2) == NULL ); - - /* find, hash OK, and cmp too */ - unit_assert( bin_find_entry(table, &bin, h, k) == &k->entry ); - - /* remove the element */ - lock_quick_lock(&bin.lock); - bin_overflow_remove(&bin, &k->entry); - lock_quick_unlock(&bin.lock); - unit_assert( bin_find_entry(table, &bin, h, k) == NULL ); - - /* prepend two different elements; so the list is long */ - /* one has the same hash, but different cmp */ - lock_quick_lock(&bin.lock); - unit_assert( k->entry.hash == k4->entry.hash ); - k4->entry.overflow_next = &k->entry; - k3->entry.overflow_next = &k4->entry; - bin.overflow_list = &k3->entry; - lock_quick_unlock(&bin.lock); - - /* find, hash not OK. */ - unit_assert( bin_find_entry(table, &bin, myhash(13), k) == NULL ); - - /* find, hash OK, but cmp not */ - unit_assert( k->entry.hash == k2->entry.hash ); - unit_assert( bin_find_entry(table, &bin, h, k2) == NULL ); - - /* find, hash OK, and cmp too */ - unit_assert( bin_find_entry(table, &bin, h, k) == &k->entry ); - - /* remove middle element */ - unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4) - == &k4->entry ); - lock_quick_lock(&bin.lock); - bin_overflow_remove(&bin, &k4->entry); - lock_quick_unlock(&bin.lock); - unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4) == NULL); - - /* remove last element */ - lock_quick_lock(&bin.lock); - bin_overflow_remove(&bin, &k->entry); - lock_quick_unlock(&bin.lock); - unit_assert( bin_find_entry(table, &bin, h, k) == NULL ); - - lock_quick_destroy(&bin.lock); - delkey(k); - delkey(k2); - delkey(k3); - delkey(k4); - deldata(d); -} - -/** test lru_front lru_remove */ -static void test_lru(struct lruhash* table) -{ - testkey_type* k = newkey(12); - testkey_type* k2 = newkey(14); - lock_quick_lock(&table->lock); - - unit_assert( table->lru_start == NULL && table->lru_end == NULL); - lru_remove(table, &k->entry); - unit_assert( table->lru_start == NULL && table->lru_end == NULL); - - /* add one */ - lru_front(table, &k->entry); - unit_assert( table->lru_start == &k->entry && - table->lru_end == &k->entry); - /* remove it */ - lru_remove(table, &k->entry); - unit_assert( table->lru_start == NULL && table->lru_end == NULL); - - /* add two */ - lru_front(table, &k->entry); - unit_assert( table->lru_start == &k->entry && - table->lru_end == &k->entry); - lru_front(table, &k2->entry); - unit_assert( table->lru_start == &k2->entry && - table->lru_end == &k->entry); - /* remove first in list */ - lru_remove(table, &k2->entry); - unit_assert( table->lru_start == &k->entry && - table->lru_end == &k->entry); - lru_front(table, &k2->entry); - unit_assert( table->lru_start == &k2->entry && - table->lru_end == &k->entry); - /* remove last in list */ - lru_remove(table, &k->entry); - unit_assert( table->lru_start == &k2->entry && - table->lru_end == &k2->entry); - - /* empty the list */ - lru_remove(table, &k2->entry); - unit_assert( table->lru_start == NULL && table->lru_end == NULL); - lock_quick_unlock(&table->lock); - delkey(k); - delkey(k2); -} - -/** test hashtable using short sequence */ -static void -test_short_table(struct lruhash* table) -{ - testkey_type* k = newkey(12); - testkey_type* k2 = newkey(14); - testdata_type* d = newdata(128); - testdata_type* d2 = newdata(129); - - k->entry.data = d; - k2->entry.data = d2; - - lruhash_insert(table, myhash(12), &k->entry, d, NULL); - lruhash_insert(table, myhash(14), &k2->entry, d2, NULL); - - unit_assert( lruhash_lookup(table, myhash(12), k, 0) == &k->entry); - lock_rw_unlock( &k->entry.lock ); - unit_assert( lruhash_lookup(table, myhash(14), k2, 0) == &k2->entry); - lock_rw_unlock( &k2->entry.lock ); - lruhash_remove(table, myhash(12), k); - lruhash_remove(table, myhash(14), k2); -} - -/** number of hash test max */ -#define HASHTESTMAX 25 - -/** test adding a random element */ -static void -testadd(struct lruhash* table, testdata_type* ref[]) -{ - int numtoadd = random() % HASHTESTMAX; - testdata_type* data = newdata(numtoadd); - testkey_type* key = newkey(numtoadd); - key->entry.data = data; - lruhash_insert(table, myhash(numtoadd), &key->entry, data, NULL); - ref[numtoadd] = data; -} - -/** test adding a random element */ -static void -testremove(struct lruhash* table, testdata_type* ref[]) -{ - int num = random() % HASHTESTMAX; - testkey_type* key = newkey(num); - lruhash_remove(table, myhash(num), key); - ref[num] = NULL; - delkey(key); -} - -/** test adding a random element */ -static void -testlookup(struct lruhash* table, testdata_type* ref[]) -{ - int num = random() % HASHTESTMAX; - testkey_type* key = newkey(num); - struct lruhash_entry* en = lruhash_lookup(table, myhash(num), key, 0); - testdata_type* data = en? (testdata_type*)en->data : NULL; - if(en) { - unit_assert(en->key); - unit_assert(en->data); - } - if(0) log_info("lookup %d got %d, expect %d", num, en? data->data :-1, - ref[num]? ref[num]->data : -1); - unit_assert( data == ref[num] ); - if(en) { lock_rw_unlock(&en->lock); } - delkey(key); -} - -/** check integrity of hash table */ -static void -check_table(struct lruhash* table) -{ - struct lruhash_entry* p; - size_t c = 0; - lock_quick_lock(&table->lock); - unit_assert( table->num <= table->size); - unit_assert( table->size_mask == (int)table->size-1 ); - unit_assert( (table->lru_start && table->lru_end) || - (!table->lru_start && !table->lru_end) ); - unit_assert( table->space_used <= table->space_max ); - /* check lru list integrity */ - if(table->lru_start) - unit_assert(table->lru_start->lru_prev == NULL); - if(table->lru_end) - unit_assert(table->lru_end->lru_next == NULL); - p = table->lru_start; - while(p) { - if(p->lru_prev) { - unit_assert(p->lru_prev->lru_next == p); - } - if(p->lru_next) { - unit_assert(p->lru_next->lru_prev == p); - } - c++; - p = p->lru_next; - } - unit_assert(c == table->num); - - /* this assertion is specific to the unit test */ - unit_assert( table->space_used == - table->num * test_slabhash_sizefunc(NULL, NULL) ); - lock_quick_unlock(&table->lock); -} - -/** test adding a random element (unlimited range) */ -static void -testadd_unlim(struct lruhash* table, testdata_type** ref) -{ - int numtoadd = random() % (HASHTESTMAX * 10); - testdata_type* data = newdata(numtoadd); - testkey_type* key = newkey(numtoadd); - key->entry.data = data; - lruhash_insert(table, myhash(numtoadd), &key->entry, data, NULL); - if(ref) - ref[numtoadd] = data; -} - -/** test adding a random element (unlimited range) */ -static void -testremove_unlim(struct lruhash* table, testdata_type** ref) -{ - int num = random() % (HASHTESTMAX*10); - testkey_type* key = newkey(num); - lruhash_remove(table, myhash(num), key); - if(ref) - ref[num] = NULL; - delkey(key); -} - -/** test adding a random element (unlimited range) */ -static void -testlookup_unlim(struct lruhash* table, testdata_type** ref) -{ - int num = random() % (HASHTESTMAX*10); - testkey_type* key = newkey(num); - struct lruhash_entry* en = lruhash_lookup(table, myhash(num), key, 0); - testdata_type* data = en? (testdata_type*)en->data : NULL; - if(en) { - unit_assert(en->key); - unit_assert(en->data); - } - if(0 && ref) log_info("lookup unlim %d got %d, expect %d", num, en ? - data->data :-1, ref[num] ? ref[num]->data : -1); - if(data && ref) { - /* its okay for !data, it fell off the lru */ - unit_assert( data == ref[num] ); - } - if(en) { lock_rw_unlock(&en->lock); } - delkey(key); -} - -/** test with long sequence of adds, removes and updates, and lookups */ -static void -test_long_table(struct lruhash* table) -{ - /* assuming it all fits in the hashtable, this check will work */ - testdata_type* ref[HASHTESTMAX * 100]; - size_t i; - memset(ref, 0, sizeof(ref)); - /* test assumption */ - if(0) log_info(" size %d x %d < %d", (int)test_slabhash_sizefunc(NULL, NULL), - (int)HASHTESTMAX, (int)table->space_max); - unit_assert( test_slabhash_sizefunc(NULL, NULL)*HASHTESTMAX < table->space_max); - if(0) lruhash_status(table, "unit test", 1); - srandom(48); - for(i=0; i<1000; i++) { - /* what to do? */ - if(i == 500) { - lruhash_clear(table); - memset(ref, 0, sizeof(ref)); - continue; - } - switch(random() % 4) { - case 0: - case 3: - testadd(table, ref); - break; - case 1: - testremove(table, ref); - break; - case 2: - testlookup(table, ref); - break; - default: - unit_assert(0); - } - if(0) lruhash_status(table, "unit test", 1); - check_table(table); - unit_assert( table->num <= HASHTESTMAX ); - } - - /* test more, but 'ref' assumption does not hold anymore */ - for(i=0; i<1000; i++) { - /* what to do? */ - switch(random() % 4) { - case 0: - case 3: - testadd_unlim(table, ref); - break; - case 1: - testremove_unlim(table, ref); - break; - case 2: - testlookup_unlim(table, ref); - break; - default: - unit_assert(0); - } - if(0) lruhash_status(table, "unlim", 1); - check_table(table); - } -} - -/** structure to threaded test the lru hash table */ -struct test_thr { - /** thread num, first entry. */ - int num; - /** id */ - ub_thread_type id; - /** hash table */ - struct lruhash* table; -}; - -/** main routine for threaded hash table test */ -static void* -test_thr_main(void* arg) -{ - struct test_thr* t = (struct test_thr*)arg; - int i; - log_thread_set(&t->num); - for(i=0; i<1000; i++) { - switch(random() % 4) { - case 0: - case 3: - testadd_unlim(t->table, NULL); - break; - case 1: - testremove_unlim(t->table, NULL); - break; - case 2: - testlookup_unlim(t->table, NULL); - break; - default: - unit_assert(0); - } - if(0) lruhash_status(t->table, "hashtest", 1); - if(i % 100 == 0) /* because of locking, not all the time */ - check_table(t->table); - } - check_table(t->table); - return NULL; -} - -/** test hash table access by multiple threads */ -static void -test_threaded_table(struct lruhash* table) -{ - int numth = 10; - struct test_thr t[100]; - int i; - - for(i=1; i<numth; i++) { - t[i].num = i; - t[i].table = table; - ub_thread_create(&t[i].id, test_thr_main, &t[i]); - } - - for(i=1; i<numth; i++) { - ub_thread_join(t[i].id); - } - if(0) lruhash_status(table, "hashtest", 1); -} - -void lruhash_test(void) -{ - /* start very very small array, so it can do lots of table_grow() */ - /* also small in size so that reclaim has to be done quickly. */ - struct lruhash* table ; - unit_show_feature("lruhash"); - table = lruhash_create(2, 8192, - test_slabhash_sizefunc, test_slabhash_compfunc, - test_slabhash_delkey, test_slabhash_deldata, NULL); - test_bin_find_entry(table); - test_lru(table); - test_short_table(table); - test_long_table(table); - lruhash_delete(table); - table = lruhash_create(2, 8192, - test_slabhash_sizefunc, test_slabhash_compfunc, - test_slabhash_delkey, test_slabhash_deldata, NULL); - test_threaded_table(table); - lruhash_delete(table); -} diff --git a/external/unbound/testcode/unitmain.c b/external/unbound/testcode/unitmain.c deleted file mode 100644 index fd56e64d3..000000000 --- a/external/unbound/testcode/unitmain.c +++ /dev/null @@ -1,919 +0,0 @@ -/* - * testcode/unitmain.c - unit test main program 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 - * Unit test main program. Calls all the other unit tests. - * Exits with code 1 on a failure. 0 if all unit tests are successful. - */ - -#include "config.h" -#ifdef HAVE_OPENSSL_ERR_H -#include <openssl/err.h> -#endif - -#ifdef HAVE_OPENSSL_RAND_H -#include <openssl/rand.h> -#endif - -#ifdef HAVE_OPENSSL_CONF_H -#include <openssl/conf.h> -#endif - -#ifdef HAVE_OPENSSL_ENGINE_H -#include <openssl/engine.h> -#endif - -#ifdef HAVE_NSS -/* nss3 */ -#include "nss.h" -#endif - -#include "sldns/rrdef.h" -#include "sldns/keyraw.h" -#include "util/log.h" -#include "testcode/unitmain.h" - -/** number of tests done */ -int testcount = 0; - -#include "util/alloc.h" -/** test alloc code */ -static void -alloc_test(void) { - alloc_special_type *t1, *t2; - struct alloc_cache major, minor1, minor2; - int i; - - unit_show_feature("alloc_special_obtain"); - alloc_init(&major, NULL, 0); - alloc_init(&minor1, &major, 0); - alloc_init(&minor2, &major, 1); - - t1 = alloc_special_obtain(&minor1); - alloc_clear(&minor1); - - alloc_special_release(&minor2, t1); - t2 = alloc_special_obtain(&minor2); - unit_assert( t1 == t2 ); /* reused */ - alloc_special_release(&minor2, t1); - - for(i=0; i<100; i++) { - t1 = alloc_special_obtain(&minor1); - alloc_special_release(&minor2, t1); - } - if(0) { - alloc_stats(&minor1); - alloc_stats(&minor2); - alloc_stats(&major); - } - /* reuse happened */ - unit_assert(minor1.num_quar + minor2.num_quar + major.num_quar == 11); - - alloc_clear(&minor1); - alloc_clear(&minor2); - unit_assert(major.num_quar == 11); - alloc_clear(&major); -} - -#include "util/net_help.h" -/** test net code */ -static void -net_test(void) -{ - const char* t4[] = {"\000\000\000\000", - "\200\000\000\000", - "\300\000\000\000", - "\340\000\000\000", - "\360\000\000\000", - "\370\000\000\000", - "\374\000\000\000", - "\376\000\000\000", - "\377\000\000\000", - "\377\200\000\000", - "\377\300\000\000", - "\377\340\000\000", - "\377\360\000\000", - "\377\370\000\000", - "\377\374\000\000", - "\377\376\000\000", - "\377\377\000\000", - "\377\377\200\000", - "\377\377\300\000", - "\377\377\340\000", - "\377\377\360\000", - "\377\377\370\000", - "\377\377\374\000", - "\377\377\376\000", - "\377\377\377\000", - "\377\377\377\200", - "\377\377\377\300", - "\377\377\377\340", - "\377\377\377\360", - "\377\377\377\370", - "\377\377\377\374", - "\377\377\377\376", - "\377\377\377\377", - "\377\377\377\377", - "\377\377\377\377", - }; - unit_show_func("util/net_help.c", "str_is_ip6"); - unit_assert( str_is_ip6("::") ); - unit_assert( str_is_ip6("::1") ); - unit_assert( str_is_ip6("2001:7b8:206:1:240:f4ff:fe37:8810") ); - unit_assert( str_is_ip6("fe80::240:f4ff:fe37:8810") ); - unit_assert( !str_is_ip6("0.0.0.0") ); - unit_assert( !str_is_ip6("213.154.224.12") ); - unit_assert( !str_is_ip6("213.154.224.255") ); - unit_assert( !str_is_ip6("255.255.255.0") ); - unit_show_func("util/net_help.c", "is_pow2"); - unit_assert( is_pow2(0) ); - unit_assert( is_pow2(1) ); - unit_assert( is_pow2(2) ); - unit_assert( is_pow2(4) ); - unit_assert( is_pow2(8) ); - unit_assert( is_pow2(16) ); - unit_assert( is_pow2(1024) ); - unit_assert( is_pow2(1024*1024) ); - unit_assert( is_pow2(1024*1024*1024) ); - unit_assert( !is_pow2(3) ); - unit_assert( !is_pow2(5) ); - unit_assert( !is_pow2(6) ); - unit_assert( !is_pow2(7) ); - unit_assert( !is_pow2(9) ); - unit_assert( !is_pow2(10) ); - unit_assert( !is_pow2(11) ); - unit_assert( !is_pow2(17) ); - unit_assert( !is_pow2(23) ); - unit_assert( !is_pow2(257) ); - unit_assert( !is_pow2(259) ); - - /* test addr_mask */ - unit_show_func("util/net_help.c", "addr_mask"); - if(1) { - struct sockaddr_in a4; - struct sockaddr_in6 a6; - socklen_t l4 = (socklen_t)sizeof(a4); - socklen_t l6 = (socklen_t)sizeof(a6); - int i; - a4.sin_family = AF_INET; - a6.sin6_family = AF_INET6; - for(i=0; i<35; i++) { - /* address 255.255.255.255 */ - memcpy(&a4.sin_addr, "\377\377\377\377", 4); - addr_mask((struct sockaddr_storage*)&a4, l4, i); - unit_assert(memcmp(&a4.sin_addr, t4[i], 4) == 0); - } - memcpy(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377", 16); - addr_mask((struct sockaddr_storage*)&a6, l6, 128); - unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377", 16) == 0); - addr_mask((struct sockaddr_storage*)&a6, l6, 122); - unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\300", 16) == 0); - addr_mask((struct sockaddr_storage*)&a6, l6, 120); - unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\000", 16) == 0); - addr_mask((struct sockaddr_storage*)&a6, l6, 64); - unit_assert(memcmp(&a6.sin6_addr, "\377\377\377\377\377\377\377\377\000\000\000\000\000\000\000\000", 16) == 0); - addr_mask((struct sockaddr_storage*)&a6, l6, 0); - unit_assert(memcmp(&a6.sin6_addr, "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000", 16) == 0); - } - - /* test addr_in_common */ - unit_show_func("util/net_help.c", "addr_in_common"); - if(1) { - struct sockaddr_in a4, b4; - struct sockaddr_in6 a6, b6; - socklen_t l4 = (socklen_t)sizeof(a4); - socklen_t l6 = (socklen_t)sizeof(a6); - int i; - a4.sin_family = AF_INET; - b4.sin_family = AF_INET; - a6.sin6_family = AF_INET6; - b6.sin6_family = AF_INET6; - memcpy(&a4.sin_addr, "abcd", 4); - memcpy(&b4.sin_addr, "abcd", 4); - unit_assert(addr_in_common((struct sockaddr_storage*)&a4, 32, - (struct sockaddr_storage*)&b4, 32, l4) == 32); - unit_assert(addr_in_common((struct sockaddr_storage*)&a4, 34, - (struct sockaddr_storage*)&b4, 32, l4) == 32); - for(i=0; i<=32; i++) { - unit_assert(addr_in_common( - (struct sockaddr_storage*)&a4, 32, - (struct sockaddr_storage*)&b4, i, l4) == i); - unit_assert(addr_in_common( - (struct sockaddr_storage*)&a4, i, - (struct sockaddr_storage*)&b4, 32, l4) == i); - unit_assert(addr_in_common( - (struct sockaddr_storage*)&a4, i, - (struct sockaddr_storage*)&b4, i, l4) == i); - } - for(i=0; i<=32; i++) { - memcpy(&a4.sin_addr, "\377\377\377\377", 4); - memcpy(&b4.sin_addr, t4[i], 4); - unit_assert(addr_in_common( - (struct sockaddr_storage*)&a4, 32, - (struct sockaddr_storage*)&b4, 32, l4) == i); - unit_assert(addr_in_common( - (struct sockaddr_storage*)&b4, 32, - (struct sockaddr_storage*)&a4, 32, l4) == i); - } - memcpy(&a6.sin6_addr, "abcdefghabcdefgh", 16); - memcpy(&b6.sin6_addr, "abcdefghabcdefgh", 16); - unit_assert(addr_in_common((struct sockaddr_storage*)&a6, 128, - (struct sockaddr_storage*)&b6, 128, l6) == 128); - unit_assert(addr_in_common((struct sockaddr_storage*)&a6, 129, - (struct sockaddr_storage*)&b6, 128, l6) == 128); - for(i=0; i<=128; i++) { - unit_assert(addr_in_common( - (struct sockaddr_storage*)&a6, 128, - (struct sockaddr_storage*)&b6, i, l6) == i); - unit_assert(addr_in_common( - (struct sockaddr_storage*)&a6, i, - (struct sockaddr_storage*)&b6, 128, l6) == i); - unit_assert(addr_in_common( - (struct sockaddr_storage*)&a6, i, - (struct sockaddr_storage*)&b6, i, l6) == i); - } - } - /* test sockaddr_cmp_addr */ - unit_show_func("util/net_help.c", "sockaddr_cmp_addr"); - if(1) { - struct sockaddr_storage a, b; - socklen_t alen = (socklen_t)sizeof(a); - socklen_t blen = (socklen_t)sizeof(b); - unit_assert(ipstrtoaddr("127.0.0.0", 53, &a, &alen)); - unit_assert(ipstrtoaddr("127.255.255.255", 53, &b, &blen)); - unit_assert(sockaddr_cmp_addr(&a, alen, &b, blen) < 0); - unit_assert(sockaddr_cmp_addr(&b, blen, &a, alen) > 0); - unit_assert(sockaddr_cmp_addr(&a, alen, &a, alen) == 0); - unit_assert(sockaddr_cmp_addr(&b, blen, &b, blen) == 0); - unit_assert(ipstrtoaddr("192.168.121.5", 53, &a, &alen)); - unit_assert(sockaddr_cmp_addr(&a, alen, &b, blen) > 0); - unit_assert(sockaddr_cmp_addr(&b, blen, &a, alen) < 0); - unit_assert(sockaddr_cmp_addr(&a, alen, &a, alen) == 0); - unit_assert(ipstrtoaddr("2001:3578:ffeb::99", 53, &b, &blen)); - unit_assert(sockaddr_cmp_addr(&b, blen, &b, blen) == 0); - unit_assert(sockaddr_cmp_addr(&a, alen, &b, blen) < 0); - unit_assert(sockaddr_cmp_addr(&b, blen, &a, alen) > 0); - } - /* test addr_is_ip4mapped */ - unit_show_func("util/net_help.c", "addr_is_ip4mapped"); - if(1) { - struct sockaddr_storage a; - socklen_t l = (socklen_t)sizeof(a); - unit_assert(ipstrtoaddr("12.13.14.15", 53, &a, &l)); - unit_assert(!addr_is_ip4mapped(&a, l)); - unit_assert(ipstrtoaddr("fe80::217:31ff:fe91:df", 53, &a, &l)); - unit_assert(!addr_is_ip4mapped(&a, l)); - unit_assert(ipstrtoaddr("ffff::217:31ff:fe91:df", 53, &a, &l)); - unit_assert(!addr_is_ip4mapped(&a, l)); - unit_assert(ipstrtoaddr("::ffff:31ff:fe91:df", 53, &a, &l)); - unit_assert(!addr_is_ip4mapped(&a, l)); - unit_assert(ipstrtoaddr("::fffe:fe91:df", 53, &a, &l)); - unit_assert(!addr_is_ip4mapped(&a, l)); - unit_assert(ipstrtoaddr("::ffff:127.0.0.1", 53, &a, &l)); - unit_assert(addr_is_ip4mapped(&a, l)); - unit_assert(ipstrtoaddr("::ffff:127.0.0.2", 53, &a, &l)); - unit_assert(addr_is_ip4mapped(&a, l)); - unit_assert(ipstrtoaddr("::ffff:192.168.0.2", 53, &a, &l)); - unit_assert(addr_is_ip4mapped(&a, l)); - unit_assert(ipstrtoaddr("2::ffff:192.168.0.2", 53, &a, &l)); - unit_assert(!addr_is_ip4mapped(&a, l)); - } - /* test addr_is_any */ - unit_show_func("util/net_help.c", "addr_is_any"); - if(1) { - struct sockaddr_storage a; - socklen_t l = (socklen_t)sizeof(a); - unit_assert(ipstrtoaddr("0.0.0.0", 53, &a, &l)); - unit_assert(addr_is_any(&a, l)); - unit_assert(ipstrtoaddr("0.0.0.0", 10053, &a, &l)); - unit_assert(addr_is_any(&a, l)); - unit_assert(ipstrtoaddr("0.0.0.0", 0, &a, &l)); - unit_assert(addr_is_any(&a, l)); - unit_assert(ipstrtoaddr("::0", 0, &a, &l)); - unit_assert(addr_is_any(&a, l)); - unit_assert(ipstrtoaddr("::0", 53, &a, &l)); - unit_assert(addr_is_any(&a, l)); - unit_assert(ipstrtoaddr("::1", 53, &a, &l)); - unit_assert(!addr_is_any(&a, l)); - unit_assert(ipstrtoaddr("2001:1667::1", 0, &a, &l)); - unit_assert(!addr_is_any(&a, l)); - unit_assert(ipstrtoaddr("2001::0", 0, &a, &l)); - unit_assert(!addr_is_any(&a, l)); - unit_assert(ipstrtoaddr("10.0.0.0", 0, &a, &l)); - unit_assert(!addr_is_any(&a, l)); - unit_assert(ipstrtoaddr("0.0.0.10", 0, &a, &l)); - unit_assert(!addr_is_any(&a, l)); - unit_assert(ipstrtoaddr("192.0.2.1", 0, &a, &l)); - unit_assert(!addr_is_any(&a, l)); - } -} - -#include "util/config_file.h" -/** test config_file: cfg_parse_memsize */ -static void -config_memsize_test(void) -{ - size_t v = 0; - unit_show_func("util/config_file.c", "cfg_parse_memsize"); - if(0) { - /* these emit errors */ - unit_assert( cfg_parse_memsize("", &v) == 0); - unit_assert( cfg_parse_memsize("bla", &v) == 0); - unit_assert( cfg_parse_memsize("nop", &v) == 0); - unit_assert( cfg_parse_memsize("n0b", &v) == 0); - unit_assert( cfg_parse_memsize("gb", &v) == 0); - unit_assert( cfg_parse_memsize("b", &v) == 0); - unit_assert( cfg_parse_memsize("kb", &v) == 0); - unit_assert( cfg_parse_memsize("kk kb", &v) == 0); - } - unit_assert( cfg_parse_memsize("0", &v) && v==0); - unit_assert( cfg_parse_memsize("1", &v) && v==1); - unit_assert( cfg_parse_memsize("10", &v) && v==10); - unit_assert( cfg_parse_memsize("10b", &v) && v==10); - unit_assert( cfg_parse_memsize("5b", &v) && v==5); - unit_assert( cfg_parse_memsize("1024", &v) && v==1024); - unit_assert( cfg_parse_memsize("1k", &v) && v==1024); - unit_assert( cfg_parse_memsize("1K", &v) && v==1024); - unit_assert( cfg_parse_memsize("1Kb", &v) && v==1024); - unit_assert( cfg_parse_memsize("1kb", &v) && v==1024); - unit_assert( cfg_parse_memsize("1 kb", &v) && v==1024); - unit_assert( cfg_parse_memsize("10 kb", &v) && v==10240); - unit_assert( cfg_parse_memsize("2k", &v) && v==2048); - unit_assert( cfg_parse_memsize("2m", &v) && v==2048*1024); - unit_assert( cfg_parse_memsize("3M", &v) && v==3072*1024); - unit_assert( cfg_parse_memsize("40m", &v) && v==40960*1024); - unit_assert( cfg_parse_memsize("1G", &v) && v==1024*1024*1024); - unit_assert( cfg_parse_memsize("1 Gb", &v) && v==1024*1024*1024); - unit_assert( cfg_parse_memsize("0 Gb", &v) && v==0*1024*1024); -} - -/** test config_file: test tag code */ -static void -config_tag_test(void) -{ - unit_show_func("util/config_file.c", "taglist_intersect"); - unit_assert( taglist_intersect( - (uint8_t*)"\000\000\000", 3, (uint8_t*)"\001\000\001", 3 - ) == 0); - unit_assert( taglist_intersect( - (uint8_t*)"\000\000\001", 3, (uint8_t*)"\001\000\001", 3 - ) == 1); - unit_assert( taglist_intersect( - (uint8_t*)"\001\000\000", 3, (uint8_t*)"\001\000\001", 3 - ) == 1); - unit_assert( taglist_intersect( - (uint8_t*)"\001", 1, (uint8_t*)"\001\000\001", 3 - ) == 1); - unit_assert( taglist_intersect( - (uint8_t*)"\001\000\001", 3, (uint8_t*)"\001", 1 - ) == 1); -} - -#include "util/rtt.h" -/** test RTT code */ -static void -rtt_test(void) -{ - int init = 376; - int i; - struct rtt_info r; - unit_show_func("util/rtt.c", "rtt_timeout"); - rtt_init(&r); - /* initial value sensible */ - unit_assert( rtt_timeout(&r) == init ); - rtt_lost(&r, init); - unit_assert( rtt_timeout(&r) == init*2 ); - rtt_lost(&r, init*2); - unit_assert( rtt_timeout(&r) == init*4 ); - rtt_update(&r, 4000); - unit_assert( rtt_timeout(&r) >= 2000 ); - rtt_lost(&r, rtt_timeout(&r) ); - for(i=0; i<100; i++) { - rtt_lost(&r, rtt_timeout(&r) ); - unit_assert( rtt_timeout(&r) > RTT_MIN_TIMEOUT-1); - unit_assert( rtt_timeout(&r) < RTT_MAX_TIMEOUT+1); - } -} - -#include "services/cache/infra.h" -#include "util/config_file.h" - -/* lookup and get key and data structs easily */ -static struct infra_data* infra_lookup_host(struct infra_cache* infra, - struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone, - size_t zonelen, int wr, time_t now, struct infra_key** k) -{ - struct infra_data* d; - struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen, - zone, zonelen, wr); - if(!e) return NULL; - d = (struct infra_data*)e->data; - if(d->ttl < now) { - lock_rw_unlock(&e->lock); - return NULL; - } - *k = (struct infra_key*)e->key; - return d; -} - -/** test host cache */ -static void -infra_test(void) -{ - struct sockaddr_storage one; - socklen_t onelen; - uint8_t* zone = (uint8_t*)"\007example\003com\000"; - size_t zonelen = 13; - struct infra_cache* slab; - struct config_file* cfg = config_create(); - time_t now = 0; - uint8_t edns_lame; - int vs, to; - struct infra_key* k; - struct infra_data* d; - int init = 376; - - unit_show_feature("infra cache"); - unit_assert(ipstrtoaddr("127.0.0.1", 53, &one, &onelen)); - - slab = infra_create(cfg); - unit_assert( infra_host(slab, &one, onelen, zone, zonelen, now, - &vs, &edns_lame, &to) ); - unit_assert( vs == 0 && to == init && edns_lame == 0 ); - - unit_assert( infra_rtt_update(slab, &one, onelen, zone, zonelen, LDNS_RR_TYPE_A, -1, init, now) ); - unit_assert( infra_host(slab, &one, onelen, zone, zonelen, - now, &vs, &edns_lame, &to) ); - unit_assert( vs == 0 && to == init*2 && edns_lame == 0 ); - - unit_assert( infra_edns_update(slab, &one, onelen, zone, zonelen, -1, now) ); - unit_assert( infra_host(slab, &one, onelen, zone, zonelen, - now, &vs, &edns_lame, &to) ); - unit_assert( vs == -1 && to == init*2 && edns_lame == 1); - - now += cfg->host_ttl + 10; - unit_assert( infra_host(slab, &one, onelen, zone, zonelen, - now, &vs, &edns_lame, &to) ); - unit_assert( vs == 0 && to == init && edns_lame == 0 ); - - unit_assert( infra_set_lame(slab, &one, onelen, - zone, zonelen, now, 0, 0, LDNS_RR_TYPE_A) ); - unit_assert( (d=infra_lookup_host(slab, &one, onelen, zone, zonelen, 0, now, &k)) ); - unit_assert( d->ttl == now+cfg->host_ttl ); - unit_assert( d->edns_version == 0 ); - unit_assert(!d->isdnsseclame && !d->rec_lame && d->lame_type_A && - !d->lame_other); - lock_rw_unlock(&k->entry.lock); - - /* test merge of data */ - unit_assert( infra_set_lame(slab, &one, onelen, - zone, zonelen, now, 0, 0, LDNS_RR_TYPE_AAAA) ); - unit_assert( (d=infra_lookup_host(slab, &one, onelen, zone, zonelen, 0, now, &k)) ); - unit_assert(!d->isdnsseclame && !d->rec_lame && d->lame_type_A && - d->lame_other); - lock_rw_unlock(&k->entry.lock); - - /* test that noEDNS cannot overwrite known-yesEDNS */ - now += cfg->host_ttl + 10; - unit_assert( infra_host(slab, &one, onelen, zone, zonelen, - now, &vs, &edns_lame, &to) ); - unit_assert( vs == 0 && to == init && edns_lame == 0 ); - - unit_assert( infra_edns_update(slab, &one, onelen, zone, zonelen, 0, now) ); - unit_assert( infra_host(slab, &one, onelen, zone, zonelen, - now, &vs, &edns_lame, &to) ); - unit_assert( vs == 0 && to == init && edns_lame == 1 ); - - unit_assert( infra_edns_update(slab, &one, onelen, zone, zonelen, -1, now) ); - unit_assert( infra_host(slab, &one, onelen, zone, zonelen, - now, &vs, &edns_lame, &to) ); - unit_assert( vs == 0 && to == init && edns_lame == 1 ); - - infra_delete(slab); - config_delete(cfg); -} - -#include "util/random.h" -/** test randomness */ -static void -rnd_test(void) -{ - struct ub_randstate* r; - int num = 1000, i; - long int a[1000]; - unsigned int seed = (unsigned)time(NULL); - unit_show_feature("ub_random"); - printf("ub_random seed is %u\n", seed); - unit_assert( (r = ub_initstate(seed, NULL)) ); - for(i=0; i<num; i++) { - a[i] = ub_random(r); - unit_assert(a[i] >= 0); - unit_assert((size_t)a[i] <= (size_t)0x7fffffff); - if(i > 5) - unit_assert(a[i] != a[i-1] || a[i] != a[i-2] || - a[i] != a[i-3] || a[i] != a[i-4] || - a[i] != a[i-5] || a[i] != a[i-6]); - } - a[0] = ub_random_max(r, 1); - unit_assert(a[0] >= 0 && a[0] < 1); - a[0] = ub_random_max(r, 10000); - unit_assert(a[0] >= 0 && a[0] < 10000); - for(i=0; i<num; i++) { - a[i] = ub_random_max(r, 10); - unit_assert(a[i] >= 0 && a[i] < 10); - } - ub_randfree(r); -} - -#include "respip/respip.h" -#include "services/localzone.h" -#include "util/data/packed_rrset.h" -typedef struct addr_action {char* ip; char* sact; enum respip_action act;} - addr_action_t; - -/** Utility function that verifies that the respip set has actions as expected */ -static void -verify_respip_set_actions(struct respip_set* set, addr_action_t actions[], - int actions_len) -{ - int i = 0; - struct rbtree_type* tree = respip_set_get_tree(set); - for (i=0; i<actions_len; i++) { - struct sockaddr_storage addr; - int net; - socklen_t addrlen; - struct resp_addr* node; - netblockstrtoaddr(actions[i].ip, UNBOUND_DNS_PORT, &addr, - &addrlen, &net); - node = (struct resp_addr*)addr_tree_find(tree, &addr, addrlen, net); - - /** we have the node and the node has the correct action - * and has no data */ - unit_assert(node); - unit_assert(actions[i].act == - resp_addr_get_action(node)); - unit_assert(resp_addr_get_rrset(node) == NULL); - } - unit_assert(actions_len && i == actions_len); - unit_assert(actions_len == (int)tree->count); -} - -/** Global respip actions test; apply raw config data and verify that - * all the nodes in the respip set, looked up by address, have expected - * actions */ -static void -respip_conf_actions_test(void) -{ - addr_action_t config_response_ip[] = { - {"192.0.1.0/24", "deny", respip_deny}, - {"192.0.2.0/24", "redirect", respip_redirect}, - {"192.0.3.0/26", "inform", respip_inform}, - {"192.0.4.0/27", "inform_deny", respip_inform_deny}, - {"2001:db8:1::/48", "always_transparent", respip_always_transparent}, - {"2001:db8:2::/49", "always_refuse", respip_always_refuse}, - {"2001:db8:3::/50", "always_nxdomain", respip_always_nxdomain}, - }; - int i; - struct respip_set* set = respip_set_create(); - struct config_file cfg; - int clen = (int)(sizeof(config_response_ip) / sizeof(addr_action_t)); - - unit_assert(set); - unit_show_feature("global respip config actions apply"); - memset(&cfg, 0, sizeof(cfg)); - for(i=0; i<clen; i++) { - char* ip = strdup(config_response_ip[i].ip); - char* sact = strdup(config_response_ip[i].sact); - unit_assert(ip && sact); - if(!cfg_str2list_insert(&cfg.respip_actions, ip, sact)) - unit_assert(0); - } - unit_assert(respip_global_apply_cfg(set, &cfg)); - verify_respip_set_actions(set, config_response_ip, clen); -} - -/** Per-view respip actions test; apply raw configuration with two views - * and verify that actions are as expected in respip sets of both views */ -static void -respip_view_conf_actions_test(void) -{ - addr_action_t config_response_ip_view1[] = { - {"192.0.1.0/24", "deny", respip_deny}, - {"192.0.2.0/24", "redirect", respip_redirect}, - {"192.0.3.0/26", "inform", respip_inform}, - {"192.0.4.0/27", "inform_deny", respip_inform_deny}, - }; - addr_action_t config_response_ip_view2[] = { - {"2001:db8:1::/48", "always_transparent", respip_always_transparent}, - {"2001:db8:2::/49", "always_refuse", respip_always_refuse}, - {"2001:db8:3::/50", "always_nxdomain", respip_always_nxdomain}, - }; - int i; - struct config_file cfg; - int clen1 = (int)(sizeof(config_response_ip_view1) / sizeof(addr_action_t)); - int clen2 = (int)(sizeof(config_response_ip_view2) / sizeof(addr_action_t)); - struct config_view* cv1; - struct config_view* cv2; - int have_respip_cfg = 0; - struct views* views = NULL; - struct view* v = NULL; - - unit_show_feature("per-view respip config actions apply"); - memset(&cfg, 0, sizeof(cfg)); - cv1 = (struct config_view*)calloc(1, sizeof(struct config_view)); - cv2 = (struct config_view*)calloc(1, sizeof(struct config_view)); - unit_assert(cv1 && cv2); - cv1->name = strdup("view1"); - cv2->name = strdup("view2"); - unit_assert(cv1->name && cv2->name); - cv1->next = cv2; - cfg.views = cv1; - - for(i=0; i<clen1; i++) { - char* ip = strdup(config_response_ip_view1[i].ip); - char* sact = strdup(config_response_ip_view1[i].sact); - unit_assert(ip && sact); - if(!cfg_str2list_insert(&cv1->respip_actions, ip, sact)) - unit_assert(0); - } - for(i=0; i<clen2; i++) { - char* ip = strdup(config_response_ip_view2[i].ip); - char* sact = strdup(config_response_ip_view2[i].sact); - unit_assert(ip && sact); - if(!cfg_str2list_insert(&cv2->respip_actions, ip, sact)) - unit_assert(0); - } - views = views_create(); - unit_assert(views); - unit_assert(views_apply_cfg(views, &cfg)); - unit_assert(respip_views_apply_cfg(views, &cfg, &have_respip_cfg)); - - /* now verify the respip sets in each view */ - v = views_find_view(views, "view1", 0); - unit_assert(v); - verify_respip_set_actions(v->respip_set, config_response_ip_view1, clen1); - lock_rw_unlock(&v->lock); - v = views_find_view(views, "view2", 0); - unit_assert(v); - verify_respip_set_actions(v->respip_set, config_response_ip_view2, clen2); - lock_rw_unlock(&v->lock); -} - -typedef struct addr_data {char* ip; char* data;} addr_data_t; - -/** find the respip address node in the specified tree (by address lookup) - * and verify type and address of the specified rdata (by index) in this - * node's rrset */ -static void -verify_rrset(struct respip_set* set, const char* ipstr, - const char* rdatastr, size_t rdi, uint16_t type) -{ - struct sockaddr_storage addr; - int net; - char buf[65536]; - socklen_t addrlen; - struct rbtree_type* tree; - struct resp_addr* node; - const struct ub_packed_rrset_key* rrs; - - netblockstrtoaddr(ipstr, UNBOUND_DNS_PORT, &addr, &addrlen, &net); - tree = respip_set_get_tree(set); - node = (struct resp_addr*)addr_tree_find(tree, &addr, addrlen, net); - unit_assert(node); - unit_assert((rrs = resp_addr_get_rrset(node))); - unit_assert(ntohs(rrs->rk.type) == type); - packed_rr_to_string((struct ub_packed_rrset_key*)rrs, - rdi, 0, buf, sizeof(buf)); - unit_assert(strstr(buf, rdatastr)); -} - -/** Dataset used to test redirect rrset initialization for both - * global and per-view respip redirect configuration */ -static addr_data_t config_response_ip_data[] = { - {"192.0.1.0/24", "A 1.2.3.4"}, - {"192.0.1.0/24", "A 11.12.13.14"}, - {"192.0.2.0/24", "CNAME www.example.com."}, - {"2001:db8:1::/48", "AAAA 2001:db8:1::2:1"}, -}; - -/** Populate raw respip redirect config data, used for both global and - * view-based respip redirect test case */ -static void -cfg_insert_respip_data(struct config_str2list** respip_actions, - struct config_str2list** respip_data) -{ - int clen = (int)(sizeof(config_response_ip_data) / sizeof(addr_data_t)); - int i = 0; - - /* insert actions (duplicate netblocks don't matter) */ - for(i=0; i<clen; i++) { - char* ip = strdup(config_response_ip_data[i].ip); - char* sact = strdup("redirect"); - unit_assert(ip && sact); - if(!cfg_str2list_insert(respip_actions, ip, sact)) - unit_assert(0); - } - /* insert data */ - for(i=0; i<clen; i++) { - char* ip = strdup(config_response_ip_data[i].ip); - char* data = strdup(config_response_ip_data[i].data); - unit_assert(ip && data); - if(!cfg_str2list_insert(respip_data, ip, data)) - unit_assert(0); - } -} - -/** Test global respip redirect w/ data directives */ -static void -respip_conf_data_test(void) -{ - struct respip_set* set = respip_set_create(); - struct config_file cfg; - - unit_show_feature("global respip config data apply"); - memset(&cfg, 0, sizeof(cfg)); - - cfg_insert_respip_data(&cfg.respip_actions, &cfg.respip_data); - - /* apply configuration and verify rrsets */ - unit_assert(respip_global_apply_cfg(set, &cfg)); - verify_rrset(set, "192.0.1.0/24", "1.2.3.4", 0, LDNS_RR_TYPE_A); - verify_rrset(set, "192.0.1.0/24", "11.12.13.14", 1, LDNS_RR_TYPE_A); - verify_rrset(set, "192.0.2.0/24", "www.example.com", 0, LDNS_RR_TYPE_CNAME); - verify_rrset(set, "2001:db8:1::/48", "2001:db8:1::2:1", 0, LDNS_RR_TYPE_AAAA); -} - -/** Test per-view respip redirect w/ data directives */ -static void -respip_view_conf_data_test(void) -{ - struct config_file cfg; - struct config_view* cv; - int have_respip_cfg = 0; - struct views* views = NULL; - struct view* v = NULL; - - unit_show_feature("per-view respip config data apply"); - memset(&cfg, 0, sizeof(cfg)); - cv = (struct config_view*)calloc(1, sizeof(struct config_view)); - unit_assert(cv); - cv->name = strdup("view1"); - unit_assert(cv->name); - cfg.views = cv; - cfg_insert_respip_data(&cv->respip_actions, &cv->respip_data); - views = views_create(); - unit_assert(views); - unit_assert(views_apply_cfg(views, &cfg)); - - /* apply configuration and verify rrsets */ - unit_assert(respip_views_apply_cfg(views, &cfg, &have_respip_cfg)); - v = views_find_view(views, "view1", 0); - unit_assert(v); - verify_rrset(v->respip_set, "192.0.1.0/24", "1.2.3.4", - 0, LDNS_RR_TYPE_A); - verify_rrset(v->respip_set, "192.0.1.0/24", "11.12.13.14", - 1, LDNS_RR_TYPE_A); - verify_rrset(v->respip_set, "192.0.2.0/24", "www.example.com", - 0, LDNS_RR_TYPE_CNAME); - verify_rrset(v->respip_set, "2001:db8:1::/48", "2001:db8:1::2:1", - 0, LDNS_RR_TYPE_AAAA); -} - -/** respip unit tests */ -static void respip_test(void) -{ - respip_view_conf_data_test(); - respip_conf_data_test(); - respip_view_conf_actions_test(); - respip_conf_actions_test(); -} - -void unit_show_func(const char* file, const char* func) -{ - printf("test %s:%s\n", file, func); -} - -void unit_show_feature(const char* feature) -{ - printf("test %s functions\n", feature); -} - -#ifdef USE_ECDSA_EVP_WORKAROUND -void ecdsa_evp_workaround_init(void); -#endif -/** - * Main unit test program. Setup, teardown and report errors. - * @param argc: arg count. - * @param argv: array of commandline arguments. - * @return program failure if test fails. - */ -int -main(int argc, char* argv[]) -{ - log_init(NULL, 0, NULL); - if(argc != 1) { - printf("usage: %s\n", argv[0]); - printf("\tperforms unit tests.\n"); - return 1; - } - printf("Start of %s unit test.\n", PACKAGE_STRING); -#ifdef HAVE_SSL -# ifdef HAVE_ERR_LOAD_CRYPTO_STRINGS - ERR_load_crypto_strings(); -# endif -# ifdef USE_GOST - (void)sldns_key_EVP_load_gost_id(); -# endif -# ifdef USE_ECDSA_EVP_WORKAROUND - ecdsa_evp_workaround_init(); -# endif -#elif defined(HAVE_NSS) - if(NSS_NoDB_Init(".") != SECSuccess) - fatal_exit("could not init NSS"); -#endif /* HAVE_SSL or HAVE_NSS*/ - checklock_start(); - neg_test(); - rnd_test(); - respip_test(); - verify_test(); - net_test(); - config_memsize_test(); - config_tag_test(); - dname_test(); - rtt_test(); - anchors_test(); - alloc_test(); - regional_test(); - lruhash_test(); - slabhash_test(); - infra_test(); - ldns_test(); - msgparse_test(); -#ifdef CLIENT_SUBNET - ecs_test(); -#endif /* CLIENT_SUBNET */ - checklock_stop(); - printf("%d checks ok.\n", testcount); -#ifdef HAVE_SSL -# if defined(USE_GOST) && defined(HAVE_LDNS_KEY_EVP_UNLOAD_GOST) - sldns_key_EVP_unload_gost(); -# endif -# ifdef HAVE_OPENSSL_CONFIG -# ifdef HAVE_EVP_CLEANUP - EVP_cleanup(); -# endif - ENGINE_cleanup(); - CONF_modules_free(); -# endif -# ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA - CRYPTO_cleanup_all_ex_data(); -# endif -# ifdef HAVE_ERR_FREE_STRINGS - ERR_free_strings(); -# endif -# ifdef HAVE_RAND_CLEANUP - RAND_cleanup(); -# endif -#elif defined(HAVE_NSS) - if(NSS_Shutdown() != SECSuccess) - fatal_exit("could not shutdown NSS"); -#endif /* HAVE_SSL or HAVE_NSS */ -#ifdef HAVE_PTHREAD - /* dlopen frees its thread specific state */ - pthread_exit(NULL); -#endif - return 0; -} diff --git a/external/unbound/testcode/unitmain.h b/external/unbound/testcode/unitmain.h deleted file mode 100644 index d81b603b2..000000000 --- a/external/unbound/testcode/unitmain.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * testcode/unitmain.h - unit test main program 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 - * Declarations useful for the unit tests. - */ - -#ifndef TESTCODE_UNITMAIN_H -#define TESTCODE_UNITMAIN_H -#include "util/log.h" - -/** number of tests done */ -extern int testcount; -/** test bool x, exits on failure, increases testcount. */ -#ifdef DEBUG_UNBOUND -#define unit_assert(x) do {testcount++; log_assert(x);} while(0) -#else -#define unit_assert(x) do {testcount++; if(!(x)) { fprintf(stderr, "assertion failure %s:%d\n", __FILE__, __LINE__); exit(1);}} while(0) -#endif - -/** we are now testing this function */ -void unit_show_func(const char* file, const char* func); -/** we are testing this functionality */ -void unit_show_feature(const char* feature); - -/** unit test lruhashtable implementation */ -void lruhash_test(void); -/** unit test slabhashtable implementation */ -void slabhash_test(void); -/** unit test for msgreply and msgparse */ -void msgparse_test(void); -/** unit test dname handling functions */ -void dname_test(void); -/** unit test trust anchor storage functions */ -void anchors_test(void); -/** unit test for verification functions */ -void verify_test(void); -/** unit test for negative cache functions */ -void neg_test(void); -/** unit test for regional allocator functions */ -void regional_test(void); -#ifdef CLIENT_SUBNET -/** Unit test for ECS functions */ -void ecs_test(void); -#endif /* CLIENT_SUBNET */ -/** unit test for ldns functions */ -void ldns_test(void); - -#endif /* TESTCODE_UNITMAIN_H */ diff --git a/external/unbound/testcode/unitmsgparse.c b/external/unbound/testcode/unitmsgparse.c deleted file mode 100644 index 627d10b78..000000000 --- a/external/unbound/testcode/unitmsgparse.c +++ /dev/null @@ -1,542 +0,0 @@ -/* - * testcode/unitmsgparse.c - unit test for msg parse 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 - * Calls msg parse unit tests. Exits with code 1 on a failure. - */ - -#include "config.h" -#include <sys/time.h> -#include "util/log.h" -#include "testcode/unitmain.h" -#include "util/data/msgparse.h" -#include "util/data/msgreply.h" -#include "util/data/msgencode.h" -#include "util/data/dname.h" -#include "util/alloc.h" -#include "util/regional.h" -#include "util/net_help.h" -#include "testcode/readhex.h" -#include "testcode/testpkts.h" -#include "sldns/sbuffer.h" -#include "sldns/str2wire.h" -#include "sldns/wire2str.h" - -/** verbose message parse unit test */ -static int vbmp = 0; -/** do not accept formerr */ -static int check_formerr_gone = 0; -/** if matching within a section should disregard the order of RRs. */ -static int matches_nolocation = 0; -/** see if RRSIGs are properly matched to RRsets. */ -static int check_rrsigs = 0; -/** do not check buffer sameness */ -static int check_nosameness = 0; - -/** see if buffers contain the same packet */ -static int -test_buffers(sldns_buffer* pkt, sldns_buffer* out) -{ - /* check binary same */ - if(sldns_buffer_limit(pkt) == sldns_buffer_limit(out) && - memcmp(sldns_buffer_begin(pkt), sldns_buffer_begin(out), - sldns_buffer_limit(pkt)) == 0) { - if(vbmp) printf("binary the same (length=%u)\n", - (unsigned)sldns_buffer_limit(pkt)); - return 1; - } - - if(vbmp) { - size_t sz = 16; - size_t count; - size_t lim = sldns_buffer_limit(out); - if(sldns_buffer_limit(pkt) < lim) - lim = sldns_buffer_limit(pkt); - for(count=0; count<lim; count+=sz) { - size_t rem = sz; - if(lim-count < sz) rem = lim-count; - if(memcmp(sldns_buffer_at(pkt, count), - sldns_buffer_at(out, count), rem) == 0) { - log_info("same %d %d", (int)count, (int)rem); - log_hex("same: ", sldns_buffer_at(pkt, count), - rem); - } else { - log_info("diff %d %d", (int)count, (int)rem); - log_hex("difp: ", sldns_buffer_at(pkt, count), - rem); - log_hex("difo: ", sldns_buffer_at(out, count), - rem); - } - } - } - - /* check if it 'means the same' */ - if(vbmp) { - char* s1, *s2; - log_buf(0, "orig in hex", pkt); - log_buf(0, "unbound out in hex", out); - printf("\npacket from unbound (%d):\n", - (int)sldns_buffer_limit(out)); - s1 = sldns_wire2str_pkt(sldns_buffer_begin(out), - sldns_buffer_limit(out)); - printf("%s\n", s1?s1:"null"); - free(s1); - - printf("\npacket original (%d):\n", - (int)sldns_buffer_limit(pkt)); - s2 = sldns_wire2str_pkt(sldns_buffer_begin(pkt), - sldns_buffer_limit(pkt)); - printf("%s\n", s2?s2:"null"); - free(s2); - printf("\n"); - } - /* if it had two EDNS sections, skip comparison */ - if(1) { - char* s = sldns_wire2str_pkt(sldns_buffer_begin(pkt), - sldns_buffer_limit(pkt)); - char* e1 = strstr(s, "; EDNS:"); - if(e1 && strstr(e1+4, "; EDNS:")) { - free(s); - return 0; - } - free(s); - } - /* compare packets */ - unit_assert(match_all(sldns_buffer_begin(pkt), sldns_buffer_limit(pkt), - sldns_buffer_begin(out), sldns_buffer_limit(out), 1, - matches_nolocation)); - return 0; -} - -/** check if unbound formerr equals ldns formerr */ -static void -checkformerr(sldns_buffer* pkt) -{ - int status = 0; - char* s = sldns_wire2str_pkt(sldns_buffer_begin(pkt), - sldns_buffer_limit(pkt)); - if(!s) fatal_exit("out of memory"); - if(strstr(s, "Error")) status = 1; - if(strstr(s, "error")) status = 1; - if(status == 0) { - printf("Formerr, but ldns gives packet:\n"); - printf("%s\n", s); - free(s); - exit(1); - } - free(s); - unit_assert(status != 0); -} - -/** performance test message encoding */ -static void -perf_encode(struct query_info* qi, struct reply_info* rep, uint16_t id, - uint16_t flags, sldns_buffer* out, time_t timenow, - struct edns_data* edns) -{ - static int num = 0; - int ret; - size_t max = 10000; - size_t i; - struct timeval start, end; - double dt; - struct regional* r2 = regional_create(); - if(gettimeofday(&start, NULL) < 0) - fatal_exit("gettimeofday: %s", strerror(errno)); - /* encode a couple times */ - for(i=0; i<max; i++) { - ret = reply_info_encode(qi, rep, id, flags, out, timenow, - r2, 65535, (int)(edns->bits & EDNS_DO) ); - unit_assert(ret != 0); /* udp packets should fit */ - attach_edns_record(out, edns); - regional_free_all(r2); - } - if(gettimeofday(&end, NULL) < 0) - fatal_exit("gettimeofday: %s", strerror(errno)); - /* time in millisec */ - dt = (double)(end.tv_sec - start.tv_sec)*1000. + - ((double)end.tv_usec - (double)start.tv_usec)/1000.; - printf("[%d] did %u in %g msec for %f encode/sec size %d\n", num++, - (unsigned)max, dt, (double)max / (dt/1000.), - (int)sldns_buffer_limit(out)); - regional_destroy(r2); -} - -/** perf test a packet */ -static void -perftestpkt(sldns_buffer* pkt, struct alloc_cache* alloc, sldns_buffer* out, - const char* hex) -{ - struct query_info qi; - struct reply_info* rep = 0; - int ret; - uint16_t id; - uint16_t flags; - time_t timenow = 0; - struct regional* region = regional_create(); - struct edns_data edns; - - hex_to_buf(pkt, hex); - memmove(&id, sldns_buffer_begin(pkt), sizeof(id)); - if(sldns_buffer_limit(pkt) < 2) - flags = 0; - else memmove(&flags, sldns_buffer_at(pkt, 2), sizeof(flags)); - flags = ntohs(flags); - ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns); - if(ret != 0) { - char rbuf[16]; - sldns_wire2str_rcode_buf(ret, rbuf, sizeof(rbuf)); - if(vbmp) printf("parse code %d: %s\n", ret, rbuf); - if(ret == LDNS_RCODE_FORMERR) - checkformerr(pkt); - unit_assert(ret != LDNS_RCODE_SERVFAIL); - } else { - perf_encode(&qi, rep, id, flags, out, timenow, &edns); - } - - query_info_clear(&qi); - reply_info_parsedelete(rep, alloc); - regional_destroy(region); -} - -/** print packed rrset */ -static void -print_rrset(struct ub_packed_rrset_key* rrset) -{ - struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> - entry.data; - char buf[65535]; - size_t i; - for(i=0; i<d->count+d->rrsig_count; i++) { - if(!packed_rr_to_string(rrset, i, 0, buf, sizeof(buf))) - printf("failedtoconvert %d\n", (int)i); - else - printf("%s\n", buf); - } -} - -/** debug print a packet that failed */ -static void -print_packet_rrsets(struct query_info* qinfo, struct reply_info* rep) -{ - size_t i; - log_query_info(0, "failed query", qinfo); - printf(";; ANSWER SECTION (%d rrsets)\n", (int)rep->an_numrrsets); - for(i=0; i<rep->an_numrrsets; i++) { - printf("; rrset %d\n", (int)i); - print_rrset(rep->rrsets[i]); - } - printf(";; AUTHORITY SECTION (%d rrsets)\n", (int)rep->ns_numrrsets); - for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) { - printf("; rrset %d\n", (int)i); - print_rrset(rep->rrsets[i]); - } - printf(";; ADDITIONAL SECTION (%d rrsets)\n", (int)rep->ar_numrrsets); - for(i=rep->an_numrrsets+rep->ns_numrrsets; i<rep->rrset_count; i++) { - printf("; rrset %d\n", (int)i); - print_rrset(rep->rrsets[i]); - } - printf(";; packet end\n"); -} - -/** check that there is no data element that matches the RRSIG */ -static int -no_data_for_rrsig(struct reply_info* rep, struct ub_packed_rrset_key* rrsig) -{ - size_t i; - for(i=0; i<rep->rrset_count; i++) { - if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_RRSIG) - continue; - if(query_dname_compare(rep->rrsets[i]->rk.dname, - rrsig->rk.dname) == 0) - /* only name is compared right now */ - return 0; - } - return 1; -} - -/** check RRSIGs in packet */ -static void -check_the_rrsigs(struct query_info* qinfo, struct reply_info* rep) -{ - /* every RRSIG must be matched to an RRset */ - 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) == LDNS_RR_TYPE_RRSIG) { - /* see if really a problem, i.e. is there a data - * element. */ - if(no_data_for_rrsig(rep, rep->rrsets[i])) - continue; - log_dns_msg("rrsig failed for packet", qinfo, rep); - print_packet_rrsets(qinfo, rep); - printf("failed rrset is nr %d\n", (int)i); - unit_assert(0); - } - } -} - -/** test a packet */ -static void -testpkt(sldns_buffer* pkt, struct alloc_cache* alloc, sldns_buffer* out, - const char* hex) -{ - struct query_info qi; - struct reply_info* rep = 0; - int ret; - uint16_t id; - uint16_t flags; - uint32_t timenow = 0; - struct regional* region = regional_create(); - struct edns_data edns; - - hex_to_buf(pkt, hex); - memmove(&id, sldns_buffer_begin(pkt), sizeof(id)); - if(sldns_buffer_limit(pkt) < 2) - flags = 0; - else memmove(&flags, sldns_buffer_at(pkt, 2), sizeof(flags)); - flags = ntohs(flags); - ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns); - if(ret != 0) { - char rbuf[16]; - sldns_wire2str_rcode_buf(ret, rbuf, sizeof(rbuf)); - if(vbmp) printf("parse code %d: %s\n", ret, rbuf); - if(ret == LDNS_RCODE_FORMERR) { - unit_assert(!check_formerr_gone); - checkformerr(pkt); - } - unit_assert(ret != LDNS_RCODE_SERVFAIL); - } else if(!check_formerr_gone) { - const size_t lim = 512; - ret = reply_info_encode(&qi, rep, id, flags, out, timenow, - region, 65535, (int)(edns.bits & EDNS_DO) ); - unit_assert(ret != 0); /* udp packets should fit */ - attach_edns_record(out, &edns); - if(vbmp) printf("inlen %u outlen %u\n", - (unsigned)sldns_buffer_limit(pkt), - (unsigned)sldns_buffer_limit(out)); - if(!check_nosameness) - test_buffers(pkt, out); - if(check_rrsigs) - check_the_rrsigs(&qi, rep); - - if(sldns_buffer_limit(out) > lim) { - ret = reply_info_encode(&qi, rep, id, flags, out, - timenow, region, - lim - calc_edns_field_size(&edns), - (int)(edns.bits & EDNS_DO)); - unit_assert(ret != 0); /* should fit, but with TC */ - attach_edns_record(out, &edns); - if( LDNS_QDCOUNT(sldns_buffer_begin(out)) != - LDNS_QDCOUNT(sldns_buffer_begin(pkt)) || - LDNS_ANCOUNT(sldns_buffer_begin(out)) != - LDNS_ANCOUNT(sldns_buffer_begin(pkt)) || - LDNS_NSCOUNT(sldns_buffer_begin(out)) != - LDNS_NSCOUNT(sldns_buffer_begin(pkt))) - unit_assert( - LDNS_TC_WIRE(sldns_buffer_begin(out))); - /* must set TC bit if shortened */ - unit_assert(sldns_buffer_limit(out) <= lim); - } - } - - query_info_clear(&qi); - reply_info_parsedelete(rep, alloc); - regional_destroy(region); -} - -/** simple test of parsing */ -static void -simpletest(sldns_buffer* pkt, struct alloc_cache* alloc, sldns_buffer* out) -{ - /* a root query drill -q - */ - testpkt(pkt, alloc, out, - " c5 40 01 00 00 01 00 00 00 00 00 00 00 00 02 00 01 "); - - /* very small packet */ - testpkt(pkt, alloc, out, -"; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19\n" -";-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n" -"74 0c 85 83 00 01 00 00 00 01 00 00 03 62 6c 61 09 6e 6c 6e ; 1- 20\n" -"65 74 6c 61 62 73 02 6e 6c 00 00 0f 00 01 09 6e 6c 6e 65 74 ; 21- 40\n" -"6c 61 62 73 02 6e 6c 00 00 06 00 01 00 00 46 50 00 40 04 6f ; 41- 60\n" -"70 65 6e 09 6e 6c 6e 65 74 6c 61 62 73 02 6e 6c 00 0a 68 6f ; 61- 80\n" -"73 74 6d 61 73 74 65 72 09 6e 6c 6e 65 74 6c 61 62 73 02 6e ; 81- 100\n" -"6c 00 77 a1 02 58 00 00 70 80 00 00 1c 20 00 09 3a 80 00 00 ; 101- 120\n" -"46 50\n"); - - /* a root reply drill -w - */ - testpkt(pkt, alloc, out, - " ; 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19\n" - " ;-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --\n" - " 97 3f 81 80 00 01 00 0d 00 00 00 02 00 00 02 00 01 00 00 02 ; 1- 20\n" - " 00 01 00 06 6d 38 00 14 01 49 0c 52 4f 4f 54 2d 53 45 52 56 ; 21- 40\n" - " 45 52 53 03 4e 45 54 00 00 00 02 00 01 00 06 6d 38 00 14 01 ; 41- 60\n" - " 4a 0c 52 4f 4f 54 2d 53 45 52 56 45 52 53 03 4e 45 54 00 00 ; 61- 80\n" - " 00 02 00 01 00 06 6d 38 00 14 01 4b 0c 52 4f 4f 54 2d 53 45 ; 81- 100\n" - " 52 56 45 52 53 03 4e 45 54 00 00 00 02 00 01 00 06 6d 38 00 ; 101- 120\n" - " 14 01 4c 0c 52 4f 4f 54 2d 53 45 52 56 45 52 53 03 4e 45 54 ; 121- 140\n" - " 00 00 00 02 00 01 00 06 6d 38 00 14 01 4d 0c 52 4f 4f 54 2d ; 141- 160\n" - " 53 45 52 56 45 52 53 03 4e 45 54 00 00 00 02 00 01 00 06 6d ; 161- 180\n" - " 38 00 14 01 41 0c 52 4f 4f 54 2d 53 45 52 56 45 52 53 03 4e ; 181- 200\n" - " 45 54 00 00 00 02 00 01 00 06 6d 38 00 14 01 42 0c 52 4f 4f ; 201- 220\n" - " 54 2d 53 45 52 56 45 52 53 03 4e 45 54 00 00 00 02 00 01 00 ; 221- 240\n" - " 06 6d 38 00 14 01 43 0c 52 4f 4f 54 2d 53 45 52 56 45 52 53 ; 241- 260\n" - " 03 4e 45 54 00 00 00 02 00 01 00 06 6d 38 00 14 01 44 0c 52 ; 261- 280\n" - " 4f 4f 54 2d 53 45 52 56 45 52 53 03 4e 45 54 00 00 00 02 00 ; 281- 300\n" - " 01 00 06 6d 38 00 14 01 45 0c 52 4f 4f 54 2d 53 45 52 56 45 ; 301- 320\n" - " 52 53 03 4e 45 54 00 00 00 02 00 01 00 06 6d 38 00 14 01 46 ; 321- 340\n" - " 0c 52 4f 4f 54 2d 53 45 52 56 45 52 53 03 4e 45 54 00 00 00 ; 341- 360\n" - " 02 00 01 00 06 6d 38 00 14 01 47 0c 52 4f 4f 54 2d 53 45 52 ; 361- 380\n" - " 56 45 52 53 03 4e 45 54 00 00 00 02 00 01 00 06 6d 38 00 14 ; 381- 400\n" - " 01 48 0c 52 4f 4f 54 2d 53 45 52 56 45 52 53 03 4e 45 54 00 ; 401- 420\n" - " 01 41 0c 52 4f 4f 54 2d 53 45 52 56 45 52 53 03 4e 45 54 00 ; 421- 440\n" - " 00 01 00 01 00 02 64 b9 00 04 c6 29 00 04 01 4a 0c 52 4f 4f ; 441- 460\n" - " 54 2d 53 45 52 56 45 52 53 03 4e 45 54 00 00 01 00 01 00 02 ; 461- 480\n" - " 64 b9 00 04 c0 3a 80 1e "); - - /* root delegation from unbound trace with new AAAA glue */ - perftestpkt(pkt, alloc, out, - "55BC84000001000D00000014000002000100000200010007E900001401610C726F6F742D73657276657273036E65740000000200010007E90000040162C01E00000200010007E90000040163C01E00000200010007E90000040164C01E00000200010007E90000040165C01E00000200010007E90000040166C01E00000200010007E90000040167C01E00000200010007E90000040168C01E00000200010007E90000040169C01E00000200010007E9000004016AC01E00000200010007E9000004016BC01E00000200010007E9000004016CC01E00000200010007E9000004016DC01EC01C000100010007E9000004C6290004C03B000100010007E9000004C0E44FC9C04A000100010007E9000004C021040CC059000100010007E900000480080A5AC068000100010007E9000004C0CBE60AC077000100010007E9000004C00505F1C086000100010007E9000004C0702404C095000100010007E9000004803F0235C0A4000100010007E9000004C0249411C0B3000100010007E9000004C03A801EC0C2000100010007E9000004C1000E81C0D1000100010007E9000004C707532AC0E0000100010007E9000004CA0C1B21C01C001C00010007E900001020010503BA3E00000000000000020030C077001C00010007E900001020010500002F0000000000000000000FC095001C00010007E90000102001050000010000" - "00000000803F0235C0B3001C00010007E9000010200105030C2700000000000000020030C0C2001C00010007E9000010200107FD000000000000000000000001C0E0001C00010007E900001020010DC30000000000000000000000350000291000000000000000" - ); -} - -/** simple test of parsing, pcat file */ -static void -testfromfile(sldns_buffer* pkt, struct alloc_cache* alloc, sldns_buffer* out, - const char* fname) -{ - FILE* in = fopen(fname, "r"); - char buf[102400]; - int no=0; - if(!in) { - perror("fname"); - return; - } - while(fgets(buf, (int)sizeof(buf), in)) { - if(buf[0] == ';') /* comment */ - continue; - if(strlen(buf) < 10) /* skip pcat line numbers. */ - continue; - if(vbmp) { - printf("test no %d: %s", no, buf); - fflush(stdout); - } - testpkt(pkt, alloc, out, buf); - no++; - } - fclose(in); -} - -/** simple test of parsing, drill file */ -static void -testfromdrillfile(sldns_buffer* pkt, struct alloc_cache* alloc, - sldns_buffer* out, const char* fname) -{ - /* ;-- is used to indicate a new message */ - FILE* in = fopen(fname, "r"); - char buf[102400]; - char* np = buf; - buf[0]=0; - if(!in) { - perror("fname"); - return; - } - while(fgets(np, (int)sizeof(buf) - (np-buf), in)) { - if(strncmp(np, ";--", 3) == 0) { - /* new entry */ - /* test previous */ - if(np != buf) - testpkt(pkt, alloc, out, buf); - /* set for new entry */ - np = buf; - buf[0]=0; - continue; - } - if(np[0] == ';') /* comment */ - continue; - np = &np[strlen(np)]; - } - testpkt(pkt, alloc, out, buf); - fclose(in); -} - -void msgparse_test(void) -{ - time_t origttl = MAX_NEG_TTL; - sldns_buffer* pkt = sldns_buffer_new(65553); - sldns_buffer* out = sldns_buffer_new(65553); - struct alloc_cache super_a, alloc; - MAX_NEG_TTL = 86400; - /* init */ - alloc_init(&super_a, NULL, 0); - alloc_init(&alloc, &super_a, 2); - - unit_show_feature("message parse"); - simpletest(pkt, &alloc, out); - /* plain hex dumps, like pcat */ - testfromfile(pkt, &alloc, out, "testdata/test_packets.1"); - testfromfile(pkt, &alloc, out, "testdata/test_packets.2"); - testfromfile(pkt, &alloc, out, "testdata/test_packets.3"); - /* like from drill -w - */ - testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.4"); - testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.5"); - - matches_nolocation = 1; /* RR order not important for the next test */ - testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.6"); - check_rrsigs = 1; - testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.7"); - check_rrsigs = 0; - matches_nolocation = 0; - - check_formerr_gone = 1; - testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.8"); - check_formerr_gone = 0; - - check_rrsigs = 1; - check_nosameness = 1; - testfromdrillfile(pkt, &alloc, out, "testdata/test_packets.9"); - check_nosameness = 0; - check_rrsigs = 0; - - /* cleanup */ - alloc_clear(&alloc); - alloc_clear(&super_a); - sldns_buffer_free(pkt); - sldns_buffer_free(out); - MAX_NEG_TTL = origttl; -} diff --git a/external/unbound/testcode/unitneg.c b/external/unbound/testcode/unitneg.c deleted file mode 100644 index 2b67df182..000000000 --- a/external/unbound/testcode/unitneg.c +++ /dev/null @@ -1,543 +0,0 @@ -/* - * testcode/unitneg.c - unit test for negative cache routines. - * - * 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 - * Calls negative cache unit tests. Exits with code 1 on a failure. - */ - -#include "config.h" -#include "util/log.h" -#include "util/net_help.h" -#include "util/data/packed_rrset.h" -#include "util/data/dname.h" -#include "testcode/unitmain.h" -#include "validator/val_neg.h" -#include "sldns/rrdef.h" - -/** verbose unit test for negative cache */ -static int negverbose = 0; - -/** debug printout of neg cache */ -static void print_neg_cache(struct val_neg_cache* neg) -{ - char buf[1024]; - struct val_neg_zone* z; - struct val_neg_data* d; - printf("neg_cache print\n"); - printf("memuse %d of %d\n", (int)neg->use, (int)neg->max); - printf("maxiter %d\n", (int)neg->nsec3_max_iter); - printf("%d zones\n", (int)neg->tree.count); - RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) { - dname_str(z->name, buf); - printf("%24s", buf); - printf(" len=%2.2d labs=%d inuse=%d count=%d tree.count=%d\n", - (int)z->len, z->labs, (int)z->in_use, z->count, - (int)z->tree.count); - } - RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) { - printf("\n"); - dname_print(stdout, NULL, z->name); - printf(" zone details\n"); - printf("len=%2.2d labs=%d inuse=%d count=%d tree.count=%d\n", - (int)z->len, z->labs, (int)z->in_use, z->count, - (int)z->tree.count); - if(z->parent) { - printf("parent="); - dname_print(stdout, NULL, z->parent->name); - printf("\n"); - } else { - printf("parent=NULL\n"); - } - - RBTREE_FOR(d, struct val_neg_data*, &z->tree) { - dname_str(d->name, buf); - printf("%24s", buf); - printf(" len=%2.2d labs=%d inuse=%d count=%d\n", - (int)d->len, d->labs, (int)d->in_use, d->count); - } - } -} - -/** get static pointer to random zone name */ -static char* get_random_zone(void) -{ - static char zname[256]; - int labels = random() % 3; - int i; - char* p = zname; - int labnum; - - for(i=0; i<labels; i++) { - labnum = random()%10; - snprintf(p, 256-(p-zname), "\003%3.3d", labnum); - p+=4; - } - snprintf(p, 256-(p-zname), "\007example\003com"); - return zname; -} - -/** get static pointer to random data names from and to */ -static void get_random_data(char** fromp, char** top, char* zname) -{ - static char buf1[256], buf2[256]; - int type; - int lab1, lab2; - int labnum1[10], labnum2[10]; - int i; - char* p; - - *fromp = buf1; - *top = buf2; - type = random()%10; - - if(type == 0) { - /* ENT */ - lab1 = random() %3 + 1; - lab2 = lab1 + random()%3 + 1; - for(i=0; i<lab1; i++) { - labnum1[i] = random()%100; - labnum2[i] = labnum1[i]; - } - for(i=lab1; i<lab2; i++) { - labnum2[i] = random()%100; - } - } else if(type == 1) { - /* end of zone */ - lab2 = 0; - lab1 = random()%3 + 1; - for(i=0; i<lab1; i++) { - labnum1[i] = random()%100; - } - } else if(type == 2) { - /* start of zone */ - lab1 = 0; - lab2 = random()%3 + 1; - for(i=0; i<lab2; i++) { - labnum2[i] = random()%100; - } - } else { - /* normal item */ - int common = random()%3; - lab1 = random() %3 + 1; - lab2 = random() %3 + 1; - for(i=0; i<common; i++) { - labnum1[i] = random()%100; - labnum2[i] = labnum1[i]; - } - labnum1[common] = random()%100; - labnum2[common] = labnum1[common] + random()%20; - for(i=common; i<lab1; i++) - labnum1[i] = random()%100; - for(i=common; i<lab2; i++) - labnum2[i] = random()%100; - } - - /* construct first */ - p = buf1; - for(i=0; i<lab1; i++) { - snprintf(p, 256-(p-buf1), "\003%3.3d", labnum1[i]); - p+=4; - } - snprintf(p, 256-(p-buf1), "%s", zname); - - /* construct 2nd */ - p = buf2+2; - for(i=0; i<lab2; i++) { - snprintf(p, 256-(p-buf2)-3, "\003%3.3d", labnum2[i]); - p+=4; - } - snprintf(p, 256-(p-buf2)-3, "%s", zname); - buf2[0] = (char)(strlen(buf2+2)+1); - buf2[1] = 0; - - if(negverbose) { - log_nametypeclass(0, "add from", (uint8_t*)buf1, 0, 0); - log_nametypeclass(0, "add to ", (uint8_t*)buf2+2, 0, 0); - } -} - -/** add a random item */ -static void add_item(struct val_neg_cache* neg) -{ - struct val_neg_zone* z; - struct packed_rrset_data rd; - struct ub_packed_rrset_key nsec; - size_t rr_len; - time_t rr_ttl; - uint8_t* rr_data; - char* zname = get_random_zone(); - char* from, *to; - - lock_basic_lock(&neg->lock); - if(negverbose) - log_nametypeclass(0, "add to zone", (uint8_t*)zname, 0, 0); - z = neg_find_zone(neg, (uint8_t*)zname, strlen(zname)+1, - LDNS_RR_CLASS_IN); - if(!z) { - z = neg_create_zone(neg, (uint8_t*)zname, strlen(zname)+1, - LDNS_RR_CLASS_IN); - } - unit_assert(z); - val_neg_zone_take_inuse(z); - - /* construct random NSEC item */ - get_random_data(&from, &to, zname); - - /* create nsec and insert it */ - memset(&rd, 0, sizeof(rd)); - memset(&nsec, 0, sizeof(nsec)); - nsec.rk.dname = (uint8_t*)from; - nsec.rk.dname_len = strlen(from)+1; - nsec.rk.type = htons(LDNS_RR_TYPE_NSEC); - nsec.rk.rrset_class = htons(LDNS_RR_CLASS_IN); - nsec.entry.data = &rd; - rd.security = sec_status_secure; - rd.count = 1; - rd.rr_len = &rr_len; - rr_len = 19; - rd.rr_ttl = &rr_ttl; - rr_ttl = 0; - rd.rr_data = &rr_data; - rr_data = (uint8_t*)to; - - neg_insert_data(neg, z, &nsec); - lock_basic_unlock(&neg->lock); -} - -/** remove a random item */ -static void remove_item(struct val_neg_cache* neg) -{ - int n, i; - struct val_neg_data* d; - rbnode_type* walk; - struct val_neg_zone* z; - - lock_basic_lock(&neg->lock); - if(neg->tree.count == 0) { - lock_basic_unlock(&neg->lock); - return; /* nothing to delete */ - } - - /* pick a random zone */ - walk = rbtree_first(&neg->tree); /* first highest parent, big count */ - z = (struct val_neg_zone*)walk; - n = random() % (int)(z->count); - if(negverbose) - printf("neg stress delete zone %d\n", n); - i=0; - walk = rbtree_first(&neg->tree); - z = (struct val_neg_zone*)walk; - while(i!=n+1 && walk && walk != RBTREE_NULL && !z->in_use) { - walk = rbtree_next(walk); - z = (struct val_neg_zone*)walk; - if(z->in_use) - i++; - } - if(!walk || walk == RBTREE_NULL) { - lock_basic_unlock(&neg->lock); - return; - } - if(!z->in_use) { - lock_basic_unlock(&neg->lock); - return; - } - if(negverbose) - log_nametypeclass(0, "delete zone", z->name, 0, 0); - - /* pick a random nsec item. - that is in use */ - walk = rbtree_first(&z->tree); /* first is highest parent */ - d = (struct val_neg_data*)walk; - n = random() % (int)(d->count); - if(negverbose) - printf("neg stress delete item %d\n", n); - i=0; - walk = rbtree_first(&z->tree); - d = (struct val_neg_data*)walk; - while(i!=n+1 && walk && walk != RBTREE_NULL && !d->in_use) { - walk = rbtree_next(walk); - d = (struct val_neg_data*)walk; - if(d->in_use) - i++; - } - if(!walk || walk == RBTREE_NULL) { - lock_basic_unlock(&neg->lock); - return; - } - if(d->in_use) { - if(negverbose) - log_nametypeclass(0, "neg delete item:", d->name, 0, 0); - neg_delete_data(neg, d); - } - lock_basic_unlock(&neg->lock); -} - -/** sum up the zone trees */ -static size_t sumtrees_all(struct val_neg_cache* neg) -{ - size_t res = 0; - struct val_neg_zone* z; - RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) { - res += z->tree.count; - } - return res; -} - -/** sum up the zone trees, in_use only */ -static size_t sumtrees_inuse(struct val_neg_cache* neg) -{ - size_t res = 0; - struct val_neg_zone* z; - struct val_neg_data* d; - RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) { - /* get count of highest parent for num in use */ - d = (struct val_neg_data*)rbtree_first(&z->tree); - if(d && (rbnode_type*)d!=RBTREE_NULL) - res += d->count; - } - return res; -} - -/** check if lru is still valid */ -static void check_lru(struct val_neg_cache* neg) -{ - struct val_neg_data* p, *np; - size_t num = 0; - size_t inuse; - p = neg->first; - while(p) { - if(!p->prev) { - unit_assert(neg->first == p); - } - np = p->next; - if(np) { - unit_assert(np->prev == p); - } else { - unit_assert(neg->last == p); - } - num++; - p = np; - } - inuse = sumtrees_inuse(neg); - if(negverbose) - printf("num lru %d, inuse %d, all %d\n", - (int)num, (int)sumtrees_inuse(neg), - (int)sumtrees_all(neg)); - unit_assert( num == inuse); - unit_assert( inuse <= sumtrees_all(neg)); -} - -/** sum up number of items inuse in subtree */ -static int sum_subtree_inuse(struct val_neg_zone* zone, - struct val_neg_data* data) -{ - struct val_neg_data* d; - int num = 0; - RBTREE_FOR(d, struct val_neg_data*, &zone->tree) { - if(dname_subdomain_c(d->name, data->name)) { - if(d->in_use) - num++; - } - } - return num; -} - -/** sum up number of items inuse in subtree */ -static int sum_zone_subtree_inuse(struct val_neg_cache* neg, - struct val_neg_zone* zone) -{ - struct val_neg_zone* z; - int num = 0; - RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) { - if(dname_subdomain_c(z->name, zone->name)) { - if(z->in_use) - num++; - } - } - return num; -} - -/** check point in data tree */ -static void check_data(struct val_neg_zone* zone, struct val_neg_data* data) -{ - unit_assert(data->count > 0); - if(data->parent) { - unit_assert(data->parent->count >= data->count); - if(data->parent->in_use) { - unit_assert(data->parent->count > data->count); - } - unit_assert(data->parent->labs == data->labs-1); - /* and parent must be one label shorter */ - unit_assert(data->name[0] == (data->len-data->parent->len-1)); - unit_assert(query_dname_compare(data->name + data->name[0]+1, - data->parent->name) == 0); - } else { - /* must be apex */ - unit_assert(dname_is_root(data->name)); - } - /* tree property: */ - unit_assert(data->count == sum_subtree_inuse(zone, data)); -} - -/** check if tree of data in zone is valid */ -static void checkzonetree(struct val_neg_zone* zone) -{ - struct val_neg_data* d; - - /* check all data in tree */ - RBTREE_FOR(d, struct val_neg_data*, &zone->tree) { - check_data(zone, d); - } -} - -/** check if negative cache is still valid */ -static void check_zone_invariants(struct val_neg_cache* neg, - struct val_neg_zone* zone) -{ - unit_assert(zone->nsec3_hash == 0); - unit_assert(zone->tree.cmp == &val_neg_data_compare); - unit_assert(zone->count != 0); - - if(zone->tree.count == 0) - unit_assert(!zone->in_use); - else { - if(!zone->in_use) { - /* details on error */ - log_nametypeclass(0, "zone", zone->name, 0, 0); - log_err("inuse %d count=%d tree.count=%d", - zone->in_use, zone->count, - (int)zone->tree.count); - if(negverbose) - print_neg_cache(neg); - } - unit_assert(zone->in_use); - } - - if(zone->parent) { - unit_assert(zone->parent->count >= zone->count); - if(zone->parent->in_use) { - unit_assert(zone->parent->count > zone->count); - } - unit_assert(zone->parent->labs == zone->labs-1); - /* and parent must be one label shorter */ - unit_assert(zone->name[0] == (zone->len-zone->parent->len-1)); - unit_assert(query_dname_compare(zone->name + zone->name[0]+1, - zone->parent->name) == 0); - } else { - /* must be apex */ - unit_assert(dname_is_root(zone->name)); - } - /* tree property: */ - unit_assert(zone->count == sum_zone_subtree_inuse(neg, zone)); - - /* check structure of zone data tree */ - checkzonetree(zone); -} - -/** check if negative cache is still valid */ -static void check_neg_invariants(struct val_neg_cache* neg) -{ - struct val_neg_zone* z; - /* check structure of LRU list */ - lock_basic_lock(&neg->lock); - check_lru(neg); - unit_assert(neg->max == 1024*1024); - unit_assert(neg->nsec3_max_iter == 1500); - unit_assert(neg->tree.cmp == &val_neg_zone_compare); - - if(neg->tree.count == 0) { - /* empty */ - unit_assert(neg->tree.count == 0); - unit_assert(neg->first == NULL); - unit_assert(neg->last == NULL); - unit_assert(neg->use == 0); - lock_basic_unlock(&neg->lock); - return; - } - - unit_assert(neg->first != NULL); - unit_assert(neg->last != NULL); - - RBTREE_FOR(z, struct val_neg_zone*, &neg->tree) { - check_zone_invariants(neg, z); - } - lock_basic_unlock(&neg->lock); -} - -/** perform stress test on insert and delete in neg cache */ -static void stress_test(struct val_neg_cache* neg) -{ - int i; - if(negverbose) - printf("negcache test\n"); - for(i=0; i<100; i++) { - if(random() % 10 < 8) - add_item(neg); - else remove_item(neg); - check_neg_invariants(neg); - } - /* empty it */ - if(negverbose) - printf("neg stress empty\n"); - while(neg->first) { - remove_item(neg); - check_neg_invariants(neg); - } - if(negverbose) - printf("neg stress emptied\n"); - unit_assert(neg->first == NULL); - /* insert again */ - for(i=0; i<100; i++) { - if(random() % 10 < 8) - add_item(neg); - else remove_item(neg); - check_neg_invariants(neg); - } -} - -void neg_test(void) -{ - struct val_neg_cache* neg; - srandom(48); - unit_show_feature("negative cache"); - - /* create with defaults */ - neg = val_neg_create(NULL, 1500); - unit_assert(neg); - - stress_test(neg); - - neg_cache_delete(neg); -} diff --git a/external/unbound/testcode/unitregional.c b/external/unbound/testcode/unitregional.c deleted file mode 100644 index 49c8147c9..000000000 --- a/external/unbound/testcode/unitregional.c +++ /dev/null @@ -1,244 +0,0 @@ -/* - * testcode/unitregional.c - unit test for regional allocator. - * - * Copyright (c) 2010, 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 - * Tests the regional special purpose allocator. - */ - -#include "config.h" -#include "testcode/unitmain.h" -#include "util/log.h" -#include "util/regional.h" - -/** test regional corner cases, zero, one, end of structure */ -static void -corner_cases(struct regional* r) -{ - size_t s; /* shadow count of allocated memory */ - void* a; - size_t minsize = sizeof(uint64_t); - size_t mysize; - char* str; - unit_assert(r); - /* alloc cases: - * 0, 1, 2. - * smaller than LARGE_OBJECT_SIZE. - * smaller but does not fit in remainder in regional. - * smaller but exactly fits in remainder of regional. - * size is remainder of regional - 8. - * size is remainder of regional + 8. - * larger than LARGE_OBJECT_SIZE. - */ - s = sizeof(struct regional); - unit_assert((s % minsize) == 0); - unit_assert(r->available == r->first_size - s); - unit_assert(r->large_list == NULL); - unit_assert(r->next == NULL); - - /* Note an alloc of 0 gets a pointer to current last - * position (where you should then use 0 bytes) */ - a = regional_alloc(r, 0); - unit_assert(a); - s+=0; - unit_assert(r->available == r->first_size - s); - - a = regional_alloc(r, 1); - unit_assert(a); - memset(a, 0x42, 1); - s+=minsize; - unit_assert(r->available == r->first_size - s); - - a = regional_alloc(r, 2); - unit_assert(a); - memset(a, 0x42, 2); - s+=minsize; - unit_assert(r->available == r->first_size - s); - - a = regional_alloc(r, 128); - unit_assert(a); - memset(a, 0x42, 128); - s+=128; - unit_assert(r->available == r->first_size - s); - - unit_assert(r->large_list == NULL); - a = regional_alloc(r, 10240); - unit_assert(a); - unit_assert(r->large_list != NULL); - memset(a, 0x42, 10240); - /* s does not change */ - unit_assert(r->available == r->first_size - s); - unit_assert(r->total_large == 10240+minsize); - - /* go towards the end of the current chunk */ - while(r->available > 1024) { - a = regional_alloc(r, 1024); - unit_assert(a); - memset(a, 0x42, 1024); - s += 1024; - unit_assert(r->available == r->first_size - s); - } - - unit_assert(r->next == NULL); - mysize = 1280; /* does not fit in current chunk */ - a = regional_alloc(r, mysize); - memset(a, 0x42, mysize); - unit_assert(r->next != NULL); - unit_assert(a); - - /* go towards the end of the current chunk */ - while(r->available > 864) { - a = regional_alloc(r, 864); - unit_assert(a); - memset(a, 0x42, 864); - s += 864; - } - - mysize = r->available; /* exactly fits */ - a = regional_alloc(r, mysize); - memset(a, 0x42, mysize); - unit_assert(a); - unit_assert(r->available == 0); /* implementation does not go ahead*/ - - a = regional_alloc(r, 8192); /* another large allocation */ - unit_assert(a); - memset(a, 0x42, 8192); - unit_assert(r->available == 0); - unit_assert(r->total_large == 10240 + 8192 + 2*minsize); - - a = regional_alloc(r, 32); /* make new chunk */ - unit_assert(a); - memset(a, 0x42, 32); - unit_assert(r->available > 0); - unit_assert(r->total_large == 10240 + 8192 + 2*minsize); - - /* go towards the end of the current chunk */ - while(r->available > 1320) { - a = regional_alloc(r, 1320); - unit_assert(a); - memset(a, 0x42, 1320); - s += 1320; - } - - mysize = r->available + 8; /* exact + 8 ; does not fit */ - a = regional_alloc(r, mysize); - memset(a, 0x42, mysize); - unit_assert(a); - unit_assert(r->available > 0); /* new chunk */ - - /* go towards the end of the current chunk */ - while(r->available > 1480) { - a = regional_alloc(r, 1480); - unit_assert(a); - memset(a, 0x42, 1480); - s += 1480; - } - - mysize = r->available - 8; /* exact - 8 ; fits. */ - a = regional_alloc(r, mysize); - memset(a, 0x42, mysize); - unit_assert(a); - unit_assert(r->available == 8); - - /* test if really copied over */ - str = "test12345"; - a = regional_alloc_init(r, str, 8); - unit_assert(a); - unit_assert(memcmp(a, str, 8) == 0); - - /* test if really zeroed */ - a = regional_alloc_zero(r, 32); - str="\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"; - unit_assert(a); - unit_assert(memcmp(a, str, 32) == 0); - - /* test if copied over (and null byte) */ - str = "an interesting string"; - a = regional_strdup(r, str); - unit_assert(a); - unit_assert(memcmp(a, str, strlen(str)+1) == 0); - - regional_free_all(r); -} - -/** test specific cases */ -static void -specific_cases(void) -{ - struct regional* r = regional_create(); - corner_cases(r); - regional_destroy(r); - r = regional_create_custom(2048); /* a small regional */ - unit_assert(r->first_size == 2048); - unit_assert(regional_get_mem(r) == 2048); - corner_cases(r); - unit_assert(regional_get_mem(r) == 2048); - regional_destroy(r); -} - -/** put random stuff in a region and free it */ -static void -burden_test(size_t max) -{ - size_t get; - void* a; - int i; - struct regional* r = regional_create_custom(2048); - for(i=0; i<1000; i++) { - get = random() % max; - a = regional_alloc(r, get); - unit_assert(a); - memset(a, 0x54, get); - } - regional_free_all(r); - regional_destroy(r); -} - -/** randomly allocate stuff */ -static void -random_burden(void) -{ - size_t max_alloc = 2048 + 128; /* small chance of LARGE */ - int i; - for(i=0; i<100; i++) - burden_test(max_alloc); -} - -void regional_test(void) -{ - unit_show_feature("regional"); - specific_cases(); - random_burden(); -} diff --git a/external/unbound/testcode/unitslabhash.c b/external/unbound/testcode/unitslabhash.c deleted file mode 100644 index 565d36139..000000000 --- a/external/unbound/testcode/unitslabhash.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * testcode/unitslabhash.c - unit test for slabhash table. - * - * 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 - * Tests the locking LRU keeping hash table implementation. - */ - -#include "config.h" -#include "testcode/unitmain.h" -#include "util/log.h" -#include "util/storage/slabhash.h" - -/** use this type for the slabhash test key */ -typedef struct slabhash_testkey testkey_type; -/** use this type for the slabhash test data */ -typedef struct slabhash_testdata testdata_type; - -/** delete key */ -static void delkey(struct slabhash_testkey* k) { - lock_rw_destroy(&k->entry.lock); free(k);} - -/** hash func, very bad to improve collisions, both high and low bits */ -static hashvalue_type myhash(int id) { - hashvalue_type h = (hashvalue_type)id & 0x0f; - h |= (h << 28); - return h; -} - -/** allocate new key, fill in hash */ -static testkey_type* newkey(int id) { - testkey_type* k = (testkey_type*)calloc(1, sizeof(testkey_type)); - if(!k) fatal_exit("out of memory"); - k->id = id; - k->entry.hash = myhash(id); - k->entry.key = k; - lock_rw_init(&k->entry.lock); - return k; -} -/** new data el */ -static testdata_type* newdata(int val) { - testdata_type* d = (testdata_type*)calloc(1, - sizeof(testdata_type)); - if(!d) fatal_exit("out of memory"); - d->data = val; - return d; -} - -/** test hashtable using short sequence */ -static void -test_short_table(struct slabhash* table) -{ - testkey_type* k = newkey(12); - testkey_type* k2 = newkey(14); - testdata_type* d = newdata(128); - testdata_type* d2 = newdata(129); - - k->entry.data = d; - k2->entry.data = d2; - - slabhash_insert(table, myhash(12), &k->entry, d, NULL); - slabhash_insert(table, myhash(14), &k2->entry, d2, NULL); - - unit_assert( slabhash_lookup(table, myhash(12), k, 0) == &k->entry); - lock_rw_unlock( &k->entry.lock ); - unit_assert( slabhash_lookup(table, myhash(14), k2, 0) == &k2->entry); - lock_rw_unlock( &k2->entry.lock ); - slabhash_remove(table, myhash(12), k); - slabhash_remove(table, myhash(14), k2); -} - -/** number of hash test max */ -#define HASHTESTMAX 32 - -/** test adding a random element */ -static void -testadd(struct slabhash* table, testdata_type* ref[]) -{ - int numtoadd = random() % HASHTESTMAX; - testdata_type* data = newdata(numtoadd); - testkey_type* key = newkey(numtoadd); - key->entry.data = data; - slabhash_insert(table, myhash(numtoadd), &key->entry, data, NULL); - ref[numtoadd] = data; -} - -/** test adding a random element */ -static void -testremove(struct slabhash* table, testdata_type* ref[]) -{ - int num = random() % HASHTESTMAX; - testkey_type* key = newkey(num); - slabhash_remove(table, myhash(num), key); - ref[num] = NULL; - delkey(key); -} - -/** test adding a random element */ -static void -testlookup(struct slabhash* table, testdata_type* ref[]) -{ - int num = random() % HASHTESTMAX; - testkey_type* key = newkey(num); - struct lruhash_entry* en = slabhash_lookup(table, myhash(num), key, 0); - testdata_type* data = en? (testdata_type*)en->data : NULL; - if(en) { - unit_assert(en->key); - unit_assert(en->data); - } - if(0) log_info("lookup %d got %d, expect %d", num, en? data->data :-1, - ref[num]? ref[num]->data : -1); - unit_assert( data == ref[num] ); - if(en) { lock_rw_unlock(&en->lock); } - delkey(key); -} - -/** check integrity of hash table */ -static void -check_lru_table(struct lruhash* table) -{ - struct lruhash_entry* p; - size_t c = 0; - lock_quick_lock(&table->lock); - unit_assert( table->num <= table->size); - unit_assert( table->size_mask == (int)table->size-1 ); - unit_assert( (table->lru_start && table->lru_end) || - (!table->lru_start && !table->lru_end) ); - unit_assert( table->space_used <= table->space_max ); - /* check lru list integrity */ - if(table->lru_start) - unit_assert(table->lru_start->lru_prev == NULL); - if(table->lru_end) - unit_assert(table->lru_end->lru_next == NULL); - p = table->lru_start; - while(p) { - if(p->lru_prev) { - unit_assert(p->lru_prev->lru_next == p); - } - if(p->lru_next) { - unit_assert(p->lru_next->lru_prev == p); - } - c++; - p = p->lru_next; - } - unit_assert(c == table->num); - - /* this assertion is specific to the unit test */ - unit_assert( table->space_used == - table->num * test_slabhash_sizefunc(NULL, NULL) ); - lock_quick_unlock(&table->lock); -} - -/** check integrity of hash table */ -static void -check_table(struct slabhash* table) -{ - size_t i; - for(i=0; i<table->size; i++) - check_lru_table(table->array[i]); -} - -/** test adding a random element (unlimited range) */ -static void -testadd_unlim(struct slabhash* table, testdata_type** ref) -{ - int numtoadd = random() % (HASHTESTMAX * 10); - testdata_type* data = newdata(numtoadd); - testkey_type* key = newkey(numtoadd); - key->entry.data = data; - slabhash_insert(table, myhash(numtoadd), &key->entry, data, NULL); - if(ref) - ref[numtoadd] = data; -} - -/** test adding a random element (unlimited range) */ -static void -testremove_unlim(struct slabhash* table, testdata_type** ref) -{ - int num = random() % (HASHTESTMAX*10); - testkey_type* key = newkey(num); - slabhash_remove(table, myhash(num), key); - if(ref) - ref[num] = NULL; - delkey(key); -} - -/** test adding a random element (unlimited range) */ -static void -testlookup_unlim(struct slabhash* table, testdata_type** ref) -{ - int num = random() % (HASHTESTMAX*10); - testkey_type* key = newkey(num); - struct lruhash_entry* en = slabhash_lookup(table, myhash(num), key, 0); - testdata_type* data = en? (testdata_type*)en->data : NULL; - if(en) { - unit_assert(en->key); - unit_assert(en->data); - } - if(0 && ref) log_info("lookup unlim %d got %d, expect %d", num, en ? - data->data :-1, ref[num] ? ref[num]->data : -1); - if(data && ref) { - /* its okay for !data, it fell off the lru */ - unit_assert( data == ref[num] ); - } - if(en) { lock_rw_unlock(&en->lock); } - delkey(key); -} - -/** test with long sequence of adds, removes and updates, and lookups */ -static void -test_long_table(struct slabhash* table) -{ - /* assuming it all fits in the hashtable, this check will work */ - testdata_type* ref[HASHTESTMAX * 100]; - size_t i; - memset(ref, 0, sizeof(ref)); - /* test assumption */ - if(0) slabhash_status(table, "unit test", 1); - srandom(48); - for(i=0; i<1000; i++) { - /* what to do? */ - if(i == 500) { - slabhash_clear(table); - memset(ref, 0, sizeof(ref)); - continue; - } - switch(random() % 4) { - case 0: - case 3: - testadd(table, ref); - break; - case 1: - testremove(table, ref); - break; - case 2: - testlookup(table, ref); - break; - default: - unit_assert(0); - } - if(0) slabhash_status(table, "unit test", 1); - check_table(table); - } - - /* test more, but 'ref' assumption does not hold anymore */ - for(i=0; i<1000; i++) { - /* what to do? */ - switch(random() % 4) { - case 0: - case 3: - testadd_unlim(table, ref); - break; - case 1: - testremove_unlim(table, ref); - break; - case 2: - testlookup_unlim(table, ref); - break; - default: - unit_assert(0); - } - if(0) slabhash_status(table, "unlim", 1); - check_table(table); - } -} - -/** structure to threaded test the lru hash table */ -struct slab_test_thr { - /** thread num, first entry. */ - int num; - /** id */ - ub_thread_type id; - /** hash table */ - struct slabhash* table; -}; - -/** main routine for threaded hash table test */ -static void* -test_thr_main(void* arg) -{ - struct slab_test_thr* t = (struct slab_test_thr*)arg; - int i; - log_thread_set(&t->num); - for(i=0; i<1000; i++) { - switch(random() % 4) { - case 0: - case 3: - testadd_unlim(t->table, NULL); - break; - case 1: - testremove_unlim(t->table, NULL); - break; - case 2: - testlookup_unlim(t->table, NULL); - break; - default: - unit_assert(0); - } - if(0) slabhash_status(t->table, "hashtest", 1); - if(i % 100 == 0) /* because of locking, not all the time */ - check_table(t->table); - } - check_table(t->table); - return NULL; -} - -/** test hash table access by multiple threads */ -static void -test_threaded_table(struct slabhash* table) -{ - int numth = 10; - struct slab_test_thr t[100]; - int i; - - for(i=1; i<numth; i++) { - t[i].num = i; - t[i].table = table; - ub_thread_create(&t[i].id, test_thr_main, &t[i]); - } - - for(i=1; i<numth; i++) { - ub_thread_join(t[i].id); - } - if(0) slabhash_status(table, "hashtest", 1); -} - -void slabhash_test(void) -{ - /* start very very small array, so it can do lots of table_grow() */ - /* also small in size so that reclaim has to be done quickly. */ - struct slabhash* table; - unit_show_feature("slabhash"); - table = slabhash_create(4, 2, 10400, - test_slabhash_sizefunc, test_slabhash_compfunc, - test_slabhash_delkey, test_slabhash_deldata, NULL); - test_short_table(table); - test_long_table(table); - slabhash_delete(table); - table = slabhash_create(4, 2, 10400, - test_slabhash_sizefunc, test_slabhash_compfunc, - test_slabhash_delkey, test_slabhash_deldata, NULL); - test_threaded_table(table); - slabhash_delete(table); -} diff --git a/external/unbound/testcode/unitverify.c b/external/unbound/testcode/unitverify.c deleted file mode 100644 index 37994a377..000000000 --- a/external/unbound/testcode/unitverify.c +++ /dev/null @@ -1,545 +0,0 @@ -/* - * testcode/unitverify.c - unit test for signature verification 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 - * Calls verification unit tests. Exits with code 1 on a failure. - */ - -#include "config.h" -#include "util/log.h" -#include "testcode/unitmain.h" -#include "validator/val_sigcrypt.h" -#include "validator/val_secalgo.h" -#include "validator/val_nsec.h" -#include "validator/val_nsec3.h" -#include "validator/validator.h" -#include "testcode/testpkts.h" -#include "util/data/msgreply.h" -#include "util/data/msgparse.h" -#include "util/data/dname.h" -#include "util/regional.h" -#include "util/alloc.h" -#include "util/rbtree.h" -#include "util/net_help.h" -#include "util/module.h" -#include "util/config_file.h" -#include "sldns/sbuffer.h" -#include "sldns/keyraw.h" -#include "sldns/str2wire.h" -#include "sldns/wire2str.h" - -/** verbose signature test */ -static int vsig = 0; - -/** entry to packet buffer with wireformat */ -static void -entry_to_buf(struct entry* e, sldns_buffer* pkt) -{ - unit_assert(e->reply_list); - if(e->reply_list->reply_from_hex) { - sldns_buffer_copy(pkt, e->reply_list->reply_from_hex); - } else { - sldns_buffer_clear(pkt); - sldns_buffer_write(pkt, e->reply_list->reply_pkt, - e->reply_list->reply_len); - sldns_buffer_flip(pkt); - } -} - -/** entry to reply info conversion */ -static void -entry_to_repinfo(struct entry* e, struct alloc_cache* alloc, - struct regional* region, sldns_buffer* pkt, struct query_info* qi, - struct reply_info** rep) -{ - int ret; - struct edns_data edns; - entry_to_buf(e, pkt); - /* lock alloc lock to please lock checking software. - * alloc_special_obtain assumes it is talking to a ub-alloc, - * and does not need to perform locking. Here the alloc is - * the only one, so we lock it here */ - lock_quick_lock(&alloc->lock); - ret = reply_info_parse(pkt, alloc, qi, rep, region, &edns); - lock_quick_unlock(&alloc->lock); - if(ret != 0) { - char rcode[16]; - sldns_wire2str_rcode_buf(ret, rcode, sizeof(rcode)); - printf("parse code %d: %s\n", ret, rcode); - unit_assert(ret != 0); - } -} - -/** extract DNSKEY rrset from answer and convert it */ -static struct ub_packed_rrset_key* -extract_keys(struct entry* e, struct alloc_cache* alloc, - struct regional* region, sldns_buffer* pkt) -{ - struct ub_packed_rrset_key* dnskey = NULL; - struct query_info qinfo; - struct reply_info* rep = NULL; - size_t i; - - entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep); - for(i=0; i<rep->an_numrrsets; i++) { - if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_DNSKEY) { - dnskey = rep->rrsets[i]; - rep->rrsets[i] = NULL; - break; - } - } - unit_assert(dnskey); - - reply_info_parsedelete(rep, alloc); - query_info_clear(&qinfo); - return dnskey; -} - -/** return true if answer should be bogus */ -static int -should_be_bogus(struct ub_packed_rrset_key* rrset, struct query_info* qinfo) -{ - struct packed_rrset_data* d = (struct packed_rrset_data*)rrset-> - entry.data; - if(d->rrsig_count == 0) - return 1; - /* name 'bogus' as first label signals bogus */ - if(rrset->rk.dname_len > 6 && memcmp(rrset->rk.dname+1, "bogus", 5)==0) - return 1; - if(qinfo->qname_len > 6 && memcmp(qinfo->qname+1, "bogus", 5)==0) - return 1; - return 0; -} - -/** return number of rrs in an rrset */ -static size_t -rrset_get_count(struct ub_packed_rrset_key* rrset) -{ - struct packed_rrset_data* d = (struct packed_rrset_data*) - rrset->entry.data; - if(!d) return 0; - return d->count; -} - -/** setup sig alg list from dnskey */ -static void -setup_sigalg(struct ub_packed_rrset_key* dnskey, uint8_t* sigalg) -{ - uint8_t a[ALGO_NEEDS_MAX]; - size_t i, n = 0; - memset(a, 0, sizeof(a)); - for(i=0; i<rrset_get_count(dnskey); i++) { - uint8_t algo = (uint8_t)dnskey_get_algo(dnskey, i); - if(a[algo] == 0) { - a[algo] = 1; - sigalg[n++] = algo; - } - } - sigalg[n] = 0; -} - -/** verify and test one rrset against the key rrset */ -static void -verifytest_rrset(struct module_env* env, struct val_env* ve, - struct ub_packed_rrset_key* rrset, struct ub_packed_rrset_key* dnskey, - struct query_info* qinfo) -{ - enum sec_status sec; - char* reason = NULL; - uint8_t sigalg[ALGO_NEEDS_MAX+1]; - if(vsig) { - log_nametypeclass(VERB_QUERY, "verify of rrset", - rrset->rk.dname, ntohs(rrset->rk.type), - ntohs(rrset->rk.rrset_class)); - } - setup_sigalg(dnskey, sigalg); /* check all algorithms in the dnskey */ - sec = dnskeyset_verify_rrset(env, ve, rrset, dnskey, sigalg, &reason); - if(vsig) { - printf("verify outcome is: %s %s\n", sec_status_to_string(sec), - reason?reason:""); - } - if(should_be_bogus(rrset, qinfo)) { - unit_assert(sec == sec_status_bogus); - } else { - unit_assert(sec == sec_status_secure); - } -} - -/** verify and test an entry - every rr in the message */ -static void -verifytest_entry(struct entry* e, struct alloc_cache* alloc, - struct regional* region, sldns_buffer* pkt, - struct ub_packed_rrset_key* dnskey, struct module_env* env, - struct val_env* ve) -{ - struct query_info qinfo; - struct reply_info* rep = NULL; - size_t i; - - regional_free_all(region); - if(vsig) { - char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt, - e->reply_list->reply_len); - printf("verifying pkt:\n%s\n", s?s:"outofmemory"); - free(s); - } - entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep); - - for(i=0; i<rep->rrset_count; i++) { - verifytest_rrset(env, ve, rep->rrsets[i], dnskey, &qinfo); - } - - reply_info_parsedelete(rep, alloc); - query_info_clear(&qinfo); -} - -/** find RRset in reply by type */ -static struct ub_packed_rrset_key* -find_rrset_type(struct reply_info* rep, uint16_t type) -{ - size_t i; - for(i=0; i<rep->rrset_count; i++) { - if(ntohs(rep->rrsets[i]->rk.type) == type) - return rep->rrsets[i]; - } - return NULL; -} - -/** DS sig test an entry - get DNSKEY and DS in entry and verify */ -static void -dstest_entry(struct entry* e, struct alloc_cache* alloc, - struct regional* region, sldns_buffer* pkt, struct module_env* env) -{ - struct query_info qinfo; - struct reply_info* rep = NULL; - struct ub_packed_rrset_key* ds, *dnskey; - int ret; - - regional_free_all(region); - if(vsig) { - char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt, - e->reply_list->reply_len); - printf("verifying DS-DNSKEY match:\n%s\n", s?s:"outofmemory"); - free(s); - } - entry_to_repinfo(e, alloc, region, pkt, &qinfo, &rep); - ds = find_rrset_type(rep, LDNS_RR_TYPE_DS); - dnskey = find_rrset_type(rep, LDNS_RR_TYPE_DNSKEY); - /* check test is OK */ - unit_assert(ds && dnskey); - - ret = ds_digest_match_dnskey(env, dnskey, 0, ds, 0); - if(strncmp((char*)qinfo.qname, "\003yes", 4) == 0) { - if(vsig) { - printf("result(yes)= %s\n", ret?"yes":"no"); - } - unit_assert(ret); - } else if (strncmp((char*)qinfo.qname, "\002no", 3) == 0) { - if(vsig) { - printf("result(no)= %s\n", ret?"yes":"no"); - } - unit_assert(!ret); - verbose(VERB_QUERY, "DS fail: OK; matched unit test"); - } else { - fatal_exit("Bad qname in DS unit test, yes or no"); - } - - reply_info_parsedelete(rep, alloc); - query_info_clear(&qinfo); -} - -/** verify from a file */ -static void -verifytest_file(const char* fname, const char* at_date) -{ - /* - * The file contains a list of ldns-testpkts entries. - * The first entry must be a query for DNSKEY. - * The answer rrset is the keyset that will be used for verification - */ - struct ub_packed_rrset_key* dnskey; - struct regional* region = regional_create(); - struct alloc_cache alloc; - sldns_buffer* buf = sldns_buffer_new(65535); - struct entry* e; - struct entry* list = read_datafile(fname, 1); - struct module_env env; - struct val_env ve; - time_t now = time(NULL); - - if(!list) - fatal_exit("could not read %s: %s", fname, strerror(errno)); - alloc_init(&alloc, NULL, 1); - memset(&env, 0, sizeof(env)); - memset(&ve, 0, sizeof(ve)); - env.scratch = region; - env.scratch_buffer = buf; - env.now = &now; - ve.date_override = cfg_convert_timeval(at_date); - unit_assert(region && buf); - dnskey = extract_keys(list, &alloc, region, buf); - if(vsig) log_nametypeclass(VERB_QUERY, "test dnskey", - dnskey->rk.dname, ntohs(dnskey->rk.type), - ntohs(dnskey->rk.rrset_class)); - /* ready to go! */ - for(e = list->next; e; e = e->next) { - verifytest_entry(e, &alloc, region, buf, dnskey, &env, &ve); - } - - ub_packed_rrset_parsedelete(dnskey, &alloc); - delete_entry(list); - regional_destroy(region); - alloc_clear(&alloc); - sldns_buffer_free(buf); -} - -/** verify DS matches DNSKEY from a file */ -static void -dstest_file(const char* fname) -{ - /* - * The file contains a list of ldns-testpkts entries. - * The first entry must be a query for DNSKEY. - * The answer rrset is the keyset that will be used for verification - */ - struct regional* region = regional_create(); - struct alloc_cache alloc; - sldns_buffer* buf = sldns_buffer_new(65535); - struct entry* e; - struct entry* list = read_datafile(fname, 1); - struct module_env env; - - if(!list) - fatal_exit("could not read %s: %s", fname, strerror(errno)); - alloc_init(&alloc, NULL, 1); - memset(&env, 0, sizeof(env)); - env.scratch = region; - env.scratch_buffer = buf; - unit_assert(region && buf); - - /* ready to go! */ - for(e = list; e; e = e->next) { - dstest_entry(e, &alloc, region, buf, &env); - } - - delete_entry(list); - regional_destroy(region); - alloc_clear(&alloc); - sldns_buffer_free(buf); -} - -/** helper for unittest of NSEC routines */ -static int -unitest_nsec_has_type_rdata(char* bitmap, size_t len, uint16_t type) -{ - return nsecbitmap_has_type_rdata((uint8_t*)bitmap, len, type); -} - -/** Test NSEC type bitmap routine */ -static void -nsectest(void) -{ - /* bitmap starts at type bitmap rdata field */ - /* from rfc 4034 example */ - char* bitmap = "\000\006\100\001\000\000\000\003" - "\004\033\000\000\000\000\000\000" - "\000\000\000\000\000\000\000\000" - "\000\000\000\000\000\000\000\000" - "\000\000\000\000\040"; - size_t len = 37; - - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 0)); - unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_A)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 2)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 3)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 4)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 5)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 6)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 7)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 8)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 9)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 10)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 11)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 12)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 13)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 14)); - unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_MX)); - unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_RRSIG)); - unit_assert(unitest_nsec_has_type_rdata(bitmap, len, LDNS_RR_TYPE_NSEC)); - unit_assert(unitest_nsec_has_type_rdata(bitmap, len, 1234)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1233)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1235)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1236)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1237)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1238)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1239)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 1240)); - unit_assert(!unitest_nsec_has_type_rdata(bitmap, len, 2230)); -} - -/** Test hash algo - NSEC3 hash it and compare result */ -static void -nsec3_hash_test_entry(struct entry* e, rbtree_type* ct, - struct alloc_cache* alloc, struct regional* region, - sldns_buffer* buf) -{ - struct query_info qinfo; - struct reply_info* rep = NULL; - struct ub_packed_rrset_key* answer, *nsec3; - struct nsec3_cached_hash* hash = NULL; - int ret; - uint8_t* qname; - - if(vsig) { - char* s = sldns_wire2str_pkt(e->reply_list->reply_pkt, - e->reply_list->reply_len); - printf("verifying NSEC3 hash:\n%s\n", s?s:"outofmemory"); - free(s); - } - entry_to_repinfo(e, alloc, region, buf, &qinfo, &rep); - nsec3 = find_rrset_type(rep, LDNS_RR_TYPE_NSEC3); - answer = find_rrset_type(rep, LDNS_RR_TYPE_AAAA); - qname = regional_alloc_init(region, qinfo.qname, qinfo.qname_len); - /* check test is OK */ - unit_assert(nsec3 && answer && qname); - - ret = nsec3_hash_name(ct, region, buf, nsec3, 0, qname, - qinfo.qname_len, &hash); - if(ret != 1) { - printf("Bad nsec3_hash_name retcode %d\n", ret); - unit_assert(ret == 1); - } - unit_assert(hash->dname && hash->hash && hash->hash_len && - hash->b32 && hash->b32_len); - unit_assert(hash->b32_len == (size_t)answer->rk.dname[0]); - /* does not do lowercasing. */ - unit_assert(memcmp(hash->b32, answer->rk.dname+1, hash->b32_len) - == 0); - - reply_info_parsedelete(rep, alloc); - query_info_clear(&qinfo); -} - - -/** Read file to test NSEC3 hash algo */ -static void -nsec3_hash_test(const char* fname) -{ - /* - * The list contains a list of ldns-testpkts entries. - * Every entry is a test. - * The qname is hashed. - * The answer section AAAA RR name is the required result. - * The auth section NSEC3 is used to get hash parameters. - * The hash cache is maintained per file. - * - * The test does not perform canonicalization during the compare. - */ - rbtree_type ct; - struct regional* region = regional_create(); - struct alloc_cache alloc; - sldns_buffer* buf = sldns_buffer_new(65535); - struct entry* e; - struct entry* list = read_datafile(fname, 1); - - if(!list) - fatal_exit("could not read %s: %s", fname, strerror(errno)); - rbtree_init(&ct, &nsec3_hash_cmp); - alloc_init(&alloc, NULL, 1); - unit_assert(region && buf); - - /* ready to go! */ - for(e = list; e; e = e->next) { - nsec3_hash_test_entry(e, &ct, &alloc, region, buf); - } - - delete_entry(list); - regional_destroy(region); - alloc_clear(&alloc); - sldns_buffer_free(buf); -} - -void -verify_test(void) -{ - unit_show_feature("signature verify"); -#ifdef USE_SHA1 - verifytest_file("testdata/test_signatures.1", "20070818005004"); -#endif -#if defined(USE_DSA) && defined(USE_SHA1) - verifytest_file("testdata/test_signatures.2", "20080414005004"); - verifytest_file("testdata/test_signatures.3", "20080416005004"); - verifytest_file("testdata/test_signatures.4", "20080416005004"); - verifytest_file("testdata/test_signatures.5", "20080416005004"); - verifytest_file("testdata/test_signatures.6", "20080416005004"); - verifytest_file("testdata/test_signatures.7", "20070829144150"); -#endif /* USE_DSA */ -#ifdef USE_SHA1 - verifytest_file("testdata/test_signatures.8", "20070829144150"); -#endif -#if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2) - verifytest_file("testdata/test_sigs.rsasha256", "20070829144150"); -# ifdef USE_SHA1 - verifytest_file("testdata/test_sigs.sha1_and_256", "20070829144150"); -# endif - verifytest_file("testdata/test_sigs.rsasha256_draft", "20090101000000"); -#endif -#if (defined(HAVE_EVP_SHA512) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2) - verifytest_file("testdata/test_sigs.rsasha512_draft", "20070829144150"); -#endif -#ifdef USE_SHA1 - verifytest_file("testdata/test_sigs.hinfo", "20090107100022"); - verifytest_file("testdata/test_sigs.revoked", "20080414005004"); -#endif -#ifdef USE_GOST - if(sldns_key_EVP_load_gost_id()) - verifytest_file("testdata/test_sigs.gost", "20090807060504"); - else printf("Warning: skipped GOST, openssl does not provide gost.\n"); -#endif -#ifdef USE_ECDSA - /* test for support in case we use libNSS and ECC is removed */ - if(dnskey_algo_id_is_supported(LDNS_ECDSAP256SHA256)) { - verifytest_file("testdata/test_sigs.ecdsa_p256", "20100908100439"); - verifytest_file("testdata/test_sigs.ecdsa_p384", "20100908100439"); - } - dstest_file("testdata/test_ds.sha384"); -#endif -#ifdef USE_SHA1 - dstest_file("testdata/test_ds.sha1"); -#endif - nsectest(); - nsec3_hash_test("testdata/test_nsec3_hash.1"); -} |