]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Added RPZ response IP support
authorRalph Dolmans <ralph@nlnetlabs.nl>
Tue, 16 Jul 2019 16:43:16 +0000 (18:43 +0200)
committerRalph Dolmans <ralph@nlnetlabs.nl>
Tue, 16 Jul 2019 16:43:16 +0000 (18:43 +0200)
17 files changed:
daemon/daemon.c
daemon/daemon.h
daemon/worker.c
libunbound/context.c
respip/respip.c
respip/respip.h
services/authzone.c
services/authzone.h
services/localzone.h
services/rpz.c
services/rpz.h
smallapp/unbound-checkconf.c
util/config_file.c
util/config_file.h
util/net_help.c
util/storage/dnstree.c
util/storage/dnstree.h

index 7461a26e210422ceb0a158d9db028b91888dc1e6..de67b073d25c539e055ff9e4c7dd00f375331893 100644 (file)
@@ -616,7 +616,8 @@ daemon_fork(struct daemon* daemon)
                have_view_respip_cfg;
        
        /* read auth zonefiles */
-       if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1))
+       if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1,
+               &daemon->use_rpz))
                fatal_exit("auth_zones could not be setup");
 
        /* setup modules */
@@ -628,6 +629,12 @@ daemon_fork(struct daemon* daemon)
        if(daemon->use_response_ip &&
                modstack_find(&daemon->mods, "respip") < 0)
                fatal_exit("response-ip options require respip module");
+       /* RPZ response ip triggers don't work as expected without the respip
+        * module.  To avoid run-time operational surprise we reject such
+        * configuration. */
+       if(daemon->use_rpz &&
+               modstack_find(&daemon->mods, "respip") < 0)
+               fatal_exit("RPZ requires the respip module");
 
        /* first create all the worker structures, so we can pass
         * them to the newly created threads. 
index 5749dbef8fbf45be926723c1c7f62a9138fa4f9d..3effbafb79183a2da8312a082d50dec0b5e2d008 100644 (file)
@@ -132,6 +132,8 @@ struct daemon {
        struct respip_set* respip_set;
        /** some response-ip tags or actions are configured if true */
        int use_response_ip;
+       /** some RPZ policies are configured */
+       int use_rpz;
 #ifdef USE_DNSCRYPT
        /** the dnscrypt environment */
        struct dnsc_env* dnscenv;
index 8440dd22c917d39f413774e78d8ebf330e63062a..547a7610bb17a0603b78f958244af74de1c91a19 100644 (file)
@@ -572,7 +572,7 @@ static int
 apply_respip_action(struct worker* worker, const struct query_info* qinfo,
        struct respip_client_info* cinfo, struct reply_info* rep,
        struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset,
-       struct reply_info** encode_repp)
+       struct reply_info** encode_repp, struct auth_zones* az)
 {
        struct respip_action_info actinfo = {respip_none, NULL};
 
@@ -582,7 +582,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
                return 1;
 
        if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo,
-               alias_rrset, 0, worker->scratchpad))
+               alias_rrset, 0, worker->scratchpad, az))
                return 0;
 
        /* xxx_deny actions mean dropping the reply, unless the original reply
@@ -709,20 +709,20 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
                (int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad))
                goto bail_out;
        *alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
-       if(worker->daemon->use_response_ip && !partial_rep &&
-          !apply_respip_action(worker, qinfo, cinfo, rep, repinfo, alias_rrset,
-                       &encode_rep)) {
+       if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
+               !partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
+               repinfo, alias_rrset,
+               &encode_rep, worker->env.auth_zones)) {
                goto bail_out;
        } else if(partial_rep &&
                !respip_merge_cname(partial_rep, qinfo, rep, cinfo,
-               must_validate, &encode_rep, worker->scratchpad)) {
+               must_validate, &encode_rep, worker->scratchpad,
+               worker->env.auth_zones)) {
                goto bail_out;
        }
        if(encode_rep != rep)
                secure = 0; /* if rewritten, it can't be considered "secure" */
        if(!encode_rep || *alias_rrset) {
-               sldns_buffer_clear(repinfo->c->buffer);
-               sldns_buffer_flip(repinfo->c->buffer);
                if(!encode_rep)
                        *need_drop = 1;
                else {
@@ -768,12 +768,18 @@ bail_out:
  * being deferred). */
 static void
 reply_and_prefetch(struct worker* worker, struct query_info* qinfo, 
-       uint16_t flags, struct comm_reply* repinfo, time_t leeway)
+       uint16_t flags, struct comm_reply* repinfo, time_t leeway, int noreply)
 {
        /* first send answer to client to keep its latency 
         * as small as a cachereply */
-       if(sldns_buffer_limit(repinfo->c->buffer) != 0)
+       if(!noreply) {
+               if(repinfo->c->tcp_req_info) {
+                       sldns_buffer_copy(
+                               repinfo->c->tcp_req_info->spool_buffer,
+                               repinfo->c->buffer);
+               }
                comm_point_send_reply(repinfo);
+       }
        server_stats_prefetch(&worker->stats, worker);
        
        /* create the prefetch in the mesh as a normal lookup without
@@ -1445,7 +1451,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
        /* If we may apply IP-based actions to the answer, build the client
         * information.  As this can be expensive, skip it if there is
         * absolutely no possibility of it. */
-       if(worker->daemon->use_response_ip &&
+       if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
                (qinfo.qtype == LDNS_RR_TYPE_A ||
                qinfo.qtype == LDNS_RR_TYPE_AAAA ||
                qinfo.qtype == LDNS_RR_TYPE_ANY)) {
@@ -1490,7 +1496,8 @@ lookup_cache:
                                        lock_rw_unlock(&e->lock);
                                        reply_and_prefetch(worker, lookup_qinfo,
                                                sldns_buffer_read_u16_at(c->buffer, 2),
-                                               repinfo, leeway);
+                                               repinfo, leeway,
+                                               (partial_rep || need_drop));
                                        if(!partial_rep) {
                                                rc = 0;
                                                regional_free_all(worker->scratchpad);
index 20e3680ec3bca96079abdda2193ffa1973b87592..524544a91cf486af50acc011577ddc367d676c10 100644 (file)
@@ -55,6 +55,7 @@
 int 
 context_finalize(struct ub_ctx* ctx)
 {
+       int is_rpz;
        struct config_file* cfg = ctx->env->cfg;
        verbosity = cfg->verbosity;
        if(ctx->logfile_override)
@@ -69,7 +70,7 @@ context_finalize(struct ub_ctx* ctx)
                return UB_NOMEM;
        if(!local_zones_apply_cfg(ctx->local_zones, cfg))
                return UB_INITFAIL;
-       if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1))
+       if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1i, &is_rpz))
                return UB_INITFAIL;
        if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size,
                cfg->msg_cache_slabs)) {
index d61877b556cded929eb02171cc41695e3ce889ae..176abea829eaa9abaa947cabb1362668972b18a9 100644 (file)
@@ -12,6 +12,7 @@
 #include "config.h"
 
 #include "services/localzone.h"
+#include "services/authzone.h"
 #include "services/cache/dns.h"
 #include "sldns/str2wire.h"
 #include "util/config_file.h"
 #include "services/view.h"
 #include "sldns/rrdef.h"
 
-/**
- * Conceptual set of IP addresses for response AAAA or A records that should
- * trigger special actions.
- */
-struct respip_set {
-       struct regional* region;
-       struct rbtree_type ip_tree;
-       char* const* tagname;   /* shallow copy of tag names, for logging */
-       int num_tags;           /* number of tagname entries */
-};
-
-/** An address span with response control information */
-struct resp_addr {
-       /** node in address tree */
-       struct addr_tree_node node;
-       /** tag bitlist */
-       uint8_t* taglist;
-       /** length of the taglist (in bytes) */
-       size_t taglen;
-       /** action for this address span */
-       enum respip_action action;
-        /** "local data" for this node */
-       struct ub_packed_rrset_key* data;
-};
 
 /** Subset of resp_addr.node, used for inform-variant logging */
 struct respip_addr_info {
@@ -88,6 +65,7 @@ respip_set_create(void)
                return NULL;
        }
        addr_tree_init(&set->ip_tree);
+       lock_rw_init(&set->lock);
        return set;
 }
 
