]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
forwarder mode options for library.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 24 Jan 2008 14:58:51 +0000 (14:58 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 24 Jan 2008 14:58:51 +0000 (14:58 +0000)
git-svn-id: file:///svn/unbound/trunk@895 be551aaa-1e26-0410-a405-d3ace91eadb9

doc/Changelog
doc/libunbound.3
libunbound/context.h
libunbound/ubsyms.def
libunbound/unbound.c
libunbound/unbound.h
testcode/asynclook.c
util/config_file.c
util/config_file.h

index aa60812ff6d3efadf2ee5713c0bf370b1b9e9c39..fd0c7b4f0ae201b610870c3438cc4da3263cf6ca 100644 (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.
index d2a2bfd95d43f3c27cbc493836787d181024ba8a..27d2bee423dfd8d9f2a8e559d543e28d2a78db3a 100644 (file)
 .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, 
@@ -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), 
index e1e8819ec54a83b07a5e4eba31bd4e1ee100e652..5be7dc8acb6ca10caf192037bab221e05b923294 100644 (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
 };
 
 /**
index 8e4ae9d48354c698ab4e8d958720b15b665e7017..ed1ebbf6ddf18900e140e25657bcc2e4bd112279 100644 (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
index 148c22737503ee01f7963a755f76b0c0f978b957..a3fcf95c32cdb4be26872fe510fc98367fe42fdc 100644 (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;
+}
index bbfb6469049e1e50f17543d3fc0c0dc154fdb028..aa6b81a1412046c8f06831cc13fee652f824de0d 100644 (file)
  * 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.
index 53714275a73ab6e03145607564282610774bbf64..91939eb98ffd99d27f3f5ec511432afb0ee7d3e4 100644 (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;
                }
index 7634170b8473ed0580b7fc72872f5ac24437de8f..34fe2d0be24424106c233779ebc7bdca30cccfa4 100644 (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;
index 0fda53fff2e8db0202d14c00c0be50aa9833b2c2..98a7325c56209a3e3ff53b6a1cc3211f1891c1b1 100644 (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