]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
forward command for unbound-control.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 13 Feb 2009 15:26:37 +0000 (15:26 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Fri, 13 Feb 2009 15:26:37 +0000 (15:26 +0000)
git-svn-id: file:///svn/unbound/trunk@1482 be551aaa-1e26-0410-a405-d3ace91eadb9

14 files changed:
daemon/remote.c
daemon/worker.c
doc/Changelog
doc/unbound-control.8.in
iterator/iter_fwd.c
iterator/iter_fwd.h
iterator/iter_utils.c
iterator/iterator.c
iterator/iterator.h
libunbound/libworker.c
smallapp/unbound-control.c
util/module.h
util/net_help.c
util/net_help.h

index 6cd52e0ba88ea38e34a02c9e0ac2385f4b464e37..8d569bb7cb3e6af8aa1bd9c23ee409c8d46cdaa6 100644 (file)
@@ -63,6 +63,8 @@
 #include "validator/val_kcache.h"
 #include "validator/val_kentry.h"
 #include "iterator/iterator.h"
+#include "iterator/iter_fwd.h"
+#include "iterator/iter_delegpt.h"
 #include "services/outbound_list.h"
 #include "services/outside_network.h"
 
@@ -1221,24 +1223,102 @@ do_flush_name(SSL* ssl, struct worker* worker, char* arg)
 
 /** print root forwards */
 static int
-print_root_fwds(SSL* ssl, struct config_file* cfg)
+print_root_fwds(SSL* ssl, struct iter_forwards* fwds, uint8_t* root)
 {
-       struct config_stub* s;
-       if(!ssl_printf(ssl, "root-forward:"))
-               return 0;
-       for(s = cfg->forwards; s; s = s->next) {
-               if(s->name && strcmp(s->name, ".") == 0) {
-                       struct config_strlist* p;
-                       for(p = s->hosts; p; p = p->next)
-                               if(!ssl_printf(ssl, " %s", p->str))
-                                       return 0;
-                       for(p = s->addrs; p; p = p->next)
-                               if(!ssl_printf(ssl, " %s", p->str))
-                                       return 0;
-                       return ssl_printf(ssl, "\n");
+       char buf[257];
+       struct delegpt* dp;
+       struct delegpt_ns* ns;
+       struct delegpt_addr* a;
+       int f = 0;
+       dp = forwards_lookup(fwds, root, LDNS_RR_CLASS_IN);
+       if(!dp) 
+               return ssl_printf(ssl, "off (using root hints)\n");
+       /* if dp is returned it must be the root */
+       log_assert(query_dname_compare(dp->name, root)==0);
+       for(ns = dp->nslist; ns; ns = ns->next) {
+               dname_str(ns->name, buf);
+               if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf))
+                       return 0;
+               f = 1;
+       }
+       for(a = dp->target_list; a; a = a->next_target) {
+               addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf));
+               if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf))
+                       return 0;
+               f = 1;
+       }
+       return ssl_printf(ssl, "\n");
+}
+
+/** parse args into delegpt */
+static struct delegpt*
+parse_delegpt(SSL* ssl, struct regional* region, char* args, uint8_t* root)
+{
+       /* parse args and add in */
+       char* p = args;
+       char* todo;
+       struct delegpt* dp = delegpt_create(region);
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+       if(!dp || !delegpt_set_name(dp, region, root)) {
+               (void)ssl_printf(ssl, "error out of memory\n");
+               return NULL;
+       }
+       while(p) {
+               todo = p;
+               p = strchr(p, ' '); /* find next spot, if any */
+               if(p) {
+                       *p++ = 0;       /* end this spot */
+                       p = skipwhite(p); /* position at next spot */
+               }
+               /* parse address */
+               if(!extstrtoaddr(todo, &addr, &addrlen)) {
+                       (void)ssl_printf(ssl, "error cannot parse"
+                               " IP address '%s'\n", todo);
+                       return NULL;
+               }
+               /* add address */
+               if(!delegpt_add_addr(dp, region, &addr, addrlen, 0, 1)) {
+                       (void)ssl_printf(ssl, "error out of memory\n");
+                       return NULL;
                }
        }
-       return ssl_printf(ssl, " no (using root hints)\n");
+       return dp;
+}
+
+/** do the status command */
+static void
+do_forward(SSL* ssl, struct worker* worker, char* args)
+{
+       struct iter_forwards* fwd = worker->env.fwds;
+       uint8_t* root = (uint8_t*)"\000";
+       if(!fwd) {
+               (void)ssl_printf(ssl, "error: structure not allocated\n");
+               return;
+       }
+       if(args == NULL || args[0] == 0) {
+               (void)print_root_fwds(ssl, fwd, root);
+               return;
+       }
+       /* set root forwards for this thread. since we are in remote control
+        * the actual mesh is not running, so we can freely edit it. */
+       /* delete all the existing queries first */
+       mesh_delete_all(worker->env.mesh);
+       /* reset the fwd structure ; the cfg is unchanged (shared by threads)*/
+       /* this reset frees up memory */
+       forwards_apply_cfg(fwd, worker->env.cfg);
+       if(strcmp(args, "off") == 0) {
+               forwards_delete_zone(fwd, LDNS_RR_CLASS_IN, root);
+       } else {
+               struct delegpt* dp;
+               if(!(dp = parse_delegpt(ssl, fwd->region, args, root)))
+                       return;
+               if(!forwards_add_zone(fwd, LDNS_RR_CLASS_IN, dp)) {
+                       (void)ssl_printf(ssl, "error out of memory\n");
+                       return;
+               }
+       }
+       send_ok(ssl);
 }
 
 /** do the status command */
