rpz: continue work on the nsip trigger

This commit is contained in:
mb 2020-11-16 12:42:23 +01:00
parent 07d937f508
commit f7fb338c95
5 changed files with 202 additions and 68 deletions

View file

@ -635,43 +635,6 @@ respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
return NULL; return NULL;
} }
/*
* Create a new reply_info based on 'rep'. The new info is based on
* the passed 'rep', but ignores any rrsets except for the first 'an_numrrsets'
* RRsets in the answer section. These answer rrsets are copied to the
* new info, up to 'copy_rrsets' rrsets (which must not be larger than
* 'an_numrrsets'). If an_numrrsets > copy_rrsets, the remaining rrsets array
* entries will be kept empty so the caller can fill them later. When rrsets
* are copied, they are shallow copied. The caller must ensure that the
* copied rrsets are valid throughout its lifetime and must provide appropriate
* mutex if it can be shared by multiple threads.
*/
static struct reply_info *
make_new_reply_info(const struct reply_info* rep, struct regional* region,
size_t an_numrrsets, size_t copy_rrsets)
{
struct reply_info* new_rep;
size_t i;
/* create a base struct. we specify 'insecure' security status as
* the modified response won't be DNSSEC-valid. In our faked response
* the authority and additional sections will be empty (except possible
* EDNS0 OPT RR in the additional section appended on sending it out),
* so the total number of RRsets is an_numrrsets. */
new_rep = construct_reply_info_base(region, rep->flags,
rep->qdcount, rep->ttl, rep->prefetch_ttl,
rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets,
sec_status_insecure);
if(!new_rep)
return NULL;
if(!reply_info_alloc_rrset_keys(new_rep, NULL, region))
return NULL;
for(i=0; i<copy_rrsets; i++)
new_rep->rrsets[i] = rep->rrsets[i];
return new_rep;
}
/** /**
* See if response-ip or tag data should override the original answer rrset * See if response-ip or tag data should override the original answer rrset
* (which is rep->rrsets[rrset_id]) and if so override it. * (which is rep->rrsets[rrset_id]) and if so override it.

View file

@ -1361,11 +1361,11 @@ rpz_local_encode(struct query_info* qinfo, struct module_env* env,
} }
static struct local_rrset* static struct local_rrset*
rpz_clientip_find_rrset(struct query_info* qinfo, struct clientip_synthesized_rr* data) { rpz_find_synthesized_rrset(int qtype, struct clientip_synthesized_rr* data) {
struct local_rrset* cursor = data->data; struct local_rrset* cursor = data->data;
while( cursor != NULL) { while( cursor != NULL) {
struct packed_rrset_key* packed_rrset = &cursor->rrset->rk; struct packed_rrset_key* packed_rrset = &cursor->rrset->rk;
if(htons(qinfo->qtype) == packed_rrset->type) { if(htons(qtype) == packed_rrset->type) {
return cursor; return cursor;
} }
cursor = cursor->next; cursor = cursor->next;
@ -1397,7 +1397,7 @@ rpz_apply_clientip_localdata_action(struct rpz* r, struct clientip_synthesized_r
/* check query type / rr type */ /* check query type / rr type */
rrset = rpz_clientip_find_rrset(qinfo, raddr); rrset = rpz_find_synthesized_rrset(qinfo->qtype, raddr);
if(rrset == NULL) { if(rrset == NULL) {
verbose(VERB_ALGO, "rpz: unable to find local-data for query"); verbose(VERB_ALGO, "rpz: unable to find local-data for query");
rrset_count = 0; rrset_count = 0;
@ -1420,19 +1420,82 @@ nodata:
rpz_local_encode(qinfo, env, edns, repinfo, buf, temp, rp, rrset_count, rcode); rpz_local_encode(qinfo, env, edns, repinfo, buf, temp, rp, rrset_count, rcode);
} }
static inline void
rpz_patch_nodata(struct reply_info* ri)
{
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;
}
static inline void
rpz_patch_nxdomain(struct reply_info* ri)
{
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;
}
static inline int
rpz_patch_localdata(struct dns_msg* response, struct clientip_synthesized_rr* data,
struct regional* region)
{
struct query_info* qi = &response->qinfo;
struct ub_packed_rrset_key* rp;
struct local_rrset* rrset;
struct reply_info* new_reply_info;
struct reply_info* ri = response->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;
}
new_reply_info = make_new_reply_info(ri, region, 0, 0);
if(new_reply_info == NULL) {
log_err("out of memory");
rpz_patch_nodata(ri);
return 1;
}
rp = respip_copy_rrset(rrset->rrset, region);
if(rp == NULL) {
log_err("out of memory");
rpz_patch_nodata(ri);
return 1;
}
new_reply_info->rrsets = regional_alloc(region, sizeof(*new_reply_info->rrsets));
if(new_reply_info->rrsets == NULL) {
log_err("out of memory");
rpz_patch_nodata(ri);
return 1;
}
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;
}
int int
rpz_iterator_module_callback(struct module_qstate* ms, struct iter_qstate* is) rpz_iterator_module_callback(struct module_qstate* ms, struct iter_qstate* is)
{ {
struct auth_zones* az = ms->env->auth_zones; struct auth_zones* az = ms->env->auth_zones;
struct auth_zone* a; struct auth_zone* a;
struct clientip_synthesized_rr* raddr; struct clientip_synthesized_rr* raddr;
struct local_rrset* rrset;
enum rpz_action action = RPZ_INVALID_ACTION; enum rpz_action action = RPZ_INVALID_ACTION;
struct sockaddr_storage* addr = &ms->reply->addr;
socklen_t addrlen = ms->reply->addrlen;
struct ub_packed_rrset_key* rp = NULL;
int rcode = LDNS_RCODE_NOERROR|BIT_AA;
int rrset_count = 1;
struct rpz* r; struct rpz* r;
int ret = 0; int ret = 0;
@ -1466,39 +1529,29 @@ rpz_iterator_module_callback(struct module_qstate* ms, struct iter_qstate* is)
switch(action) { switch(action) {
case RPZ_NXDOMAIN_ACTION: case RPZ_NXDOMAIN_ACTION:
FLAGS_SET_RCODE(is->response->rep->flags, LDNS_RCODE_NXDOMAIN); rpz_patch_nxdomain(is->response->rep);
is->response->rep->flags |= BIT_QR | BIT_AA | BIT_RA;
is->response->rep->an_numrrsets = 0;
is->response->rep->ns_numrrsets = 0;
is->response->rep->ar_numrrsets = 0;
is->response->rep->authoritative = 1;
is->response->rep->qdcount = 1;
ret = 1; ret = 1;
break; break;
case RPZ_NODATA_ACTION: case RPZ_NODATA_ACTION:
FLAGS_SET_RCODE(is->response->rep->flags, LDNS_RCODE_NOERROR); rpz_patch_nodata(is->response->rep);
is->response->rep->flags |= BIT_QR | BIT_AA | BIT_RA;
is->response->rep->an_numrrsets = 0;
is->response->rep->ns_numrrsets = 0;
is->response->rep->ar_numrrsets = 0;
is->response->rep->authoritative = 1;
is->response->rep->qdcount = 1;
ret = 1; ret = 1;
break; break;
case RPZ_TCP_ONLY_ACTION:
log_err("rpz: nsip: tcp-only trigger unimplemented; resorting to passthru");
ret = 0;
break;
case RPZ_PASSTHRU_ACTION: case RPZ_PASSTHRU_ACTION:
ret = 0; ret = 0;
break; break;
case RPZ_LOCAL_DATA_ACTION:
ret = rpz_patch_localdata(is->response, raddr, ms->region);
break;
default: default:
verbose(VERB_ALGO, "rpz: nsip: bug: unhandled or invalid action: '%s'",
rpz_action_to_string(action));
ret = 0; ret = 0;
} }
//rrset = rpz_clientip_find_rrset(qinfo, raddr);
//if(rrset == NULL) {
// verbose(VERB_ALGO, "rpz: unable to find local-data for query");
// rrset_count = 0;
// goto nodata;
//}
done: done:
lock_rw_unlock(&raddr->lock); lock_rw_unlock(&raddr->lock);
return ret; return ret;

79
testdata/rpz_nsip.rpl vendored
View file

@ -119,6 +119,18 @@ SECTION ADDITIONAL
ns1.ee. IN A 8.8.5.8 ns1.ee. IN A 8.8.5.8
ENTRY_END ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
ff. IN A
SECTION AUTHORITY
ff. IN NS ns1.ff.
SECTION ADDITIONAL
ns1.ff. IN A 8.8.6.8
ENTRY_END
RANGE_END RANGE_END
; com. ----------------------------------------------------------------------- ; com. -----------------------------------------------------------------------
@ -192,7 +204,7 @@ REPLY QR NOERROR
SECTION QUESTION SECTION QUESTION
bb. IN NS bb. IN NS
SECTION ANSWER SECTION ANSWER
bb. IN NS ns1.aa. bb. IN NS ns1.bb.
SECTION ADDITIONAL SECTION ADDITIONAL
ns1.bb. IN A 8.8.1.8 ns1.bb. IN A 8.8.1.8
ENTRY_END ENTRY_END
@ -211,6 +223,36 @@ ENTRY_END
RANGE_END RANGE_END
; ff. ------------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 8.8.6.8
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
ff. IN NS
SECTION ANSWER
ff. IN NS ns1.ff.
SECTION ADDITIONAL
ns1.ff. IN A 8.8.6.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
gotham.ff. IN A
SECTION AUTHORITY
gotham.ff. IN NS ns1.gotham.ff.
SECTION ADDITIONAL
ns1.gotham.ff. IN A 192.0.5.1
ENTRY_END
RANGE_END
; ns1.gotham.com. ------------------------------------------------------------ ; ns1.gotham.com. ------------------------------------------------------------
RANGE_BEGIN 0 100 RANGE_BEGIN 0 100
ADDRESS 192.0.6.1 ADDRESS 192.0.6.1
@ -259,6 +301,24 @@ ENTRY_END
RANGE_END RANGE_END
; ns1.gotham.ff. -------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 192.0.5.1
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
gotham.ff. IN A
SECTION ANSWER
gotham.ff. IN A 192.0.5.2
ENTRY_END
RANGE_END
; ----------------------------------------------------------------------------
STEP 1 QUERY STEP 1 QUERY
ENTRY_BEGIN ENTRY_BEGIN
REPLY RD REPLY RD
@ -308,4 +368,21 @@ gotham.bb. IN A
SECTION ANSWER SECTION ANSWER
ENTRY_END ENTRY_END
STEP 30 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
gotham.ff. IN A
ENTRY_END
STEP 31 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
gotham.ff. IN A
SECTION ANSWER
gotham.ff. IN A 127.0.0.1
ENTRY_END
SCENARIO_END SCENARIO_END

View file

@ -164,6 +164,32 @@ reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
return 1; return 1;
} }
struct reply_info *
make_new_reply_info(const struct reply_info* rep, struct regional* region,
size_t an_numrrsets, size_t copy_rrsets)
{
struct reply_info* new_rep;
size_t i;
/* create a base struct. we specify 'insecure' security status as
* the modified response won't be DNSSEC-valid. In our faked response
* the authority and additional sections will be empty (except possible
* EDNS0 OPT RR in the additional section appended on sending it out),
* so the total number of RRsets is an_numrrsets. */
new_rep = construct_reply_info_base(region, rep->flags,
rep->qdcount, rep->ttl, rep->prefetch_ttl,
rep->serve_expired_ttl, an_numrrsets, 0, 0, an_numrrsets,
sec_status_insecure);
if(!new_rep)
return NULL;
if(!reply_info_alloc_rrset_keys(new_rep, NULL, region))
return NULL;
for(i=0; i<copy_rrsets; i++)
new_rep->rrsets[i] = rep->rrsets[i];
return new_rep;
}
/** find the minimumttl in the rdata of SOA record */ /** find the minimumttl in the rdata of SOA record */
static time_t static time_t
soa_find_minttl(struct rr_parse* rr) soa_find_minttl(struct rr_parse* rr)

