diff options
author | Cy Schubert <cy@FreeBSD.org> | 2023-09-18 19:59:52 +0000 |
---|---|---|
committer | Cy Schubert <cy@FreeBSD.org> | 2023-09-18 19:59:52 +0000 |
commit | 401770e05c71ecb5ae61a59d316069b4b78bf622 (patch) | |
tree | a66e3d57ff5dde81aaa0fdc4c2d86c8b7a525ae0 /testcode | |
parent | 7699e1386a16236002b26107ffd2dcbde375e197 (diff) | |
download | src-401770e05c71ecb5ae61a59d316069b4b78bf622.tar.gz src-401770e05c71ecb5ae61a59d316069b4b78bf622.zip |
unbound: Vendor import 1.18.0vendor/unbound/1.18.0
Release notes at
https://www.nlnetlabs.nl/news/2023/Aug/30/unbound-1.18.0-released/
Diffstat (limited to 'testcode')
-rw-r--r-- | testcode/dohclient.c | 9 | ||||
-rw-r--r-- | testcode/fake_event.c | 171 | ||||
-rw-r--r-- | testcode/lock_verify.c | 2 | ||||
-rw-r--r-- | testcode/perf.c | 8 | ||||
-rw-r--r-- | testcode/replay.c | 85 | ||||
-rw-r--r-- | testcode/streamtcp.c | 18 | ||||
-rw-r--r-- | testcode/testpkts.c | 73 | ||||
-rw-r--r-- | testcode/testpkts.h | 18 | ||||
-rw-r--r-- | testcode/unitlruhash.c | 22 | ||||
-rw-r--r-- | testcode/unitmain.c | 416 |
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 */ |