@@ -96,6 +74,7 @@ respip_set_delete(struct respip_set* set)
 {
        if(!set)
                return;
+       lock_rw_destroy(&set->lock);
        regional_destroy(set->region);
        free(set);
 }
@@ -108,29 +87,21 @@ respip_set_get_tree(struct respip_set* set)
        return &set->ip_tree;
 }
 
-/** returns the node in the address tree for the specified netblock string;
- * non-existent node will be created if 'create' is true */
-static struct resp_addr*
-respip_find_or_create(struct respip_set* set, const char* ipstr, int create)
+struct resp_addr*
+respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage* addr,
+               socklen_t addrlen, int net, int create, const char* ipstr)
 {
        struct resp_addr* node;
-       struct sockaddr_storage addr;
-       int net;
-       socklen_t addrlen;
-
-       if(!netblockstrtoaddr(ipstr, 0, &addr, &addrlen, &net)) {
-               log_err("cannot parse netblock: '%s'", ipstr);
-               return NULL;
-       }
-       node = (struct resp_addr*)addr_tree_find(&set->ip_tree, &addr, addrlen, net);
+       node = (struct resp_addr*)addr_tree_find(&set->ip_tree, addr, addrlen, net);
        if(!node && create) {
                node = regional_alloc_zero(set->region, sizeof(*node));
                if(!node) {
                        log_err("out of memory");
                        return NULL;
                }
+               lock_rw_init(&node->lock);
                node->action = respip_none;
-               if(!addr_tree_insert(&set->ip_tree, &node->node, &addr,
+               if(!addr_tree_insert(&set->ip_tree, &node->node, addr,
                        addrlen, net)) {
                        /* We know we didn't find it, so this should be
                         * impossible. */
@@ -140,6 +111,37 @@ respip_find_or_create(struct respip_set* set, const char* ipstr, int create)
        return node;
 }
 
+void
+respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node)
+{
+       struct resp_addr* prev;
+       prev = (struct resp_addr*)rbtree_previous((struct rbnode_type*)node);   
+       lock_rw_destroy(&node->lock);
+       rbtree_delete(&set->ip_tree, node);
+       /* no free'ing, all allocated in region */
+       if(!prev)
+               addr_tree_init_parents((rbtree_type*)set);
+       else
+               addr_tree_init_parents_node(&prev->node);
+}
+
+/** returns the node in the address tree for the specified netblock string;
+ * non-existent node will be created if 'create' is true */
+static struct resp_addr*
+respip_find_or_create(struct respip_set* set, const char* ipstr, int create)
+{
+       struct sockaddr_storage addr;
+       int net;
+       socklen_t addrlen;
+
+       if(!netblockstrtoaddr(ipstr, 0, &addr, &addrlen, &net)) {
+               log_err("cannot parse netblock: '%s'", ipstr);
+               return NULL;
+       }
+       return respip_sockaddr_find_or_create(set, &addr, addrlen, net, create,
+               ipstr);
+}
+
 static int
 respip_tag_cfg(struct respip_set* set, const char* ipstr,
        const uint8_t* taglist, size_t taglen)
@@ -191,6 +193,8 @@ respip_action_cfg(struct respip_set* set, const char* ipstr,
                 action = respip_always_refuse;
         else if(strcmp(actnstr, "always_nxdomain") == 0)
                 action = respip_always_nxdomain;
+        else if(strcmp(actnstr, "always_nodata") == 0)
+                action = respip_always_nodata;
         else {
                 log_err("unknown response-ip action %s", actnstr);
                 return 0;
@@ -232,8 +236,43 @@ new_rrset(struct regional* region, uint16_t rrtype, uint16_t rrclass)
 }
 
 /** enter local data as resource records into a response-ip node */
-static int
+
+int
 respip_enter_rr(struct regional* region, struct resp_addr* raddr,
+       uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata,
+       size_t rdata_len, const char* rrstr, const char* netblockstr)
+{
+       struct packed_rrset_data* pd;
+       struct sockaddr* sa;
+       sa = (struct sockaddr*)&raddr->node.addr;
+       if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data) {
+               log_err("CNAME response-ip data (%s) can not co-exist with other "
+                       "response-ip data for netblock %s", rrstr, netblockstr);
+               return 0;
+       } else if (raddr->data &&
+               raddr->data->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
+               log_err("response-ip data (%s) can not be added; CNAME response-ip "
+                       "data already in place for netblock %s", rrstr, netblockstr);
+               return 0;
+       } else if((rrtype != LDNS_RR_TYPE_CNAME) &&
+               ((sa->sa_family == AF_INET && rrtype != LDNS_RR_TYPE_A) ||
+               (sa->sa_family == AF_INET6 && rrtype != LDNS_RR_TYPE_AAAA))) {
+               log_err("response-ip data %s record type does not correspond "
+                       "to netblock %s address family", rrstr, netblockstr);
+               return 0;
+       }
+
+       if(!raddr->data) {
+               raddr->data = new_rrset(region, rrtype, rrclass);
+               if(!raddr->data)
+                       return 0;
+       }
+       pd = raddr->data->entry.data;
+       return rrset_insert_rr(region, pd, rdata, rdata_len, ttl, rrstr);
+}
+
+static int
+respip_enter_rrstr(struct regional* region, struct resp_addr* raddr,
                const char* rrstr, const char* netblock)
 {
        uint8_t* nm;
@@ -244,8 +283,6 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
        size_t rdata_len = 0;
        char buf[65536];
        char bufshort[64];
-       struct packed_rrset_data* pd;
-       struct sockaddr* sa;
        int ret;
        if(raddr->action != respip_redirect
                && raddr->action != respip_inform_redirect) {
@@ -265,31 +302,8 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
                return 0;
        }
        free(nm);
-       sa = (struct sockaddr*)&raddr->node.addr;
-       if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data) {
-               log_err("CNAME response-ip data (%s) can not co-exist with other "
-                       "response-ip data for netblock %s", rrstr, netblock);
-               return 0;
-       } else if (raddr->data &&
-               raddr->data->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
-               log_err("response-ip data (%s) can not be added; CNAME response-ip "
-                       "data already in place for netblock %s", rrstr, netblock);
-               return 0;
-       } else if((rrtype != LDNS_RR_TYPE_CNAME) &&
-               ((sa->sa_family == AF_INET && rrtype != LDNS_RR_TYPE_A) ||
-               (sa->sa_family == AF_INET6 && rrtype != LDNS_RR_TYPE_AAAA))) {
-               log_err("response-ip data %s record type does not correspond "
-                       "to netblock %s address family", rrstr, netblock);
-               return 0;
-       }
-
-       if(!raddr->data) {
-               raddr->data = new_rrset(region, rrtype, rrclass);
-               if(!raddr->data)
-                       return 0;
-       }
-       pd = raddr->data->entry.data;
-       return rrset_insert_rr(region, pd, rdata, rdata_len, ttl, rrstr);
+       return respip_enter_rr(region, raddr, rrtype, rrclass, ttl, rdata,
+               rdata_len, rrstr, netblock);
 }
 
 static int
@@ -303,7 +317,7 @@ respip_data_cfg(struct respip_set* set, const char* ipstr, const char* rrstr)
                        "response-ip node for %s not found", rrstr, ipstr);
                return 0;
        }
