From 75073cefea9598975443037aa9ca0068d78ca933 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Thu, 6 Dec 2007 15:11:07 +0000 Subject: [PATCH] library resolution working. git-svn-id: file:///svn/unbound/trunk@809 be551aaa-1e26-0410-a405-d3ace91eadb9 --- Makefile.in | 2 +- daemon/worker.c | 42 ++++ doc/Changelog | 4 + iterator/iterator.c | 5 +- libunbound/context.c | 34 +++ libunbound/context.h | 25 +++ libunbound/unbound.c | 72 ++++-- libunbound/unbound.h | 2 + libunbound/worker.c | 444 ++++++++++++++++++++++++++++++++++--- libunbound/worker.h | 60 ++++- services/mesh.c | 133 ++++++++++- services/mesh.h | 67 ++++++ services/outside_network.c | 5 + smallapp/unbound-host.c | 96 ++++++-- smallapp/worker_cb.c | 41 ++++ util/config_file.c | 20 ++ util/config_file.h | 6 + util/fptr_wlist.c | 8 + util/log.c | 1 + util/netevent.c | 2 +- 20 files changed, 993 insertions(+), 76 deletions(-) diff --git a/Makefile.in b/Makefile.in index 311446b75..0d5a2abd4 100644 --- a/Makefile.in +++ b/Makefile.in @@ -87,7 +87,7 @@ SIGNIT_OBJ=$(addprefix $(BUILD),$(SIGNIT_SRC:.c=.o)) $(COMPAT_OBJ) MEMSTATS_SRC=testcode/memstats.c smallapp/worker_cb.c $(COMMON_SRC) MEMSTATS_OBJ=$(addprefix $(BUILD),$(MEMSTATS_SRC:.c=.o)) $(COMPAT_OBJ) LIBUNBOUND_SRC=$(patsubst $(srcdir)/%,%, \ - $(wildcard $(srcdir)/libunbound/*.c) smallapp/worker_cb.c $(COMMON_SRC)) + $(wildcard $(srcdir)/libunbound/*.c) $(COMMON_SRC)) LIBUNBOUND_OBJ=$(addprefix $(BUILD),$(LIBUNBOUND_SRC:.c=.o)) $(COMPAT_OBJ) ALL_SRC=$(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \ $(TESTBOUND_SRC) $(LOCKVERIFY_SRC) $(PKTVIEW_SRC) $(SIGNIT_SRC) \ diff --git a/daemon/worker.c b/daemon/worker.c index 6f6ee2ac6..e65290e9d 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -1074,3 +1074,45 @@ worker_alloc_cleanup(void* arg) slabhash_clear(&worker->env.rrset_cache->table); slabhash_clear(worker->env.msg_cache); } + +/* --- fake callbacks for fptr_wlist to work --- */ +int libworker_send_packet(ldns_buffer* ATTR_UNUSED(pkt), + struct sockaddr_storage* ATTR_UNUSED(addr), + socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(timeout), + struct module_qstate* ATTR_UNUSED(q), int ATTR_UNUSED(use_tcp)) +{ + log_assert(0); + return 0; +} + +struct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname), + size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), + uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), + int ATTR_UNUSED(dnssec), struct sockaddr_storage* ATTR_UNUSED(addr), + socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q)) +{ + log_assert(0); + return 0; +} + +int libworker_handle_reply(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(reply_info)) +{ + log_assert(0); + return 0; +} + +int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(reply_info)) +{ + log_assert(0); + return 0; +} + +int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) +{ + log_assert(0); + return 0; +} diff --git a/doc/Changelog b/doc/Changelog index 098554ae9..0e6a986d8 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -1,3 +1,7 @@ +6 December 2007: Wouter + - library resolution works in foreground mode, unbound-host app + receives data. + 5 December 2007: Wouter - locking in context_new() inside the function. - setup of libworker. diff --git a/iterator/iterator.c b/iterator/iterator.c index a6a568c13..0a5cb7a91 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -1174,8 +1174,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, iq->chase_flags, EDNS_DO|BIT_CD, &target->addr, target->addrlen, qstate); if(!outq) { - log_err("error sending query to auth server; skip this address"); - log_addr(0, "error for address:", + verbose(VERB_OPS, "error sending query to auth server; " + "skip this address"); + log_addr(VERB_OPS, "error for address:", &target->addr, target->addrlen); return next_state(iq, QUERYTARGETS_STATE); } diff --git a/libunbound/context.c b/libunbound/context.c index 1f971f2b5..dc51b1f82 100644 --- a/libunbound/context.c +++ b/libunbound/context.c @@ -81,6 +81,7 @@ context_finalize(struct ub_val_ctx* ctx) ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg); if(!ctx->env->infra_cache) return UB_NOMEM; + ctx->finalized = 1; return UB_NOERROR; } @@ -149,3 +150,36 @@ context_new(struct ub_val_ctx* ctx, char* name, int rrtype, int rrclass, lock_basic_unlock(&ctx->cfglock); return q; } + +struct alloc_cache* +context_obtain_alloc(struct ub_val_ctx* ctx) +{ + struct alloc_cache* a; + int tnum = 0; + lock_basic_lock(&ctx->cfglock); + a = ctx->alloc_list; + if(a) + ctx->alloc_list = a->super; /* snip off list */ + else tnum = ctx->thr_next_num++; + lock_basic_unlock(&ctx->cfglock); + if(a) { + a->super = &ctx->superalloc; + return a; + } + a = (struct alloc_cache*)calloc(1, sizeof(*a)); + if(!a) + return NULL; + alloc_init(a, &ctx->superalloc, tnum); + return a; +} + +void +context_release_alloc(struct ub_val_ctx* ctx, struct alloc_cache* alloc) +{ + if(!ctx || !alloc) + return; + lock_basic_lock(&ctx->cfglock); + alloc->super = ctx->alloc_list; + ctx->alloc_list = alloc; + lock_basic_unlock(&ctx->cfglock); +} diff --git a/libunbound/context.h b/libunbound/context.h index c5fc67ac5..e42509c74 100644 --- a/libunbound/context.h +++ b/libunbound/context.h @@ -75,6 +75,13 @@ struct ub_val_ctx { */ int finalized; + /** is bg worker created yet ? */ + int created_bg; + /** pid of bg worker process */ + pid_t bg_pid; + /** tid of bg worker thread */ + ub_thread_t bg_tid; + /** do threading (instead of forking) for async resolution */ int dothread; /** next thread number for new threads */ @@ -155,6 +162,10 @@ enum ub_ctx_err { UB_SYNTAX, /** DNS service failed */ UB_SERVFAIL, + /** fork() failed */ + UB_FORKFAIL, + /** cfg change after finalize() */ + UB_AFTERFINAL, /** initialization failed (bad settings) */ UB_INITFAIL }; @@ -182,4 +193,18 @@ int context_query_cmp(const void* a, const void* b); struct ctx_query* context_new(struct ub_val_ctx* ctx, char* name, int rrtype, int rrclass, ub_val_callback_t cb, void* cbarg); +/** + * Get a new alloc. Creates a new one or uses a cached one. + * @param ctx: context + * @return an alloc, or NULL on mem error. + */ +struct alloc_cache* context_obtain_alloc(struct ub_val_ctx* ctx); + +/** + * Release an alloc. Puts it into the cache. + * @param ctx: context + * @param alloc: alloc to relinquish. + */ +void context_release_alloc(struct ub_val_ctx* ctx, struct alloc_cache* alloc); + #endif /* LIBUNBOUND_CONTEXT_H */ diff --git a/libunbound/unbound.c b/libunbound/unbound.c index e67daeb84..3bb3d55a4 100644 --- a/libunbound/unbound.c +++ b/libunbound/unbound.c @@ -45,6 +45,7 @@ #include "libunbound/unbound.h" #include "config.h" #include "libunbound/context.h" +#include "libunbound/worker.h" #include "util/locks.h" #include "util/config_file.h" #include "util/alloc.h" @@ -89,7 +90,7 @@ ub_val_ctx_create() errno = ENOMEM; return NULL; } - ctx->env->cfg = config_create(); + ctx->env->cfg = config_create_forlib(); if(!ctx->env->cfg) { ub_val_ctx_delete(ctx); errno = ENOMEM; @@ -124,9 +125,9 @@ ub_val_ctx_delete(struct ub_val_ctx* ctx) na = a->super; a->super = &ctx->superalloc; alloc_clear(a); + free(a); a = na; } - alloc_clear(&ctx->superalloc); local_zones_delete(ctx->local_zones); lock_basic_destroy(&ctx->qqpipe_lock); lock_basic_destroy(&ctx->rrpipe_lock); @@ -142,6 +143,7 @@ ub_val_ctx_delete(struct ub_val_ctx* ctx) config_delete(ctx->env->cfg); free(ctx->env); } + alloc_clear(&ctx->superalloc); traverse_postorder(&ctx->queries, delq, NULL); free(ctx); } @@ -150,7 +152,10 @@ int ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname) { lock_basic_lock(&ctx->cfglock); - ctx->finalized = 0; + if(ctx->finalized) { + lock_basic_unlock(&ctx->cfglock); + return UB_AFTERFINAL; + } if(!config_read(ctx->env->cfg, fname)) { lock_basic_unlock(&ctx->cfglock); return UB_SYNTAX; @@ -165,7 +170,10 @@ ub_val_ctx_add_ta(struct ub_val_ctx* ctx, char* ta) char* dup = strdup(ta); if(!dup) return UB_NOMEM; lock_basic_lock(&ctx->cfglock); - ctx->finalized = 0; + if(ctx->finalized) { + lock_basic_unlock(&ctx->cfglock); + return UB_AFTERFINAL; + } if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) { lock_basic_unlock(&ctx->cfglock); free(dup); @@ -181,7 +189,10 @@ ub_val_ctx_trustedkeys(struct ub_val_ctx* ctx, char* fname) char* dup = strdup(fname); if(!dup) return UB_NOMEM; lock_basic_lock(&ctx->cfglock); - ctx->finalized = 0; + if(ctx->finalized) { + lock_basic_unlock(&ctx->cfglock); + return UB_AFTERFINAL; + } if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) { lock_basic_unlock(&ctx->cfglock); free(dup); @@ -195,7 +206,10 @@ int ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread) { lock_basic_lock(&ctx->cfglock); - ctx->finalized = 0; + if(ctx->finalized) { + lock_basic_unlock(&ctx->cfglock); + return UB_AFTERFINAL; + } ctx->dothread = dothread; lock_basic_unlock(&ctx->cfglock); return UB_NOERROR; @@ -233,10 +247,9 @@ int ub_val_ctx_wait(struct ub_val_ctx* ctx) { lock_basic_lock(&ctx->cfglock); - /* TODO until no more queries outstanding */ while(ctx->num_async > 0) { - lock_basic_unlock(&ctx->cfglock); lock_basic_lock(&ctx->rrpipe_lock); + lock_basic_unlock(&ctx->cfglock); (void)pollit(ctx, NULL); lock_basic_unlock(&ctx->rrpipe_lock); ub_val_ctx_process(ctx); @@ -265,10 +278,11 @@ ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype, int rrclass, int* secure, int* data, struct ub_val_result** result) { struct ctx_query* q; + int r; lock_basic_lock(&ctx->cfglock); if(!ctx->finalized) { - int r = context_finalize(ctx); + r = context_finalize(ctx); if(r) { lock_basic_unlock(&ctx->cfglock); return r; @@ -284,8 +298,23 @@ ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype, *data = 0; *result = NULL; - /* TODO */ - return UB_NOMEM; + r = libworker_fg(ctx, q); + if(r) { + ub_val_result_free(q->res); + free(q); + return r; + } + + if(q->msg_security == sec_status_secure) + *secure = 1; + if(q->res->data && q->res->data[0]) + *data = 1; + *result = q->res; + + (void)rbtree_delete(&ctx->queries, q->node.key); + free(q->msg); + free(q); + return UB_NOERROR; } int @@ -302,8 +331,17 @@ ub_val_resolve_async(struct ub_val_ctx* ctx, char* name, int rrtype, return r; } } - /* create new ctx_query and attempt to add to the list */ + if(!ctx->created_bg) { + int r = libworker_bg(ctx); + if(r) { + lock_basic_unlock(&ctx->cfglock); + return r; + } + ctx->created_bg = 1; + } lock_basic_unlock(&ctx->cfglock); + + /* create new ctx_query and attempt to add to the list */ q = context_new(ctx, name, rrtype, rrclass, callback, mydata); if(!q) return UB_NOMEM; @@ -336,9 +374,11 @@ ub_val_result_free(struct ub_val_result* result) char** p; if(!result) return; free(result->qname); - free(result->canonname); - for(p = result->data; *p; p++) - free(*p); + if(result->canonname != result->qname) + free(result->canonname); + if(result->data) + for(p = result->data; *p; p++) + free(*p); free(result->data); free(result->len); free(result); @@ -353,7 +393,9 @@ ub_val_strerror(int err) case UB_SOCKET: return "socket io error"; case UB_SYNTAX: return "syntax error"; case UB_SERVFAIL: return "server failure"; + case UB_FORKFAIL: return "could not fork"; case UB_INITFAIL: return "initialization failure"; + case UB_AFTERFINAL: return "setting change after finalize"; default: return "unknown error"; } } diff --git a/libunbound/unbound.h b/libunbound/unbound.h index 4a6d5b6c6..8efab283e 100644 --- a/libunbound/unbound.h +++ b/libunbound/unbound.h @@ -281,6 +281,7 @@ int ub_val_ctx_process(struct ub_val_ctx* ctx); /** * Perform resolution and validation of the target name. * @param ctx: context. + * The context is finalized, and can no longer accept config changes. * @param name: domain name in text format (a zero terminated text string). * @param rrtype: type of RR in host order, 1 is A (address). * @param rrclass: class of RR in host order, 1 is IN (for internet). @@ -305,6 +306,7 @@ int ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype, * @param ctx: context. * If no thread or process has been created yet to perform the * work in the background, it is created now. + * The context is finalized, and can no longer accept config changes. * @param name: domain name in text format (a string). * @param rrtype: type of RR in host order, 1 is A. * @param rrclass: class of RR in host order, 1 is IN (for internet). diff --git a/libunbound/worker.c b/libunbound/worker.c index a4d9564bf..087d39d20 100644 --- a/libunbound/worker.c +++ b/libunbound/worker.c @@ -45,39 +45,109 @@ #include "libunbound/worker.h" #include "libunbound/context.h" #include "libunbound/unbound.h" +#include "services/outside_network.h" +#include "services/mesh.h" +#include "services/cache/rrset.h" +#include "services/outbound_list.h" +#include "util/module.h" +#include "util/regional.h" +#include "util/random.h" +#include "util/config_file.h" +#include "util/netevent.h" +#include "util/storage/slabhash.h" +#include "util/net_help.h" +#include "util/data/dname.h" + +/** size of table used for random numbers. large to be more secure. */ +#define RND_STATE_SIZE 256 /** delete libworker struct */ static void libworker_delete(struct libworker* w) { if(!w) return; - lock_basic_lock(&w->ctx->cfglock); - /* return alloc */ - lock_basic_unlock(&w->ctx->cfglock); - + if(w->env) { + mesh_delete(w->env->mesh); + context_release_alloc(w->ctx, w->env->alloc); + ldns_buffer_free(w->env->scratch_buffer); + regional_destroy(w->env->scratch); + ub_randfree(w->env->rnd); + free(w->env->rnd); + free(w->env); + } + outside_network_delete(w->back); + comm_base_delete(w->base); + free(w); } /** setup fresh libworker struct */ static struct libworker* libworker_setup(struct ub_val_ctx* ctx) { + unsigned int seed; struct libworker* w = (struct libworker*)calloc(1, sizeof(*w)); + struct config_file* cfg = ctx->env->cfg; if(!w) return NULL; w->ctx = ctx; - lock_basic_lock(&ctx->cfglock); - /* obtain a new alloc */ - lock_basic_unlock(&ctx->cfglock); - /* setup event base */ - /* setup outnet */ - /* setup rnd */ - /* setup env */ - /* setup env.scratch */ - /* setup env.scratch_buffer */ - /* setup env.worker */ - /* setup env.mesh */ - /* setup env.alloc */ - /* setup env.rnd */ - /* setup env - callback ptrs */ + w->env = (struct module_env*)malloc(sizeof(*w->env)); + if(!w->env) { + free(w); + return NULL; + } + *w->env = *ctx->env; + w->env->alloc = context_obtain_alloc(ctx); + if(!w->env->alloc) { + libworker_delete(w); + return NULL; + } + alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w); + w->env->scratch = regional_create_custom(cfg->msg_buffer_size); + w->env->scratch_buffer = ldns_buffer_new(cfg->msg_buffer_size); + if(!w->env->scratch || !w->env->scratch_buffer) { + libworker_delete(w); + return NULL; + } + w->env->rnd = (struct ub_randstate*)calloc(1, sizeof(*w->env->rnd)); + if(!w->env->rnd) { + libworker_delete(w); + return NULL; + } + w->env->worker = (struct worker*)w; + seed = (unsigned int)time(NULL) ^ (unsigned int)getpid() ^ + (((unsigned int)w->thread_num)<<17); + seed ^= (unsigned int)w->env->alloc->next_id; + if(!ub_initstate(seed, w->env->rnd, RND_STATE_SIZE)) { + seed = 0; + libworker_delete(w); + return NULL; + } + seed = 0; + + w->base = comm_base_create(); + if(!w->base) { + libworker_delete(w); + return NULL; + } + w->back = outside_network_create(w->base, cfg->msg_buffer_size, + (size_t)cfg->outgoing_num_ports, cfg->out_ifs, + cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, -1, + cfg->do_tcp?cfg->outgoing_num_tcp:0, + w->env->infra_cache, w->env->rnd); + if(!w->back) { + libworker_delete(w); + return NULL; + } + w->env->mesh = mesh_create(&ctx->mods, w->env); + if(!w->env->mesh) { + libworker_delete(w); + return NULL; + } + w->env->send_packet = &libworker_send_packet; + w->env->send_query = &libworker_send_query; + w->env->detach_subs = &mesh_detach_subs; + w->env->attach_sub = &mesh_attach_sub; + w->env->kill_sub = &mesh_state_delete; + w->env->detect_cycle = &mesh_detect_cycle; return w; } @@ -96,38 +166,350 @@ libworker_dobg(void* arg) int libworker_bg(struct ub_val_ctx* ctx) { /* fork or threadcreate */ - lock_basic_lock(&ctx->cfglock); if(ctx->dothread) { - ub_thread_t t; - lock_basic_unlock(&ctx->cfglock); - ub_thread_create(&t, libworker_dobg, ctx); - /* ctx.tid = t or so */ + ub_thread_create(&ctx->bg_tid, libworker_dobg, ctx); } else { - pid_t p; - lock_basic_unlock(&ctx->cfglock); - switch((p=fork())) { + switch((ctx->bg_pid=fork())) { case 0: + lock_basic_unlock(&ctx->cfglock); (void)libworker_dobg(ctx); exit(0); break; case -1: - /* TODO make UB_FORKFAILED */ - return UB_SOCKET; + lock_basic_unlock(&ctx->cfglock); + return UB_FORKFAIL; default: - /* ctx.pid = p or so */ break; } } + lock_basic_unlock(&ctx->cfglock); return UB_NOERROR; } +/** get msg reply struct (in temp region) */ +static struct reply_info* +parse_reply(ldns_buffer* pkt, struct regional* region, struct query_info* qi) +{ + struct reply_info* rep; + struct msg_parse* msg; + if(!(msg = regional_alloc(region, sizeof(*msg)))) { + return NULL; + } + memset(msg, 0, sizeof(*msg)); + ldns_buffer_set_position(pkt, 0); + if(parse_packet(pkt, msg, region) != 0) + return 0; + if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) { + return 0; + } + return rep; +} + +/** fill data into result */ +static int +fill_res(struct ub_val_result* res, struct ub_packed_rrset_key* answer, + struct query_info* rq) +{ + size_t i; + struct packed_rrset_data* data; + if(!answer) { + res->data = calloc(1, sizeof(char*)); + res->len = calloc(1, sizeof(size_t)); + return (res->data && res->len); + } + data = (struct packed_rrset_data*)answer->entry.data; + if(query_dname_compare(rq->qname, answer->rk.dname) != 0) { + char buf[255+2]; + dname_str(answer->rk.dname, buf); + res->canonname = strdup(buf); + if(!res->canonname) + return 0; /* out of memory */ + } else + res->canonname = res->qname; + res->data = calloc(data->count+1, sizeof(char*)); + res->len = calloc(data->count+1, sizeof(size_t)); + if(!res->data || !res->len) + return 0; /* out of memory */ + for(i=0; icount; i++) { + /* remove rdlength from rdata */ + res->len[i] = data->rr_len[i] - 2; + res->data[i] = memdup(data->rr_data[i]+2, res->len[i]); + if(!res->data[i]) + return 0; /* out of memory */ + } + res->data[data->count] = NULL; + res->len[data->count] = 0; + return 1; +} + +/** callback with fg results */ +static void +libworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s) +{ + struct query_info rq; /* replied query */ + struct reply_info* rep; + struct libworker_fg_data* d = (struct libworker_fg_data*)arg; + /* fg query is done; exit comm base */ + comm_base_exit(d->w->base); + + if(rcode != 0) { + d->q->res->rcode = rcode; + d->q->msg_security = 0; + return; + } + + d->q->res->rcode = LDNS_RCODE_SERVFAIL; + d->q->msg_security = 0; + d->q->msg = memdup(ldns_buffer_begin(buf), ldns_buffer_limit(buf)); + d->q->msg_len = ldns_buffer_limit(buf); + if(!d->q->msg) { + return; /* error in rcode */ + } + + /* canonname and results */ + rep = parse_reply(buf, d->w->env->scratch, &rq); + if(!rep) { + return; /* error parsing buf, or out of memory */ + } + /* log_dns_msg("fg reply", &rq, rep); @@@ DEBUG */ + if(!fill_res(d->q->res, reply_find_answer_rrset(&rq, rep), &rq)) + return; /* out of memory */ + /* rcode, nxdomain, bogus */ + d->q->res->rcode = (int)LDNS_RCODE_WIRE(d->q->msg); + if(d->q->res->rcode == LDNS_RCODE_NXDOMAIN) + d->q->res->nxdomain = 1; + if(d->q->msg_security == sec_status_bogus) + d->q->res->bogus = 1; + + d->q->msg_security = s; +} + +/** setup qinfo and edns */ +static int +setup_qinfo_edns(struct libworker* w, struct ctx_query* q, + struct query_info* qinfo, struct edns_data* edns) +{ + ldns_rdf* rdf; + qinfo->qtype = (uint16_t)q->res->qtype; + qinfo->qclass = (uint16_t)q->res->qclass; + rdf = ldns_dname_new_frm_str(q->res->qname); + if(!rdf) { + return 0; + } + qinfo->qname = ldns_rdf_data(rdf); + qinfo->qname_len = ldns_rdf_size(rdf); + edns->edns_present = 1; + edns->ext_rcode = 0; + edns->edns_version = 0; + edns->bits = EDNS_DO; + if(ldns_buffer_capacity(w->back->udp_buff) < 65535) + edns->udp_size = (uint16_t)ldns_buffer_capacity( + w->back->udp_buff); + else edns->udp_size = 65535; + ldns_rdf_free(rdf); + return 1; +} + int libworker_fg(struct ub_val_ctx* ctx, struct ctx_query* q) { struct libworker* w = libworker_setup(ctx); + uint16_t qflags, qid; + struct query_info qinfo; + struct edns_data edns; + struct libworker_fg_data d; if(!w) + return UB_INITFAIL; + if(!setup_qinfo_edns(w, q, &qinfo, &edns)) { + libworker_delete(w); + return UB_SYNTAX; + } + qid = 0; + qflags = BIT_RD; + d.q = q; + d.w = w; + if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, + w->back->udp_buff, qid, libworker_fg_done_cb, &d)) { + free(qinfo.qname); return UB_NOMEM; - /* TODO */ - q->res->bogus = 1; + } + free(qinfo.qname); + comm_base_dispatch(w->base); libworker_delete(w); return UB_NOERROR; } + +void libworker_alloc_cleanup(void* arg) +{ + struct libworker* w = (struct libworker*)arg; + slabhash_clear(&w->env->rrset_cache->table); + slabhash_clear(w->env->msg_cache); +} + +int libworker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr, + socklen_t addrlen, int timeout, struct module_qstate* q, int use_tcp) +{ + struct libworker* w = (struct libworker*)q->env->worker; + if(use_tcp) { + return pending_tcp_query(w->back, pkt, addr, addrlen, + timeout, libworker_handle_reply, q, + q->env->rnd) != 0; + } + return pending_udp_query(w->back, pkt, addr, addrlen, + timeout*1000, libworker_handle_reply, q, + q->env->rnd) != 0; +} + +/** compare outbound entry qstates */ +static int +outbound_entry_compare(void* a, void* b) +{ + struct outbound_entry* e1 = (struct outbound_entry*)a; + struct outbound_entry* e2 = (struct outbound_entry*)b; + if(e1->qstate == e2->qstate) + return 1; + return 0; +} + +struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, + uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, + struct sockaddr_storage* addr, socklen_t addrlen, + struct module_qstate* q) +{ + struct libworker* w = (struct libworker*)q->env->worker; + struct outbound_entry* e = (struct outbound_entry*)regional_alloc( + q->region, sizeof(*e)); + if(!e) + return NULL; + e->qstate = q; + e->qsent = outnet_serviced_query(w->back, qname, + qnamelen, qtype, qclass, flags, dnssec, addr, addrlen, + libworker_handle_service_reply, e, w->back->udp_buff, + &outbound_entry_compare); + if(!e->qsent) { + return NULL; + } + return e; +} + +int +libworker_handle_reply(struct comm_point* c, void* arg, int error, + struct comm_reply* reply_info) +{ + struct module_qstate* q = (struct module_qstate*)arg; + struct libworker* lw = (struct libworker*)q->env->worker; + struct outbound_entry e; + e.qstate = q; + e.qsent = NULL; + + if(error != 0) { + mesh_report_reply(lw->env->mesh, &e, 0, reply_info); + return 0; + } + /* sanity check. */ + if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer)) + || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) != + LDNS_PACKET_QUERY + || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { + /* error becomes timeout for the module as if this reply + * never arrived. */ + mesh_report_reply(lw->env->mesh, &e, 0, reply_info); + return 0; + } + mesh_report_reply(lw->env->mesh, &e, 1, reply_info); + return 0; +} + +int +libworker_handle_service_reply(struct comm_point* c, void* arg, int error, + struct comm_reply* reply_info) +{ + struct outbound_entry* e = (struct outbound_entry*)arg; + struct libworker* lw = (struct libworker*)e->qstate->env->worker; + + if(error != 0) { + mesh_report_reply(lw->env->mesh, e, 0, reply_info); + return 0; + } + /* sanity check. */ + if(!LDNS_QR_WIRE(ldns_buffer_begin(c->buffer)) + || LDNS_OPCODE_WIRE(ldns_buffer_begin(c->buffer)) != + LDNS_PACKET_QUERY + || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { + /* error becomes timeout for the module as if this reply + * never arrived. */ + mesh_report_reply(lw->env->mesh, e, 0, reply_info); + return 0; + } + mesh_report_reply(lw->env->mesh, e, 1, reply_info); + return 0; +} + +/* --- fake callbacks for fptr_wlist to work --- */ +int worker_handle_control_cmd(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(reply_info)) +{ + log_assert(0); + return 0; +} + +int worker_handle_request(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(repinfo)) +{ + log_assert(0); + return 0; +} + +int worker_handle_reply(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(reply_info)) +{ + log_assert(0); + return 0; +} + +int worker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(reply_info)) +{ + log_assert(0); + return 0; +} + +void worker_sighandler(int ATTR_UNUSED(sig), void* ATTR_UNUSED(arg)) +{ + log_assert(0); +} + +int worker_send_packet(ldns_buffer* ATTR_UNUSED(pkt), + struct sockaddr_storage* ATTR_UNUSED(addr), + socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(timeout), + struct module_qstate* ATTR_UNUSED(q), int ATTR_UNUSED(use_tcp)) +{ + log_assert(0); + return 0; +} + +struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname), + size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), + uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), + int ATTR_UNUSED(dnssec), struct sockaddr_storage* ATTR_UNUSED(addr), + socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q)) +{ + log_assert(0); + return 0; +} + +void +worker_alloc_cleanup(void* ATTR_UNUSED(arg)) +{ + log_assert(0); +} + +int +acl_list_cmp(const void* ATTR_UNUSED(k1), const void* ATTR_UNUSED(k2)) +{ + log_assert(0); + return 0; +} diff --git a/libunbound/worker.h b/libunbound/worker.h index 8a00bf44f..dae67da43 100644 --- a/libunbound/worker.h +++ b/libunbound/worker.h @@ -49,6 +49,10 @@ struct comm_base; struct outside_network; struct ub_randstate; struct ctx_query; +struct outbound_entry; +struct module_qstate; +struct comm_point; +struct comm_reply; /** * The library-worker status structure @@ -72,8 +76,16 @@ struct libworker { /** random() table for this worker. */ struct ub_randstate* rndstate; - /** do we need to exit (when done) */ - int need_to_exit; +}; + +/** + * Foreground query cb struct + */ +struct libworker_fg_data { + /** the worker involved */ + struct libworker* w; + /** the query involved */ + struct ctx_query* q; }; /** @@ -97,4 +109,48 @@ int libworker_bg(struct ub_val_ctx* ctx); */ int libworker_fg(struct ub_val_ctx* ctx, struct ctx_query* q); +/** cleanup the cache to remove all rrset IDs from it, arg is libworker */ +void libworker_alloc_cleanup(void* arg); + +/** + * Worker service routine to send udp messages for modules. + * @param pkt: packet to send. + * @param addr: where to. + * @param addrlen: length of addr. + * @param timeout: seconds to wait until timeout. + * @param q: wich query state to reactivate upon return. + * @param use_tcp: true to use TCP, false for UDP. + * @return: false on failure (memory or socket related). no query was + * sent. + */ +int libworker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr, + socklen_t addrlen, int timeout, struct module_qstate* q, int use_tcp); + +/** + * Worker service routine to send serviced queries to authoritative servers. + * @param qname: query name. (host order) + * @param qnamelen: length in bytes of qname, including trailing 0. + * @param qtype: query type. (host order) + * @param qclass: query class. (host order) + * @param flags: host order flags word, with opcode and CD bit. + * @param dnssec: if set, EDNS record will have DO bit set. + * @param addr: where to. + * @param addrlen: length of addr. + * @param q: wich query state to reactivate upon return. + * @return: false on failure (memory or socket related). no query was + * sent. + */ +struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen, + uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec, + struct sockaddr_storage* addr, socklen_t addrlen, + struct module_qstate* q); + +/** process incoming replies from the network */ +int libworker_handle_reply(struct comm_point* c, void* arg, int error, + struct comm_reply* reply_info); + +/** process incoming serviced query replies from the network */ +int libworker_handle_service_reply(struct comm_point* c, void* arg, int error, + struct comm_reply* reply_info); + #endif /* LIBUNBOUND_WORKER_H */ diff --git a/services/mesh.c b/services/mesh.c index 3f6f570a6..a8222056e 100644 --- a/services/mesh.c +++ b/services/mesh.c @@ -155,9 +155,9 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, mesh->num_detached_states++; added = 1; } - if(!s->reply_list && s->super_set.count == 0) + if(!s->reply_list && !s->cb_list && s->super_set.count == 0) was_detached = 1; - if(!s->reply_list) + if(!s->reply_list && !s->cb_list) was_noreply = 1; /* add reply to s */ if(!mesh_state_add_reply(s, edns, rep, qid, qflags)) { @@ -182,6 +182,52 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, mesh_run(mesh, s, module_event_new, NULL); } +int +mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, + uint16_t qflags, struct edns_data* edns, ldns_buffer* buf, + uint16_t qid, mesh_cb_func_t cb, void* cb_arg) +{ + struct mesh_state* s = mesh_area_find(mesh, qinfo, qflags, 0); + int was_detached = 0; + int was_noreply = 0; + int added = 0; + /* see if it already exists, if not, create one */ + if(!s) { + struct rbnode_t* n; + s = mesh_state_create(mesh->env,qinfo, qflags, 0); + if(!s) { + return 0; + } + n = rbtree_insert(&mesh->all, &s->node); + log_assert(n != NULL); + /* set detached (it is now) */ + mesh->num_detached_states++; + added = 1; + } + if(!s->reply_list && !s->cb_list && s->super_set.count == 0) + was_detached = 1; + if(!s->reply_list && !s->cb_list) + was_noreply = 1; + /* add reply to s */ + if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) { + if(added) + mesh_state_delete(&s->s); + return 0; + } + /* update statistics */ + if(was_detached) { + log_assert(mesh->num_detached_states > 0); + mesh->num_detached_states--; + } + if(was_noreply) { + mesh->num_reply_states ++; + } + mesh->num_reply_addrs++; + if(added) + mesh_run(mesh, s, module_event_new, NULL); + return 1; +} + void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, int is_ok, struct comm_reply* reply) { @@ -271,11 +317,12 @@ mesh_state_delete(struct module_qstate* qstate) mstate = qstate->mesh_info; mesh = mstate->s.env->mesh; mesh_detach_subs(&mstate->s); - if(!mstate->reply_list && mstate->super_set.count == 0) { + if(!mstate->reply_list && !mstate->cb_list + && mstate->super_set.count == 0) { log_assert(mesh->num_detached_states > 0); mesh->num_detached_states--; } - if(mstate->reply_list) { + if(mstate->reply_list || mstate->cb_list) { log_assert(mesh->num_reply_states > 0); mesh->num_reply_states--; } @@ -299,7 +346,8 @@ void mesh_detach_subs(struct module_qstate* qstate) RBTREE_FOR(ref, struct mesh_state_ref*, &qstate->mesh_info->sub_set) { n = rbtree_delete(&ref->s->super_set, &lookup); log_assert(n != NULL); /* must have been present */ - if(!ref->s->reply_list && ref->s->super_set.count == 0) { + if(!ref->s->reply_list && !ref->s->cb_list + && ref->s->super_set.count == 0) { mesh->num_detached_states++; log_assert(mesh->num_detached_states + mesh->num_reply_states <= mesh->all.count); @@ -334,7 +382,7 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo, *newq = NULL; if(!mesh_state_attachment(qstate->mesh_info, sub)) return 0; - if(!sub->reply_list && sub->super_set.count == 1) { + if(!sub->reply_list && !sub->cb_list && sub->super_set.count == 1) { /* it used to be detached, before this one got added */ log_assert(mesh->num_detached_states > 0); mesh->num_detached_states--; @@ -413,6 +461,49 @@ timeval_divide(struct timeval* avg, struct timeval* sum, size_t d) #endif } +/** + * callback results to mesh cb entry + * @param m: mesh state to send it for. + * @param rcode: if not 0, error code. + * @param rep: reply to send (or NULL if rcode is set). + * @param r: callback entry + */ +static void +mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep, + struct mesh_cb* r) +{ + int secure; + /* bogus messages are not made into servfail, sec_status passed + * to the callback function */ + if(rep && rep->security == sec_status_secure) + secure = 1; + else secure = 0; + if(!rep && rcode == LDNS_RCODE_NOERROR) + rcode = LDNS_RCODE_SERVFAIL; + /* send the reply */ + if(rcode) { + (*r->cb)(r->cb_arg, rcode, r->buf, sec_status_unchecked); + } else { + size_t udp_size = r->edns.udp_size; + ldns_buffer_clear(r->buf); + r->edns.edns_version = EDNS_ADVERTISED_VERSION; + r->edns.udp_size = EDNS_ADVERTISED_SIZE; + r->edns.ext_rcode = 0; + r->edns.bits &= EDNS_DO; + if(!reply_info_answer_encode(&m->s.qinfo, rep, r->qid, + r->qflags, r->buf, 0, 1, + m->s.env->scratch, udp_size, &r->edns, + (int)(r->edns.bits & EDNS_DO), secure)) + { + (*r->cb)(r->cb_arg, LDNS_RCODE_SERVFAIL, r->buf, + sec_status_unchecked); + } + else (*r->cb)(r->cb_arg, LDNS_RCODE_NOERROR, r->buf, + rep->security); + } + m->s.env->mesh->num_reply_addrs--; +} + /** * Send reply to mesh reply entry * @param m: mesh state to send it for. @@ -477,11 +568,15 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep, void mesh_query_done(struct mesh_state* mstate) { struct mesh_reply* r; + struct mesh_cb* c; struct reply_info* rep = (mstate->s.return_msg? mstate->s.return_msg->rep:NULL); for(r = mstate->reply_list; r; r = r->next) { mesh_send_reply(mstate, mstate->s.return_rcode, rep, r); } + for(c = mstate->cb_list; c; c = c->next) { + mesh_do_callback(mstate, mstate->s.return_rcode, rep, c); + } } void mesh_walk_supers(struct mesh_area* mesh, struct mesh_state* mstate) @@ -514,6 +609,26 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh, return result; } +int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, + ldns_buffer* buf, mesh_cb_func_t cb, void* cb_arg, + uint16_t qid, uint16_t qflags) +{ + struct mesh_cb* r = regional_alloc(s->s.region, + sizeof(struct mesh_cb)); + if(!r) + return 0; + r->buf = buf; + r->cb = cb; + r->cb_arg = cb_arg; + r->edns = *edns; + r->qid = qid; + r->qflags = qflags; + r->next = s->cb_list; + s->cb_list = r; + return 1; + +} + int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, struct comm_reply* rep, uint16_t qid, uint16_t qflags) { @@ -637,13 +752,15 @@ mesh_log_list(struct mesh_area* mesh) struct mesh_state* m; int num = 0; RBTREE_FOR(m, struct mesh_state*, &mesh->all) { - snprintf(buf, sizeof(buf), "%d%s%s%s%s%s mod%d %s", + snprintf(buf, sizeof(buf), "%d%s%s%s%s%s mod%d %s%s", num++, (m->s.is_priming)?"p":"", /* prime */ (m->s.query_flags&BIT_RD)?"RD":"", (m->s.query_flags&BIT_CD)?"CD":"", (m->super_set.count==0)?"d":"", /* detached */ (m->sub_set.count!=0)?"c":"", /* children */ - m->s.curmod, (m->reply_list)?"hr":"nr"); /*hasreply*/ + m->s.curmod, (m->reply_list)?"rep":"", /*hasreply*/ + (m->cb_list)?"cb":"" /* callbacks */ + ); log_query_info(VERB_ALGO, buf, &m->s.qinfo); } } diff --git a/services/mesh.h b/services/mesh.h index 7ba98732f..46d4372b7 100644 --- a/services/mesh.h +++ b/services/mesh.h @@ -53,6 +53,7 @@ #include "services/modstack.h" struct mesh_state; struct mesh_reply; +struct mesh_cb; struct query_info; struct reply_info; struct outbound_entry; @@ -116,6 +117,8 @@ struct mesh_state { struct module_qstate s; /** the list of replies to clients for the results */ struct mesh_reply* reply_list; + /** the list of callbacks for the results */ + struct mesh_cb* cb_list; /** set of superstates (that want this state's result) * contains struct mesh_state_ref* */ rbtree_t super_set; @@ -155,6 +158,35 @@ struct mesh_reply { uint16_t qflags; }; +/** + * Mesh result callback func. + * called as func(cb_arg, rcode, buffer_with_reply, security); + * */ +typedef void (*mesh_cb_func_t)(void*, int, ldns_buffer*, enum sec_status); + +/** + * Callback to result routine + */ +struct mesh_cb { + /** next in list */ + struct mesh_cb* next; + /** edns data from query */ + struct edns_data edns; + /** id of query, in network byteorder. */ + uint16_t qid; + /** flags of query, for reply flags */ + uint16_t qflags; + /** buffer for reply */ + ldns_buffer* buf; + + /** callback routine for results. if rcode != 0 buf has message. + * called as cb(cb_arg, rcode, buf); + */ + mesh_cb_func_t cb; + /** user arg for callback */ + void* cb_arg; +}; + /* ------------------- Functions for worker -------------------- */ /** @@ -188,6 +220,25 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo, uint16_t qflags, struct edns_data* edns, struct comm_reply* rep, uint16_t qid); +/** + * New query with callback. Create new query state if needed, and + * add mesh_cb to it. + * Will run the mesh area queries to process if a new query state is created. + * + * @param mesh: the mesh. + * @param qinfo: query from client. + * @param qflags: flags from client query. + * @param edns: edns data from client query. + * @param buf: buffer for reply contents. + * @param qid: query id to reply with. + * @param cb: callback function. + * @param cb_arg: callback user arg. + * @return 0 on error. + */ +int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, + uint16_t qflags, struct edns_data* edns, ldns_buffer* buf, + uint16_t qid, mesh_cb_func_t cb, void* cb_arg); + /** * Handle new event from the wire. A serviced query has returned. * The query state will be made runnable, and the mesh_area will process @@ -329,6 +380,22 @@ int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub); int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns, struct comm_reply* rep, uint16_t qid, uint16_t qflags); +/** + * Create new callback structure and attach it to a mesh state. + * Does not update stat items in mesh area. + * @param s: the mesh state. + * @param edns: edns data for reply (bufsize). + * @param buf: buffer for reply + * @param cb: callback to call with results. + * @param cb_arg: callback user arg. + * @param qid: ID of reply. + * @param qflags: original query flags. + * @return: 0 on alloc error. + */ +int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns, + ldns_buffer* buf, mesh_cb_func_t cb, void* cb_arg, uint16_t qid, + uint16_t qflags); + /** * Run the mesh. Run all runnable mesh states. Which can create new * runnable mesh states. Until completion. Automatically called by diff --git a/services/outside_network.c b/services/outside_network.c index da1dd5462..9bee14885 100644 --- a/services/outside_network.c +++ b/services/outside_network.c @@ -288,6 +288,11 @@ open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint) char portstr[32]; if(porthint != -1) snprintf(portstr, sizeof(portstr), "%d", porthint); + else if(!ifname) { + if(hints->ai_family == AF_INET) + ifname = "0.0.0.0"; + else ifname="::"; + } if((r=getaddrinfo(ifname, ((porthint==-1)?NULL:portstr), hints, &res)) != 0 || !res) { diff --git a/smallapp/unbound-host.c b/smallapp/unbound-host.c index af4e93f68..0babe60d3 100644 --- a/smallapp/unbound-host.c +++ b/smallapp/unbound-host.c @@ -44,6 +44,9 @@ #include "libunbound/unbound.h" #include +/** verbosity for unbound-host app */ +static int verb = 0; + /** Give unbound-host usage, and exit (1). */ static void usage() @@ -54,6 +57,7 @@ usage() printf(" If an ip-address is given a reverse lookup is done.\n"); printf("-t type what type to look for.\n"); printf("-c class what class to look for, if not class IN.\n"); + printf("-v be more verbose.\n"); printf("-h show this usage help.\n"); printf("Version %s\n", PACKAGE_VERSION); printf("BSD licensed, see LICENSE in source package for details.\n"); @@ -204,11 +208,55 @@ pretty_rcode(char* s, size_t len, int r) } } +/** convert and print rdata */ +static void +print_rd(int t, char* data, size_t len) +{ + /* + size_t i, pos = 0; + ldns_status status; + ldns_rr* rr = ldns_rr_new_frm_type(t); + ldns_rr_set_owner(rr, NULL); + status = ldns_wire2rdf(rr, (uint8_t*)data, len, &pos); + if(status != LDNS_STATUS_OK) { + + printf("error_printing_data"); + } + printf("len = %d\n", len); + for(i=0; ircode, rcodestr, secstatus); return; } + if(docname && result->canonname && + result->canonname != result->qname) + printf("%s is an alias for %s\n", result->qname, + result->canonname); if(!haved) { - printf("%s %s %s: no data. %s\n", - q, cstr, tstr, secstatus); + if(verb > 0) + printf("%s %s %s: no data. %s\n", + q, cstr, tstr, secstatus); + /* else: emptiness to indicate no data */ return; } - printf("%s %s %s: have data. %s\n", - q, cstr, tstr, secstatus); - /* TODO print the data nicely */ + i=0; + while(result->data[i]) + { + pretty_rdata( + result->canonname?result->canonname:q, + cstr, tstr, t, secstatus, result->data[i], + result->len[i]); + i++; + } } /** perform a lookup and printout return if domain existed */ static int -dnslook(struct ub_val_ctx* ctx, char* q, int t, int c) +dnslook(struct ub_val_ctx* ctx, char* q, int t, int c, int docname) { int ret, sec, haved; struct ub_val_result* result; ret = ub_val_resolve(ctx, q, t, c, &sec, &haved, &result); if(ret != 0) { - fprintf(stderr, "error: %s\n", ub_val_strerror(ret)); + fprintf(stderr, "resolve error: %s\n", ub_val_strerror(ret)); exit(1); } - pretty_output(q, t, c, sec, haved, result); + pretty_output(q, t, c, sec, haved, result, docname); ret = result->nxdomain; ub_val_result_free(result); return ret; @@ -264,21 +324,22 @@ lookup(const char* nm, const char* qt, const char* qc) /* perform the query */ struct ub_val_ctx* ctx = NULL; - printf("lookup %s %d %d reverse=%d multi=%d\n", - realq, t, c, reverse, multi); + if(verb>0) + printf("lookup %s %d %d reverse=%d multi=%d\n", + realq, t, c, reverse, multi); ctx = ub_val_ctx_create(); if(!ctx) { fprintf(stderr, "error: out of memory\n"); exit(1); } if(multi) { - if(!dnslook(ctx, realq, LDNS_RR_TYPE_A, c)) { + if(!dnslook(ctx, realq, LDNS_RR_TYPE_A, c, 1)) { /* domain exists, lookup more */ - (void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c); - (void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c); + (void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c, 0); + (void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c, 0); } } else { - (void)dnslook(ctx, realq, t, c); + (void)dnslook(ctx, realq, t, c, 1); } ub_val_ctx_delete(ctx); free(realq); @@ -296,7 +357,7 @@ int main(int argc, char* argv[]) char* qclass = NULL; char* qtype = NULL; /* parse the options */ - while( (c=getopt(argc, argv, "c:ht:")) != -1) { + while( (c=getopt(argc, argv, "c:ht:v")) != -1) { switch(c) { case 'c': qclass = optarg; @@ -304,6 +365,9 @@ int main(int argc, char* argv[]) case 't': qtype = optarg; break; + case 'v': + verb++; + break; case '?': case 'h': default: diff --git a/smallapp/worker_cb.c b/smallapp/worker_cb.c index fb7dbd091..6e6b74f75 100644 --- a/smallapp/worker_cb.c +++ b/smallapp/worker_cb.c @@ -114,3 +114,44 @@ acl_list_cmp(const void* ATTR_UNUSED(k1), const void* ATTR_UNUSED(k2)) log_assert(0); return 0; } + +int libworker_send_packet(ldns_buffer* ATTR_UNUSED(pkt), + struct sockaddr_storage* ATTR_UNUSED(addr), + socklen_t ATTR_UNUSED(addrlen), int ATTR_UNUSED(timeout), + struct module_qstate* ATTR_UNUSED(q), int ATTR_UNUSED(use_tcp)) +{ + log_assert(0); + return 0; +} + +struct outbound_entry* libworker_send_query(uint8_t* ATTR_UNUSED(qname), + size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype), + uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags), + int ATTR_UNUSED(dnssec), struct sockaddr_storage* ATTR_UNUSED(addr), + socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q)) +{ + log_assert(0); + return 0; +} + +int libworker_handle_reply(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(reply_info)) +{ + log_assert(0); + return 0; +} + +int libworker_handle_service_reply(struct comm_point* ATTR_UNUSED(c), + void* ATTR_UNUSED(arg), int ATTR_UNUSED(error), + struct comm_reply* ATTR_UNUSED(reply_info)) +{ + log_assert(0); + return 0; +} + +int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b)) +{ + log_assert(0); + return 0; +} diff --git a/util/config_file.c b/util/config_file.c index fd6cb61ac..ca5e73d74 100644 --- a/util/config_file.c +++ b/util/config_file.c @@ -45,6 +45,7 @@ #include "util/configyyrename.h" #include "util/config_file.h" #include "util/configparser.h" +#include "util/net_help.h" /** global config during parsing */ struct config_parser_state* cfg_parser = 0; /** lex in file */ @@ -139,6 +140,24 @@ error_exit: return NULL; } +struct config_file* config_create_forlib() +{ + struct config_file* cfg = config_create(); + if(!cfg) return NULL; + /* modifications for library use, less verbose, less memory */ + cfg->verbosity = 0; + cfg->outgoing_num_tcp = 2; + cfg->msg_cache_size = 1024*1024; + cfg->msg_cache_slabs = 1; + cfg->rrset_cache_size = 1024*1024; + cfg->rrset_cache_slabs = 1; + cfg->infra_cache_slabs = 1; + cfg->use_syslog = 0; + cfg->key_cache_size = 1024*1024; + cfg->key_cache_slabs = 1; + return cfg; +} + /** initialize the global cfg_parser object */ static void create_cfg_parser(struct config_file* cfg, char* filename) @@ -375,3 +394,4 @@ config_apply(struct config_file* config) { MAX_TTL = (uint32_t)config->max_ttl; } + diff --git a/util/config_file.h b/util/config_file.h index 940450b0c..4ed90b378 100644 --- a/util/config_file.h +++ b/util/config_file.h @@ -239,6 +239,12 @@ struct config_str2list { */ struct config_file* config_create(); +/** + * Create config file structure for library use. Filled with default values. + * @return: the new structure or NULL on memory error. + */ +struct config_file* config_create_forlib(); + /** * Read the config file from the specified filename. * @param config: where options are stored into, must be freshly created. diff --git a/util/fptr_wlist.c b/util/fptr_wlist.c index abb7e29a9..21a292f1e 100644 --- a/util/fptr_wlist.c +++ b/util/fptr_wlist.c @@ -67,6 +67,8 @@ #include "util/locks.h" #include "testcode/checklocks.h" #include "daemon/acl_list.h" +#include "libunbound/worker.h" +#include "libunbound/context.h" int fptr_whitelist_comm_point(comm_point_callback_t *fptr) @@ -110,6 +112,7 @@ fptr_whitelist_pending_udp(comm_point_callback_t *fptr) { if(fptr == &serviced_udp_callback) return 1; else if(fptr == &worker_handle_reply) return 1; + else if(fptr == &libworker_handle_reply) return 1; return 0; } @@ -118,6 +121,7 @@ fptr_whitelist_pending_tcp(comm_point_callback_t *fptr) { if(fptr == &serviced_tcp_callback) return 1; else if(fptr == &worker_handle_reply) return 1; + else if(fptr == &libworker_handle_reply) return 1; return 0; } @@ -125,6 +129,7 @@ int fptr_whitelist_serviced_query(comm_point_callback_t *fptr) { if(fptr == &worker_handle_service_reply) return 1; + else if(fptr == &libworker_handle_service_reply) return 1; return 0; } @@ -147,6 +152,7 @@ fptr_whitelist_rbtree_cmp(int (*fptr) (const void *, const void *)) else if(fptr == &mini_ev_cmp) return 1; else if(fptr == &anchor_cmp) return 1; else if(fptr == &canonical_tree_compare) return 1; + else if(fptr == &context_query_cmp) return 1; return 0; } @@ -212,6 +218,7 @@ fptr_whitelist_modenv_send_packet(int (*fptr)(ldns_buffer* pkt, struct module_qstate* q, int use_tcp)) { if(fptr == &worker_send_packet) return 1; + else if(fptr == &libworker_send_packet) return 1; return 0; } @@ -222,6 +229,7 @@ fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)( socklen_t addrlen, struct module_qstate* q)) { if(fptr == &worker_send_query) return 1; + else if(fptr == &libworker_send_query) return 1; return 0; } diff --git a/util/log.c b/util/log.c index a63080947..a0304c2ef 100644 --- a/util/log.c +++ b/util/log.c @@ -195,6 +195,7 @@ fatal_exit(const char *format, ...) va_start(args, format); log_vmsg(LOG_CRIT, "fatal error", format, args); va_end(args); + abort(); exit(1); } diff --git a/util/netevent.c b/util/netevent.c index 7fdc8e008..3d61a27c0 100644 --- a/util/netevent.c +++ b/util/netevent.c @@ -168,7 +168,7 @@ comm_point_send_udp_msg(struct comm_point *c, ldns_buffer* packet, ldns_buffer_remaining(packet), 0, addr, addrlen); if(sent == -1) { - log_err("sendto failed: %s", strerror(errno)); + verbose(VERB_OPS, "sendto failed: %s", strerror(errno)); return 0; } else if((size_t)sent != ldns_buffer_remaining(packet)) { log_err("sent %d in place of %d bytes", -- 2.47.2