Merge pull request #401 from NLnetLabs/rpz-triggers

RPZ triggers
This commit is contained in:
Wouter Wijngaards 2021-08-25 10:14:12 +02:00 committed by GitHub
commit 74f1f0addd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
24 changed files with 3321 additions and 300 deletions

View file

@ -1355,7 +1355,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
goto send_reply;
}
if(worker->env.auth_zones &&
rpz_apply_qname_trigger(worker->env.auth_zones,
rpz_callback_from_worker_request(worker->env.auth_zones,
&worker->env, &qinfo, &edns, c->buffer, worker->scratchpad,
repinfo, acladdr->taglist, acladdr->taglen, &worker->stats)) {
regional_free_all(worker->scratchpad);

View file

@ -1152,10 +1152,11 @@ remote-control:
# dnstap-log-forwarder-response-messages: no
# Response Policy Zones
# RPZ policies. Applied in order of configuration. QNAME and Response IP
# Address trigger are the only supported triggers. Supported actions are:
# NXDOMAIN, NODATA, PASSTHRU, DROP and Local Data. Policies can be loaded from
# file, using zone transfer, or using HTTP. The respip module needs to be added
# RPZ policies. Applied in order of configuration. QNAME, Response IP
# Address, nsdname, nsip and clientip triggers are supported. Supported
# actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp-only
# and drop. Policies can be loaded from a file, or using zone
# transfer, or using HTTP. The respip module needs to be added
# to the module-config, e.g.: module-config: "respip validator iterator".
# rpz:
# name: "rpz.example.com"

View file

@ -684,8 +684,8 @@ specific cache, after getting processed by the edns client subnet module.
.TP
.I num.rpz.action.<rpz_action>
Number of queries answered using configured RPZ policy, per RPZ action type.
Possible actions are: nxdomain, nodata, passthru, drop, local_data, disabled,
and cname_override.
Possible actions are: nxdomain, nodata, passthru, drop, tcp\-only, local\-data,
disabled, and cname\-override.
.SH "FILES"
.TP
.I @ub_conf_file@

View file

@ -2516,10 +2516,49 @@ with a different name. RPZ clauses are applied in order of configuration. The
\fBrespip\fR module needs to be added to the \fBmodule-config\fR, e.g.:
\fBmodule-config: "respip validator iterator"\fR.
.P
Only the QNAME and Response IP Address triggers are supported. The supported RPZ
actions are: NXDOMAIN, NODATA, PASSTHRU, DROP and Local Data. RPZ QNAME triggers
are applied after
\fBlocal-zones\fR and before \fBauth-zones\fR.
QNAME, Response IP Address, nsdname, nsip and clientip triggers are supported.
Supported actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp\-only
and drop. RPZ QNAME triggers are applied after \fBlocal\-zones\fR and
before \fBauth\-zones\fR.
.P
The rpz zone is formatted with a SOA start record as usual. The items in
the zone are entries, that specify what to act on (the trigger) and what to
do (the action). The trigger to act on is recorded in the name, the action
to do is recorded as the resource record. The names all end in the zone
name, so you could type the trigger names without a trailing dot in the
zonefile.
.P
An example RPZ record, that answers example.com with NXDOMAIN
.nf
example.com CNAME .
.fi
.P
The triggers are encoded in the name on the left
.nf
name query name
netblock.rpz-client-ip client IP address
netblock.rpz-ip response IP address in the answer
name.rpz-nsdname nameserver name
netblock.rpz-nsip nameserver IP address
.fi
The netblock is written as <netblocklen>.<ip address in reverse>.
For IPv6 use 'zz' for '::'. Specify individual addresses with scope length
of 32 or 128. For example, 24.10.100.51.198.rpz-ip is 198.51.100.10/24 and
32.10.zz.db8.2001.rpz-ip is 2001:db8:0:0:0:0:0:10/32.
.P
The actions are specified with the record on the right
.nf
CNAME . nxdomain reply
CNAME *. nodata reply
CNAME rpz-passthru. do nothing, allow to continue
CNAME rpz-drop. the query is dropped
CNAME rpz-tcp-only. answer over TCP
A 192.0.2.1 answer with this IP address
.fi
Other records like AAAA, TXT and other CNAMEs (not rpz-..) can also be used to
answer queries with that content.
.P
The RPZ zones can be configured in the config file with these settings in the \fBrpz:\fR block.
.TP
.B name: \fI<zone name>
Name of the authority zone.

View file

@ -2529,6 +2529,23 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
/* Add the current set of unused targets to our queue. */
delegpt_add_unused_targets(iq->dp);
if(qstate->env->auth_zones) {
/* apply rpz triggers at query time */
struct dns_msg* forged_response = rpz_callback_from_iterator_module(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;
iq->response = 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);
}
return 0;
}
}
/* Select the next usable target, filtering out unsuitable targets. */
target = iter_server_selection(ie, qstate->env, iq->dp,
iq->dp->name, iq->dp->namelen, iq->qchase.qtype,
@ -2719,6 +2736,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
{
int dnsseclame = 0;
enum response_type type;
iq->num_current_queries--;
if(!inplace_cb_query_response_call(qstate->env, qstate, iq->response))
@ -3062,6 +3080,39 @@ 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;
iq->response = forged_response;
next_state(iq, FINISHED_STATE);
if(!iter_prepend(iq, qstate->return_msg, qstate->region)) {
log_err("rpz after cname, 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;

View file

@ -25,6 +25,7 @@
#include "respip/respip.h"
#include "services/view.h"
#include "sldns/rrdef.h"
#include "util/data/dname.h"
/** Subset of resp_addr.node, used for inform-variant logging */
@ -483,8 +484,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));
@ -602,7 +603,7 @@ rdata2sockaddr(const struct packed_rrset_data* rd, uint16_t rtype, size_t i,
*/
static struct resp_addr*
respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
size_t* rrset_id)
size_t* rrset_id, size_t* rr_id)
{
size_t i;
struct resp_addr* ra;
@ -625,6 +626,7 @@ respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
&ss, addrlen);
if(ra) {
*rrset_id = i;
*rr_id = j;
lock_rw_rdlock(&ra->lock);
lock_rw_unlock(&rs->lock);
return ra;
@ -635,43 +637,6 @@ respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
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
* (which is rep->rrsets[rrset_id]) and if so override it.
@ -730,7 +695,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 +708,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;
@ -807,7 +772,6 @@ respip_nodata_answer(uint16_t qtype, enum respip_action action,
* is explicitly specified. */
int rcode = (action == respip_always_nxdomain)?
LDNS_RCODE_NXDOMAIN:LDNS_RCODE_NOERROR;
/* We should empty the answer section except for any preceding
* CNAMEs (in that case rrset_id > 0). Type-ANY case is
* special as noted in respip_data_answer(). */
@ -907,7 +871,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
size_t tag_datas_size;
struct view* view = NULL;
struct respip_set* ipset = NULL;
size_t rrset_id = 0;
size_t rrset_id = 0, rr_id = 0;
enum respip_action action = respip_none;
int tag = -1;
struct resp_addr* raddr = NULL;
@ -948,7 +912,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
lock_rw_rdlock(&view->lock);
if(view->respip_set) {
if((raddr = respip_addr_lookup(rep,
view->respip_set, &rrset_id))) {
view->respip_set, &rrset_id, &rr_id))) {
/** for per-view respip directives the action
* can only be direct (i.e. not tag-based) */
action = raddr->action;
@ -962,7 +926,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
}
}
if(!raddr && (raddr = respip_addr_lookup(rep, ipset,
&rrset_id))) {
&rrset_id, &rr_id))) {
action = (enum respip_action)local_data_find_tag_action(
raddr->taglist, raddr->taglen, ctaglist, ctaglen,
tag_actions, tag_actions_size,
@ -976,7 +940,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
if(!r->taglist || taglist_intersect(r->taglist,
r->taglistlen, ctaglist, ctaglen)) {
if((raddr = respip_addr_lookup(rep,
r->respip_set, &rrset_id))) {
r->respip_set, &rrset_id, &rr_id))) {
if(!respip_use_rpz(raddr, r, &action, &data,
&rpz_log, &log_name, &rpz_cname_override,
region, &rpz_used)) {
@ -987,6 +951,21 @@ respip_rewrite_reply(const struct query_info* qinfo,
return 0;
}
if(rpz_used) {
if(verbosity >= VERB_ALGO) {
struct sockaddr_storage ss;
socklen_t ss_len = 0;
char nm[256], ip[256];
char qn[255+1];
if(!rdata2sockaddr(rep->rrsets[rrset_id]->entry.data, ntohs(rep->rrsets[rrset_id]->rk.type), rr_id, &ss, &ss_len))
snprintf(ip, sizeof(ip), "invalidRRdata");
else
addr_to_str(&ss, ss_len, ip, sizeof(ip));
dname_str(qinfo->qname, qn);
addr_to_str(&raddr->node.addr,
raddr->node.addrlen,
nm, sizeof(nm));
verbose(VERB_ALGO, "respip: rpz response-ip trigger %s/%d on %s %s with action %s", nm, raddr->node.net, qn, ip, rpz_action_to_string(respip_action_to_rpz_action(action)));
}
/* break to make sure 'a' stays pointed
* to used auth_zone, and keeps lock */
break;
@ -1209,7 +1188,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;
}

View file

@ -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 */

View file

@ -1950,6 +1950,17 @@ static int auth_zone_zonemd_check_hash(struct auth_zone* z,
return 0;
}
/** find the apex SOA RRset, if it exists */
struct auth_rrset* auth_zone_get_soa_rrset(struct auth_zone* z)
{
struct auth_data* apex;
struct auth_rrset* soa;
apex = az_find_name(z, z->name, z->namelen);
if(!apex) return NULL;
soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
return soa;
}
/** find serial number of zone or false if none */
int
auth_zone_get_serial(struct auth_zone* z, uint32_t* serial)

View file

@ -636,6 +636,9 @@ int auth_zones_startprobesequence(struct auth_zones* az,
/** read auth zone from zonefile. caller must lock zone. false on failure */
int auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg);
/** find the apex SOA RRset, if it exists. NULL if no SOA RRset. */
struct auth_rrset* auth_zone_get_soa_rrset(struct auth_zone* z);
/** find serial number of zone or false if none (no SOA record) */
int auth_zone_get_serial(struct auth_zone* z, uint32_t* serial);

View file

@ -1570,6 +1570,15 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
return (lr == NULL);
}
static inline int
local_zone_is_udp_query(struct comm_reply* repinfo) {
return repinfo != NULL
? (repinfo->c != NULL
? repinfo->c->type == comm_udp
: 0)
: 0;
}
int
local_zones_zone_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
@ -1592,7 +1601,9 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
lz_type == local_zone_redirect ||
lz_type == local_zone_inform_redirect ||
lz_type == local_zone_always_nxdomain ||
lz_type == local_zone_always_nodata) {
lz_type == local_zone_always_nodata ||
(lz_type == local_zone_truncate
&& local_zone_is_udp_query(repinfo))) {
/* for static, reply nodata or nxdomain
* for redirect, reply nodata */
/* no additional section processing,
@ -1602,9 +1613,11 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
*/
int rcode = (ld || lz_type == local_zone_redirect ||
lz_type == local_zone_inform_redirect ||
lz_type == local_zone_always_nodata)?
lz_type == local_zone_always_nodata ||
lz_type == local_zone_truncate)?
LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
if(z->soa && z->soa_negative)
rcode = (lz_type == local_zone_truncate ? (rcode|BIT_TC) : rcode);
if(z != NULL && z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa_negative, 0, rcode);
local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
@ -1661,7 +1674,7 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
* does not, then we should make this noerror/nodata */
if(ld && ld->rrsets) {
int rcode = LDNS_RCODE_NOERROR;
if(z->soa && z->soa_negative)
if(z != NULL && z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa_negative, 0, rcode);
local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
@ -1860,6 +1873,7 @@ const char* local_zone_type2str(enum localzone_type t)
case local_zone_always_deny: return "always_deny";
case local_zone_always_null: return "always_null";
case local_zone_noview: return "noview";
case local_zone_truncate: return "truncate";
case local_zone_invalid: return "invalid";
}
return "badtyped";
@ -1899,6 +1913,8 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
*t = local_zone_always_null;
else if(strcmp(type, "noview") == 0)
*t = local_zone_noview;
else if(strcmp(type, "truncate") == 0)
*t = local_zone_truncate;
else if(strcmp(type, "nodefault") == 0)
*t = local_zone_nodefault;
else return 0;

View file

@ -101,6 +101,8 @@ enum localzone_type {
local_zone_always_null,
/** answer not from the view, but global or no-answer */
local_zone_noview,
/** truncate the response; client should retry via tcp */
local_zone_truncate,
/** Invalid type, cannot be used to generate answer */
local_zone_invalid
};
@ -563,6 +565,8 @@ enum respip_action {
respip_always_nodata = local_zone_always_nodata,
/** answer with nodata response */
respip_always_deny = local_zone_always_deny,
/** RPZ: truncate answer in order to force switch to tcp */
respip_truncate = local_zone_truncate,
/* The rest of the values are only possible as
* access-control-tag-action */

View file

@ -1183,6 +1183,22 @@ mesh_do_callback(struct mesh_state* m, int rcode, struct reply_info* rep,
m->s.env->mesh->num_reply_addrs--;
}
static inline int
mesh_is_rpz_respip_tcponly_action(struct mesh_state const* m)
{
struct respip_action_info const* respip_info = m->s.respip_action_info;
return respip_info == NULL
? 0
: (respip_info->rpz_used
&& !respip_info->rpz_disabled
&& respip_info->action == respip_truncate);
}
static inline int
mesh_is_udp(struct mesh_reply const* r) {
return r->query_reply.c->type == comm_udp;
}
/**
* Send reply to mesh reply entry
* @param m: mesh state to send it for.
@ -1210,6 +1226,11 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
* null stops the mesh state remove and thus
* reply_list modification and accounting */
struct mesh_reply* rlist = m->reply_list;
/* rpz: apply actions */
rcode = mesh_is_udp(r) && mesh_is_rpz_respip_tcponly_action(m)
? (rcode|BIT_TC) : rcode;
/* examine security status */
if(m->s.env->need_to_validate && (!(r->qflags&BIT_CD) ||
m->s.env->cfg->ignore_cd) && rep &&

File diff suppressed because it is too large Load diff

View file

@ -50,6 +50,7 @@
#include "sldns/sbuffer.h"
#include "daemon/stats.h"
#include "respip/respip.h"
struct iter_qstate;
/**
* RPZ triggers, only the QNAME trigger is currently supported in Unbound.
@ -83,6 +84,27 @@ enum rpz_action {
RPZ_CNAME_OVERRIDE_ACTION, /* RPZ CNAME action override*/
};
struct clientip_synthesized_rrset{
struct regional* region;
struct rbtree_type entries;
lock_rw_type lock; /* lock on the respip tree */
};
struct clientip_synthesized_rr {
/** node in address tree */
struct addr_tree_node node;
/** lock on the node item */
lock_rw_type lock;
/** tag bitlist */
uint8_t* taglist;
/** length of the taglist (in bytes) */
size_t taglen;
/** action for this address span */
enum rpz_action action;
/** "local data" for this node */
struct local_rrset* data;
};
/**
* RPZ containing policies. Pointed to from corresponding auth-zone. Part of a
* linked list to keep configuration order. Iterating or changing the linked
@ -92,6 +114,9 @@ enum rpz_action {
struct rpz {
struct local_zones* local_zones;
struct respip_set* respip_set;
struct clientip_synthesized_rrset* client_set;
struct clientip_synthesized_rrset* ns_set;
struct local_zones* nsdname_zones;
uint8_t* taglist;
size_t taglistlen;
enum rpz_action action_override;
@ -151,11 +176,34 @@ void rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
* @param stats: worker stats struct
* @return: 1 if client answer is ready, 0 to continue resolving
*/
int rpz_apply_qname_trigger(struct auth_zones* az, struct module_env* env,
int rpz_callback_from_worker_request(struct auth_zones* az, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns, sldns_buffer* buf,
struct regional* temp, struct comm_reply* repinfo,
uint8_t* taglist, size_t taglen, struct ub_server_stats* stats);
/**
* Callback to process when the iterator module is about to send queries.
* Checks for nsip and nsdname triggers.
* @param qstate: the query state.
* @param iq: iterator module query state.
* @return NULL if nothing is done. Or a new message with the contents from
* the rpz, based on the delegation point. It is allocated in the
* qstate region.
*/
struct dns_msg* rpz_callback_from_iterator_module(struct module_qstate* qstate,
struct iter_qstate* iq);
/**
* Callback to process when the iterator module has followed a cname.
* There can be a qname trigger for the new query name.
* @param qstate: the query state.
* @param iq: iterator module query state.
* @return NULL if nothing is done. Or a new message with the contents from
* the rpz, based on the iq.qchase. It is allocated in the qstate region.
*/
struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* qstate,
struct iter_qstate* iq);
/**
* Delete RPZ
* @param r: RPZ struct to delete

264
testdata/rpz_clientip.rpl vendored Normal file
View file

@ -0,0 +1,264 @@
; config options
server:
module-config: "respip validator iterator"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
minimal-responses: no
access-control: 192.0.0.0/8 allow
rpz:
name: "rpz.example.com."
zonefile:
TEMPFILE_NAME rpz.example.com
TEMPFILE_CONTENTS rpz.example.com
$ORIGIN example.com.
rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. (
1379078166 28800 7200 604800 7200 )
3600 IN NS ns1.rpz.example.com.
3600 IN NS ns2.rpz.example.com.
$ORIGIN rpz.example.com.
24.0.0.0.192.rpz-client-ip CNAME .
24.0.1.0.192.rpz-client-ip CNAME *.
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
24.0.5.0.192.rpz-client-ip TXT "42"
TEMPFILE_END
stub-zone:
name: "a."
stub-addr: 10.20.30.40
CONFIG_END
SCENARIO_BEGIN Test RPZ client ip triggers
RANGE_BEGIN 0 100
ADDRESS 10.20.30.40
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
a. IN NS
SECTION ANSWER
a. IN NS ns.a.
SECTION ADDITIONAL
ns.a IN A 10.20.30.40
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
a.a. IN TXT "upstream txt rr a.a."
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
a.a. IN A
SECTION ANSWER
a.a. IN A 10.20.30.40
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
a.a. IN AAAA
SECTION ANSWER
a.a. IN AAAA 2001:db8::123
ENTRY_END
RANGE_END
; unrelated client ip address -- passthru
STEP 10 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN TXT
ENTRY_END
STEP 11 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
a.a. IN TXT "upstream txt rr a.a."
ENTRY_END
; should be NXDOMAIN
STEP 20 QUERY ADDRESS 192.0.0.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN TXT
ENTRY_END
STEP 21 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR AA RD RA NXDOMAIN
SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
ENTRY_END
; should be NODATA
STEP 30 QUERY ADDRESS 192.0.1.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN TXT
ENTRY_END
STEP 31 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR AA RD RA NOERROR
SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
ENTRY_END
; should be PASSTHRU
STEP 40 QUERY ADDRESS 192.0.3.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN TXT
ENTRY_END
STEP 41 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
a.a. IN TXT "upstream txt rr a.a."
ENTRY_END
; should be TRUNCATED
STEP 50 QUERY ADDRESS 192.0.4.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN TXT
ENTRY_END
STEP 51 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR AA TC RD RA NOERROR
SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
ENTRY_END
; should not be TRUNCATED via TCP
STEP 52 QUERY ADDRESS 192.0.4.1
ENTRY_BEGIN
MATCH TCP
REPLY RD
SECTION QUESTION
a.a. IN TXT
ENTRY_END
STEP 53 CHECK_ANSWER
ENTRY_BEGIN
MATCH all TCP
REPLY QR RD RA NOERROR
SECTION QUESTION
a.a. IN TXT
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 A
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
SECTION ADDITIONAL
rpz.example.com. 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( 1379078166 28800 7200 604800 7200 )
ENTRY_END
; should be synthesized
STEP 62 QUERY ADDRESS 192.0.5.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN TXT
ENTRY_END
STEP 63 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR AA RD RA NOERROR
SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
a.a. IN TXT "42"
SECTION ADDITIONAL
rpz.example.com. 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( 1379078166 28800 7200 604800 7200 )
ENTRY_END
; should be synthesized NODATA
STEP 64 QUERY ADDRESS 192.0.5.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN AAAA
ENTRY_END
STEP 65 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR AA RD RA NOERROR
SECTION QUESTION
a.a. IN AAAA
SECTION ADDITIONAL
rpz.example.com. 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. ( 1379078166 28800 7200 604800 7200 )
ENTRY_END
; should be DROPPED
STEP 90 QUERY ADDRESS 192.0.2.1
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN TXT
ENTRY_END
SCENARIO_END

390
testdata/rpz_nsdname.rpl vendored Normal file
View file

@ -0,0 +1,390 @@
; config options
server:
module-config: "respip validator iterator"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
access-control: 192.0.0.0/8 allow
rpz:
name: "rpz.example.com."
rpz-log: yes
rpz-log-name: "rpz.example.com"
zonefile:
TEMPFILE_NAME rpz.example.com
TEMPFILE_CONTENTS rpz.example.com
$ORIGIN example.com.
rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. (
1379078166 28800 7200 604800 7200 )
3600 IN NS ns1.rpz.example.com.
3600 IN NS ns2.rpz.example.com.
$ORIGIN rpz.example.com.
ns1.gotham.aa.rpz-nsdname CNAME .
ns1.gotham.bb.rpz-nsdname CNAME *.
ns1.gotham.cc.rpz-nsdname CNAME rpz-drop.
ns1.gotham.com.rpz-nsdname CNAME rpz-passthru.
ns1.gotham.dd.rpz-nsdname CNAME rpz-tcp-only.
ns1.gotham.ff.rpz-nsdname A 127.0.0.1
ns1.gotham.ff.rpz-nsdname TXT "42"
TEMPFILE_END
stub-zone:
name: "."
stub-addr: 1.1.1.1
CONFIG_END
SCENARIO_BEGIN Test RPZ nsip triggers
; . --------------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 1.1.1.1
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS ns.root.
SECTION ADDITIONAL
ns.root IN A 1.1.1.1
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
com. IN A
SECTION AUTHORITY
com. IN NS ns1.com.
SECTION ADDITIONAL
ns1.com. IN A 8.8.8.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
aa. IN A
SECTION AUTHORITY
aa. IN NS ns1.aa.
SECTION ADDITIONAL
ns1.aa. IN A 8.8.0.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
bb. IN A
SECTION AUTHORITY
bb. IN NS ns1.bb.
SECTION ADDITIONAL
ns1.bb. IN A 8.8.1.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
cc. IN A
SECTION AUTHORITY
cc. IN NS ns1.cc.
SECTION ADDITIONAL
ns1.cc. IN A 8.8.2.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
dd. IN A
SECTION AUTHORITY
dd. IN NS ns1.dd.
SECTION ADDITIONAL
ns1.dd. IN A 8.8.3.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
ee. IN A
SECTION AUTHORITY
ee. IN NS ns1.ee.
SECTION ADDITIONAL
ns1.ee. IN A 8.8.5.8
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
; com. -----------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 8.8.8.8
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
com. IN NS
SECTION ANSWER
com. IN NS ns1.com.
SECTION ADDITIONAL
ns1.com. IN A 8.8.8.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
gotham.com. IN A
SECTION AUTHORITY
gotham.com. IN NS ns1.gotham.com.
SECTION ADDITIONAL
ns1.gotham.com. IN A 192.0.6.1
ENTRY_END
RANGE_END
; aa. ------------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 8.8.0.8
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
aa. IN NS
SECTION ANSWER
aa. IN NS ns1.aa.
SECTION ADDITIONAL
ns1.aa. IN A 8.8.0.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
gotham.aa. IN A
SECTION AUTHORITY
gotham.aa. IN NS ns1.gotham.aa.
SECTION ADDITIONAL
ns1.gotham.aa. IN A 192.0.0.1
ENTRY_END
RANGE_END
; bb. ------------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 8.8.1.8
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
bb. IN NS
SECTION ANSWER
bb. IN NS ns1.bb.
SECTION ADDITIONAL
ns1.bb. IN A 8.8.1.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
gotham.bb. IN A
SECTION AUTHORITY
gotham.bb. IN NS ns1.gotham.bb.
SECTION ADDITIONAL
ns1.gotham.bb. IN A 192.0.1.1
ENTRY_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. ------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 192.0.6.1
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
gotham.com. IN A
SECTION ANSWER
gotham.com. IN A 192.0.6.2
ENTRY_END
RANGE_END
; ns1.gotham.aa. -------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 192.0.0.1
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
gotham.aa. IN A
SECTION ANSWER
gotham.aa. IN A 192.0.0.2
ENTRY_END
RANGE_END
; ns1.gotham.bb. -------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 192.0.1.1
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
gotham.bb. IN A
SECTION ANSWER
gotham.bb. IN A 192.0.1.2
ENTRY_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
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
gotham.com. IN A
ENTRY_END
STEP 2 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
gotham.com. IN A
SECTION ANSWER
gotham.com. IN A 192.0.6.2
ENTRY_END
STEP 10 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
gotham.aa. IN A
ENTRY_END
STEP 11 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
gotham.aa. IN A
SECTION ANSWER
ENTRY_END
STEP 20 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
gotham.bb. IN A
ENTRY_END
STEP 21 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
gotham.bb. IN A
SECTION ANSWER
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 AA NOERROR
SECTION QUESTION
gotham.ff. IN A
SECTION ANSWER
gotham.ff. IN A 127.0.0.1
ENTRY_END
SCENARIO_END

408
testdata/rpz_nsip.rpl vendored Normal file
View file

@ -0,0 +1,408 @@
; config options
server:
module-config: "respip validator iterator"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
access-control: 192.0.0.0/8 allow
rpz:
name: "rpz.example.com."
rpz-log: yes
rpz-log-name: "rpz.example.com"
zonefile:
TEMPFILE_NAME rpz.example.com
TEMPFILE_CONTENTS rpz.example.com
$ORIGIN example.com.
rpz 3600 IN SOA ns1.rpz.gotham.com. hostmaster.rpz.example.com. (
1379078166 28800 7200 604800 7200 )
3600 IN NS ns1.rpz.example.com.
3600 IN NS ns2.rpz.example.com.
$ORIGIN rpz.example.com.
24.0.0.0.192.rpz-nsip CNAME .
24.0.1.0.192.rpz-nsip CNAME *.
24.0.2.0.192.rpz-nsip CNAME rpz-drop.
24.0.3.0.192.rpz-nsip CNAME rpz-passthru.
24.0.4.0.192.rpz-nsip CNAME rpz-tcp-only.
24.0.5.0.192.rpz-nsip A 127.0.0.1
24.0.5.0.192.rpz-nsip TXT "42"
TEMPFILE_END
stub-zone:
name: "."
stub-addr: 1.1.1.1
CONFIG_END
SCENARIO_BEGIN Test RPZ nsip triggers
; . --------------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 1.1.1.1
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS ns.root.
SECTION ADDITIONAL
ns.root IN A 1.1.1.1
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
com. IN A
SECTION AUTHORITY
com. IN NS ns1.com.
SECTION ADDITIONAL
ns1.com. IN A 8.8.8.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
aa. IN A
SECTION AUTHORITY
aa. IN NS ns1.aa.
SECTION ADDITIONAL
ns1.aa. IN A 8.8.0.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
bb. IN A
SECTION AUTHORITY
bb. IN NS ns1.bb.
SECTION ADDITIONAL
ns1.bb. IN A 8.8.1.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
cc. IN A
SECTION AUTHORITY
cc. IN NS ns1.cc.
SECTION ADDITIONAL
ns1.cc. IN A 8.8.2.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
dd. IN A
SECTION AUTHORITY
dd. IN NS ns1.dd.
SECTION ADDITIONAL
ns1.dd. IN A 8.8.3.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
ee. IN A
SECTION AUTHORITY
ee. IN NS ns1.ee.
SECTION ADDITIONAL
ns1.ee. IN A 8.8.5.8
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
; com. -----------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 8.8.8.8
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
com. IN NS
SECTION ANSWER
com. IN NS ns1.com.
SECTION ADDITIONAL
ns1.com. IN A 8.8.8.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
gotham.com. IN A
SECTION AUTHORITY
gotham.com. IN NS ns1.gotham.com.
SECTION ADDITIONAL
ns1.gotham.com. IN A 192.0.6.1
ENTRY_END
RANGE_END
; aa. ------------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 8.8.0.8
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
aa. IN NS
SECTION ANSWER
aa. IN NS ns1.aa.
SECTION ADDITIONAL
ns1.aa. IN A 8.8.0.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
gotham.aa. IN A
SECTION AUTHORITY
gotham.aa. IN NS ns1.gotham.aa.
SECTION ADDITIONAL
ns1.gotham.aa. IN A 192.0.0.1
ENTRY_END
RANGE_END
; bb. ------------------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 8.8.1.8
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
bb. IN NS
SECTION ANSWER
bb. IN NS ns1.bb.
SECTION ADDITIONAL
ns1.bb. IN A 8.8.1.8
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
gotham.bb. IN A
SECTION AUTHORITY
gotham.bb. IN NS ns1.gotham.bb.
SECTION ADDITIONAL
ns1.gotham.bb. IN A 192.0.1.1
ENTRY_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. ------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 192.0.6.1
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
gotham.com. IN A
SECTION ANSWER
gotham.com. IN A 192.0.6.2
ENTRY_END
RANGE_END
; ns1.gotham.aa. -------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 192.0.0.1
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
gotham.aa. IN A
SECTION ANSWER
gotham.aa. IN A 192.0.0.2
ENTRY_END
RANGE_END
; ns1.gotham.bb. -------------------------------------------------------------
RANGE_BEGIN 0 100
ADDRESS 192.0.1.1
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
gotham.bb. IN A
SECTION ANSWER
gotham.bb. IN A 192.0.1.2
ENTRY_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
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
gotham.com. IN A
ENTRY_END
STEP 2 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
gotham.com. IN A
SECTION ANSWER
gotham.com. IN A 192.0.6.2
ENTRY_END
STEP 10 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
gotham.aa. IN A
ENTRY_END
STEP 11 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
gotham.aa. IN A
SECTION ANSWER
ENTRY_END
STEP 20 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
gotham.bb. IN A
ENTRY_END
STEP 21 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
gotham.bb. IN A
SECTION ANSWER
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 AA NOERROR
SECTION QUESTION
gotham.ff. IN A
SECTION ANSWER
gotham.ff. IN A 127.0.0.1
ENTRY_END
; again with more cache items
STEP 40 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
gotham.ff. IN A
ENTRY_END
STEP 41 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
gotham.ff. IN A
SECTION ANSWER
gotham.ff. IN A 127.0.0.1
ENTRY_END
SCENARIO_END

104
testdata/rpz_qname.rpl vendored
View file

@ -38,6 +38,7 @@ d TXT "local data 2nd zone"
e CNAME *.a.example.
*.e CNAME *.b.example.
drop CNAME rpz-drop.
tcp CNAME rpz-tcp-only.
TEMPFILE_END
stub-zone:
@ -46,12 +47,15 @@ stub-zone:
stub-zone:
name: "example."
stub-addr: 10.20.30.50
stub-zone:
name: "tcp."
stub-addr: 10.20.30.60
CONFIG_END
SCENARIO_BEGIN Test all support RPZ action for QNAME trigger
; a.
RANGE_BEGIN 0 100
RANGE_BEGIN 0 1000
ADDRESS 10.20.30.40
ENTRY_BEGIN
MATCH opcode qtype qname
@ -88,7 +92,7 @@ ENTRY_END
RANGE_END
; example.
RANGE_BEGIN 0 100
RANGE_BEGIN 0 1000
ADDRESS 10.20.30.50
ENTRY_BEGIN
MATCH opcode qtype qname
@ -122,6 +126,42 @@ 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.
RANGE_BEGIN 0 1000
ADDRESS 10.20.30.60
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
tcp. IN NS
SECTION ANSWER
tcp. IN NS ns.example.
SECTION ADDITIONAL
ns.tcp IN A 10.20.30.60
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
tcp. IN TXT
SECTION ANSWER
tcp. IN TXT "tcp. answer from upstream ns"
ENTRY_END
RANGE_END
STEP 10 QUERY
@ -295,10 +335,66 @@ something.e.b.example. IN TXT "*.b.example. answer from upstream ns"
ENTRY_END
; deny zone
STEP 90 QUERY
;STEP 90 QUERY
;ENTRY_BEGIN
;SECTION QUESTION
;drop. IN TXT
;ENTRY_END
; tcp-only action
STEP 95 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
drop. IN TXT
tcp. IN TXT
ENTRY_END
STEP 96 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA TC NOERROR
SECTION QUESTION
tcp. IN TXT
SECTION ANSWER
ENTRY_END
STEP 97 QUERY
ENTRY_BEGIN
MATCH TCP
REPLY RD
SECTION QUESTION
tcp. IN TXT
ENTRY_END
STEP 98 CHECK_ANSWER
ENTRY_BEGIN
MATCH all TCP
REPLY QR RD RA NOERROR
SECTION QUESTION
tcp. IN TXT
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 AA 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

117
testdata/rpz_qname_tcponly.rpl vendored Normal file
View file

@ -0,0 +1,117 @@
; config options
server:
module-config: "respip validator iterator"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
rpz:
name: "rpz.example.com."
zonefile:
TEMPFILE_NAME rpz.example.com
TEMPFILE_CONTENTS rpz.example.com
$ORIGIN example.com.
rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. (
1379078166 28800 7200 604800 7200 )
3600 IN NS ns1.rpz.example.com.
3600 IN NS ns2.rpz.example.com.
$ORIGIN rpz.example.com.
a.a CNAME rpz-passthru.
b.a CNAME rpz-tcp-only.
TEMPFILE_END
stub-zone:
name: "a."
stub-addr: 10.20.30.40
CONFIG_END
SCENARIO_BEGIN Test RPZ qname trigger and tcp-only action
RANGE_BEGIN 0 100
ADDRESS 10.20.30.40
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
a. IN NS
SECTION ANSWER
a. IN NS ns.a.
SECTION ADDITIONAL
ns.a IN A 10.20.30.40
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
a.a. IN TXT "upstream txt rr a.a."
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
b.a. IN TXT
SECTION ANSWER
b.a. IN TXT "upstream txt rr b.a."
ENTRY_END
RANGE_END
STEP 10 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN TXT
ENTRY_END
STEP 11 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
a.a. IN TXT "upstream txt rr a.a."
ENTRY_END
STEP 20 QUERY
ENTRY_BEGIN
MATCH UDP
REPLY RD
SECTION QUESTION
b.a. IN TXT
ENTRY_END
STEP 21 CHECK_ANSWER
ENTRY_BEGIN
MATCH all UDP
REPLY QR AA TC RD RA NOERROR
SECTION QUESTION
b.a. IN TXT
SECTION ANSWER
ENTRY_END
STEP 30 QUERY
ENTRY_BEGIN
MATCH TCP
REPLY RD
SECTION QUESTION
b.a. IN TXT
ENTRY_END
STEP 31 CHECK_ANSWER
ENTRY_BEGIN
MATCH all TCP
REPLY QR RD RA NOERROR
SECTION QUESTION
b.a. IN TXT
SECTION ANSWER
b.a. IN TXT "upstream txt rr b.a."
ENTRY_END
SCENARIO_END

View file

@ -20,6 +20,7 @@ $ORIGIN rpz.example.com.
16.0.0.10.10.rpz-ip CNAME .
24.0.10.10.10.rpz-ip CNAME rpz-drop.
32.10.10.10.10.rpz-ip CNAME rpz-passthru.
32.1.1.1.10.rpz-ip CNAME rpz-tcp-only.
32.zz.db8.2001.rpz-ip CNAME *.
48.zz.aa.db8.2001.rpz-ip CNAME .
64.zz.bb.aa.db8.2001.rpz-ip CNAME rpz-drop.
@ -217,6 +218,16 @@ SECTION ANSWER
h. IN AAAA 2001:db8:aa:bb:cc::124
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
y. IN A
SECTION ANSWER
y. IN A 10.1.1.1
ENTRY_END
RANGE_END
STEP 1 QUERY
@ -446,4 +457,21 @@ SECTION QUESTION
e. IN AAAA
ENTRY_END
STEP 29 TIME_PASSES ELAPSE 12
STEP 30 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
y. IN A
ENTRY_END
STEP 31 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR TC RD RA NOERROR
SECTION QUESTION
y. IN A
SECTION ANSWER
ENTRY_END
SCENARIO_END

207
testdata/rpz_respip_tcponly.rpl vendored Normal file
View file

@ -0,0 +1,207 @@
; config options
server:
module-config: "respip validator iterator"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
rpz:
name: "rpz.example.com."
zonefile:
TEMPFILE_NAME rpz.example.com
TEMPFILE_CONTENTS rpz.example.com
$ORIGIN example.com.
rpz 3600 IN SOA ns1.rpz.example.com. hostmaster.rpz.example.com. (
1379078166 28800 7200 604800 7200 )
3600 IN NS ns1.rpz.example.com.
3600 IN NS ns2.rpz.example.com.
$ORIGIN rpz.example.com.
8.0.0.0.10.rpz-ip CNAME *.
16.0.0.10.10.rpz-ip CNAME .
24.0.10.10.10.rpz-ip CNAME rpz-drop.
32.10.10.10.10.rpz-ip CNAME rpz-passthru.
32.1.1.1.10.rpz-ip CNAME rpz-tcp-only.
TEMPFILE_END
stub-zone:
name: "."
stub-addr: 10.20.30.40
CONFIG_END
SCENARIO_BEGIN Test RPZ response IP address trigger and tcp-only action
RANGE_BEGIN 0 100
ADDRESS 10.20.30.40
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS ns.
SECTION ADDITIONAL
ns. IN A 10.20.30.40
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
a. IN A
SECTION ANSWER
a. IN A 10.0.0.123
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
b. IN A
SECTION ANSWER
b. IN A 10.1.0.123
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
c. IN A
SECTION ANSWER
c. IN A 10.11.0.123
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
d. IN A
SECTION ANSWER
d. IN A 10.10.0.123
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
f. IN A
SECTION ANSWER
f. IN A 10.10.10.10
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
y. IN A
SECTION ANSWER
y. IN A 10.1.1.1
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a. IN A
ENTRY_END
STEP 2 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
a. IN A
SECTION ANSWER
ENTRY_END
STEP 10 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
b. IN A
ENTRY_END
STEP 11 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
b. IN A
SECTION ANSWER
ENTRY_END
STEP 13 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d. IN A
ENTRY_END
STEP 14 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
d. IN A
SECTION ANSWER
ENTRY_END
STEP 17 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
f. IN A
ENTRY_END
STEP 18 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
f. IN A
SECTION ANSWER
f. IN A 10.10.10.10
ENTRY_END
STEP 30 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
y. IN A
ENTRY_END
STEP 31 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR TC RD RA NOERROR
SECTION QUESTION
y. IN A
SECTION ANSWER
ENTRY_END
STEP 40 QUERY
ENTRY_BEGIN
MATCH TCP
REPLY RD
SECTION QUESTION
y. IN A
ENTRY_END
STEP 41 CHECK_ANSWER
ENTRY_BEGIN
MATCH all TCP
REPLY QR RD RA NOERROR
SECTION QUESTION
y. IN A
SECTION ANSWER
y. IN A 10.1.1.1
ENTRY_END
SCENARIO_END

View file

@ -166,6 +166,32 @@ reply_info_alloc_rrset_keys(struct reply_info* rep, struct alloc_cache* alloc,
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 */
static time_t
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,
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.
* @param pkt: packet for decompression

View file

@ -61,6 +61,13 @@ typedef uint64_t rrset_id_type;
* updated on encoding in a reply. This flag is not expected to be set in
* cached data. */
#define PACKED_RRSET_FIXEDTTL 0x80000000
/** This rrset is from RPZ. It is not real, it is synthesized data to block
* access. The flag makes lookups, from cache in iterator, ignore the fake
* items and only use actual data. Eg. when the iterator looksup NS, CNAME,
* A and AAAA types, it then gets items without this flag that are the
* actual network. But messages with these records in it can be stored in
* the cache and retrieved for a reply. */
#define PACKED_RRSET_RPZ 0x8
/** number of rrs and rrsets for integer overflow protection. More than
* this is not really possible (64K packet has much less RRs and RRsets) in
@ -88,6 +95,7 @@ struct packed_rrset_key {
* o PACKED_RRSET_PARENT_SIDE
* o PACKED_RRSET_SOA_NEG
* o PACKED_RRSET_FIXEDTTL (not supposed to be cached)
* o PACKED_RRSET_RPZ
*/
uint32_t flags;
/** the rrset type in network format */