]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix #628: A rpz-passthru action is not ending RPZ zone processing.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 15 Feb 2022 15:20:12 +0000 (16:20 +0100)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 15 Feb 2022 15:20:12 +0000 (16:20 +0100)
14 files changed:
daemon/worker.c
doc/Changelog
libunbound/libworker.c
respip/respip.c
respip/respip.h
services/authzone.c
services/mesh.c
services/mesh.h
services/rpz.c
services/rpz.h
testdata/rpz_passthru.rpl [new file with mode: 0644]
testdata/rpz_qname.rpl
util/module.h
validator/autotrust.c

index aee308d7dd20273d1332f0f082264815fdcece0f..863cd7a358cc895026753fb5d108f0d169d82366 100644 (file)
@@ -553,7 +553,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, az))
+               alias_rrset, 0, worker->scratchpad, az, NULL))
                return 0;
 
        /* xxx_deny actions mean dropping the reply, unless the original reply
@@ -742,7 +742,8 @@ bail_out:
 /** Reply to client and perform prefetch to keep cache up to date. */
 static void
 reply_and_prefetch(struct worker* worker, struct query_info* qinfo, 
-       uint16_t flags, struct comm_reply* repinfo, time_t leeway, int noreply)
+       uint16_t flags, struct comm_reply* repinfo, time_t leeway, int noreply,
+       int rpz_passthru)
 {
        /* first send answer to client to keep its latency 
         * as small as a cachereply */
@@ -761,7 +762,7 @@ reply_and_prefetch(struct worker* worker, struct query_info* qinfo,
         * the cache and go to the network for the data). */
        /* this (potentially) runs the mesh for the new query */
        mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway + 
-               PREFETCH_EXPIRY_ADD);
+               PREFETCH_EXPIRY_ADD, rpz_passthru);
 }
 
 /**
@@ -1073,6 +1074,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
        int need_drop = 0;
        int is_expired_answer = 0;
        int is_secure_answer = 0;
+       int rpz_passthru = 0;
        /* We might have to chase a CNAME chain internally, in which case
         * we'll have up to two replies and combine them to build a complete
         * answer.  These variables control this case. */
@@ -1338,7 +1340,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
        if(worker->env.auth_zones &&
                rpz_callback_from_worker_request(worker->env.auth_zones,
                &worker->env, &qinfo, &edns, c->buffer, worker->scratchpad,
-               repinfo, acladdr->taglist, acladdr->taglen, &worker->stats)) {
+               repinfo, acladdr->taglist, acladdr->taglen, &worker->stats,
+               &rpz_passthru)) {
                regional_free_all(worker->scratchpad);
                if(sldns_buffer_limit(c->buffer) == 0) {
                        comm_point_drop_reply(repinfo);
@@ -1464,7 +1467,8 @@ lookup_cache:
                                        reply_and_prefetch(worker, lookup_qinfo,
                                                sldns_buffer_read_u16_at(c->buffer, 2),
                                                repinfo, leeway,
-                                               (partial_rep || need_drop));
+                                               (partial_rep || need_drop),
+                                               rpz_passthru);
                                        if(!partial_rep) {
                                                rc = 0;
                                                regional_free_all(worker->scratchpad);
@@ -1527,7 +1531,8 @@ lookup_cache:
        /* grab a work request structure for this new request */
        mesh_new_client(worker->env.mesh, &qinfo, cinfo,
                sldns_buffer_read_u16_at(c->buffer, 2),
-               &edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer));
+               &edns, repinfo, *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
+               rpz_passthru);
        regional_free_all(worker->scratchpad);
        worker_mem_report(worker, NULL);
        return 0;
index 3690dd653eb4aafa9c5dca2c16e59f998da12c54..7dea5002e7d85c3f188c4ebe6a41d4de9bec0386 100644 (file)
@@ -1,3 +1,6 @@
+15 February 2022: Wouter
+       - Fix #628: A rpz-passthru action is not ending RPZ zone processing.
+
 11 February 2022: Wouter
        - Fix #624: Unable to stop Unbound in Windows console (does not
          respond to CTRL+C command).
