aboutsummaryrefslogtreecommitdiff
path: root/testcode
diff options
context:
space:
mode:
Diffstat (limited to 'testcode')
-rw-r--r--testcode/dohclient.c9
-rw-r--r--testcode/fake_event.c171
-rw-r--r--testcode/lock_verify.c2
-rw-r--r--testcode/perf.c8
-rw-r--r--testcode/replay.c85
-rw-r--r--testcode/streamtcp.c18
-rw-r--r--testcode/testpkts.c73
-rw-r--r--testcode/testpkts.h18
-rw-r--r--testcode/unitlruhash.c22
-rw-r--r--testcode/unitmain.c416
10 files changed, 652 insertions, 170 deletions
diff --git a/testcode/dohclient.c b/testcode/dohclient.c
index 64af699bc718..de9f39d7d941 100644
--- a/testcode/dohclient.c
+++ b/testcode/dohclient.c
@@ -226,9 +226,16 @@ make_query(char* qname, char* qtype, char* qclass)
printf("cannot parse query name: '%s'\n", qname);
exit(1);
}
-
qinfo.qtype = sldns_get_rr_type_by_name(qtype);
+ if(qinfo.qtype == 0 && strcmp(qtype, "TYPE0") != 0) {
+ printf("cannot parse query type: '%s'\n", qtype);
+ exit(1);
+ }
qinfo.qclass = sldns_get_rr_class_by_name(qclass);
+ if(qinfo.qclass == 0 && strcmp(qclass, "CLASS0") != 0) {
+ printf("cannot parse query class: '%s'\n", qclass);
+ exit(1);
+ }
qinfo.local_alias = NULL;
qinfo_query_encode(buf, &qinfo); /* flips buffer */
diff --git a/testcode/fake_event.c b/testcode/fake_event.c
index efb22a6fb634..2140b212adc3 100644
--- a/testcode/fake_event.c
+++ b/testcode/fake_event.c
@@ -2,24 +2,24 @@
* 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
@@ -65,6 +65,7 @@
#include "sldns/wire2str.h"
#include "sldns/str2wire.h"
#include "daemon/remote.h"
+#include "util/timeval_func.h"
#include <signal.h>
struct worker;
struct daemon_remote;
@@ -95,21 +96,7 @@ struct fake_commpoint {
/** 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
+void
fake_temp_file(const char* adj, const char* id, char* buf, size_t len)
{
#ifdef USE_WINSOCK
@@ -121,13 +108,13 @@ fake_temp_file(const char* adj, const char* id, char* buf, size_t len)
#endif
}
-void
+void
fake_event_init(struct replay_scenario* scen)
{
saved_scenario = scen;
}
-void
+void
fake_event_cleanup(void)
{
replay_scenario_delete(saved_scenario);
@@ -172,7 +159,7 @@ repevt_string(enum replay_event_type t)
}
/** delete a fake pending */
-static void
+static void
delete_fake_pending(struct fake_pending* pend)
{
if(!pend)
@@ -200,8 +187,8 @@ delete_replay_answer(struct replay_answer* a)
/**
* return: true if pending query matches the now event.
*/
-static int
-pending_matches_current(struct replay_runtime* runtime,
+static int
+pending_matches_current(struct replay_runtime* runtime,
struct entry** entry, struct fake_pending **pend)
{
struct fake_pending* p;
@@ -233,7 +220,7 @@ pending_matches_current(struct replay_runtime* runtime,
* @return: true if a match is found.
*/
static int
-pending_find_match(struct replay_runtime* runtime, struct entry** entry,
+pending_find_match(struct replay_runtime* runtime, struct entry** entry,
struct fake_pending* pend)
{
int timenow = runtime->now->time_step;
@@ -245,7 +232,7 @@ pending_find_match(struct replay_runtime* runtime, struct entry** entry,
(*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,
+ "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);
@@ -266,8 +253,8 @@ pending_find_match(struct replay_runtime* runtime, struct entry** entry,
* @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,
+static int
+pending_matches_range(struct replay_runtime* runtime,
struct entry** entry, struct fake_pending** pend)
{
struct fake_pending* p = runtime->pending_list;
@@ -405,9 +392,9 @@ answer_callback_from_entry(struct replay_runtime* runtime,
static void
answer_check_it(struct replay_runtime* runtime)
{
- struct replay_answer* ans = runtime->answer_list,
+ struct replay_answer* ans = runtime->answer_list,
*prev = NULL;
- log_assert(runtime && runtime->now &&
+ log_assert(runtime && runtime->now &&
runtime->now->evt_type == repevt_front_reply);
while(ans) {
enum transport_type tr = transport_tcp;
@@ -420,7 +407,7 @@ answer_check_it(struct replay_runtime* runtime)
ans->pkt_len, tr)) {
log_info("testbound matched event entry from line %d",
runtime->now->match->lineno);
- log_info("testbound: do STEP %d %s",
+ log_info("testbound: do STEP %d %s",
runtime->now->time_step,
repevt_string(runtime->now->evt_type));
if(prev)
@@ -474,7 +461,7 @@ fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo)
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,
+ if((*runtime->callback_query)(repinfo.c, runtime->cb_arg,
NETEVENT_NOERROR, &repinfo)) {
/* send immediate reply */
comm_point_send_reply(&repinfo);
@@ -487,7 +474,7 @@ fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo)
* Perform callback for fake pending message.
*/
static void
-fake_pending_callback(struct replay_runtime* runtime,
+fake_pending_callback(struct replay_runtime* runtime,
struct replay_moment* todo, int error)
{
struct fake_pending* p = runtime->pending_list;
@@ -566,7 +553,7 @@ time_passes(struct replay_runtime* runtime, struct replay_moment* mom)
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",
+ 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
@@ -603,7 +590,7 @@ autotrust_check(struct replay_runtime* runtime, struct replay_moment* mom)
}
strip_end_white(line);
expanded = macro_process(runtime->vars, runtime, p->str);
- if(!expanded)
+ 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);
@@ -656,7 +643,7 @@ tempfile_check(struct replay_runtime* runtime, struct replay_moment* mom)
}
strip_end_white(line);
expanded = macro_process(runtime->vars, runtime, p->str);
- if(!expanded)
+ 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);
@@ -746,7 +733,7 @@ do_moment_and_advance(struct replay_runtime* runtime)
advance_moment(runtime);
return;
}
- log_info("testbound: do STEP %d %s", runtime->now->time_step,
+ 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:
@@ -761,7 +748,7 @@ do_moment_and_advance(struct replay_runtime* runtime)
fake_front_query(runtime, mom);
break;
case repevt_front_reply:
- if(runtime->answer_list)
+ if(runtime->answer_list)
log_err("testbound: There are unmatched answers.");
fatal_exit("testbound: query answer not matched");
break;
@@ -810,7 +797,7 @@ do_moment_and_advance(struct replay_runtime* runtime)
advance_moment(runtime);
break;
default:
- fatal_exit("testbound: unknown event type %d",
+ fatal_exit("testbound: unknown event type %d",
runtime->now->evt_type);
}
}
@@ -831,15 +818,15 @@ run_scenario(struct replay_runtime* runtime)
/* 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",
+ 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,
+ answer_callback_from_entry(runtime, entry,
pending);
- } else if(runtime->answer_list && runtime->now &&
+ } else if(runtime->answer_list && runtime->now &&
runtime->now->evt_type == repevt_front_reply) {
- answer_check_it(runtime);
+ answer_check_it(runtime);
advance_moment(runtime);
} else if(pending_matches_range(runtime, &entry, &pending)) {
answer_callback_from_entry(runtime, entry, pending);
@@ -870,7 +857,7 @@ run_scenario(struct replay_runtime* runtime)
/*********** Dummy routines ***********/
-struct listen_dnsport*
+struct listen_dnsport*
listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports),
size_t bufsize, int ATTR_UNUSED(tcp_accept_count),
int ATTR_UNUSED(tcp_idle_timeout),
@@ -898,7 +885,7 @@ listen_create(struct comm_base* base, struct listen_port* ATTR_UNUSED(ports),
return l;
}
-void
+void
listen_delete(struct listen_dnsport* listen)
{
if(!listen)
@@ -907,7 +894,7 @@ listen_delete(struct listen_dnsport* listen)
free(listen);
}
-struct comm_base*
+struct comm_base*
comm_base_create(int ATTR_UNUSED(sigs))
{
/* we return the runtime structure instead. */
@@ -921,7 +908,7 @@ comm_base_create(int ATTR_UNUSED(sigs))
return (struct comm_base*)runtime;
}
-void
+void
comm_base_delete(struct comm_base* b)
{
struct replay_runtime* runtime = (struct replay_runtime*)b;
@@ -961,7 +948,7 @@ comm_base_timept(struct comm_base* b, time_t** tt, struct timeval** tv)
*tv = &runtime->now_tv;
}
-void
+void
comm_base_dispatch(struct comm_base* b)
{
struct replay_runtime* runtime = (struct replay_runtime*)b;
@@ -971,7 +958,7 @@ comm_base_dispatch(struct comm_base* b)
else exit(0); /* OK exit when LIBEVENT_SIGNAL_PROBLEM exists */
}
-void
+void
comm_base_exit(struct comm_base* b)
{
struct replay_runtime* runtime = (struct replay_runtime*)b;
@@ -981,7 +968,7 @@ comm_base_exit(struct comm_base* b)
}
}
-struct comm_signal*
+struct comm_signal*
comm_signal_create(struct comm_base* base,
void (*callback)(int, void*), void* cb_arg)
{
@@ -991,20 +978,20 @@ comm_signal_create(struct comm_base* base,
return calloc(1, sizeof(struct comm_signal));
}
-int
-comm_signal_bind(struct comm_signal* ATTR_UNUSED(comsig), int
+int
+comm_signal_bind(struct comm_signal* ATTR_UNUSED(comsig), int
ATTR_UNUSED(sig))
{
return 1;
}
-void
+void
comm_signal_delete(struct comm_signal* comsig)
{
free(comsig);
}
-void
+void
comm_point_send_reply(struct comm_reply* repinfo)
{
struct replay_answer* ans = (struct replay_answer*)calloc(1,
@@ -1028,7 +1015,7 @@ comm_point_send_reply(struct comm_reply* repinfo)
log_pkt("reply pkt: ", ans->pkt, ans->pkt_len);
}
-void
+void
comm_point_drop_reply(struct comm_reply* repinfo)
{
log_info("comm_point_drop_reply fake");
@@ -1038,14 +1025,14 @@ comm_point_drop_reply(struct comm_reply* repinfo)
}
}
-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 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),
int ATTR_UNUSED(dscp),
struct infra_cache* infra,
- struct ub_randstate* ATTR_UNUSED(rnd),
+ 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),
@@ -1057,7 +1044,7 @@ outside_network_create(struct comm_base* base, size_t bufsize,
int ATTR_UNUSED(tcp_auth_query_timeout))
{
struct replay_runtime* runtime = (struct replay_runtime*)base;
- struct outside_network* outnet = calloc(1,
+ struct outside_network* outnet = calloc(1,
sizeof(struct outside_network));
(void)unwanted_action;
if(!outnet)
@@ -1072,7 +1059,7 @@ outside_network_create(struct comm_base* base, size_t bufsize,
return outnet;
}
-void
+void
outside_network_delete(struct outside_network* outnet)
{
if(!outnet)
@@ -1081,12 +1068,12 @@ outside_network_delete(struct outside_network* outnet)
free(outnet);
}
-void
+void
outside_network_quit_prepare(struct outside_network* ATTR_UNUSED(outnet))
{
}
-struct pending*
+struct pending*
pending_udp_query(struct serviced_query* sq, sldns_buffer* packet,
int timeout, comm_point_callback_type* callback, void* callback_arg)
{
@@ -1128,7 +1115,7 @@ pending_udp_query(struct serviced_query* sq, sldns_buffer* packet,
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;
@@ -1178,7 +1165,7 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
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;
@@ -1202,10 +1189,10 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
sizeof(struct fake_pending));
char z[256];
log_assert(pend);
- log_nametypeclass(VERB_OPS, "pending serviced query",
+ 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",
+ 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":"");
@@ -1265,6 +1252,8 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
if(dnssec)
edns.bits = EDNS_DO;
edns.padding_block_size = 0;
+ edns.cookie_present = 0;
+ edns.cookie_valid = 0;
edns.opt_list_in = NULL;
edns.opt_list_out = per_upstream_opt_list;
edns.opt_list_inplace_cb_out = NULL;
@@ -1301,7 +1290,7 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
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;
@@ -1356,7 +1345,7 @@ void listening_ports_free(struct listen_port* 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),
+ comm_point_callback_type* ATTR_UNUSED(callback),
void* ATTR_UNUSED(callback_arg))
{
struct fake_commpoint* fc = (struct fake_commpoint*)calloc(1,
@@ -1368,7 +1357,7 @@ struct comm_point* comm_point_create_local(struct comm_base* ATTR_UNUSED(base),
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),
+ comm_point_callback_type* ATTR_UNUSED(callback),
void* ATTR_UNUSED(callback_arg))
{
/* no pipe comm possible */
@@ -1379,7 +1368,7 @@ struct comm_point* comm_point_create_raw(struct comm_base* ATTR_UNUSED(base),
return (struct comm_point*)fc;
}
-void comm_point_start_listening(struct comm_point* ATTR_UNUSED(c),
+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 */
@@ -1424,7 +1413,7 @@ size_t serviced_get_mem(struct serviced_query* ATTR_UNUSED(c))
}
/* fake for fptr wlist */
-int outnet_udp_cb(struct comm_point* ATTR_UNUSED(c),
+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))
{
@@ -1432,7 +1421,7 @@ int outnet_udp_cb(struct comm_point* ATTR_UNUSED(c),
return 0;
}
-int outnet_tcp_cb(struct comm_point* ATTR_UNUSED(c),
+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))
{
@@ -1460,67 +1449,67 @@ void outnet_tcptimer(void* ATTR_UNUSED(arg))
log_assert(0);
}
-void comm_point_udp_callback(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
+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),
+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),
+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),
+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),
+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),
+void comm_signal_callback(int ATTR_UNUSED(fd),
short ATTR_UNUSED(event), void* ATTR_UNUSED(arg))
{
log_assert(0);
}
-void comm_point_http_handle_callback(int ATTR_UNUSED(fd),
+void comm_point_http_handle_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),
+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),
+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),
+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),
+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))
{
@@ -1528,7 +1517,7 @@ int serviced_udp_callback(struct comm_point* ATTR_UNUSED(c),
return 0;
}
-int serviced_tcp_callback(struct comm_point* ATTR_UNUSED(c),
+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))
{
@@ -1561,7 +1550,7 @@ int reuse_id_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
}
/* timers in testbound for autotrust. statistics tested in tdir. */
-struct comm_timer* comm_timer_create(struct comm_base* base,
+struct comm_timer* comm_timer_create(struct comm_base* base,
void (*cb)(void*), void* cb_arg)
{
struct replay_runtime* runtime = (struct replay_runtime*)base;
@@ -1589,7 +1578,7 @@ 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",
+ 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);
}
diff --git a/testcode/lock_verify.c b/testcode/lock_verify.c
index b0cffe292ae1..0958ff0ba38e 100644
--- a/testcode/lock_verify.c
+++ b/testcode/lock_verify.c
@@ -177,6 +177,8 @@ static int readup_str(char** str, FILE* in)
}
buf[len] = 0;
*str = strdup(buf);
+ if(!*str)
+ fatal_exit("strdup failed: out of memory");
return 1;
}
diff --git a/testcode/perf.c b/testcode/perf.c
index 7fb524e22d94..2be86c4bf597 100644
--- a/testcode/perf.c
+++ b/testcode/perf.c
@@ -458,9 +458,17 @@ qlist_parse_line(sldns_buffer* buf, char* p)
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);
+ if((qinfo.qtype == 0 && strcmp(cl, "TYPE0") != 0) ||
+ (qinfo.qclass == 0 && strcmp(tp, "CLASS0") != 0)) {
+ return 0;
+ }
} else {
qinfo.qtype = sldns_get_rr_type_by_name(tp);
qinfo.qclass = sldns_get_rr_class_by_name(cl);
+ if((qinfo.qtype == 0 && strcmp(tp, "TYPE0") != 0) ||
+ (qinfo.qclass == 0 && strcmp(cl, "CLASS0") != 0)) {
+ return 0;
+ }
}
if(fl[0] == '+') rec = 1;
else if(fl[0] == '-') rec = 0;
diff --git a/testcode/replay.c b/testcode/replay.c
index 43101d6acec6..f896a5512c5d 100644
--- a/testcode/replay.c
+++ b/testcode/replay.c
@@ -2,24 +2,24 @@
* 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
@@ -51,6 +51,7 @@
#include "testcode/testpkts.h"
#include "testcode/fake_event.h"
#include "sldns/str2wire.h"
+#include "util/timeval_func.h"
/** max length of lines in file */
#define MAX_LINE_LEN 10240
@@ -59,35 +60,19 @@
* 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
+ * @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,
+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.
+/** 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.
+ * @return: true if found, false if not.
*/
-static int
+static int
parse_keyword(char** line, const char* keyword)
{
size_t len = (size_t)strlen(keyword);
@@ -135,8 +120,8 @@ strip_end_white(char* p)
}
}
-/**
- * Read a range from file.
+/**
+ * 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.
@@ -181,7 +166,7 @@ replay_range_read(char* remain, FILE* in, const char* name,
strip_end_white(parse);
if(!extstrtoaddr(parse, &rng->addr, &rng->addrlen,
UNBOUND_DNS_PORT)) {
- log_err("Line %d: could not read ADDRESS: %s",
+ log_err("Line %d: could not read ADDRESS: %s",
pstate->lineno, parse);
free(rng);
return NULL;
@@ -255,8 +240,8 @@ read_assign_step(char* remain, struct replay_moment* mom)
fatal_exit("out of memory");
}
-/**
- * Read a replay moment 'STEP' from file.
+/**
+ * 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.
@@ -376,18 +361,18 @@ replay_moment_read(char* remain, FILE* in, const char* name,
strip_end_white(remain);
if(!extstrtoaddr(remain, &mom->addr, &mom->addrlen,
UNBOUND_DNS_PORT)) {
- log_err("line %d: could not parse ADDRESS: %s",
+ 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)",
+ log_err("line %d: could not parse ELAPSE: %s (%s)",
pstate->lineno, remain, strerror(errno));
free(mom);
return NULL;
@@ -397,7 +382,7 @@ replay_moment_read(char* remain, FILE* in, const char* name,
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);
@@ -433,7 +418,7 @@ make_scenario(char* line)
return scen;
}
-struct replay_scenario*
+struct replay_scenario*
replay_scenario_read(FILE* in, const char* name, int* lineno)
{
char line[MAX_LINE_LEN];
@@ -451,7 +436,7 @@ replay_scenario_read(FILE* in, const char* name, int* lineno)
(*lineno)++;
while(isspace((unsigned char)*parse))
parse++;
- if(!*parse)
+ if(!*parse)
continue; /* empty line */
if(parse_keyword(&parse, ";"))
continue; /* comment */
@@ -462,11 +447,11 @@ replay_scenario_read(FILE* in, const char* name, int* lineno)
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,
+ struct replay_range* newr = replay_range_read(parse,
in, name, &pstate, line);
if(!newr)
fatal_exit("%d: bad range", pstate.lineno);
@@ -474,12 +459,12 @@ replay_scenario_read(FILE* in, const char* name, int* 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,
+ 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 &&
+ if(scen->mom_last &&
scen->mom_last->time_step >= mom->time_step)
fatal_exit("%d: time goes backwards", *lineno);
if(scen->mom_last)
@@ -502,7 +487,7 @@ replay_scenario_read(FILE* in, const char* name, int* lineno)
return NULL;
}
-void
+void
replay_scenario_delete(struct replay_scenario* scen)
{
struct replay_moment* mom, *momn;
@@ -630,7 +615,7 @@ do_macro_recursion(rbtree_type* store, struct replay_runtime* runtime,
{
char* after = at+2;
char* expand = macro_expand(store, runtime, &after);
- if(!expand)
+ if(!expand)
return NULL; /* expansion failed */
if(!do_buf_insert(at, remain, after, expand)) {
free(expand);
@@ -665,7 +650,7 @@ do_macro_variable(rbtree_type* store, char* buf, size_t remain)
}
/* terminator, we are working in macro_expand() buffer */
sv = *at;
- *at = 0;
+ *at = 0;
v = macro_getvar(store, name);
*at = sv;
@@ -816,7 +801,7 @@ macro_expand(rbtree_type* store, struct replay_runtime* runtime, char** text)
time_t res = 0;
if(runtime) {
struct fake_timer* t = first_timer(runtime);
- if(t && (time_t)t->tv.tv_sec >= runtime->now_secs)
+ 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);
@@ -855,9 +840,9 @@ macro_expand(rbtree_type* store, struct replay_runtime* runtime, char** text)
if(dofunc) {
/* post process functions, buf has the argument(s) */
if(strncmp(buf, "ctime", 5) == 0) {
- return do_macro_ctime(buf+6);
+ return do_macro_ctime(buf+6);
} else if(strncmp(buf, "range", 5) == 0) {
- return do_macro_range(buf+6);
+ return do_macro_range(buf+6);
}
}
return strdup(buf);
@@ -891,7 +876,7 @@ macro_process(rbtree_type* store, struct replay_runtime* runtime, char* text)
return strdup(buf);
}
-char*
+char*
macro_lookup(rbtree_type* store, char* name)
{
struct replay_var* x = macro_getvar(store, name);
@@ -907,7 +892,7 @@ void macro_print_debug(rbtree_type* store)
}
}
-int
+int
macro_assign(rbtree_type* store, char* name, char* value)
{
struct replay_var* x = macro_getvar(store, name);
diff --git a/testcode/streamtcp.c b/testcode/streamtcp.c
index b2c0d5328bb7..84d2b65f6f5c 100644
--- a/testcode/streamtcp.c
+++ b/testcode/streamtcp.c
@@ -132,7 +132,15 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
/* qtype and qclass */
qinfo.qtype = sldns_get_rr_type_by_name(strtype);
+ if(qinfo.qtype == 0 && strcmp(strtype, "TYPE0") != 0) {
+ printf("cannot parse query type: '%s'\n", strtype);
+ exit(1);
+ }
qinfo.qclass = sldns_get_rr_class_by_name(strclass);
+ if(qinfo.qclass == 0 && strcmp(strclass, "CLASS0") != 0) {
+ printf("cannot parse query class: '%s'\n", strclass);
+ exit(1);
+ }
/* clear local alias */
qinfo.local_alias = NULL;
@@ -371,15 +379,19 @@ static void
send_em(const char* svr, const char* pp2_client, int udp, int usessl,
int noanswer, int onarrival, int delay, int num, char** qs)
{
- sldns_buffer* buf = sldns_buffer_new(65553);
- sldns_buffer* proxy_buf = sldns_buffer_new(65553);
struct sockaddr_storage svr_addr;
socklen_t svr_addrlen;
int fd = open_svr(svr, udp, &svr_addr, &svr_addrlen);
int i, wait_results = 0, pp2_parsed;
SSL_CTX* ctx = NULL;
SSL* ssl = NULL;
- if(!buf) fatal_exit("out of memory");
+ sldns_buffer* buf = sldns_buffer_new(65553);
+ sldns_buffer* proxy_buf = sldns_buffer_new(65553);
+ if(!buf || !proxy_buf) {
+ sldns_buffer_free(buf);
+ sldns_buffer_free(proxy_buf);
+ fatal_exit("out of memory");
+ }
pp2_parsed = parse_pp2_client(pp2_client, udp, proxy_buf);
if(usessl) {
ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
diff --git a/testcode/testpkts.c b/testcode/testpkts.c
index 3702c3f18403..aa852f01ee47 100644
--- a/testcode/testpkts.c
+++ b/testcode/testpkts.c
@@ -21,7 +21,6 @@
*/
#include "config.h"
-struct sockaddr_storage;
#include <errno.h>
#include <stdarg.h>
#include <ctype.h>
@@ -140,6 +139,10 @@ static void matchline(char* line, struct entry* e)
e->match_noedns = 1;
} else if(str_keyword(&parse, "ednsdata")) {
e->match_ednsdata_raw = 1;
+ } else if(str_keyword(&parse, "client_cookie")) {
+ e->match_client_cookie = 1;
+ } else if(str_keyword(&parse, "server_cookie")) {
+ e->match_server_cookie = 1;
} else if(str_keyword(&parse, "UDP")) {
e->match_transport = transport_udp;
} else if(str_keyword(&parse, "TCP")) {
@@ -905,37 +908,64 @@ get_do_flag(uint8_t* pkt, size_t len)
return (int)(edns_bits&LDNS_EDNS_MASK_DO_BIT);
}
-/** Snips the EDE option out of the OPT record and returns the EDNS EDE
- * INFO-CODE if found, else -1 */
+/** Snips the specified EDNS option out of the OPT record and puts it in the
+ * provided buffer. The buffer should be able to hold any opt data ie 65535.
+ * Returns the length of the option written,
+ * or 0 if not found, else -1 on error. */
static int
-extract_ede(uint8_t* pkt, size_t len)
+pkt_snip_edns_option(uint8_t* pkt, size_t len, sldns_edns_option code,
+ uint8_t* buf)
{
uint8_t *rdata, *opt_position = pkt;
uint16_t rdlen, optlen;
size_t remaining = len;
- int ede_code;
- if(!pkt_find_edns_opt(&opt_position, &remaining)) return -1;
+ if(!pkt_find_edns_opt(&opt_position, &remaining)) return 0;
if(remaining < 8) return -1; /* malformed */
rdlen = sldns_read_uint16(opt_position+6);
rdata = opt_position + 8;
while(rdlen > 0) {
if(rdlen < 4) return -1; /* malformed */
optlen = sldns_read_uint16(rdata+2);
- if(sldns_read_uint16(rdata) == LDNS_EDNS_EDE) {
- if(rdlen < 6) return -1; /* malformed */
- ede_code = sldns_read_uint16(rdata+4);
+ if(sldns_read_uint16(rdata) == code) {
+ /* save data to buf for caller inspection */
+ memmove(buf, rdata+4, optlen);
/* snip option from packet; assumes len is correct */
memmove(rdata, rdata+4+optlen,
(pkt+len)-(rdata+4+optlen));
/* update OPT size */
sldns_write_uint16(opt_position+6,
sldns_read_uint16(opt_position+6)-(4+optlen));
- return ede_code;
+ return optlen;
}
rdlen -= 4 + optlen;
rdata += 4 + optlen;
}
- return -1;
+ return 0;
+}
+
+/** Snips the EDE option out of the OPT record and returns the EDNS EDE
+ * INFO-CODE if found, else -1 */
+static int
+extract_ede(uint8_t* pkt, size_t len)
+{
+ uint8_t buf[65535];
+ int buflen = pkt_snip_edns_option(pkt, len, LDNS_EDNS_EDE, buf);
+ if(buflen < 2 /*ede without text at minimum*/) return -1;
+ return sldns_read_uint16(buf);
+}
+
+/** Snips the DNS Cookie option out of the OPT record and puts it in the
+ * provided cookie buffer (should be at least 24 octets).
+ * Returns the length of the cookie if found, else -1. */
+static int
+extract_cookie(uint8_t* pkt, size_t len, uint8_t* cookie)
+{
+ uint8_t buf[65535];
+ int buflen = pkt_snip_edns_option(pkt, len, LDNS_EDNS_COOKIE, buf);
+ if(buflen != 8 /*client cookie*/ &&
+ buflen != 8 + 16 /*server cookie*/) return -1;
+ memcpy(cookie, buf, buflen);
+ return buflen;
}
/** zero TTLs in packet */
@@ -1530,6 +1560,27 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
continue;
}
}
+ /* Cookies could also modify the query_pkt; keep them early */
+ if(p->match_client_cookie || p->match_server_cookie) {
+ uint8_t cookie[24];
+ int cookie_len = extract_cookie(query_pkt, len,
+ cookie);
+ if(cookie_len == -1) {
+ verbose(3, "bad DNS Cookie. "
+ "Expected but not found\n");
+ continue;
+ } else if(p->match_client_cookie &&
+ cookie_len != 8) {
+ verbose(3, "bad DNS Cookie. Expected client "
+ "cookie of length 8.");
+ continue;
+ } else if((p->match_server_cookie) &&
+ cookie_len != 24) {
+ verbose(3, "bad DNS Cookie. Expected server "
+ "cookie of length 24.");
+ continue;
+ }
+ }
if(p->match_opcode && get_opcode(query_pkt, len) !=
get_opcode(reply, rlen)) {
verbose(3, "bad opcode\n");
diff --git a/testcode/testpkts.h b/testcode/testpkts.h
index 2768040c68cb..c6a3725f368e 100644
--- a/testcode/testpkts.h
+++ b/testcode/testpkts.h
@@ -64,6 +64,14 @@ struct sldns_file_parse_state;
; 'ede=any' makes the query match any EDNS EDE info-code.
; It also snips the EDE record out of the packet to facilitate
; other matches.
+ ; 'client_cookie' makes the query match any DNS Cookie option with
+ ; with a length of 8 octets.
+ ; It also snips the DNS Cookie record out of the packet to
+ ; facilitate other matches.
+ ; 'server_cookie' makes the query match any DNS Cookie option with
+ ; with a length of 24 octets.
+ ; It also snips the DNS Cookie record out of the packet to
+ ; facilitate other matches.
MATCH [opcode] [qtype] [qname] [serial=<value>] [all] [ttl]
MATCH [UDP|TCP] DO
MATCH ...
@@ -104,11 +112,11 @@ struct sldns_file_parse_state;
; 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.
+ HEX_EDNSDATA_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
+ HEX_EDNSDATA_END
ENTRY_END
@@ -214,6 +222,10 @@ struct entry {
uint8_t match_noedns;
/** match edns data field given in hex */
uint8_t match_ednsdata_raw;
+ /** match an DNS cookie of length 8 */
+ uint8_t match_client_cookie;
+ /** match an DNS cookie of length 24 */
+ uint8_t match_server_cookie;
/** match query serial with this value. */
uint32_t ixfr_soa_serial;
/** match on UDP/TCP */
@@ -235,7 +247,7 @@ struct entry {
/** increment the ECS scope copied from the sourcemask by one */
uint8_t increment_ecs_scope;
/** in seconds */
- unsigned int sleeptime;
+ unsigned int sleeptime;
/** some number that names this entry, line number in file or so */
int lineno;
diff --git a/testcode/unitlruhash.c b/testcode/unitlruhash.c
index e196f0b63211..3c66d7583ed6 100644
--- a/testcode/unitlruhash.c
+++ b/testcode/unitlruhash.c
@@ -94,7 +94,7 @@ test_bin_find_entry(struct lruhash* table)
bin_overflow_remove(&bin, &k->entry);
/* find in empty list */
- unit_assert( bin_find_entry(table, &bin, h, k) == NULL );
+ unit_assert( bin_find_entry(table, &bin, h, k, NULL) == NULL );
/* insert */
lock_quick_lock(&bin.lock);
@@ -102,20 +102,20 @@ test_bin_find_entry(struct lruhash* table)
lock_quick_unlock(&bin.lock);
/* find, hash not OK. */
- unit_assert( bin_find_entry(table, &bin, myhash(13), k) == NULL );
+ unit_assert( bin_find_entry(table, &bin, myhash(13), k, NULL) == 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 );
+ unit_assert( bin_find_entry(table, &bin, h, k2, NULL) == NULL );
/* find, hash OK, and cmp too */
- unit_assert( bin_find_entry(table, &bin, h, k) == &k->entry );
+ unit_assert( bin_find_entry(table, &bin, h, k, NULL) == &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 );
+ unit_assert( bin_find_entry(table, &bin, h, k, NULL) == NULL );
/* prepend two different elements; so the list is long */
/* one has the same hash, but different cmp */
@@ -127,28 +127,28 @@ test_bin_find_entry(struct lruhash* table)
lock_quick_unlock(&bin.lock);
/* find, hash not OK. */
- unit_assert( bin_find_entry(table, &bin, myhash(13), k) == NULL );
+ unit_assert( bin_find_entry(table, &bin, myhash(13), k, NULL) == 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 );
+ unit_assert( bin_find_entry(table, &bin, h, k2, NULL) == NULL );
/* find, hash OK, and cmp too */
- unit_assert( bin_find_entry(table, &bin, h, k) == &k->entry );
+ unit_assert( bin_find_entry(table, &bin, h, k, NULL) == &k->entry );
/* remove middle element */
- unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4)
+ unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4, NULL)
== &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);
+ unit_assert( bin_find_entry(table, &bin, k4->entry.hash, k4, NULL) == 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 );
+ unit_assert( bin_find_entry(table, &bin, h, k, NULL) == NULL );
lock_quick_destroy(&bin.lock);
delkey(k);
diff --git a/testcode/unitmain.c b/testcode/unitmain.c
index b6dac5507faf..647cbca3b05b 100644
--- a/testcode/unitmain.c
+++ b/testcode/unitmain.c
@@ -530,6 +530,207 @@ infra_test(void)
config_delete(cfg);
}
+#include "util/edns.h"
+/* Complete version-invalid client cookie; needs a new one.
+ * Based on edns_cookie_rfc9018_a2 */
+static void
+edns_cookie_invalid_version(void)
+{
+ uint32_t timestamp = 1559734385;
+ uint8_t client_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
+ 0x99, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0x9f, 0x11,
+ 0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
+ uint8_t server_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0xa8, 0x71,
+ 0xd4, 0xa5, 0x64, 0xa1, 0x44, 0x2a, 0xca, 0x77 };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, client_cookie, 8 + 4 + 4);
+ /* copy ip 198.51.100.100 */
+ memcpy(buf + 16, "\306\063\144\144", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
+ buf, timestamp) == COOKIE_STATUS_INVALID);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/* Complete hash-invalid client cookie; needs a new one. */
+static void
+edns_cookie_invalid_hash(void)
+{
+ uint32_t timestamp = 0;
+ uint8_t client_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0xF2, 0x43, 0xB9, 0xBC, 0xFE, 0xC4, 0x06 };
+ uint8_t server_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00,
+ 0xBA, 0x0D, 0x82, 0x90, 0x8F, 0xAA, 0xEB, 0xBD };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, client_cookie, 8 + 4 + 4);
+ /* copy ip 203.0.113.203 */
+ memcpy(buf + 16, "\313\000\161\313", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
+ buf, timestamp) == COOKIE_STATUS_INVALID);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/* Complete hash-valid client cookie; more than 30 minutes old; needs a
+ * refreshed server cookie.
+ * A slightly better variation of edns_cookie_rfc9018_a3 for Unbound to check
+ * that RESERVED bits do not influence cookie validation. */
+static void
+edns_cookie_rfc9018_a3_better(void)
+{
+ uint32_t timestamp = 1800 + 1;
+ uint8_t client_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0xab, 0xcd, 0xef,
+ 0x00, 0x00, 0x00, 0x00,
+ 0x32, 0xF2, 0x43, 0xB9, 0xBC, 0xFE, 0xC4, 0x06 };
+ uint8_t server_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x07, 0x09,
+ 0x62, 0xD5, 0x93, 0x09, 0x14, 0x5C, 0x23, 0x9D };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, client_cookie, 8 + 4 + 4);
+ /* copy ip 203.0.113.203 */
+ memcpy(buf + 16, "\313\000\161\313", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
+ buf, timestamp) == COOKIE_STATUS_VALID_RENEW);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/* Complete hash-valid client cookie; more than 60 minutes old (expired);
+ * needs a refreshed server cookie. */
+static void
+edns_cookie_rfc9018_a3(void)
+{
+ uint32_t timestamp = 1559734700;
+ uint8_t client_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0xab, 0xcd, 0xef,
+ 0x5c, 0xf7, 0x8f, 0x71,
+ 0xa3, 0x14, 0x22, 0x7b, 0x66, 0x79, 0xeb, 0xf5 };
+ uint8_t server_cookie[] = {
+ 0xfc, 0x93, 0xfc, 0x62, 0x80, 0x7d, 0xdb, 0x86,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0xa9, 0xac,
+ 0xf7, 0x3a, 0x78, 0x10, 0xac, 0xa2, 0x38, 0x1e };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, client_cookie, 8 + 4 + 4);
+ /* copy ip 203.0.113.203 */
+ memcpy(buf + 16, "\313\000\161\313", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
+ buf, timestamp) == COOKIE_STATUS_EXPIRED);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/* Complete hash-valid client cookie; more than 30 minutes old; needs a
+ * refreshed server cookie. */
+static void
+edns_cookie_rfc9018_a2(void)
+{
+ uint32_t timestamp = 1559734385;
+ uint8_t client_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0x9f, 0x11,
+ 0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
+ uint8_t server_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0xa8, 0x71,
+ 0xd4, 0xa5, 0x64, 0xa1, 0x44, 0x2a, 0xca, 0x77 };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, client_cookie, 8 + 4 + 4);
+ /* copy ip 198.51.100.100 */
+ memcpy(buf + 16, "\306\063\144\144", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie), server_secret, sizeof(server_secret), 1,
+ buf, timestamp) == COOKIE_STATUS_VALID_RENEW);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/* Only client cookie; needs a complete server cookie. */
+static void
+edns_cookie_rfc9018_a1(void)
+{
+ uint32_t timestamp = 1559731985;
+ uint8_t client_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57 };
+ uint8_t server_cookie[] = {
+ 0x24, 0x64, 0xc4, 0xab, 0xcf, 0x10, 0xc9, 0x57,
+ 0x01, 0x00, 0x00, 0x00,
+ 0x5c, 0xf7, 0x9f, 0x11,
+ 0x1f, 0x81, 0x30, 0xc3, 0xee, 0xe2, 0x94, 0x80 };
+ uint8_t server_secret[] = {
+ 0xe5, 0xe9, 0x73, 0xe5, 0xa6, 0xb2, 0xa4, 0x3f,
+ 0x48, 0xe7, 0xdc, 0x84, 0x9e, 0x37, 0xbf, 0xcf };
+ uint8_t buf[32];
+ /* copy client cookie|version|reserved|timestamp */
+ memcpy(buf, server_cookie, 8 + 4 + 4);
+ /* copy ip 198.51.100.100 */
+ memcpy(buf + 16, "\306\063\144\144", 4);
+ unit_assert(edns_cookie_server_validate(client_cookie,
+ sizeof(client_cookie),
+ /* these will not be used; it will return invalid
+ * because of the size. */
+ NULL, 0, 1, NULL, 0) == COOKIE_STATUS_CLIENT_ONLY);
+ edns_cookie_server_write(buf, server_secret, 1, timestamp);
+ unit_assert(memcmp(server_cookie, buf, 24) == 0);
+}
+
+/** test interoperable DNS cookies (RFC9018) */
+static void
+edns_cookie_test(void)
+{
+ unit_show_feature("interoperable dns cookies");
+ /* Check RFC9018 appendix test vectors */
+ edns_cookie_rfc9018_a1();
+ edns_cookie_rfc9018_a2();
+ edns_cookie_rfc9018_a3();
+ /* More tests */
+ edns_cookie_rfc9018_a3_better();
+ edns_cookie_invalid_hash();
+ edns_cookie_invalid_version();
+}
+
#include "util/random.h"
/** test randomness */
static void
@@ -839,6 +1040,218 @@ static void respip_test(void)
respip_conf_actions_test();
}
+#include "util/regional.h"
+#include "sldns/sbuffer.h"
+#include "util/data/dname.h"
+#include "util/data/msgreply.h"
+#include "util/data/msgencode.h"
+#include "sldns/str2wire.h"
+
+static void edns_ede_encode_setup(struct edns_data* edns,
+ struct regional* region)
+{
+ memset(edns, 0, sizeof(*edns));
+ edns->edns_present = 1;
+ edns->edns_version = EDNS_ADVERTISED_VERSION;
+ edns->udp_size = EDNS_ADVERTISED_SIZE;
+ edns->bits &= EDNS_DO;
+ /* Fill up opt_list_out with EDEs */
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_BLOCKED, "Too long blocked text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_BLOCKED, "Too long blocked text"));
+ /* Fill up opt_list_inplace_cb_out with EDEs */
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_BLOCKED, "Too long blocked text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_BLOCKED, "Too long blocked text"));
+ /* append another EDNS option to both lists */
+ unit_assert(
+ edns_opt_list_append(&edns->opt_list_out,
+ LDNS_EDNS_UNBOUND_CACHEDB_TESTFRAME_TEST, 0, NULL, region));
+ unit_assert(
+ edns_opt_list_append(&edns->opt_list_inplace_cb_out,
+ LDNS_EDNS_UNBOUND_CACHEDB_TESTFRAME_TEST, 0, NULL, region));
+ /* append LDNS_EDE_OTHER at the end of both lists */
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+ unit_assert(
+ edns_opt_list_append_ede(&edns->opt_list_inplace_cb_out, region,
+ LDNS_EDE_OTHER, "Too long other text"));
+}
+
+static void edns_ede_encode_encodedecode(struct query_info* qinfo,
+ struct reply_info* rep, struct regional* region,
+ struct edns_data* edns, sldns_buffer* pkt)
+{
+ /* encode */
+ unit_assert(
+ reply_info_answer_encode(qinfo, rep, 1, rep->flags, pkt,
+ 0, 0, region, 65535, edns, 0, 0));
+ /* buffer ready for reading; skip after the question section */
+ sldns_buffer_skip(pkt, LDNS_HEADER_SIZE);
+ (void)query_dname_len(pkt);
+ sldns_buffer_skip(pkt, 2 + 2);
+ /* decode */
+ unit_assert(parse_edns_from_query_pkt(pkt, edns, NULL, NULL, NULL, 0,
+ region) == 0);
+}
+
+static void edns_ede_encode_check(struct edns_data* edns, int* found_ede,
+ int* found_ede_other, int* found_ede_txt, int* found_other_edns)
+{
+ struct edns_option* opt;
+ for(opt = edns->opt_list_in; opt; opt = opt->next) {
+ if(opt->opt_code == LDNS_EDNS_EDE) {
+ (*found_ede)++;
+ if(opt->opt_len > 2)
+ (*found_ede_txt)++;
+ if(opt->opt_len >= 2 && sldns_read_uint16(
+ opt->opt_data) == LDNS_EDE_OTHER)
+ (*found_ede_other)++;
+ } else {
+ (*found_other_edns)++;
+ }
+ }
+
+}
+
+static void edns_ede_encode_fit_test(struct query_info* qinfo,
+ struct reply_info* rep, struct regional* region)
+{
+ struct edns_data edns;
+ int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
+ int found_other_edns = 0;
+ sldns_buffer* pkt = sldns_buffer_new(65535);
+ unit_assert(pkt);
+ edns_ede_encode_setup(&edns, region);
+ /* leave the pkt buffer as is; everything should fit */
+ edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt);
+ edns_ede_encode_check(&edns, &found_ede, &found_ede_other,
+ &found_ede_txt, &found_other_edns);
+ unit_assert(found_ede == 12);
+ unit_assert(found_ede_other == 8);
+ unit_assert(found_ede_txt == 12);
+ unit_assert(found_other_edns == 2);
+ /* cleanup */
+ sldns_buffer_free(pkt);
+}
+
+static void edns_ede_encode_notxt_fit_test( struct query_info* qinfo,
+ struct reply_info* rep, struct regional* region)
+{
+ struct edns_data edns;
+ sldns_buffer* pkt;
+ uint16_t edns_field_size, ede_txt_size;
+ int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
+ int found_other_edns = 0;
+ edns_ede_encode_setup(&edns, region);
+ /* pkt buffer should fit everything if the ede txt is cropped.
+ * OTHER EDE should not be there since it is useless without text. */
+ edns_field_size = calc_edns_field_size(&edns);
+ (void)calc_ede_option_size(&edns, &ede_txt_size);
+ pkt = sldns_buffer_new(LDNS_HEADER_SIZE
+ + qinfo->qname_len
+ + 2 + 2 /* qtype + qclass */
+ + 11 /* opt record */
+ + edns_field_size
+ - ede_txt_size);
+ unit_assert(pkt);
+ edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt);
+ edns_ede_encode_check(&edns, &found_ede, &found_ede_other,
+ &found_ede_txt, &found_other_edns);
+ unit_assert(found_ede == 4);
+ unit_assert(found_ede_other == 0);
+ unit_assert(found_ede_txt == 0);
+ unit_assert(found_other_edns == 2);
+ /* cleanup */
+ sldns_buffer_free(pkt);
+}
+
+static void edns_ede_encode_no_fit_test( struct query_info* qinfo,
+ struct reply_info* rep, struct regional* region)
+{
+ struct edns_data edns;
+ sldns_buffer* pkt;
+ uint16_t edns_field_size, ede_size, ede_txt_size;
+ int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
+ int found_other_edns = 0;
+ edns_ede_encode_setup(&edns, region);
+ /* pkt buffer should fit only non-EDE options. */
+ edns_field_size = calc_edns_field_size(&edns);
+ ede_size = calc_ede_option_size(&edns, &ede_txt_size);
+ pkt = sldns_buffer_new(LDNS_HEADER_SIZE
+ + qinfo->qname_len
+ + 2 + 2 /* qtype + qclass */
+ + 11 /* opt record */
+ + edns_field_size
+ - ede_size);
+ unit_assert(pkt);
+ edns_ede_encode_encodedecode(qinfo, rep, region, &edns, pkt);
+ edns_ede_encode_check(&edns, &found_ede, &found_ede_other,
+ &found_ede_txt, &found_other_edns);
+ unit_assert(found_ede == 0);
+ unit_assert(found_ede_other == 0);
+ unit_assert(found_ede_txt == 0);
+ unit_assert(found_other_edns == 2);
+ /* cleanup */
+ sldns_buffer_free(pkt);
+}
+
+/** test optional EDE encoding with various buffer
+ * available sizes */
+static void edns_ede_answer_encode_test(void)
+{
+ struct regional* region = regional_create();
+ struct reply_info* rep;
+ struct query_info qinfo;
+ unit_show_feature("edns ede optional encoding");
+ unit_assert(region);
+ rep = construct_reply_info_base(region,
+ LDNS_RCODE_NOERROR | BIT_QR, 1,
+ 3600, 3600, 3600,
+ 0, 0, 0, 0,
+ sec_status_unchecked, LDNS_EDE_NONE);
+ unit_assert(rep);
+ memset(&qinfo, 0, sizeof(qinfo));
+ qinfo.qname = sldns_str2wire_dname("encode.ede.", &qinfo.qname_len);
+ unit_assert(qinfo.qname);
+ qinfo.qtype = LDNS_RR_TYPE_TXT;
+ qinfo.qclass = LDNS_RR_CLASS_IN;
+
+ edns_ede_encode_fit_test(&qinfo, rep, region);
+ edns_ede_encode_notxt_fit_test(&qinfo, rep, region);
+ edns_ede_encode_no_fit_test(&qinfo, rep, region);
+
+ /* cleanup */
+ free(qinfo.qname);
+ regional_free_all(region);
+ regional_destroy(region);
+}
+
void unit_show_func(const char* file, const char* func)
{
printf("test %s:%s\n", file, func);
@@ -852,6 +1265,7 @@ void unit_show_feature(const char* 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.
@@ -906,9 +1320,11 @@ main(int argc, char* argv[])
slabhash_test();
infra_test();
ldns_test();
+ edns_cookie_test();
zonemd_test();
tcpreuse_test();
msgparse_test();
+ edns_ede_answer_encode_test();
#ifdef CLIENT_SUBNET
ecs_test();
#endif /* CLIENT_SUBNET */