@@ -1261,8 +1341,6 @@ do_status(SSL* ssl, struct worker* worker)
        }
        if(!ssl_printf(ssl, " ]\n"))
                return;
-       if(!print_root_fwds(ssl, worker->env.cfg))
-               return;
        uptime = (time_t)time(NULL) - (time_t)worker->daemon->time_boot.tv_sec;
        if(!ssl_printf(ssl, "uptime: %u seconds\n", (unsigned)uptime))
                return;
@@ -1310,21 +1388,11 @@ get_mesh_status(struct mesh_area* mesh, struct mesh_state* m,
                if(ol->first == NULL)
                        snprintf(buf, len, " (empty_list)");
                for(e = ol->first; e; e = e->next) {
-                       int af = (int)((struct sockaddr_in*)&e->qsent->addr)
-                               ->sin_family;
-                       void* sinaddr = &((struct sockaddr_in*)&e->qsent->addr)
-                               ->sin_addr;
-                       if(addr_is_ip6(&e->qsent->addr, e->qsent->addrlen))
-                               sinaddr = &((struct sockaddr_in6*)
-                                       &e->qsent->addr)->sin6_addr;
-
                        snprintf(buf, len, " ");
                        l = strlen(buf);
                        buf += l; len -= l;
-
-                       if(inet_ntop(af, sinaddr, buf, (socklen_t)len) == 0) {
-                               snprintf(buf, len, "(inet_ntop_error)");
-                       }
+                       addr_to_str(&e->qsent->addr, e->qsent->addrlen, 
+                               buf, len);
                        l = strlen(buf);
                        buf += l; len -= l;
                }
@@ -1434,6 +1502,11 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd,
        } else if(strncmp(p, "load_cache", 10) == 0) {
                if(load_cache(ssl, worker)) send_ok(ssl);
                return;
+       } else if(strncmp(p, "forward", 7) == 0) {
+               /* must always distribute this cmd */
+               if(rc) distribute_cmd(rc, ssl, cmd);
+               do_forward(ssl, worker, skipwhite(p+7));
+               return;
        } else if(strncmp(p, "flush_stats", 11) == 0) {
                /* must always distribute this cmd */
                if(rc) distribute_cmd(rc, ssl, cmd);
index e3ab440fde6fffe02dce0532ea5beb2cc6e75aed..08ea72a8dab9fd1303ec7798e6c082c92bb6bf41 100644 (file)
@@ -65,6 +65,7 @@
 #include "util/data/dname.h"
 #include "util/fptr_wlist.h"
 #include "util/tube.h"
+#include "iterator/iter_fwd.h"
 
 #ifdef HAVE_SYS_TYPES_H
 #  include <sys/types.h>
@@ -158,7 +159,8 @@ worker_mem_report(struct worker* ATTR_UNUSED(worker),
                + sizeof(worker->rndstate) 
                + regional_get_mem(worker->scratchpad) 
                + sizeof(*worker->env.scratch_buffer) 
-               + ldns_buffer_capacity(worker->env.scratch_buffer);
+               + ldns_buffer_capacity(worker->env.scratch_buffer)
+               + forwards_get_mem(worker->env.fwds);
        if(cur_serv) {
                me += serviced_get_mem(cur_serv);
        }
@@ -1119,6 +1121,12 @@ worker_init(struct worker* worker, struct config_file *cfg,
        worker->env.kill_sub = &mesh_state_delete;
        worker->env.detect_cycle = &mesh_detect_cycle;
        worker->env.scratch_buffer = ldns_buffer_new(cfg->msg_buffer_size);
+       if(!(worker->env.fwds = forwards_create()) ||
+               !forwards_apply_cfg(worker->env.fwds, cfg)) {
+               log_err("Could not set forward zones");
+               worker_delete(worker);
+               return 0;
+       }
        if(!worker->env.mesh || !worker->env.scratch_buffer) {
                worker_delete(worker);
                return 0;
@@ -1151,6 +1159,7 @@ worker_delete(struct worker* worker)
        }
        mesh_delete(worker->env.mesh);
        ldns_buffer_free(worker->env.scratch_buffer);
+       forwards_delete(worker->env.fwds);
        listen_delete(worker->front);
        outside_network_delete(worker->back);
        comm_signal_delete(worker->comsig);
index ba9280153682fdfc6af7efab74ca316d428ce593..79d42011dcdf4f23d9de879b99b5484af2c18d4f 100644 (file)
@@ -1,3 +1,9 @@
+13 February 2009: Wouter
+       - forwarder information now per-thread duplicated.
+         This keeps it read only for speed, with no locking necessary.
+       - forward command for unbound control to change forwarders to use
+         on the fly.
+
 12 February 2009: Wouter
        - call setusercontext if available (on BSD).
        - small refactor of stats clearing.
index 3b0471e69d42107856f565e23dc5d754011e6098..cb6e9fa56032e9a0fa4a8afbff151cc1de94a253 100644 (file)
@@ -134,6 +134,27 @@ such as a higher verbosity level.
 Show what is worked on.  Prints all queries that the server is currently
 working on.  Prints the time that users have been waiting.  For internal
 requests, no time is printed.  And then prints out the module status.
+.TP
+.B forward [off | addr ... ]
+Setup forwarding mode.  Configures if the server should ask other upstream
+nameservers, should go to the internet root nameservers itself, or show 
+the current config.  You could pass the nameservers after a DHCP update.
+.IP
+Without arguments the current list of addresses used to forward all queries
+to is printed.  On startup this is from the forward-zone "." configuration.
+Afterwards it shows the status.  It prints off when no forwarding is used.
+.IP
+If \fIoff\fR is passed, forwarding is disabled and the root nameservers
+are used.  This can be used to avoid to avoid buggy or non-DNSSEC supporting
+nameservers returned from DHCP.  But may not work in hotels or hotspots.
+.IP
+If one or more IPv4 or IPv6 addresses are given, those are then used to forward
+queries to.  The addresses must be separated with spaces.  With '@port' the
+port number can be set explicitly (default port is 53 (DNS)).
+.IP
+By default the forwarder information from the config file for the root "." is
+used.  The config file is not changed, so after a reload these changes are
+gone.  Other forward zones from the config file are not affected by this command.
 .SH "EXIT CODE"
 The unbound-control program exits with status code 1 on error, 0 on success.
 .SH "SET UP"
index d7485f624f56f346b84c8662f0420065ad6d780c..94ca78f824dc040583ba23efdc5cba6323450b30 100644 (file)
@@ -292,3 +292,27 @@ forwards_get_mem(struct iter_forwards* fwd)
        return sizeof(*fwd) + sizeof(*fwd->tree) + 
                regional_get_mem(fwd->region);
 }
+
+int 
+forwards_add_zone(struct iter_forwards* fwd, uint16_t c, struct delegpt* dp)
+{
+       if(!forwards_insert(fwd, c, dp))
+               return 0;
+       fwd_init_parents(fwd);
+       return 1;
+}
+
+void 
+forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm)
+{
+       struct iter_forward_zone key;
+       key.node.key = &key;
+       key.dclass = c;
+       key.name = nm;
+       key.namelabs = dname_count_size_labels(nm, &key.namelen);
+       if(!rbtree_search(fwd->tree, &key))
+               return; /* nothing to do */
+       (void)rbtree_delete(fwd->tree, &key);
+       fwd_init_parents(fwd);
+}
+
index dca4e648b91739db6f000c4fa1f4ff39448015b2..6ea2d12304ca197f9b2998c5f70ca11590c9b27c 100644 (file)
@@ -43,7 +43,6 @@
 #ifndef ITERATOR_ITER_FWD_H
 #define ITERATOR_ITER_FWD_H
 #include "util/rbtree.h"
-struct iter_env;
 struct config_file;
 struct delegpt;
 struct regional;
@@ -128,4 +127,28 @@ size_t forwards_get_mem(struct iter_forwards* fwd);
 /** compare two fwd entries */
 int fwd_cmp(const void* k1, const void* k2);
 
+/**
+ * Add zone to forward structure. For external use since it recalcs 
+ * the tree parents.
+ * @param fwd: the forward data structure
+ * @param c: class of zone
+ * @param dp: delegation point with name and target nameservers for new
+ *     forward zone. This delegation point and all its data must be
+ *     malloced in the fwd->region. (then it is freed when the fwd is
+ *     deleted).
+ * @return false on failure (out of memory);
+ */
+int forwards_add_zone(struct iter_forwards* fwd, uint16_t c, 
+       struct delegpt* dp);
+
+/**
+ * Remove zone from forward structure. For external use since it 
+ * recalcs the tree parents. Does not actually release any memory, the region 
+ * is unchanged.
+ * @param fwd: the forward data structure
+ * @param c: class of zone
+ * @param nm: name of zone (in uncompressed wireformat).
+ */
+void forwards_delete_zone(struct iter_forwards* fwd, uint16_t c, uint8_t* nm);
+
 #endif /* ITERATOR_ITER_FWD_H */
index 2133be755c11e0acf48554b753c4400716a7623e..c35b276f102032ff89728b4134338813f42c3e25 100644 (file)
@@ -112,12 +112,6 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
                log_err("Could not set root or stub hints");
                return 0;
        }