-       return respip_enter_rr(set->region, node, rrstr, ipstr);
+       return respip_enter_rrstr(set->region, node, rrstr, ipstr);
 }
 
 static int
@@ -361,6 +375,7 @@ respip_set_apply_cfg(struct respip_set* set, char* const* tagname, int num_tags,
                free(pd);
                pd = np;
        }
+       addr_tree_init_parents(&set->ip_tree);
 
        return 1;
 }
@@ -557,9 +572,10 @@ rdata2sockaddr(const struct packed_rrset_data* rd, uint16_t rtype, size_t i,
  * rep->rrsets for the RRset that contains the matching IP address record
  * (the index is normally 0, but can be larger than that if this is a CNAME
  * chain or type-ANY response).
+ * Returns resp_addr holding read lock.
  */
-static const struct resp_addr*
-respip_addr_lookup(const struct reply_info *rep, struct rbtree_type* iptree,
+static struct resp_addr*
+respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
        size_t* rrset_id)
 {
        size_t i;
@@ -567,6 +583,7 @@ respip_addr_lookup(const struct reply_info *rep, struct rbtree_type* iptree,
        struct sockaddr_storage ss;
        socklen_t addrlen;
 
+       lock_rw_rdlock(&rs->lock);
        for(i=0; i<rep->an_numrrsets; i++) {
                size_t j;
                const struct packed_rrset_data* rd;
@@ -578,15 +595,17 @@ respip_addr_lookup(const struct reply_info *rep, struct rbtree_type* iptree,
                for(j = 0; j < rd->count; j++) {
                        if(!rdata2sockaddr(rd, rtype, j, &ss, &addrlen))
                                continue;
-                       ra = (struct resp_addr*)addr_tree_lookup(iptree, &ss,
-                               addrlen);
+                       ra = (struct resp_addr*)addr_tree_lookup(&rs->ip_tree,
+                               &ss, addrlen);
                        if(ra) {
                                *rrset_id = i;
+                               lock_rw_rdlock(&ra->lock);
+                               lock_rw_unlock(&rs->lock);
                                return ra;
                        }
                }
        }
-
+       lock_rw_unlock(&rs->lock);
        return NULL;
 }
 
@@ -754,6 +773,7 @@ respip_nodata_answer(uint16_t qtype, enum respip_action action,
                return 1;
        } else if(action == respip_static || action == respip_redirect ||
                action == respip_always_nxdomain ||
+               action == respip_always_nodata ||
                action == respip_inform_redirect) {
                /* Since we don't know about other types of the owner name,
                 * we generally return NOERROR/NODATA unless an NXDOMAIN action
@@ -817,7 +837,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
        const struct respip_client_info* cinfo, const struct reply_info* rep,
        struct reply_info** new_repp, struct respip_action_info* actinfo,
        struct ub_packed_rrset_key** alias_rrset, int search_only,
-       struct regional* region)
+       struct regional* region, struct auth_zones* az)
 {
        const uint8_t* ctaglist;
        size_t ctaglen;
@@ -830,9 +850,10 @@ respip_rewrite_reply(const struct query_info* qinfo,
        size_t rrset_id = 0;
        enum respip_action action = respip_none;
        int tag = -1;
-       const struct resp_addr* raddr = NULL;
+       struct resp_addr* raddr = NULL;
        int ret = 1;
        struct ub_packed_rrset_key* redirect_rrset = NULL;
+       struct rpz* r;
 
        if(!cinfo)
                goto done;
@@ -859,7 +880,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
                lock_rw_rdlock(&view->lock);
                if(view->respip_set) {
                        if((raddr = respip_addr_lookup(rep,
-                               &view->respip_set->ip_tree, &rrset_id))) {
+                               view->respip_set, &rrset_id))) {
                                /** for per-view respip directives the action
                                 * can only be direct (i.e. not tag-based) */
                                action = raddr->action;
@@ -868,7 +889,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
                if(!raddr && !view->isfirst)
                        goto done;
        }
-       if(!raddr && ipset && (raddr = respip_addr_lookup(rep, &ipset->ip_tree,
+       if(!raddr && ipset && (raddr = respip_addr_lookup(rep, ipset,
                &rrset_id))) {
                action = (enum respip_action)local_data_find_tag_action(
                        raddr->taglist, raddr->taglen, ctaglist, ctaglen,
@@ -876,6 +897,17 @@ respip_rewrite_reply(const struct query_info* qinfo,
                        (enum localzone_type)raddr->action, &tag,
                        ipset->tagname, ipset->num_tags);
        }
+       lock_rw_rdlock(&az->rpz_lock);
+       for(r = az->rpz_first; r && !raddr; r = r->next) {
+               if(!r->taglist || taglist_intersect(r->taglist, 
+                       r->taglistlen, ctaglist, ctaglen)) {
+                       if((raddr = respip_addr_lookup(rep,
+                               r->respip_set, &rrset_id))) {
+                               action = raddr->action;
+                       }
+               }       
+       }
+       lock_rw_unlock(&az->rpz_lock);
        if(raddr && !search_only) {
                int result = 0;
 
@@ -884,6 +916,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
                if(action != respip_always_refuse
                        && action != respip_always_transparent
                        && action != respip_always_nxdomain
+                       && action != respip_always_nodata
                        && (result = respip_data_answer(raddr, action,
                        qinfo->qtype, rep, rrset_id, new_repp, tag, tag_datas,
                        tag_datas_size, ipset->tagname, ipset->num_tags,
@@ -920,6 +953,8 @@ respip_rewrite_reply(const struct query_info* qinfo,
                ret = populate_action_info(actinfo, action, raddr,
                        redirect_rrset, tag, ipset, search_only, region);
        }
+       if(raddr)
+               lock_rw_unlock(&raddr->lock);
        return ret;
 }
 
@@ -981,7 +1016,7 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
                        if(!respip_rewrite_reply(&qstate->qinfo,
                                qstate->client_info, qstate->return_msg->rep,
                                &new_rep, &actinfo, &alias_rrset, 0,
-                               qstate->region)) {
+                               qstate->region, qstate->env->auth_zones)) {
                                goto servfail;
                        }
                        if(actinfo.action != respip_none) {
@@ -1027,7 +1062,8 @@ int
 respip_merge_cname(struct reply_info* base_rep,
        const struct query_info* qinfo, const struct reply_info* tgt_rep,
        const struct respip_client_info* cinfo, int must_validate,
-       struct reply_info** new_repp, struct regional* region)
+       struct reply_info** new_repp, struct regional* region,
+       struct auth_zones* az)
 {
        struct reply_info* new_rep;
        struct reply_info* tmp_rep = NULL; /* just a placeholder */
@@ -1053,7 +1089,7 @@ respip_merge_cname(struct reply_info* base_rep,
 
        /* see if the target reply would be subject to a response-ip action. */
        if(!respip_rewrite_reply(qinfo, cinfo, tgt_rep, &tmp_rep, &actinfo,
-               &alias_rrset, 1, region))
+               &alias_rrset, 1, region, az))
                return 0;
        if(actinfo.action != respip_none) {
                log_info("CNAME target of redirect response-ip action would "
@@ -1105,7 +1141,8 @@ respip_inform_super(struct module_qstate* qstate, int id,
 
        if(!respip_merge_cname(super->return_msg->rep, &qstate->qinfo,
                qstate->return_msg->rep, super->client_info,
-               super->env->need_to_validate, &new_rep, super->region))
+               super->env->need_to_validate, &new_rep, super->region,
+               qstate->env->auth_zones))
                goto fail;
        super->return_msg->rep = new_rep;
        return;
index 01309caece519dbbcddfb4c2330c358f353091aa..d2d39872ce1eb27ad234c25d8ac1a5f7d94ee580 100644 (file)
 
 #include "util/module.h"
 #include "services/localzone.h"
+#include "util/locks.h"
 
 /**
- * Set of response IP addresses with associated actions and tags. 
- * Forward declaration only here.  Actual definition is hidden within the
- * module.
+ * Conceptual set of IP addresses for response AAAA or A records that should
+ * trigger special actions.
  */
-struct respip_set;
+struct respip_set {
+       struct regional* region;
+       struct rbtree_type ip_tree;
+       lock_rw_type lock;      /* lock on the respip tree */
+       char* const* tagname;   /* shallow copy of tag names, for logging */
+       int num_tags;           /* number of tagname entries */
+};
+
+
+/** An address span with response control information */
+struct resp_addr {
+       /** node in address tree */
+       struct addr_tree_node node;
+       /** lock on the node item */
+       lock_rw_type lock;
+       /** tag bitlist */
+       uint8_t* taglist;
+       /** length of the taglist (in bytes) */
+       size_t taglen;
+       /** action for this address span */
+       enum respip_action action;
+        /** "local data" for this node */
+       struct ub_packed_rrset_key* data;
+};
 
-/**
- * Forward declaration for the structure that represents a node in the
- * respip_set address tree
- */
-struct resp_addr;
 
 /**
  * Forward declaration for the structure that represents a tree of view data.
@@ -124,12 +142,14 @@ int respip_views_apply_cfg(struct views* vs, struct config_file* cfg,
  * @param new_repp: pointer placeholder for the merged reply.  will be intact
  *   on error.
  * @param region: allocator to build *new_repp.
+ * @param az: auth zones containing RPZ information.
  * @return 1 on success, 0 on error.
  */
 int respip_merge_cname(struct reply_info* base_rep,
        const struct query_info* qinfo, const struct reply_info* tgt_rep,
        const struct respip_client_info* cinfo, int must_validate,
-       struct reply_info** new_repp, struct regional* region);
+       struct reply_info** new_repp, struct regional* region,
+       struct auth_zones* az);
 
 /**
  * See if any IP-based action should apply to any IP address of AAAA/A answer
@@ -148,6 +168,7 @@ int respip_merge_cname(struct reply_info* base_rep,
  * @param alias_rrset: must not be NULL.
  * @param search_only: if true, only check if an action would apply.  actionp
  *   will be set (or intact) accordingly but the modified reply won't be built.
+ * @param az: auth zones containing RPZ information.
  * @param region: allocator to build *new_repp.
  * @return 1 on success, 0 on error.
  */
@@ -156,7 +177,7 @@ int respip_rewrite_reply(const struct query_info* qinfo,
        const struct reply_info *rep, struct reply_info** new_repp,
        struct respip_action_info* actinfo,
        struct ub_packed_rrset_key** alias_rrset,
-       int search_only, struct regional* region);
+       int search_only, struct regional* region, struct auth_zones* az);
 
 /**
  * Get the response-ip function block.
@@ -227,4 +248,44 @@ void respip_inform_print(struct respip_addr_info* respip_addr, uint8_t* qname,
        uint16_t qtype, uint16_t qclass, struct local_rrset* local_alias,
        struct comm_reply* repinfo);
 
+/**
+ * Find resp_addr in tree, create and add to tree if it does not exist.
+ * @param set: struct containing the tree and region to alloc new node on.
+ *     should hold write lock.
+ * @param addr: address to look up.
+ * @param addrlen: length of addr.
+ * @param net: netblock to lookup.
+ * @param create: create node if it does not exist when 1.
+ * @param ipstr: human redable ip string, for logging.
+ * @return newly created of found node, not holding lock.
+ */
+struct resp_addr*
+respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage* addr,
+               socklen_t addrlen, int net, int create, const char* ipstr);
+
+/**
+ * Add RR to resp_addr's RRset. Create RRset is not existing.
+ * @param region: region to alloc RR(set).
+ * @param raddr: resp_addr containing RRset. Must hold write lock.
+ * @param rrtype: RR type.
+ * @param rrclass: RR class.
+ * @param ttl: TTL.
+ * @param rdata: RDATA.
+ * @param rdata_len: length of rdata.
+ * @param rrstr: RR as string, for logging
+ * @param netblockstr: netblock as string, for logging
+ * @return 0 on error
+ */
+int
+respip_enter_rr(struct regional* region, struct resp_addr* raddr,
+       uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata,
+       size_t rdata_len, const char* rrstr, const char* netblockstr);
+
+/**
+ * Delete resp_addr node from tree.
+ * @param set: struct containing tree. Must hold write lock.
+ * @param node: node to delete. Must hold write lock.
+ */
+void
+respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node);
 #endif /* RESPIP_RESPIP_H */
index a408166e576e66df244e7106c9ad50e32624c4c3..3594fe41db243713133761f75e0e798423ff9453 100644 (file)
@@ -1542,9 +1542,9 @@ auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg)
        /* clear the data tree */
        traverse_postorder(&z->data, auth_data_del, NULL);
        rbtree_init(&z->data, &auth_data_cmp);
-       /* clear the RPZ local_zone tree */
+       /* clear the RPZ policies */
        if(z->rpz)
-               rpz_clear_lz(z->rpz);
+               rpz_clear(z->rpz);
 
        memset(&state, 0, sizeof(state));
        /* default TTL to 3600 */
@@ -1564,6 +1564,9 @@ auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg)
                return 0;
        }
        fclose(in);
+
+       if(z->rpz)
+               rpz_finish_config(z->rpz);
        return 1;
 }
 
@@ -1926,7 +1929,7 @@ az_delete_deleted_zones(struct auth_zones* az)
 }
 
 int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
-       int setup)
+       int setup, int* is_rpz)
 {
        struct config_auth* p;
        az_setall_deleted(az);
@@ -1935,6 +1938,7 @@ int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
                        log_warn("auth-zone without a name, skipped");
                        continue;
                }