index ab28dd54f94258cdea8b886012b360ab3a428173..11bf5f9db555d0f9e69c4547fdd6287fcff24394 100644 (file)
@@ -650,7 +650,7 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
        }
        /* process new query */
        if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 
-               w->back->udp_buff, qid, libworker_fg_done_cb, q)) {
+               w->back->udp_buff, qid, libworker_fg_done_cb, q, 0)) {
                free(qinfo.qname);
                return UB_NOMEM;
        }
@@ -730,7 +730,7 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
        if(async_id)
                *async_id = q->querynum;
        if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 
-               w->back->udp_buff, qid, libworker_event_done_cb, q)) {
+               w->back->udp_buff, qid, libworker_event_done_cb, q, 0)) {
                free(qinfo.qname);
                return UB_NOMEM;
        }
@@ -867,7 +867,7 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
        q->w = w;
        /* process new query */
        if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 
-               w->back->udp_buff, qid, libworker_bg_done_cb, q)) {
+               w->back->udp_buff, qid, libworker_bg_done_cb, q, 0)) {
                add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0);
        }
        free(qinfo.qname);
index 3d1b3feaf460339fda5824139c8309c43cac937c..569943e9ea08cf4c7496a52013ad0250e1256cbe 100644 (file)
@@ -833,8 +833,11 @@ static int
 respip_use_rpz(struct resp_addr* raddr, struct rpz* r,
        enum respip_action* action,
        struct ub_packed_rrset_key** data, int* rpz_log, char** log_name,
-       int* rpz_cname_override, struct regional* region, int* is_rpz)
+       int* rpz_cname_override, struct regional* region, int* is_rpz,
+       int* rpz_passthru)
 {
+       if(rpz_passthru && *rpz_passthru)
+               return 0;
        if(r->action_override == RPZ_DISABLED_ACTION) {
                *is_rpz = 0;
                return 1;
@@ -848,6 +851,9 @@ respip_use_rpz(struct resp_addr* raddr, struct rpz* r,
                *data = r->cname_override;
                *rpz_cname_override = 1;
        }
+       if(*action == respip_always_transparent /* RPZ_PASSTHRU_ACTION */
+               && rpz_passthru)
+               *rpz_passthru = 1;
        *rpz_log = r->log;
        if(r->log_name)
                if(!(*log_name = regional_strdup(region, r->log_name)))
@@ -861,7 +867,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 auth_zones* az)
+       struct regional* region, struct auth_zones* az, int* rpz_passthru)
 {
        const uint8_t* ctaglist;
        size_t ctaglen;
@@ -934,7 +940,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
                        ipset->tagname, ipset->num_tags);
        }
        lock_rw_rdlock(&az->rpz_lock);
