RPZ: towards client ip trigger and local data action

This commit is contained in:
mb 2020-11-06 12:54:32 +01:00
parent bd0c910830
commit 80205ba133
4 changed files with 123 additions and 31 deletions

View file

@ -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 * This function returns the copied rrset key on success, and NULL on memory
* allocation failure. * allocation failure.
*/ */
static struct ub_packed_rrset_key* struct ub_packed_rrset_key*
copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region) respip_copy_rrset(const struct ub_packed_rrset_key* key, struct regional* region)
{ {
struct ub_packed_rrset_key* ck = regional_alloc(region, struct ub_packed_rrset_key* ck = regional_alloc(region,
sizeof(struct ub_packed_rrset_key)); 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", "response-ip redirect with tag data [%d] %s",
tag, (tag<num_tags?tagname[tag]:"null")); tag, (tag<num_tags?tagname[tag]:"null"));
/* use copy_rrset() to 'normalize' memory layout */ /* use copy_rrset() to 'normalize' memory layout */
rp = copy_rrset(&r, region); rp = respip_copy_rrset(&r, region);
if(!rp) if(!rp)
return -1; return -1;
} }
@ -743,7 +743,7 @@ respip_data_answer(enum respip_action action,
* rename the dname for other actions than redirect. This is because * rename the dname for other actions than redirect. This is because
* response-ip-data isn't associated to any specific name. */ * response-ip-data isn't associated to any specific name. */
if(rp == data) { if(rp == data) {
rp = copy_rrset(rp, region); rp = respip_copy_rrset(rp, region);
if(!rp) if(!rp)
return -1; return -1;
rp->rk.dname = rep->rrsets[rrset_id]->rk.dname; rp->rk.dname = rep->rrsets[rrset_id]->rk.dname;
@ -1208,7 +1208,7 @@ respip_merge_cname(struct reply_info* base_rep,
if(!new_rep) if(!new_rep)
return 0; return 0;
for(i=0,j=base_rep->an_numrrsets; i<tgt_rep->an_numrrsets; i++,j++) { 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]) if(!new_rep->rrsets[j])
return 0; return 0;
} }

View file

@ -294,4 +294,7 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
*/ */
void void
respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node); 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 */ #endif /* RESPIP_RESPIP_H */

View file

@ -50,6 +50,7 @@
#include "util/data/dname.h" #include "util/data/dname.h"
#include "util/locks.h" #include "util/locks.h"
#include "util/regional.h" #include "util/regional.h"
#include "util/data/msgencode.h"
typedef struct resp_addr rpz_aclnode_type; 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; enum localzone_type lzt;
if(r->action_override == RPZ_NO_OVERRIDE_ACTION) { if(r->action_override == RPZ_NO_OVERRIDE_ACTION) {
switch (client_action) { lzt = z->type;
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 { } else {
lzt = rpz_action_to_localzone_type(r->action_override); lzt = rpz_action_to_localzone_type(r->action_override);
} }
@ -1132,6 +1113,88 @@ rpz_is_udp_query(struct comm_reply* repinfo) {
: 0; : 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 int
rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env, rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf, 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", verbose(VERB_ALGO, "RPZ: qname trigger: client action=%s",
rpz_action_to_string(client_action)); 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"); verbose(VERB_ALGO, "RPZ: client action without zone");
if(client_action == RPZ_PASSTHRU_ACTION if(client_action == RPZ_PASSTHRU_ACTION
|| client_action == RPZ_INVALID_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))) { && !rpz_is_udp_query(repinfo))) {
return 0; return 0;
} }
// XXX: log_rpz_apply not possbile because no zone
stats->rpz_action[client_action]++; stats->rpz_action[client_action]++;
local_zones_zone_answer(NULL /*no zone*/, env, qinfo, edns, if(client_action == RPZ_LOCAL_DATA_ACTION) {
repinfo, buf, temp, 0 /* no local data used */, rpz_apply_clientip_localdata_action(r, env, qinfo, edns,
rpz_action_to_localzone_type(client_action)); 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; return 1;
} }

View file

@ -21,6 +21,7 @@ $ORIGIN rpz.example.com.
24.0.2.0.192.rpz-client-ip CNAME rpz-drop. 24.0.2.0.192.rpz-client-ip CNAME rpz-drop.
24.0.3.0.192.rpz-client-ip CNAME rpz-passthru. 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.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 TEMPFILE_END
stub-zone: stub-zone:
@ -168,6 +169,25 @@ SECTION ANSWER
a.a. IN TXT "upstream txt rr a.a." a.a. IN TXT "upstream txt rr a.a."
ENTRY_END 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 ; should be DROPPED
STEP 90 QUERY ADDRESS 192.0.2.1 STEP 90 QUERY ADDRESS 192.0.2.1