mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 06:37:08 +00:00
- 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:
parent
eaa6e239f7
commit
17023457a9
@ -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);
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
38
testdata/local_acl_taglist.rpl
vendored
38
testdata/local_acl_taglist.rpl
vendored
@ -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
|
||||
|
2
testdata/local_acl_taglist_action.rpl
vendored
2
testdata/local_acl_taglist_action.rpl
vendored
@ -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"
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user