From b3a2c790f3cd6d4257a7434963804a142816962e Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Wed, 14 Aug 2024 23:46:44 +1000 Subject: [PATCH] Store static-stub addresses seperately in the adb Static-stub address and addresses from other sources where being mixed together resulting in static-stub queries going to addresses not specified in the configuration or alternatively static-stub addresses being used instead of the real addresses. --- lib/dns/adb.c | 54 +++++++++++++++++++++------------- lib/dns/include/dns/adb.h | 4 +++ lib/dns/include/dns/rdataset.h | 1 + lib/dns/resolver.c | 16 +++++++--- lib/dns/view.c | 12 +++++++- 5 files changed, 62 insertions(+), 25 deletions(-) diff --git a/lib/dns/adb.c b/lib/dns/adb.c index ef92322afa..d934e232d0 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -265,7 +265,7 @@ ISC_REFCOUNT_DECL(dns_adbentry); * Internal functions (and prototypes). */ static dns_adbname_t * -new_adbname(dns_adb_t *adb, const dns_name_t *, bool start_at_zone); +new_adbname(dns_adb_t *adb, const dns_name_t *, unsigned int flags); static void destroy_adbname(dns_adbname_t *); static bool @@ -296,7 +296,7 @@ static void purge_stale_names(dns_adb_t *adb, isc_stdtime_t now); static dns_adbname_t * get_attached_and_locked_name(dns_adb_t *, const dns_name_t *, - bool start_at_zone, isc_stdtime_t now); + unsigned int flags, isc_stdtime_t now); static void purge_stale_entries(dns_adb_t *adb, isc_stdtime_t now); static dns_adbentry_t * @@ -409,9 +409,12 @@ enum { #define FIND_WANTEMPTYEVENT(fn) (((fn)->options & DNS_ADBFIND_EMPTYEVENT) != 0) #define FIND_AVOIDFETCHES(fn) (((fn)->options & DNS_ADBFIND_AVOIDFETCHES) != 0) #define FIND_STARTATZONE(fn) (((fn)->options & DNS_ADBFIND_STARTATZONE) != 0) +#define FIND_STATICSTUB(fn) (((fn)->options & DNS_ADBFIND_STATICSTUB) != 0) #define FIND_HAS_ADDRS(fn) (!ISC_LIST_EMPTY((fn)->list)) #define FIND_NOFETCH(fn) (((fn)->options & DNS_ADBFIND_NOFETCH) != 0) +#define ADBNAME_FLAGS_MASK (DNS_ADBFIND_STARTATZONE | DNS_ADBFIND_STATICSTUB) + /* * These are currently used on simple unsigned ints, so they are * not really associated with any particular type. @@ -951,7 +954,7 @@ clean_finds_at_name(dns_adbname_t *name, dns_adbstatus_t astat, } static dns_adbname_t * -new_adbname(dns_adb_t *adb, const dns_name_t *dnsname, bool start_at_zone) { +new_adbname(dns_adb_t *adb, const dns_name_t *dnsname, unsigned int flags) { dns_adbname_t *name = NULL; name = isc_mem_get(adb->mctx, sizeof(*name)); @@ -966,6 +969,7 @@ new_adbname(dns_adb_t *adb, const dns_name_t *dnsname, bool start_at_zone) { .v6 = ISC_LIST_INITIALIZER, .finds = ISC_LIST_INITIALIZER, .link = ISC_LINK_INITIALIZER, + .flags = flags & ADBNAME_FLAGS_MASK, .magic = DNS_ADBNAME_MAGIC, }; @@ -981,10 +985,6 @@ new_adbname(dns_adb_t *adb, const dns_name_t *dnsname, bool start_at_zone) { dns_name_copy(dnsname, name->name); dns_name_init(&name->target, NULL); - if (start_at_zone) { - name->flags |= DNS_ADBFIND_STARTATZONE; - } - inc_adbstats(adb, dns_adbstats_namescnt); return (name); } @@ -1235,8 +1235,8 @@ match_adbname(void *node, const void *key) { const dns_adbname_t *adbname0 = node; const dns_adbname_t *adbname1 = key; - if ((adbname0->flags & DNS_ADBFIND_STARTATZONE) != - (adbname1->flags & DNS_ADBFIND_STARTATZONE)) + if ((adbname0->flags & ADBNAME_FLAGS_MASK) != + (adbname1->flags & ADBNAME_FLAGS_MASK)) { return (false); } @@ -1247,12 +1247,12 @@ match_adbname(void *node, const void *key) { static uint32_t hash_adbname(const dns_adbname_t *adbname) { isc_hash32_t hash; - bool start_at_zone = adbname->flags & DNS_ADBFIND_STARTATZONE; + unsigned int flags = adbname->flags & ADBNAME_FLAGS_MASK; isc_hash32_init(&hash); isc_hash32_hash(&hash, adbname->name->ndata, adbname->name->length, false); - isc_hash32_hash(&hash, &start_at_zone, sizeof(start_at_zone), true); + isc_hash32_hash(&hash, &flags, sizeof(flags), true); return (isc_hash32_finalize(&hash)); } @@ -1261,14 +1261,14 @@ hash_adbname(const dns_adbname_t *adbname) { */ static dns_adbname_t * get_attached_and_locked_name(dns_adb_t *adb, const dns_name_t *name, - bool start_at_zone, isc_stdtime_t now) { + unsigned int flags, isc_stdtime_t now) { isc_result_t result; dns_adbname_t *adbname = NULL; isc_time_t timenow; isc_stdtime_t last_update; dns_adbname_t key = { .name = UNCONST(name), - .flags = (start_at_zone) ? DNS_ADBFIND_STARTATZONE : 0, + .flags = flags & ADBNAME_FLAGS_MASK, }; uint32_t hashval = hash_adbname(&key); isc_rwlocktype_t locktype = isc_rwlocktype_read; @@ -1294,7 +1294,7 @@ get_attached_and_locked_name(dns_adb_t *adb, const dns_name_t *name, UPGRADELOCK(&adb->names_lock, locktype); /* Allocate a new name and add it to the hash table. */ - adbname = new_adbname(adb, name, start_at_zone); + adbname = new_adbname(adb, name, key.flags); void *found = NULL; result = isc_hashmap_add(adb->names, hashval, match_adbname, @@ -1959,6 +1959,13 @@ dns_adb_createfind(dns_adb_t *adb, isc_loop_t *loop, isc_job_cb cb, void *cbarg, now = isc_stdtime_now(); } + /* + * If STATICSTUB is set we always want to have STARTATZONE set. + */ + if (options & DNS_ADBFIND_STATICSTUB) { + options |= DNS_ADBFIND_STARTATZONE; + } + /* * Remember what types of addresses we are interested in. */ @@ -1975,8 +1982,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_loop_t *loop, isc_job_cb cb, void *cbarg, again: /* Try to see if we know anything about this name at all. */ - adbname = get_attached_and_locked_name(adb, name, - FIND_STARTATZONE(find), now); + adbname = get_attached_and_locked_name(adb, name, find->options, now); if (NAME_DEAD(adbname)) { UNLOCK(&adbname->lock); @@ -2050,7 +2056,7 @@ again: * Any other result, start a fetch for A, then fall * through to AAAA. */ - if (!NAME_FETCH_A(adbname)) { + if (!NAME_FETCH_A(adbname) && !FIND_STATICSTUB(find)) { wanted_fetches |= DNS_ADBFIND_INET; } break; @@ -2093,7 +2099,8 @@ again: /* * Any other result, start a fetch for AAAA. */ - if (!NAME_FETCH_AAAA(adbname)) { + if (!NAME_FETCH_AAAA(adbname) && !FIND_STATICSTUB(find)) + { wanted_fetches |= DNS_ADBFIND_INET6; } break; @@ -3391,6 +3398,7 @@ dns_adb_flushname(dns_adb_t *adb, const dns_name_t *name) { dns_adbname_t *adbname = NULL; isc_result_t result; bool start_at_zone = false; + bool static_stub = false; dns_adbname_t key = { .name = UNCONST(name) }; REQUIRE(DNS_ADB_VALID(adb)); @@ -3403,9 +3411,11 @@ dns_adb_flushname(dns_adb_t *adb, const dns_name_t *name) { RWLOCK(&adb->names_lock, isc_rwlocktype_write); again: /* - * Delete both entries - without and with DNS_ADBFIND_STARTATZONE set. + * Delete all entries - with and without DNS_ADBFIND_STARTATZONE set + * and with and without DNS_ADBFIND_STATICSTUB set. */ - key.flags = (start_at_zone) ? DNS_ADBFIND_STARTATZONE : 0; + key.flags = ((static_stub) ? DNS_ADBFIND_STATICSTUB : 0) | + ((start_at_zone) ? DNS_ADBFIND_STARTATZONE : 0); result = isc_hashmap_find(adb->names, hash_adbname(&key), match_adbname, (void *)&key, (void **)&adbname); @@ -3422,6 +3432,10 @@ again: start_at_zone = true; goto again; } + if (!static_stub) { + static_stub = true; + goto again; + } RWUNLOCK(&adb->names_lock, isc_rwlocktype_write); } diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index 91f7039b73..7288cdd527 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -192,6 +192,10 @@ struct dns_adbfind { * Don't perform a fetch even if there are no address records available. */ #define DNS_ADBFIND_NOFETCH 0x00000800 +/*% + * Only look for glue record for static stub. + */ +#define DNS_ADBFIND_STATICSTUB 0x00001000 /*% * The answers to queries come back as a list of these. diff --git a/lib/dns/include/dns/rdataset.h b/lib/dns/include/dns/rdataset.h index 9d8788676a..cb0a8d327b 100644 --- a/lib/dns/include/dns/rdataset.h +++ b/lib/dns/include/dns/rdataset.h @@ -265,6 +265,7 @@ struct dns_rdataset { #define DNS_RDATASETATTR_STALE_WINDOW 0x04000000 #define DNS_RDATASETATTR_STALE_ADDED 0x08000000 #define DNS_RDATASETATTR_KEEPCASE 0x10000000 +#define DNS_RDATASETATTR_STATICSTUB 0x20000000 /*% * _OMITDNSSEC: diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index e64d6693af..a78fb15033 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -627,8 +627,9 @@ enum { #define BADCOOKIE(a) (((a)->flags & FCTX_ADDRINFO_BADCOOKIE) != 0) #define ISDUALSTACK(a) (((a)->flags & FCTX_ADDRINFO_DUALSTACK) != 0) -#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) -#define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) +#define NXDOMAIN(r) (((r)->attributes & DNS_RDATASETATTR_NXDOMAIN) != 0) +#define NEGATIVE(r) (((r)->attributes & DNS_RDATASETATTR_NEGATIVE) != 0) +#define STATICSTUB(r) (((r)->attributes & DNS_RDATASETATTR_STATICSTUB) != 0) #ifdef ENABLE_AFL bool dns_fuzzing_resolver = false; @@ -3596,6 +3597,7 @@ normal_nses: result = dns_rdataset_next(&fctx->nameservers)) { bool overquota = false; + unsigned int static_stub = 0; dns_rdataset_current(&fctx->nameservers, &rdata); /* @@ -3606,13 +3608,19 @@ normal_nses: continue; } + if (STATICSTUB(&fctx->nameservers) && + dns_name_equal(&ns.name, fctx->domain)) + { + static_stub = DNS_ADBFIND_STATICSTUB; + } + if (no_addresses > NS_FAIL_LIMIT && dns_rdataset_count(&fctx->nameservers) > NS_RR_LIMIT) { stdoptions |= DNS_ADBFIND_NOFETCH; } - findname(fctx, &ns.name, 0, stdoptions, 0, now, &overquota, - &need_alternate, &no_addresses); + findname(fctx, &ns.name, 0, stdoptions | static_stub, 0, now, + &overquota, &need_alternate, &no_addresses); if (!overquota) { all_spilled = false; diff --git a/lib/dns/view.c b/lib/dns/view.c index 7e9e5bb0e3..2be324156c 100644 --- a/lib/dns/view.c +++ b/lib/dns/view.c @@ -930,7 +930,9 @@ db_find: result = ISC_R_SUCCESS; } - if (result == ISC_R_NOTFOUND && use_hints && view->hints != NULL) { + if (result == ISC_R_NOTFOUND && !is_staticstub_zone && use_hints && + view->hints != NULL) + { if (dns_rdataset_isassociated(rdataset)) { dns_rdataset_disassociate(rdataset); } @@ -1145,6 +1147,14 @@ db_find: goto cleanup; } + /* + * Tag static stub NS RRset so that when we look for + * addresses we use the configured server addresses. + */ + if (dns_zone_gettype(zone) == dns_zone_staticstub) { + rdataset->attributes |= DNS_RDATASETATTR_STATICSTUB; + } + if (use_cache && view->cachedb != NULL && db != view->hints) { /* * We found an answer, but the cache may be better.