xref: /freebsd/contrib/unbound/testcode/unitinfra.c (revision be771a7b7f4580a30d99e41a5bb1b93a385a119d)
1*be771a7bSCy Schubert /*
2*be771a7bSCy Schubert  * testcode/unitinfra.c - unit test for infra cache.
3*be771a7bSCy Schubert  *
4*be771a7bSCy Schubert  * Copyright (c) 2025, NLnet Labs. All rights reserved.
5*be771a7bSCy Schubert  *
6*be771a7bSCy Schubert  * This software is open source.
7*be771a7bSCy Schubert  *
8*be771a7bSCy Schubert  * Redistribution and use in source and binary forms, with or without
9*be771a7bSCy Schubert  * modification, are permitted provided that the following conditions
10*be771a7bSCy Schubert  * are met:
11*be771a7bSCy Schubert  *
12*be771a7bSCy Schubert  * Redistributions of source code must retain the above copyright notice,
13*be771a7bSCy Schubert  * this list of conditions and the following disclaimer.
14*be771a7bSCy Schubert  *
15*be771a7bSCy Schubert  * Redistributions in binary form must reproduce the above copyright notice,
16*be771a7bSCy Schubert  * this list of conditions and the following disclaimer in the documentation
17*be771a7bSCy Schubert  * and/or other materials provided with the distribution.
18*be771a7bSCy Schubert  *
19*be771a7bSCy Schubert  * Neither the name of the NLNET LABS nor the names of its contributors may
20*be771a7bSCy Schubert  * be used to endorse or promote products derived from this software without
21*be771a7bSCy Schubert  * specific prior written permission.
22*be771a7bSCy Schubert  *
23*be771a7bSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24*be771a7bSCy Schubert  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25*be771a7bSCy Schubert  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
26*be771a7bSCy Schubert  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
27*be771a7bSCy Schubert  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
28*be771a7bSCy Schubert  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
29*be771a7bSCy Schubert  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30*be771a7bSCy Schubert  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
31*be771a7bSCy Schubert  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
32*be771a7bSCy Schubert  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33*be771a7bSCy Schubert  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34*be771a7bSCy Schubert  *
35*be771a7bSCy Schubert  */
36*be771a7bSCy Schubert /**
37*be771a7bSCy Schubert  * \file
38*be771a7bSCy Schubert  * Tests the infra functionality.
39*be771a7bSCy Schubert  */
40*be771a7bSCy Schubert 
41*be771a7bSCy Schubert #include "config.h"
42*be771a7bSCy Schubert #include "testcode/unitmain.h"
43*be771a7bSCy Schubert #include "iterator/iterator.h"
44*be771a7bSCy Schubert #include "services/cache/infra.h"
45*be771a7bSCy Schubert #include "util/config_file.h"
46*be771a7bSCy Schubert #include "util/net_help.h"
47*be771a7bSCy Schubert 
48*be771a7bSCy Schubert /* lookup and get key and data structs easily */
49*be771a7bSCy Schubert static struct infra_data* infra_lookup_host(struct infra_cache* infra,
50*be771a7bSCy Schubert 	struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
51*be771a7bSCy Schubert 	size_t zonelen, int wr, time_t now, struct infra_key** k)
52*be771a7bSCy Schubert {
53*be771a7bSCy Schubert 	struct infra_data* d;
54*be771a7bSCy Schubert 	struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
55*be771a7bSCy Schubert 		zone, zonelen, wr);
56*be771a7bSCy Schubert 	if(!e) return NULL;
57*be771a7bSCy Schubert 	d = (struct infra_data*)e->data;
58*be771a7bSCy Schubert 	if(d->ttl < now) {
59*be771a7bSCy Schubert 		lock_rw_unlock(&e->lock);
60*be771a7bSCy Schubert 		return NULL;
61*be771a7bSCy Schubert 	}
62*be771a7bSCy Schubert 	*k = (struct infra_key*)e->key;
63*be771a7bSCy Schubert 	return d;
64*be771a7bSCy Schubert }
65*be771a7bSCy Schubert 
66*be771a7bSCy Schubert static void test_keep_probing(struct infra_cache* slab,
67*be771a7bSCy Schubert 	struct config_file* cfg, struct sockaddr_storage one, socklen_t onelen,
68*be771a7bSCy Schubert 	uint8_t* zone, size_t zonelen, time_t *now, int keep_probing,
69*be771a7bSCy Schubert 	int rtt_max_timeout)
70*be771a7bSCy Schubert {
71*be771a7bSCy Schubert 	uint8_t edns_lame;
72*be771a7bSCy Schubert 	int vs, to, lame, dnsseclame, reclame, probedelay;
73*be771a7bSCy Schubert 	struct infra_key* k;
74*be771a7bSCy Schubert 	struct infra_data* d;
75*be771a7bSCy Schubert 
76*be771a7bSCy Schubert 	/* configure */
77*be771a7bSCy Schubert 	cfg->infra_cache_max_rtt = rtt_max_timeout;
78*be771a7bSCy Schubert 	config_apply_max_rtt(rtt_max_timeout);
79*be771a7bSCy Schubert 	slab->infra_keep_probing = keep_probing;
80*be771a7bSCy Schubert 
81*be771a7bSCy Schubert 	/* expired previous entry */
82*be771a7bSCy Schubert 	*now += cfg->host_ttl + 10;
83*be771a7bSCy Schubert 	unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
84*be771a7bSCy Schubert 			*now, &vs, &edns_lame, &to) );
85*be771a7bSCy Schubert 
86*be771a7bSCy Schubert 	/* simulate timeouts until the USEFUL_SERVER_TOP_TIMEOUT is reached */
87*be771a7bSCy Schubert 	while(to < USEFUL_SERVER_TOP_TIMEOUT) {
88*be771a7bSCy Schubert 		unit_assert( infra_rtt_update(slab, &one, onelen, zone, zonelen,
89*be771a7bSCy Schubert 			LDNS_RR_TYPE_A, -1, to, *now) );
90*be771a7bSCy Schubert 		unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
91*be771a7bSCy Schubert 			*now, &vs, &edns_lame, &to) );
92*be771a7bSCy Schubert 		unit_assert( vs == 0 && to <= USEFUL_SERVER_TOP_TIMEOUT && edns_lame == 0 );
93*be771a7bSCy Schubert 	}
94*be771a7bSCy Schubert 	unit_assert( vs == 0 && to == USEFUL_SERVER_TOP_TIMEOUT && edns_lame == 0 );
95*be771a7bSCy Schubert 
96*be771a7bSCy Schubert 	/* don't let the record expire */
97*be771a7bSCy Schubert 	unit_assert( (d=infra_lookup_host(slab, &one, onelen, zone, zonelen, 0, *now, &k)) );
98*be771a7bSCy Schubert 	unit_assert( d->timeout_A >= TIMEOUT_COUNT_MAX );
99*be771a7bSCy Schubert 	unit_assert( d->probedelay > 0 );
100*be771a7bSCy Schubert 	probedelay = d->probedelay;
101*be771a7bSCy Schubert 	lock_rw_unlock(&k->entry.lock);
102*be771a7bSCy Schubert 	cfg->host_ttl = cfg->host_ttl + *now < probedelay
103*be771a7bSCy Schubert 		?cfg->host_ttl :probedelay + 10;
104*be771a7bSCy Schubert 
105*be771a7bSCy Schubert 	/* advance time and check that probing is as expected; we already had a
106*be771a7bSCy Schubert 	 * lot of A timeouts (checked above). */
107*be771a7bSCy Schubert 	*now = probedelay;
108*be771a7bSCy Schubert 	unit_assert( infra_get_lame_rtt(slab, &one, onelen, zone, zonelen,
109*be771a7bSCy Schubert 		LDNS_RR_TYPE_A, &lame, &dnsseclame, &reclame, &to, *now) );
110*be771a7bSCy Schubert 	unit_assert( lame == 0 && dnsseclame == 0 && reclame == 0
111*be771a7bSCy Schubert 		&& to == keep_probing ?still_useful_timeout() :USEFUL_SERVER_TOP_TIMEOUT);
112*be771a7bSCy Schubert }
113*be771a7bSCy Schubert 
114*be771a7bSCy Schubert /** test host cache */
115*be771a7bSCy Schubert void infra_test(void)
116*be771a7bSCy Schubert {
117*be771a7bSCy Schubert 	struct sockaddr_storage one;
118*be771a7bSCy Schubert 	socklen_t onelen;
119*be771a7bSCy Schubert 	uint8_t* zone = (uint8_t*)"\007example\003com\000";
120*be771a7bSCy Schubert 	size_t zonelen = 13;
121*be771a7bSCy Schubert 	struct infra_cache* slab;
122*be771a7bSCy Schubert 	struct config_file* cfg = config_create();
123*be771a7bSCy Schubert 	time_t now = 0;
124*be771a7bSCy Schubert 	uint8_t edns_lame;
125*be771a7bSCy Schubert 	int vs, to;
126*be771a7bSCy Schubert 	struct infra_key* k;
127*be771a7bSCy Schubert 	struct infra_data* d;
128*be771a7bSCy Schubert 	int init = UNKNOWN_SERVER_NICENESS;
129*be771a7bSCy Schubert 	int default_max_rtt = USEFUL_SERVER_TOP_TIMEOUT;
130*be771a7bSCy Schubert 
131*be771a7bSCy Schubert 	unit_show_feature("infra cache");
132*be771a7bSCy Schubert 	unit_assert(ipstrtoaddr("127.0.0.1", 53, &one, &onelen));
133*be771a7bSCy Schubert 
134*be771a7bSCy Schubert 	slab = infra_create(cfg);
135*be771a7bSCy Schubert 	/* insert new record */
136*be771a7bSCy Schubert 	unit_assert( infra_host(slab, &one, onelen, zone, zonelen, now,
137*be771a7bSCy Schubert 		&vs, &edns_lame, &to) );
138*be771a7bSCy Schubert 	unit_assert( vs == 0 && to == init && edns_lame == 0 );
139*be771a7bSCy Schubert 
140*be771a7bSCy Schubert 	/* simulate no answer */
141*be771a7bSCy Schubert 	unit_assert( infra_rtt_update(slab, &one, onelen, zone, zonelen, LDNS_RR_TYPE_A, -1, init, now) );
142*be771a7bSCy Schubert 	unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
143*be771a7bSCy Schubert 			now, &vs, &edns_lame, &to) );
144*be771a7bSCy Schubert 	unit_assert( vs == 0 && to == init*2 && edns_lame == 0 );
145*be771a7bSCy Schubert 
146*be771a7bSCy Schubert 	/* simulate EDNS lame */
147*be771a7bSCy Schubert 	unit_assert( infra_edns_update(slab, &one, onelen, zone, zonelen, -1, now) );
148*be771a7bSCy Schubert 	unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
149*be771a7bSCy Schubert 			now, &vs, &edns_lame, &to) );
150*be771a7bSCy Schubert 	unit_assert( vs == -1 && to == init*2  && edns_lame == 1);
151*be771a7bSCy Schubert 
152*be771a7bSCy Schubert 	/* simulate cache expiry */
153*be771a7bSCy Schubert 	now += cfg->host_ttl + 10;
154*be771a7bSCy Schubert 	unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
155*be771a7bSCy Schubert 			now, &vs, &edns_lame, &to) );
156*be771a7bSCy Schubert 	unit_assert( vs == 0 && to == init && edns_lame == 0 );
157*be771a7bSCy Schubert 
158*be771a7bSCy Schubert 	/* simulate no lame answer */
159*be771a7bSCy Schubert 	unit_assert( infra_set_lame(slab, &one, onelen,
160*be771a7bSCy Schubert 		zone, zonelen,  now, 0, 0, LDNS_RR_TYPE_A) );
161*be771a7bSCy Schubert 	unit_assert( (d=infra_lookup_host(slab, &one, onelen, zone, zonelen, 0, now, &k)) );
162*be771a7bSCy Schubert 	unit_assert( d->ttl == now+cfg->host_ttl );
163*be771a7bSCy Schubert 	unit_assert( d->edns_version == 0 );
164*be771a7bSCy Schubert 	unit_assert(!d->isdnsseclame && !d->rec_lame && d->lame_type_A &&
165*be771a7bSCy Schubert 		!d->lame_other);
166*be771a7bSCy Schubert 	lock_rw_unlock(&k->entry.lock);
167*be771a7bSCy Schubert 
168*be771a7bSCy Schubert 	/* test merge of data */
169*be771a7bSCy Schubert 	unit_assert( infra_set_lame(slab, &one, onelen,
170*be771a7bSCy Schubert 		zone, zonelen,  now, 0, 0, LDNS_RR_TYPE_AAAA) );
171*be771a7bSCy Schubert 	unit_assert( (d=infra_lookup_host(slab, &one, onelen, zone, zonelen, 0, now, &k)) );
172*be771a7bSCy Schubert 	unit_assert(!d->isdnsseclame && !d->rec_lame && d->lame_type_A &&
173*be771a7bSCy Schubert 		d->lame_other);
174*be771a7bSCy Schubert 	lock_rw_unlock(&k->entry.lock);
175*be771a7bSCy Schubert 
176*be771a7bSCy Schubert 	/* test that noEDNS cannot overwrite known-yesEDNS */
177*be771a7bSCy Schubert 	now += cfg->host_ttl + 10;
178*be771a7bSCy Schubert 	unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
179*be771a7bSCy Schubert 			now, &vs, &edns_lame, &to) );
180*be771a7bSCy Schubert 	unit_assert( vs == 0 && to == init && edns_lame == 0 );
181*be771a7bSCy Schubert 
182*be771a7bSCy Schubert 	unit_assert( infra_edns_update(slab, &one, onelen, zone, zonelen, 0, now) );
183*be771a7bSCy Schubert 	unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
184*be771a7bSCy Schubert 			now, &vs, &edns_lame, &to) );
185*be771a7bSCy Schubert 	unit_assert( vs == 0 && to == init && edns_lame == 1 );
186*be771a7bSCy Schubert 
187*be771a7bSCy Schubert 	unit_assert( infra_edns_update(slab, &one, onelen, zone, zonelen, -1, now) );
188*be771a7bSCy Schubert 	unit_assert( infra_host(slab, &one, onelen, zone, zonelen,
189*be771a7bSCy Schubert 			now, &vs, &edns_lame, &to) );
190*be771a7bSCy Schubert 	unit_assert( vs == 0 && to == init && edns_lame == 1 );
191*be771a7bSCy Schubert 
192*be771a7bSCy Schubert 	unit_show_feature("infra cache probing (keep-probing off, default infra-cache-max-rtt)");
193*be771a7bSCy Schubert 	test_keep_probing(slab, cfg, one, onelen, zone, zonelen, &now, 0, default_max_rtt);
194*be771a7bSCy Schubert 
195*be771a7bSCy Schubert 	unit_show_feature("infra cache probing (keep-probing on,  default infra-cache-max-rtt)");
196*be771a7bSCy Schubert 	test_keep_probing(slab, cfg, one, onelen, zone, zonelen, &now, 1, default_max_rtt);
197*be771a7bSCy Schubert 
198*be771a7bSCy Schubert 	unit_show_feature("infra cache probing (keep-probing off, low infra-cache-max-rtt)");
199*be771a7bSCy Schubert 	test_keep_probing(slab, cfg, one, onelen, zone, zonelen, &now, 0, 3000);
200*be771a7bSCy Schubert 
201*be771a7bSCy Schubert 	unit_show_feature("infra cache probing (keep-probing on,  low infra-cache-max-rtt)");
202*be771a7bSCy Schubert 	test_keep_probing(slab, cfg, one, onelen, zone, zonelen, &now, 1, 3000);
203*be771a7bSCy Schubert 
204*be771a7bSCy Schubert 	/* Re-apply defaults for other unit tests that follow */
205*be771a7bSCy Schubert 	config_apply_max_rtt(default_max_rtt);
206*be771a7bSCy Schubert 
207*be771a7bSCy Schubert 	infra_delete(slab);
208*be771a7bSCy Schubert 	config_delete(cfg);
209*be771a7bSCy Schubert }
210