- make pipe nonblocking at start.
- update plane for retry mode with caution to limit bandwidth.
- fix Makefile for concurrent make of unbound-host.
+ - renamed ub_val_ctx_wait/poll/process/fd to ub_val*.
+ - new calls to set forwarding added to header and docs.
23 January 2008: Wouter
- removed debug prints from if-auto, verb-algo enables some.
.B ub_val_ctx_create,
.B ub_val_ctx_delete,
.B ub_val_ctx_config,
+.B ub_val_ctx_set_fwd,
+.B ub_val_ctx_resolvconf,
.B ub_val_ctx_add_ta,
.B ub_val_ctx_add_ta_file,
.B ub_val_ctx_trustedkeys,
.B ub_val_ctx_debuglevel,
.B ub_val_ctx_async,
-.B ub_val_ctx_poll,
-.B ub_val_ctx_wait,
-.B ub_val_ctx_fd,
-.B ub_val_ctx_process,
+.B ub_val_poll,
+.B ub_val_wait,
+.B ub_val_fd,
+.B ub_val_process,
.B ub_val_resolve,
.B ub_val_resolve_async,
.B ub_val_cancel,
\fBub_val_ctx_config\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR fname);
.LP
\fIint\fR
+\fBub_val_ctx_set_fwd\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR addr);
+.LP
+\fIint\fR
+\fBub_val_ctx_resolvconf\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR fname);
+.LP
+\fIint\fR
\fBub_val_ctx_add_ta\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR ta);
.LP
\fIint\fR
\fBub_val_ctx_async\fR(\fIstruct ub_val_ctx*\fR ctx, \fIint\fR dothread);
.LP
\fIint\fR
-\fBub_val_ctx_poll\fR(\fIstruct ub_val_ctx*\fR ctx);
+\fBub_val_poll\fR(\fIstruct ub_val_ctx*\fR ctx);
.LP
\fIint\fR
-\fBub_val_ctx_wait\fR(\fIstruct ub_val_ctx*\fR ctx);
+\fBub_val_wait\fR(\fIstruct ub_val_ctx*\fR ctx);
.LP
\fIint\fR
-\fBub_val_ctx_fd\fR(\fIstruct ub_val_ctx*\fR ctx);
+\fBub_val_fd\fR(\fIstruct ub_val_ctx*\fR ctx);
.LP
\fIint\fR
-\fBub_val_ctx_process\fR(\fIstruct ub_val_ctx*\fR ctx);
+\fBub_val_process\fR(\fIstruct ub_val_ctx*\fR ctx);
.LP
\fIint\fR
\fBub_val_resolve\fR(\fIstruct ub_val_ctx*\fR ctx, \fIchar*\fR name,
relevant. For some specific options, such as adding trust anchors, special
routines exist.
.TP
+.B ub_val_ctx_set_fwd
+Set machine to forward DNS queries to, the caching resolver to use.
+IP4 or IP6 address. Forwards all DNS requests to that machine, which
+is expected to run a recursive resolver. If the proxy is not
+DNSSEC capable, validation may fail. Can be called several times, in
+that case the addresses are used as backup servers.
+At this time it is only possible to set configuration before the
+first resolve is done.
+.TP
+.B ub_val_ctx_resolvconf
+Read list of nameservers to use from the filename given.
+Usually "/etc/resolv.conf". Uses those nameservers as caching proxies.
+If they do not support DNSSEC, validation may fail.
+Only nameservers are picked up, the searchdomain, ndots and other
+settings from \fIresolv.conf\fR(5) are ignored.
+If fname NULL is passed, "/etc/resolv.conf" is used.
+At this time it is only possible to set configuration before the
+first resolve is done.
+.TP
.B
ub_val_ctx_add_ta
Add a trust anchor to the given context.
calls have been made have no effect (delete and re\-create the context
to change).
.TP
-.B ub_val_ctx_poll
+.B ub_val_poll
Poll a context to see if it has any new results.
Do not poll in a loop, instead extract the fd below to poll for readiness,
and then check, or wait using the wait routine.
Returns 0 if nothing to read, or nonzero if a result is available.
If nonzero, call
-.B ub_val_ctx_process
+.B ub_val_process
to do callbacks.
.TP
-.B ub_val_ctx_wait
+.B ub_val_wait
Wait for a context to finish with results. Calls
-.B ub_val_ctx_process
+.B ub_val_process
after the wait for you. After the wait, there are no more outstanding
asynchronous queries.
.TP
-.B ub_val_ctx_fd
+.B ub_val_fd
Get file descriptor. Wait for it to become readable, at this point
answers are returned from the asynchronous validating resolver.
-Then call the \fBub_val_ctx_process\fR to continue processing.
+Then call the \fBub_val_process\fR to continue processing.
.TP
-.B ub_val_ctx_process
+.B ub_val_process
Call this routine to continue processing results from the validating
resolver (when the fd becomes readable).
Will perform necessary callbacks.
returns a zero terminated string.
.B ub_val_ctx_create
returns NULL on an error (a malloc failure).
-.B ub_val_ctx_poll
+.B ub_val_poll
returns true if some information may be available, false otherwise.
-.B ub_val_ctx_fd
+.B ub_val_fd
returns a file descriptor or -1 on error.
.SH "SEE ALSO"
\fIunbound.conf\fR(5),
/** initialization failed (bad settings) */
UB_INITFAIL = -7,
/** error in pipe communication with async bg worker */
- UB_PIPE = -8
+ UB_PIPE = -8,
+ /** error reading from file (resolv.conf) */
+ UB_READFILE = -9
};
/**
ub_val_ctx_create
ub_val_ctx_delete
ub_val_ctx_config
+ub_val_ctx_set_fwd
+ub_val_ctx_resolvconf
ub_val_ctx_add_ta
ub_val_ctx_add_ta_file
ub_val_ctx_trustedkeys
ub_val_ctx_debuglevel
ub_val_ctx_async
-ub_val_ctx_poll
-ub_val_ctx_wait
-ub_val_ctx_fd
-ub_val_ctx_process
+ub_val_poll
+ub_val_wait
+ub_val_fd
+ub_val_process
ub_val_resolve
ub_val_resolve_async
ub_val_cancel
}
int
-ub_val_ctx_poll(struct ub_val_ctx* ctx)
+ub_val_poll(struct ub_val_ctx* ctx)
{
struct timeval t;
int r;
}
int
-ub_val_ctx_wait(struct ub_val_ctx* ctx)
+ub_val_wait(struct ub_val_ctx* ctx)
{
int r;
lock_basic_lock(&ctx->cfglock);
r = pollit(ctx, NULL);
lock_basic_unlock(&ctx->rrpipe_lock);
if(r)
- ub_val_ctx_process(ctx);
+ ub_val_process(ctx);
lock_basic_lock(&ctx->cfglock);
}
lock_basic_unlock(&ctx->cfglock);
}
int
-ub_val_ctx_fd(struct ub_val_ctx* ctx)
+ub_val_fd(struct ub_val_ctx* ctx)
{
int fd;
lock_basic_lock(&ctx->rrpipe_lock);
}
int
-ub_val_ctx_process(struct ub_val_ctx* ctx)
+ub_val_process(struct ub_val_ctx* ctx)
{
int r;
uint8_t* msg = NULL;
case UB_INITFAIL: return "initialization failure";
case UB_AFTERFINAL: return "setting change after finalize";
case UB_PIPE: return "error in pipe communication with async";
+ case UB_READFILE: return "error reading file";
default: return "unknown error";
}
}
+
+int
+ub_val_ctx_set_fwd(struct ub_val_ctx* ctx, char* addr)
+{
+ struct sockaddr_storage storage;
+ socklen_t stlen;
+ struct config_stub* s;
+ char* dupl;
+ lock_basic_lock(&ctx->cfglock);
+ if(ctx->finalized) {
+ lock_basic_unlock(&ctx->cfglock);
+ errno=EINVAL;
+ return UB_AFTERFINAL;
+ }
+ if(!addr) {
+ /* disable fwd mode - the root stub should be first. */
+ if(ctx->env->cfg->forwards &&
+ strcmp(ctx->env->cfg->forwards->name, ".") == 0) {
+ s = ctx->env->cfg->forwards;
+ ctx->env->cfg->forwards = s->next;
+ s->next = NULL;
+ config_delstubs(s);
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+
+ /* check syntax for addr */
+ if(!extstrtoaddr(addr, &storage, &stlen)) {
+ errno=EINVAL;
+ return UB_SYNTAX;
+ }
+
+ /* it parses, add root stub in front of list */
+ lock_basic_lock(&ctx->cfglock);
+ if(!ctx->env->cfg->forwards ||
+ strcmp(ctx->env->cfg->forwards->name, ".") != 0) {
+ s = calloc(1, sizeof(*s));
+ if(!s) {
+ lock_basic_unlock(&ctx->cfglock);
+ errno=ENOMEM;
+ return UB_NOMEM;
+ }
+ s->name = strdup(".");
+ if(!s->name) {
+ free(s);
+ lock_basic_unlock(&ctx->cfglock);
+ errno=ENOMEM;
+ return UB_NOMEM;
+ }
+ s->next = ctx->env->cfg->forwards;
+ ctx->env->cfg->forwards = s;
+ } else {
+ log_assert(ctx->env->cfg->forwards);
+ s = ctx->env->cfg->forwards;
+ }
+ dupl = strdup(addr);
+ if(!dupl) {
+ lock_basic_unlock(&ctx->cfglock);
+ errno=ENOMEM;
+ return UB_NOMEM;
+ }
+ if(!cfg_strlist_insert(&s->addrs, dupl)) {
+ free(dupl);
+ lock_basic_unlock(&ctx->cfglock);
+ errno=ENOMEM;
+ return UB_NOMEM;
+ }
+ lock_basic_unlock(&ctx->cfglock);
+ return UB_NOERROR;
+}
+
+int
+ub_val_ctx_resolvconf(struct ub_val_ctx* ctx, char* fname)
+{
+ FILE* in;
+ int numserv = 0;
+ char buf[1024];
+ char* parse, *addr;
+ int r;
+ if(fname == NULL)
+ fname = "/etc/resolv.conf";
+ in = fopen(fname, "r");
+ if(!in) {
+ /* error in errno! perror(fname) */
+ return UB_READFILE;
+ }
+ while(fgets(buf, (int)sizeof(buf), in)) {
+ buf[sizeof(buf)-1] = 0;
+ parse=buf;
+ while(*parse == ' ' || *parse == '\t')
+ parse++;
+ if(strncmp(parse, "nameserver", 10) == 0) {
+ numserv++;
+ parse += 10; /* skip 'nameserver' */
+ /* skip whitespace */
+ while(*parse == ' ' || *parse == '\t')
+ parse++;
+ addr = parse;
+ /* skip [0-9a-fA-F.:]*, i.e. IP4 and IP6 address */
+ while(isxdigit(*parse) || *parse=='.' || *parse==':')
+ parse++;
+ /* terminate after the address, remove newline */
+ *parse = 0;
+
+ if((r = ub_val_ctx_set_fwd(ctx, addr)) != UB_NOERROR) {
+ fclose(in);
+ return r;
+ }
+ }
+ }
+ fclose(in);
+ if(numserv == 0) {
+ /* from resolv.conf(5) if none given, use localhost */
+ log_info("resconf: no nameservers, using localhost");
+ return ub_val_ctx_set_fwd(ctx, "127.0.0.1");
+ }
+ return UB_NOERROR;
+}
* Application not threaded. Non-blocking ('asynchronous').
* err = ub_val_resolve_async(ctx, "www.example.com", ... my_callback);
* ... application resumes processing ...
- * ... and when either ub_val_ctx_poll(ctx) is true
- * ... or when the file descriptor ub_val_ctx_fd(ctx) is readable,
+ * ... and when either ub_val_poll(ctx) is true
+ * ... or when the file descriptor ub_val_fd(ctx) is readable,
* ... or whenever, the app calls ...
- * ub_val_ctx_process(ctx);
+ * ub_val_process(ctx);
* ... if no result is ready, the app resumes processing above,
* ... or process() calls my_callback() with results.
*
* ... if the application has nothing more to do, wait for answer
- * ub_val_ctx_wait(ctx);
+ * ub_val_wait(ctx);
*
* Application threaded. Blocking.
* Blocking, same as above. The current thread does the work.
* 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
+ * ub_val_resolve() and ub_val_resolve_async() && ub_val_wait() are
* not the same. The first makes the current thread do the work, setting
* up buffers, etc, to perform the work (but using shared cache data).
* The second calls another worker thread (or process) to perform the work.
*/
int ub_val_ctx_config(struct ub_val_ctx* ctx, char* fname);
+/**
+ * Set machine to forward DNS queries to, the caching resolver to use.
+ * IP4 or IP6 address. Forwards all DNS requests to that machine, which
+ * is expected to run a recursive resolver. If the proxy is not
+ * DNSSEC-capable, validation may fail. Can be called several times, in
+ * that case the addresses are used as backup servers.
+ *
+ * To read the list of nameservers from /etc/resolv.conf (from DHCP or so),
+ * use the call ub_val_ctx_resolvconf.
+ *
+ * @param ctx: context.
+ * At this time it is only possible to set configuration before the
+ * first resolve is done.
+ * @param addr: address, IP4 or IP6 in string format.
+ * If the addr is NULL, forwarding is disabled.
+ * @return 0 if OK, else error.
+ */
+int ub_val_ctx_set_fwd(struct ub_val_ctx* ctx, char* addr);
+
+/**
+ * Read list of nameservers to use from the filename given.
+ * Usually "/etc/resolv.conf". Uses those nameservers as caching proxies.
+ * If they do not support DNSSEC, validation may fail.
+ *
+ * Only nameservers are picked up, the searchdomain, ndots and other
+ * settings from resolv.conf(5) are ignored.
+ *
+ * @param ctx: context.
+ * At this time it is only possible to set configuration before the
+ * first resolve is done.
+ * @param fname: file name string. If NULL "/etc/resolv.conf" is used.
+ * @return 0 if OK, else error.
+ */
+int ub_val_ctx_resolvconf(struct ub_val_ctx* ctx, char* fname);
+
/**
* Add a trust anchor to the given context.
* The trust anchor is a string, on one line, that holds a valid DNSKEY or
* @return: 0 if nothing to read, or nonzero if a result is available.
* If nonzero, call ctx_process() to do callbacks.
*/
-int ub_val_ctx_poll(struct ub_val_ctx* ctx);
+int ub_val_poll(struct ub_val_ctx* ctx);
/**
- * Wait for a context to finish with results. Calls ctx_process() after
+ * Wait for a context to finish with results. Calls ub_val_process() after
* the wait for you. After the wait, there are no more outstanding
* asynchronous queries.
* @param ctx: context.
* @return: 0 if OK, else error.
*/
-int ub_val_ctx_wait(struct ub_val_ctx* ctx);
+int ub_val_wait(struct ub_val_ctx* ctx);
/**
* Get file descriptor. Wait for it to become readable, at this point
* answers are returned from the asynchronous validating resolver.
- * Then call the ub_val_ctx_process to continue processing.
+ * Then call the ub_val_process to continue processing.
* This routine works immediately after context creation, the fd
* does not change.
* @param ctx: context.
* @return: -1 on error, or file descriptor to use select(2) with.
*/
-int ub_val_ctx_fd(struct ub_val_ctx* ctx);
+int ub_val_fd(struct ub_val_ctx* ctx);
/**
* Call this routine to continue processing results from the validating
* @param ctx: context
* @return: 0 if OK, else error.
*/
-int ub_val_ctx_process(struct ub_val_ctx* ctx);
+int ub_val_process(struct ub_val_ctx* ctx);
/**
* Perform resolution and validation of the target name.
printf("-d : enable debug output\n");
printf("-t : use a resolver thread instead of forking a process\n");
printf("-c : cancel the requests\n");
+ printf("-r fname : read resolv.conf from fname\n");
+ printf("-f addr : use addr, forward to that server\n");
exit(1);
}
argc--;
argv++;
}
+ if(argc > 1 && strcmp(argv[0], "-r") == 0) {
+ r = ub_val_ctx_resolvconf(ctx, argv[1]);
+ if(r != 0) {
+ printf("ub_val_ctx_resolvconf error: %s : %s\n",
+ ub_val_strerror(r), strerror(errno));
+ return 1;
+ }
+ argc-=2;
+ argv+=2;
+ }
+ if(argc > 1 && strcmp(argv[0], "-f") == 0) {
+ r = ub_val_ctx_set_fwd(ctx, argv[1]);
+ if(r != 0) {
+ printf("ub_val_ctx_set_fwd error: %s\n",
+ ub_val_strerror(r));
+ return 1;
+ }
+ argc-=2;
+ argv+=2;
+ }
/* allocate array for results. */
lookups = (struct lookinfo*)calloc((size_t)argc,
r = ub_val_resolve_async(ctx, argv[i], LDNS_RR_TYPE_A,
LDNS_RR_CLASS_IN, &lookups[i], &lookup_is_done,
&lookups[i].async_id);
+ if(r != 0) {
+ printf("ub_val_resolve_async error: %s\n",
+ ub_val_strerror(r));
+ return 1;
+ }
}
if(cancel) {
for(i=0; i<argc; i++) {
for(i=0; i<1000; i++) {
usleep(100000);
fprintf(stderr, "%g seconds passed\n", 0.1*(double)i);
- r = ub_val_ctx_process(ctx);
+ r = ub_val_process(ctx);
if(r != 0) {
- printf("ub_val_ctx_process error: %s\n",
+ printf("ub_val_process error: %s\n",
ub_val_strerror(r));
return 1;
}
}
}
-/** delete config stublist */
-static void
+void
config_delstubs(struct config_stub* p)
{
struct config_stub* np;
*/
void config_deldblstrlist(struct config_str2list* list);
+/**
+ * Delete items in config stub list.
+ * @param list: list.
+ */
+void config_delstubs(struct config_stub* list);
+
/**
* Convert 14digit to time value
* @param str: string of 14 digits