]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
rpz: forge responses
authormb <mb@64k.by>
Tue, 24 Nov 2020 10:25:01 +0000 (11:25 +0100)
committermb <mb@64k.by>
Tue, 24 Nov 2020 10:25:01 +0000 (11:25 +0100)
iterator/iterator.c
services/rpz.c
services/rpz.h

index f2585be319a34a1a11b8196467562efa1090888a..609786a1668236e3d062c396f8193e0fb0bbacd8 100644 (file)
@@ -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) {
index 5b5c10eb8b97597aca56d4dfd92511a615aea20c..acf2b8848e3fcf3f8ae6657ff4e4ba3254ff5a40 100644 (file)
@@ -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:
index 71badbb7429a455d0885aaf18b90be629dd5051d..7a2e9500e8f5ff3b48d3760d9a0331d0eec32481 100644 (file)
@@ -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