forward command for unbound-control.

git-svn-id: file:///svn/unbound/trunk@1482 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2009-02-13 15:26:37 +00:00
parent dfef08c21f
commit a2dcd9c019
14 changed files with 231 additions and 50 deletions

View 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);

View 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);

View 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.

View 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"

View 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);
}

View 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 */

View 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)) {

View 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);
}
/**

View 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;

View 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;
}

View 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);

View 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];
};

View 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)");
}
}

View 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 */