From: Witold KrÄ™cicki Date: Sat, 14 Jul 2018 18:11:03 +0000 (+0200) Subject: Fix looping issues X-Git-Tag: v9.13.4~105^2~10 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f2af336dc42e39990e1b0b6790779a7281a4addb;p=thirdparty%2Fbind9.git Fix looping issues --- diff --git a/bin/named/server.c b/bin/named/server.c index af3bc162b12..1fc81d8991e 100644 --- a/bin/named/server.c +++ b/bin/named/server.c @@ -6764,8 +6764,8 @@ dotat(dns_keytable_t *keytable, dns_keynode_t *keynode, void *arg) { */ domain = dns_fixedname_initname(&fdomain); dns_rdataset_init(&nameservers); - result = dns_view_findzonecut(view, origin, domain, 0, 0, true, - true, &nameservers, NULL); + result = dns_view_findzonecut(view, origin, domain, NULL, 0, 0, + true, true, &nameservers, NULL); if (result == ISC_R_SUCCESS) { result = dns_resolver_createfetch(view->resolver, tatname, dns_rdatatype_null, domain, diff --git a/bin/tests/optional/adb_test.c b/bin/tests/optional/adb_test.c index f871c216917..557976fcb23 100644 --- a/bin/tests/optional/adb_test.c +++ b/bin/tests/optional/adb_test.c @@ -258,7 +258,7 @@ lookup(const char *target) { result = dns_adb_createfind(adb, t2, lookup_callback, client, &client->name, dns_rootname, 0, options, now, NULL, view->dstport, 0, NULL, - &client->find); + NULL, 0, &client->find); if (result != ISC_R_SUCCESS) printf("DNS_ADB_CREATEFIND -> %s\n", dns_result_totext(result)); dns_adb_dumpfind(client->find, stderr); diff --git a/bin/tests/optional/byname_test.c b/bin/tests/optional/byname_test.c index c48baec0bd1..2c16bfd3aa2 100644 --- a/bin/tests/optional/byname_test.c +++ b/bin/tests/optional/byname_test.c @@ -117,7 +117,7 @@ do_find(bool want_event) { dns_fixedname_name(&fixed), dns_rootname, 0, options, 0, dns_fixedname_name(&target), 0, - 0, NULL, &find); + 0, NULL, NULL, 0, &find); if (result == ISC_R_SUCCESS) { if (!ISC_LIST_EMPTY(find->list)) { /* diff --git a/bin/tests/system/qmin/tests.sh b/bin/tests/system/qmin/tests.sh index 848e291b954..b88df3dd046 100755 --- a/bin/tests/system/qmin/tests.sh +++ b/bin/tests/system/qmin/tests.sh @@ -239,7 +239,6 @@ NS boing.slow. NS zoop.boing.slow. ADDR ns3.slow. ADDR ns3.slow. -NS icky.ptang.zoop.boing.slow. ADDR a.bit.longer.ns.name.slow. ADDR a.bit.longer.ns.name.slow. __EOF diff --git a/lib/dns/adb.c b/lib/dns/adb.c index 1572732bcd9..06792041478 100644 --- a/lib/dns/adb.c +++ b/lib/dns/adb.c @@ -195,6 +195,8 @@ struct dns_adbname { isc_stdtime_t last_used; ISC_LINK(dns_adbname_t) plink; + isc_sockaddr_t client; + dns_messageid_t id; }; /*% The adbfetch structure */ @@ -337,7 +339,8 @@ static isc_result_t dbfind_name(dns_adbname_t *, isc_stdtime_t, dns_rdatatype_t); static isc_result_t fetch_name(dns_adbname_t *, bool, unsigned int, isc_counter_t *qc, - dns_rdatatype_t); + dns_rdatatype_t, const isc_sockaddr_t *client, + dns_messageid_t id); static inline void check_exit(dns_adb_t *); static void destroy(dns_adb_t *); static bool shutdown_names(dns_adb_t *); @@ -1539,6 +1542,8 @@ clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype, isc_task_sendanddetach(&task, (isc_event_t **)&ev); find->flags |= FIND_EVENT_SENT; + memset(&name->client, 0, sizeof(name->client)); + name->id = 0; } else { DP(DEF_LEVEL, "cfan: skipping find %p", find); } @@ -1546,7 +1551,6 @@ clean_finds_at_name(dns_adbname_t *name, isc_eventtype_t evtype, UNLOCK(&find->lock); find = next_find; } - DP(ENTER_LEVEL, "EXIT clean_finds_at_name, name %p", name); } @@ -1696,6 +1700,8 @@ new_adbname(dns_adb_t *adb, const dns_name_t *dnsname) { name->fetch_aaaa = NULL; name->fetch_err = FIND_ERR_UNEXPECTED; name->fetch6_err = FIND_ERR_UNEXPECTED; + memset(&name->client, 0, sizeof(name->client)); + name->id = 0; ISC_LIST_INIT(name->finds); ISC_LINK_INIT(name, plink); @@ -2936,6 +2942,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, dns_rdatatype_t qtype, unsigned int options, isc_stdtime_t now, dns_name_t *target, in_port_t port, unsigned int depth, isc_counter_t *qc, + const isc_sockaddr_t *client, dns_messageid_t id, dns_adbfind_t **findp) { dns_adbfind_t *find; @@ -3025,6 +3032,18 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, result = ISC_R_SHUTTINGDOWN; goto out; } + if (adbname != NULL && client != NULL && + isc_sockaddr_equal(client, &adbname->client) && id == adbname->id) { + char buf[DNS_NAME_FORMATSIZE + DNS_RDATATYPE_FORMATSIZE]; + char typebuf[DNS_RDATATYPE_FORMATSIZE]; + dns_name_format(qname, buf, sizeof(buf)); + dns_rdatatype_format(qtype, typebuf, sizeof(typebuf)); + result = DNS_R_DUPLICATE; + DP(DEF_LEVEL, + "dns_adb_createfind: duplicate query (possible loop) for %s/%s", buf, typebuf); + RUNTIME_CHECK(!free_adbfind(adb, &find)); + goto out; + } /* * Nothing found. Allocate a new adbname structure for this name. @@ -3175,7 +3194,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, */ if (WANT_INET(wanted_fetches) && fetch_name(adbname, start_at_zone, depth, qc, - dns_rdatatype_a) == ISC_R_SUCCESS) { + dns_rdatatype_a, client, id) == ISC_R_SUCCESS) { DP(DEF_LEVEL, "dns_adb_createfind: " "started A fetch for name %s (%p)", namebuf, adbname); @@ -3186,7 +3205,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, */ if (WANT_INET6(wanted_fetches) && fetch_name(adbname, start_at_zone, depth, qc, - dns_rdatatype_aaaa) == ISC_R_SUCCESS) { + dns_rdatatype_aaaa, client, id) == ISC_R_SUCCESS) { DP(DEF_LEVEL, "dns_adb_createfind: " "started AAAA fetch for name %s (%p)", namebuf, adbname); @@ -3221,12 +3240,20 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, if (want_event) { find->adbname = adbname; find->name_bucket = bucket; + bool empty = ISC_LIST_EMPTY(adbname->finds); + /* If there are no finds pending take ownership of adbname */ + if (adbname->client.length == 0 && client != NULL) { + adbname->client = *client; + adbname->id = id; + } ISC_LIST_APPEND(adbname->finds, find, plink); find->query_pending = (query_pending & wanted_addresses); find->flags &= ~DNS_ADBFIND_ADDRESSMASK; find->flags |= (find->query_pending & DNS_ADBFIND_ADDRESSMASK); - DP(DEF_LEVEL, "createfind: attaching find %p to adbname %p", - find, adbname); + DP(DEF_LEVEL, "createfind: attaching find %p to adbname " + "%p (%d/%d) %d", + find, adbname, isc_sockaddr_hash(&adbname->client, true), + adbname->id, empty); } else { /* * Remove the flag so the caller knows there will never @@ -3993,7 +4020,8 @@ fetch_callback(isc_task_t *task, isc_event_t *ev) { static isc_result_t fetch_name(dns_adbname_t *adbname, bool start_at_zone, - unsigned int depth, isc_counter_t *qc, dns_rdatatype_t type) + unsigned int depth, isc_counter_t *qc, dns_rdatatype_t type, + const isc_sockaddr_t *client, dns_messageid_t id) { isc_result_t result; dns_adbfetch_t *fetch = NULL; @@ -4046,15 +4074,18 @@ fetch_name(dns_adbname_t *adbname, bool start_at_zone, * createfetch to find deepest cached name when we're providing * domain and nameservers. */ - result = dns_resolver_createfetch(adb->view->resolver, &adbname->name, type, name, nameservers, NULL, - NULL, 0, options, depth, qc, + client, id, options, depth, qc, adb->task, fetch_callback, adbname, &fetch->rdataset, NULL, &fetch->fetch); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + DP(ENTER_LEVEL, + "fetch_name: createfetch failed with %s", + isc_result_totext(result)); goto cleanup; + } if (type == dns_rdatatype_a) { adbname->fetch_a = fetch; diff --git a/lib/dns/include/dns/adb.h b/lib/dns/include/dns/adb.h index 5ba920c8537..2af2115b357 100644 --- a/lib/dns/include/dns/adb.h +++ b/lib/dns/include/dns/adb.h @@ -337,6 +337,7 @@ dns_adb_createfind(dns_adb_t *adb, isc_task_t *task, isc_taskaction_t action, dns_rdatatype_t qtype, unsigned int options, isc_stdtime_t now, dns_name_t *target, in_port_t port, unsigned int depth, isc_counter_t *qc, + const isc_sockaddr_t *client, dns_messageid_t id, dns_adbfind_t **find); /*%< * Main interface for clients. The adb will look up the name given in diff --git a/lib/dns/resolver.c b/lib/dns/resolver.c index a19e5680ba8..4af6b9e3760 100644 --- a/lib/dns/resolver.c +++ b/lib/dns/resolver.c @@ -68,7 +68,6 @@ #include #include #include - #ifdef WANT_QUERYTRACE #define RTRACE(m) isc_log_write(dns_lctx, \ DNS_LOGCATEGORY_RESOLVER, \ @@ -385,6 +384,7 @@ struct fetchctx { bool timeout; dns_adbaddrinfo_t *addrinfo; const isc_sockaddr_t *client; + dns_messageid_t id; unsigned int depth; }; @@ -3317,6 +3317,7 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port, bool unshared; isc_result_t result; + FCTXTRACE("FINDNAME"); res = fctx->res; unshared = (fctx->options & DNS_FETCHOPT_UNSHARED); /* @@ -3341,8 +3342,13 @@ findname(fetchctx_t *fctx, const dns_name_t *name, in_port_t port, &fctx->name, fctx->type, options, now, NULL, res->view->dstport, - fctx->depth + 1, fctx->qc, &find); - + fctx->depth + 1, fctx->qc, fctx->client, + fctx->id, &find); + isc_log_write(dns_lctx, DNS_LOGCATEGORY_RESOLVER, + DNS_LOGMODULE_RESOLVER, ISC_LOG_DEBUG(3), + "fctx %p(%s): createfind for %p/%d - %s", + fctx, fctx->info, fctx->client, fctx->id, + isc_result_totext(result)); if (result != ISC_R_SUCCESS) { if (result == DNS_R_ALIAS) { char namebuf[DNS_NAME_FORMATSIZE]; @@ -3967,12 +3973,15 @@ fctx_try(fetchctx_t *fctx, bool retrying, bool badcache) { fctx_increference(fctx); task = res->buckets[bucketnum].task; result = dns_resolver_createfetch(fctx->res, &fctx->qminname, - fctx->qmintype, NULL, - NULL, NULL, NULL, 0, - options, 0, fctx->qc, - task, resume_qmin, fctx, - &fctx->qminrrset, NULL, - &fctx->qminfetch); + fctx->qmintype, &fctx->domain, + &fctx->nameservers, NULL, fctx->client, + fctx->id, options, 0, + fctx->qc, task, resume_qmin, + fctx, &fctx->qminrrset, + NULL, &fctx->qminfetch); + if (result != ISC_R_SUCCESS) { + fctx_done(fctx, DNS_R_SERVFAIL, __LINE__); + } return; } @@ -4559,7 +4568,6 @@ fctx_join(fetchctx_t *fctx, isc_task_t *task, const isc_sockaddr_t *client, else ISC_LIST_APPEND(fctx->events, event, ev_link); fctx->references++; - fctx->client = client; fetch->magic = DNS_FETCH_MAGIC; fetch->private = fctx; @@ -4585,7 +4593,8 @@ static isc_result_t fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, const dns_name_t *domain, dns_rdataset_t *nameservers, unsigned int options, unsigned int bucketnum, unsigned int depth, - isc_counter_t *qc, fetchctx_t **fctxp) + isc_counter_t *qc, const isc_sockaddr_t *client, dns_messageid_t id, + fetchctx_t **fctxp) { fetchctx_t *fctx; isc_result_t result; @@ -4705,7 +4714,8 @@ fctx_create(dns_resolver_t *res, const dns_name_t *name, dns_rdatatype_t type, fctx->rand_bits = 0; fctx->timeout = false; fctx->addrinfo = NULL; - fctx->client = NULL; + fctx->client = client; + fctx->id = id; fctx->ns_ttl = 0; fctx->ns_ttl_ok = false; @@ -7032,7 +7042,8 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { result = dns_resolver_createfetch(fctx->res, &fctx->nsname, dns_rdatatype_ns, domain, - nsrdataset, NULL, NULL, 0, + nsrdataset, NULL, + fctx->client, fctx->id, fctx->options, 0, NULL, task, resume_dslookup, fctx, &fctx->nsrrset, NULL, @@ -7043,6 +7054,9 @@ resume_dslookup(isc_task_t *task, isc_event_t *event) { * another thread concurrently processing the fetch. */ if (result != ISC_R_SUCCESS) { + if (result == DNS_R_DUPLICATE) { + result = DNS_R_SERVFAIL; + } fctx_done(fctx, result, __LINE__); } else { LOCK(&res->buckets[bucketnum].lock); @@ -9303,14 +9317,18 @@ rctx_chaseds(respctx_t *rctx, dns_adbaddrinfo_t *addrinfo, isc_result_t result) result = dns_resolver_createfetch(fctx->res, &fctx->nsname, dns_rdatatype_ns, - NULL, NULL, NULL, NULL, 0, + NULL, NULL, NULL, + fctx->client, fctx->id, fctx->options, 0, NULL, rctx->task, resume_dslookup, fctx, &fctx->nsrrset, NULL, &fctx->nsfetch); - if (result != ISC_R_SUCCESS) + if (result != ISC_R_SUCCESS) { + if (result == DNS_R_DUPLICATE) { + result = DNS_R_SERVFAIL; + } fctx_done(fctx, result, __LINE__); - else { + } else { fctx_increference(fctx); result = fctx_stopidletimer(fctx); if (result != ISC_R_SUCCESS) @@ -10469,7 +10487,8 @@ dns_resolver_createfetch(dns_resolver_t *res, const dns_name_t *name, if (fctx == NULL) { result = fctx_create(res, name, type, domain, nameservers, - options, bucketnum, depth, qc, &fctx); + options, bucketnum, depth, qc, client, + id, &fctx); if (result != ISC_R_SUCCESS) goto unlock; new_fctx = true; diff --git a/lib/dns/zone.c b/lib/dns/zone.c index 60545141c75..59bf892ddec 100644 --- a/lib/dns/zone.c +++ b/lib/dns/zone.c @@ -10991,7 +10991,7 @@ notify_find_address(dns_notify_t *notify) { ¬ify->ns, dns_rootname, 0, options, 0, NULL, notify->zone->view->dstport, - 0, NULL, ¬ify->find); + 0, NULL, NULL, 0, ¬ify->find); /* Something failed? */ if (result != ISC_R_SUCCESS)