]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- auth-load-thread, process end of successful transfer.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 1 Jul 2026 14:54:36 +0000 (16:54 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Wed, 1 Jul 2026 14:54:36 +0000 (16:54 +0200)
services/authload.c
services/authzone.c
services/authzone.h

index 6ba58ced5bd0d49f81203a14056a6b34df08f18a..756ece7daedfe4587e916b55ce403b9e3defcd5f 100644 (file)
@@ -668,6 +668,7 @@ worker_auth_load_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(bits),
        uint8_t recv_item;
        ssize_t ret;
        struct auth_xfer* xfr;
+       struct auth_chunk* chunk_list;
        struct module_env* env;
        int ixfr_fail;
 
@@ -721,8 +722,17 @@ worker_auth_load_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(bits),
        lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
        env = &thr->task->worker->env;
        ixfr_fail = thr->task->ixfr_fail;
+       if(thr->task->on_http) {
+               chunk_list = thr->task->chunks_first;
+               thr->task->chunks_first = NULL;
+               thr->task->chunks_last = NULL;
+               thr->task->chunks_total = 0;
+       } else {
+               chunk_list = NULL;
+       }
        auth_load_thread_delete(thr);
-       xfr_process_load_end_transfer(xfr, env, recv_item, ixfr_fail);
+       xfr_process_load_end_transfer(xfr, env, recv_item, ixfr_fail,
+               chunk_list);
 }
 
 /** Attach worker to the auth load thread. */
index fbc0b946eb799edb03aa8edb3c614ff55dd3ee51..91b786b7828240fb7ac7d98a0b928034767243e7 100644 (file)
@@ -6407,46 +6407,116 @@ process_list_end_transfer(struct auth_xfer* xfr, struct module_env* env)
        xfr_process_transfer_failed(xfr, env, ixfr_fail);
 }
 
