forwarder mode options for library.

git-svn-id: file:///svn/unbound/trunk@895 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-01-24 14:58:51 +00:00
parent 452b7cc069
commit 2e28288b1d
9 changed files with 263 additions and 42 deletions

View File

@ -5,6 +5,8 @@
- 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.

View File

@ -17,15 +17,17 @@
.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,
@ -46,6 +48,12 @@
\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
@ -65,16 +73,16 @@
\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,
@ -138,6 +146,25 @@ A power\-user interface that lets you specify an unbound config file, see
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.
@ -173,27 +200,27 @@ Changes to this setting after
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.
@ -264,9 +291,9 @@ to obtain a readable error string.
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),

View File

@ -175,7 +175,9 @@ enum ub_ctx_err {
/** 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
};
/**

View File

@ -1,15 +1,17 @@
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

View File

@ -319,7 +319,7 @@ pollit(struct ub_val_ctx* ctx, struct timeval* t)
}
int
ub_val_ctx_poll(struct ub_val_ctx* ctx)
ub_val_poll(struct ub_val_ctx* ctx)
{
struct timeval t;
int r;
@ -331,7 +331,7 @@ ub_val_ctx_poll(struct ub_val_ctx* ctx)
}
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);
@ -341,7 +341,7 @@ ub_val_ctx_wait(struct ub_val_ctx* ctx)
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);
@ -349,7 +349,7 @@ ub_val_ctx_wait(struct ub_val_ctx* ctx)
}
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);
@ -418,7 +418,7 @@ process_answer(struct ub_val_ctx* ctx, uint8_t* msg, uint32_t len)
}
int
ub_val_ctx_process(struct ub_val_ctx* ctx)
ub_val_process(struct ub_val_ctx* ctx)
{
int r;
uint8_t* msg = NULL;
@ -601,6 +601,127 @@ ub_val_strerror(int err)
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;
}

View File

@ -57,15 +57,15 @@
* 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.
@ -84,7 +84,7 @@
* 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.
@ -217,6 +217,41 @@ void ub_val_ctx_delete(struct ub_val_ctx* ctx);
*/
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
@ -283,27 +318,27 @@ int ub_val_ctx_async(struct ub_val_ctx* ctx, int dothread);
* @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
@ -312,7 +347,7 @@ int ub_val_ctx_fd(struct ub_val_ctx* ctx);
* @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.

View File

@ -69,6 +69,8 @@ void usage(char* argv[])
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);
}
@ -119,6 +121,26 @@ int main(int argc, char** argv)
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,
@ -136,6 +158,11 @@ int main(int argc, char** argv)
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++) {
@ -149,9 +176,9 @@ int main(int argc, char** argv)
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;
}

View File

@ -220,8 +220,7 @@ config_deldblstrlist(struct config_str2list* p)
}
}
/** delete config stublist */
static void
void
config_delstubs(struct config_stub* p)
{
struct config_stub* np;

View File

@ -298,6 +298,12 @@ void config_delstrlist(struct config_strlist* list);
*/
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