]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- access-control-tag-data implemented. verbose(4) prints tag debug.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 7 Jul 2016 10:20:05 +0000 (10:20 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 7 Jul 2016 10:20:05 +0000 (10:20 +0000)
git-svn-id: file:///svn/unbound/trunk@3811 be551aaa-1e26-0410-a405-d3ace91eadb9

daemon/worker.c
doc/Changelog
doc/example.conf.in
libunbound/libworker.c
services/localzone.c
services/localzone.h
testdata/local_acl_taglist.rpl
testdata/local_acl_taglist_action.rpl

index 89c074f51f65e2c6630e85fb641760ff4731e97d..860ba8f0af0c9693db4c9a5ff8ac78589f6fbaaf 100644 (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);
index 2c140b7235c337ea6cc5531ee5337d5f4e812c85..aaf454073b9e5547700ae852f5b6a00bc05a066f 100644 (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.
index d7caf3827f899fbbbb94f4a7cc3ab50aefc7aa35..3facc721c47c88300e7f22f215d9534014180bbf 100644 (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
index 7321072af1e7616fd51fc9f3d3d04c7726751967..6f535414407d8fed30ae9fc62f6d396dfba35ead 100644 (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);
index bc8ad0926a37c62c1f10b49fe2fdef7d21e15e34..80bb566c99df8f5f35711c4d189a566f8975478d 100644 (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)
-                               return (enum localzone_type)tagactions[i*8+j];
+                       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;
        }
index ead231d62d534e494dc8869cec09fab709bbcb72..69fdbee2d7a3bcd6e54f76a9fb1dcb3d41ba1326 100644 (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.
index 26dd9d9feb92bc659a019e89f8d8fb7060bbe662..834abe81e4f3dc797b5daf937a704e47d8d4427b 100644 (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,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
index 77b3ac31b21027615c6c5a787b954ab6e39d785c..9977e0213571c94705d1cab4234a49aaf90b7275 100644 (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"