-void xfr_process_load_end_transfer(struct auth_xfer* xfr,
-       struct module_env* env, uint8_t status, int ixfr_fail)
+/** deal with successful load end, starts holding xfr lock,
+ * ends holding xfr lock. */
+static int
+xfr_process_loaded_transfer(struct auth_xfer* xfr, struct module_env* env,
+       int* gone)
 {
-       if(status) {
-               struct auth_zone* z = NULL;
-               lock_basic_unlock(&xfr->lock);
+       struct auth_zone* z = NULL;
+       lock_basic_unlock(&xfr->lock);
+       if(!xfr_process_reacquire_locks(xfr, env, &z)) {
+               /* the zone is gone, ignore xfr results */
+               *gone = 1;
+               return 0;
+       }
+       /* holding xfr and z locks */
+
+       if(xfr->task_transfer->master->http) {
+               xfr->num_ixfrs = 0;
+               xfr->have_zone = 0;
+               xfr->serial = 0;
+       } else if(xfr->task_transfer->on_ixfr &&
+               !xfr->task_transfer->on_ixfr_is_axfr) {
+               xfr->num_ixfrs++;
+       } else {
+               /* AXFR */
+               xfr->num_ixfrs = 0;
+               xfr->have_zone = 0;
+               xfr->serial = 0;
+       }
+
+       xfr->zone_expired = 0;
+       z->zone_expired = 0;
+       if(!xfr_find_soa(z, xfr)) {
+               verbose(VERB_ALGO, "xfr from %s: no SOA in zone after update"
+                       " (or malformed RR)", xfr->task_transfer->master->host);
+               return 0;
+       }
+       z->soa_zone_acquired = *env->now;
+       xfr->soa_zone_acquired = *env->now;
+       xfr->is_rpz = (z->rpz!=NULL);
+
+       /* release xfr lock while verifying zonemd because it may have
+        * to spawn lookups in the state machines */
+       lock_basic_unlock(&xfr->lock);
+       /* holding z lock */
+       auth_zone_verify_zonemd(z, env, &env->mesh->mods, NULL, 0, 0);
+       if(z->zone_expired) {
+               char zname[LDNS_MAX_DOMAINLEN];
+               /* ZONEMD must have failed */
+               /* reacquire locks, so we hold xfr lock on exit of routine,
+                * and both xfr and z again after releasing xfr for potential
+                * state machine mesh callbacks */
+               lock_rw_unlock(&z->lock);
                if(!xfr_process_reacquire_locks(xfr, env, &z)) {
-                       /* the zone is gone, ignore xfr results */
-                       lock_basic_unlock(&xfr->lock);
-                       return;
+                       *gone = 1;
+                       return 0;
                }
-               /* holding xfr and z locks */
+               dname_str(xfr->name, zname);
+               verbose(VERB_ALGO, "xfr from %s: ZONEMD failed for %s, transfer is failed", xfr->task_transfer->master->host, zname);
+               xfr->zone_expired = 1;
+               lock_rw_unlock(&z->lock);
+               return 0;
+       }
+       /* reacquire locks, so we hold xfr lock on exit of routine,
+        * and both xfr and z again after releasing xfr for potential
+        * state machine mesh callbacks */
+       lock_rw_unlock(&z->lock);
+       if(!xfr_process_reacquire_locks(xfr, env, &z)) {
+               *gone = 1;
+               return 0;
+       }
+       /* holding xfr and z locks */
 
-               if(xfr->task_transfer->master->http) {
-                       xfr->num_ixfrs = 0;
-               } else if(xfr->task_transfer->on_ixfr &&
-                       !xfr->task_transfer->on_ixfr_is_axfr) {
-                       xfr->num_ixfrs++;
-               } else {
-                       /* AXFR */
-                       xfr->num_ixfrs = 0;
-               }
+       if(xfr->have_zone)
+               xfr->lease_time = *env->now;
+       /* unlock */
+       lock_rw_unlock(&z->lock);
 
-               xfr->zone_expired = 0;
-               z->zone_expired = 0;
+       if(verbosity >= VERB_QUERY && xfr->have_zone) {
+               char zname[LDNS_MAX_DOMAINLEN];
+               dname_str(xfr->name, zname);
+               verbose(VERB_QUERY, "auth zone %s updated to serial %u", zname,
+                       (unsigned)xfr->serial);
+       }
+       /* see if we need to write to a zonefile */
+       xfr_write_after_update(xfr, env);
 
-               xfr->have_zone = 0;
-               xfr->serial = 0;
-               if(!xfr_find_soa(z, xfr)) {
-                       verbose(VERB_ALGO, "xfr from %s: no SOA in zone after update"
-                               " (or malformed RR)", xfr->task_transfer->master->host);
+       return 1;
+}
+
+void xfr_process_load_end_transfer(struct auth_xfer* xfr,
+       struct module_env* env, uint8_t status, int ixfr_fail,
+       struct auth_chunk* chunk_list)
+{
+       /* Chunks are put here for the auth zone write for the http case. */
+       xfr->task_transfer->chunks_first = chunk_list;
+       if(status) {
+               int gone = 0;
+               if(!xfr_process_loaded_transfer(xfr, env, &gone)) {
                        status = 0;
+                       if(gone) {
+                               /* the zone is gone from the authzones. */
+                               lock_basic_unlock(&xfr->lock);
+                               auth_chunks_delete(xfr->task_transfer);
+                               xfr->task_transfer->chunks_first = NULL;
+                               return;
+                       }
                }
-               if(status) {
-                       z->soa_zone_acquired = *env->now;
-                       xfr->soa_zone_acquired = *env->now;
-                       xfr->is_rpz = (z->rpz!=NULL);
-               }
-               lock_rw_unlock(&z->lock);
        }
+       auth_chunks_delete(xfr->task_transfer);
+       xfr->task_transfer->chunks_first = NULL;
 
        if(status) {
                /* it worked! */
index 9d41e71da7fb187da83acfb46462d6f87472ee63..3e9521dc0305d1c59ed9a264ef307e0e20080c6d 100644 (file)
@@ -867,7 +867,8 @@ void auth_data_del(rbnode_type* n, void* arg);
 
 /** Handle the end of an auth load task. */
 void xfr_process_load_end_transfer(struct auth_xfer* xfr,
-       struct module_env* env, uint8_t status, int ixfr_fail);
+       struct module_env* env, uint8_t status, int ixfr_fail,
+       struct auth_chunk* chunk_list);
 
 /** Log preview of http transfer */
 void xfr_http_preview(const char* file, struct auth_chunk* chunk_list);