-       if(!iter_env->fwds)
-               iter_env->fwds = forwards_create();
-       if(!iter_env->fwds || !forwards_apply_cfg(iter_env->fwds, cfg)) {
-               log_err("Could not set forward zones");
-               return 0;
-       }
        if(!iter_env->donotq)
                iter_env->donotq = donotq_create();
        if(!iter_env->donotq || !donotq_apply_cfg(iter_env->donotq, cfg)) {
index dac8581e03449bb5597d2a88894aecc7a3ae770b..878c5c92e850949b99257385be61a39ea9e47954 100644 (file)
@@ -89,7 +89,6 @@ iter_deinit(struct module_env* env, int id)
        free(iter_env->target_fetch_policy);
        priv_delete(iter_env->priv);
        hints_delete(iter_env->hints);
-       forwards_delete(iter_env->fwds);
        donotq_delete(iter_env->donotq);
        free(iter_env);
        env->modinfo[id] = NULL;
@@ -775,16 +774,14 @@ generate_ns_check(struct module_qstate* qstate, struct iter_qstate* iq, int id)
  * 
  * @param qstate: query state.
  * @param iq: iterator query state.
- * @param ie: iterator shared global environment.
  * @return true if the request is forwarded, false if not.
  *     If returns true but, iq->dp is NULL then a malloc failure occurred.
  */
 static int
-forward_request(struct module_qstate* qstate, struct iter_qstate* iq,
-       struct iter_env* ie)
+forward_request(struct module_qstate* qstate, struct iter_qstate* iq)
 {
-       struct delegpt* dp = forwards_lookup(ie->fwds, iq->qchase.qname,
-               iq->qchase.qclass);
+       struct delegpt* dp = forwards_lookup(qstate->env->fwds, 
+               iq->qchase.qname, iq->qchase.qclass);
        if(!dp) 
                return 0;
        /* send recursion desired to forward addr */
@@ -892,7 +889,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
        }
        
        /* attempt to forward the request */
-       if(forward_request(qstate, iq, ie))
+       if(forward_request(qstate, iq))
        {
                if(!iq->dp) {
                        log_err("alloc failure for forward dp");
@@ -2129,8 +2126,7 @@ iter_get_mem(struct module_env* env, int id)
        if(!ie)
                return 0;
        return sizeof(*ie) + sizeof(int)*((size_t)ie->max_dependency_depth+1)
-               + hints_get_mem(ie->hints) + forwards_get_mem(ie->fwds)
-               + donotq_get_mem(ie->donotq);
+               + hints_get_mem(ie->hints) + donotq_get_mem(ie->donotq);
 }
 
 /**
index a3f839bf9c74416e632aec3e3551e792df28535f..c70dadd9c7f9300293dd660fb0402e99751f79e6 100644 (file)
@@ -87,9 +87,6 @@ struct iter_env {
        /** A flag to indicate whether or not we have an IPv6 route */
        int supports_ipv6;
 
-       /** Mapping of forwarding zones to targets. */
-       struct iter_forwards* fwds;
-
        /** A set of inetaddrs that should never be queried. */
        struct iter_donotq* donotq;
 
index 10baff79a7612547eb4fc34d5ac5ddd3d6e4b8f2..5f90bf249c110774fb44353191db15d90090bf6e 100644 (file)
@@ -61,6 +61,7 @@
 #include "util/data/msgreply.h"
 #include "util/data/msgencode.h"
 #include "util/tube.h"
+#include "iterator/iter_fwd.h"
 
 /** handle new query command for bg worker */
 static void handle_newq(struct libworker* w, uint8_t* buf, uint32_t len);
@@ -76,6 +77,7 @@ libworker_delete(struct libworker* w)
                        !w->is_bg || w->is_bg_thread);
                ldns_buffer_free(w->env->scratch_buffer);
                regional_destroy(w->env->scratch);
+               forwards_delete(w->env->fwds);
                ub_randfree(w->env->rnd);
                free(w->env);
        }
