Skip to content

Commit

Permalink
- Fix #628: A rpz-passthru action is not ending RPZ zone processing.
Browse files Browse the repository at this point in the history
  • Loading branch information
wcawijngaards committed Feb 15, 2022
1 parent 91a5cc9 commit 2b90181
Show file tree
Hide file tree
Showing 14 changed files with 241 additions and 36 deletions.
17 changes: 11 additions & 6 deletions daemon/worker.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -742,7 +742,8 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
/** 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 */
Expand All @@ -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);
}

/**
Expand Down Expand Up @@ -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. */
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1464,7 +1467,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
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);
Expand Down Expand Up @@ -1527,7 +1531,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
/* 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;
Expand Down
3 changes: 3 additions & 0 deletions doc/Changelog
Original file line number Diff line number Diff line change
@@ -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).
Expand Down
6 changes: 3 additions & 3 deletions libunbound/libworker.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down
19 changes: 13 additions & 6 deletions respip/respip.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)))
Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 "
Expand Down
5 changes: 4 additions & 1 deletion respip/respip.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,14 +176,17 @@ 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,
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);
int search_only, struct regional* region, struct auth_zones* az,
int* rpz_passthru);

/**
* Get the response-ip function block.
Expand Down
6 changes: 3 additions & 3 deletions services/authzone.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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"));
Expand Down
24 changes: 16 additions & 8 deletions services/mesh.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -606,7 +608,7 @@ void mesh_new_client(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, 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);
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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;
}
Expand Down Expand Up @@ -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
Expand Down
13 changes: 10 additions & 3 deletions services/mesh.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand All @@ -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.
Expand Down
Loading

0 comments on commit 2b90181

Please sign in to comment.