Home | History | Annotate | Line # | Download | only in testcode
      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