+               *is_rpz = (*is_rpz || p->isrpz);
                if(!auth_zones_cfg(az, p)) {
                        log_err("cannot config auth zone %s", p->name);
                        return 0;
@@ -4654,9 +4658,9 @@ apply_axfr(struct auth_xfer* xfr, struct auth_zone* z,
        /* clear the data tree */
        traverse_postorder(&z->data, auth_data_del, NULL);
        rbtree_init(&z->data, &auth_data_cmp);
-       /* clear the RPZ local_zone tree */
+       /* clear the RPZ policies */
        if(z->rpz)
-               rpz_clear_lz(z->rpz);
+               rpz_clear(z->rpz);
 
        xfr->have_zone = 0;
        xfr->serial = 0;
@@ -4754,9 +4758,9 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
        /* clear the data tree */
        traverse_postorder(&z->data, auth_data_del, NULL);
        rbtree_init(&z->data, &auth_data_cmp);
-       /* clear the RPZ local_zone tree */
+       /* clear the RPZ policies */
        if(z->rpz)
-               rpz_clear_lz(z->rpz);
+               rpz_clear(z->rpz);
 
        xfr->have_zone = 0;
        xfr->serial = 0;
@@ -4937,6 +4941,9 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
        if(xfr->have_zone)
                xfr->lease_time = *env->now;
 
+       if(z->rpz)
+               rpz_finish_config(z->rpz);
+
        /* unlock */
        lock_rw_unlock(&z->lock);
 
index 00f5d665516a2cf01636d7d26c3624b5d84d8cd2..968ff72189ae815f04a528e6b22c417c31bd4998 100644 (file)
@@ -468,10 +468,11 @@ struct auth_zones* auth_zones_create(void);
  * @param az: auth zones structure
  * @param cfg: config to apply.
  * @param setup: if true, also sets up values in the auth zones structure
+ * @param is_rpz: set to 1 if at least one RPZ zone is configured.
  * @return false on failure.
  */
 int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
-       int setup);
+       int setup, int* iz_rpz);
 
 /** initial pick up of worker timeouts, ties events to worker event loop
  * @param az: auth zones structure
index e8c493f63a85b8ef18b4133f768d3a452770eb3c..a476f36c9b848b8a1535989bb2a132e05e1547d5 100644 (file)
@@ -555,6 +555,8 @@ enum respip_action {
        respip_transparent = local_zone_transparent,
        /** gives response data (if any), else nodata answer. */
        respip_typetransparent = local_zone_typetransparent,