View file

@ -382,6 +382,21 @@ struct reply_info* reply_info_copy(struct reply_info* rep,
int reply_info_alloc_rrset_keys(struct reply_info* rep, int reply_info_alloc_rrset_keys(struct reply_info* rep,
struct alloc_cache* alloc, struct regional* region); struct alloc_cache* alloc, struct regional* region);
/*
* Create a new reply_info based on 'rep'. The new info is based on
* the passed 'rep', but ignores any rrsets except for the first 'an_numrrsets'
* RRsets in the answer section. These answer rrsets are copied to the
* new info, up to 'copy_rrsets' rrsets (which must not be larger than
* 'an_numrrsets'). If an_numrrsets > copy_rrsets, the remaining rrsets array
* entries will be kept empty so the caller can fill them later. When rrsets
* are copied, they are shallow copied. The caller must ensure that the
* copied rrsets are valid throughout its lifetime and must provide appropriate
* mutex if it can be shared by multiple threads.
*/
struct reply_info *
make_new_reply_info(const struct reply_info* rep, struct regional* region,
size_t an_numrrsets, size_t copy_rrsets);
/** /**
* Copy a parsed rrset into given key, decompressing and allocating rdata. * Copy a parsed rrset into given key, decompressing and allocating rdata.
* @param pkt: packet for decompression * @param pkt: packet for decompression