]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix looping issues
authorWitold Kręcicki <wpk@isc.org>
Sat, 14 Jul 2018 18:11:03 +0000 (20:11 +0200)
committerWitold Kręcicki <wpk@isc.org>
Tue, 23 Oct 2018 12:15:04 +0000 (12:15 +0000)
bin/named/server.c
bin/tests/optional/adb_test.c
bin/tests/optional/byname_test.c
bin/tests/system/qmin/tests.sh
lib/dns/adb.c
lib/dns/include/dns/adb.h
lib/dns/resolver.c
lib/dns/zone.c

index af3bc162b12d42da46b489364be429ff41daa6d1..1fc81d8991e2c4df8a21ac897b612e83295fc8cf 100644 (file)
@@ -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,
index f871c216917264bd9269bf39f4fda6809185ec4c..557976fcb23aa9e9e1c5a58af7b41ab2789f9bd7 100644 (file)
@@ -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);
index c48baec0bd1deb1083ae687b0cfc6935fae49502..2c16bfd3aa2d3aadefc21f08cfbc309a5e5f92c4 100644 (file)
@@ -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)) {
                        /*
index 848e291b9548ab5f99b8e8934cbacdc653c2e518..b88df3dd046c1a6b298f80eaba6690285ed382cd 100755 (executable)
@@ -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
index 1572732bcd914247d79f2423bf53afac099212f2..06792041478ad7619e6e9094060de55a678ee3e7 100644 (file)
@@ -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;
index 5ba920c853716fd4a972be95e33b52bf2d512868..2af2115b3579d5fa325cb5dbbd8b59cd76d97e9d 100644 (file)
@@ -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
index a19e5680ba8c4eaa38a4db941482c1221d4f9fca..4af6b9e3760235253c54e4d3748dd91d7cf79a6c 100644 (file)
@@ -68,7 +68,6 @@
 #include <dns/stats.h>
 #include <dns/tsig.h>
 #include <dns/validator.h>
-
 #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;
index 60545141c7534272700bcd8dd7db6774de2278e7..59bf892ddecaf47eac56fe4ad54b2c28c5f0843e 100644 (file)
@@ -10991,7 +10991,7 @@ notify_find_address(dns_notify_t *notify) {
                                    &notify->ns, dns_rootname, 0,
                                    options, 0, NULL,
                                    notify->zone->view->dstport,
-                                   0, NULL, &notify->find);
+                                   0, NULL, NULL, 0, &notify->find);
 
        /* Something failed? */
        if (result != ISC_R_SUCCESS)