/* * 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 #endif #include #include "testcode/testpkts.h" #include "testcode/replay.h" #include "testcode/fake_event.h" #include "daemon/remote.h" #include "libunbound/worker.h" #include "daemon/worker.h" #include "util/config_file.h" #include "sldns/keyraw.h" #ifdef UB_ON_WINDOWS #include "winrc/win_svc.h" #endif /** signal that this is a testbound compile */ #define unbound_testbound 1 /** renamed main routine */ int daemon_main(int argc, char* argv[]); /** * 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("-i detect IPSECMOD 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; ititle); return scen; } /** remove config file at exit */ static void remove_configfile(void) { struct config_strlist* p; for(p=cfgfiles; p; p=p->next) unlink(p->str); config_delstrlist(cfgfiles); cfgfiles = NULL; } /** perform the playback on the playback_file with the args. */ static int perform_playback(char* playback_file, int pass_argc, char** pass_argv) { struct replay_scenario* scen = NULL; int c, res; /* 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); /* run the normal daemon */ res = daemon_main(pass_argc, pass_argv); fake_event_cleanup(); for(c=1; cbase; runtime->daemon = worker->daemon; 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); } #ifdef UB_ON_WINDOWS 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); } #endif #ifdef UB_ON_WINDOWS void wsvc_setup_worker(struct worker* ATTR_UNUSED(worker)) { /* do nothing */ } #endif #ifdef UB_ON_WINDOWS void wsvc_desetup_worker(struct worker* ATTR_UNUSED(worker)) { /* do nothing */ } #endif #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 */ int tcp_connect_errno_needs_log(struct sockaddr* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen)) { return 1; } int squelch_err_ssl_handshake(unsigned long ATTR_UNUSED(err)) { return 0; } void listen_setup_locks(void) { /* nothing */ } void listen_desetup_locks(void) { /* nothing */ } void fast_reload_printq_list_delete( struct fast_reload_printq* ATTR_UNUSED(list)) { /* nothing */ } void fast_reload_worker_pickup_changes(struct worker* ATTR_UNUSED(worker)) { /* nothing */ } #ifdef HAVE_NGTCP2 void* quic_sslctx_create(char* ATTR_UNUSED(key), char* ATTR_UNUSED(pem), char* ATTR_UNUSED(verifypem)) { return NULL; } void comm_point_doq_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event), void* ATTR_UNUSED(arg)) { /* nothing */ } int doq_conn_cmp(const void* ATTR_UNUSED(key1), const void* ATTR_UNUSED(key2)) { return 0; } int doq_conid_cmp(const void* ATTR_UNUSED(key1), const void* ATTR_UNUSED(key2)) { return 0; } int doq_timer_cmp(const void* ATTR_UNUSED(key1), const void* ATTR_UNUSED(key2)) { return 0; } int doq_stream_cmp(const void* ATTR_UNUSED(key1), const void* ATTR_UNUSED(key2)) { return 0; } struct doq_table* doq_table_create(struct config_file* ATTR_UNUSED(cfg), struct ub_randstate* ATTR_UNUSED(rnd)) { return calloc(1, sizeof(struct doq_table)); } void doq_table_delete(struct doq_table* table) { free(table); } void doq_timer_cb(void* ATTR_UNUSED(arg)) { /* nothing */ } size_t doq_table_quic_size_get(struct doq_table* ATTR_UNUSED(table)) { return 0; } #endif