+       /** type invalid */
+       respip_invalid = local_zone_invalid,
 };
 
 int
index ef2d504ca98f6128fb056642fdb6b985c28de079..0b39c95c93dc732d1417b29c62b773c98a8c903d 100644 (file)
@@ -209,6 +209,24 @@ rpz_action_to_localzone_type(enum rpz_action a)
        }
 }
 
+static enum respip_action
+rpz_action_to_respip_action(enum rpz_action a)
+{
+       switch(a) {
+       case RPZ_NXDOMAIN_ACTION:       return respip_always_nxdomain;
+       case RPZ_NODATA_ACTION:         return respip_always_nodata;
+       case RPZ_DROP_ACTION:           return respip_deny;
+       case RPZ_PASSTHRU_ACTION:       return respip_always_transparent;
+       case RPZ_LOCAL_DATA_ACTION:
+       case RPZ_CNAME_OVERRIDE_ACTION:
+                                       return respip_redirect;
+       case RPZ_INVALID_ACTION:
+       case RPZ_TCP_ONLY_ACTION:
+       default:
+               return respip_invalid;
+       }
+}
+
 static enum rpz_action
 localzone_type_to_rpz_action(enum localzone_type lzt)
 {
@@ -256,6 +274,7 @@ void rpz_delete(struct rpz* r)
        if(!r)
                return;
        local_zones_delete(r->local_zones);
+       respip_set_delete(r->respip_set);
        regional_destroy(r->region);
        free(r->taglist);
        free(r->log_name);
@@ -263,16 +282,28 @@ void rpz_delete(struct rpz* r)
 }
 
 int
