mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
add remove local data and local zone with remote control
(ldns-testpkts sync with ldns trunk). git-svn-id: file:///svn/unbound/trunk@1261 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
parent
c77be35670
commit
cf4b56d883
10 changed files with 586 additions and 52 deletions
|
|
@ -9,8 +9,9 @@
|
||||||
# statistics-cumulative: no
|
# statistics-cumulative: no
|
||||||
# statistics-interval: 0
|
# statistics-interval: 0
|
||||||
# remote-control: control-enable: yes
|
# remote-control: control-enable: yes
|
||||||
|
# Run the command unbound-control-setup to generate the key files.
|
||||||
#
|
#
|
||||||
# Environment variables
|
# Environment variables for this script
|
||||||
# statefile - where to put temporary statefile.
|
# statefile - where to put temporary statefile.
|
||||||
# unbound_conf - where the unbound.conf file is located.
|
# unbound_conf - where the unbound.conf file is located.
|
||||||
# unbound_control - where to find unbound-control executable.
|
# unbound_control - where to find unbound-control executable.
|
||||||
|
|
|
||||||
143
daemon/remote.c
143
daemon/remote.c
|
|
@ -54,8 +54,10 @@
|
||||||
#include "services/listen_dnsport.h"
|
#include "services/listen_dnsport.h"
|
||||||
#include "services/cache/rrset.h"
|
#include "services/cache/rrset.h"
|
||||||
#include "services/mesh.h"
|
#include "services/mesh.h"
|
||||||
|
#include "services/localzone.h"
|
||||||
#include "util/storage/slabhash.h"
|
#include "util/storage/slabhash.h"
|
||||||
#include "util/fptr_wlist.h"
|
#include "util/fptr_wlist.h"
|
||||||
|
#include "util/data/dname.h"
|
||||||
|
|
||||||
#ifdef HAVE_SYS_TYPES_H
|
#ifdef HAVE_SYS_TYPES_H
|
||||||
# include <sys/types.h>
|
# include <sys/types.h>
|
||||||
|
|
@ -839,6 +841,139 @@ do_stats(SSL* ssl, struct daemon_remote* rc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** parse commandline argument domain name */
|
||||||
|
static int
|
||||||
|
parse_arg_name(SSL* ssl, char* str, uint8_t** res, size_t* len, int* labs)
|
||||||
|
{
|
||||||
|
ldns_rdf* rdf;
|
||||||
|
*res = NULL;
|
||||||
|
*len = 0;
|
||||||
|
*labs = 0;
|
||||||
|
rdf = ldns_dname_new_frm_str(str);
|
||||||
|
if(!rdf) {
|
||||||
|
ssl_printf(ssl, "error cannot parse name %s\n", str);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*res = memdup(ldns_rdf_data(rdf), ldns_rdf_size(rdf));
|
||||||
|
ldns_rdf_deep_free(rdf);
|
||||||
|
if(!*res) {
|
||||||
|
ssl_printf(ssl, "error out of memory\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*labs = dname_count_size_labels(*res, len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** find second argument, modifies string */
|
||||||
|
static int
|
||||||
|
find_arg2(SSL* ssl, char* arg, char** arg2)
|
||||||
|
{
|
||||||
|
char* as = strchr(arg, ' ');
|
||||||
|
char* at = strchr(arg, '\t');
|
||||||
|
if(as && at) {
|
||||||
|
if(at < as)
|
||||||
|
as = at;
|
||||||
|
as[0]=0;
|
||||||
|
*arg2 = skipwhite(as+1);
|
||||||
|
} else if(as) {
|
||||||
|
as[0]=0;
|
||||||
|
*arg2 = skipwhite(as+1);
|
||||||
|
} else if(at) {
|
||||||
|
at[0]=0;
|
||||||
|
*arg2 = skipwhite(at+1);
|
||||||
|
} else {
|
||||||
|
ssl_printf(ssl, "error could not find next argument "
|
||||||
|
"after %s\n", arg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add a new zone */
|
||||||
|
static void
|
||||||
|
do_zone_add(SSL* ssl, struct worker* worker, char* arg)
|
||||||
|
{
|
||||||
|
uint8_t* nm;
|
||||||
|
int nmlabs;
|
||||||
|
size_t nmlen;
|
||||||
|
char* arg2;
|
||||||
|
enum localzone_type t;
|
||||||
|
struct local_zone* z;
|
||||||
|
if(!find_arg2(ssl, arg, &arg2))
|
||||||
|
return;
|
||||||
|
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
|
||||||
|
return;
|
||||||
|
if(!local_zone_str2type(arg2, &t)) {
|
||||||
|
ssl_printf(ssl, "error not a zone type. %s\n", arg2);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lock_quick_lock(&worker->daemon->local_zones->lock);
|
||||||
|
if((z=local_zones_find(worker->daemon->local_zones, nm, nmlen,
|
||||||
|
nmlabs, LDNS_RR_CLASS_IN))) {
|
||||||
|
/* already present in tree */
|
||||||
|
lock_rw_wrlock(&z->lock);
|
||||||
|
z->type = t; /* update type anyway */
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
|
lock_quick_unlock(&worker->daemon->local_zones->lock);
|
||||||
|
send_ok(ssl);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(!local_zones_add_zone(worker->daemon->local_zones, nm, nmlen,
|
||||||
|
nmlabs, LDNS_RR_CLASS_IN, t)) {
|
||||||
|
lock_quick_unlock(&worker->daemon->local_zones->lock);
|
||||||
|
ssl_printf(ssl, "error out of memory\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lock_quick_unlock(&worker->daemon->local_zones->lock);
|
||||||
|
send_ok(ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove a zone */
|
||||||
|
static void
|
||||||
|
do_zone_remove(SSL* ssl, struct worker* worker, char* arg)
|
||||||
|
{
|
||||||
|
uint8_t* nm;
|
||||||
|
int nmlabs;
|
||||||
|
size_t nmlen;
|
||||||
|
struct local_zone* z;
|
||||||
|
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
|
||||||
|
return;
|
||||||
|
lock_quick_lock(&worker->daemon->local_zones->lock);
|
||||||
|
if((z=local_zones_find(worker->daemon->local_zones, nm, nmlen,
|
||||||
|
nmlabs, LDNS_RR_CLASS_IN))) {
|
||||||
|
/* present in tree */
|
||||||
|
local_zones_del_zone(worker->daemon->local_zones, z);
|
||||||
|
}
|
||||||
|
lock_quick_unlock(&worker->daemon->local_zones->lock);
|
||||||
|
send_ok(ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Add new RR data */
|
||||||
|
static void
|
||||||
|
do_data_add(SSL* ssl, struct worker* worker, char* arg)
|
||||||
|
{
|
||||||
|
if(!local_zones_add_RR(worker->daemon->local_zones, arg,
|
||||||
|
worker->env.scratch_buffer)) {
|
||||||
|
ssl_printf(ssl,"error in syntax or out of memory, %s\n", arg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
send_ok(ssl);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Remove RR data */
|
||||||
|
static void
|
||||||
|
do_data_remove(SSL* ssl, struct worker* worker, char* arg)
|
||||||
|
{
|
||||||
|
uint8_t* nm;
|
||||||
|
int nmlabs;
|
||||||
|
size_t nmlen;
|
||||||
|
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
|
||||||
|
return;
|
||||||
|
local_zones_del_data(worker->daemon->local_zones, nm,
|
||||||
|
nmlen, nmlabs, LDNS_RR_CLASS_IN);
|
||||||
|
send_ok(ssl);
|
||||||
|
}
|
||||||
|
|
||||||
/** execute a remote control command */
|
/** execute a remote control command */
|
||||||
static void
|
static void
|
||||||
execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd)
|
execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd)
|
||||||
|
|
@ -853,6 +988,14 @@ execute_cmd(struct daemon_remote* rc, SSL* ssl, char* cmd)
|
||||||
do_verbosity(ssl, skipwhite(p+9));
|
do_verbosity(ssl, skipwhite(p+9));
|
||||||
} else if(strncmp(p, "stats", 5) == 0) {
|
} else if(strncmp(p, "stats", 5) == 0) {
|
||||||
do_stats(ssl, rc);
|
do_stats(ssl, rc);
|
||||||
|
} else if(strncmp(p, "local_zone_remove", 17) == 0) {
|
||||||
|
do_zone_remove(ssl, rc->worker, skipwhite(p+17));
|
||||||
|
} else if(strncmp(p, "local_zone", 10) == 0) {
|
||||||
|
do_zone_add(ssl, rc->worker, skipwhite(p+10));
|
||||||
|
} else if(strncmp(p, "local_data_remove", 17) == 0) {
|
||||||
|
do_data_remove(ssl, rc->worker, skipwhite(p+17));
|
||||||
|
} else if(strncmp(p, "local_data", 10) == 0) {
|
||||||
|
do_data_add(ssl, rc->worker, skipwhite(p+10));
|
||||||
} else {
|
} else {
|
||||||
(void)ssl_printf(ssl, "error unknown command '%s'\n", p);
|
(void)ssl_printf(ssl, "error unknown command '%s'\n", p);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,7 @@
|
||||||
|
19 September 2008: Wouter
|
||||||
|
- locking on the localdata structure.
|
||||||
|
- add and remove local zone and data with unbound-control.
|
||||||
|
|
||||||
18 September 2008: Wouter
|
18 September 2008: Wouter
|
||||||
- fixup error in time calculation.
|
- fixup error in time calculation.
|
||||||
- munin plugin improvements.
|
- munin plugin improvements.
|
||||||
|
|
|
||||||
14
doc/plan
14
doc/plan
|
|
@ -43,19 +43,19 @@ like dnswall does. Allow certain subdomains to do it, config options.
|
||||||
note in config/man that we may consider turning on by default.
|
note in config/man that we may consider turning on by default.
|
||||||
|
|
||||||
*** Remote control feature
|
*** Remote control feature
|
||||||
* remote control using a TCP unbound-control commandline app.
|
+ remote control using a TCP unbound-control commandline app.
|
||||||
* secure remote control w. TSIG. Or TLS.
|
+ secure remote control w. TSIG. Or TLS.
|
||||||
* Nicer statistics (over that unbound-control app for ease)
|
+ Nicer statistics (over that unbound-control app for ease)
|
||||||
stats display added over threads, displayed in rddtool easy format.
|
stats display added over threads, displayed in rddtool easy format.
|
||||||
* option for extended statistics. If enabled (not by default) collect print
|
+ option for extended statistics. If enabled (not by default) collect print
|
||||||
rcode, uptime, spoofnearmisses, cache size, qtype,
|
rcode, uptime, spoofnearmisses, cache size, qtype,
|
||||||
bits(RD, CD, DO, EDNS-present, AD)query, (Secure, Bogus)reply.
|
bits(RD, CD, DO, EDNS-present, AD)query, (Secure, Bogus)reply.
|
||||||
perhaps also see which slow auth servers cause >1sec values.
|
|
||||||
stats-file possible with key: value or key=value lines in it.
|
stats-file possible with key: value or key=value lines in it.
|
||||||
stats on SIGUSR1. addup stats over threads.
|
addup stats over threads.
|
||||||
|
not stats on SIGUSR1. perhaps also see which slow auth servers cause >1sec values.
|
||||||
* remote control to add/remove localinfo, redirects.
|
* remote control to add/remove localinfo, redirects.
|
||||||
* remote control to load/store cache contents
|
* remote control to load/store cache contents
|
||||||
* remote control to start, stop, reload.
|
+ remote control to start, stop, reload.
|
||||||
* remote control to flush names or domains (all under a name) from the
|
* remote control to flush names or domains (all under a name) from the
|
||||||
cache. Include NSes. And the A, AAAA for its NSes.
|
cache. Include NSes. And the A, AAAA for its NSes.
|
||||||
* remote control to see delegation; what servers would be used to get
|
* remote control to see delegation; what servers would be used to get
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,30 @@ a reload (taken from config file again), or the next verbosity control command.
|
||||||
Print statistics. Resets the internal counters to zero, this can be
|
Print statistics. Resets the internal counters to zero, this can be
|
||||||
controlled using the \fBstatistics\-cumulative\fR config statement.
|
controlled using the \fBstatistics\-cumulative\fR config statement.
|
||||||
Statistics are printed with one [name]: [value] per line.
|
Statistics are printed with one [name]: [value] per line.
|
||||||
|
.TP
|
||||||
|
.B local_zone \fIname\fR \fItype
|
||||||
|
Add new local zone with name and type. Like \fBlocal\-zone\fR config statement.
|
||||||
|
If the zone already exists, the type is changed to the given argument.
|
||||||
|
.TP
|
||||||
|
.B local_zone_remove \fIname
|
||||||
|
Remove the local zone with the given name. Removes all local data inside
|
||||||
|
it. If the zone does not exist, the command succeeds.
|
||||||
|
.TP
|
||||||
|
.B local_data \fIRR data...
|
||||||
|
Add new local data, the given resource record. Like \fBlocal\-data\fR
|
||||||
|
config statement, except for when no covering zone exists. In that case
|
||||||
|
this remote control command creates a transparent zone with the same
|
||||||
|
name as this record. This command is not good at returning detailed syntax
|
||||||
|
errors.
|
||||||
|
.TP
|
||||||
|
.B local_data_remove \fIname
|
||||||
|
Remove all RR data from local name. If the name already has no items,
|
||||||
|
nothing happens. Often results in NXDOMAIN for the name (in a static zone),
|
||||||
|
but if the name has become an empty nonterminal (there is still data in
|
||||||
|
domain names below the removed name), NOERROR nodata answers are the
|
||||||
|
result for that name.
|
||||||
.SH "EXIT CODE"
|
.SH "EXIT CODE"
|
||||||
The unbound-control program exits with status code 1 on error.
|
The unbound-control program exits with status code 1 on error, 0 on success.
|
||||||
.SH "SET UP"
|
.SH "SET UP"
|
||||||
The setup requires a self\-signed certificate and private keys for both
|
The setup requires a self\-signed certificate and private keys for both
|
||||||
the server and client. The script \fIunbound\-control\-setup\fR generates
|
the server and client. The script \fIunbound\-control\-setup\fR generates
|
||||||
|
|
|
||||||
|
|
@ -57,6 +57,9 @@ local_zones_create()
|
||||||
if(!zones)
|
if(!zones)
|
||||||
return NULL;
|
return NULL;
|
||||||
rbtree_init(&zones->ztree, &local_zone_cmp);
|
rbtree_init(&zones->ztree, &local_zone_cmp);
|
||||||
|
lock_quick_init(&zones->lock);
|
||||||
|
lock_protect(&zones->lock, &zones->ztree, sizeof(zones->ztree));
|
||||||
|
/* also lock protects the rbnode's in struct local_zone */
|
||||||
return zones;
|
return zones;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -73,6 +76,7 @@ local_zones_delete(struct local_zones* zones)
|
||||||
{
|
{
|
||||||
if(!zones)
|
if(!zones)
|
||||||
return;
|
return;
|
||||||
|
lock_quick_destroy(&zones->lock);
|
||||||
/* walk through zones and delete them all */
|
/* walk through zones and delete them all */
|
||||||
traverse_postorder(&zones->ztree, lzdel, NULL);
|
traverse_postorder(&zones->ztree, lzdel, NULL);
|
||||||
free(zones);
|
free(zones);
|
||||||
|
|
@ -83,6 +87,7 @@ local_zone_delete(struct local_zone* z)
|
||||||
{
|
{
|
||||||
if(!z)
|
if(!z)
|
||||||
return;
|
return;
|
||||||
|
lock_rw_destroy(&z->lock);
|
||||||
regional_destroy(z->region);
|
regional_destroy(z->region);
|
||||||
free(z->name);
|
free(z->name);
|
||||||
free(z);
|
free(z);
|
||||||
|
|
@ -137,14 +142,13 @@ parse_dname(const char* str, uint8_t** res, size_t* len, int* labs)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** enter a new zone with allocated dname */
|
/** create a new localzone */
|
||||||
static struct local_zone*
|
static struct local_zone*
|
||||||
lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len,
|
local_zone_create(struct local_zones* zones, uint8_t* nm, size_t len,
|
||||||
int labs, enum localzone_type t, uint16_t dclass)
|
int labs, enum localzone_type t, uint16_t dclass)
|
||||||
{
|
{
|
||||||
struct local_zone* z = (struct local_zone*)calloc(1, sizeof(*z));
|
struct local_zone* z = (struct local_zone*)calloc(1, sizeof(*z));
|
||||||
if(!z) {
|
if(!z) {
|
||||||
log_err("out of memory");
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
z->node.key = z;
|
z->node.key = z;
|
||||||
|
|
@ -153,19 +157,46 @@ lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len,
|
||||||
z->name = nm;
|
z->name = nm;
|
||||||
z->namelen = len;
|
z->namelen = len;
|
||||||
z->namelabs = labs;
|
z->namelabs = labs;
|
||||||
|
lock_rw_init(&z->lock);
|
||||||
z->region = regional_create();
|
z->region = regional_create();
|
||||||
if(!z->region) {
|
if(!z->region) {
|
||||||
log_err("out of memory");
|
|
||||||
free(z);
|
free(z);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
rbtree_init(&z->data, &local_data_cmp);
|
rbtree_init(&z->data, &local_data_cmp);
|
||||||
/* add to rbtree */
|
lock_protect(&z->lock, &z->parent, sizeof(*z)-sizeof(rbnode_t));
|
||||||
if(!rbtree_insert(&zones->ztree, &z->node)) {
|
lock_protect(&zones->lock, &z->node, sizeof(z->node));
|
||||||
log_warn("duplicate local-zone");
|
lock_protect(&zones->lock, &z->parent, sizeof(z->parent));
|
||||||
local_zone_delete(z);
|
lock_protect(&zones->lock, &z->name, sizeof(z->name));
|
||||||
|
lock_protect(&zones->lock, &z->namelen, sizeof(z->namelen));
|
||||||
|
lock_protect(&zones->lock, &z->namelabs, sizeof(z->namelabs));
|
||||||
|
lock_protect(&zones->lock, &z->dclass, sizeof(z->dclass));
|
||||||
|
(void)zones; /* avoid argument unused warning if no lock checks */
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** enter a new zone with allocated dname returns with WRlock */
|
||||||
|
static struct local_zone*
|
||||||
|
lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len,
|
||||||
|
int labs, enum localzone_type t, uint16_t c)
|
||||||
|
{
|
||||||
|
struct local_zone* z = local_zone_create(zones, nm, len, labs, t, c);
|
||||||
|
if(!z) {
|
||||||
|
log_err("out of memory");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* add to rbtree */
|
||||||
|
lock_quick_lock(&zones->lock);
|
||||||
|
lock_rw_wrlock(&z->lock);
|
||||||
|
if(!rbtree_insert(&zones->ztree, &z->node)) {
|
||||||
|
log_warn("duplicate local-zone");
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
|
local_zone_delete(z);
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
return z;
|
return z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -183,17 +214,7 @@ lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
|
||||||
log_err("bad zone name %s %s", name, type);
|
log_err("bad zone name %s %s", name, type);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if(strcmp(type, "deny") == 0)
|
if(!local_zone_str2type(type, &t)) {
|
||||||
t = local_zone_deny;
|
|
||||||
else if(strcmp(type, "refuse") == 0)
|
|
||||||
t = local_zone_refuse;
|
|
||||||
else if(strcmp(type, "static") == 0)
|
|
||||||
t = local_zone_static;
|
|
||||||
else if(strcmp(type, "transparent") == 0)
|
|
||||||
t = local_zone_transparent;
|
|
||||||
else if(strcmp(type, "redirect") == 0)
|
|
||||||
t = local_zone_redirect;
|
|
||||||
else {
|
|
||||||
log_err("bad lz_enter_zone type %s %s", name, type);
|
log_err("bad lz_enter_zone type %s %s", name, type);
|
||||||
free(nm);
|
free(nm);
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -373,18 +394,24 @@ insert_rr(struct regional* region, struct packed_rrset_data* pd,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** find a data node by exact name */
|
||||||
|
static struct local_data*
|
||||||
|
lz_find_node(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs)
|
||||||
|
{
|
||||||
|
struct local_data key;
|
||||||
|
key.node.key = &key;
|
||||||
|
key.name = nm;
|
||||||
|
key.namelen = nmlen;
|
||||||
|
key.namelabs = nmlabs;
|
||||||
|
return (struct local_data*)rbtree_search(&z->data, &key.node);
|
||||||
|
}
|
||||||
|
|
||||||
/** find a node, create it if not and all its empty nonterminal parents */
|
/** find a node, create it if not and all its empty nonterminal parents */
|
||||||
static int
|
static int
|
||||||
lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
|
lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
|
||||||
int nmlabs, struct local_data** res)
|
int nmlabs, struct local_data** res)
|
||||||
{
|
{
|
||||||
struct local_data key;
|
struct local_data* ld = lz_find_node(z, nm, nmlen, nmlabs);
|
||||||
struct local_data* ld;
|
|
||||||
key.node.key = &key;
|
|
||||||
key.name = nm;
|
|
||||||
key.namelen = nmlen;
|
|
||||||
key.namelabs = nmlabs;
|
|
||||||
ld = (struct local_data*)rbtree_search(&z->data, &key.node);
|
|
||||||
if(!ld) {
|
if(!ld) {
|
||||||
/* create a domain name to store rr. */
|
/* create a domain name to store rr. */
|
||||||
ld = (struct local_data*)regional_alloc_zero(z->region,
|
ld = (struct local_data*)regional_alloc_zero(z->region,
|
||||||
|
|
@ -480,16 +507,24 @@ lz_enter_rr_str(struct local_zones* zones, const char* rr, ldns_buffer* buf)
|
||||||
size_t len;
|
size_t len;
|
||||||
int labs;
|
int labs;
|
||||||
struct local_zone* z;
|
struct local_zone* z;
|
||||||
|
int r;
|
||||||
if(!get_rr_nameclass(rr, &rr_name, &rr_class)) {
|
if(!get_rr_nameclass(rr, &rr_name, &rr_class)) {
|
||||||
log_err("bad rr %s", rr);
|
log_err("bad rr %s", rr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
labs = dname_count_size_labels(rr_name, &len);
|
labs = dname_count_size_labels(rr_name, &len);
|
||||||
|
lock_quick_lock(&zones->lock);
|
||||||
z = local_zones_lookup(zones, rr_name, len, labs, rr_class);
|
z = local_zones_lookup(zones, rr_name, len, labs, rr_class);
|
||||||
if(!z)
|
if(!z) {
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
fatal_exit("internal error: no zone for rr %s", rr);
|
fatal_exit("internal error: no zone for rr %s", rr);
|
||||||
|
}
|
||||||
|
lock_rw_wrlock(&z->lock);
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
free(rr_name);
|
free(rr_name);
|
||||||
return lz_enter_rr_into_zone(z, buf, rr);
|
r = lz_enter_rr_into_zone(z, buf, rr);
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** parse local-zone: statements */
|
/** parse local-zone: statements */
|
||||||
|
|
@ -497,9 +532,12 @@ static int
|
||||||
lz_enter_zones(struct local_zones* zones, struct config_file* cfg)
|
lz_enter_zones(struct local_zones* zones, struct config_file* cfg)
|
||||||
{
|
{
|
||||||
struct config_str2list* p;
|
struct config_str2list* p;
|
||||||
|
struct local_zone* z;
|
||||||
for(p = cfg->local_zones; p; p = p->next) {
|
for(p = cfg->local_zones; p; p = p->next) {
|
||||||
if(!lz_enter_zone(zones, p->str, p->str2, LDNS_RR_CLASS_IN))
|
if(!(z=lz_enter_zone(zones, p->str, p->str2,
|
||||||
|
LDNS_RR_CLASS_IN)))
|
||||||
return 0;
|
return 0;
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
@ -515,10 +553,13 @@ lz_exists(struct local_zones* zones, const char* name)
|
||||||
log_err("bad name %s", name);
|
log_err("bad name %s", name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
lock_quick_lock(&zones->lock);
|
||||||
if(rbtree_search(&zones->ztree, &z.node)) {
|
if(rbtree_search(&zones->ztree, &z.node)) {
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
free(z.name);
|
free(z.name);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
free(z.name);
|
free(z.name);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -555,11 +596,16 @@ add_as112_default(struct local_zones* zones, struct config_file* cfg,
|
||||||
return 0;
|
return 0;
|
||||||
snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. "
|
snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. "
|
||||||
"nobody.invalid. 1 3600 1200 604800 10800", name);
|
"nobody.invalid. 1 3600 1200 604800 10800", name);
|
||||||
if(!lz_enter_rr_into_zone(z, buf, str))
|
if(!lz_enter_rr_into_zone(z, buf, str)) {
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name);
|
snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name);
|
||||||
if(!lz_enter_rr_into_zone(z, buf, str))
|
if(!lz_enter_rr_into_zone(z, buf, str)) {
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -585,8 +631,10 @@ lz_enter_defaults(struct local_zones* zones, struct config_file* cfg,
|
||||||
!lz_enter_rr_into_zone(z, buf,
|
!lz_enter_rr_into_zone(z, buf,
|
||||||
"localhost. 10800 IN AAAA ::1")) {
|
"localhost. 10800 IN AAAA ::1")) {
|
||||||
log_err("out of memory adding default zone");
|
log_err("out of memory adding default zone");
|
||||||
|
if(z) { lock_rw_unlock(&z->lock); }
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
}
|
}
|
||||||
/* reverse ip4 zone */
|
/* reverse ip4 zone */
|
||||||
if(!lz_exists(zones, "127.in-addr.arpa.") &&
|
if(!lz_exists(zones, "127.in-addr.arpa.") &&
|
||||||
|
|
@ -601,8 +649,10 @@ lz_enter_defaults(struct local_zones* zones, struct config_file* cfg,
|
||||||
!lz_enter_rr_into_zone(z, buf,
|
!lz_enter_rr_into_zone(z, buf,
|
||||||
"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
|
"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
|
||||||
log_err("out of memory adding default zone");
|
log_err("out of memory adding default zone");
|
||||||
|
if(z) { lock_rw_unlock(&z->lock); }
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
}
|
}
|
||||||
/* reverse ip6 zone */
|
/* reverse ip6 zone */
|
||||||
if(!lz_exists(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.") &&
|
if(!lz_exists(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.") &&
|
||||||
|
|
@ -617,8 +667,10 @@ lz_enter_defaults(struct local_zones* zones, struct config_file* cfg,
|
||||||
!lz_enter_rr_into_zone(z, buf,
|
!lz_enter_rr_into_zone(z, buf,
|
||||||
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN PTR localhost.")) {
|
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN PTR localhost.")) {
|
||||||
log_err("out of memory adding default zone");
|
log_err("out of memory adding default zone");
|
||||||
|
if(z) { lock_rw_unlock(&z->lock); }
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
}
|
}
|
||||||
if ( !add_as112_default(zones, cfg, buf, "10.in-addr.arpa.") ||
|
if ( !add_as112_default(zones, cfg, buf, "10.in-addr.arpa.") ||
|
||||||
!add_as112_default(zones, cfg, buf, "16.172.in-addr.arpa.") ||
|
!add_as112_default(zones, cfg, buf, "16.172.in-addr.arpa.") ||
|
||||||
|
|
@ -661,10 +713,13 @@ init_parents(struct local_zones* zones)
|
||||||
{
|
{
|
||||||
struct local_zone* node, *prev = NULL, *p;
|
struct local_zone* node, *prev = NULL, *p;
|
||||||
int m;
|
int m;
|
||||||
|
lock_quick_lock(&zones->lock);
|
||||||
RBTREE_FOR(node, struct local_zone*, &zones->ztree) {
|
RBTREE_FOR(node, struct local_zone*, &zones->ztree) {
|
||||||
|
lock_rw_wrlock(&node->lock);
|
||||||
node->parent = NULL;
|
node->parent = NULL;
|
||||||
if(!prev || prev->dclass != node->dclass) {
|
if(!prev || prev->dclass != node->dclass) {
|
||||||
prev = node;
|
prev = node;
|
||||||
|
lock_rw_unlock(&node->lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
(void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
|
(void)dname_lab_cmp(prev->name, prev->namelabs, node->name,
|
||||||
|
|
@ -681,7 +736,9 @@ init_parents(struct local_zones* zones)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prev = node;
|
prev = node;
|
||||||
|
lock_rw_unlock(&node->lock);
|
||||||
}
|
}
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** enter implicit transparent zone for local-data: without local-zone: */
|
/** enter implicit transparent zone for local-data: without local-zone: */
|
||||||
|
|
@ -711,6 +768,7 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
labs = dname_count_size_labels(rr_name, &len);
|
labs = dname_count_size_labels(rr_name, &len);
|
||||||
|
lock_quick_lock(&zones->lock);
|
||||||
if(!local_zones_lookup(zones, rr_name, len, labs, rr_class)) {
|
if(!local_zones_lookup(zones, rr_name, len, labs, rr_class)) {
|
||||||
if(!have_name) {
|
if(!have_name) {
|
||||||
dclass = rr_class;
|
dclass = rr_class;
|
||||||
|
|
@ -725,6 +783,7 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
|
||||||
/* process other classes later */
|
/* process other classes later */
|
||||||
free(rr_name);
|
free(rr_name);
|
||||||
have_other_classes = 1;
|
have_other_classes = 1;
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
/* find smallest shared topdomain */
|
/* find smallest shared topdomain */
|
||||||
|
|
@ -735,9 +794,11 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
|
||||||
match = m;
|
match = m;
|
||||||
}
|
}
|
||||||
} else free(rr_name);
|
} else free(rr_name);
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
}
|
}
|
||||||
if(have_name) {
|
if(have_name) {
|
||||||
uint8_t* n2;
|
uint8_t* n2;
|
||||||
|
struct local_zone* z;
|
||||||
/* allocate zone of smallest shared topdomain to contain em */
|
/* allocate zone of smallest shared topdomain to contain em */
|
||||||
n2 = nm;
|
n2 = nm;
|
||||||
dname_remove_labels(&n2, &nmlen, nmlabs - match);
|
dname_remove_labels(&n2, &nmlen, nmlabs - match);
|
||||||
|
|
@ -749,10 +810,11 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
|
||||||
}
|
}
|
||||||
log_nametypeclass(VERB_ALGO, "implicit transparent local-zone",
|
log_nametypeclass(VERB_ALGO, "implicit transparent local-zone",
|
||||||
n2, 0, dclass);
|
n2, 0, dclass);
|
||||||
if(!lz_enter_zone_dname(zones, n2, nmlen, match,
|
if(!(z=lz_enter_zone_dname(zones, n2, nmlen, match,
|
||||||
local_zone_transparent, dclass)) {
|
local_zone_transparent, dclass))) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
}
|
}
|
||||||
if(have_other_classes) {
|
if(have_other_classes) {
|
||||||
/* restart to setup other class */
|
/* restart to setup other class */
|
||||||
|
|
@ -854,6 +916,20 @@ local_zones_lookup(struct local_zones* zones,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct local_zone*
|
||||||
|
local_zones_find(struct local_zones* zones,
|
||||||
|
uint8_t* name, size_t len, int labs, uint16_t dclass)
|
||||||
|
{
|
||||||
|
struct local_zone key;
|
||||||
|
key.node.key = &key;
|
||||||
|
key.dclass = dclass;
|
||||||
|
key.name = name;
|
||||||
|
key.namelen = len;
|
||||||
|
key.namelabs = labs;
|
||||||
|
/* exact */
|
||||||
|
return (struct local_zone*)rbtree_search(&zones->ztree, &key);
|
||||||
|
}
|
||||||
|
|
||||||
/** print all RRsets in local zone */
|
/** print all RRsets in local zone */
|
||||||
static void
|
static void
|
||||||
local_zone_out(struct local_zone* z)
|
local_zone_out(struct local_zone* z)
|
||||||
|
|
@ -872,8 +948,10 @@ local_zone_out(struct local_zone* z)
|
||||||
void local_zones_print(struct local_zones* zones)
|
void local_zones_print(struct local_zones* zones)
|
||||||
{
|
{
|
||||||
struct local_zone* z;
|
struct local_zone* z;
|
||||||
|
lock_quick_lock(&zones->lock);
|
||||||
log_info("number of auth zones %u", (unsigned)zones->ztree.count);
|
log_info("number of auth zones %u", (unsigned)zones->ztree.count);
|
||||||
RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
|
RBTREE_FOR(z, struct local_zone*, &zones->ztree) {
|
||||||
|
lock_rw_rdlock(&z->lock);
|
||||||
switch(z->type) {
|
switch(z->type) {
|
||||||
case local_zone_deny:
|
case local_zone_deny:
|
||||||
log_nametypeclass(0, "deny zone",
|
log_nametypeclass(0, "deny zone",
|
||||||
|
|
@ -901,7 +979,9 @@ void local_zones_print(struct local_zones* zones)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
local_zone_out(z);
|
local_zone_out(z);
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
}
|
}
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** encode answer consisting of 1 rrset */
|
/** encode answer consisting of 1 rrset */
|
||||||
|
|
@ -1032,10 +1112,203 @@ local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
|
||||||
* - look at zone type for negative response. */
|
* - look at zone type for negative response. */
|
||||||
int labs = dname_count_labels(qinfo->qname);
|
int labs = dname_count_labels(qinfo->qname);
|
||||||
struct local_data* ld;
|
struct local_data* ld;
|
||||||
struct local_zone* z = local_zones_lookup(zones, qinfo->qname,
|
struct local_zone* z;
|
||||||
|
int r;
|
||||||
|
lock_quick_lock(&zones->lock);
|
||||||
|
z = local_zones_lookup(zones, qinfo->qname,
|
||||||
qinfo->qname_len, labs, qinfo->qclass);
|
qinfo->qname_len, labs, qinfo->qclass);
|
||||||
if(!z) return 0;
|
if(!z) {
|
||||||
if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld))
|
lock_quick_unlock(&zones->lock);
|
||||||
return 1;
|
return 0;
|
||||||
return lz_zone_answer(z, qinfo, edns, buf, temp, ld);
|
}
|
||||||
|
lock_rw_rdlock(&z->lock);
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
|
|
||||||
|
if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) {
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
r = lz_zone_answer(z, qinfo, edns, buf, temp, ld);
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int local_zone_str2type(const char* type, enum localzone_type* t)
|
||||||
|
{
|
||||||
|
if(strcmp(type, "deny") == 0)
|
||||||
|
*t = local_zone_deny;
|
||||||
|
else if(strcmp(type, "refuse") == 0)
|
||||||
|
*t = local_zone_refuse;
|
||||||
|
else if(strcmp(type, "static") == 0)
|
||||||
|
*t = local_zone_static;
|
||||||
|
else if(strcmp(type, "transparent") == 0)
|
||||||
|
*t = local_zone_transparent;
|
||||||
|
else if(strcmp(type, "redirect") == 0)
|
||||||
|
*t = local_zone_redirect;
|
||||||
|
else return 0;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** iterate over the kiddies of the given name and set their parent ptr */
|
||||||
|
static void
|
||||||
|
set_kiddo_parents(struct local_zone* z, struct local_zone* match,
|
||||||
|
struct local_zone* newp)
|
||||||
|
{
|
||||||
|
/* both zones and z are locked already */
|
||||||
|
/* in the sorted rbtree, the kiddies of z are located after z */
|
||||||
|
/* z must be present in the tree */
|
||||||
|
struct local_zone* p = z;
|
||||||
|
p = (struct local_zone*)rbtree_next(&p->node);
|
||||||
|
while(p!=(struct local_zone*)RBTREE_NULL &&
|
||||||
|
p->dclass == z->dclass && dname_strict_subdomain(p->name,
|
||||||
|
p->namelabs, z->name, z->namelabs)) {
|
||||||
|
/* update parent ptr */
|
||||||
|
/* only when matches with existing parent pointer, so that
|
||||||
|
* deeper child structures are not touched, i.e.
|
||||||
|
* update of x, and a.x, b.x, f.b.x, g.b.x, c.x, y
|
||||||
|
* gets to update a.x, b.x and c.x */
|
||||||
|
lock_rw_wrlock(&p->lock);
|
||||||
|
if(p->parent == match)
|
||||||
|
p->parent = newp;
|
||||||
|
lock_rw_unlock(&p->lock);
|
||||||
|
p = (struct local_zone*)rbtree_next(&p->node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct local_zone* local_zones_add_zone(struct local_zones* zones,
|
||||||
|
uint8_t* name, size_t len, int labs, uint16_t dclass,
|
||||||
|
enum localzone_type tp)
|
||||||
|
{
|
||||||
|
/* create */
|
||||||
|
struct local_zone* z = local_zone_create(zones, name, len, labs, tp,
|
||||||
|
dclass);
|
||||||
|
if(!z) return NULL;
|
||||||
|
lock_rw_wrlock(&z->lock);
|
||||||
|
|
||||||
|
/* find the closest parent */
|
||||||
|
z->parent = local_zones_find(zones, name, len, labs, dclass);
|
||||||
|
|
||||||
|
/* insert into the tree */
|
||||||
|
if(!rbtree_insert(&zones->ztree, &z->node)) {
|
||||||
|
/* duplicate entry! */
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
|
local_zone_delete(z);
|
||||||
|
log_err("internal: duplicate entry in local_zones_add_zone");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set parent pointers right */
|
||||||
|
set_kiddo_parents(z, z->parent, z);
|
||||||
|
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
|
return z;
|
||||||
|
}
|
||||||
|
|
||||||
|
void local_zones_del_zone(struct local_zones* zones, struct local_zone* z)
|
||||||
|
{
|
||||||
|
/* fix up parents in tree */
|
||||||
|
lock_rw_wrlock(&z->lock);
|
||||||
|
set_kiddo_parents(z, z, z->parent);
|
||||||
|
|
||||||
|
/* remove from tree */
|
||||||
|
(void)rbtree_delete(&zones->ztree, z);
|
||||||
|
|
||||||
|
/* delete the zone */
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
|
local_zone_delete(z);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
local_zones_add_RR(struct local_zones* zones, const char* rr, ldns_buffer* buf)
|
||||||
|
{
|
||||||
|
uint8_t* rr_name;
|
||||||
|
uint16_t rr_class;
|
||||||
|
size_t len;
|
||||||
|
int labs;
|
||||||
|
struct local_zone* z;
|
||||||
|
int r;
|
||||||
|
if(!get_rr_nameclass(rr, &rr_name, &rr_class)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
labs = dname_count_size_labels(rr_name, &len);
|
||||||
|
lock_quick_lock(&zones->lock);
|
||||||
|
z = local_zones_lookup(zones, rr_name, len, labs, rr_class);
|
||||||
|
if(!z) {
|
||||||
|
z = local_zones_add_zone(zones, rr_name, len, labs, rr_class,
|
||||||
|
local_zone_transparent);
|
||||||
|
if(!z) {
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lock_rw_wrlock(&z->lock);
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
|
free(rr_name);
|
||||||
|
r = lz_enter_rr_into_zone(z, buf, rr);
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** returns true if the node is terminal so no deeper domain names exist */
|
||||||
|
static int
|
||||||
|
is_terminal(struct local_data* d)
|
||||||
|
{
|
||||||
|
/* for empty nonterminals, the deeper domain names are sorted
|
||||||
|
* right after them, so simply check the next name in the tree
|
||||||
|
*/
|
||||||
|
struct local_data* n = (struct local_data*)rbtree_next(&d->node);
|
||||||
|
if(n == (struct local_data*)RBTREE_NULL)
|
||||||
|
return 1; /* last in tree, no deeper node */
|
||||||
|
if(dname_strict_subdomain(n->name, n->namelabs, d->name, d->namelabs))
|
||||||
|
return 0; /* there is a deeper node */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** delete empty terminals from tree when final data is deleted */
|
||||||
|
static void
|
||||||
|
del_empty_term(struct local_zone* z, struct local_data* d,
|
||||||
|
uint8_t* name, size_t len, int labs)
|
||||||
|
{
|
||||||
|
while(d && d->rrsets == NULL && is_terminal(d)) {
|
||||||
|
/* is this empty nonterminal? delete */
|
||||||
|
/* note, no memory recycling in zone region */
|
||||||
|
(void)rbtree_delete(&z->data, d);
|
||||||
|
|
||||||
|
/* go up and to the next label */
|
||||||
|
if(dname_is_root(name))
|
||||||
|
return;
|
||||||
|
dname_remove_label(&name, &len);
|
||||||
|
labs--;
|
||||||
|
d = lz_find_node(z, name, len, labs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void local_zones_del_data(struct local_zones* zones,
|
||||||
|
uint8_t* name, size_t len, int labs, uint16_t dclass)
|
||||||
|
{
|
||||||
|
/* find zone */
|
||||||
|
struct local_zone* z;
|
||||||
|
struct local_data* d;
|
||||||
|
lock_quick_lock(&zones->lock);
|
||||||
|
z = local_zones_lookup(zones, name, len, labs, dclass);
|
||||||
|
if(!z) {
|
||||||
|
/* no such zone, we're done */
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lock_rw_wrlock(&z->lock);
|
||||||
|
lock_quick_unlock(&zones->lock);
|
||||||
|
|
||||||
|
/* find the domain */
|
||||||
|
d = lz_find_node(z, name, len, labs);
|
||||||
|
/* no memory recycling for zone deletions ... */
|
||||||
|
d->rrsets = NULL;
|
||||||
|
/* did we delete the soa record ? */
|
||||||
|
if(query_dname_compare(d->name, z->name) == 0)
|
||||||
|
z->soa = NULL;
|
||||||
|
|
||||||
|
/* cleanup the empty nonterminals for this name */
|
||||||
|
del_empty_term(z, d, name, len, labs);
|
||||||
|
|
||||||
|
lock_rw_unlock(&z->lock);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@
|
||||||
#ifndef SERVICES_LOCALZONE_H
|
#ifndef SERVICES_LOCALZONE_H
|
||||||
#define SERVICES_LOCALZONE_H
|
#define SERVICES_LOCALZONE_H
|
||||||
#include "util/rbtree.h"
|
#include "util/rbtree.h"
|
||||||
|
#include "util/locks.h"
|
||||||
struct ub_packed_rrset_key;
|
struct ub_packed_rrset_key;
|
||||||
struct regional;
|
struct regional;
|
||||||
struct config_file;
|
struct config_file;
|
||||||
|
|
@ -74,6 +75,8 @@ enum localzone_type {
|
||||||
* This tree is fixed at startup, so, readonly, no locks or mutexes necessary.
|
* This tree is fixed at startup, so, readonly, no locks or mutexes necessary.
|
||||||
*/
|
*/
|
||||||
struct local_zones {
|
struct local_zones {
|
||||||
|
/** lock on the localzone tree */
|
||||||
|
lock_quick_t lock;
|
||||||
/** rbtree of struct local_zone */
|
/** rbtree of struct local_zone */
|
||||||
rbtree_t ztree;
|
rbtree_t ztree;
|
||||||
};
|
};
|
||||||
|
|
@ -97,6 +100,12 @@ struct local_zone {
|
||||||
* uses 'dclass' to not conflict with c++ keyword class. */
|
* uses 'dclass' to not conflict with c++ keyword class. */
|
||||||
uint16_t dclass;
|
uint16_t dclass;
|
||||||
|
|
||||||
|
/** lock on the data in the structure
|
||||||
|
* For the node, parent, name, namelen, namelabs, dclass, you
|
||||||
|
* need to also hold the zones_tree lock to change them (or to
|
||||||
|
* delete this zone) */
|
||||||
|
lock_rw_t lock;
|
||||||
|
|
||||||
/** how to process zone */
|
/** how to process zone */
|
||||||
enum localzone_type type;
|
enum localzone_type type;
|
||||||
|
|
||||||
|
|
@ -151,6 +160,7 @@ void local_zones_delete(struct local_zones* zones);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply config settings; setup the local authoritative data.
|
* Apply config settings; setup the local authoritative data.
|
||||||
|
* Takes care of locking.
|
||||||
* @param zones: is set up.
|
* @param zones: is set up.
|
||||||
* @param cfg: config data.
|
* @param cfg: config data.
|
||||||
* @return false on error.
|
* @return false on error.
|
||||||
|
|
@ -182,6 +192,7 @@ void local_zone_delete(struct local_zone* z);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lookup zone that contains the given name, class.
|
* Lookup zone that contains the given name, class.
|
||||||
|
* User must lock the tree or result zone.
|
||||||
* @param zones: the zones tree
|
* @param zones: the zones tree
|
||||||
* @param name: dname to lookup
|
* @param name: dname to lookup
|
||||||
* @param len: length of name.
|
* @param len: length of name.
|
||||||
|
|
@ -194,12 +205,14 @@ struct local_zone* local_zones_lookup(struct local_zones* zones,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Debug helper. Print all zones
|
* Debug helper. Print all zones
|
||||||
|
* Takes care of locking.
|
||||||
* @param zones: the zones tree
|
* @param zones: the zones tree
|
||||||
*/
|
*/
|
||||||
void local_zones_print(struct local_zones* zones);
|
void local_zones_print(struct local_zones* zones);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Answer authoritatively for local zones.
|
* Answer authoritatively for local zones.
|
||||||
|
* Takes care of locking.
|
||||||
* @param zones: the stored zones (shared, read only).
|
* @param zones: the stored zones (shared, read only).
|
||||||
* @param qinfo: query info (parsed).
|
* @param qinfo: query info (parsed).
|
||||||
* @param edns: edns info (parsed).
|
* @param edns: edns info (parsed).
|
||||||
|
|
@ -212,4 +225,74 @@ void local_zones_print(struct local_zones* zones);
|
||||||
int local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
|
int local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
|
||||||
struct edns_data* edns, ldns_buffer* buf, struct regional* temp);
|
struct edns_data* edns, ldns_buffer* buf, struct regional* temp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the string into localzone type.
|
||||||
|
*
|
||||||
|
* @param str: string to parse
|
||||||
|
* @param t: local zone type returned here.
|
||||||
|
* @return 0 on parse error.
|
||||||
|
*/
|
||||||
|
int local_zone_str2type(const char* str, enum localzone_type* t);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find zone that with exactly given name, class.
|
||||||
|
* User must lock the tree or result zone.
|
||||||
|
* @param zones: the zones tree
|
||||||
|
* @param name: dname to lookup
|
||||||
|
* @param len: length of name.
|
||||||
|
* @param labs: labelcount of name.
|
||||||
|
* @param dclass: class to lookup.
|
||||||
|
* @return the exact local_zone or NULL.
|
||||||
|
*/
|
||||||
|
struct local_zone* local_zones_find(struct local_zones* zones,
|
||||||
|
uint8_t* name, size_t len, int labs, uint16_t dclass);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a new zone. Caller must hold the zones lock.
|
||||||
|
* Adjusts the other zones as well (parent pointers) after insertion.
|
||||||
|
* The zone must NOT exist (returns NULL and logs error).
|
||||||
|
* @param zones: the zones tree
|
||||||
|
* @param name: dname to add
|
||||||
|
* @param len: length of name.
|
||||||
|
* @param labs: labelcount of name.
|
||||||
|
* @param dclass: class to add.
|
||||||
|
* @param tp: type.
|
||||||
|
* @return local_zone or NULL on error, caller must printout memory error.
|
||||||
|
*/
|
||||||
|
struct local_zone* local_zones_add_zone(struct local_zones* zones,
|
||||||
|
uint8_t* name, size_t len, int labs, uint16_t dclass,
|
||||||
|
enum localzone_type tp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete a zone. Caller must hold the zones lock.
|
||||||
|
* Adjusts the other zones as well (parent pointers) after insertion.
|
||||||
|
* @param zones: the zones tree
|
||||||
|
* @param zone: the zone to delete from tree. Also deletes zone from memory.
|
||||||
|
*/
|
||||||
|
void local_zones_del_zone(struct local_zones* zones, struct local_zone* zone);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add RR data into the localzone data.
|
||||||
|
* Looks up the zone, if no covering zone, a transparent zone with the
|
||||||
|
* name of the RR is created.
|
||||||
|
* @param zones: the zones tree. Not locked by caller.
|
||||||
|
* @param rr: string with on RR.
|
||||||
|
* @param buf: buffer for scratch.
|
||||||
|
* @return false on failure.
|
||||||
|
*/
|
||||||
|
int local_zones_add_RR(struct local_zones* zones, const char* rr,
|
||||||
|
ldns_buffer* buf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove data from domain name in the tree.
|
||||||
|
* All types are removed. No effect if zone or name does not exist.
|
||||||
|
* @param zones: zones tree.
|
||||||
|
* @param name: dname to remove
|
||||||
|
* @param len: length of name.
|
||||||
|
* @param labs: labelcount of name.
|
||||||
|
* @param dclass: class to remove.
|
||||||
|
*/
|
||||||
|
void local_zones_del_data(struct local_zones* zones,
|
||||||
|
uint8_t* name, size_t len, int labs, uint16_t dclass);
|
||||||
|
|
||||||
#endif /* SERVICES_LOCALZONE_H */
|
#endif /* SERVICES_LOCALZONE_H */
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,11 @@ usage()
|
||||||
printf(" reload reloads the server\n");
|
printf(" reload reloads the server\n");
|
||||||
printf(" stats print statistics\n");
|
printf(" stats print statistics\n");
|
||||||
printf(" verbosity [number] change logging detail\n");
|
printf(" verbosity [number] change logging detail\n");
|
||||||
|
printf(" local_zone [name] [type] add new local zone\n");
|
||||||
|
printf(" local_zone_remove [name] remove local zone and its contents\n");
|
||||||
|
printf(" local_data [RR data...] add local data, for example\n");
|
||||||
|
printf(" local_data www.example.com A 192.0.2.1\n");
|
||||||
|
printf(" local_data_remove [name] remove local RR data from name\n");
|
||||||
printf("Version %s\n", PACKAGE_VERSION);
|
printf("Version %s\n", PACKAGE_VERSION);
|
||||||
printf("BSD licensed, see LICENSE in source package for details.\n");
|
printf("BSD licensed, see LICENSE in source package for details.\n");
|
||||||
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
|
printf("Report bugs to %s\n", PACKAGE_BUGREPORT);
|
||||||
|
|
|
||||||
|
|
@ -487,8 +487,11 @@ read_entry(FILE* in, const char* name, int *lineno, uint32_t* default_ttl,
|
||||||
/* it must be a RR, parse and add to packet. */
|
/* it must be a RR, parse and add to packet. */
|
||||||
ldns_rr* n = NULL;
|
ldns_rr* n = NULL;
|
||||||
ldns_status status;
|
ldns_status status;
|
||||||
status = ldns_rr_new_frm_str(&n, parse, *default_ttl,
|
if(add_section == LDNS_SECTION_QUESTION)
|
||||||
*origin, prev_rr);
|
status = ldns_rr_new_question_frm_str(
|
||||||
|
&n, parse, *origin, prev_rr);
|
||||||
|
else status = ldns_rr_new_frm_str(&n, parse,
|
||||||
|
*default_ttl, *origin, prev_rr);
|
||||||
if(status != LDNS_STATUS_OK)
|
if(status != LDNS_STATUS_OK)
|
||||||
error("%s line %d:\n\t%s: %s", name, *lineno,
|
error("%s line %d:\n\t%s: %s", name, *lineno,
|
||||||
ldns_get_errorstr_by_id(status), parse);
|
ldns_get_errorstr_by_id(status), parse);
|
||||||
|
|
@ -637,7 +640,7 @@ match_all(ldns_pkt* q, ldns_pkt* p, bool mttl)
|
||||||
{ verbose(3, "allmatch: nscount different"); return 0;}
|
{ verbose(3, "allmatch: nscount different"); return 0;}
|
||||||
if(ldns_pkt_arcount(q) != ldns_pkt_arcount(p))
|
if(ldns_pkt_arcount(q) != ldns_pkt_arcount(p))
|
||||||
{ verbose(3, "allmatch: arcount different"); return 0;}
|
{ verbose(3, "allmatch: arcount different"); return 0;}
|
||||||
if(!match_list(ldns_pkt_question(q), ldns_pkt_question(p), mttl))
|
if(!match_list(ldns_pkt_question(q), ldns_pkt_question(p), 0))
|
||||||
{ verbose(3, "allmatch: qd section different"); return 0;}
|
{ verbose(3, "allmatch: qd section different"); return 0;}
|
||||||
if(!match_list(ldns_pkt_answer(q), ldns_pkt_answer(p), mttl))
|
if(!match_list(ldns_pkt_answer(q), ldns_pkt_answer(p), mttl))
|
||||||
{ verbose(3, "allmatch: an section different"); return 0;}
|
{ verbose(3, "allmatch: an section different"); return 0;}
|
||||||
|
|
|
||||||
|
|
@ -156,7 +156,7 @@ val_init(struct module_env* env, int id)
|
||||||
val_env->permissive_mode = 0;
|
val_env->permissive_mode = 0;
|
||||||
lock_basic_init(&val_env->bogus_lock);
|
lock_basic_init(&val_env->bogus_lock);
|
||||||
lock_protect(&val_env->bogus_lock, &val_env->num_rrset_bogus,
|
lock_protect(&val_env->bogus_lock, &val_env->num_rrset_bogus,
|
||||||
sizeof(val->env->num_rrset_bogus));
|
sizeof(val_env->num_rrset_bogus));
|
||||||
if(!val_apply_cfg(env, val_env, env->cfg)) {
|
if(!val_apply_cfg(env, val_env, env->cfg)) {
|
||||||
log_err("validator: could not apply configuration settings.");
|
log_err("validator: could not apply configuration settings.");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue