mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-09-22 01:34:56 +02:00
- auth-load-thread, process transfer content and swap result back in.
This commit is contained in:
+118
-2
@@ -50,6 +50,7 @@
|
||||
#include "util/net_help.h"
|
||||
#include "util/log.h"
|
||||
#include "util/ub_event.h"
|
||||
#include "util/data/dname.h"
|
||||
|
||||
/** Auth load notification to string, for descriptive purposes. */
|
||||
static const char*
|
||||
@@ -273,12 +274,127 @@ auth_load_thread_signal_worker(struct auth_load_thread* thr, int status)
|
||||
}
|
||||
}
|
||||
|
||||
/** Create proxy auth zone structure, that is used to hold the data
|
||||
* that is processed. */
|
||||
static struct auth_zone*
|
||||
auth_zone_create_proxy(uint8_t* nm, size_t nmlen, uint16_t dclass)
|
||||
{
|
||||
struct auth_zone* z = (struct auth_zone*)calloc(1, sizeof(*z));
|
||||
if(!z) {
|
||||
return NULL;
|
||||
}
|
||||
z->node.key = z;
|
||||
z->dclass = dclass;
|
||||
z->namelen = nmlen;
|
||||
z->namelabs = dname_count_labels(nm);
|
||||
z->name = memdup(nm, nmlen);
|
||||
if(!z->name) {
|
||||
free(z);
|
||||
return NULL;
|
||||
}
|
||||
rbtree_init(&z->data, &auth_data_cmp);
|
||||
return z;
|
||||
}
|
||||
|
||||
/** Delete proxy auth zone structure */
|
||||
static void
|
||||
auth_zone_delete_proxy(struct auth_zone* z)
|
||||
{
|
||||
if(!z)
|
||||
return;
|
||||
traverse_postorder(&z->data, auth_data_del, NULL);
|
||||
if(z->rpz)
|
||||
rpz_delete(z->rpz);
|
||||
free(z->name);
|
||||
free(z);
|
||||
}
|
||||
|
||||
/** Swap the final zone contents with the live zone */
|
||||
static void
|
||||
auth_load_swap_zone(struct auth_load_thread* thr, struct auth_zone* proxyz)
|
||||
{
|
||||
rbtree_type data;
|
||||
struct rpz* rpz;
|
||||
struct auth_zone* z;
|
||||
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 after auth load.");
|
||||
return;
|
||||
}
|
||||
lock_rw_wrlock(&z->lock);
|
||||
lock_rw_unlock(&thr->task->worker->env.auth_zones->lock);
|
||||
|
||||
data = proxyz->data;
|
||||
proxyz->data = z->data;
|
||||
z->data = data;
|
||||
|
||||
rpz = proxyz->rpz;
|
||||
proxyz->rpz = z->rpz;
|
||||
z->rpz = rpz;
|
||||
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
|
||||
/** Process http transfer */
|
||||
static int
|
||||
auth_load_process_http(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;
|
||||
}
|
||||
|
||||
xfr_http_preview(task->file, task->chunks_first);
|
||||
if(!xfr_http_syntax_check(task->name, task->namelen, task->dclass,
|
||||
task->host, task->file, task->chunks_first, scratch_buffer)) {
|
||||
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);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_free(scratch_buffer);
|
||||
if(z->rpz)
|
||||
rpz_finish_config(z->rpz);
|
||||
|
||||
auth_load_swap_zone(thr, z);
|
||||
auth_zone_delete_proxy(z);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** In the auth load thread, process the task */
|
||||
static int
|
||||
auth_load_thread_process(struct auth_load_thread* thr)
|
||||
{
|
||||
(void)thr;
|
||||
return 0;
|
||||
struct auth_load_task* task = thr->task;
|
||||
|
||||
/* apply data */
|
||||
if(task->on_http) {
|
||||
if(!auth_load_process_http(thr))
|
||||
return 0;
|
||||
} else if(task->on_ixfr && !task->on_ixfr_is_axfr) {
|
||||
} else {
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** The auth load thread. The thread main function. */
|
||||
|
||||
+128
-59
@@ -386,7 +386,7 @@ auth_data_delete(struct auth_data* n)
|
||||
}
|
||||
|
||||
/** helper traverse to delete zones */
|
||||
static void
|
||||
void
|
||||
auth_data_del(rbnode_type* n, void* ATTR_UNUSED(arg))
|
||||
{
|
||||
struct auth_data* z = (struct auth_data*)n->key;
|
||||
@@ -4735,7 +4735,8 @@ chunkline_non_comment_RR(struct auth_chunk** chunk, size_t* chunk_pos,
|
||||
* failure and return a string in the scratch buffer (first RR string)
|
||||
* on failure. */
|
||||
static int
|
||||
http_zonefile_syntax_check(struct auth_xfer* xfr, sldns_buffer* buf)
|
||||
http_zonefile_syntax_check(uint8_t* name, size_t namelen, uint16_t dclass,
|
||||
struct auth_chunk* chunk_list, struct sldns_buffer* buf)
|
||||
{
|
||||
uint8_t rr[LDNS_RR_BUF_SIZE];
|
||||
size_t rr_len, dname_len = 0;
|
||||
@@ -4745,11 +4746,11 @@ http_zonefile_syntax_check(struct auth_xfer* xfr, sldns_buffer* buf)
|
||||
int e;
|
||||
memset(&pstate, 0, sizeof(pstate));
|
||||
pstate.default_ttl = 3600;
|
||||
if(xfr->namelen < sizeof(pstate.origin)) {
|
||||
pstate.origin_len = xfr->namelen;
|
||||
memmove(pstate.origin, xfr->name, xfr->namelen);
|
||||
if(namelen < sizeof(pstate.origin)) {
|
||||
pstate.origin_len = namelen;
|
||||
memmove(pstate.origin, name, namelen);
|
||||
}
|
||||
chunk = xfr->task_transfer->chunks_first;
|
||||
chunk = chunk_list;
|
||||
chunk_pos = 0;
|
||||
if(!chunkline_non_comment_RR(&chunk, &chunk_pos, buf, &pstate)) {
|
||||
return 0;
|
||||
@@ -4766,7 +4767,7 @@ http_zonefile_syntax_check(struct auth_xfer* xfr, sldns_buffer* buf)
|
||||
return 0;
|
||||
}
|
||||
/* check that class is correct */
|
||||
if(sldns_wirerr_get_class(rr, rr_len, dname_len) != xfr->dclass) {
|
||||
if(sldns_wirerr_get_class(rr, rr_len, dname_len) != dclass) {
|
||||
log_err("parse failure: first record in downloaded zonefile "
|
||||
"from wrong RR class");
|
||||
return 0;
|
||||
@@ -4788,7 +4789,7 @@ chunklist_sum(struct auth_chunk* list)
|
||||
|
||||
/** for http download, parse and add RR to zone */
|
||||
static int
|
||||
http_parse_add_rr(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
http_parse_add_rr(const char* host, const char* file, struct auth_zone* z,
|
||||
sldns_buffer* buf, struct sldns_file_parse_state* pstate)
|
||||
{
|
||||
uint8_t rr[LDNS_RR_BUF_SIZE];
|
||||
@@ -4802,9 +4803,7 @@ http_parse_add_rr(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
pstate->prev_rr_len?pstate->prev_rr:NULL, pstate->prev_rr_len);
|
||||
if(e != 0) {
|
||||
log_err("%s/%s parse failure RR[%d]: %s in '%s'",
|
||||
xfr->task_transfer->master->host,
|
||||
xfr->task_transfer->master->file,
|
||||
LDNS_WIREPARSE_OFFSET(e),
|
||||
host, file, LDNS_WIREPARSE_OFFSET(e),
|
||||
sldns_get_errorstr_parse(LDNS_WIREPARSE_ERROR(e)),
|
||||
line);
|
||||
return 0;
|
||||
@@ -5011,8 +5010,6 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
int delmode = 0;
|
||||
int softfail = 0;
|
||||
|
||||
xfr->num_ixfrs++;
|
||||
|
||||
/* start RR iterator over chunklist of packets */
|
||||
chunk_rrlist_start(xfr, &rr_chunk, &rr_num, &rr_pos);
|
||||
while(!chunk_rrlist_end(rr_chunk, rr_num)) {
|
||||
@@ -5132,6 +5129,16 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** 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,
|
||||
struct sldns_buffer* scratch_buffer)
|
||||
{
|
||||
xfr->num_ixfrs++;
|
||||
|
||||
return apply_ixfr(xfr, z, scratch_buffer);
|
||||
}
|
||||
|
||||
/** apply AXFR to zone in memory. z is locked. false on failure(mallocfail) */
|
||||
static int
|
||||
apply_axfr(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
@@ -5198,9 +5205,46 @@ apply_axfr(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
xfr_http_preview(const char* file, struct auth_chunk* chunk_list)
|
||||
{
|
||||
if(verbosity >= VERB_ALGO)
|
||||
verbose(VERB_ALGO, "http download %s of size %d",
|
||||
file, (int)chunklist_sum(chunk_list));
|
||||
if(chunk_list && verbosity >= VERB_ALGO) {
|
||||
char preview[1024];
|
||||
if(chunk_list->len+1 > sizeof(preview)) {
|
||||
memmove(preview, chunk_list->data, sizeof(preview)-1);
|
||||
preview[sizeof(preview)-1]=0;
|
||||
} else {
|
||||
memmove(preview, chunk_list->data, chunk_list->len);
|
||||
preview[chunk_list->len]=0;
|
||||
}
|
||||
log_info("auth zone http downloaded content preview: %s",
|
||||
preview);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
xfr_http_syntax_check(uint8_t* name, size_t namelen, uint16_t dclass,
|
||||
const char* host, const char* file, struct auth_chunk* chunk_list,
|
||||
struct sldns_buffer* scratch_buffer)
|
||||
{
|
||||
/* perhaps a little syntax check before we try to apply the data? */
|
||||
if(!http_zonefile_syntax_check(name, namelen, dclass, chunk_list,
|
||||
scratch_buffer)) {
|
||||
log_err("http download %s/%s does not contain a zonefile, "
|
||||
"but got '%s'", host, file,
|
||||
sldns_buffer_begin(scratch_buffer));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** apply HTTP to zone in memory. z is locked. false on failure(mallocfail) */
|
||||
static int
|
||||
apply_http(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
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)
|
||||
{
|
||||
/* parse data in chunks */
|
||||
@@ -5212,46 +5256,14 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
int ret;
|
||||
memset(&pstate, 0, sizeof(pstate));
|
||||
pstate.default_ttl = 3600;
|
||||
if(xfr->namelen < sizeof(pstate.origin)) {
|
||||
pstate.origin_len = xfr->namelen;
|
||||
memmove(pstate.origin, xfr->name, xfr->namelen);
|
||||
}
|
||||
|
||||
if(verbosity >= VERB_ALGO)
|
||||
verbose(VERB_ALGO, "http download %s of size %d",
|
||||
xfr->task_transfer->master->file,
|
||||
(int)chunklist_sum(xfr->task_transfer->chunks_first));
|
||||
if(xfr->task_transfer->chunks_first && verbosity >= VERB_ALGO) {
|
||||
char preview[1024];
|
||||
if(xfr->task_transfer->chunks_first->len+1 > sizeof(preview)) {
|
||||
memmove(preview, xfr->task_transfer->chunks_first->data,
|
||||
sizeof(preview)-1);
|
||||
preview[sizeof(preview)-1]=0;
|
||||
} else {
|
||||
memmove(preview, xfr->task_transfer->chunks_first->data,
|
||||
xfr->task_transfer->chunks_first->len);
|
||||
preview[xfr->task_transfer->chunks_first->len]=0;
|
||||
}
|
||||
log_info("auth zone http downloaded content preview: %s",
|
||||
preview);
|
||||
}
|
||||
|
||||
/* perhaps a little syntax check before we try to apply the data? */
|
||||
if(!http_zonefile_syntax_check(xfr, scratch_buffer)) {
|
||||
log_err("http download %s/%s does not contain a zonefile, "
|
||||
"but got '%s'", xfr->task_transfer->master->host,
|
||||
xfr->task_transfer->master->file,
|
||||
sldns_buffer_begin(scratch_buffer));
|
||||
return 0;
|
||||
if(namelen < sizeof(pstate.origin)) {
|
||||
pstate.origin_len = namelen;
|
||||
memmove(pstate.origin, name, namelen);
|
||||
}
|
||||
|
||||
auth_zone_clear_data(z);
|
||||
xfr->have_zone = 0;
|
||||
xfr->serial = 0;
|
||||
xfr->soa_zone_acquired = 0;
|
||||
xfr->num_ixfrs = 0;
|
||||
|
||||
chunk = xfr->task_transfer->chunks_first;
|
||||
chunk = chunk_list;
|
||||
chunk_pos = 0;
|
||||
pstate.lineno = 0;
|
||||
while(chunkline_get_line_collated(&chunk, &chunk_pos, scratch_buffer)) {
|
||||
@@ -5265,8 +5277,7 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
if((ret=http_parse_origin(scratch_buffer, &pstate))!=0) {
|
||||
if(ret == 2) {
|
||||
verbose(VERB_ALGO, "error parsing ORIGIN on line [%s:%d] %s",
|
||||
xfr->task_transfer->master->file,
|
||||
pstate.lineno,
|
||||
file, pstate.lineno,
|
||||
sldns_buffer_begin(scratch_buffer));
|
||||
return 0;
|
||||
}
|
||||
@@ -5275,17 +5286,15 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
if((ret=http_parse_ttl(scratch_buffer, &pstate))!=0) {
|
||||
if(ret == 2) {
|
||||
verbose(VERB_ALGO, "error parsing TTL on line [%s:%d] %s",
|
||||
xfr->task_transfer->master->file,
|
||||
pstate.lineno,
|
||||
file, pstate.lineno,
|
||||
sldns_buffer_begin(scratch_buffer));
|
||||
return 0;
|
||||
}
|
||||
continue; /* $TTL has been handled */
|
||||
}
|
||||
if(!http_parse_add_rr(xfr, z, scratch_buffer, &pstate)) {
|
||||
if(!http_parse_add_rr(host, file, z, scratch_buffer, &pstate)) {
|
||||
verbose(VERB_ALGO, "error parsing line [%s:%d] %s",
|
||||
xfr->task_transfer->master->file,
|
||||
pstate.lineno,
|
||||
file, pstate.lineno,
|
||||
sldns_buffer_begin(scratch_buffer));
|
||||
return 0;
|
||||
}
|
||||
@@ -5293,6 +5302,28 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** apply HTTP to zone in memory. z is locked. false on failure(mallocfail) */
|
||||
static int
|
||||
apply_http(struct auth_xfer* xfr, struct auth_zone* z,
|
||||
struct sldns_buffer* scratch_buffer)
|
||||
{
|
||||
xfr_http_preview(xfr->task_transfer->master->file,
|
||||
xfr->task_transfer->chunks_first);
|
||||
if(!xfr_http_syntax_check(xfr->name, xfr->namelen, xfr->dclass,
|
||||
xfr->task_transfer->master->host,
|
||||
xfr->task_transfer->master->file,
|
||||
xfr->task_transfer->chunks_first, scratch_buffer))
|
||||
return 0;
|
||||
xfr->have_zone = 0;
|
||||
xfr->serial = 0;
|
||||
xfr->soa_zone_acquired = 0;
|
||||
xfr->num_ixfrs = 0;
|
||||
return xfr_apply_http(xfr->name, xfr->namelen,
|
||||
xfr->task_transfer->master->host,
|
||||
xfr->task_transfer->master->file,
|
||||
xfr->task_transfer->chunks_first, z, scratch_buffer);
|
||||
}
|
||||
|
||||
/** write http chunks to zonefile to create downloaded file */
|
||||
static int
|
||||
auth_zone_write_chunks(struct auth_xfer* xfr, const char* fname)
|
||||
@@ -5438,7 +5469,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(!apply_ixfr(xfr, z, env->scratch_buffer)) {
|
||||
if(!xfr_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"
|
||||
@@ -6357,6 +6388,44 @@ process_list_end_transfer(struct auth_xfer* xfr, struct module_env* env)
|
||||
void xfr_process_load_end_transfer(struct auth_xfer* xfr,
|
||||
struct module_env* env, uint8_t status, int ixfr_fail)
|
||||
{
|
||||
if(status) {
|
||||
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 */
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
return;
|
||||
}
|
||||
/* 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;
|
||||
}
|
||||
|
||||
xfr->zone_expired = 0;
|
||||
z->zone_expired = 0;
|
||||
|
||||
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);
|
||||
status = 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
if(status) {
|
||||
/* it worked! */
|
||||
xfr_process_transfer_success(xfr, env);
|
||||
|
||||
@@ -857,8 +857,24 @@ 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);
|
||||
|
||||
/** helper traverse to delete zones */
|
||||
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);
|
||||
|
||||
/** Log preview of http transfer */
|
||||
void xfr_http_preview(const char* file, struct auth_chunk* chunk_list);
|
||||
|
||||
/** Check syntax of first part of the http download */
|
||||
int xfr_http_syntax_check(uint8_t* name, size_t namelen, uint16_t dclass,
|
||||
const char* host, const char* file, struct auth_chunk* chunk_list,
|
||||
struct sldns_buffer* scratch_buffer);
|
||||
|
||||
/** Apply http transfer to auth_zone */
|
||||
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);
|
||||
|
||||
#endif /* SERVICES_AUTHZONE_H */
|
||||
|
||||
Reference in New Issue
Block a user