-rpz_clear_lz(struct rpz* r)
+rpz_clear(struct rpz* r)
 {
        /* must hold write lock on auth_zone */
        local_zones_delete(r->local_zones);
+       respip_set_delete(r->respip_set);
        if(!(r->local_zones = local_zones_create())){
                return 0;
        }
+       if(!(r->respip_set = respip_set_create())) {
+               return 0;
+       }
        return 1;
 }
 
+void
+rpz_finish_config(struct rpz* r)
+{
+       lock_rw_wrlock(&r->respip_set->lock);
+       addr_tree_init_parents(&r->respip_set->ip_tree);
+       lock_rw_unlock(&r->respip_set->lock);
+}
+
 /** new rrset containing CNAME override, does not yet contain a dname */
 static struct ub_packed_rrset_key*
 new_cname_override(struct regional* region, uint8_t* ct, size_t ctlen)
@@ -323,17 +354,18 @@ rpz_create(struct config_auth* p)
 {
        struct rpz* r = calloc(1, sizeof(*r));
        if(!r)
-               return 0;
+               goto err;
 
        r->region = regional_create_custom(sizeof(struct regional));
        if(!r->region) {
-               free(r);
-               return 0;
+               goto err;
        }
 
        if(!(r->local_zones = local_zones_create())){
-               free(r);
-               return 0;
+               goto err;
+       }
+       if(!(r->respip_set = respip_set_create())) {
+               goto err;
        }
        r->taglistlen = p->rpz_taglistlen;
        r->taglist = memdup(p->rpz_taglist, r->taglistlen);
@@ -350,26 +382,34 @@ rpz_create(struct config_auth* p)
                if(!p->rpz_cname) {
                        log_err("RPZ override with cname action found, but not "
                                "rpz-cname-override configured");
-                       free(r);
-                       return 0;
+                       goto err;
                }
 
                if(sldns_str2wire_dname_buf(p->rpz_cname, nm, &nmlen) != 0) {
                        log_err("cannot parse RPZ cname override: %s",
                                p->rpz_cname);
-                       free(r);
-                       return 0;
+                       goto err;
                }
                r->cname_override = new_cname_override(r->region, nm, nmlen);
                if(!r->cname_override) {
-                       free(r);
-                       return 0;
+                       goto err;
                }
        }
        r->log = p->rpz_log;
        if(p->rpz_log_name)
                r->log_name = strdup(p->rpz_log_name);
        return r;
+err:
+       if(r) {
+               if(r->local_zones)
+                       local_zones_delete(r->local_zones);
+               if(r->respip_set)
+                       respip_set_delete(r->respip_set);
+               if(r->taglist)
+                       free(r->taglist);
+               free(r);
+       }
+       return NULL;
 }
 
 /** Remove RPZ zone name from dname */
@@ -436,46 +476,46 @@ rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
        return 1;
 }
 
-/** Insert RR into RPZ's ACL tree */
+/** Insert RR into RPZ's respip_set */
 static int
-rpz_insert_client_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
+rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname,
        enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
        uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
 {
-       /* TODO: remove void casts */
-       (void)r;
-       (void)dnamelen;
-       (void)rrtype;
-       (void)rrclass;
-       (void)ttl;
-       (void)rdata;
-       (void)rdata_len;
-       (void)rr;
-       (void)rr_len;
-
-       if(a == RPZ_DROP_ACTION) {
-               /* insert into r->acl tree */
-               struct sockaddr_storage addr;
-               char str[INET6_ADDRSTRLEN];
-               socklen_t addrlen;
-               int net, af;
-               if(!netblockdnametoaddr(dname, &addr, &addrlen, &net, &af))
-                       return 0;
-               /* TODO insert into acl tree */
-#if 0
-               if((inet_ntop(af,
-                       (af == AF_INET) ?
-                               (void*)&((struct sockaddr_in*)&addr)->sin_addr :
-                               (void*)&((struct sockaddr_in6*)&addr)->sin6_addr,
-                       str, INET6_ADDRSTRLEN)))
-                       log_info("rpz %s/%d\n", str, net);
-#endif
-       } else {
+       struct resp_addr* node;
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+       int net, af;
+       char* rrstr = sldns_wire2str_rr(rr, rr_len);
+       enum respip_action respa = rpz_action_to_respip_action(a);
+
+       if(a == RPZ_TCP_ONLY_ACTION || a == RPZ_INVALID_ACTION ||
+               respa == respip_invalid) {
                verbose(VERB_ALGO, "RPZ: skipping unsupported action: %s",
                        rpz_action_to_string(a));
                return 0;
        }
-       return 0;
+
+       if(!netblockdnametoaddr(dname, &addr, &addrlen, &net, &af))
+               return 0;
+
+       lock_rw_wrlock(&r->respip_set->lock);
+       if(!(node=respip_sockaddr_find_or_create(r->respip_set, &addr, addrlen,
+               net, 1, rrstr))) {
+               lock_rw_unlock(&r->respip_set->lock);
+               return 0;
+       }
+
+       lock_rw_wrlock(&node->lock);
+       lock_rw_unlock(&r->respip_set->lock);
+       node->action = respa;
+
+       if(a == RPZ_LOCAL_DATA_ACTION) {
+               respip_enter_rr(r->respip_set->region, node, rrtype,
+                       rrclass, ttl, rdata, rdata_len, rrstr, "");
+       }
+       lock_rw_unlock(&node->lock);
+       return 1;
 }
 
 void
@@ -501,8 +541,8 @@ rpz_insert_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
                        a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
                        rr_len);
        }
