- access-control-tag-data implemented. verbose(4) prints tag debug.

git-svn-id: file:///svn/unbound/trunk@3811 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2016-07-07 10:20:05 +00:00
parent eaa6e239f7
commit 17023457a9
8 changed files with 192 additions and 17 deletions

View File

@ -945,7 +945,9 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
if(local_zones_answer(worker->daemon->local_zones, &qinfo, &edns,
c->buffer, worker->scratchpad, repinfo,
acladdr->taglist, acladdr->taglen, acladdr->tag_actions,
acladdr->tag_actions_size)) {
acladdr->tag_actions_size, acladdr->tag_datas,
acladdr->tag_datas_size, worker->daemon->cfg->tagname,
worker->daemon->cfg->num_tags)) {
regional_free_all(worker->scratchpad);
if(sldns_buffer_limit(c->buffer) == 0) {
comm_point_drop_reply(repinfo);

View File

@ -1,3 +1,6 @@
7 July 2016: Wouter
- access-control-tag-data implemented. verbose(4) prints tag debug.
5 July 2016: Wouter
- Fix dynamic link of anchor-update.exe on windows.
- Fix detect of mingw for MXE package build.

View File

@ -222,6 +222,9 @@ server:
# access-control-tag: 192.0.2.0/24 "tag2 tag3"
# set action for particular tag for given access control element
# if you have multiple tag values, the tag used to lookup the action
# is the first tag match between access-control-tag and local-zone-tag
# where "first" comes from the order of the define-tag values.
# access-control-tag-action: 192.0.2.0/24 tag3 refuse
# set redirect data for particular tag for access control element

View File

@ -608,7 +608,8 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0)) {
w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
NULL, 0, NULL, 0)) {
regional_free_all(w->env->scratch);
libworker_fillup_fg(q, LDNS_RCODE_NOERROR,
w->back->udp_buff, sec_status_insecure, NULL);
@ -678,7 +679,8 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
if(local_zones_answer(ctx->local_zones, &qinfo, &edns,
w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0)) {
w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
NULL, 0, NULL, 0)) {
regional_free_all(w->env->scratch);
free(qinfo.qname);
libworker_event_done_cb(q, LDNS_RCODE_NOERROR,
@ -798,7 +800,8 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
sldns_buffer_write_u16_at(w->back->udp_buff, 0, qid);
sldns_buffer_write_u16_at(w->back->udp_buff, 2, qflags);
if(local_zones_answer(w->ctx->local_zones, &qinfo, &edns,
w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0)) {
w->back->udp_buff, w->env->scratch, NULL, NULL, 0, NULL, 0,
NULL, 0, NULL, 0)) {
regional_free_all(w->env->scratch);
q->msg_security = sec_status_insecure;
add_bg_result(w, q, w->back->udp_buff, UB_NOERROR, NULL);

View File

@ -1177,11 +1177,98 @@ local_encode(struct query_info* qinfo, struct edns_data* edns,
return 1;
}
/** find local data tag string match for the given type in the list */
static int
find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
struct ub_packed_rrset_key* r, struct regional* temp,
uint8_t* zname, size_t zlen)
{
struct config_strlist* p;
char buf[65536];
uint8_t rr[LDNS_RR_BUF_SIZE];
size_t len = sizeof(rr);
int res;
struct packed_rrset_data* d;
for(p=list; p; p=p->next) {
/* does this element match the type? */
snprintf(buf, sizeof(buf), ". %s", p->str);
res = sldns_str2wire_rr_buf(buf, rr, &len, NULL, 3600,
zname, zlen, NULL, 0);
if(res != 0)
/* parse errors are already checked before, in
* acllist check_data, skip this for robustness */
continue;
if(len < 1 /* . */ + 8 /* typeclassttl*/ + 2 /*rdatalen*/)
continue;
if(sldns_wirerr_get_type(rr, len, 1) != qinfo->qtype)
continue;
/* do we have entries already? if not setup key */
if(r->rk.dname == NULL) {
r->entry.key = r;
r->rk.dname = qinfo->qname;
r->rk.dname_len = qinfo->qname_len;
r->rk.type = htons(qinfo->qtype);
r->rk.rrset_class = htons(qinfo->qclass);
r->rk.flags = 0;
d = (struct packed_rrset_data*)regional_alloc_zero(
temp, sizeof(struct packed_rrset_data)
+ sizeof(size_t) + sizeof(uint8_t*) +
sizeof(time_t));
if(!d) return 0; /* out of memory */
r->entry.data = d;
d->ttl = sldns_wirerr_get_ttl(rr, len, 1);
d->rr_len = (size_t*)((uint8_t*)d +
sizeof(struct packed_rrset_data));
d->rr_data = (uint8_t**)&(d->rr_len[1]);
d->rr_ttl = (time_t*)&(d->rr_data[1]);
}
d = (struct packed_rrset_data*)r->entry.data;
/* add entry to the data */
if(d->count != 0) {
size_t* oldlen = d->rr_len;
uint8_t** olddata = d->rr_data;
time_t* oldttl = d->rr_ttl;
/* increase arrays for lookup */
/* this is of course slow for very many records,
* but most redirects are expected with few records */
d->rr_len = (size_t*)regional_alloc_zero(temp,
(d->count+1)*sizeof(size_t));
d->rr_data = (uint8_t**)regional_alloc_zero(temp,
(d->count+1)*sizeof(uint8_t*));
d->rr_ttl = (time_t*)regional_alloc_zero(temp,
(d->count+1)*sizeof(time_t));
if(!d->rr_len || !d->rr_data || !d->rr_ttl)
return 0; /* out of memory */
/* first one was allocated after struct d, but new
* ones get their own array increment alloc, so
* copy old content */
memmove(d->rr_len, oldlen, d->count*sizeof(size_t));
memmove(d->rr_data, olddata, d->count*sizeof(uint8_t*));
memmove(d->rr_ttl, oldttl, d->count*sizeof(time_t));
}
d->rr_len[d->count] = sldns_wirerr_get_rdatalen(rr, len, 1)+2;
d->rr_ttl[d->count] = sldns_wirerr_get_ttl(rr, len, 1);
d->rr_data[d->count] = regional_alloc_init(temp,
sldns_wirerr_get_rdatawl(rr, len, 1),
d->rr_len[d->count]);
if(!d->rr_data[d->count])
if(!d) return 0; /* out of memory */
d->count++;
}
if(r->rk.dname)
return 1;
return 0;
}
/** answer local data match */
static int
local_data_answer(struct local_zone* z, struct query_info* qinfo,
struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
int labs, struct local_data** ldp, enum localzone_type lz_type)
int labs, struct local_data** ldp, enum localzone_type lz_type,
int tag, struct config_strlist** tag_datas, size_t tag_datas_size,
char** tagname, int num_tags)
{
struct local_data key;
struct local_data* ld;
@ -1194,6 +1281,17 @@ local_data_answer(struct local_zone* z, struct query_info* qinfo,
key.name = z->name;
key.namelen = z->namelen;
key.namelabs = z->namelabs;
if(tag != -1 && (size_t)tag<tag_datas_size && tag_datas[tag]) {
struct ub_packed_rrset_key r;
memset(&r, 0, sizeof(r));
if(find_tag_datas(qinfo, tag_datas[tag], &r, temp,
z->name, z->namelen)) {
verbose(VERB_ALGO, "redirect with tag data [%d] %s",
tag, (tag<num_tags?tagname[tag]:"null"));
return local_encode(qinfo, edns, buf, temp,
&r, 1, LDNS_RCODE_NOERROR);
}
}
}
ld = (struct local_data*)rbtree_search(&z->data, &key.node);
*ldp = ld;
@ -1302,7 +1400,8 @@ lz_inform_print(struct local_zone* z, struct query_info* qinfo,
enum localzone_type
lz_type(uint8_t *taglist, size_t taglen, uint8_t *taglist2, size_t taglen2,
uint8_t *tagactions, size_t tagactionssize, enum localzone_type lzt,
struct comm_reply* repinfo, struct rbtree_t* override_tree)
struct comm_reply* repinfo, struct rbtree_t* override_tree, int* tag,
char** tagname, int num_tags)
{
size_t i, j;
uint8_t tagmatch;
@ -1310,17 +1409,33 @@ lz_type(uint8_t *taglist, size_t taglen, uint8_t *taglist2, size_t taglen2,
if(repinfo && override_tree) {
lzo = (struct local_zone_override*)addr_tree_lookup(
override_tree, &repinfo->addr, repinfo->addrlen);
if(lzo && lzo->type)
if(lzo && lzo->type) {
verbose(VERB_ALGO, "local zone override to type %s",
local_zone_type2str(lzo->type));
return lzo->type;
}
if(!taglist || !taglist2 || !tagactions)
}
if(!taglist || !taglist2)
return lzt;
for(i=0; i<taglen && i<taglen2; i++) {
tagmatch = (taglist[i] & taglist2[i]);
for(j=0; j<8 && tagmatch>0; j++) {
if((tagmatch & 0x1) && i*8+j < tagactionssize
&& tagactions[i*8+j] != 0)
if((tagmatch & 0x1)) {
*tag = i*8+j;
verbose(VERB_ALGO, "matched tag [%d] %s",
*tag, (*tag<num_tags?tagname[*tag]:"null"));
/* does this tag have a tag action? */
if(i*8+j < tagactionssize && tagactions
&& tagactions[i*8+j] != 0) {
verbose(VERB_ALGO, "tag action [%d] %s to type %s",
*tag, (*tag<num_tags?tagname[*tag]:"null"),
local_zone_type2str(
(enum localzone_type)
tagactions[i*8+j]));
return (enum localzone_type)tagactions[i*8+j];
}
return lzt;
}
tagmatch >>= 1;
}
}
@ -1331,7 +1446,9 @@ int
local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
struct edns_data* edns, sldns_buffer* buf, struct regional* temp,
struct comm_reply* repinfo, uint8_t* taglist, size_t taglen,
uint8_t* tagactions, size_t tagactionssize)
uint8_t* tagactions, size_t tagactionssize,
struct config_strlist** tag_datas, size_t tag_datas_size,
char** tagname, int num_tags)
{
/* see if query is covered by a zone,
* if so: - try to match (exact) local data
@ -1340,7 +1457,7 @@ local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
struct local_data* ld = NULL;
struct local_zone* z;
enum localzone_type lzt;
int r;
int r, tag = -1;
lock_rw_rdlock(&zones->lock);
z = local_zones_tags_lookup(zones, qinfo->qname,
qinfo->qname_len, labs, qinfo->qclass, taglist, taglen, 0);
@ -1352,7 +1469,8 @@ local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
lock_rw_unlock(&zones->lock);
lzt = lz_type(taglist, taglen, z->taglist, z->taglen, tagactions,
tagactionssize, z->type, repinfo, z->override_tree);
tagactionssize, z->type, repinfo, z->override_tree, &tag,
tagname, num_tags);
if((lzt == local_zone_inform || lzt == local_zone_inform_deny)
&& repinfo)
@ -1360,7 +1478,8 @@ local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
if(lzt != local_zone_always_refuse && lzt != local_zone_always_transparent
&& lzt != local_zone_always_nxdomain
&& local_data_answer(z, qinfo, edns, buf, temp, labs, &ld, lzt)) {
&& local_data_answer(z, qinfo, edns, buf, temp, labs, &ld, lzt,
tag, tag_datas, tag_datas_size, tagname, num_tags)) {
lock_rw_unlock(&z->lock);
return 1;
}

View File

@ -51,6 +51,7 @@ struct edns_data;
struct query_info;
struct sldns_buffer;
struct comm_reply;
struct config_strlist;
/**
* Local zone type
@ -272,6 +273,10 @@ void local_zones_print(struct local_zones* zones);
* @param taglen: length of the taglist.
* @param tagactions: local zone actions for tags. May be NULL.
* @param tagactionssize: length of the tagactions.
* @param tag_datas: array per tag of strlist with rdata strings. or NULL.
* @param tag_datas_size: size of tag_datas array.
* @param tagname: array of tag name strings (for debug output).
* @param num_tags: number of items in tagname array.
* @return true if answer is in buffer. false if query is not answered
* by authority data. If the reply should be dropped altogether, the return
* value is true, but the buffer is cleared (empty).
@ -279,7 +284,9 @@ void local_zones_print(struct local_zones* zones);
int local_zones_answer(struct local_zones* zones, struct query_info* qinfo,
struct edns_data* edns, struct sldns_buffer* buf, struct regional* temp,
struct comm_reply* repinfo, uint8_t* taglist, size_t taglen,
uint8_t* tagactions, size_t tagactionssize);
uint8_t* tagactions, size_t tagactionssize,
struct config_strlist** tag_datas, size_t tag_datas_size,
char** tagname, int num_tags);
/**
* Parse the string into localzone type.

View File

@ -1,6 +1,7 @@
; config options
server:
define-tag: "tag1 tag2 tag3"
define-tag: "tag4"
local-zone: "example." redirect
local-data: 'example. IN TXT "data 0"'
local-zone: "d.example." static
@ -9,16 +10,23 @@ server:
local-data: 'c.d.example. IN TXT "data 2"'
local-zone: "b.c.d.example." redirect
local-data: 'b.c.d.example. IN TXT "data 3"'
local-zone: "foo." redirect
local-data: 'foo. IN TXT "data plain 4"'
; no tags for local-zones example. and c.d.example.
local-zone-tag: "d.example." "tag1 tag2"
local-zone-tag: "b.c.d.example." "tag3"
local-zone-tag: "foo." "tag4"
access-control: 10.10.10.0/24 allow
access-control-tag: 10.10.10.20/32 "tag1"
access-control-tag: 10.10.10.30/32 "tag2 tag3"
access-control-tag: 10.10.10.40/32 "tag3"
access-control-tag: 10.10.10.50/32 "tag4"
access-control-tag-data: 10.10.10.50/32 "tag4" 'TXT "data tag4"'
access-control-tag: 10.10.10.60/32 "tag4"
CONFIG_END
SCENARIO_BEGIN Test local data queries
@ -128,4 +136,34 @@ SECTION ANSWER
a.b.c.d.example. IN TXT "data 3"
ENTRY_END
STEP 15 QUERY ADDRESS 10.10.10.50
ENTRY_BEGIN
SECTION QUESTION
www.foo. IN TXT
ENTRY_END
STEP 16 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RA AA
SECTION QUESTION
www.foo. IN TXT
SECTION ANSWER
www.foo. IN TXT "data tag4"
ENTRY_END
STEP 17 QUERY ADDRESS 10.10.10.60
ENTRY_BEGIN
SECTION QUESTION
www.foo. IN TXT
ENTRY_END
STEP 18 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RA AA
SECTION QUESTION
www.foo. IN TXT
SECTION ANSWER
www.foo. IN TXT "data plain 4"
ENTRY_END
SCENARIO_END

View File

@ -9,7 +9,7 @@ server:
access-control: 10.10.10.0/24 allow
access-control-tag: 10.10.10.10/32 "tag1"
access-control-tag: 10.10.10.20/32 "tag2 tag3"
access-control-tag: 10.10.10.30/32 "tag2 tag3"
access-control-tag: 10.10.10.30/32 "tag3"
access-control-tag: 10.10.10.40/32 "tag3"
access-control-tag: 10.10.10.50/32 "tag3"