/* set the current request's qname to the new value. */
iq->qchase.qname = sname;
iq->qchase.qname_len = snamelen;
+ if(qstate->env->auth_zones) {
+ /* apply rpz qname triggers after cname */
+ struct dns_msg* forged_response =
+ rpz_callback_from_iterator_cname(qstate, iq);
+ while(forged_response && reply_find_rrset_section_an(
+ forged_response->rep, iq->qchase.qname,
+ iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
+ iq->qchase.qclass)) {
+ /* another cname to follow */
+ if(!handle_cname_response(qstate, iq, forged_response,
+ &sname, &snamelen)) {
+ errinf(qstate, "malloc failure, CNAME info");
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
+ iq->qchase.qname = sname;
+ iq->qchase.qname_len = snamelen;
+ forged_response =
+ rpz_callback_from_iterator_cname(qstate, iq);
+ }
+ if(forged_response != NULL) {
+ qstate->ext_state[id] = module_finished;
+ qstate->return_rcode = FLAGS_GET_RCODE(forged_response->rep->flags);
+ qstate->return_msg = forged_response;
+ next_state(iq, FINISHED_STATE);
+ if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
+ log_err("rpz, prepend rrsets: out of memory");
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
+ qstate->return_msg->qinfo = qstate->qinfo;
+ return 0;
+ }
+ }
/* Clear the query state, since this is a query restart. */
iq->deleg_msg = NULL;
iq->dp = NULL;
static inline struct dns_msg*
rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms,
- struct local_rrset* rrset)
+ struct query_info* qi, struct local_rrset* rrset)
{
struct dns_msg* msg = NULL;
- struct query_info* qi = &ms->qinfo;
struct reply_info* new_reply_info;
struct ub_packed_rrset_key* rp;
return NULL;
}
- return rpz_synthesize_localdata_from_rrset(r, ms, rrset);
+ return rpz_synthesize_localdata_from_rrset(r, ms, &ms->qinfo, rrset);
}
// copy'n'paste from localzone.c
return NULL;
}
- return rpz_synthesize_localdata_from_rrset(r, ms, rrset);
+ return rpz_synthesize_localdata_from_rrset(r, ms, &ms->qinfo, rrset);
+}
+
+/* like local_data_answer for qname triggers after a cname */
+static struct dns_msg*
+rpz_synthesize_qname_localdata_msg(struct rpz* r, struct module_qstate* ms,
+ struct query_info* qinfo, struct local_zone* z)
+{
+ struct local_data key;
+ struct local_data* ld;
+ struct local_rrset* rrset;
+ key.node.key = &key;
+ key.name = qinfo->qname;
+ key.namelen = qinfo->qname_len;
+ key.namelabs = dname_count_labels(qinfo->qname);
+ ld = (struct local_data*)rbtree_search(&z->data, &key.node);
+ if(ld == NULL) {
+ verbose(VERB_ALGO, "rpz: qname after cname: name not found");
+ return NULL;
+ }
+ rrset = local_data_find_type(ld, qinfo->qtype, 1);
+ if(rrset == NULL) {
+ verbose(VERB_ALGO, "rpz: qname after cname: type not found");
+ return NULL;
+ }
+ return rpz_synthesize_localdata_from_rrset(r, ms, qinfo, rrset);
}
static int
else { return NULL; }
}
+struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
+ struct iter_qstate* is)
+{
+ struct auth_zones* az;
+ struct auth_zone* a = NULL;
+ struct rpz* r = NULL;
+ struct local_zone* z = NULL;
+ enum localzone_type lzt;
+ struct dns_msg* ret = NULL;
+
+ if(ms->env == NULL || ms->env->auth_zones == NULL) { return 0; }
+ az = ms->env->auth_zones;
+
+ lock_rw_rdlock(&az->rpz_lock);
+
+ for(a = az->rpz_first; a; a = a->rpz_az_next) {
+ lock_rw_rdlock(&a->lock);
+ r = a->rpz;
+ if(r->disabled) {
+ lock_rw_unlock(&a->lock);
+ continue;
+ }
+ z = rpz_find_zone(r->local_zones, is->qchase.qname,
+ is->qchase.qname_len, is->qchase.qclass, 0, 0, 0);
+ if(z && r->action_override == RPZ_DISABLED_ACTION) {
+ lock_rw_unlock(&z->lock);
+ z = NULL;
+ }
+ if(z) {
+ break;
+ }
+ /* not found in this auth_zone */
+ lock_rw_unlock(&a->lock);
+ }
+ lock_rw_unlock(&az->rpz_lock);
+
+ if(z == NULL)
+ return NULL;
+ if(r->action_override == RPZ_NO_OVERRIDE_ACTION) {
+ lzt = z->type;
+ } else {
+ lzt = rpz_action_to_localzone_type(r->action_override);
+ }
+
+ verbose(VERB_ALGO, "rpz: qname trigger after cname, with action=%s",
+ rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
+ switch(localzone_type_to_rpz_action(lzt)) {
+ case RPZ_NXDOMAIN_ACTION:
+ ret = rpz_synthesize_nxdomain(r, ms);
+ break;
+ case RPZ_NODATA_ACTION:
+ ret = rpz_synthesize_nodata(r, ms);
+ break;
+ case RPZ_TCP_ONLY_ACTION:
+ /* basically a passthru here but the tcp-only will be
+ * honored before the query gets sent. */
+ ms->respip_action_info->action = respip_truncate;
+ ret = NULL;
+ break;
+ case RPZ_DROP_ACTION:
+ ret = rpz_synthesize_nodata(r, ms);
+ ms->is_drop = 1;
+ break;
+ case RPZ_LOCAL_DATA_ACTION:
+ ret = rpz_synthesize_qname_localdata_msg(r, ms, &is->qchase, z);
+ if(ret == NULL) { ret = rpz_synthesize_nodata(r, ms); }
+ break;
+ case RPZ_PASSTHRU_ACTION:
+ ret = NULL;
+ break;
+ default:
+ verbose(VERB_ALGO, "rpz: qname trigger after cname: bug: unhandled or invalid action: '%s'",
+ rpz_action_to_string(localzone_type_to_rpz_action(lzt)));
+ ret = NULL;
+ }
+ lock_rw_unlock(&z->lock);
+ lock_rw_unlock(&a->lock);
+ return ret;
+}
+
static int
rpz_apply_maybe_clientip_trigger(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, struct comm_reply* repinfo,