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