-       else if(t == RPZ_CLIENT_IP_TRIGGER) {
-               rpz_insert_client_ip_trigger(r, policydname, policydnamelen,
+       else if(t == RPZ_RESPONSE_IP_TRIGGER) {
+               rpz_insert_response_ip_trigger(r, policydname,
                        a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
                        rr_len);
        }
@@ -637,46 +677,135 @@ rpz_data_delete_rr(struct local_zone* z, uint8_t* policydname,
        return 1;
 }
 
-void
-rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
-       size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl,
-       size_t rdatalen)
+/**
+ * Remove RR from RPZ's respip set
+ * @param raddr: respip node
+ * @param rdata: rdata of RR to remove
+ * @param rdatalen: length of rdata
+ * @param region: RPZ's repsip_set region
+ * @return: 1 if zone must be removed after RR deletion
+ */
+static int
+rpz_rrset_delete_rr(struct resp_addr* raddr, uint16_t rr_type, uint8_t* rdata,
+       size_t rdatalen, struct regional* region)
+{
+       size_t index;
+       struct packed_rrset_data* d;
+       if(!raddr->data)
+               return 1;
+       d = raddr->data->entry.data;
+       if(ntohs(raddr->data->rk.type) != rr_type) {
+               return 0;
+       }
+       if(packed_rrset_find_rr(d, rdata, rdatalen, &index)) {
+               if(d->count == 1) {
+                       /* regional alloc'd */
+                       raddr->data->entry.data = NULL; 
+                       raddr->data = NULL;
+                       return 1;
+               }
+               if(d->count > 1) {
+                       struct packed_rrset_data* new;
+                       new = packed_rrset_remove_rr(d, index, region);
+                       if(!new)
+                               return 0;
+                       raddr->data->entry.data = new;  
+               }
+       }
+       return 0;
+
+}
+
+/** Remove RR from RPZ's local-zone */
+static void
+rpz_remove_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
+       enum rpz_action a, uint16_t rr_type, uint16_t rr_class,
+       uint8_t* rdatawl, size_t rdatalen)
 {
        struct local_zone* z;
+       int delete_zone = 1;
+       z = rpz_find_zone(r, dname, dnamelen, rr_class,
+               1 /* only exact */, 1 /* wr lock */);
+       if(!z) {
+               verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, "
+                       "RPZ domain not found");
+               return;
+       }
+       if(a == RPZ_LOCAL_DATA_ACTION)
+               delete_zone = rpz_data_delete_rr(z, dname,
+                       dnamelen, rr_type, rdatawl, rdatalen);
+       else if(a != localzone_type_to_rpz_action(z->type)) {
+               return;
+       }
+       lock_rw_unlock(&z->lock); 
+       if(delete_zone) {
+               local_zones_del_zone(r->local_zones, z);
+       }
+       return;
+}
+
+static void
+rpz_remove_response_ip_trigger(struct rpz* r, uint8_t* dname, enum rpz_action a,
+       uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
+{
+       struct resp_addr* node;
+       struct sockaddr_storage addr;
+       socklen_t addrlen;
+       int net, af;
+       int delete_respip = 1;
+
+       if(!netblockdnametoaddr(dname, &addr, &addrlen, &net, &af))
+               return;
+
+       lock_rw_wrlock(&r->respip_set->lock);
+       if(!(node = (struct resp_addr*)addr_tree_find(
+               &r->respip_set->ip_tree, &addr, addrlen, net))) {
+               verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, "
+                       "RPZ domain not found");
+               lock_rw_unlock(&r->respip_set->lock);
+               return;
+       }
+
+       lock_rw_wrlock(&node->lock);
+       if(a == RPZ_LOCAL_DATA_ACTION) {
+               /* remove RR, signal whether RR can be removed */
+               delete_respip = rpz_rrset_delete_rr(node, rr_type, rdatawl, 
+                       rdatalen, r->respip_set->region);
+       }
+       if(delete_respip) {
+               /* delete + reset parent pointers */    
+               respip_sockaddr_delete(r->respip_set, node);
+       } else {
+               lock_rw_unlock(&node->lock);
+       }
+       lock_rw_unlock(&r->respip_set->lock);
+}
+
+void
+rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname, size_t dnamelen,
+       uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl, size_t rdatalen)
+{
        size_t policydnamelen;
        /* name is free'd in local_zone delete */
        uint8_t* policydname = calloc(1, LDNS_MAX_DOMAINLEN + 1);
        enum rpz_trigger t;
        enum rpz_action a;
-       int delete_zone = 1;
 
        a = rpz_rr_to_action(rr_type, rdatawl, rdatalen);
+       if(a == RPZ_INVALID_ACTION)
+               return;
        if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen,
                policydname))) {
                free(policydname);
                return;
        }
        t = rpz_dname_to_trigger(policydname);
-       if(a != RPZ_INVALID_ACTION && t == RPZ_QNAME_TRIGGER) {
-               z = rpz_find_zone(r, policydname, policydnamelen, rr_class,
-                       1 /* only exact */, 1 /* wr lock */);
-               if(!z) {
-                       verbose(VERB_ALGO, "RPZ: cannot remove RR from IXFR, "
-                               "RPZ domain not found");
-                       free(policydname);
-                       return;
-               }
-               if(a == RPZ_LOCAL_DATA_ACTION)
-                       delete_zone = rpz_data_delete_rr(z, policydname,
-                               policydnamelen, rr_type, rdatawl, rdatalen);
-               else if(a != localzone_type_to_rpz_action(z->type)) {
-                       free(policydname);
-                       return;
-               }
-               lock_rw_unlock(&z->lock); 
-               if(delete_zone) {
-                       local_zones_del_zone(r->local_zones, z);
-               }
+       if(t == RPZ_QNAME_TRIGGER) {
+               rpz_remove_qname_trigger(r, policydname, policydnamelen, a,
+                       rr_type, rr_class, rdatawl, rdatalen);
+       } else if(t == RPZ_RESPONSE_IP_TRIGGER) {
+               rpz_remove_response_ip_trigger(r, policydname, a, rr_type,
+                       rdatawl, rdatalen);
        }
        free(policydname);
 }
