mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
RPZ: towards client ip trigger and local data action
This commit is contained in:
parent
bd0c910830
commit
80205ba133
4 changed files with 123 additions and 31 deletions
|
|
@ -483,8 +483,8 @@ respip_views_apply_cfg(struct views* vs, struct config_file* cfg,
|
|||
* This function returns the copied rrset key on success, and NULL on memory
|
||||
* allocation failure.
|
||||
*/
|
||||
static struct ub_packed_rrset_key*
|
||||
copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region)
|
||||
struct ub_packed_rrset_key*
|
||||
respip_copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region)
|
||||
{
|
||||
struct ub_packed_rrset_key* ck = regional_alloc(region,
|
||||
sizeof(struct ub_packed_rrset_key));
|
||||
|
|
@ -730,7 +730,7 @@ respip_data_answer(enum respip_action action,
|
|||
"response-ip redirect with tag data [%d] %s",
|
||||
tag, (tag<num_tags?tagname[tag]:"null"));
|
||||
/* use copy_rrset() to 'normalize' memory layout */
|
||||
rp = copy_rrset(&r, region);
|
||||
rp = respip_copy_rrset(&r, region);
|
||||
if(!rp)
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -743,7 +743,7 @@ respip_data_answer(enum respip_action action,
|
|||
* rename the dname for other actions than redirect. This is because
|
||||
* response-ip-data isn't associated to any specific name. */
|
||||
if(rp == data) {
|
||||
rp = copy_rrset(rp, region);
|
||||
rp = respip_copy_rrset(rp, region);
|
||||
if(!rp)
|
||||
return -1;
|
||||
rp->rk.dname = rep->rrsets[rrset_id]->rk.dname;
|
||||
|
|
@ -1208,7 +1208,7 @@ respip_merge_cname(struct reply_info* base_rep,
|
|||
if(!new_rep)
|
||||
return 0;
|
||||
for(i=0,j=base_rep->an_numrrsets; i<tgt_rep->an_numrrsets; i++,j++) {
|
||||
new_rep->rrsets[j] = copy_rrset(tgt_rep->rrsets[i], region);
|
||||
new_rep->rrsets[j] = respip_copy_rrset(tgt_rep->rrsets[i], region);
|
||||
if(!new_rep->rrsets[j])
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -294,4 +294,7 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
|
|||
*/
|
||||
void
|
||||
respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node);
|
||||
|
||||
struct ub_packed_rrset_key*
|
||||
respip_copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region);
|
||||
#endif /* RESPIP_RESPIP_H */
|
||||
|
|
|
|||
113
services/rpz.c
113
services/rpz.c
|
|
@ -50,6 +50,7 @@
|
|||
#include "util/data/dname.h"
|
||||
#include "util/locks.h"
|
||||
#include "util/regional.h"
|
||||
#include "util/data/msgencode.h"
|
||||
|
||||
typedef struct resp_addr rpz_aclnode_type;
|
||||
|
||||
|
|
@ -1096,27 +1097,7 @@ rpz_resolve_final_localzone_action(struct rpz* r, struct local_zone* z, enum rpz
|
|||
{
|
||||
enum localzone_type lzt;
|
||||
if(r->action_override == RPZ_NO_OVERRIDE_ACTION) {
|
||||
switch (client_action) {
|
||||
case RPZ_NODATA_ACTION:
|
||||
case RPZ_NXDOMAIN_ACTION:
|
||||
case RPZ_DROP_ACTION:
|
||||
case RPZ_TCP_ONLY_ACTION:
|
||||
case RPZ_PASSTHRU_ACTION:
|
||||
lzt = rpz_action_to_localzone_type(client_action);
|
||||
break;
|
||||
case RPZ_LOCAL_DATA_ACTION:
|
||||
verbose(VERB_ALGO,
|
||||
"RPZ: client ip trigger with local-data unimplemented:"
|
||||
" defaulting to rpz-passthru");
|
||||
lzt = rpz_action_to_localzone_type(RPZ_PASSTHRU_ACTION);
|
||||
break;
|
||||
case RPZ_INVALID_ACTION:
|
||||
lzt = z->type;
|
||||
break;
|
||||
default:
|
||||
lzt = z->type;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
lzt = rpz_action_to_localzone_type(r->action_override);
|
||||
}
|
||||
|
|
@ -1132,6 +1113,88 @@ rpz_is_udp_query(struct comm_reply* repinfo) {
|
|||
: 0;
|
||||
}
|
||||
|
||||
/** encode answer consisting of 1 rrset */
|
||||
static int
|
||||
rpz_local_encode(struct query_info* qinfo, struct module_env* env,
|
||||
struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
|
||||
struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec,
|
||||
int rcode)
|
||||
{
|
||||
struct reply_info rep;
|
||||
uint16_t udpsize;
|
||||
/* make answer with time=0 for fixed TTL values */
|
||||
memset(&rep, 0, sizeof(rep));
|
||||
rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode);
|
||||
rep.qdcount = 1;
|
||||
if(ansec)
|
||||
rep.an_numrrsets = 1;
|
||||
else rep.ns_numrrsets = 1;
|
||||
rep.rrset_count = 1;
|
||||
rep.rrsets = &rrset;
|
||||
|
||||
udpsize = edns->udp_size;
|
||||
edns->edns_version = EDNS_ADVERTISED_VERSION;
|
||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||
edns->ext_rcode = 0;
|
||||
edns->bits &= EDNS_DO;
|
||||
//!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,repinfo, temp) ||
|
||||
if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,repinfo, temp) ||!reply_info_answer_encode(qinfo, &rep,
|
||||
*(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
|
||||
buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
|
||||
error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
|
||||
*(uint16_t*)sldns_buffer_begin(buf),
|
||||
sldns_buffer_read_u16_at(buf, 2), edns);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
rpz_apply_clientip_localdata_action(struct rpz* r, struct module_env* env,
|
||||
struct query_info* qinfo, struct edns_data* edns, struct comm_reply* repinfo,
|
||||
sldns_buffer* buf, struct regional* temp)
|
||||
{
|
||||
struct resp_addr* raddr = NULL;
|
||||
enum rpz_action action = RPZ_INVALID_ACTION;
|
||||
struct sockaddr_storage* addr = &repinfo->addr;
|
||||
socklen_t addrlen = repinfo->addrlen;
|
||||
struct ub_packed_rrset_key* rp = NULL;
|
||||
int rcode = LDNS_RCODE_NOERROR|BIT_AA;
|
||||
|
||||
verbose(VERB_ALGO, "RPZ: apply client ip trigger: found=%d action=%s",
|
||||
raddr != NULL, rpz_action_to_string(action));
|
||||
|
||||
lock_rw_rdlock(&r->client_set->lock);
|
||||
|
||||
raddr = (struct resp_addr*)addr_tree_lookup(&r->client_set->ip_tree,
|
||||
addr, addrlen);
|
||||
if(raddr == NULL) {
|
||||
lock_rw_unlock(&r->client_set->lock);
|
||||
return;
|
||||
}
|
||||
|
||||
/* prepare synthesized answer for the matching client */
|
||||
|
||||
action = respip_action_to_rpz_action(raddr->action);
|
||||
if(action != RPZ_LOCAL_DATA_ACTION && raddr->data == NULL ) {
|
||||
verbose(VERB_ALGO, "RPZ: bug: local-data action and no local data");
|
||||
goto done;
|
||||
}
|
||||
rp = respip_copy_rrset(raddr->data, temp);
|
||||
if(!rp) {
|
||||
verbose(VERB_ALGO, "RPZ: local-data action: out of memory");
|
||||
goto done;
|
||||
}
|
||||
rp->rk.flags |= PACKED_RRSET_FIXEDTTL;
|
||||
rp->rk.dname = qinfo->qname;
|
||||
rp->rk.dname_len = qinfo->qname_len;
|
||||
rpz_local_encode(qinfo, env, edns, repinfo, buf, temp, rp, 1, rcode);
|
||||
|
||||
done:
|
||||
lock_rw_unlock(&raddr->lock);
|
||||
lock_rw_unlock(&r->client_set->lock);
|
||||
|
||||
}
|
||||
|
||||
int
|
||||
rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
|
||||
struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
|
||||
|
|
@ -1152,7 +1215,8 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
|
|||
verbose(VERB_ALGO, "RPZ: qname trigger: client action=%s",
|
||||
rpz_action_to_string(client_action));
|
||||
|
||||
if(!z) {
|
||||
if(z == NULL || (client_action != RPZ_INVALID_ACTION &&
|
||||
client_action != RPZ_PASSTHRU_ACTION)) {
|
||||
verbose(VERB_ALGO, "RPZ: client action without zone");
|
||||
if(client_action == RPZ_PASSTHRU_ACTION
|
||||
|| client_action == RPZ_INVALID_ACTION
|
||||
|
|
@ -1160,11 +1224,16 @@ rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
|
|||
&& !rpz_is_udp_query(repinfo))) {
|
||||
return 0;
|
||||
}
|
||||
// XXX: log_rpz_apply not possbile because no zone
|
||||
stats->rpz_action[client_action]++;
|
||||
if(client_action == RPZ_LOCAL_DATA_ACTION) {
|
||||
rpz_apply_clientip_localdata_action(r, env, qinfo, edns,
|
||||
repinfo, buf, temp);
|
||||
} else {
|
||||
// XXX: log_rpz_apply not possbile because no zone
|
||||
local_zones_zone_answer(NULL /*no zone*/, env, qinfo, edns,
|
||||
repinfo, buf, temp, 0 /* no local data used */,
|
||||
rpz_action_to_localzone_type(client_action));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
20
testdata/rpz_clientip.rpl
vendored
20
testdata/rpz_clientip.rpl
vendored
|
|
@ -21,6 +21,7 @@ $ORIGIN rpz.example.com.
|
|||
24.0.2.0.192.rpz-client-ip CNAME rpz-drop.
|
||||
24.0.3.0.192.rpz-client-ip CNAME rpz-passthru.
|
||||
24.0.4.0.192.rpz-client-ip CNAME rpz-tcp-only.
|
||||
24.0.5.0.192.rpz-client-ip A 127.0.0.1
|
||||
TEMPFILE_END
|
||||
|
||||
stub-zone:
|
||||
|
|
@ -168,6 +169,25 @@ SECTION ANSWER
|
|||
a.a. IN TXT "upstream txt rr a.a."
|
||||
ENTRY_END
|
||||
|
||||
; should be synthesized
|
||||
|
||||
STEP 60 QUERY ADDRESS 192.0.5.1
|
||||
ENTRY_BEGIN
|
||||
REPLY RD
|
||||
SECTION QUESTION
|
||||
a.a. IN TXT
|
||||
ENTRY_END
|
||||
|
||||
STEP 61 CHECK_ANSWER
|
||||
ENTRY_BEGIN
|
||||
MATCH all
|
||||
REPLY QR AA RD RA NOERROR
|
||||
SECTION QUESTION
|
||||
a.a. IN A
|
||||
SECTION ANSWER
|
||||
a.a. IN A 127.0.0.1
|
||||
ENTRY_END
|
||||
|
||||
; should be DROPPED
|
||||
|
||||
STEP 90 QUERY ADDRESS 192.0.2.1
|
||||
|
|
|
|||
Loading…
Reference in a new issue