-       for(a = az->rpz_first; a && !raddr; a = a->rpz_az_next) {
+       for(a = az->rpz_first; a && !raddr && !(rpz_passthru && *rpz_passthru); a = a->rpz_az_next) {
                lock_rw_rdlock(&a->lock);
                r = a->rpz;
                if(!r->taglist || taglist_intersect(r->taglist, 
@@ -943,7 +949,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
                                r->respip_set, &rrset_id, &rr_id))) {
                                if(!respip_use_rpz(raddr, r, &action, &data,
                                        &rpz_log, &log_name, &rpz_cname_override,
-                                       region, &rpz_used)) {
+                                       region, &rpz_used, rpz_passthru)) {
                                        log_err("out of memory");
                                        lock_rw_unlock(&raddr->lock);
                                        lock_rw_unlock(&a->lock);
@@ -1094,7 +1100,8 @@ 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->env->auth_zones)) {
+                               qstate->region, qstate->env->auth_zones,
+                               &qstate->rpz_passthru)) {
                                goto servfail;
                        }
                        if(actinfo.action != respip_none) {
@@ -1169,7 +1176,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, az))
+               &alias_rrset, 1, region, az, NULL))
                return 0;
        if(actinfo.action != respip_none) {
                log_info("CNAME target of redirect response-ip action would "
index 3dfb4e9f01c755ab9f054a99ef8867eb1fa44911..988a7226339071eb91b42c1209fca1edb552051e 100644 (file)
@@ -176,6 +176,8 @@ int respip_merge_cname(struct reply_info* base_rep,
  *   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.
+ * @param rpz_passthru: keeps track of query state can have passthru that
+ *   stops further rpz processing. Or NULL for cached answer processing.
  * @return 1 on success, 0 on error.
  */
 int respip_rewrite_reply(const struct query_info* qinfo,
@@ -183,7 +185,8 @@ 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, struct auth_zones* az);
+       int search_only, struct regional* region, struct auth_zones* az,
+       int* rpz_passthru);
 
 /**
  * Get the response-ip function block.
index e83af533dbc0a007e39192f4986f4d84460acbd1..66d118b02df232e46d916af9729f67c411400549 100644 (file)
@@ -5370,7 +5370,7 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
         * called straight away */
        lock_basic_unlock(&xfr->lock);
        if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
-               &auth_xfer_transfer_lookup_callback, xfr)) {
+               &auth_xfer_transfer_lookup_callback, xfr, 0)) {
                lock_basic_lock(&xfr->lock);
                log_err("out of memory lookup up master %s", master->host);
                return 0;
@@ -6561,7 +6561,7 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
         * called straight away */
        lock_basic_unlock(&xfr->lock);
        if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
-               &auth_xfer_probe_lookup_callback, xfr)) {
+               &auth_xfer_probe_lookup_callback, xfr, 0)) {
                lock_basic_lock(&xfr->lock);
                log_err("out of memory lookup up master %s", master->host);
                return 0;
@@ -8340,7 +8340,7 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
        /* the callback can be called straight away */
        lock_rw_unlock(&z->lock);
        if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0,
-               &auth_zonemd_dnskey_lookup_callback, z)) {
+               &auth_zonemd_dnskey_lookup_callback, z, 0)) {
                lock_rw_wrlock(&z->lock);
                log_err("out of memory lookup of %s for zonemd",
                        (fetch_ds?"DS":"DNSKEY"));
index cdcfedda270cd7b9f4ef78734ed2955c52455079..4b022d47f16f6cae14f8b7ca476bda03814d2d7f 100644 (file)
@@ -458,7 +458,8 @@ mesh_serve_expired_init(struct mesh_state* mstate, int timeout)
 
 void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
        struct respip_client_info* cinfo, uint16_t qflags,
-       struct edns_data* edns, struct comm_reply* rep, uint16_t qid)
+       struct edns_data* edns, struct comm_reply* rep, uint16_t qid,
+       int rpz_passthru)
 {
        struct mesh_state* s = NULL;
        int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
@@ -513,6 +514,7 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
                }
                if(unique)
                        mesh_state_make_unique(s);
+               s->s.rpz_passthru = rpz_passthru;
                /* copy the edns options we got from the front */
                if(edns->opt_list_in) {
                        s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
@@ -606,7 +608,7 @@ servfail_mem:
 int 
 mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
        uint16_t qflags, struct edns_data* edns, sldns_buffer* buf, 
-       uint16_t qid, mesh_cb_func_type cb, void* cb_arg)
+       uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru)
 {
        struct mesh_state* s = NULL;
        int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
@@ -632,6 +634,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
                }
                if(unique)
                        mesh_state_make_unique(s);
+               s->s.rpz_passthru = rpz_passthru;
                if(edns->opt_list_in) {
                        s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
                                s->s.region);