index 64fac1ea475aa469a5e7f5d6ca5b4a8f186b1b55..a5b9e67ab02fc2fa68f27007c7b2876b32a7f500 100644 (file)
@@ -48,6 +48,7 @@
 #include "services/authzone.h"
 #include "sldns/sbuffer.h"
 #include "daemon/stats.h"
+#include "respip/respip.h"
 
 /**
  * RPZ triggers, only the QNAME trigger is currently supported in Unbound.
@@ -87,6 +88,7 @@ enum rpz_action {
  */
 struct rpz {
        struct local_zones* local_zones;
+       struct respip_set* respip_set;
        uint8_t* taglist;
        size_t taglistlen;
        enum rpz_action action_override;
@@ -157,10 +159,11 @@ int rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
 void rpz_delete(struct rpz* r);
 
 /**
- * Clear local-zones in RPZ, used after reloading file or AXFR/HTTP transfer.
+ * Clear local-zones and respip data in RPZ, used after reloading file or
+ * AXFR/HTTP transfer.
  * @param r: RPZ to use
  */
-int rpz_clear_lz(struct rpz* r);
+int rpz_clear(struct rpz* r);
 
 /**
  * Create RPZ. RPZ must be added to linked list after creation.
@@ -175,4 +178,10 @@ struct rpz* rpz_create(struct config_auth* p);
  */
 const char* rpz_action_to_string(enum rpz_action a);
 
+/**
+ * Prepare RPZ after procesing feed content.
+ * @param r: RPZ to use
+ */
+void rpz_finish_config(struct rpz* r);
+
 #endif /* SERVICES_RPZ_H */
index 0cf3d35aa4925d1436b37c4158e5a84517505450..713380600a7841481df1242387fb61f928fe4897 100644 (file)
@@ -642,8 +642,9 @@ check_hints(struct config_file* cfg)
 static void
 check_auth(struct config_file* cfg)
 {
+       int is_rpz;
        struct auth_zones* az = auth_zones_create();
-       if(!az || !auth_zones_apply_cfg(az, cfg, 0)) {
+       if(!az || !auth_zones_apply_cfg(az, cfg, 0i, &is_rpz)) {
                fatal_exit("Could not setup authority zones");
        }
        auth_zones_delete(az);
index dbd5a7bad57f159c5acda595c746b17fa2c46ea8..1042d1a2c19ff707dcbec404f7a1227ed622610f 100644 (file)
@@ -1900,7 +1900,7 @@ char* config_taglist2str(struct config_file* cfg, uint8_t* taglist,
        return strdup(buf);
 }
 
-int taglist_intersect(uint8_t* list1, size_t list1len, uint8_t* list2,
+int taglist_intersect(uint8_t* list1, size_t list1len, const uint8_t* list2,
        size_t list2len)
 {
        size_t i;
index 3bcd3db0accdecd33bb2bfbcfaff96eb08329578..a8fb88a4f1807ce61e305551ec210027b97bc207 100644 (file)
@@ -1036,7 +1036,7 @@ char* config_taglist2str(struct config_file* cfg, uint8_t* taglist,
  * @param list2len: length in bytes of second list.
  * @return true if there are tags in common, 0 if not.
  */
-int taglist_intersect(uint8_t* list1, size_t list1len, uint8_t* list2,
+int taglist_intersect(uint8_t* list1, size_t list1len, const uint8_t* list2,
        size_t list2len);
 
 /**
index 9bc240c5d9e941efc1b25c2dbe18346bff90f818..9ba5ca15b6ded10edc8441c3fd815a8d6bc0ce4f 100644 (file)
@@ -356,13 +356,12 @@ static int ipdnametoaddr(uint8_t* dname, struct sockaddr_storage* addr,
 int netblockdnametoaddr(uint8_t* dname, struct sockaddr_storage* addr,
        socklen_t* addrlen, int* net, int* af)
 {
-       int e;
        char buff[3 /* 3 digit netblock */ + 1];
        if(*dname > 3)
                /* netblock invalid */
                return 0;
        memcpy(buff, dname+1, *dname);
-       buff[(*dname)+1] = '\0';
+       buff[*dname] = '\0';
        *net = atoi(buff);
        dname += *dname;
        dname++;
index 190369d851c815d91ac3cb51432eceaf8973c11e..f883044afa4b0cbc2ba69c78dbc36814c91397da 100644 (file)
@@ -104,11 +104,12 @@ int addr_tree_insert(rbtree_type* tree, struct addr_tree_node* node,
        return rbtree_insert(tree, &node->node) != NULL;
 }
 
-void addr_tree_init_parents(rbtree_type* tree)
+void addr_tree_init_parents_node(struct addr_tree_node* node)
 {
-        struct addr_tree_node* node, *prev = NULL, *p;
+       struct addr_tree_node* prev = NULL, *p;
         int m;
-        RBTREE_FOR(node, struct addr_tree_node*, tree) {
+       for(; (rbnode_type*)node != RBTREE_NULL;
+               node = (struct addr_tree_node*)rbtree_next((rbnode_type*)node)) {
                 node->parent = NULL;
                 if(!prev || prev->addrlen != node->addrlen) {
                         prev = node;
@@ -130,6 +131,12 @@ void addr_tree_init_parents(rbtree_type* tree)
         }
 }
 
+void addr_tree_init_parents(rbtree_type* tree)
+{
+       addr_tree_init_parents_node(
+                       (struct addr_tree_node*)rbtree_first(tree));
+}
+
 void name_tree_init_parents(rbtree_type* tree)
 {
         struct name_tree_node* node, *prev = NULL, *p;
index 782644b633e9db076a0e31ec30ba996684bca3b0..d54602fd7ddfe426934fb4459b6adab75ab1e1c4 100644 (file)
@@ -173,6 +173,13 @@ int addr_tree_insert(rbtree_type* tree, struct addr_tree_node* node,
  */
 void addr_tree_init_parents(rbtree_type* tree);
 
+/**
+ * Initialize parent pointers in partial addr tree.
+ * Reinitialize pointer for part of tree, used after node deletion
+ * @param node: node to start parent pointer initialization for.
+ */
+void addr_tree_init_parents_node(struct addr_tree_node* node);
+
 /**
  * Lookup closest encloser in addr tree.
  * @param tree: addr tree