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