@@ -686,7 +689,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
  * 0 (false), in which case the new state is only made runnable so it
  * will not be run recursively on top of the current state. */
 static void mesh_schedule_prefetch(struct mesh_area* mesh,
-       struct query_info* qinfo, uint16_t qflags, time_t leeway, int run)
+       struct query_info* qinfo, uint16_t qflags, time_t leeway, int run,
+       int rpz_passthru)
 {
        struct mesh_state* s = mesh_area_find(mesh, NULL, qinfo,
                qflags&(BIT_RD|BIT_CD), 0, 0);
@@ -741,6 +745,7 @@ static void mesh_schedule_prefetch(struct mesh_area* mesh,
                        s->list_select = mesh_jostle_list;
                }
        }
+       s->s.rpz_passthru = rpz_passthru;
 
        if(!run) {
 #ifdef UNBOUND_DEBUG
@@ -757,9 +762,9 @@ static void mesh_schedule_prefetch(struct mesh_area* mesh,
 }
 
 void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
-        uint16_t qflags, time_t leeway)
+        uint16_t qflags, time_t leeway, int rpz_passthru)
 {
-       mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1);
+       mesh_schedule_prefetch(mesh, qinfo, qflags, leeway, 1, rpz_passthru);
 }
 
 void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
@@ -1693,6 +1698,7 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
                if(mstate->s.curmod == 0) {
                        struct query_info* qinfo = NULL;
                        uint16_t qflags;
+                       int rpz_p = 0;
 
                        mesh_query_done(mstate);
                        mesh_walk_supers(mesh, mstate);
@@ -1701,13 +1707,15 @@ mesh_continue(struct mesh_area* mesh, struct mesh_state* mstate,
                         * from an external DNS server, we'll need to schedule
                         * a prefetch after removing the current state, so
                         * we need to make a copy of the query info here. */
-                       if(mstate->s.need_refetch)
+                       if(mstate->s.need_refetch) {
                                mesh_copy_qinfo(mstate, &qinfo, &qflags);
+                               rpz_p = mstate->s.rpz_passthru;
+                       }
 
                        mesh_state_delete(&mstate->s);
                        if(qinfo) {
                                mesh_schedule_prefetch(mesh, qinfo, qflags,
-                                       0, 1);
+                                       0, 1, rpz_p);
                        }
                        return 0;
                }
@@ -1917,7 +1925,7 @@ apply_respip_action(struct module_qstate* qstate,
                return 1;
 
        if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, actinfo,
-               alias_rrset, 0, qstate->region, az))
+               alias_rrset, 0, qstate->region, az, NULL))
                return 0;
 
        /* xxx_deny actions mean dropping the reply, unless the original reply
index d0a4b5fb3d0da6d124707cf6671a9956562a8b71..526e679fe991c64c1403e43e16213a13c712a79e 100644 (file)
@@ -296,10 +296,13 @@ void mesh_delete(struct mesh_area* mesh);
  * @param edns: edns data from client query.
  * @param rep: where to reply to.
  * @param qid: query id to reply with.
+ * @param rpz_passthru: if true, the rpz passthru was previously found and
+ *     further rpz processing is stopped.
  */
 void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
        struct respip_client_info* cinfo, uint16_t qflags,
-       struct edns_data* edns, struct comm_reply* rep, uint16_t qid);
+       struct edns_data* edns, struct comm_reply* rep, uint16_t qid,
+       int rpz_passthru);
 
 /**
  * New query with callback. Create new query state if needed, and
@@ -314,11 +317,13 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
  * @param qid: query id to reply with.
  * @param cb: callback function.
  * @param cb_arg: callback user arg.
+ * @param rpz_passthru: if true, the rpz passthru was previously found and
+ *     further rpz processing is stopped.
  * @return 0 on error.
  */
 int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
        uint16_t qflags, struct edns_data* edns, struct sldns_buffer* buf, 
