- 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.
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
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 */
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;
if(!q)
return UB_NOMEM;
/* become a resolver thread for a bit */
- *secure = 0;
- *data = 0;
*result = NULL;
r = libworker_fg(ctx, q);
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);
{
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";
* 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.
* 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
*/
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
*/
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.
* 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.
* @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.
* 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.
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);
}
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;
}
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;
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;
}
/** 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;
};
/**
/** 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)";
}
/** 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];
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)
/* 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)
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;