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