-       uint16_t qid, mesh_cb_func_type cb, void* cb_arg);
+       uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru);
 
 /**
  * New prefetch message. Create new query state if needed.
@@ -328,9 +333,11 @@ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
  * @param qinfo: query from client.
  * @param qflags: flags from client query.
  * @param leeway: TTL leeway what to expire earlier for this update.
+ * @param rpz_passthru: if true, the rpz passthru was previously found and
+ *     further rpz processing is stopped.
  */
 void mesh_new_prefetch(struct mesh_area* mesh, struct query_info* qinfo,
-       uint16_t qflags, time_t leeway);
+       uint16_t qflags, time_t leeway, int rpz_passthru);
 
 /**
  * Handle new event from the wire. A serviced query has returned.
index 322e9d1393c44c07d2f47a7f5edb3a09473e7986..2d8b06922d209bd1788952909f6ffdb0c9b51a35 100644 (file)
@@ -1997,6 +1997,7 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
                break;
        case RPZ_PASSTHRU_ACTION:
                ret = NULL;
+               ms->rpz_passthru = 1;
                break;
        default:
                verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
@@ -2051,6 +2052,7 @@ rpz_apply_nsdname_trigger(struct module_qstate* ms, struct rpz* r,
                break;
        case RPZ_PASSTHRU_ACTION:
                ret = NULL;
+               ms->rpz_passthru = 1;
                break;
        default:
                verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
@@ -2114,6 +2116,11 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
        struct local_zone* z = NULL;
        struct matched_delegation_point match = {0};
 
+       if(ms->rpz_passthru) {
+               verbose(VERB_ALGO, "query is rpz_passthru, no futher processing");
+               return NULL;
+       }
+
        if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
 
        az = ms->env->auth_zones;
@@ -2179,6 +2186,11 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
        enum localzone_type lzt;
        struct dns_msg* ret = NULL;
 
+       if(ms->rpz_passthru) {
+               verbose(VERB_ALGO, "query is rpz_passthru, no futher processing");
+               return NULL;
+       }
+
        if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
        az = ms->env->auth_zones;
 
@@ -2253,6 +2265,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
                break;
        case RPZ_PASSTHRU_ACTION:
                ret = NULL;
+               ms->rpz_passthru = 1;
                break;
        default:
                verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'",
@@ -2270,7 +2283,8 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
        uint8_t* taglist, size_t taglen, struct ub_server_stats* stats,
        sldns_buffer* buf, struct regional* temp,
        /* output parameters */
-       struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out)
+       struct local_zone** z_out, struct auth_zone** a_out, struct rpz** r_out,
+       int* passthru)
 {
        int ret = 0;
        enum rpz_action client_action;
@@ -2278,7 +2292,9 @@ rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
                az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out);
 
        client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action);