@@ -114,10 +116,15 @@ libworker_setup(struct ub_ctx* ctx, int is_bg)
        }
        w->env->scratch = regional_create_custom(cfg->msg_buffer_size);
        w->env->scratch_buffer = ldns_buffer_new(cfg->msg_buffer_size);
+       w->env->fwds = forwards_create();
+       if(w->env->fwds && !forwards_apply_cfg(w->env->fwds, cfg)) { 
+               forwards_delete(w->env->fwds);
+               w->env->fwds = NULL;
+       }
        if(!w->is_bg || w->is_bg_thread) {
                lock_basic_unlock(&ctx->cfglock);
        }
-       if(!w->env->scratch || !w->env->scratch_buffer) {
+       if(!w->env->scratch || !w->env->scratch_buffer || !w->env->fwds) {
                libworker_delete(w);
                return NULL;
        }
index 2d90a05e7ed65cef5e4cd637fe8788f367993636..9cfd46a24bb0c110ae46b4271fc570e4b3adfbe5 100644 (file)
@@ -83,6 +83,9 @@ usage()
        printf("  flush_stats                   flush statistics, make zero\n");
        printf("  flush_requestlist             drop queries that are worked on\n");
        printf("  dump_requestlist              show what is worked on\n");
+       printf("  forward [off | addr ...]      without arg show forward setup\n");
+       printf("                                or off to turn off root forwarding\n");
+       printf("                                or give list of ip addresses\n");
        printf("Version %s\n", PACKAGE_VERSION);
        printf("BSD licensed, see LICENSE in source package for details.\n");
        printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
index 21682849043f465417091411a1b8620c3b6baef3..736956716b6629568ee5577d3e87b75d654fdd2f 100644 (file)
@@ -58,6 +58,7 @@ struct mesh_area;
 struct mesh_state;
 struct val_anchors;
 struct val_neg_cache;
+struct iter_forwards;
 
 /** Maximum number of modules in operation */
 #define MAX_MODULE 5
@@ -208,6 +209,9 @@ struct module_env {
        /** negative cache, configured by the validator. if not NULL,
         * contains NSEC record lookup trees. */
        struct val_neg_cache* neg_cache;
+       /** Mapping of forwarding zones to targets.
+        * iterator forwarder information. per-thread, created by worker */
+       struct iter_forwards* fwds;
        /** module specific data. indexed by module id. */
        void* modinfo[MAX_MODULE];
 };
index 7a901c99075086303ab0f95d8844f434d13ad097..c77ccdc7ca539fc926c2a4ded4f3924e4d030445 100644 (file)
@@ -461,3 +461,16 @@ addr_in_common(struct sockaddr_storage* addr1, int net1,
        if(match > min) match = min;
        return match;
 }
+
+void 
+addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen, 
+       char* buf, size_t len)
+{
+       int af = (int)((struct sockaddr_in*)addr)->sin_family;
+       void* sinaddr = &((struct sockaddr_in*)addr)->sin_addr;
+       if(addr_is_ip6(addr, addrlen))
+               sinaddr = &((struct sockaddr_in6*)addr)->sin6_addr;
+       if(inet_ntop(af, sinaddr, buf, (socklen_t)len) == 0) {
+               snprintf(buf, len, "(inet_ntop_error)");
+       }
+}
index 0ad88b4129f0f2a5d4027e6158610f47c379cf54..0a60cae9883d1389bbb6a0e187260239587eb046 100644 (file)
@@ -258,4 +258,15 @@ void addr_mask(struct sockaddr_storage* addr, socklen_t len, int net);
 int addr_in_common(struct sockaddr_storage* addr1, int net1,
        struct sockaddr_storage* addr2, int net2, socklen_t addrlen);
 
+/**
+ * Put address into string, works for IPv4 and IPv6.
+ * @param addr: address
+ * @param addrlen: length of address
+ * @param buf: result string stored here
+ * @param len: length of buf.
+ * On failure a string with "error" is stored inside.
+ */
+void addr_to_str(struct sockaddr_storage* addr, socklen_t addrlen,
+       char* buf, size_t len);
+
 #endif /* NET_HELP_H */