mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 06:37:08 +00:00
unbound lib work.
git-svn-id: file:///svn/unbound/trunk@880 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
b63db13e72
commit
c7ad292438
@ -6,6 +6,8 @@
|
||||
- goodbye ip4to6 mapping.
|
||||
- update ldns-testpkts with latest version from ldns-trunk.
|
||||
- updated makedist for relative ldns pathnames.
|
||||
- library API with more information inside the result structure.
|
||||
- work on background resolves.
|
||||
|
||||
17 January 2008: Wouter
|
||||
- fixup configure in case -lldns is installed.
|
||||
|
@ -245,11 +245,16 @@ The result of the DNS resolution and validation is returned as
|
||||
char** data; /* array of rdata items, NULL terminated*/
|
||||
int* len; /* array with lengths of rdata items */
|
||||
char* canonname; /* canonical name of result */
|
||||
int rcode; /* additional error code in case of error */
|
||||
int nxdomain; /* true if nodata because no domain */
|
||||
int bogus; /* true if there was a security failure */
|
||||
int rcode; /* additional error code in case of no data */
|
||||
int havedata; /* true if there is data */
|
||||
int nxdomain; /* true if nodata because name does not exist */
|
||||
int secure; /* true if result is secure */
|
||||
int bogus; /* true if a security failure happened */
|
||||
};
|
||||
.fi
|
||||
.P
|
||||
If both secure and bogus are false, security was not enabled for the
|
||||
domain of the query.
|
||||
.SH "RETURN VALUES"
|
||||
Many routines return an error code. The value 0 (zero) denotes no error
|
||||
happened. Other values can be passed to
|
||||
|
@ -154,10 +154,11 @@ struct ctx_query {
|
||||
enum ub_ctx_err {
|
||||
/** no error */
|
||||
UB_NOERROR = 0,
|
||||
/** socket operation. Set to -1, so that if an error from _fd() is
|
||||
* passed (-1) it gives a socket error. */
|
||||
UB_SOCKET = -1,
|
||||
/** alloc failure */
|
||||
UB_NOMEM = -1,
|
||||
/** socket operation */
|
||||
UB_SOCKET = -2,
|
||||
UB_NOMEM = -2,
|
||||
/** syntax error */
|
||||
UB_SYNTAX = -3,
|
||||
/** DNS service failed */
|
||||
|
@ -304,7 +304,7 @@ ub_val_ctx_process(struct ub_val_ctx* ctx)
|
||||
|
||||
int
|
||||
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, struct ub_val_result** result)
|
||||
{
|
||||
struct ctx_query* q;
|
||||
int r;
|
||||
@ -323,8 +323,6 @@ ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
|
||||
if(!q)
|
||||
return UB_NOMEM;
|
||||
/* become a resolver thread for a bit */
|
||||
*secure = 0;
|
||||
*data = 0;
|
||||
*result = NULL;
|
||||
|
||||
r = libworker_fg(ctx, q);
|
||||
@ -333,11 +331,6 @@ ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
|
||||
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);
|
||||
@ -418,8 +411,8 @@ ub_val_strerror(int err)
|
||||
{
|
||||
switch(err) {
|
||||
case UB_NOERROR: return "no error";
|
||||
case UB_NOMEM: return "out of memory";
|
||||
case UB_SOCKET: return "socket io error";
|
||||
case UB_NOMEM: return "out of memory";
|
||||
case UB_SYNTAX: return "syntax error";
|
||||
case UB_SERVFAIL: return "server failure";
|
||||
case UB_FORKFAIL: return "could not fork";
|
||||
|
@ -73,11 +73,12 @@
|
||||
* shared cache data from the context.
|
||||
*
|
||||
* Application threaded. Non-blocking ('asynchronous').
|
||||
* ... setup threaded-asynchronous config option
|
||||
* err = ub_val_ctx_async(ctx, 1);
|
||||
* ... same as async for non-threaded
|
||||
* ... the callbacks are called in the thread that calls process(ctx)
|
||||
*
|
||||
* If not threading is compiled in, the above async example uses fork(2) to
|
||||
* If no threading is compiled in, the above async example uses fork(2) to
|
||||
* create a process to perform the work. The forked process exits when the
|
||||
* calling process exits, or ctx_delete() is called.
|
||||
* Otherwise, for asynchronous with threading, a worker thread is created.
|
||||
@ -85,9 +86,9 @@
|
||||
* The blocking calls use shared ctx-cache when threaded. Thus
|
||||
* ub_val_resolve() and ub_val_resolve_async() && ub_val_ctx_wait() are
|
||||
* not the same. The first makes the current thread do the work, setting
|
||||
* up buffers, etc, to perform its thing (but using shared cache data).
|
||||
* up buffers, etc, to perform the work (but using shared cache data).
|
||||
* The second calls another worker thread (or process) to perform the work.
|
||||
* And no buffers need to be setup, but a context-switch happens.
|
||||
* And no buffers need to be set up, but a context-switch happens.
|
||||
*/
|
||||
#ifndef _UB_UNBOUND_H
|
||||
#define _UB_UNBOUND_H
|
||||
@ -138,6 +139,12 @@ struct ub_val_result {
|
||||
*/
|
||||
int rcode;
|
||||
|
||||
/**
|
||||
* If there is any data, this is true.
|
||||
* If false, there was no data (nxdomain may be true, rcode can be set).
|
||||
*/
|
||||
int havedata;
|
||||
|
||||
/**
|
||||
* If there was no data, and the domain did not exist, this is true.
|
||||
* If it is false, and there was no data, then the domain name
|
||||
@ -145,6 +152,16 @@ struct ub_val_result {
|
||||
*/
|
||||
int nxdomain;
|
||||
|
||||
/**
|
||||
* True, if the result is validated securely.
|
||||
* False, if validation failed or domain queried has no security info.
|
||||
*
|
||||
* It is possible to get a result with no data (havedata is false),
|
||||
* and secure is true. This means that the non-existance of the data
|
||||
* was cryptographically proven (with signatures).
|
||||
*/
|
||||
int secure;
|
||||
|
||||
/**
|
||||
* If the result was not secure (secure==0), and this result is due
|
||||
* to a security failure, bogus is true.
|
||||
@ -165,16 +182,15 @@ struct ub_val_result {
|
||||
* void my_callback(void* my_arg, int err, int secure, int havedata,
|
||||
* struct ub_val_result* result);
|
||||
* It is called with
|
||||
* my_arg: your pointer to a (struct of) data of your choice, or NULL.
|
||||
* err: if 0 all is OK, otherwise an error occured and no results
|
||||
* void* my_arg: your pointer to a (struct of) data of your choice,
|
||||
* or NULL.
|
||||
* int err: if 0 all is OK, otherwise an error occured and no results
|
||||
* are forthcoming.
|
||||
* secure: if true, the result is validated securely.
|
||||
* havedata: if true, there was data, false if no data.
|
||||
* result: pointer to more detailed result structure.
|
||||
* struct result: pointer to more detailed result structure.
|
||||
* This structure is allocated on the heap and needs to be
|
||||
* freed with ub_val_result_free(result);
|
||||
*/
|
||||
typedef void (*ub_val_callback_t)(void*, int, int, int, struct ub_val_result*);
|
||||
typedef void (*ub_val_callback_t)(void*, int, struct ub_val_result*);
|
||||
|
||||
/**
|
||||
* Create a resolving and validation context.
|
||||
@ -306,19 +322,13 @@ int ub_val_ctx_process(struct ub_val_ctx* ctx);
|
||||
* @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).
|
||||
* @param secure: returns true if the answer validated securely.
|
||||
* false if not.
|
||||
* It is possible to get a result with no data (data is false),
|
||||
* and secure is true. This means that the non-existance of the data
|
||||
* was cryptographically proven (with signatures).
|
||||
* @param data: returns false if there was no data, or the domain did not exist,
|
||||
* else true.
|
||||
* @param result: the result data is returned in a newly allocated result
|
||||
* structure.
|
||||
* structure. May be NULL on return, return value is set to an error
|
||||
* in that case (out of memory).
|
||||
* @return 0 if OK, else error.
|
||||
*/
|
||||
int 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, struct ub_val_result** result);
|
||||
|
||||
/**
|
||||
* Perform resolution and validation of the target name.
|
||||
@ -337,14 +347,13 @@ int ub_val_resolve(struct ub_val_ctx* ctx, char* name, int rrtype,
|
||||
* It is called as:
|
||||
* void callback(void* mydata, int err, int secure, int havedata,
|
||||
* struct ub_val_result* result)
|
||||
* with mydata, the same as passed here,
|
||||
* with err is 0 when a result has been found.
|
||||
* with secure true if the answer validated securely.
|
||||
* with havedata true if any data was found.
|
||||
* with result newly allocated result structure.
|
||||
* with mydata: the same as passed here, you may pass NULL,
|
||||
* with err: is 0 when a result has been found.
|
||||
* with result: a newly allocated result structure.
|
||||
* The result may be NULL, in that case err is set.
|
||||
*
|
||||
* If an error happens during processing, your callback will be called
|
||||
* with error set to a nonzero value (and secure=0, data=0, result=0).
|
||||
* with error set to a nonzero value (and result==NULL).
|
||||
* @param async_id: if you pass a non-NULL value, an identifier number is
|
||||
* returned for the query as it is in progress. It can be used to
|
||||
* cancel the query.
|
||||
|
@ -78,6 +78,8 @@ libworker_delete(struct libworker* w)
|
||||
free(w->env);
|
||||
}
|
||||
outside_network_delete(w->back);
|
||||
comm_point_delete(w->cmd_com);
|
||||
comm_point_delete(w->res_com);
|
||||
comm_base_delete(w->base);
|
||||
free(w);
|
||||
}
|
||||
@ -153,14 +155,86 @@ libworker_setup(struct ub_val_ctx* ctx)
|
||||
return w;
|
||||
}
|
||||
|
||||
static int
|
||||
libworker_handle_control_cmd(struct comm_point* c, void* arg,
|
||||
int err, struct comm_reply* ATTR_UNUSED(rep))
|
||||
{
|
||||
/*struct ub_val_ctx* ctx = (struct ub_val_ctx*)arg;*/
|
||||
if(err != NETEVENT_NOERROR) {
|
||||
if(err == NETEVENT_CLOSED) {
|
||||
/* parent closed pipe, must have exited somehow */
|
||||
/* it is of no use to go on, exit */
|
||||
exit(0);
|
||||
}
|
||||
log_err("internal error: control cmd err %d", err);
|
||||
exit(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
libworker_handle_result_write(struct comm_point* c, void* arg,
|
||||
int err, struct comm_reply* ATTR_UNUSED(rep))
|
||||
{
|
||||
/*struct ub_val_ctx* ctx = (struct ub_val_ctx*)arg;*/
|
||||
if(err != NETEVENT_NOERROR) {
|
||||
if(err == NETEVENT_CLOSED) {
|
||||
/* parent closed pipe, must have exited somehow */
|
||||
/* it is of no use to go on, exit */
|
||||
exit(0);
|
||||
}
|
||||
log_err("internal error: pipe comm err %d", err);
|
||||
exit(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** get bufsize for cfg */
|
||||
static size_t
|
||||
getbufsz(struct ub_val_ctx* ctx)
|
||||
{
|
||||
size_t s = 65535;
|
||||
lock_basic_lock(&ctx->cfglock);
|
||||
s = ctx->env->cfg->msg_buffer_size;
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
return s;
|
||||
}
|
||||
|
||||
/** the background thread func */
|
||||
static void*
|
||||
libworker_dobg(void* arg)
|
||||
{
|
||||
/* setup */
|
||||
struct ub_val_ctx* ctx = (struct ub_val_ctx*)arg;
|
||||
struct libworker* w = libworker_setup(ctx);
|
||||
size_t bufsz = getbufsz(ctx);
|
||||
log_thread_set(&w->thread_num);
|
||||
/* TODO do bg thread */
|
||||
if(!w) {
|
||||
log_err("libunbound bg worker init failed, nomem");
|
||||
return NULL;
|
||||
}
|
||||
lock_basic_lock(&ctx->qqpipe_lock);
|
||||
if(!(w->cmd_com=comm_point_create_local(w->base, ctx->qqpipe[0],
|
||||
bufsz, libworker_handle_control_cmd, w))) {
|
||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||
log_err("libunbound bg worker init failed, no cmdcom");
|
||||
return NULL;
|
||||
}
|
||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||
lock_basic_lock(&ctx->rrpipe_lock);
|
||||
/* TODO create writing local commpoint */
|
||||
if(!(w->res_com=comm_point_create_local(w->base, ctx->rrpipe[1],
|
||||
bufsz, libworker_handle_result_write, w))) {
|
||||
lock_basic_unlock(&ctx->qqpipe_lock);
|
||||
log_err("libunbound bg worker init failed, no cmdcom");
|
||||
return NULL;
|
||||
}
|
||||
lock_basic_unlock(&ctx->rrpipe_lock);
|
||||
|
||||
/* do the work */
|
||||
comm_base_dispatch(w->base);
|
||||
|
||||
/* cleanup */
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
@ -287,10 +361,14 @@ libworker_fg_done_cb(void* arg, int rcode, ldns_buffer* buf, enum sec_status s)
|
||||
if(!fill_res(d->q->res, reply_find_answer_rrset(&rq, rep),
|
||||
reply_find_final_cname_target(&rq, rep), &rq))
|
||||
return; /* out of memory */
|
||||
/* rcode, nxdomain, bogus */
|
||||
/* rcode, havedata, nxdomain, secure, bogus */
|
||||
d->q->res->rcode = (int)LDNS_RCODE_WIRE(d->q->msg);
|
||||
if(d->q->res->data && d->q->res->data[0])
|
||||
d->q->res->havedata = 1;
|
||||
if(d->q->res->rcode == LDNS_RCODE_NXDOMAIN)
|
||||
d->q->res->nxdomain = 1;
|
||||
if(s == sec_status_secure)
|
||||
d->q->res->secure = 1;
|
||||
if(s == sec_status_bogus)
|
||||
d->q->res->bogus = 1;
|
||||
|
||||
@ -340,20 +418,25 @@ int libworker_fg(struct ub_val_ctx* ctx, struct ctx_query* q)
|
||||
qflags = BIT_RD;
|
||||
d.q = q;
|
||||
d.w = w;
|
||||
/* see if there is a fixed answer */
|
||||
if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
|
||||
w->back->udp_buff, w->env->scratch)) {
|
||||
libworker_fg_done_cb(&d, LDNS_RCODE_NOERROR,
|
||||
w->back->udp_buff, sec_status_insecure);
|
||||
libworker_delete(w);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
else {
|
||||
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;
|
||||
}
|
||||
/* process new query */
|
||||
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
|
||||
w->back->udp_buff, qid, libworker_fg_done_cb, &d)) {
|
||||
free(qinfo.qname);
|
||||
comm_base_dispatch(w->base);
|
||||
return UB_NOMEM;
|
||||
}
|
||||
free(qinfo.qname);
|
||||
|
||||
/* wait for reply */
|
||||
comm_base_dispatch(w->base);
|
||||
|
||||
libworker_delete(w);
|
||||
return UB_NOERROR;
|
||||
}
|
||||
|
@ -76,6 +76,10 @@ struct libworker {
|
||||
|
||||
/** random() table for this worker. */
|
||||
struct ub_randstate* rndstate;
|
||||
/** commpoint to listen to commands */
|
||||
struct comm_point* cmd_com;
|
||||
/** commpoint to write results back (nonblocking) */
|
||||
struct comm_point* res_com;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -176,10 +176,10 @@ massage_class(const char* c)
|
||||
|
||||
/** nice security status string */
|
||||
static const char*
|
||||
statstr(int sec, struct ub_val_result* result)
|
||||
secure_str(struct ub_val_result* result)
|
||||
{
|
||||
if(sec) return "(secure)";
|
||||
if(result->bogus) return "(BOGUS (security failure))]";
|
||||
if(result->secure) return "(secure)";
|
||||
if(result->bogus) return "(BOGUS (security failure))";
|
||||
return "(insecure)";
|
||||
}
|
||||
|
||||
@ -274,11 +274,10 @@ pretty_rdata(char* q, char* cstr, char* tstr, int t, const char* sec,
|
||||
|
||||
/** 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, int docname)
|
||||
pretty_output(char* q, int t, int c, struct ub_val_result* result, int docname)
|
||||
{
|
||||
int i;
|
||||
const char *secstatus = statstr(sec, result);
|
||||
const char *secstatus = secure_str(result);
|
||||
char tstr[16];
|
||||
char cstr[16];
|
||||
char rcodestr[16];
|
||||
@ -286,7 +285,7 @@ pretty_output(char* q, int t, int c, int sec, int haved,
|
||||
pretty_class(cstr, 16, c);
|
||||
pretty_rcode(rcodestr, 16, result->rcode);
|
||||
|
||||
if(!haved && result->rcode) {
|
||||
if(!result->havedata && result->rcode) {
|
||||
printf("Host %s not found: %d(%s).",
|
||||
q, result->rcode, rcodestr);
|
||||
if(verb > 0)
|
||||
@ -305,7 +304,7 @@ pretty_output(char* q, int t, int c, int sec, int haved,
|
||||
/* remove trailing . from long canonnames for nicer output */
|
||||
if(result->canonname && strlen(result->canonname) > 1)
|
||||
result->canonname[strlen(result->canonname)-1] = 0;
|
||||
if(!haved) {
|
||||
if(!result->havedata) {
|
||||
if(verb > 0) {
|
||||
printf("%s", result->canonname?result->canonname:q);
|
||||
if(strcmp(cstr, "IN") != 0)
|
||||
@ -339,15 +338,15 @@ pretty_output(char* q, int t, int c, int sec, int haved,
|
||||
static int
|
||||
dnslook(struct ub_val_ctx* ctx, char* q, int t, int c, int docname)
|
||||
{
|
||||
int ret, sec, haved;
|
||||
int ret;
|
||||
struct ub_val_result* result;
|
||||
|
||||
ret = ub_val_resolve(ctx, q, t, c, &sec, &haved, &result);
|
||||
ret = ub_val_resolve(ctx, q, t, c, &result);
|
||||
if(ret != 0) {
|
||||
fprintf(stderr, "resolve error: %s\n", ub_val_strerror(ret));
|
||||
exit(1);
|
||||
}
|
||||
pretty_output(q, t, c, sec, haved, result, docname);
|
||||
pretty_output(q, t, c, result, docname);
|
||||
ret = result->nxdomain;
|
||||
ub_val_result_free(result);
|
||||
return ret;
|
||||
|
Loading…
Reference in New Issue
Block a user