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