mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
library resolution working.
git-svn-id: file:///svn/unbound/trunk@809 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
9374c1465a
commit
75073cefea
20 changed files with 993 additions and 76 deletions
|
|
@ -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_SRC=testcode/memstats.c smallapp/worker_cb.c $(COMMON_SRC)
|
||||||
MEMSTATS_OBJ=$(addprefix $(BUILD),$(MEMSTATS_SRC:.c=.o)) $(COMPAT_OBJ)
|
MEMSTATS_OBJ=$(addprefix $(BUILD),$(MEMSTATS_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||||
LIBUNBOUND_SRC=$(patsubst $(srcdir)/%,%, \
|
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)
|
LIBUNBOUND_OBJ=$(addprefix $(BUILD),$(LIBUNBOUND_SRC:.c=.o)) $(COMPAT_OBJ)
|
||||||
ALL_SRC=$(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
|
ALL_SRC=$(COMMON_SRC) $(UNITTEST_SRC) $(DAEMON_SRC) \
|
||||||
$(TESTBOUND_SRC) $(LOCKVERIFY_SRC) $(PKTVIEW_SRC) $(SIGNIT_SRC) \
|
$(TESTBOUND_SRC) $(LOCKVERIFY_SRC) $(PKTVIEW_SRC) $(SIGNIT_SRC) \
|
||||||
|
|
|
||||||
|
|
@ -1074,3 +1074,45 @@ worker_alloc_cleanup(void* arg)
|
||||||
slabhash_clear(&worker->env.rrset_cache->table);
|
slabhash_clear(&worker->env.rrset_cache->table);
|
||||||
slabhash_clear(worker->env.msg_cache);
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
6 December 2007: Wouter
|
||||||
|
- library resolution works in foreground mode, unbound-host app
|
||||||
|
receives data.
|
||||||
|
|
||||||
5 December 2007: Wouter
|
5 December 2007: Wouter
|
||||||
- locking in context_new() inside the function.
|
- locking in context_new() inside the function.
|
||||||
- setup of libworker.
|
- setup of libworker.
|
||||||
|
|
|
||||||
|
|
@ -1174,8 +1174,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||||
iq->chase_flags, EDNS_DO|BIT_CD,
|
iq->chase_flags, EDNS_DO|BIT_CD,
|
||||||
&target->addr, target->addrlen, qstate);
|
&target->addr, target->addrlen, qstate);
|
||||||
if(!outq) {
|
if(!outq) {
|
||||||
log_err("error sending query to auth server; skip this address");
|
verbose(VERB_OPS, "error sending query to auth server; "
|
||||||
log_addr(0, "error for address:",
|
"skip this address");
|
||||||
|
log_addr(VERB_OPS, "error for address:",
|
||||||
&target->addr, target->addrlen);
|
&target->addr, target->addrlen);
|
||||||
return next_state(iq, QUERYTARGETS_STATE);
|
return next_state(iq, QUERYTARGETS_STATE);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,6 +81,7 @@ context_finalize(struct ub_val_ctx* ctx)
|
||||||
ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg);
|
ctx->env->infra_cache = infra_adjust(ctx->env->infra_cache, cfg);
|
||||||
if(!ctx->env->infra_cache)
|
if(!ctx->env->infra_cache)
|
||||||
return UB_NOMEM;
|
return UB_NOMEM;
|
||||||
|
ctx->finalized = 1;
|
||||||
return UB_NOERROR;
|
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);
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
return q;
|
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);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,13 @@ struct ub_val_ctx {
|
||||||
*/
|
*/
|
||||||
int finalized;
|
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 */
|
/** do threading (instead of forking) for async resolution */
|
||||||
int dothread;
|
int dothread;
|
||||||
/** next thread number for new threads */
|
/** next thread number for new threads */
|
||||||
|
|
@ -155,6 +162,10 @@ enum ub_ctx_err {
|
||||||
UB_SYNTAX,
|
UB_SYNTAX,
|
||||||
/** DNS service failed */
|
/** DNS service failed */
|
||||||
UB_SERVFAIL,
|
UB_SERVFAIL,
|
||||||
|
/** fork() failed */
|
||||||
|
UB_FORKFAIL,
|
||||||
|
/** cfg change after finalize() */
|
||||||
|
UB_AFTERFINAL,
|
||||||
/** initialization failed (bad settings) */
|
/** initialization failed (bad settings) */
|
||||||
UB_INITFAIL
|
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,
|
struct ctx_query* context_new(struct ub_val_ctx* ctx, char* name, int rrtype,
|
||||||
int rrclass, ub_val_callback_t cb, void* cbarg);
|
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 */
|
#endif /* LIBUNBOUND_CONTEXT_H */
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@
|
||||||
#include "libunbound/unbound.h"
|
#include "libunbound/unbound.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "libunbound/context.h"
|
#include "libunbound/context.h"
|
||||||
|
#include "libunbound/worker.h"
|
||||||
#include "util/locks.h"
|
#include "util/locks.h"
|
||||||
#include "util/config_file.h"
|
#include "util/config_file.h"
|
||||||
#include "util/alloc.h"
|
#include "util/alloc.h"
|
||||||
|
|
@ -89,7 +90,7 @@ ub_val_ctx_create()
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ctx->env->cfg = config_create();
|
ctx->env->cfg = config_create_forlib();
|
||||||
if(!ctx->env->cfg) {
|
if(!ctx->env->cfg) {
|
||||||
ub_val_ctx_delete(ctx);
|
ub_val_ctx_delete(ctx);
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
|
|
@ -124,9 +125,9 @@ ub_val_ctx_delete(struct ub_val_ctx* ctx)
|
||||||
na = a->super;
|
na = a->super;
|
||||||
a->super = &ctx->superalloc;
|
a->super = &ctx->superalloc;
|
||||||
alloc_clear(a);
|
alloc_clear(a);
|
||||||
|
free(a);
|
||||||
a = na;
|
a = na;
|
||||||
}
|
}
|
||||||
alloc_clear(&ctx->superalloc);
|
|
||||||
local_zones_delete(ctx->local_zones);
|
local_zones_delete(ctx->local_zones);
|
||||||
lock_basic_destroy(&ctx->qqpipe_lock);
|
lock_basic_destroy(&ctx->qqpipe_lock);
|
||||||
lock_basic_destroy(&ctx->rrpipe_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);
|
config_delete(ctx->env->cfg);
|
||||||
free(ctx->env);
|
free(ctx->env);
|
||||||
}
|
}
|
||||||
|
alloc_clear(&ctx->superalloc);
|
||||||
traverse_postorder(&ctx->queries, delq, NULL);
|
traverse_postorder(&ctx->queries, delq, NULL);
|
||||||
free(ctx);
|
free(ctx);
|
||||||
}
|
}
|
||||||
|
|
@ -150,7 +152,10 @@ int
|
||||||
ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname)
|
ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname)
|
||||||
{
|
{
|
||||||
lock_basic_lock(&ctx->cfglock);
|
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)) {
|
if(!config_read(ctx->env->cfg, fname)) {
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
return UB_SYNTAX;
|
return UB_SYNTAX;
|
||||||
|
|
@ -165,7 +170,10 @@ ub_val_ctx_add_ta(struct ub_val_ctx* ctx, char* ta)
|
||||||
char* dup = strdup(ta);
|
char* dup = strdup(ta);
|
||||||
if(!dup) return UB_NOMEM;
|
if(!dup) return UB_NOMEM;
|
||||||
lock_basic_lock(&ctx->cfglock);
|
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)) {
|
if(!cfg_strlist_insert(&ctx->env->cfg->trust_anchor_list, dup)) {
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
free(dup);
|
free(dup);
|
||||||
|
|
@ -181,7 +189,10 @@ ub_val_ctx_trustedkeys(struct ub_val_ctx* ctx, char* fname)
|
||||||
char* dup = strdup(fname);
|
char* dup = strdup(fname);
|
||||||
if(!dup) return UB_NOMEM;
|
if(!dup) return UB_NOMEM;
|
||||||
lock_basic_lock(&ctx->cfglock);
|
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)) {
|
if(!cfg_strlist_insert(&ctx->env->cfg->trusted_keys_file_list, dup)) {
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
free(dup);
|
free(dup);
|
||||||
|
|
@ -195,7 +206,10 @@ int
|
||||||
ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread)
|
ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread)
|
||||||
{
|
{
|
||||||
lock_basic_lock(&ctx->cfglock);
|
lock_basic_lock(&ctx->cfglock);
|
||||||
ctx->finalized = 0;
|
if(ctx->finalized) {
|
||||||
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
|
return UB_AFTERFINAL;
|
||||||
|
}
|
||||||
ctx->dothread = dothread;
|
ctx->dothread = dothread;
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
return UB_NOERROR;
|
return UB_NOERROR;
|
||||||
|
|
@ -233,10 +247,9 @@ int
|
||||||
ub_val_ctx_wait(struct ub_val_ctx* ctx)
|
ub_val_ctx_wait(struct ub_val_ctx* ctx)
|
||||||
{
|
{
|
||||||
lock_basic_lock(&ctx->cfglock);
|
lock_basic_lock(&ctx->cfglock);
|
||||||
/* TODO until no more queries outstanding */
|
|
||||||
while(ctx->num_async > 0) {
|
while(ctx->num_async > 0) {
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
|
||||||
lock_basic_lock(&ctx->rrpipe_lock);
|
lock_basic_lock(&ctx->rrpipe_lock);
|
||||||
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
(void)pollit(ctx, NULL);
|
(void)pollit(ctx, NULL);
|
||||||
lock_basic_unlock(&ctx->rrpipe_lock);
|
lock_basic_unlock(&ctx->rrpipe_lock);
|
||||||
ub_val_ctx_process(ctx);
|
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)
|
int rrclass, int* secure, int* data, struct ub_val_result** result)
|
||||||
{
|
{
|
||||||
struct ctx_query* q;
|
struct ctx_query* q;
|
||||||
|
int r;
|
||||||
|
|
||||||
lock_basic_lock(&ctx->cfglock);
|
lock_basic_lock(&ctx->cfglock);
|
||||||
if(!ctx->finalized) {
|
if(!ctx->finalized) {
|
||||||
int r = context_finalize(ctx);
|
r = context_finalize(ctx);
|
||||||
if(r) {
|
if(r) {
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
return r;
|
return r;
|
||||||
|
|
@ -284,8 +298,23 @@ ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
|
||||||
*data = 0;
|
*data = 0;
|
||||||
*result = NULL;
|
*result = NULL;
|
||||||
|
|
||||||
/* TODO */
|
r = libworker_fg(ctx, q);
|
||||||
return UB_NOMEM;
|
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
|
int
|
||||||
|
|
@ -302,8 +331,17 @@ ub_val_resolve_async(struct ub_val_ctx* ctx, char* name, int rrtype,
|
||||||
return r;
|
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);
|
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);
|
q = context_new(ctx, name, rrtype, rrclass, callback, mydata);
|
||||||
if(!q)
|
if(!q)
|
||||||
return UB_NOMEM;
|
return UB_NOMEM;
|
||||||
|
|
@ -336,7 +374,9 @@ ub_val_result_free(struct ub_val_result* result)
|
||||||
char** p;
|
char** p;
|
||||||
if(!result) return;
|
if(!result) return;
|
||||||
free(result->qname);
|
free(result->qname);
|
||||||
|
if(result->canonname != result->qname)
|
||||||
free(result->canonname);
|
free(result->canonname);
|
||||||
|
if(result->data)
|
||||||
for(p = result->data; *p; p++)
|
for(p = result->data; *p; p++)
|
||||||
free(*p);
|
free(*p);
|
||||||
free(result->data);
|
free(result->data);
|
||||||
|
|
@ -353,7 +393,9 @@ ub_val_strerror(int err)
|
||||||
case UB_SOCKET: return "socket io error";
|
case UB_SOCKET: return "socket io error";
|
||||||
case UB_SYNTAX: return "syntax error";
|
case UB_SYNTAX: return "syntax error";
|
||||||
case UB_SERVFAIL: return "server failure";
|
case UB_SERVFAIL: return "server failure";
|
||||||
|
case UB_FORKFAIL: return "could not fork";
|
||||||
case UB_INITFAIL: return "initialization failure";
|
case UB_INITFAIL: return "initialization failure";
|
||||||
|
case UB_AFTERFINAL: return "setting change after finalize";
|
||||||
default: return "unknown error";
|
default: return "unknown error";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -281,6 +281,7 @@ int ub_val_ctx_process(struct ub_val_ctx* ctx);
|
||||||
/**
|
/**
|
||||||
* Perform resolution and validation of the target name.
|
* Perform resolution and validation of the target name.
|
||||||
* @param ctx: context.
|
* @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 name: domain name in text format (a zero terminated text string).
|
||||||
* @param rrtype: type of RR in host order, 1 is A (address).
|
* @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).
|
* @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.
|
* @param ctx: context.
|
||||||
* If no thread or process has been created yet to perform the
|
* If no thread or process has been created yet to perform the
|
||||||
* work in the background, it is created now.
|
* 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 name: domain name in text format (a string).
|
||||||
* @param rrtype: type of RR in host order, 1 is A.
|
* @param rrtype: type of RR in host order, 1 is A.
|
||||||
* @param rrclass: class of RR in host order, 1 is IN (for internet).
|
* @param rrclass: class of RR in host order, 1 is IN (for internet).
|
||||||
|
|
|
||||||
|
|
@ -45,39 +45,109 @@
|
||||||
#include "libunbound/worker.h"
|
#include "libunbound/worker.h"
|
||||||
#include "libunbound/context.h"
|
#include "libunbound/context.h"
|
||||||
#include "libunbound/unbound.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 */
|
/** delete libworker struct */
|
||||||
static void
|
static void
|
||||||
libworker_delete(struct libworker* w)
|
libworker_delete(struct libworker* w)
|
||||||
{
|
{
|
||||||
if(!w) return;
|
if(!w) return;
|
||||||
lock_basic_lock(&w->ctx->cfglock);
|
if(w->env) {
|
||||||
/* return alloc */
|
mesh_delete(w->env->mesh);
|
||||||
lock_basic_unlock(&w->ctx->cfglock);
|
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 */
|
/** setup fresh libworker struct */
|
||||||
static struct libworker*
|
static struct libworker*
|
||||||
libworker_setup(struct ub_val_ctx* ctx)
|
libworker_setup(struct ub_val_ctx* ctx)
|
||||||
{
|
{
|
||||||
|
unsigned int seed;
|
||||||
struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
|
struct libworker* w = (struct libworker*)calloc(1, sizeof(*w));
|
||||||
|
struct config_file* cfg = ctx->env->cfg;
|
||||||
if(!w) return NULL;
|
if(!w) return NULL;
|
||||||
w->ctx = ctx;
|
w->ctx = ctx;
|
||||||
lock_basic_lock(&ctx->cfglock);
|
w->env = (struct module_env*)malloc(sizeof(*w->env));
|
||||||
/* obtain a new alloc */
|
if(!w->env) {
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
free(w);
|
||||||
/* setup event base */
|
return NULL;
|
||||||
/* setup outnet */
|
}
|
||||||
/* setup rnd */
|
*w->env = *ctx->env;
|
||||||
/* setup env */
|
w->env->alloc = context_obtain_alloc(ctx);
|
||||||
/* setup env.scratch */
|
if(!w->env->alloc) {
|
||||||
/* setup env.scratch_buffer */
|
libworker_delete(w);
|
||||||
/* setup env.worker */
|
return NULL;
|
||||||
/* setup env.mesh */
|
}
|
||||||
/* setup env.alloc */
|
alloc_set_id_cleanup(w->env->alloc, &libworker_alloc_cleanup, w);
|
||||||
/* setup env.rnd */
|
w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
|
||||||
/* setup env - callback ptrs */
|
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;
|
return w;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -96,38 +166,350 @@ libworker_dobg(void* arg)
|
||||||
int libworker_bg(struct ub_val_ctx* ctx)
|
int libworker_bg(struct ub_val_ctx* ctx)
|
||||||
{
|
{
|
||||||
/* fork or threadcreate */
|
/* fork or threadcreate */
|
||||||
lock_basic_lock(&ctx->cfglock);
|
|
||||||
if(ctx->dothread) {
|
if(ctx->dothread) {
|
||||||
ub_thread_t t;
|
ub_thread_create(&ctx->bg_tid, libworker_dobg, ctx);
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
|
||||||
ub_thread_create(&t, libworker_dobg, ctx);
|
|
||||||
/* ctx.tid = t or so */
|
|
||||||
} else {
|
} else {
|
||||||
pid_t p;
|
switch((ctx->bg_pid=fork())) {
|
||||||
lock_basic_unlock(&ctx->cfglock);
|
|
||||||
switch((p=fork())) {
|
|
||||||
case 0:
|
case 0:
|
||||||
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
(void)libworker_dobg(ctx);
|
(void)libworker_dobg(ctx);
|
||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
case -1:
|
case -1:
|
||||||
/* TODO make UB_FORKFAILED */
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
return UB_SOCKET;
|
return UB_FORKFAIL;
|
||||||
default:
|
default:
|
||||||
/* ctx.pid = p or so */
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lock_basic_unlock(&ctx->cfglock);
|
||||||
return UB_NOERROR;
|
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)
|
int libworker_fg(struct ub_val_ctx* ctx, struct ctx_query* q)
|
||||||
{
|
{
|
||||||
struct libworker* w = libworker_setup(ctx);
|
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)
|
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;
|
return UB_NOMEM;
|
||||||
/* TODO */
|
}
|
||||||
q->res->bogus = 1;
|
free(qinfo.qname);
|
||||||
|
comm_base_dispatch(w->base);
|
||||||
libworker_delete(w);
|
libworker_delete(w);
|
||||||
return UB_NOERROR;
|
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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,10 @@ struct comm_base;
|
||||||
struct outside_network;
|
struct outside_network;
|
||||||
struct ub_randstate;
|
struct ub_randstate;
|
||||||
struct ctx_query;
|
struct ctx_query;
|
||||||
|
struct outbound_entry;
|
||||||
|
struct module_qstate;
|
||||||
|
struct comm_point;
|
||||||
|
struct comm_reply;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The library-worker status structure
|
* The library-worker status structure
|
||||||
|
|
@ -72,8 +76,16 @@ struct libworker {
|
||||||
|
|
||||||
/** random() table for this worker. */
|
/** random() table for this worker. */
|
||||||
struct ub_randstate* rndstate;
|
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);
|
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 */
|
#endif /* LIBUNBOUND_WORKER_H */
|
||||||
|
|
|
||||||
133
services/mesh.c
133
services/mesh.c
|
|
@ -155,9 +155,9 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||||
mesh->num_detached_states++;
|
mesh->num_detached_states++;
|
||||||
added = 1;
|
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;
|
was_detached = 1;
|
||||||
if(!s->reply_list)
|
if(!s->reply_list && !s->cb_list)
|
||||||
was_noreply = 1;
|
was_noreply = 1;
|
||||||
/* add reply to s */
|
/* add reply to s */
|
||||||
if(!mesh_state_add_reply(s, edns, rep, qid, qflags)) {
|
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);
|
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,
|
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
|
||||||
int is_ok, struct comm_reply* reply)
|
int is_ok, struct comm_reply* reply)
|
||||||
{
|
{
|
||||||
|
|
@ -271,11 +317,12 @@ mesh_state_delete(struct module_qstate* qstate)
|
||||||
mstate = qstate->mesh_info;
|
mstate = qstate->mesh_info;
|
||||||
mesh = mstate->s.env->mesh;
|
mesh = mstate->s.env->mesh;
|
||||||
mesh_detach_subs(&mstate->s);
|
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);
|
log_assert(mesh->num_detached_states > 0);
|
||||||
mesh->num_detached_states--;
|
mesh->num_detached_states--;
|
||||||
}
|
}
|
||||||
if(mstate->reply_list) {
|
if(mstate->reply_list || mstate->cb_list) {
|
||||||
log_assert(mesh->num_reply_states > 0);
|
log_assert(mesh->num_reply_states > 0);
|
||||||
mesh->num_reply_states--;
|
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) {
|
RBTREE_FOR(ref, struct mesh_state_ref*, &qstate->mesh_info->sub_set) {
|
||||||
n = rbtree_delete(&ref->s->super_set, &lookup);
|
n = rbtree_delete(&ref->s->super_set, &lookup);
|
||||||
log_assert(n != NULL); /* must have been present */
|
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++;
|
mesh->num_detached_states++;
|
||||||
log_assert(mesh->num_detached_states +
|
log_assert(mesh->num_detached_states +
|
||||||
mesh->num_reply_states <= mesh->all.count);
|
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;
|
*newq = NULL;
|
||||||
if(!mesh_state_attachment(qstate->mesh_info, sub))
|
if(!mesh_state_attachment(qstate->mesh_info, sub))
|
||||||
return 0;
|
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 */
|
/* it used to be detached, before this one got added */
|
||||||
log_assert(mesh->num_detached_states > 0);
|
log_assert(mesh->num_detached_states > 0);
|
||||||
mesh->num_detached_states--;
|
mesh->num_detached_states--;
|
||||||
|
|
@ -413,6 +461,49 @@ timeval_divide(struct timeval* avg, struct timeval* sum, size_t d)
|
||||||
#endif
|
#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
|
* Send reply to mesh reply entry
|
||||||
* @param m: mesh state to send it for.
|
* @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)
|
void mesh_query_done(struct mesh_state* mstate)
|
||||||
{
|
{
|
||||||
struct mesh_reply* r;
|
struct mesh_reply* r;
|
||||||
|
struct mesh_cb* c;
|
||||||
struct reply_info* rep = (mstate->s.return_msg?
|
struct reply_info* rep = (mstate->s.return_msg?
|
||||||
mstate->s.return_msg->rep:NULL);
|
mstate->s.return_msg->rep:NULL);
|
||||||
for(r = mstate->reply_list; r; r = r->next) {
|
for(r = mstate->reply_list; r; r = r->next) {
|
||||||
mesh_send_reply(mstate, mstate->s.return_rcode, rep, r);
|
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)
|
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;
|
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,
|
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||||
struct comm_reply* rep, uint16_t qid, uint16_t qflags)
|
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;
|
struct mesh_state* m;
|
||||||
int num = 0;
|
int num = 0;
|
||||||
RBTREE_FOR(m, struct mesh_state*, &mesh->all) {
|
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 */
|
num++, (m->s.is_priming)?"p":"", /* prime */
|
||||||
(m->s.query_flags&BIT_RD)?"RD":"",
|
(m->s.query_flags&BIT_RD)?"RD":"",
|
||||||
(m->s.query_flags&BIT_CD)?"CD":"",
|
(m->s.query_flags&BIT_CD)?"CD":"",
|
||||||
(m->super_set.count==0)?"d":"", /* detached */
|
(m->super_set.count==0)?"d":"", /* detached */
|
||||||
(m->sub_set.count!=0)?"c":"", /* children */
|
(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);
|
log_query_info(VERB_ALGO, buf, &m->s.qinfo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,7 @@
|
||||||
#include "services/modstack.h"
|
#include "services/modstack.h"
|
||||||
struct mesh_state;
|
struct mesh_state;
|
||||||
struct mesh_reply;
|
struct mesh_reply;
|
||||||
|
struct mesh_cb;
|
||||||
struct query_info;
|
struct query_info;
|
||||||
struct reply_info;
|
struct reply_info;
|
||||||
struct outbound_entry;
|
struct outbound_entry;
|
||||||
|
|
@ -116,6 +117,8 @@ struct mesh_state {
|
||||||
struct module_qstate s;
|
struct module_qstate s;
|
||||||
/** the list of replies to clients for the results */
|
/** the list of replies to clients for the results */
|
||||||
struct mesh_reply* reply_list;
|
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)
|
/** set of superstates (that want this state's result)
|
||||||
* contains struct mesh_state_ref* */
|
* contains struct mesh_state_ref* */
|
||||||
rbtree_t super_set;
|
rbtree_t super_set;
|
||||||
|
|
@ -155,6 +158,35 @@ struct mesh_reply {
|
||||||
uint16_t qflags;
|
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 -------------------- */
|
/* ------------------- 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 qflags, struct edns_data* edns, struct comm_reply* rep,
|
||||||
uint16_t qid);
|
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.
|
* Handle new event from the wire. A serviced query has returned.
|
||||||
* The query state will be made runnable, and the mesh_area will process
|
* 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,
|
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||||
struct comm_reply* rep, uint16_t qid, uint16_t qflags);
|
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
|
* Run the mesh. Run all runnable mesh states. Which can create new
|
||||||
* runnable mesh states. Until completion. Automatically called by
|
* runnable mesh states. Until completion. Automatically called by
|
||||||
|
|
|
||||||
|
|
@ -288,6 +288,11 @@ open_udp_port_range(const char* ifname, struct addrinfo* hints, int porthint)
|
||||||
char portstr[32];
|
char portstr[32];
|
||||||
if(porthint != -1)
|
if(porthint != -1)
|
||||||
snprintf(portstr, sizeof(portstr), "%d", porthint);
|
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,
|
if((r=getaddrinfo(ifname, ((porthint==-1)?NULL:portstr), hints,
|
||||||
&res)) != 0 || !res) {
|
&res)) != 0 || !res) {
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,9 @@
|
||||||
#include "libunbound/unbound.h"
|
#include "libunbound/unbound.h"
|
||||||
#include <ldns/ldns.h>
|
#include <ldns/ldns.h>
|
||||||
|
|
||||||
|
/** verbosity for unbound-host app */
|
||||||
|
static int verb = 0;
|
||||||
|
|
||||||
/** Give unbound-host usage, and exit (1). */
|
/** Give unbound-host usage, and exit (1). */
|
||||||
static void
|
static void
|
||||||
usage()
|
usage()
|
||||||
|
|
@ -54,6 +57,7 @@ usage()
|
||||||
printf(" If an ip-address is given a reverse lookup is done.\n");
|
printf(" If an ip-address is given a reverse lookup is done.\n");
|
||||||
printf("-t type what type to look for.\n");
|
printf("-t type what type to look for.\n");
|
||||||
printf("-c class what class to look for, if not class IN.\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("-h show this usage help.\n");
|
||||||
printf("Version %s\n", PACKAGE_VERSION);
|
printf("Version %s\n", PACKAGE_VERSION);
|
||||||
printf("BSD licensed, see LICENSE in source package for details.\n");
|
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 */
|
/** pretty line of output for results */
|
||||||
static void
|
static void
|
||||||
pretty_output(char* q, int t, int c, int sec, int haved,
|
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);
|
const char *secstatus = statstr(sec, result);
|
||||||
char tstr[16];
|
char tstr[16];
|
||||||
char cstr[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);
|
q, result->rcode, rcodestr, secstatus);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(docname && result->canonname &&
|
||||||
|
result->canonname != result->qname)
|
||||||
|
printf("%s is an alias for %s\n", result->qname,
|
||||||
|
result->canonname);
|
||||||
if(!haved) {
|
if(!haved) {
|
||||||
|
if(verb > 0)
|
||||||
printf("%s %s %s: no data. %s\n",
|
printf("%s %s %s: no data. %s\n",
|
||||||
q, cstr, tstr, secstatus);
|
q, cstr, tstr, secstatus);
|
||||||
|
/* else: emptiness to indicate no data */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printf("%s %s %s: have data. %s\n",
|
i=0;
|
||||||
q, cstr, tstr, secstatus);
|
while(result->data[i])
|
||||||
/* TODO print the data nicely */
|
{
|
||||||
|
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 */
|
/** perform a lookup and printout return if domain existed */
|
||||||
static int
|
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;
|
int ret, sec, haved;
|
||||||
struct ub_val_result* result;
|
struct ub_val_result* result;
|
||||||
|
|
||||||
ret = ub_val_resolve(ctx, q, t, c, &sec, &haved, &result);
|
ret = ub_val_resolve(ctx, q, t, c, &sec, &haved, &result);
|
||||||
if(ret != 0) {
|
if(ret != 0) {
|
||||||
fprintf(stderr, "error: %s\n", ub_val_strerror(ret));
|
fprintf(stderr, "resolve error: %s\n", ub_val_strerror(ret));
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
pretty_output(q, t, c, sec, haved, result);
|
pretty_output(q, t, c, sec, haved, result, docname);
|
||||||
ret = result->nxdomain;
|
ret = result->nxdomain;
|
||||||
ub_val_result_free(result);
|
ub_val_result_free(result);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
@ -264,6 +324,7 @@ lookup(const char* nm, const char* qt, const char* qc)
|
||||||
/* perform the query */
|
/* perform the query */
|
||||||
struct ub_val_ctx* ctx = NULL;
|
struct ub_val_ctx* ctx = NULL;
|
||||||
|
|
||||||
|
if(verb>0)
|
||||||
printf("lookup %s %d %d reverse=%d multi=%d\n",
|
printf("lookup %s %d %d reverse=%d multi=%d\n",
|
||||||
realq, t, c, reverse, multi);
|
realq, t, c, reverse, multi);
|
||||||
ctx = ub_val_ctx_create();
|
ctx = ub_val_ctx_create();
|
||||||
|
|
@ -272,13 +333,13 @@ lookup(const char* nm, const char* qt, const char* qc)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
if(multi) {
|
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 */
|
/* domain exists, lookup more */
|
||||||
(void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c);
|
(void)dnslook(ctx, realq, LDNS_RR_TYPE_AAAA, c, 0);
|
||||||
(void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c);
|
(void)dnslook(ctx, realq, LDNS_RR_TYPE_MX, c, 0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
(void)dnslook(ctx, realq, t, c);
|
(void)dnslook(ctx, realq, t, c, 1);
|
||||||
}
|
}
|
||||||
ub_val_ctx_delete(ctx);
|
ub_val_ctx_delete(ctx);
|
||||||
free(realq);
|
free(realq);
|
||||||
|
|
@ -296,7 +357,7 @@ int main(int argc, char* argv[])
|
||||||
char* qclass = NULL;
|
char* qclass = NULL;
|
||||||
char* qtype = NULL;
|
char* qtype = NULL;
|
||||||
/* parse the options */
|
/* parse the options */
|
||||||
while( (c=getopt(argc, argv, "c:ht:")) != -1) {
|
while( (c=getopt(argc, argv, "c:ht:v")) != -1) {
|
||||||
switch(c) {
|
switch(c) {
|
||||||
case 'c':
|
case 'c':
|
||||||
qclass = optarg;
|
qclass = optarg;
|
||||||
|
|
@ -304,6 +365,9 @@ int main(int argc, char* argv[])
|
||||||
case 't':
|
case 't':
|
||||||
qtype = optarg;
|
qtype = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'v':
|
||||||
|
verb++;
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
|
|
|
||||||
|
|
@ -114,3 +114,44 @@ acl_list_cmp(const void* ATTR_UNUSED(k1), const void* ATTR_UNUSED(k2))
|
||||||
log_assert(0);
|
log_assert(0);
|
||||||
return 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;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@
|
||||||
#include "util/configyyrename.h"
|
#include "util/configyyrename.h"
|
||||||
#include "util/config_file.h"
|
#include "util/config_file.h"
|
||||||
#include "util/configparser.h"
|
#include "util/configparser.h"
|
||||||
|
#include "util/net_help.h"
|
||||||
/** global config during parsing */
|
/** global config during parsing */
|
||||||
struct config_parser_state* cfg_parser = 0;
|
struct config_parser_state* cfg_parser = 0;
|
||||||
/** lex in file */
|
/** lex in file */
|
||||||
|
|
@ -139,6 +140,24 @@ error_exit:
|
||||||
return NULL;
|
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 */
|
/** initialize the global cfg_parser object */
|
||||||
static void
|
static void
|
||||||
create_cfg_parser(struct config_file* cfg, char* filename)
|
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;
|
MAX_TTL = (uint32_t)config->max_ttl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -239,6 +239,12 @@ struct config_str2list {
|
||||||
*/
|
*/
|
||||||
struct config_file* config_create();
|
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.
|
* Read the config file from the specified filename.
|
||||||
* @param config: where options are stored into, must be freshly created.
|
* @param config: where options are stored into, must be freshly created.
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,8 @@
|
||||||
#include "util/locks.h"
|
#include "util/locks.h"
|
||||||
#include "testcode/checklocks.h"
|
#include "testcode/checklocks.h"
|
||||||
#include "daemon/acl_list.h"
|
#include "daemon/acl_list.h"
|
||||||
|
#include "libunbound/worker.h"
|
||||||
|
#include "libunbound/context.h"
|
||||||
|
|
||||||
int
|
int
|
||||||
fptr_whitelist_comm_point(comm_point_callback_t *fptr)
|
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;
|
if(fptr == &serviced_udp_callback) return 1;
|
||||||
else if(fptr == &worker_handle_reply) return 1;
|
else if(fptr == &worker_handle_reply) return 1;
|
||||||
|
else if(fptr == &libworker_handle_reply) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,6 +121,7 @@ fptr_whitelist_pending_tcp(comm_point_callback_t *fptr)
|
||||||
{
|
{
|
||||||
if(fptr == &serviced_tcp_callback) return 1;
|
if(fptr == &serviced_tcp_callback) return 1;
|
||||||
else if(fptr == &worker_handle_reply) return 1;
|
else if(fptr == &worker_handle_reply) return 1;
|
||||||
|
else if(fptr == &libworker_handle_reply) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -125,6 +129,7 @@ int
|
||||||
fptr_whitelist_serviced_query(comm_point_callback_t *fptr)
|
fptr_whitelist_serviced_query(comm_point_callback_t *fptr)
|
||||||
{
|
{
|
||||||
if(fptr == &worker_handle_service_reply) return 1;
|
if(fptr == &worker_handle_service_reply) return 1;
|
||||||
|
else if(fptr == &libworker_handle_service_reply) return 1;
|
||||||
return 0;
|
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 == &mini_ev_cmp) return 1;
|
||||||
else if(fptr == &anchor_cmp) return 1;
|
else if(fptr == &anchor_cmp) return 1;
|
||||||
else if(fptr == &canonical_tree_compare) return 1;
|
else if(fptr == &canonical_tree_compare) return 1;
|
||||||
|
else if(fptr == &context_query_cmp) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -212,6 +218,7 @@ fptr_whitelist_modenv_send_packet(int (*fptr)(ldns_buffer* pkt,
|
||||||
struct module_qstate* q, int use_tcp))
|
struct module_qstate* q, int use_tcp))
|
||||||
{
|
{
|
||||||
if(fptr == &worker_send_packet) return 1;
|
if(fptr == &worker_send_packet) return 1;
|
||||||
|
else if(fptr == &libworker_send_packet) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -222,6 +229,7 @@ fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
|
||||||
socklen_t addrlen, struct module_qstate* q))
|
socklen_t addrlen, struct module_qstate* q))
|
||||||
{
|
{
|
||||||
if(fptr == &worker_send_query) return 1;
|
if(fptr == &worker_send_query) return 1;
|
||||||
|
else if(fptr == &libworker_send_query) return 1;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,7 @@ fatal_exit(const char *format, ...)
|
||||||
va_start(args, format);
|
va_start(args, format);
|
||||||
log_vmsg(LOG_CRIT, "fatal error", format, args);
|
log_vmsg(LOG_CRIT, "fatal error", format, args);
|
||||||
va_end(args);
|
va_end(args);
|
||||||
|
abort();
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -168,7 +168,7 @@ comm_point_send_udp_msg(struct comm_point *c, ldns_buffer* packet,
|
||||||
ldns_buffer_remaining(packet), 0,
|
ldns_buffer_remaining(packet), 0,
|
||||||
addr, addrlen);
|
addr, addrlen);
|
||||||
if(sent == -1) {
|
if(sent == -1) {
|
||||||
log_err("sendto failed: %s", strerror(errno));
|
verbose(VERB_OPS, "sendto failed: %s", strerror(errno));
|
||||||
return 0;
|
return 0;
|
||||||
} else if((size_t)sent != ldns_buffer_remaining(packet)) {
|
} else if((size_t)sent != ldns_buffer_remaining(packet)) {
|
||||||
log_err("sent %d in place of %d bytes",
|
log_err("sent %d in place of %d bytes",
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue