- auth-load-thread, process IXFR, by making a copy, adjust changes, swap in.

This commit is contained in:
W.C.A. Wijngaards
2026-07-01 13:05:19 +02:00
parent 2fbaee2255
commit 56f66de89f
3 changed files with 167 additions and 13 deletions
+143
View File
@@ -358,6 +358,11 @@ auth_load_process_http(struct auth_load_thread* thr)
sldns_buffer_free(scratch_buffer);
return 0;
}
if(auth_load_thread_poll_for_quit(thr)) {
sldns_buffer_free(scratch_buffer);
auth_zone_delete_proxy(z);
return 0;
}
xfr_http_preview(task->file, task->chunks_first);
if(!xfr_http_syntax_check(task->name, task->namelen, task->dclass,
@@ -366,6 +371,11 @@ auth_load_process_http(struct auth_load_thread* thr)
auth_zone_delete_proxy(z);
return 0;
}
if(auth_load_thread_poll_for_quit(thr)) {
sldns_buffer_free(scratch_buffer);
auth_zone_delete_proxy(z);
return 0;
}
if(!xfr_apply_http(task->name, task->namelen, task->host, task->file,
task->chunks_first, z, scratch_buffer)) {
sldns_buffer_free(scratch_buffer);
@@ -375,9 +385,140 @@ auth_load_process_http(struct auth_load_thread* thr)
sldns_buffer_free(scratch_buffer);
if(z->rpz)
rpz_finish_config(z->rpz);
if(auth_load_thread_poll_for_quit(thr)) {
sldns_buffer_free(scratch_buffer);
auth_zone_delete_proxy(z);
return 0;
}
auth_load_swap_zone(thr, z);
auth_zone_delete_proxy(z);
sldns_buffer_free(scratch_buffer);
return 1;
}
/** Copy RRset and append it to the domain, update last pointer. */
static int
rrset_append_copy(struct auth_data* domain, struct auth_rrset* rrset,
struct auth_rrset** last)
{
struct auth_rrset* s = calloc(1, sizeof(*s));
if(!s)
return 0;
s->type = rrset->type;
s->data = (struct packed_rrset_data*)memdup(rrset->data,
packed_rrset_sizeof(rrset->data));
if(!s->data)
return 0;
packed_rrset_ptr_fixup(s->data);
if(!*last)
domain->rrsets = s;
else (*last)->next = s;
*last = s;
return 1;
}
/** Copy the existing zone for modification */
static int
auth_load_copy_into_zone(struct auth_load_thread* thr, struct auth_zone* proxyz)
{
int count = 0;
struct auth_zone* z;
struct auth_data* d;
lock_rw_rdlock(&thr->task->worker->env.auth_zones->lock);
z = auth_zone_find(thr->task->worker->env.auth_zones,
thr->task->name, thr->task->namelen, thr->task->dclass);
if(!z) {
lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
verbose(VERB_ALGO, "auth zone missing for copy for IXFR.");
return 0;
}
lock_rw_rdlock(&z->lock);
lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
/* Copy from z into proxyz. */
RBTREE_FOR(d, struct auth_data*, &z->data) {
struct auth_rrset* rrset, *last = NULL;
struct auth_data* proxy_d = az_domain_create(proxyz,
d->name, d->namelen);
if(!proxy_d) {
log_err("out of memory");
lock_rw_unlock(&z->lock);
return 0;
}
for(rrset = d->rrsets; rrset; rrset=rrset->next) {
if(!rrset_append_copy(proxy_d, rrset, &last)) {
log_err("out of memory");
lock_rw_unlock(&z->lock);
return 0;
}
if((count++)%10000 == 0) {
if(auth_load_thread_poll_for_quit(thr)) {
lock_rw_unlock(&z->lock);
return 0;
}
}
}
if((count++)%10000 == 0) {
if(auth_load_thread_poll_for_quit(thr)) {
lock_rw_unlock(&z->lock);
return 0;
}
}
}
lock_rw_unlock(&z->lock);
return 1;
}
/** Process ixfr transfer */
static int
auth_load_process_ixfr(struct auth_load_thread* thr)
{
struct auth_load_task* task = thr->task;
struct sldns_buffer* scratch_buffer;
struct auth_zone* z;
scratch_buffer = sldns_buffer_new(sldns_buffer_capacity(
thr->task->worker->env.scratch_buffer));
if(!scratch_buffer) {
log_err("out of memory");
return 0;
}
z = auth_zone_create_proxy(task->name, task->namelen, task->dclass);
if(!z) {
log_err("out of memory");
sldns_buffer_free(scratch_buffer);
return 0;
}
if(auth_load_thread_poll_for_quit(thr)) {
sldns_buffer_free(scratch_buffer);
auth_zone_delete_proxy(z);
return 0;
}
/* Copy the existing zone for modification, that uses a read lock.
* That then does not interrupt the service of threads. */
if(!auth_load_copy_into_zone(thr, z)) {
sldns_buffer_free(scratch_buffer);
auth_zone_delete_proxy(z);
return 0;
}
if(!xfr_apply_ixfr(task->chunks_first, task->serial, z,
scratch_buffer)) {
sldns_buffer_free(scratch_buffer);
auth_zone_delete_proxy(z);
return 0;
}
if(auth_load_thread_poll_for_quit(thr)) {
sldns_buffer_free(scratch_buffer);
auth_zone_delete_proxy(z);
return 0;
}
auth_load_swap_zone(thr, z);
auth_zone_delete_proxy(z);
sldns_buffer_free(scratch_buffer);
return 1;
}
@@ -392,6 +533,8 @@ auth_load_thread_process(struct auth_load_thread* thr)
if(!auth_load_process_http(thr))
return 0;
} else if(task->on_ixfr && !task->on_ixfr_is_axfr) {
if(!auth_load_process_ixfr(thr))
return 0;
} else {
}
return 1;
+16 -13
View File
@@ -593,7 +593,7 @@ auth_zone_set_fallback(struct auth_zone* z, char* fallbackstr)
}
/** create domain with the given name */
static struct auth_data*
struct auth_data*
az_domain_create(struct auth_zone* z, uint8_t* nm, size_t nmlen)
{
struct auth_data* n = (struct auth_data*)malloc(sizeof(*n));
@@ -4823,10 +4823,10 @@ http_parse_add_rr(const char* host, const char* file, struct auth_zone* z,
/** RR list iterator, returns RRs from answer section one by one from the
* dns packets in the chunklist */
static void
chunk_rrlist_start(struct auth_xfer* xfr, struct auth_chunk** rr_chunk,
chunk_rrlist_start(struct auth_chunk* chunk_list, struct auth_chunk** rr_chunk,
int* rr_num, size_t* rr_pos)
{
*rr_chunk = xfr->task_transfer->chunks_first;
*rr_chunk = chunk_list;
*rr_num = 0;
*rr_pos = 0;
}
@@ -4993,9 +4993,9 @@ ixfr_start_serial(struct auth_chunk* rr_chunk, int rr_num, size_t rr_pos,
}
/** apply IXFR to zone in memory. z is locked. false on failure(mallocfail) */
static int
apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
struct sldns_buffer* scratch_buffer)
int
xfr_apply_ixfr(struct auth_chunk* chunk_list, uint32_t xfr_serial,
struct auth_zone* z, struct sldns_buffer* scratch_buffer)
{
struct auth_chunk* rr_chunk;
int rr_num;
@@ -5011,7 +5011,7 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
int softfail = 0;
/* start RR iterator over chunklist of packets */
chunk_rrlist_start(xfr, &rr_chunk, &rr_num, &rr_pos);
chunk_rrlist_start(chunk_list, &rr_chunk, &rr_num, &rr_pos);
while(!chunk_rrlist_end(rr_chunk, rr_num)) {
if(!chunk_rrlist_get_current(rr_chunk, rr_num, rr_pos,
&rr_dname, &rr_type, &rr_class, &rr_ttl, &rr_rdlen,
@@ -5042,7 +5042,7 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
if(!ixfr_start_serial(rr_chunk, rr_num, rr_pos,
rr_dname, rr_type, rr_class, rr_ttl,
rr_rdlen, rr_rdata, rr_nextpos,
transfer_serial, xfr->serial)) {
transfer_serial, xfr_serial)) {
return 0;
}
} else if(transfer_serial == serial) {
@@ -5063,7 +5063,8 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
* SOA 3 followed by add
* SOA 3 end */
/* ended by SOA record */
xfr->serial = transfer_serial;
/* xfr->serial is set by xfr_find_soa
* after this function. */
break;
}
}
@@ -5131,12 +5132,13 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
/** apply IXFR to zone in memory. z is locked. false on failure(mallocfail) */
static int
xfr_apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
struct sldns_buffer* scratch_buffer)
{
xfr->num_ixfrs++;
return apply_ixfr(xfr, z, scratch_buffer);
return xfr_apply_ixfr(xfr->task_transfer->chunks_first, xfr->serial, z,
scratch_buffer);
}
/** apply AXFR to zone in memory. z is locked. false on failure(mallocfail) */
@@ -5164,7 +5166,8 @@ apply_axfr(struct auth_xfer* xfr, struct auth_zone* z,
/* insert all RRs in to the zone */
/* insert the SOA only once, skip the last one */
/* start RR iterator over chunklist of packets */
chunk_rrlist_start(xfr, &rr_chunk, &rr_num, &rr_pos);
chunk_rrlist_start(xfr->task_transfer->chunks_first, &rr_chunk,
&rr_num, &rr_pos);
while(!chunk_rrlist_end(rr_chunk, rr_num)) {
if(!chunk_rrlist_get_current(rr_chunk, rr_num, rr_pos,
&rr_dname, &rr_type, &rr_class, &rr_ttl, &rr_rdlen,
@@ -5469,7 +5472,7 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
}
} else if(xfr->task_transfer->on_ixfr &&
!xfr->task_transfer->on_ixfr_is_axfr) {
if(!xfr_apply_ixfr(xfr, z, env->scratch_buffer)) {
if(!apply_ixfr(xfr, z, env->scratch_buffer)) {
auth_zone_clear_data(z);
lock_rw_unlock(&z->lock);
verbose(VERB_ALGO, "xfr from %s: could not store IXFR"
+8
View File
@@ -857,6 +857,10 @@ int chunkline_count_parens(struct sldns_buffer* buf, size_t start);
/** Clear data in auth zone */
void auth_zone_clear_data(struct auth_zone* z);
/** create domain with the given name */
struct auth_data* az_domain_create(struct auth_zone* z, uint8_t* nm,
size_t nmlen);
/** helper traverse to delete zones */
void auth_data_del(rbnode_type* n, void* arg);
@@ -877,4 +881,8 @@ int xfr_apply_http(uint8_t* name, size_t namelen, const char* host,
const char* file, struct auth_chunk* chunk_list, struct auth_zone* z,
struct sldns_buffer* scratch_buffer);
/** Apply IXFR transfer to auth_zone */
int xfr_apply_ixfr(struct auth_chunk* chunk_list, uint32_t xfr_serial,
struct auth_zone* z, struct sldns_buffer* scratch_buffer);
#endif /* SERVICES_AUTHZONE_H */