From: mb Date: Tue, 24 Nov 2020 10:25:01 +0000 (+0100) Subject: rpz: forge responses X-Git-Tag: release-1.14.0rc1~62^2~53^2^2~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=126e114d6f5f3ce1668f1c70845b8169dc1c2db3;p=thirdparty%2Funbound.git rpz: forge responses --- diff --git a/iterator/iterator.c b/iterator/iterator.c index f2585be31..609786a16 100644 --- a/iterator/iterator.c +++ b/iterator/iterator.c @@ -2471,7 +2471,14 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq, /* Add the current set of unused targets to our queue. */ delegpt_add_unused_targets(iq->dp); - rpz_iterator_module_callback(qstate, iq); + { /* apply rpz triggers at query time */ + struct dns_msg* forged_response = rpz_iterator_module_callback(qstate, iq); + if(forged_response != NULL) { + iq->response = forged_response; + next_state(iq, FINISHED_STATE); + return 0; + } + } /* Select the next usable target, filtering out unsuitable targets. */ target = iter_server_selection(ie, qstate->env, iq->dp, @@ -2662,16 +2669,12 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq, { int dnsseclame = 0; enum response_type type; - //int rpz_filter_result; iq->num_current_queries--; if(!inplace_cb_query_response_call(qstate->env, qstate, iq->response)) log_err("unable to call query_response callback"); - //rpz_filter_result = rpz_iterator_module_callback(qstate, iq); - //if(rpz_filter_result > 0) { next_state(iq, FINISHED_STATE); } - if(iq->response == NULL) { /* Don't increment qname when QNAME minimisation is enabled */ if(qstate->env->cfg->qname_minimisation) { diff --git a/services/rpz.c b/services/rpz.c index 5b5c10eb8..acf2b8848 100644 --- a/services/rpz.c +++ b/services/rpz.c @@ -1421,73 +1421,101 @@ nodata: rpz_local_encode(qinfo, env, edns, repinfo, buf, temp, rp, rrset_count, rcode); } -static inline void -rpz_patch_nodata(struct reply_info* ri) +static inline struct dns_msg* +rpz_dns_msg_new(struct regional* region) { - FLAGS_SET_RCODE(ri->flags, LDNS_RCODE_NOERROR); - ri->flags |= BIT_QR | BIT_AA | BIT_RA; - ri->an_numrrsets = 0; - ri->ns_numrrsets = 0; - ri->ar_numrrsets = 0; - ri->authoritative = 0; - ri->rrset_count = 1; - ri->qdcount = 1; + struct dns_msg* msg = + (struct dns_msg*)regional_alloc(region, + sizeof(struct dns_msg)); + if(msg == NULL) { return NULL; } + memset(msg, 0, sizeof(struct dns_msg)); + + return msg; } -static inline void -rpz_patch_nxdomain(struct reply_info* ri) +static inline struct dns_msg* +rpz_patch_nodata(struct rpz* r, struct module_qstate* ms) { - FLAGS_SET_RCODE(ri->flags, LDNS_RCODE_NXDOMAIN); - ri->flags |= BIT_QR | BIT_AA | BIT_RA; - ri->an_numrrsets = 0; - ri->ns_numrrsets = 0; - ri->ar_numrrsets = 0; - ri->authoritative = 0; - ri->rrset_count = 1; - ri->qdcount = 1; + struct dns_msg* msg = rpz_dns_msg_new(ms->region); + if(msg == NULL) { return msg; } + msg->qinfo = ms->qinfo; + msg->rep = construct_reply_info_base(ms->region, + LDNS_RCODE_NOERROR|BIT_QR|BIT_AA|BIT_RA, + 1, //qd + 0, //ttl + 0, //prettl + 0, //expttl + 0, //an + 0, //ns + 0, //ar + 1, //total + sec_status_secure); + return msg; } -static inline int -rpz_patch_localdata(struct dns_msg* response, struct clientip_synthesized_rr* data, - struct regional* region) +static inline struct dns_msg* +rpz_patch_nxdomain(struct rpz* r, struct module_qstate* ms) +{ + struct dns_msg* msg = rpz_dns_msg_new(ms->region); + if(msg == NULL) { return msg; } + msg->qinfo = ms->qinfo; + msg->rep = construct_reply_info_base(ms->region, + LDNS_RCODE_NXDOMAIN|BIT_QR|BIT_AA|BIT_RA, + 1, //qd + 0, //ttl + 0, //prettl + 0, //expttl + 0, //an + 0, //ns + 0, //ar + 1, //total + sec_status_secure); + return msg; +} + +static inline struct dns_msg* +rpz_patch_localdata(struct rpz* r, + struct module_qstate* ms, + struct clientip_synthesized_rr* data) { - struct query_info* qi = &response->qinfo; + struct dns_msg* msg = NULL; + struct query_info* qi = &msg->qinfo; struct ub_packed_rrset_key* rp; struct local_rrset* rrset; struct reply_info* new_reply_info; - struct reply_info* ri = response->rep; + struct reply_info* ri = msg->rep; rrset = rpz_find_synthesized_rrset(qi->qtype, data); if(rrset == NULL) { verbose(VERB_ALGO, "rpz: nsip: no matching synthesized data found; resorting to nodata"); - rpz_patch_nodata(ri); - return 1; + return rpz_patch_nodata(r, ms); } - new_reply_info = make_new_reply_info(ri, region, 0, 0); + msg = rpz_dns_msg_new(ms->region); + if(msg == NULL) { return NULL; } + + // XXX: use ttl etc from rpz zone? + new_reply_info = make_new_reply_info(ri, ms->region, 0, 0); if(new_reply_info == NULL) { log_err("out of memory"); - rpz_patch_nodata(ri); - return 1; + return NULL; } - rp = respip_copy_rrset(rrset->rrset, region); + rp = respip_copy_rrset(rrset->rrset, ms->region); if(rp == NULL) { log_err("out of memory"); - rpz_patch_nodata(ri); - return 1; + return NULL; } - new_reply_info->rrsets = regional_alloc(region, sizeof(*new_reply_info->rrsets)); + new_reply_info->rrsets = regional_alloc(ms->region, sizeof(*new_reply_info->rrsets)); if(new_reply_info->rrsets == NULL) { log_err("out of memory"); - rpz_patch_nodata(ri); - return 1; + return NULL; } rp->rk.dname = qi->qname; rp->rk.dname_len = qi->qname_len; new_reply_info->rrset_count = 1; new_reply_info->an_numrrsets = 1; new_reply_info->rrsets[0] = rp; - response->rep = new_reply_info; - return 1; + msg->rep = new_reply_info; + return msg; } struct clientip_synthesized_rr* @@ -1505,7 +1533,7 @@ rpz_delegation_point_ipbased_trigger_lookup(struct rpz* rpz, return NULL; } -int +struct dns_msg* rpz_iterator_module_callback(struct module_qstate* ms, struct iter_qstate* is) { struct auth_zones* az; @@ -1513,7 +1541,7 @@ rpz_iterator_module_callback(struct module_qstate* ms, struct iter_qstate* is) struct clientip_synthesized_rr* raddr; enum rpz_action action = RPZ_INVALID_ACTION; struct rpz* r; - int ret = 0; + struct dns_msg* ret = NULL; if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; } @@ -1537,7 +1565,7 @@ rpz_iterator_module_callback(struct module_qstate* ms, struct iter_qstate* is) lock_rw_unlock(&az->rpz_lock); - if(raddr == NULL) { return 0; } + if(raddr == NULL) { return NULL; } verbose(VERB_ALGO, "rpz: iterator callback: nsip: apply action=%s", rpz_action_to_string(raddr->action)); @@ -1545,33 +1573,31 @@ rpz_iterator_module_callback(struct module_qstate* ms, struct iter_qstate* is) action = raddr->action; if(action == RPZ_LOCAL_DATA_ACTION && raddr->data == NULL) { verbose(VERB_ALGO, "rpz: bug: local-data action but no local data"); - ret = -1; + ret = rpz_patch_nodata(r, ms); goto done; } switch(action) { case RPZ_NXDOMAIN_ACTION: - rpz_patch_nxdomain(is->response->rep); - ret = 1; + ret = rpz_patch_nxdomain(r, ms); break; case RPZ_NODATA_ACTION: - rpz_patch_nodata(is->response->rep); - ret = 1; + ret = rpz_patch_nodata(r, ms); break; case RPZ_TCP_ONLY_ACTION: - log_err("rpz: nsip: tcp-only trigger unimplemented; resorting to passthru"); - ret = 0; + verbose(VERB_ALGO, "rpz: nsip: tcp-only trigger ignored"); + ret = NULL; break; case RPZ_PASSTHRU_ACTION: - ret = 0; + ret = NULL; break; case RPZ_LOCAL_DATA_ACTION: - ret = rpz_patch_localdata(is->response, raddr, ms->region); + ret = rpz_patch_localdata(r, ms, raddr); break; default: verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'", rpz_action_to_string(action)); - ret = 0; + ret = NULL; } done: diff --git a/services/rpz.h b/services/rpz.h index 71badbb74..7a2e9500e 100644 --- a/services/rpz.h +++ b/services/rpz.h @@ -179,7 +179,7 @@ int rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env, uint8_t* taglist, size_t taglen, struct ub_server_stats* stats); struct iter_qstate; -int rpz_iterator_module_callback(struct module_qstate*, struct iter_qstate*); +struct dns_msg* rpz_iterator_module_callback(struct module_qstate*, struct iter_qstate*); /** * Delete RPZ