library resolution working.

git-svn-id: file:///svn/unbound/trunk@809 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-12-06 15:11:07 +00:00
parent 9374c1465a
commit 75073cefea
20 changed files with 993 additions and 76 deletions

View file

@ -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) \

View file

@ -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;
}

View file

@ -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.

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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 */

View file

@ -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";
}
}

View file

@ -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).

View file

@ -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; i<data->count; 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;
}

View file

@ -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 */

View file

@ -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);
}
}

View file

@ -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

View file

@ -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) {

View file

@ -44,6 +44,9 @@
#include "libunbound/unbound.h"
#include <ldns/ldns.h>
/** 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; i<ldns_rr_rd_count(rr); i++) {
ldns_rdf_print(stdout, ldns_rr_rdf(rr, i));
}
ldns_rr_free(rr);
*/
printf("TODO");
}
/** pretty line of RR data for results */
static void
pretty_rdata(char* q, char* cstr, char* tstr, int t, const char* sec,
char* data, size_t len)
{
printf("%s", q);
if(strcmp(cstr, "IN") != 0)
printf(" in class %s", cstr);
if(t == LDNS_RR_TYPE_A)
printf(" has address ");
else if(t == LDNS_RR_TYPE_AAAA)
printf(" has IPv6 address ");
else if(t == LDNS_RR_TYPE_MX)
printf(" mail is handled by ");
else printf(" has %s record ", tstr);
print_rd(t, data, len);
printf(" %s", sec);
printf("\n");
}
/** pretty line of output for results */
static void
pretty_output(char* q, int t, int c, int sec, int haved,
struct ub_val_result* result)
struct ub_val_result* result, int docname)
{
int i;
const char *secstatus = statstr(sec, result);
char tstr[16];
char cstr[16];
@ -222,29 +270,41 @@ pretty_output(char* q, int t, int c, int sec, int haved,
q, result->rcode, 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:

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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.

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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",