- Fix #628: A rpz-passthru action is not ending RPZ zone processing.

This commit is contained in:
W.C.A. Wijngaards 2022-02-15 16:20:12 +01:00
parent 91a5cc9a08
commit 2b90181d3a
14 changed files with 241 additions and 36 deletions

View File

@ -553,7 +553,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
return 1; return 1;
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo, 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; return 0;
/* xxx_deny actions mean dropping the reply, unless the original reply /* 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. */ /** Reply to client and perform prefetch to keep cache up to date. */
static void static void
reply_and_prefetch(struct worker* worker, struct query_info* qinfo, 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 /* first send answer to client to keep its latency
* as small as a cachereply */ * 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). */ * the cache and go to the network for the data). */
/* this (potentially) runs the mesh for the new query */ /* this (potentially) runs the mesh for the new query */
mesh_new_prefetch(worker->env.mesh, qinfo, flags, leeway + 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 need_drop = 0;
int is_expired_answer = 0; int is_expired_answer = 0;
int is_secure_answer = 0; int is_secure_answer = 0;
int rpz_passthru = 0;
/* We might have to chase a CNAME chain internally, in which case /* 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 * we'll have up to two replies and combine them to build a complete
* answer. These variables control this case. */ * 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 && if(worker->env.auth_zones &&
rpz_callback_from_worker_request(worker->env.auth_zones, rpz_callback_from_worker_request(worker->env.auth_zones,
&worker->env, &qinfo, &edns, c->buffer, worker->scratchpad, &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); regional_free_all(worker->scratchpad);
if(sldns_buffer_limit(c->buffer) == 0) { if(sldns_buffer_limit(c->buffer) == 0) {
comm_point_drop_reply(repinfo); comm_point_drop_reply(repinfo);
@ -1464,7 +1467,8 @@ lookup_cache:
reply_and_prefetch(worker, lookup_qinfo, reply_and_prefetch(worker, lookup_qinfo,
sldns_buffer_read_u16_at(c->buffer, 2), sldns_buffer_read_u16_at(c->buffer, 2),
repinfo, leeway, repinfo, leeway,
(partial_rep || need_drop)); (partial_rep || need_drop),
rpz_passthru);
if(!partial_rep) { if(!partial_rep) {
rc = 0; rc = 0;
regional_free_all(worker->scratchpad); regional_free_all(worker->scratchpad);
@ -1527,7 +1531,8 @@ lookup_cache:
/* grab a work request structure for this new request */ /* grab a work request structure for this new request */
mesh_new_client(worker->env.mesh, &qinfo, cinfo, mesh_new_client(worker->env.mesh, &qinfo, cinfo,
sldns_buffer_read_u16_at(c->buffer, 2), 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); regional_free_all(worker->scratchpad);
worker_mem_report(worker, NULL); worker_mem_report(worker, NULL);
return 0; return 0;

View 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 11 February 2022: Wouter
- Fix #624: Unable to stop Unbound in Windows console (does not - Fix #624: Unable to stop Unbound in Windows console (does not
respond to CTRL+C command). respond to CTRL+C command).

View File

@ -650,7 +650,7 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
} }
/* process new query */ /* process new query */
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 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); free(qinfo.qname);
return UB_NOMEM; return UB_NOMEM;
} }
@ -730,7 +730,7 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
if(async_id) if(async_id)
*async_id = q->querynum; *async_id = q->querynum;
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 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); free(qinfo.qname);
return UB_NOMEM; return UB_NOMEM;
} }
@ -867,7 +867,7 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
q->w = w; q->w = w;
/* process new query */ /* process new query */
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns, 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); add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0);
} }
free(qinfo.qname); free(qinfo.qname);

View File