-
+       if(client_action == RPZ_PASSTHRU_ACTION) {
+               *passthru = 1;
+       }
        if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION &&
                              client_action != RPZ_PASSTHRU_ACTION)) {
                if(client_action == RPZ_PASSTHRU_ACTION
@@ -2323,7 +2339,7 @@ int
 rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
        struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
        struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist,
-       size_t taglen, struct ub_server_stats* stats)
+       size_t taglen, struct ub_server_stats* stats, int* passthru)
 {
        struct rpz* r = NULL;
        struct auth_zone* a = NULL;
@@ -2332,7 +2348,8 @@ rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
        enum localzone_type lzt;
 
        int clientip_trigger = rpz_apply_maybe_clientip_trigger(az, env, qinfo,
-               edns, repinfo, taglist, taglen, stats, buf, temp, &z, &a, &r);
+               edns, repinfo, taglist, taglen, stats, buf, temp, &z, &a, &r,
+               passthru);
        if(clientip_trigger >= 0) {
                if(a) {
                        lock_rw_unlock(&a->lock);
@@ -2357,6 +2374,9 @@ rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
        } else {
                lzt = rpz_action_to_localzone_type(r->action_override);
        }
+       if(r->action_override == RPZ_PASSTHRU_ACTION) {
+               *passthru = 1;
+       }
 
        if(verbosity >= VERB_ALGO) {
                char nm[255+1], zn[255+1];
index c29d30dff506c3b8c6c24f2a0b062ca32344e87a..53781197aeec4c4b4955bd2f3cecee90cba10123 100644 (file)
@@ -176,12 +176,14 @@ void rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
  * @param taglist: taglist to lookup.
  * @param taglen: length of taglist.
  * @param stats: worker stats struct
+ * @param passthru: returns if the query can passthru further rpz processing.
  * @return: 1 if client answer is ready, 0 to continue resolving
  */
 int rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
        struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
        struct regional* temp, struct comm_reply* repinfo,
-       uint8_t* taglist, size_t taglen, struct ub_server_stats* stats);
+       uint8_t* taglist, size_t taglen, struct ub_server_stats* stats,
+       int* passthru);
 
 /**
  * Callback to process when the iterator module is about to send queries.
diff --git a/testdata/rpz_passthru.rpl b/testdata/rpz_passthru.rpl
new file mode 100644 (file)
index 0000000..cc7a6af
--- /dev/null
@@ -0,0 +1,111 @@
+; config options
+server:
+       module-config: "respip validator iterator"
+       target-fetch-policy: "0 0 0 0 0"
+       qname-minimisation: no
+       access-control: 192.0.0.0/8 allow
+
+rpz:
+       name: "rpz.example.com."
+       rpz-log: yes
+       rpz-log-name: "rpz.example.com"
+       rpz-action-override: passthru
+       zonefile:
+TEMPFILE_NAME rpz.example.com
+TEMPFILE_CONTENTS rpz.example.com
+$ORIGIN example.com.
+rpz    3600    IN      SOA     ns1.rpz.example.com. hostmaster.rpz.example.com. (
+               1379078166 28800 7200 604800 7200 )
+       3600    IN      NS      ns1.rpz.example.com.
+       3600    IN      NS      ns2.rpz.example.com.
+$ORIGIN rpz.example.com.
+c.a    TXT     "local data 1st zone"
+d.a    A 127.0.0.1
+TEMPFILE_END
+
+rpz:
+       name: "rpz2.example.com."
+       rpz-log: yes
+       rpz-log-name: "rpz2.example.com"
+       rpz-action-override: nxdomain
+       zonefile:
+TEMPFILE_NAME rpz2.example.com
+TEMPFILE_CONTENTS rpz2.example.com
+$ORIGIN example.com.
+rpz2   3600    IN      SOA     ns1.rpz.example.com. hostmaster.rpz.example.com. (
+               1379078166 28800 7200 604800 7200 )
+       3600    IN      NS      ns1.rpz.example.com.
+       3600    IN      NS      ns2.rpz.example.com.
+$ORIGIN rpz2.example.com.
+c.a    TXT     "local data 2nd zone"
+24.0.5.0.192.rpz-client-ip A 127.0.0.1
+24.0.5.0.192.rpz-client-ip TXT "clientip 2nd zone"
+24.0.3.2.1.rpz-ip A 127.0.0.2
+TEMPFILE_END
+
+stub-zone:
+       name: "a."
+       stub-addr: 10.20.30.40
+CONFIG_END
+
+SCENARIO_BEGIN Test RPZ passthru ends processing for later triggers.
+
+; a.
+RANGE_BEGIN 0 1000
+       ADDRESS 10.20.30.40
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+c.a. IN TXT
+SECTION ANSWER
+c.a. IN TXT "answer from upstream ns"
+ENTRY_END
+
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+d.a. IN A
+SECTION ANSWER
+d.a. IN A 1.2.3.4
+ENTRY_END
+RANGE_END
+
+STEP 10 QUERY ADDRESS 192.0.5.1
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+c.a.   IN      TXT
+ENTRY_END
+
+STEP 11 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+c.a.   IN      TXT
+SECTION ANSWER
+c.a. IN TXT "answer from upstream ns"
+ENTRY_END
+
+STEP 20 QUERY ADDRESS 192.0.2.1
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+d.a.   IN      A
+ENTRY_END
+
+STEP 21 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+d.a.   IN      A
+SECTION ANSWER
+d.a. IN A 1.2.3.4
+ENTRY_END
+
+SCENARIO_END
index ede6972331d0fe63ea9ae4582379d1551206dbd4..aae55b57310bd8691d79c06b95941e1814437abc 100644 (file)
@@ -6,6 +6,8 @@ server:
 
 rpz:
        name: "rpz.example.com."
+       rpz-log: yes
+       rpz-log-name: "rpz.example.com"
        zonefile:
 TEMPFILE_NAME rpz.example.com
 TEMPFILE_CONTENTS rpz.example.com
@@ -20,10 +22,13 @@ a   CNAME   *. ; duplicate CNAME here on purpose
 *.a    TXT     "wildcard local data"
 b.a    CNAME   *.
 c.a    CNAME   rpz-passthru.
+c.g    CNAME   rpz-passthru.
 TEMPFILE_END
 
 rpz:
        name: "rpz2.example.com."
+       rpz-log: yes
+       rpz-log-name: "rpz2.example.com"
        zonefile:
 TEMPFILE_NAME rpz2.example.com
 TEMPFILE_CONTENTS rpz2.example.com
@@ -39,6 +44,7 @@ e     CNAME   *.a.example.
 *.e    CNAME   *.b.example.
 drop   CNAME   rpz-drop.
 tcp    CNAME   rpz-tcp-only.
+c.g    CNAME   .
 TEMPFILE_END
 
 stub-zone:
@@ -50,6 +56,9 @@ stub-zone:
 stub-zone:
        name: "tcp."
        stub-addr: 10.20.30.60
+stub-zone:
+       name: "g."
+       stub-addr: 10.20.30.40
 CONFIG_END
 
 SCENARIO_BEGIN Test all support RPZ action for QNAME trigger
@@ -89,6 +98,16 @@ SECTION ANSWER
 x.b.a. IN TXT "answer from upstream ns"
 ENTRY_END
 
+ENTRY_BEGIN
+MATCH opcode qtype qname
+ADJUST copy_id
+REPLY QR NOERROR
+SECTION QUESTION
+c.g. IN TXT
+SECTION ANSWER
+c.g. IN TXT "answer from upstream ns"
+ENTRY_END
+
 RANGE_END
 
 ; example.
@@ -396,5 +415,23 @@ f.example. IN      CNAME   d.
 d.             IN      TXT     "local data 2nd zone"
 ENTRY_END
 
+; check if passthru ends processing
+STEP 110 QUERY
+ENTRY_BEGIN
+REPLY RD
+SECTION QUESTION
+c.g.  IN TXT
+ENTRY_END
+
+STEP 111 CHECK_ANSWER
+ENTRY_BEGIN
+MATCH all
+REPLY QR RD RA NOERROR
+SECTION QUESTION
+c.g.   IN      TXT
+SECTION ANSWER
+c.g.   IN      TXT "answer from upstream ns"
+ENTRY_END
+
 ; no answer is checked at exit of testbound.
 SCENARIO_END
index 7a548003397a9b4ed99a7a8fd8be628d0ed5cd10..1ae7477cbd77b26a33cea08465a5df87b3777663 100644 (file)
@@ -667,6 +667,8 @@ struct module_qstate {
        /** Extended result of response-ip action processing, mainly
         *  for logging purposes. */
        struct respip_action_info* respip_action_info;
+       /** if the query is rpz passthru, no further rpz processing for it */
+       int rpz_passthru;
 
        /** whether the reply should be dropped */
        int is_drop;
index 55e82c176daefb9bc1502459d732f2f81e134a03..ec656a1bd4fbd90bad74eb9baf526ceecee5696b 100644 (file)
@@ -2397,7 +2397,7 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp)
                qinfo.qclass);
 
        if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, 
-               &probe_answer_cb, env)) {
+               &probe_answer_cb, env, 0)) {
                log_err("out of memory making 5011 probe");
        }
 }