From 17023457a96a6ae7c6b475eb506a6c10c1905813 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Thu, 7 Jul 2016 10:20:05 +0000 Subject: [PATCH] - access-control-tag-data implemented. verbose(4) prints tag debug. git-svn-id: file:///svn/unbound/trunk@3811 be551aaa-1e26-0410-a405-d3ace91eadb9 --- daemon/worker.c | 4 +- doc/Changelog | 3 + doc/example.conf.in | 3 + libunbound/libworker.c | 9 +- services/localzone.c | 141 ++++++++++++++++++++++++-- services/localzone.h | 9 +- testdata/local_acl_taglist.rpl | 38 +++++++ testdata/local_acl_taglist_action.rpl | 2 +- 8 files changed, 192 insertions(+), 17 deletions(-) diff --git a/daemon/worker.c b/daemon/worker.c index 89c074f51..860ba8f0a 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -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); diff --git a/doc/Changelog b/doc/Changelog index 2c140b723..aaf454073 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/doc/example.conf.in b/doc/example.conf.in index d7caf3827..3facc721c 100644 --- a/doc/example.conf.in +++ b/doc/example.conf.in @@ -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 diff --git a/libunbound/libworker.c b/libunbound/libworker.c index 7321072af..6f5354144 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -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); diff --git a/services/localzone.c b/services/localzone.c index bc8ad0926..80bb566c9 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -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)tagname, z->namelen)) { + verbose(VERB_ALGO, "redirect with tag data [%d] %s", + tag, (tagdata, &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; i0; j++) { - if((tagmatch & 0x1) && i*8+j < tagactionssize - && tagactions[i*8+j] != 0) - return (enum localzone_type)tagactions[i*8+j]; + if((tagmatch & 0x1)) { + *tag = i*8+j; + verbose(VERB_ALGO, "matched tag [%d] %s", + *tag, (*tag>= 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; } diff --git a/services/localzone.h b/services/localzone.h index ead231d62..69fdbee2d 100644 --- a/services/localzone.h +++ b/services/localzone.h @@ -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. diff --git a/testdata/local_acl_taglist.rpl b/testdata/local_acl_taglist.rpl index 26dd9d9fe..834abe81e 100644 --- a/testdata/local_acl_taglist.rpl +++ b/testdata/local_acl_taglist.rpl @@ -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,15 +10,22 @@ 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 @@ -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 diff --git a/testdata/local_acl_taglist_action.rpl b/testdata/local_acl_taglist_action.rpl index 77b3ac31b..9977e0213 100644 --- a/testdata/local_acl_taglist_action.rpl +++ b/testdata/local_acl_taglist_action.rpl @@ -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"