@ -833,8 +833,11 @@ static int
respip_use_rpz(struct resp_addr* raddr, struct rpz* r, respip_use_rpz(struct resp_addr* raddr, struct rpz* r,
enum respip_action* action, enum respip_action* action,
struct ub_packed_rrset_key** data, int* rpz_log, char** log_name, 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) { if(r->action_override == RPZ_DISABLED_ACTION) {
*is_rpz = 0; *is_rpz = 0;
return 1; return 1;
@ -848,6 +851,9 @@ respip_use_rpz(struct resp_addr* raddr, struct rpz* r,
*data = r->cname_override; *data = r->cname_override;
*rpz_cname_override = 1; *rpz_cname_override = 1;
} }
if(*action == respip_always_transparent /* RPZ_PASSTHRU_ACTION */
&& rpz_passthru)
*rpz_passthru = 1;
*rpz_log = r->log; *rpz_log = r->log;
if(r->log_name) if(r->log_name)
if(!(*log_name = regional_strdup(region, 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, const struct respip_client_info* cinfo, const struct reply_info* rep,
struct reply_info** new_repp, struct respip_action_info* actinfo, struct reply_info** new_repp, struct respip_action_info* actinfo,
struct ub_packed_rrset_key** alias_rrset, int search_only, 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; const uint8_t* ctaglist;
size_t ctaglen; size_t ctaglen;
@ -934,7 +940,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
ipset->tagname, ipset->num_tags); ipset->tagname, ipset->num_tags);
} }
lock_rw_rdlock(&az->rpz_lock); 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); lock_rw_rdlock(&a->lock);
r = a->rpz; r = a->rpz;
if(!r->taglist || taglist_intersect(r->taglist, 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))) { r->respip_set, &rrset_id, &rr_id))) {
if(!respip_use_rpz(raddr, r, &action, &data, if(!respip_use_rpz(raddr, r, &action, &data,
&rpz_log, &log_name, &rpz_cname_override, &rpz_log, &log_name, &rpz_cname_override,
region, &rpz_used)) { region, &rpz_used, rpz_passthru)) {
log_err("out of memory"); log_err("out of memory");
lock_rw_unlock(&raddr->lock); lock_rw_unlock(&raddr->lock);
lock_rw_unlock(&a->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, if(!respip_rewrite_reply(&qstate->qinfo,
qstate->client_info, qstate->return_msg->rep, qstate->client_info, qstate->return_msg->rep,
&new_rep, &actinfo, &alias_rrset, 0, &new_rep, &actinfo, &alias_rrset, 0,
qstate->region, qstate->env->auth_zones)) { qstate->region, qstate->env->auth_zones,
&qstate->rpz_passthru)) {
goto servfail; goto servfail;
} }
if(actinfo.action != respip_none) { 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. */ /* see if the target reply would be subject to a response-ip action. */
if(!respip_rewrite_reply(qinfo, cinfo, tgt_rep, &tmp_rep, &actinfo, if(!respip_rewrite_reply(qinfo, cinfo, tgt_rep, &tmp_rep, &actinfo,
&alias_rrset, 1, region, az)) &alias_rrset, 1, region, az, NULL))
return 0; return 0;
if(actinfo.action != respip_none) { if(actinfo.action != respip_none) {
log_info("CNAME target of redirect response-ip action would " log_info("CNAME target of redirect response-ip action would "

View 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. * will be set (or intact) accordingly but the modified reply won't be built.
* @param az: auth zones containing RPZ information. * @param az: auth zones containing RPZ information.
* @param region: allocator to build *new_repp. * @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. * @return 1 on success, 0 on error.
*/ */
int respip_rewrite_reply(const struct query_info* qinfo, 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, const struct reply_info *rep, struct reply_info** new_repp,
struct respip_action_info* actinfo, struct respip_action_info* actinfo,
struct ub_packed_rrset_key** alias_rrset, 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. * Get the response-ip function block.

View File

@ -5370,7 +5370,7 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
* called straight away */ * called straight away */
lock_basic_unlock(&xfr->lock); lock_basic_unlock(&xfr->lock);
if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, 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); lock_basic_lock(&xfr->lock);
log_err("out of memory lookup up master %s", master->host); log_err("out of memory lookup up master %s", master->host);
return 0; return 0;
@ -6561,7 +6561,7 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
* called straight away */ * called straight away */
lock_basic_unlock(&xfr->lock); lock_basic_unlock(&xfr->lock);
if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, 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); lock_basic_lock(&xfr->lock);
log_err("out of memory lookup up master %s", master->host); log_err("out of memory lookup up master %s", master->host);
return 0; return 0;
@ -8340,7 +8340,7 @@ zonemd_lookup_dnskey(struct auth_zone* z, struct module_env* env)
/* the callback can be called straight away */ /* the callback can be called straight away */
lock_rw_unlock(&z->lock); lock_rw_unlock(&z->lock);
if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, 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); lock_rw_wrlock(&z->lock);
log_err("out of memory lookup of %s for zonemd", log_err("out of memory lookup of %s for zonemd",
(fetch_ds?"DS":"DNSKEY")); (fetch_ds?"DS":"DNSKEY"));

View 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, void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
struct respip_client_info* cinfo, uint16_t qflags, 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; struct mesh_state* s = NULL;
int unique = unique_mesh_state(edns->opt_list_in, mesh->env); 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) if(unique)
mesh_state_make_unique(s); mesh_state_make_unique(s);
s->s.rpz_passthru = rpz_passthru;
/* copy the edns options we got from the front */ /* copy the edns options we got from the front */
if(edns->opt_list_in) { if(edns->opt_list_in) {
s->s.edns_opts_front_in = edns_opt_copy_region(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 int
mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, struct edns_data* edns, sldns_buffer* buf, 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; struct mesh_state* s = NULL;
int unique = unique_mesh_state(edns->opt_list_in, mesh->env); 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) if(unique)
mesh_state_make_unique(s); mesh_state_make_unique(s);
s->s.rpz_passthru = rpz_passthru;
if(edns->opt_list_in) { if(edns->opt_list_in) {
s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in, s->s.edns_opts_front_in = edns_opt_copy_region(edns->opt_list_in,
s->s.region); 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 * 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. */ * will not be run recursively on top of the current state. */
static void mesh_schedule_prefetch(struct mesh_area* mesh, 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, struct mesh_state* s = mesh_area_find(mesh, NULL, qinfo,
qflags&(BIT_RD|BIT_CD), 0, 0); 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->list_select = mesh_jostle_list;
} }
} }
s->s.rpz_passthru = rpz_passthru;
if(!run) { if(!run) {
#ifdef UNBOUND_DEBUG #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, 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, 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) { if(mstate->s.curmod == 0) {
struct query_info* qinfo = NULL; struct query_info* qinfo = NULL;
uint16_t qflags; uint16_t qflags;
int rpz_p = 0;
mesh_query_done(mstate); mesh_query_done(mstate);
mesh_walk_supers(mesh, 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 * from an external DNS server, we'll need to schedule
* a prefetch after removing the current state, so * a prefetch after removing the current state, so
* we need to make a copy of the query info here. */ * 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); mesh_copy_qinfo(mstate, &qinfo, &qflags);
rpz_p = mstate->s.rpz_passthru;
}
mesh_state_delete(&mstate->s); mesh_state_delete(&mstate->s);
if(qinfo) { if(qinfo) {
mesh_schedule_prefetch(mesh, qinfo, qflags, mesh_schedule_prefetch(mesh, qinfo, qflags,
0, 1); 0, 1, rpz_p);
} }
return 0; return 0;
} }
@ -1917,7 +1925,7 @@ apply_respip_action(struct module_qstate* qstate,
return 1; return 1;
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, actinfo, 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; return 0;
/* xxx_deny actions mean dropping the reply, unless the original reply /* xxx_deny actions mean dropping the reply, unless the original reply

View File

@ -296,10 +296,13 @@ void mesh_delete(struct mesh_area* mesh);
* @param edns: edns data from client query. * @param edns: edns data from client query.
* @param rep: where to reply to. * @param rep: where to reply to.
* @param qid: query id to reply with. * @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, void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
struct respip_client_info* cinfo, uint16_t qflags, 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 * 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 qid: query id to reply with.
* @param cb: callback function. * @param cb: callback function.
* @param cb_arg: callback user arg. * @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. * @return 0 on error.
*/ */
int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo, 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 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. * 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 qinfo: query from client.
* @param qflags: flags from client query. * @param qflags: flags from client query.
* @param leeway: TTL leeway what to expire earlier for this update. * @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, 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. * Handle new event from the wire. A serviced query has returned.

View File

@ -1997,6 +1997,7 @@ rpz_apply_nsip_trigger(struct module_qstate* ms, struct rpz* r,
break; break;
case RPZ_PASSTHRU_ACTION: case RPZ_PASSTHRU_ACTION:
ret = NULL; ret = NULL;
ms->rpz_passthru = 1;
break; break;
default: default:
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'", 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; break;
case RPZ_PASSTHRU_ACTION: case RPZ_PASSTHRU_ACTION:
ret = NULL; ret = NULL;
ms->rpz_passthru = 1;
break; break;
default: default:
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'", 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 local_zone* z = NULL;
struct matched_delegation_point match = {0}; 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; } if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
az = ms->env->auth_zones; 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; enum localzone_type lzt;
struct dns_msg* ret = NULL; 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; } if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
az = ms->env->auth_zones; az = ms->env->auth_zones;
@ -2253,6 +2265,7 @@ struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
break; break;
case RPZ_PASSTHRU_ACTION: case RPZ_PASSTHRU_ACTION:
ret = NULL; ret = NULL;
ms->rpz_passthru = 1;
break; break;
default: default:
verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'", 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, uint8_t* taglist, size_t taglen, struct ub_server_stats* stats,
sldns_buffer* buf, struct regional* temp, sldns_buffer* buf, struct regional* temp,
/* output parameters */ /* 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; int ret = 0;
enum rpz_action client_action; 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); az, qinfo, repinfo, taglist, taglen, stats, z_out, a_out, r_out);
client_action = ((node == NULL) ? RPZ_INVALID_ACTION : node->action); 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 && if(*z_out == NULL || (client_action != RPZ_INVALID_ACTION &&
client_action != RPZ_PASSTHRU_ACTION)) { client_action != RPZ_PASSTHRU_ACTION)) {
if(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, 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 query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
struct regional* temp, struct comm_reply* repinfo, uint8_t* taglist, 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 rpz* r = NULL;
struct auth_zone* a = 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; enum localzone_type lzt;
int clientip_trigger = rpz_apply_maybe_clientip_trigger(az, env, qinfo, 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(clientip_trigger >= 0) {
if(a) { if(a) {
lock_rw_unlock(&a->lock); lock_rw_unlock(&a->lock);
@ -2357,6 +2374,9 @@ rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
} else { } else {
lzt = rpz_action_to_localzone_type(r->action_override); lzt = rpz_action_to_localzone_type(r->action_override);
} }
if(r->action_override == RPZ_PASSTHRU_ACTION) {
*passthru = 1;
}
if(verbosity >= VERB_ALGO) { if(verbosity >= VERB_ALGO) {
char nm[255+1], zn[255+1]; char nm[255+1], zn[255+1];

View File

@ -176,12 +176,14 @@ void rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
* @param taglist: taglist to lookup. * @param taglist: taglist to lookup.
* @param taglen: length of taglist. * @param taglen: length of taglist.
* @param stats: worker stats struct * @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 * @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, 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 query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
struct regional* temp, struct comm_reply* repinfo, 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. * Callback to process when the iterator module is about to send queries.

111
testdata/rpz_passthru.rpl vendored Normal file
View File

@ -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

View File

@ -6,6 +6,8 @@ server:
rpz: rpz:
name: "rpz.example.com." name: "rpz.example.com."
rpz-log: yes
rpz-log-name: "rpz.example.com"
zonefile: zonefile:
TEMPFILE_NAME rpz.example.com TEMPFILE_NAME rpz.example.com
TEMPFILE_CONTENTS rpz.example.com TEMPFILE_CONTENTS rpz.example.com
@ -20,10 +22,13 @@ a CNAME *. ; duplicate CNAME here on purpose
*.a TXT "wildcard local data" *.a TXT "wildcard local data"
b.a CNAME *. b.a CNAME *.
c.a CNAME rpz-passthru. c.a CNAME rpz-passthru.
c.g CNAME rpz-passthru.
TEMPFILE_END TEMPFILE_END
rpz: rpz:
name: "rpz2.example.com." name: "rpz2.example.com."
rpz-log: yes
rpz-log-name: "rpz2.example.com"
zonefile: zonefile:
TEMPFILE_NAME rpz2.example.com TEMPFILE_NAME rpz2.example.com
TEMPFILE_CONTENTS rpz2.example.com TEMPFILE_CONTENTS rpz2.example.com
@ -39,6 +44,7 @@ e CNAME *.a.example.
*.e CNAME *.b.example. *.e CNAME *.b.example.
drop CNAME rpz-drop. drop CNAME rpz-drop.
tcp CNAME rpz-tcp-only. tcp CNAME rpz-tcp-only.
c.g CNAME .
TEMPFILE_END TEMPFILE_END
stub-zone: stub-zone:
@ -50,6 +56,9 @@ stub-zone:
stub-zone: stub-zone:
name: "tcp." name: "tcp."
stub-addr: 10.20.30.60 stub-addr: 10.20.30.60
stub-zone:
name: "g."
stub-addr: 10.20.30.40
CONFIG_END CONFIG_END
SCENARIO_BEGIN Test all support RPZ action for QNAME trigger 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" x.b.a. IN TXT "answer from upstream ns"
ENTRY_END 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 RANGE_END
; example. ; example.
@ -396,5 +415,23 @@ f.example. IN CNAME d.
d. IN TXT "local data 2nd zone" d. IN TXT "local data 2nd zone"
ENTRY_END 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. ; no answer is checked at exit of testbound.
SCENARIO_END SCENARIO_END

View File

@ -667,6 +667,8 @@ struct module_qstate {
/** Extended result of response-ip action processing, mainly /** Extended result of response-ip action processing, mainly
* for logging purposes. */ * for logging purposes. */
struct respip_action_info* respip_action_info; 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 */ /** whether the reply should be dropped */
int is_drop; int is_drop;

View File

@ -2397,7 +2397,7 @@ probe_anchor(struct module_env* env, struct trust_anchor* tp)
qinfo.qclass); qinfo.qclass);
if(!mesh_new_callback(env->mesh, &qinfo, qflags, &edns, buf, 0, 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"); log_err("out of memory making 5011 probe");
} }
} }