mirror of
https://github.com/NLnetLabs/unbound.git
synced 2025-12-20 23:00:56 -05:00
rpz: continue work on the nsip trigger
This commit is contained in:
parent
07d937f508
commit
f7fb338c95
5 changed files with 202 additions and 68 deletions
|
|
@ -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.
|
||||||
|
|
|
||||||
113
services/rpz.c
113
services/rpz.c
|
|
@ -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
79
testdata/rpz_nsip.rpl
vendored
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue