* Create and send a new dnstap "Message" event of type CLIENT_QUERY.
* @param env: dnstap environment object.
* @param qsock: address/port of client.
+ * @param rsock: local (service) address/port.
* @param cptype: comm_udp or comm_tcp.
* @param qmsg: query message.
*/
void
dt_msg_send_client_query(struct dt_env *env,
struct sockaddr_storage *qsock,
+ struct sockaddr_storage *rsock,
enum comm_point_type cptype,
struct sldns_buffer *qmsg);
* Create and send a new dnstap "Message" event of type CLIENT_RESPONSE.
* @param env: dnstap environment object.
* @param qsock: address/port of client.
+ * @param rsock: local (service) address/port.
* @param cptype: comm_udp or comm_tcp.
* @param rmsg: response message.
*/
void
dt_msg_send_client_response(struct dt_env *env,
struct sockaddr_storage *qsock,
+ struct sockaddr_storage *rsock,
enum comm_point_type cptype,
struct sldns_buffer *rmsg);
* FORWARDER_QUERY. The type used is dependent on the value of the RD bit
* in the query header.
* @param env: dnstap environment object.
- * @param rsock: address/port of server the query is being sent to.
+ * @param rsock: address/port of server (upstream) the query is being sent to.
+ * @param qsock: address/port of server (local) the query is being sent from.
* @param cptype: comm_udp or comm_tcp.
* @param zone: query zone.
* @param zone_len: length of zone.
void
dt_msg_send_outside_query(struct dt_env *env,
struct sockaddr_storage *rsock,
+ struct sockaddr_storage *qsock,
enum comm_point_type cptype,
uint8_t *zone, size_t zone_len,
struct sldns_buffer *qmsg);
* FORWARDER_RESPONSE. The type used is dependent on the value of the RD bit
* in the query header.
* @param env: dnstap environment object.
- * @param rsock: address/port of server the response was received from.
+ * @param rsock: address/port of server (upstream) the response was received from.
+ * @param qsock: address/port of server (local) the response was received to.
* @param cptype: comm_udp or comm_tcp.
* @param zone: query zone.
* @param zone_len: length of zone.
void
dt_msg_send_outside_response(struct dt_env *env,
struct sockaddr_storage *rsock,
+ struct sockaddr_storage *qsock,
enum comm_point_type cptype,
uint8_t *zone, size_t zone_len,
uint8_t *qbuf, size_t qbuf_len,
if(verbosity) log_info("bidirectional stream");
if(!reply_with_accept(data)) {
tap_data_free(data);
+ return;
}
} else if(data->len >= 4 && sldns_read_uint32(data->frame) ==
FSTRM_CONTROL_FRAME_STOP && data->is_bidirectional) {
/** signal handler for user quit */
static RETSIGTYPE main_sigh(int sig)
{
- if(!sig_quit)
- fprintf(stderr, "exit on signal %d\n", sig);
+ if(!sig_quit) {
+ char str[] = "exit on signal \n";
+ str[15] = '0' + (sig/10)%10;
+ str[16] = '0' + sig%10;
+ /* simple cast to void will not silence Wunused-result */
+ (void)!write(STDERR_FILENO, str, strlen(str));
+ }
if(sig_base) {
ub_event_base_loopexit(sig_base);
sig_base = NULL;
return 0;
}
-int worker_handle_reply(struct comm_point* ATTR_UNUSED(c),
- void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
- struct comm_reply* ATTR_UNUSED(reply_info))
-{
- log_assert(0);
- return 0;
-}
-
int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
struct comm_reply* ATTR_UNUSED(reply_info))
return 0;
}
-int libworker_handle_reply(struct comm_point* ATTR_UNUSED(c),
- void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
- struct comm_reply* ATTR_UNUSED(reply_info))
-{
- log_assert(0);
- return 0;
-}
-
int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c),
void* ATTR_UNUSED(arg), int ATTR_UNUSED(error),
struct comm_reply* ATTR_UNUSED(reply_info))
case LDNS_RR_TYPE_RRSIG:
case LDNS_RR_TYPE_NSEC:
case LDNS_RR_TYPE_NSEC3:
+ case LDNS_RR_TYPE_NSEC3PARAM:
return RPZ_INVALID_ACTION;
case LDNS_RR_TYPE_CNAME:
break;
int newzone = 0;
if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION) {
- verbose(VERB_ALGO, "RPZ: skipping unsupported action: %s",
- rpz_action_to_string(a));
+ char str[255+1];
+ if(rrtype == LDNS_RR_TYPE_SOA || rrtype == LDNS_RR_TYPE_NS ||
+ rrtype == LDNS_RR_TYPE_DNAME ||
+ rrtype == LDNS_RR_TYPE_DNSKEY ||
+ rrtype == LDNS_RR_TYPE_RRSIG ||
+ rrtype == LDNS_RR_TYPE_NSEC ||
+ rrtype == LDNS_RR_TYPE_NSEC3PARAM ||
+ rrtype == LDNS_RR_TYPE_NSEC3 ||
+ rrtype == LDNS_RR_TYPE_DS) {
+ free(dname);
+ return; /* no need to log these types as unsupported */
+ }
+ dname_str(dname, str);
+ verbose(VERB_ALGO, "RPZ: qname trigger, %s skipping unsupported action: %s",
+ str, rpz_action_to_string(a));
free(dname);
return;
}
if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION ||
respa == respip_invalid) {
- verbose(VERB_ALGO, "RPZ: skipping unsupported action: %s",
- rpz_action_to_string(a));
+ char str[255+1];
+ dname_str(dname, str);
+ verbose(VERB_ALGO, "RPZ: respip trigger, %s skipping unsupported action: %s",
+ str, rpz_action_to_string(a));
return 0;
}
* zone match, append '*' to that and do another lookup. */
ce = dname_get_shared_topdomain(z->name, qname);
- if(!ce /* should not happen */ || !*ce /* root */) {
+ if(!ce /* should not happen */) {
lock_rw_unlock(&z->lock);
if(zones_keep_lock) {
lock_rw_unlock(&r->local_zones->lock);
/** signal handler for user quit */
static RETSIGTYPE delayer_sigh(int sig)
{
- printf("exit on signal %d\n", sig);
+ char str[] = "exit on signal \n";
+ str[15] = '0' + (sig/10)%10;
+ str[16] = '0' + sig%10;
+ /* simple cast to void will not silence Wunused-result */
+ (void)!write(STDOUT_FILENO, str, strlen(str));
do_quit = 1;
}
#!/usr/bin/env bash
. testdata/common.sh
+quiet=0
+if test "$1" = "-q"; then
+ quiet=1
+ tdirarg="-q"
+ shift
+fi
NEED_SPLINT='00-lint.tdir'
NEED_DOXYGEN='01-doc.tdir'
export -n NOTIFY_SOCKET
cd testdata;
-sh ../testcode/mini_tdir.sh clean
+sh ../testcode/mini_tdir.sh $tdirarg clean
rm -f .perfstats.txt
for test in `ls -d *.tdir`; do
SKIP=0
fi
if test $SKIP -eq 0; then
echo $test
- sh ../testcode/mini_tdir.sh -a ../.. exe $test
+ sh ../testcode/mini_tdir.sh -a ../.. $tdirarg exe $test
else
echo "skip $test"
fi
done
-sh ../testcode/mini_tdir.sh report
+sh ../testcode/mini_tdir.sh $tdirarg report
cat .perfstats.txt
if(nghttp2_session_callbacks_new(&callbacks) == NGHTTP2_ERR_NOMEM) {
log_err("failed to initialize nghttp2 callback");
+ free(h2_session);
return NULL;
}
nghttp2_session_callbacks_set_recv_callback(callbacks, http2_recv_cb);
if(!no_tls) {
ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
if(!ctx) fatal_exit("cannot create ssl ctx");
+#ifdef HAVE_SSL_CTX_SET_ALPN_PROTOS
SSL_CTX_set_alpn_protos(ctx, (const unsigned char *)"\x02h2", 3);
+#endif
ssl = outgoing_ssl_fd(ctx, fd);
if(!ssl) {
printf("cannot create ssl\n");
return 1;
}
-
+ if(!no_tls) {
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
+ ERR_load_SSL_strings();
+#endif
+#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_CRYPTO)
+# ifndef S_SPLINT_S
+ OpenSSL_add_all_algorithms();
+# endif
+#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(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
+#endif
+ }
run(h2_session, port, no_tls, argc, argv);
checklock_stop();
struct comm_reply repinfo;
memset(&repinfo, 0, sizeof(repinfo));
repinfo.c = (struct comm_point*)calloc(1, sizeof(struct comm_point));
+ if(!repinfo.c)
+ fatal_exit("out of memory in fake_front_query");
repinfo.addrlen = (socklen_t)sizeof(struct sockaddr_in);
if(todo->addrlen != 0) {
repinfo.addrlen = todo->addrlen;
log_err("should be: %s", p->str);
fatal_exit("autotrust_check failed");
}
- if(line[0]) line[strlen(line)-1] = 0; /* remove newline */
+ strip_end_white(line);
expanded = macro_process(runtime->vars, runtime, p->str);
if(!expanded)
fatal_exit("could not expand macro line %d", lineno);
log_err("should be: %s", p->str);
fatal_exit("tempfile_check failed");
}
- if(line[0]) line[strlen(line)-1] = 0; /* remove newline */
+ strip_end_white(line);
expanded = macro_process(runtime->vars, runtime, p->str);
if(!expanded)
fatal_exit("could not expand macro line %d", lineno);
/* we return the runtime structure instead. */
struct replay_runtime* runtime = (struct replay_runtime*)
calloc(1, sizeof(struct replay_runtime));
+ if(!runtime)
+ fatal_exit("out of memory in fake_event.c:comm_base_create");
runtime->scenario = saved_scenario;
runtime->vars = macro_store_create();
if(!runtime->vars) fatal_exit("out of memory");
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param),
int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx),
int ATTR_UNUSED(delayclose), int ATTR_UNUSED(tls_use_sni),
- struct dt_env* ATTR_UNUSED(dtenv), int ATTR_UNUSED(udp_connect))
+ struct dt_env* ATTR_UNUSED(dtenv), int ATTR_UNUSED(udp_connect),
+ int ATTR_UNUSED(max_reuse_tcp_queries), int ATTR_UNUSED(tcp_reuse_timeout),
+ int ATTR_UNUSED(tcp_auth_query_timeout))
{
struct replay_runtime* runtime = (struct replay_runtime*)base;
struct outside_network* outnet = calloc(1,
log_info("double delete of pending serviced query");
}
-int resolve_interface_names(struct config_file* ATTR_UNUSED(cfg),
- char*** ATTR_UNUSED(resif), int* ATTR_UNUSED(num_resif))
+int resolve_interface_names(char** ATTR_UNUSED(ifs), int ATTR_UNUSED(num_ifs),
+ struct config_strlist* ATTR_UNUSED(list), char*** ATTR_UNUSED(resif),
+ int* ATTR_UNUSED(num_resif))
{
return 1;
}
{
struct replay_runtime* runtime = (struct replay_runtime*)base;
struct fake_timer* t = (struct fake_timer*)calloc(1, sizeof(*t));
+ if(!t)
+ fatal_exit("out of memory in fake_event.c:comm_timer_create");
t->cb = cb;
t->cb_arg = cb_arg;
fptr_ok(fptr_whitelist_comm_timer(t->cb)); /* check in advance */
struct comm_point* comm_point_create_udp(struct comm_base *ATTR_UNUSED(base),
int ATTR_UNUSED(fd), sldns_buffer* ATTR_UNUSED(buffer),
comm_point_callback_type* ATTR_UNUSED(callback),
- void* ATTR_UNUSED(callback_arg))
+ void* ATTR_UNUSED(callback_arg),
+ struct unbound_socket* ATTR_UNUSED(socket))
{
log_assert(0);
return NULL;
addr_to_str((struct sockaddr_storage*)to_addr, to_addrlen,
addrbuf, sizeof(addrbuf));
if(verbosity >= VERB_ALGO) {
- if(buf[0] != 0) buf[strlen(buf)-1] = 0; /* del newline*/
+ strip_end_white(buf);
log_info("tcp to %s: %s", addrbuf, buf);
}
log_assert(sldns_buffer_limit(query)-LDNS_HEADER_SIZE >= 2);
struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
comm_point_callback_type* cb, void* cb_arg,
struct sockaddr_storage* to_addr, socklen_t to_addrlen, int timeout,
- int ssl, char* host, char* path)
+ int ssl, char* host, char* path, struct config_file* cfg)
{
struct replay_runtime* runtime = (struct replay_runtime*)
outnet->base;
(void)ssl;
(void)host;
(void)path;
+ (void)cfg;
/* handle http comm point and return contents from test script */
return (struct comm_point*)fc;
addr_to_str((struct sockaddr_storage*)addr, addrlen,
addrbuf, sizeof(addrbuf));
if(verbosity >= VERB_ALGO) {
- if(buf[0] != 0) buf[strlen(buf)-1] = 0; /* del newline*/
+ strip_end_white(buf);
log_info("udp to %s: %s", addrbuf, buf);
}
log_assert(sldns_buffer_limit(packet)-LDNS_HEADER_SIZE >= 2);
shift
shift
fi
-
+quiet=0
+if test "$1" = "-q"; then
+ quiet=1
+ shift
+fi
+
if test "$1" = "clean"; then
- echo "rm -f result.* .done* .tdir.var.master .tdir.var.test"
+ if test $quiet = 0; then
+ echo "rm -f result.* .done* .tdir.var.master .tdir.var.test"
+ fi
rm -f result.* .done* .tdir.var.master .tdir.var.test
exit 0
fi
if test "$1" = "fake"; then
- echo "minitdir fake $2"
+ if test $quiet = 0; then
+ echo "minitdir fake $2"
+ fi
echo "fake" > .done-`basename $2 .tdir`
exit 0
fi
desc=`grep ^Description: "result.$name" | sed -e 's/Description: //'`
fi
if test -f ".done-$name"; then
- if test "$1" != "-q"; then
+ if test $quiet = 0; then
echo "** PASSED ** $timelen $name: $desc"
pass=`expr $pass + 1`
fi
for result in *.tdir; do
name=`basename $result .tdir`
if test -f ".done-$name"; then
- if test "$1" != "-q"; then
+ if test $quiet = 0; then
echo "** PASSED ** : $name"
fi
else
if test "$1" != 'exe'; then
# usage
echo "mini tdir. Reduced functionality for old shells."
- echo " tdir exe <file>"
- echo " tdir fake <file>"
- echo " tdir clean"
+ echo " tdir [-q] exe <file>"
+ echo " tdir [-q] fake <file>"
+ echo " tdir [-q] clean"
echo " tdir [-q|-f] report"
exit 1
fi
fi
# Copy
-echo "minitdir copy $1 to $dir"
+if test $quiet = 0; then
+ echo "minitdir copy $1 to $dir"
+fi
mkdir $dir
if cp --help 2>&1 | grep -- "-a" >/dev/null; then
cp -a $name.tdir/* $dir/
grep "Description:" $name.dsc >> $result 2>&1
echo "DateRunStart: "`date "+%s" 2>/dev/null` >> $result
if test -f $name.pre; then
- echo "minitdir exe $name.pre"
+ if test $quiet = 0; then
+ echo "minitdir exe $name.pre"
+ fi
echo "minitdir exe $name.pre" >> $result
$shell $name.pre $args >> $result
if test $? -ne 0; then
fi
fi
if test -f $name.test; then
- echo "minitdir exe $name.test"
+ if test $quiet = 0; then
+ echo "minitdir exe $name.test"
+ fi
echo "minitdir exe $name.test" >> $result
$shell $name.test $args >>$result 2>&1
if test $? -ne 0; then
else
echo "$name: PASSED" >> $result
echo "$name: PASSED" > ../.done-$name
- echo "$name: PASSED"
+ if test $quiet = 0; then
+ echo "$name: PASSED"
+ fi
success="yes"
fi
fi
if test -f $name.post; then
- echo "minitdir exe $name.post"
+ if test $quiet = 0; then
+ echo "minitdir exe $name.post"
+ fi
echo "minitdir exe $name.post" >> $result
$shell $name.post $args >> $result
if test $? -ne 0; then
(void)SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
#endif
(void)SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv3);
+#ifdef HAVE_SSL_CTX_SET_SECURITY_LEVEL
+ SSL_CTX_set_security_level(ctx, 0); /* for keys in tests */
+#endif
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))
--- /dev/null
+/*
+ * testcode/readzone.c - readzone tool reads zonefiles
+ *
+ * Copyright (c) 2021, 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
+ * Command to read and echo a zonefile.
+ */
+
+#include "config.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <stdint.h>
+#include "sldns/str2wire.h"
+#include "sldns/wire2str.h"
+
+int print_usage(FILE *out, const char *progname)
+{
+ fprintf(out, "usage: %s [ -u ] <zonefile> [<origin>]\n", progname);
+ fprintf(out, "\t-u\tprint in unknown type (RFC3597) format\n");
+ return out == stdout ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+int main(int argc, char *const *argv)
+{
+ char *progname = argv[0];
+ uint8_t rr[LDNS_RR_BUF_SIZE];
+ char *str = malloc(1024 * 1024);
+ size_t str_len = sizeof(str);
+ struct sldns_file_parse_state state;
+ FILE *in = NULL;
+ int s = -1;
+ int opt;
+ int print_in_unknown_type_format = 0;
+
+ while ((opt = getopt(argc, argv, "hu")) != -1) {
+ switch (opt) {
+ case 'h':
+ free(str);
+ return print_usage(stdout, progname);
+ case 'u':
+ print_in_unknown_type_format = 1;
+ break;
+ default:
+ free(str);
+ return print_usage(stderr, progname);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ memset(&state, 0, sizeof(state));
+ state.default_ttl = 3600;
+ state.lineno = 1;
+ if (argc == 2) {
+ state.origin_len = sizeof(state.origin);
+ s = sldns_str2wire_dname_buf(argv[1], state.origin
+ , &state.origin_len);
+ if (s) {
+ fprintf(stderr, "Error parsing origin: %s\n"
+ , sldns_get_errorstr_parse(s));
+ free(str);
+ return EXIT_FAILURE;
+ }
+ s = -1;
+ }
+ if (!str)
+ fprintf(stderr, "Memory allocation error: %s\n"
+ , strerror(errno));
+
+ else if (argc != 1 && argc != 2) {
+ free(str);
+ return print_usage(stderr, progname);
+ }
+
+ else if (!(in = fopen(argv[0], "r")))
+ fprintf(stderr, "Error opening \"%s\": %s\n"
+ , argv[0], strerror(errno));
+ else while (!feof(in)) {
+ size_t rr_len = sizeof(rr), dname_len = 0;
+ size_t written;
+
+ s = sldns_fp2wire_rr_buf(in, rr, &rr_len, &dname_len, &state);
+ if (s) {
+ fprintf( stderr, "parse error %d:%d: %s\n"
+ , state.lineno, LDNS_WIREPARSE_OFFSET(s)
+ , sldns_get_errorstr_parse(s));
+ break;
+ }
+ if (rr_len == 0)
+ continue;
+
+ if (print_in_unknown_type_format)
+ written = sldns_wire2str_rr_unknown_buf(
+ rr, rr_len, str, str_len);
+ else
+ written = sldns_wire2str_rr_buf(
+ rr, rr_len, str, str_len);
+
+ if (written > str_len) {
+ while (written > str_len)
+ str_len *= 2;
+ free(str);
+ if (!(str = malloc(str_len))) {
+ fprintf(stderr, "Memory allocation error: %s\n"
+ , strerror(errno));
+ s = -1;
+ break;
+ }
+ if (print_in_unknown_type_format)
+ (void) sldns_wire2str_rr_unknown_buf(
+ rr, rr_len, str, str_len);
+ else
+ (void) sldns_wire2str_rr_buf(
+ rr, rr_len, str, str_len);
+ }
+ fprintf(stdout, "%s", str);
+ }
+ if (in)
+ fclose(in);
+ free(str);
+ return !in || s ? EXIT_FAILURE : EXIT_SUCCESS;
+}
free(rng);
}
-/** strip whitespace from end of string */
-static void
+void
strip_end_white(char* p)
{
size_t i;
if(strncmp(line, "FILE_END", 8) == 0) {
return;
}
- if(line[0]) line[strlen(line)-1] = 0; /* remove newline */
+ strip_end_white(line);
if(!cfg_strlist_insert(last, strdup(line)))
fatal_exit("malloc failure");
last = &( (*last)->next );
if(eq != '=')
fatal_exit("no '=' in assign: %s", remain);
remain += skip;
- if(remain[0]) remain[strlen(remain)-1]=0; /* remove newline */
+ strip_end_white(remain);
mom->string = strdup(remain);
if(!mom->variable || !mom->string)
fatal_exit("out of memory");
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;
+ strip_end_white(remain);
mom->autotrust_id = strdup(remain);
if(!mom->autotrust_id) fatal_exit("out of memory");
read_file_content(in, &pstate->lineno, mom);
mom->evt_type = repevt_tempfile_check;
while(isspace((unsigned char)*remain))
remain++;
- if(strlen(remain)>0 && remain[strlen(remain)-1]=='\n')
- remain[strlen(remain)-1] = 0;
+ strip_end_white(remain);
mom->autotrust_id = strdup(remain);
if(!mom->autotrust_id) fatal_exit("out of memory");
read_file_content(in, &pstate->lineno, mom);
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;
+ strip_end_white(m);
mom->variable = strdup(remain);
mom->string = strdup(m);
if(!mom->string) fatal_exit("out of memory");
if(parse_keyword(&remain, "ADDRESS")) {
while(isspace((unsigned char)*remain))
remain++;
- if(strlen(remain) > 0) /* remove \n */
- remain[strlen(remain)-1] = 0;
+ strip_end_white(remain);
if(!extstrtoaddr(remain, &mom->addr, &mom->addrlen)) {
log_err("line %d: could not parse ADDRESS: %s",
pstate->lineno, remain);
return NULL;
}
ctime_r(&tt, buf);
- if(buf[0]) buf[strlen(buf)-1]=0; /* remove trailing newline */
+#ifdef USE_WINSOCK
+ if(strlen(buf) > 10 && buf[7]==' ' && buf[8]=='0')
+ buf[8]=' '; /* fix error in windows ctime */
+#endif
+ strip_end_white(buf);
return strdup(buf);
}
/** get oldest enabled fake timer */
struct fake_timer* replay_get_oldest_timer(struct replay_runtime* runtime);
+/** strip whitespace from end of string */
+void strip_end_white(char* p);
+
/**
* Create variable storage
* @return new or NULL on failure.
/** SIGPIPE handler */
static RETSIGTYPE sigh(int sig)
{
+ char str[] = "Got unhandled signal \n";
if(sig == SIGPIPE) {
- printf("got SIGPIPE, remote connection gone\n");
+ char* strpipe = "got SIGPIPE, remote connection gone\n";
+ /* simple cast to void will not silence Wunused-result */
+ (void)!write(STDOUT_FILENO, strpipe, strlen(strpipe));
exit(1);
}
- printf("Got unhandled signal %d\n", sig);
+ str[21] = '0' + (sig/10)%10;
+ str[22] = '0' + sig%10;
+ /* simple cast to void will not silence Wunused-result */
+ (void)!write(STDOUT_FILENO, str, strlen(str));
exit(1);
}
#endif /* SIGPIPE */
id++;
if(*id == '\0')
fatal_exit("TEMPFILE_NAME must have id, line %d", *lineno);
- id[strlen(id)-1]=0; /* remove newline */
+ strip_end_white(id);
fake_temp_file("_temp_", id, line, sizeof(line));
fprintf(cfg, "\"%s\"\n", line);
}
id++;
if(*id == '\0')
fatal_exit("TEMPFILE_CONTENTS must have id, line %d", *lineno);
- id[strlen(id)-1]=0; /* remove newline */
+ strip_end_white(id);
fake_temp_file("_temp_", id, line, sizeof(line));
/* open file and spool to it */
spool = fopen(line, "w");
char* tid = parse+17;
while(isspace((unsigned char)*tid))
tid++;
- tid[strlen(tid)-1]=0; /* remove newline */
+ strip_end_white(tid);
fake_temp_file("_temp_", tid, l2, sizeof(l2));
snprintf(line, sizeof(line), "$INCLUDE %s\n", l2);
}
id++;
if(*id == '\0')
fatal_exit("AUTROTRUST_FILE must have id, line %d", *lineno);
- id[strlen(id)-1]=0; /* remove newline */
+ strip_end_white(id);
fake_temp_file("_auto_", id, line, sizeof(line));
/* add option for the file */
fprintf(cfg, "server: auto-trust-anchor-file: \"%s\"\n", line);
fprintf(cfg, " username: \"\"\n");
fprintf(cfg, " pidfile: \"\"\n");
fprintf(cfg, " val-log-level: 2\n");
+ fprintf(cfg, " log-servfail: yes\n");
fprintf(cfg, "remote-control: control-enable: no\n");
while(fgets(line, MAX_LINE_LEN-1, in)) {
parse = line;
int i;
char buf[256];
for(i=0; i<tempno; i++) {
+#ifdef USE_WINSOCK
+ snprintf(buf, sizeof(buf), "unbound.unittest.%u.%d",
+ (unsigned)getpid(), i);
+#else
snprintf(buf, sizeof(buf), "/tmp/unbound.unittest.%u.%d",
(unsigned)getpid(), i);
+#endif
if(vbmp) printf("cleanup: unlink %s\n", buf);
unlink(buf);
}
char *fname;
FILE *out;
size_t r;
+#ifdef USE_WINSOCK
+ snprintf(buf, sizeof(buf), "unbound.unittest.%u.%d",
+ (unsigned)getpid(), tempno++);
+#else
snprintf(buf, sizeof(buf), "/tmp/unbound.unittest.%u.%d",
(unsigned)getpid(), tempno++);
+#endif
fname = strdup(buf);
if(!fname) fatal_exit("out of memory");
/* if no string, just make the name */
}
/** Add zone from file for testing */
-static struct auth_zone*
-addzone(struct auth_zones* az, const char* name, char* fname)
+struct auth_zone*
+authtest_addzone(struct auth_zones* az, const char* name, char* fname)
{
struct auth_zone* z;
size_t nmlen;
az = auth_zones_create();
unit_assert(az);
- z = addzone(az, name, fname);
+ z = authtest_addzone(az, name, fname);
unit_assert(z);
outf = create_tmp_file(NULL);
if(!auth_zone_write_file(z, outf)) {
fname = create_tmp_file(zone);
az = auth_zones_create();
if(!az) fatal_exit("out of memory");
- z = addzone(az, name, fname);
+ z = authtest_addzone(az, name, fname);
if(!z) fatal_exit("could not read zone for queries test");
del_tmp_file(fname);
#include "sldns/parseutil.h"
/** verbose this unit test */
-static int vbmp = 0;
+static int vbmp = 0;
/** print buffer to hex into string */
static void
respip_conf_actions_test();
}
-#include "services/outside_network.h"
-/** add number of new IDs to the reuse tree, randomly chosen */
-static void tcpid_addmore(struct reuse_tcp* reuse,
- struct outside_network* outnet, unsigned int addnum)
-{
- unsigned int i;
- struct waiting_tcp* w;
- for(i=0; i<addnum; i++) {
- uint16_t id = reuse_tcp_select_id(reuse, outnet);
- unit_assert(!reuse_tcp_by_id_find(reuse, id));
- w = calloc(1, sizeof(*w));
- unit_assert(w);
- w->id = id;
- w->outnet = outnet;
- w->next_waiting = (void*)reuse->pending;
- reuse_tree_by_id_insert(reuse, w);
- }
-}
-
-/** fill up the reuse ID tree and test assertions */
-static void tcpid_fillup(struct reuse_tcp* reuse,
- struct outside_network* outnet)
-{
- int t, numtest=3;
- for(t=0; t<numtest; t++) {
- rbtree_init(&reuse->tree_by_id, reuse_id_cmp);
- tcpid_addmore(reuse, outnet, 65535);
- reuse_del_readwait(&reuse->tree_by_id);
- }
-}
-
-/** test TCP ID selection */
-static void tcpid_test(void)
-{
- struct pending_tcp pend;
- struct outside_network outnet;
- unit_show_func("services/outside_network.c", "reuse_tcp_select_id");
- memset(&pend, 0, sizeof(pend));
- pend.reuse.pending = &pend;
- memset(&outnet, 0, sizeof(outnet));
- outnet.rnd = ub_initstate(NULL);
- rbtree_init(&pend.reuse.tree_by_id, reuse_id_cmp);
- tcpid_fillup(&pend.reuse, &outnet);
- ub_randfree(outnet.rnd);
-}
-
void unit_show_func(const char* file, const char* func)
{
printf("test %s:%s\n", file, func);
slabhash_test();
infra_test();
ldns_test();
+ zonemd_test();
+ tcpreuse_test();
msgparse_test();
- tcpid_test();
#ifdef CLIENT_SUBNET
ecs_test();
#endif /* CLIENT_SUBNET */
void ldns_test(void);
/** unit test for auth zone functions */
void authzone_test(void);
+/** unit test for zonemd functions */
+void zonemd_test(void);
+/** unit test for tcp_reuse functions */
+void tcpreuse_test(void);
#endif /* TESTCODE_UNITMAIN_H */
--- /dev/null
+/*
+ * testcode/unittcpreuse.c - unit test for tcp_reuse.
+ *
+ * Copyright (c) 2021, 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 tcp_reuse functionality.
+ */
+
+#include "config.h"
+#include "testcode/unitmain.h"
+#include "util/log.h"
+#include "util/random.h"
+#include "services/outside_network.h"
+
+/** add number of new IDs to the reuse tree, randomly chosen */
+static void tcpid_addmore(struct reuse_tcp* reuse,
+ struct outside_network* outnet, unsigned int addnum)
+{
+ unsigned int i;
+ struct waiting_tcp* w;
+ for(i=0; i<addnum; i++) {
+ uint16_t id = reuse_tcp_select_id(reuse, outnet);
+ unit_assert(!reuse_tcp_by_id_find(reuse, id));
+ w = calloc(1, sizeof(*w));
+ unit_assert(w);
+ w->id = id;
+ w->outnet = outnet;
+ w->next_waiting = (void*)reuse->pending;
+ reuse_tree_by_id_insert(reuse, w);
+ }
+}
+
+/** fill up the reuse ID tree and test assertions */
+static void tcpid_fillup(struct reuse_tcp* reuse,
+ struct outside_network* outnet)
+{
+ int t, numtest=3;
+ for(t=0; t<numtest; t++) {
+ rbtree_init(&reuse->tree_by_id, reuse_id_cmp);
+ tcpid_addmore(reuse, outnet, 65535);
+ reuse_del_readwait(&reuse->tree_by_id);
+ }
+}
+
+/** test TCP ID selection */
+static void tcpid_test(void)
+{
+ struct pending_tcp pend;
+ struct outside_network outnet;
+ unit_show_func("services/outside_network.c", "reuse_tcp_select_id");
+ memset(&pend, 0, sizeof(pend));
+ pend.reuse.pending = &pend;
+ memset(&outnet, 0, sizeof(outnet));
+ outnet.rnd = ub_initstate(NULL);
+ rbtree_init(&pend.reuse.tree_by_id, reuse_id_cmp);
+ tcpid_fillup(&pend.reuse, &outnet);
+ ub_randfree(outnet.rnd);
+}
+
+/** check that the tree has present number of nodes and the LRU is linked
+ * properly. */
+static void check_tree_and_list(struct outside_network* outnet, int present)
+{
+ int i;
+ struct reuse_tcp *reuse, *next_reuse;
+ unit_assert(present == (int)outnet->tcp_reuse.count);
+ if(present < 1) {
+ unit_assert(outnet->tcp_reuse_first == NULL);
+ unit_assert(outnet->tcp_reuse_last == NULL);
+ return;
+ }
+ unit_assert(outnet->tcp_reuse_first->item_on_lru_list);
+ unit_assert(!outnet->tcp_reuse_first->lru_prev);
+ reuse = outnet->tcp_reuse_first;
+ for(i=0; i<present-1; i++) {
+ unit_assert(reuse->item_on_lru_list);
+ unit_assert(reuse->lru_next);
+ unit_assert(reuse->lru_next != reuse);
+ next_reuse = reuse->lru_next;
+ unit_assert(next_reuse->lru_prev == reuse);
+ reuse = next_reuse;
+ }
+ unit_assert(!reuse->lru_next);
+ unit_assert(outnet->tcp_reuse_last->item_on_lru_list);
+ unit_assert(outnet->tcp_reuse_last == reuse);
+}
+
+/** creates pending_tcp. Copy of outside_network.c:create_pending_tcp without
+ * the comm_point creation */
+static int create_pending_tcp(struct outside_network* outnet)
+{
+ size_t i;
+ if(outnet->num_tcp == 0)
+ return 1; /* no tcp needed, nothing to do */
+ if(!(outnet->tcp_conns = (struct pending_tcp **)calloc(
+ outnet->num_tcp, sizeof(struct pending_tcp*))))
+ return 0;
+ for(i=0; i<outnet->num_tcp; i++) {
+ if(!(outnet->tcp_conns[i] = (struct pending_tcp*)calloc(1,
+ sizeof(struct pending_tcp))))
+ return 0;
+ outnet->tcp_conns[i]->next_free = outnet->tcp_free;
+ outnet->tcp_free = outnet->tcp_conns[i];
+ }
+ return 1;
+}
+
+/** empty the tcp_reuse tree and LRU list */
+static void empty_tree(struct outside_network* outnet)
+{
+ size_t i;
+ struct reuse_tcp* reuse;
+ reuse = outnet->tcp_reuse_first;
+ i = outnet->tcp_reuse.count;
+ while(reuse) {
+ reuse_tcp_remove_tree_list(outnet, reuse);
+ check_tree_and_list(outnet, --i);
+ reuse = outnet->tcp_reuse_first;
+ }
+}
+
+/** check removal of the LRU element on the given position of total elements */
+static void check_removal(struct outside_network* outnet, int position, int total)
+{
+ int i;
+ struct reuse_tcp* reuse;
+ empty_tree(outnet);
+ for(i=0; i<total; i++) {
+ reuse_tcp_insert(outnet, outnet->tcp_conns[i]);
+ }
+ check_tree_and_list(outnet, total);
+ reuse = outnet->tcp_reuse_first;
+ for(i=0; i<position; i++) reuse = reuse->lru_next;
+ reuse_tcp_remove_tree_list(outnet, reuse);
+ check_tree_and_list(outnet, total-1);
+}
+
+/** check snipping off the last element of the LRU with total elements */
+static void check_snip(struct outside_network* outnet, int total)
+{
+ int i;
+ struct reuse_tcp* reuse;
+ empty_tree(outnet);
+ for(i=0; i<total; i++) {
+ reuse_tcp_insert(outnet, outnet->tcp_conns[i]);
+ }
+ check_tree_and_list(outnet, total);
+ reuse = reuse_tcp_lru_snip(outnet);
+ while(reuse) {
+ reuse_tcp_remove_tree_list(outnet, reuse);
+ check_tree_and_list(outnet, --total);
+ reuse = reuse_tcp_lru_snip(outnet);
+ }
+ unit_assert(outnet->tcp_reuse_first == NULL);
+ unit_assert(outnet->tcp_reuse_last == NULL);
+ unit_assert(outnet->tcp_reuse.count == 0);
+}
+
+/** test tcp_reuse tree and LRU list functions */
+static void tcp_reuse_tree_list_test(void)
+{
+ size_t i;
+ struct outside_network outnet;
+ struct reuse_tcp* reuse;
+ memset(&outnet, 0, sizeof(outnet));
+ rbtree_init(&outnet.tcp_reuse, reuse_cmp);
+ outnet.num_tcp = 5;
+ outnet.tcp_reuse_max = outnet.num_tcp;
+ if(!create_pending_tcp(&outnet)) fatal_exit("out of memory");
+ /* add all to the tree */
+ unit_show_func("services/outside_network.c", "reuse_tcp_insert");
+ for(i=0; i<outnet.num_tcp; i++) {
+ reuse_tcp_insert(&outnet, outnet.tcp_conns[i]);
+ check_tree_and_list(&outnet, i+1);
+ }
+ /* check touching */
+ unit_show_func("services/outside_network.c", "reuse_tcp_lru_touch");
+ for(i=0; i<outnet.tcp_reuse.count; i++) {
+ for(reuse = outnet.tcp_reuse_first; reuse->lru_next; reuse = reuse->lru_next);
+ reuse_tcp_lru_touch(&outnet, reuse);
+ check_tree_and_list(&outnet, outnet.num_tcp);
+ }
+ /* check removal */
+ unit_show_func("services/outside_network.c", "reuse_tcp_remove_tree_list");
+ check_removal(&outnet, 2, 5);
+ check_removal(&outnet, 1, 3);
+ check_removal(&outnet, 1, 2);
+ /* check snip */
+ unit_show_func("services/outside_network.c", "reuse_tcp_lru_snip");
+ check_snip(&outnet, 4);
+
+ for(i=0; i<outnet.num_tcp; i++)
+ if(outnet.tcp_conns[i]) {
+ free(outnet.tcp_conns[i]);
+ }
+ free(outnet.tcp_conns);
+}
+
+void tcpreuse_test(void)
+{
+ unit_show_feature("tcp_reuse");
+ tcpid_test();
+ tcp_reuse_tree_list_test();
+}
--- /dev/null
+/*
+ * testcode/unitzonemd.c - unit test for zonemd.
+ *
+ * Copyright (c) 2020, 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 tests for ZONEMD functionality.
+ */
+
+#include "config.h"
+#include <ctype.h>
+#include "util/log.h"
+#include "testcode/unitmain.h"
+#include "sldns/str2wire.h"
+#include "services/authzone.h"
+#include "util/data/dname.h"
+#include "util/regional.h"
+#include "validator/val_anchor.h"
+
+#define xstr(s) str(s)
+#define str(s) #s
+#define SRCDIRSTR xstr(SRCDIR)
+
+/** Add zone from file for testing */
+struct auth_zone* authtest_addzone(struct auth_zones* az, const char* name,
+ char* fname);
+
+/** zonemd unit test, generate a zonemd digest and check if correct */
+static void zonemd_generate_test(const char* zname, char* zfile,
+ int scheme, int hashalgo, const char* digest)
+{
+ uint8_t zonemd_hash[512];
+ size_t hashlen = 0;
+ char output[1024+1];
+ size_t i;
+ struct auth_zones* az;
+ struct auth_zone* z;
+ int result;
+ struct regional* region = NULL;
+ struct sldns_buffer* buf = NULL;
+ char* reason = NULL;
+ char* digestdup;
+
+ if(!zonemd_hashalgo_supported(hashalgo))
+ return; /* cannot test unsupported algo */
+
+ /* setup environment */
+ az = auth_zones_create();
+ unit_assert(az);
+ region = regional_create();
+ unit_assert(region);
+ buf = sldns_buffer_new(65535);
+ unit_assert(buf);
+
+ /* read file */
+ z = authtest_addzone(az, zname, zfile);
+ unit_assert(z);
+ lock_rw_wrlock(&z->lock);
+ z->zonemd_check = 1;
+ lock_rw_unlock(&z->lock);
+
+ /* create zonemd digest */
+ result = auth_zone_generate_zonemd_hash(z, scheme, hashalgo,
+ zonemd_hash, sizeof(zonemd_hash), &hashlen, region, buf,
+ &reason);
+ if(reason) printf("zonemd failure reason: %s\n", reason);
+ unit_assert(result);
+
+ /* check digest */
+ unit_assert(hashlen*2+1 <= sizeof(output));
+ for(i=0; i<hashlen; i++) {
+ const char* hexl = "0123456789ABCDEF";
+ output[i*2] = hexl[(zonemd_hash[i]&0xf0)>>4];
+ output[i*2+1] = hexl[zonemd_hash[i]&0xf];
+ }
+ output[hashlen*2] = 0;
+ digestdup = strdup(digest);
+ unit_assert(digestdup);
+ for(i=0; i<strlen(digestdup); i++) {
+ digestdup[i] = toupper(digestdup[i]);
+ }
+ if(verbosity >= VERB_ALGO) {
+ char zname[255+1];
+ dname_str(z->name, zname);
+ printf("zonemd generated for %s in %s with "
+ "scheme=%d hashalgo=%d\n", zname, z->zonefile,
+ scheme, hashalgo);
+ printf("digest %s\n", output);
+ printf("wanted %s\n", digestdup);
+ }
+ unit_assert(strcmp(output, digestdup) == 0);
+
+ /* delete environment */
+ free(digestdup);
+ auth_zones_delete(az);
+ regional_destroy(region);
+ sldns_buffer_free(buf);
+
+ if(verbosity >= VERB_ALGO) {
+ printf("\n");
+ }
+}
+
+/** loop over files and test generated zonemd digest */
+static void zonemd_generate_tests(void)
+{
+ unit_show_func("services/authzone.c", "auth_zone_generate_zonemd_hash");
+ zonemd_generate_test("example.org", SRCDIRSTR "/testdata/zonemd.example1.zone",
+ 1, 2, "20564D10F50A0CEBEC856C64032B7DFB53D3C449A421A5BC7A21F7627B4ACEA4DF29F2C6FE82ED9C23ADF6F4D420D5DD63EF6E6349D60FDAB910B65DF8D481B7");
+
+ /* https://tools.ietf.org/html/draft-ietf-dnsop-dns-zone-digest-12
+ * from section A.1 */
+ zonemd_generate_test("example", SRCDIRSTR "/testdata/zonemd.example_a1.zone",
+ 1, 1, "c68090d90a7aed716bc459f9340e3d7c1370d4d24b7e2fc3a1ddc0b9a87153b9a9713b3c9ae5cc27777f98b8e730044c");
+
+ /* https://tools.ietf.org/html/draft-ietf-dnsop-dns-zone-digest-12
+ * from section A.2 */
+ zonemd_generate_test("example", SRCDIRSTR "/testdata/zonemd.example_a2.zone",
+ 1, 1, "31cefb03814f5062ad12fa951ba0ef5f8da6ae354a415767246f7dc932ceb1e742a2108f529db6a33a11c01493de358d");
+
+ /* https://tools.ietf.org/html/draft-ietf-dnsop-dns-zone-digest-12
+ * from section A.3 SHA384 digest */
+ zonemd_generate_test("example", SRCDIRSTR "/testdata/zonemd.example_a3.zone",
+ 1, 1, "62e6cf51b02e54b9b5f967d547ce43136792901f9f88e637493daaf401c92c279dd10f0edb1c56f8080211f8480ee306");
+
+ /* https://tools.ietf.org/html/draft-ietf-dnsop-dns-zone-digest-12
+ * from section A.3 SHA512 digest*/
+ zonemd_generate_test("example", SRCDIRSTR "/testdata/zonemd.example_a3.zone",
+ 1, 2, "08cfa1115c7b948c4163a901270395ea226a930cd2cbcf2fa9a5e6eb85f37c8a4e114d884e66f176eab121cb02db7d652e0cc4827e7a3204f166b47e5613fd27");
+
+ /* https://tools.ietf.org/html/draft-ietf-dnsop-dns-zone-digest-12
+ * from section A.4 */
+ zonemd_generate_test("uri.arpa", SRCDIRSTR "/testdata/zonemd.example_a4.zone",
+ 1, 1, "1291b78ddf7669b1a39d014d87626b709b55774c5d7d58fadc556439889a10eaf6f11d615900a4f996bd46279514e473");
+
+ /* https://tools.ietf.org/html/draft-ietf-dnsop-dns-zone-digest-12
+ * from section A.5 */
+ zonemd_generate_test("root-servers.net", SRCDIRSTR "/testdata/zonemd.example_a5.zone",
+ 1, 1, "f1ca0ccd91bd5573d9f431c00ee0101b2545c97602be0a978a3b11dbfc1c776d5b3e86ae3d973d6b5349ba7f04340f79");
+}
+
+/** test the zonemd check routine */
+static void zonemd_check_test(void)
+{
+ const char* zname = "example.org";
+ char* zfile = SRCDIRSTR "/testdata/zonemd.example1.zone";
+ int scheme = 1;
+ int hashalgo = 2;
+ const char* digest = "20564D10F50A0CEBEC856C64032B7DFB53D3C449A421A5BC7A21F7627B4ACEA4DF29F2C6FE82ED9C23ADF6F4D420D5DD63EF6E6349D60FDAB910B65DF8D481B7";
+ const char* digestwrong = "20564D10F50A0CEBEC856C64032B7DFB53D3C449A421A5BC7A21F7627B4ACEA4DF29F2C6FE82ED9C23ADF6F4D420D5DD63EF6E6349D60FDAB910B65DF8D48100";
+ uint8_t hash[512], hashwrong[512];
+ size_t hashlen = 0, hashwronglen = 0;
+ struct auth_zones* az;
+ struct auth_zone* z;
+ int result;
+ struct regional* region = NULL;
+ struct sldns_buffer* buf = NULL;
+ char* reason = NULL;
+
+ if(!zonemd_hashalgo_supported(hashalgo))
+ return; /* cannot test unsupported algo */
+ unit_show_func("services/authzone.c", "auth_zone_generate_zonemd_check");
+
+ /* setup environment */
+ az = auth_zones_create();
+ unit_assert(az);
+ region = regional_create();
+ unit_assert(region);
+ buf = sldns_buffer_new(65535);
+ unit_assert(buf);
+
+ /* read file */
+ z = authtest_addzone(az, zname, zfile);
+ unit_assert(z);
+ lock_rw_wrlock(&z->lock);
+ z->zonemd_check = 1;
+ lock_rw_unlock(&z->lock);
+ hashlen = sizeof(hash);
+ if(sldns_str2wire_hex_buf(digest, hash, &hashlen) != 0) {
+ unit_assert(0); /* parse failure */
+ }
+ hashwronglen = sizeof(hashwrong);
+ if(sldns_str2wire_hex_buf(digestwrong, hashwrong, &hashwronglen) != 0) {
+ unit_assert(0); /* parse failure */
+ }
+
+ /* check return values of the check routine */
+ result = auth_zone_generate_zonemd_check(z, scheme, hashalgo,
+ hash, hashlen, region, buf, &reason);
+ unit_assert(result && reason == NULL);
+ result = auth_zone_generate_zonemd_check(z, 241, hashalgo,
+ hash, hashlen, region, buf, &reason);
+ unit_assert(!result && strcmp(reason, "unsupported scheme")==0);
+ result = auth_zone_generate_zonemd_check(z, scheme, 242,
+ hash, hashlen, region, buf, &reason);
+ unit_assert(!result && strcmp(reason, "unsupported algorithm")==0);
+ result = auth_zone_generate_zonemd_check(z, scheme, hashalgo,
+ hash, 2, region, buf, &reason);
+ unit_assert(!result && strcmp(reason, "digest length too small, less than 12")==0);
+ result = auth_zone_generate_zonemd_check(z, scheme, hashalgo,
+ hashwrong, hashwronglen, region, buf, &reason);
+ unit_assert(!result && strcmp(reason, "incorrect digest")==0);
+ result = auth_zone_generate_zonemd_check(z, scheme, hashalgo,
+ hashwrong, hashwronglen-3, region, buf, &reason);
+ unit_assert(!result && strcmp(reason, "incorrect digest length")==0);
+
+ /* delete environment */
+ auth_zones_delete(az);
+ regional_destroy(region);
+ sldns_buffer_free(buf);
+
+ if(verbosity >= VERB_ALGO) {
+ printf("\n");
+ }
+}
+
+/** zonemd test verify */
+static void zonemd_verify_test(char* zname, char* zfile, char* tastr,
+ char* date_override, char* result_wanted)
+{
+ time_t now = 0;
+ struct module_stack mods;
+ struct module_env env;
+ char* result = NULL;
+ struct auth_zone* z;
+
+ /* setup test harness */
+ memset(&mods, 0, sizeof(mods));
+ memset(&env, 0, sizeof(env));
+ env.scratch = regional_create();
+ if(!env.scratch)
+ fatal_exit("out of memory");
+ env.scratch_buffer = sldns_buffer_new(65553);
+ if(!env.scratch_buffer)
+ fatal_exit("out of memory");
+ env.cfg = config_create();
+ if(!env.cfg)
+ fatal_exit("out of memory");
+ env.now = &now;
+ env.cfg->val_date_override = cfg_convert_timeval(date_override);
+ if(!env.cfg->val_date_override)
+ fatal_exit("could not parse datetime %s", date_override);
+ if(env.cfg->module_conf)
+ free(env.cfg->module_conf);
+ env.cfg->module_conf = strdup("validator iterator");
+ if(!env.cfg->module_conf)
+ fatal_exit("out of memory");
+ if(tastr) {
+ if(!cfg_strlist_insert(&env.cfg->trust_anchor_list,
+ strdup(tastr)))
+ fatal_exit("out of memory");
+ }
+ env.anchors = anchors_create();
+ if(!env.anchors)
+ fatal_exit("out of memory");
+ env.auth_zones = auth_zones_create();
+ if(!env.auth_zones)
+ fatal_exit("out of memory");
+ modstack_init(&mods);
+ if(!modstack_setup(&mods, env.cfg->module_conf, &env))
+ fatal_exit("could not modstack_setup");
+ env.mesh = mesh_create(&mods, &env);
+ if(!env.mesh)
+ fatal_exit("out of memory");
+
+ /* load data */
+ z = authtest_addzone(env.auth_zones, zname, zfile);
+ if(!z)
+ fatal_exit("could not addzone %s %s", zname, zfile);
+
+ /* test */
+ lock_rw_wrlock(&z->lock);
+ z->zonemd_check = 1;
+ auth_zone_verify_zonemd(z, &env, &mods, &result, 1, 0);
+ lock_rw_unlock(&z->lock);
+ if(verbosity >= VERB_ALGO) {
+ printf("auth zone %s: ZONEMD verification %s: %s\n", zname,
+ (strcmp(result, "ZONEMD verification successful")==0?"successful":"failed"),
+ result);
+ }
+ if(!result)
+ fatal_exit("out of memory");
+ unit_assert(strcmp(result, result_wanted) == 0);
+ if(strcmp(result, "ZONEMD verification successful") == 0 ||
+ strcmp(result, "DNSSEC verified nonexistence of ZONEMD") == 0 ||
+ strcmp(result, "no ZONEMD present") == 0) {
+ lock_rw_rdlock(&z->lock);
+ unit_assert(!z->zone_expired);
+ lock_rw_unlock(&z->lock);
+ } else {
+ lock_rw_rdlock(&z->lock);
+ unit_assert(z->zone_expired);
+ lock_rw_unlock(&z->lock);
+ }
+ free(result);
+
+ /* desetup test harness */
+ mesh_delete(env.mesh);
+ modstack_desetup(&mods, &env);
+ auth_zones_delete(env.auth_zones);
+ anchors_delete(env.anchors);
+ config_delete(env.cfg);
+ regional_destroy(env.scratch);
+ sldns_buffer_free(env.scratch_buffer);
+
+ if(verbosity >= VERB_ALGO) {
+ printf("\n");
+ }
+}
+
+/** zonemd test verify suite */
+static void zonemd_verify_tests(void)
+{
+ unit_show_func("services/authzone.c", "auth_zone_verify_zonemd");
+ /* give trustanchor for unsigned zone, should fail */
+ zonemd_verify_test("example.org",
+ SRCDIRSTR "/testdata/zonemd.example1.zone",
+ "example.org. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20180302005009",
+ "verify DNSKEY RRset with trust anchor failed: have trust anchor, but zone has no DNSKEY");
+ /* unsigned zone without ZONEMD in it */
+ zonemd_verify_test("example.org",
+ SRCDIRSTR "/testdata/zonemd.example1.zone",
+ NULL,
+ "20180302005009",
+ "no ZONEMD present");
+ /* no trust anchor, so it succeeds for zone with a correct ZONEMD */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example2.zone",
+ NULL,
+ "20180302005009",
+ "ZONEMD verification successful");
+ /* trust anchor for another zone, so it is indeterminate */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example2.zone",
+ "example.org. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20180302005009",
+ "ZONEMD verification successful");
+
+ /* load a DNSSEC signed zone, but no trust anchor */
+ /* this zonefile has an incorrect ZONEMD digest, with correct
+ * DNSSEC signature. */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example3.zone",
+ NULL,
+ "20180302005009",
+ "incorrect digest");
+ /* load a DNSSEC zone with NSEC3, but no trust anchor */
+ /* this zonefile has an incorrect ZONEMD digest, with correct
+ * DNSSEC signature. */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example4.zone",
+ NULL,
+ "20180302005009",
+ "incorrect digest");
+ /* valid zonemd, in dnssec signed zone, no trust anchor*/
+ /* this zonefile has a correct ZONEMD digest and
+ * correct DNSSEC signature */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example5.zone",
+ NULL,
+ "20180302005009",
+ "ZONEMD verification successful");
+ /* valid zonemd, in dnssec NSEC3 zone, no trust anchor*/
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example6.zone",
+ NULL,
+ "20180302005009",
+ "ZONEMD verification successful");
+
+ /* load a DNSSEC signed zone with a trust anchor, valid ZONEMD */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example5.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+ "ZONEMD verification successful");
+ /* load a DNSSEC NSEC3 signed zone with a trust anchor, valid ZONEMD */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example6.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+ "ZONEMD verification successful");
+
+ /* load a DNSSEC NSEC zone without ZONEMD */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example7.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+ "DNSSEC verified nonexistence of ZONEMD");
+ /* load a DNSSEC NSEC3 zone without ZONEMD */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example8.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+ "DNSSEC verified nonexistence of ZONEMD");
+
+ /* load DNSSEC zone but RRSIG on ZONEMD is wrong */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example9.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+#ifdef HAVE_SSL
+ "DNSSEC verify failed for ZONEMD RRset: signature crypto failed"
+#else /* HAVE_NETTLE */
+ "DNSSEC verify failed for ZONEMD RRset: RSA signature verification failed"
+#endif
+ );
+ /* load DNSSEC zone but RRSIG on SOA is wrong */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example10.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+#ifdef HAVE_SSL
+ "DNSSEC verify failed for SOA RRset: signature crypto failed"
+#else /* HAVE_NETTLE */
+ "DNSSEC verify failed for SOA RRset: RSA signature verification failed"
+#endif
+ );
+
+ /* load DNSSEC zone without ZONEMD, but NSEC bitmap says it exists */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example11.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+ "DNSSEC NSEC bitmap says type ZONEMD exists");
+ /* load DNSSEC zone without ZONEMD, but NSEC3 bitmap says it exists */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example12.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+ "DNSSEC NSEC3 bitmap says type ZONEMD exists");
+
+ /* load DNSSEC zone without ZONEMD, but RRSIG on NSEC not okay */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example13.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+#ifdef HAVE_SSL
+ "DNSSEC verify failed for NSEC RRset: signature crypto failed"
+#else /* HAVE_NETTLE */
+ "DNSSEC verify failed for NSEC RRset: RSA signature verification failed"
+#endif
+ );
+ /* load DNSSEC zone without ZONEMD, but RRSIG on NSEC3 not okay */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example14.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+#ifdef HAVE_SSL
+ "DNSSEC verify failed for NSEC3 RRset: signature crypto failed"
+#else /* HAVE_NETTLE */
+ "DNSSEC verify failed for NSEC3 RRset: RSA signature verification failed"
+#endif
+ );
+
+ /* load DNSSEC zone, with ZONEMD, but DNSKEY RRSIG is not okay. */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example15.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+#ifdef HAVE_SSL
+ "verify DNSKEY RRset with trust anchor failed: signature crypto failed"
+#else /* HAVE_NETTLE */
+ "verify DNSKEY RRset with trust anchor failed: RSA signature verification failed"
+#endif
+ );
+ /* load DNSSEC zone, but trust anchor mismatches DNSKEY */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example5.zone",
+ /* okay anchor is
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af", */
+ "example.com. IN DS 55566 8 2 0000000000111111222223333444444dfcf92595148022f2c2fd98e5deee90af",
+ "20201020135527",
+ "verify DNSKEY RRset with trust anchor failed: DS hash mismatches key");
+ /* load DNSSEC zone, but trust anchor fails because the zone
+ * has expired signatures. We set the date for it */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example5.zone",
+ "example.com. IN DS 55566 8 2 9c148338951ce1c3b5cd3da532f3d90dfcf92595148022f2c2fd98e5deee90af",
+ /* okay date: "20201020135527", */
+ "20221020135527",
+ "verify DNSKEY RRset with trust anchor failed: signature expired");
+
+ /* duplicate zonemd with same scheme and algorithm */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example16.zone",
+ NULL,
+ "20180302005009",
+ "ZONEMD RRSet contains more than one RR with the same scheme and hash algorithm");
+ /* different capitalisation of ns name and owner names, should
+ * be canonicalized. */
+ zonemd_verify_test("example.com",
+ SRCDIRSTR "/testdata/zonemd.example17.zone",
+ NULL,
+ "20180302005009",
+ "ZONEMD verification successful");
+}
+
+/** zonemd unit tests */
+void zonemd_test(void)
+{
+ unit_show_feature("zonemd");
+ zonemd_generate_tests();
+ zonemd_check_test();
+ zonemd_verify_tests();
+}