mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 14:47:09 +00:00
- rpz triggers, implement qname trigger after cname.
This commit is contained in:
parent
1a528238e2
commit
7f39003c04
@ -3013,6 +3013,38 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* 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;
|
||||
|
112
services/rpz.c
112
services/rpz.c
@ -1607,10 +1607,9 @@ rpz_synthesize_nxdomain(struct rpz* ATTR_UNUSED(r), struct module_qstate* ms)
|
||||
|
||||
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;
|
||||
|
||||
@ -1659,7 +1658,7 @@ rpz_synthesize_nsip_localdata(struct rpz* r, struct module_qstate* ms,
|
||||
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
|
||||
@ -1708,7 +1707,32 @@ rpz_synthesize_nsdname_localdata(struct rpz* r, struct module_qstate* ms,
|
||||
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
|
||||
@ -1965,6 +1989,86 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
|
||||
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,
|
||||
|
@ -183,6 +183,8 @@ int rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* e
|
||||
struct iter_qstate;
|
||||
struct dns_msg* rpz_callback_from_iterator_module(struct module_qstate*, struct iter_qstate*);
|
||||
|
||||
struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate*, struct iter_qstate*);
|
||||
|
||||
/**
|
||||
* Delete RPZ
|
||||
* @param r: RPZ struct to delete
|
||||
|
29
testdata/rpz_qname.rpl
vendored
29
testdata/rpz_qname.rpl
vendored
@ -126,6 +126,16 @@ SECTION ANSWER
|
||||
something.e.b.example. IN TXT "*.b.example. answer from upstream ns"
|
||||
ENTRY_END
|
||||
|
||||
ENTRY_BEGIN
|
||||
MATCH opcode qtype qname
|
||||
ADJUST copy_id
|
||||
REPLY QR NOERROR
|
||||
SECTION QUESTION
|
||||
f.example. IN TXT
|
||||
SECTION ANSWER
|
||||
f.example. IN CNAME d.
|
||||
ENTRY_END
|
||||
|
||||
RANGE_END
|
||||
|
||||
; tcp.
|
||||
@ -367,5 +377,24 @@ SECTION ANSWER
|
||||
tcp. IN TXT "tcp. answer from upstream ns"
|
||||
ENTRY_END
|
||||
|
||||
; check if the name after the CNAME has the qname trigger applied to it.
|
||||
STEP 100 QUERY
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
f.example. IN TXT
|
||||
ENTRY_END
|
||||
|
||||
STEP 101 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
f.example. IN TXT
|
||||
SECTION ANSWER
|
||||
f.example. IN CNAME d.
|
||||
d. IN TXT "local data 2nd zone"
|
||||
ENTRY_END
|
||||
|
||||
; no answer is checked at exit of testbound.
|
||||
SCENARIO_END
|
||||
|
Loading…
Reference in New Issue
Block a user