Merge branch 'master' into framestreams

This commit is contained in:
W.C.A. Wijngaards 2020-01-30 16:22:12 +01:00
commit 8dd683768b
47 changed files with 8653 additions and 4294 deletions

File diff suppressed because it is too large Load Diff

View File

@ -616,7 +616,8 @@ daemon_fork(struct daemon* daemon)
have_view_respip_cfg;
/* read auth zonefiles */
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1))
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1,
&daemon->use_rpz))
fatal_exit("auth_zones could not be setup");
/* setup modules */
@ -628,6 +629,12 @@ daemon_fork(struct daemon* daemon)
if(daemon->use_response_ip &&
modstack_find(&daemon->mods, "respip") < 0)
fatal_exit("response-ip options require respip module");
/* RPZ response ip triggers don't work as expected without the respip
* module. To avoid run-time operational surprise we reject such
* configuration. */
if(daemon->use_rpz &&
modstack_find(&daemon->mods, "respip") < 0)
fatal_exit("RPZ requires the respip module");
/* first create all the worker structures, so we can pass
* them to the newly created threads.

View File

@ -132,6 +132,8 @@ struct daemon {
struct respip_set* respip_set;
/** some response-ip tags or actions are configured if true */
int use_response_ip;
/** some RPZ policies are configured */
int use_rpz;
#ifdef USE_DNSCRYPT
/** the dnscrypt environment */
struct dnsc_env* dnscenv;

View File

@ -69,6 +69,7 @@
#include "services/mesh.h"
#include "services/localzone.h"
#include "services/authzone.h"
#include "services/rpz.h"
#include "util/storage/slabhash.h"
#include "util/fptr_wlist.h"
#include "util/data/dname.h"
@ -1045,6 +1046,16 @@ print_ext(RES* ssl, struct ub_stats_info* s)
(unsigned)s->svr.infra_cache_count)) return 0;
if(!ssl_printf(ssl, "key.cache.count"SQ"%u\n",
(unsigned)s->svr.key_cache_count)) return 0;
/* applied RPZ actions */
for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++) {
if(i == RPZ_NO_OVERRIDE_ACTION)
continue;
if(inhibit_zero && s->svr.rpz_action[i] == 0)
continue;
if(!ssl_printf(ssl, "num.rpz.action.%s"SQ"%lu\n",
rpz_action_to_string(i),
(unsigned long)s->svr.rpz_action[i])) return 0;
}
#ifdef USE_DNSCRYPT
if(!ssl_printf(ssl, "dnscrypt_shared_secret.cache.count"SQ"%u\n",
(unsigned)s->svr.shared_secret_cache_count)) return 0;

View File

@ -271,8 +271,10 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
s->svr.ans_secure += (long long)worker->env.mesh->ans_secure;
s->svr.ans_bogus += (long long)worker->env.mesh->ans_bogus;
s->svr.ans_rcode_nodata += (long long)worker->env.mesh->ans_nodata;
for(i=0; i<16; i++)
for(i=0; i<UB_STATS_RCODE_NUM; i++)
s->svr.ans_rcode[i] += (long long)worker->env.mesh->ans_rcode[i];
for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++)
s->svr.rpz_action[i] += (long long)worker->env.mesh->rpz_action[i];
timehist_export(worker->env.mesh->histogram, s->svr.hist,
NUM_BUCKETS_HIST);
/* values from outside network */
@ -446,6 +448,8 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
total->svr.ans_rcode[i] += a->svr.ans_rcode[i];
for(i=0; i<NUM_BUCKETS_HIST; i++)
total->svr.hist[i] += a->svr.hist[i];
for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++)
total->svr.rpz_action[i] += a->svr.rpz_action[i];
}
total->mesh_num_states += a->mesh_num_states;

View File

@ -61,6 +61,7 @@
#include "services/authzone.h"
#include "services/mesh.h"
#include "services/localzone.h"
#include "services/rpz.h"
#include "util/data/msgparse.h"
#include "util/data/msgencode.h"
#include "util/data/dname.h"
@ -573,9 +574,10 @@ static int
apply_respip_action(struct worker* worker, const struct query_info* qinfo,
struct respip_client_info* cinfo, struct reply_info* rep,
struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset,
struct reply_info** encode_repp)
struct reply_info** encode_repp, struct auth_zones* az)
{
struct respip_action_info actinfo = {respip_none, NULL};
struct respip_action_info actinfo = {0};
actinfo.action = respip_none;
if(qinfo->qtype != LDNS_RR_TYPE_A &&
qinfo->qtype != LDNS_RR_TYPE_AAAA &&
@ -583,7 +585,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
return 1;
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo,
alias_rrset, 0, worker->scratchpad))
alias_rrset, 0, worker->scratchpad, az))
return 0;
/* xxx_deny actions mean dropping the reply, unless the original reply
@ -596,9 +598,20 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
/* If address info is returned, it means the action should be an
* 'inform' variant and the information should be logged. */
if(actinfo.addrinfo) {
respip_inform_print(actinfo.addrinfo, qinfo->qname,
respip_inform_print(&actinfo, qinfo->qname,
qinfo->qtype, qinfo->qclass, qinfo->local_alias,
repinfo);
if(worker->stats.extended && actinfo.rpz_used) {
if(actinfo.rpz_disabled)
worker->stats.rpz_action[RPZ_DISABLED_ACTION] +=
actinfo.rpz_disabled;
if(actinfo.rpz_cname_override)
worker->stats.rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
else
worker->stats.rpz_action[
respip_action_to_rpz_action(actinfo.action)]++;
}
}
return 1;
@ -710,13 +723,15 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
(int)(flags&LDNS_RCODE_MASK), edns, repinfo, worker->scratchpad))
goto bail_out;
*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
if(worker->daemon->use_response_ip && !partial_rep &&
!apply_respip_action(worker, qinfo, cinfo, rep, repinfo, alias_rrset,
&encode_rep)) {
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
repinfo, alias_rrset,
&encode_rep, worker->env.auth_zones)) {
goto bail_out;
} else if(partial_rep &&
!respip_merge_cname(partial_rep, qinfo, rep, cinfo,
must_validate, &encode_rep, worker->scratchpad)) {
must_validate, &encode_rep, worker->scratchpad,
worker->env.auth_zones)) {
goto bail_out;
}
if(encode_rep != rep)
@ -1365,6 +1380,18 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
server_stats_insrcode(&worker->stats, c->buffer);
goto send_reply;
}
if(worker->env.auth_zones &&
rpz_apply_qname_trigger(worker->env.auth_zones,
&worker->env, &qinfo, &edns, c->buffer, worker->scratchpad,
repinfo, acladdr->taglist, acladdr->taglen, &worker->stats)) {
regional_free_all(worker->scratchpad);
if(sldns_buffer_limit(c->buffer) == 0) {
comm_point_drop_reply(repinfo);
return 0;
}
server_stats_insrcode(&worker->stats, c->buffer);
goto send_reply;
}
if(worker->env.auth_zones &&
auth_zones_answer(worker->env.auth_zones, &worker->env,
&qinfo, &edns, repinfo, c->buffer, worker->scratchpad)) {
@ -1435,7 +1462,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
/* If we may apply IP-based actions to the answer, build the client
* information. As this can be expensive, skip it if there is
* absolutely no possibility of it. */
if(worker->daemon->use_response_ip &&
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
(qinfo.qtype == LDNS_RR_TYPE_A ||
qinfo.qtype == LDNS_RR_TYPE_AAAA ||
qinfo.qtype == LDNS_RR_TYPE_ANY)) {

View File

@ -2,6 +2,8 @@
- Fix memory leak in error condition remote.c
- Fix double free in error condition view.c
- Fix memory leak in do_auth_zone_transfer on success
- Merge RPZ support into master. Only QNAME and Response IP triggers are
supported.
30 January 2020: Wouter
- Fix subnet tests for disabled DSA algorithm by default.
@ -10,6 +12,8 @@
and Frzk. Updates the unbound.service systemd file and adds
a portable systemd service file.
- updated .gitignore for added contrib file.
- Add build rule for ipset to Makefile
- Add getentropy_freebsd.o to Makefile dependencies.
29 January 2020: Ralph
- Merge PR#156 from Alexander Berkes; Added unbound-control

View File

@ -1006,3 +1006,20 @@ remote-control:
# name-v6: "list-v6"
#
# 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
# to the module-config, e.g.: module-config: "respip validator iterator".
# rpz:
# name: "rpz.example.com"
# zonefile: "rpz.example.com"
# master: 192.0.2.0
# allow-notify: 192.0.2.0/32
# url: http://www.example.com/rpz.example.org.zone
# rpz-action-override: cname
# rpz-cname-override: www.example.org
# rpz-log: yes
# rpz-log-name: "example policy"
# tags: "example"

View File

@ -663,6 +663,11 @@ Number of queries that got an answer that contained EDNS client subnet data.
Number of queries answered from the edns client subnet cache. These are
counted as cachemiss by the main counters, but hit the client subnet
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.
.SH "FILES"
.TP
.I @ub_conf_file@

View File

@ -2090,6 +2090,70 @@ If this timeout expires Unbound closes the connection, treats it as
if the Redis server does not have the requested data, and will try to
re-establish a new connection later.
This option defaults to 100 milliseconds.
.SS Response Policy Zone Options
.LP
Response Policy Zones are configured with \fBrpz:\fR, and each one must have a
\fBname:\fR. There can be multiple ones, by listing multiple rpz clauses, each
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.
.TP
.B name: \fI<zone name>
Name of the authority zone.
.TP
.B master: \fI<IP address or host name>
Where to download a copy of the zone from, with AXFR and IXFR. Multiple
masters can be specified. They are all tried if one fails.
.TP
.B url: \fI<url to zonefile>
Where to download a zonefile for the zone. With http or https. An example
for the url is "http://www.example.com/example.org.zone". Multiple url
statements can be given, they are tried in turn. If only urls are given
the SOA refresh timer is used to wait for making new downloads. If also
masters are listed, the masters are first probed with UDP SOA queries to
see if the SOA serial number has changed, reducing the number of downloads.
If none of the urls work, the masters are tried with IXFR and AXFR.
For https, the \fBtls\-cert\-bundle\fR and the hostname from the url are used
to authenticate the connection.
.TP
.B allow\-notify: \fI<IP address or host name or netblockIP/prefix>
With allow\-notify you can specify additional sources of notifies.
When notified, the server attempts to first probe and then zone transfer.
If the notify is from a master, it first attempts that master. Otherwise
other masters are attempted. If there are no masters, but only urls, the
file is downloaded when notified. The masters from master: statements are
allowed notify by default.
.TP
.B zonefile: \fI<filename>
The filename where the zone is stored. If not given then no zonefile is used.
If the file does not exist or is empty, unbound will attempt to fetch zone
data (eg. from the master servers).
.TP
.B rpz\-action\-override: \fI<action>
Always use this RPZ action for matching triggers from this zone. Possible action
are: nxdomain, nodata, passthru, drop, disabled and cname.
.TP
.B rpz\-cname\-override: \fI<domain>
The CNAME target domain to use if the cname action is configured for
\fBrpz\-action\-override\fR.
.TP
.B rpz\-log: \fI<yes or no>
Log all applied RPZ actions for this RPZ zone. Default is no.
.TP
.B rpz\-log\-name: \fI<name>
Specify a string to be part of the log line, for easy referencing.
.TP
.B tags: \fI<list of tags>
Limit the policies from this RPZ clause to clients with a matching tag. Tags
need to be defined in \fBdefine\-tag\fR and can be assiged to client addresses
using \fBaccess\-control\-tag\fR. Enclose list of tags in quotes ("") and put
spaces between tags. If no tags are specified the policies from this clause will
be applied for all clients.
.SH "MEMORY CONTROL EXAMPLE"
In the example config settings below memory usage is reduced. Some service
levels are lower, notable very large data and a high TCP load are no longer

View File

@ -55,6 +55,7 @@
int
context_finalize(struct ub_ctx* ctx)
{
int is_rpz = 0;
struct config_file* cfg = ctx->env->cfg;
verbosity = cfg->verbosity;
if(ctx_logfile_overridden && !ctx->logfile_override) {
@ -76,7 +77,7 @@ context_finalize(struct ub_ctx* ctx)
return UB_NOMEM;
if(!local_zones_apply_cfg(ctx->local_zones, cfg))
return UB_INITFAIL;
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1))
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz))
return UB_INITFAIL;
if(!slabhash_is_size(ctx->env->msg_cache, cfg->msg_cache_size,
cfg->msg_cache_slabs)) {

View File

@ -654,6 +654,8 @@ struct ub_shm_stat_info {
#define UB_STATS_OPCODE_NUM 16
/** number of histogram buckets */
#define UB_STATS_BUCKET_NUM 40
/** number of RPZ actions */
#define UB_STATS_RPZ_ACTION_NUM 10
/** per worker statistics. */
struct ub_server_stats {
@ -785,6 +787,8 @@ struct ub_server_stats {
long long mem_stream_wait;
/** number of TLS connection resume */
long long qtls_resume;
/** RPZ action stats */
long long rpz_action[UB_STATS_RPZ_ACTION_NUM];
};
/**

View File

@ -12,6 +12,7 @@
#include "config.h"
#include "services/localzone.h"
#include "services/authzone.h"
#include "services/cache/dns.h"
#include "sldns/str2wire.h"
#include "util/config_file.h"
@ -25,30 +26,6 @@
#include "services/view.h"
#include "sldns/rrdef.h"
/**
* Conceptual set of IP addresses for response AAAA or A records that should
* trigger special actions.
*/
struct respip_set {
struct regional* region;
struct rbtree_type ip_tree;
char* const* tagname; /* shallow copy of tag names, for logging */
int num_tags; /* number of tagname entries */
};
/** An address span with response control information */
struct resp_addr {
/** node in address tree */
struct addr_tree_node node;
/** tag bitlist */
uint8_t* taglist;
/** length of the taglist (in bytes) */
size_t taglen;
/** action for this address span */
enum respip_action action;
/** "local data" for this node */
struct ub_packed_rrset_key* data;
};
/** Subset of resp_addr.node, used for inform-variant logging */
struct respip_addr_info {
@ -88,6 +65,7 @@ respip_set_create(void)
return NULL;
}
addr_tree_init(&set->ip_tree);
lock_rw_init(&set->lock);
return set;
}
@ -96,6 +74,7 @@ respip_set_delete(struct respip_set* set)
{
if(!set)
return;
lock_rw_destroy(&set->lock);
regional_destroy(set->region);
free(set);
}
@ -108,12 +87,49 @@ respip_set_get_tree(struct respip_set* set)
return &set->ip_tree;
}
struct resp_addr*
respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage* addr,
socklen_t addrlen, int net, int create, const char* ipstr)
{
struct resp_addr* node;
node = (struct resp_addr*)addr_tree_find(&set->ip_tree, addr, addrlen, net);
if(!node && create) {
node = regional_alloc_zero(set->region, sizeof(*node));
if(!node) {
log_err("out of memory");
return NULL;
}
lock_rw_init(&node->lock);
node->action = respip_none;
if(!addr_tree_insert(&set->ip_tree, &node->node, addr,
addrlen, net)) {
/* We know we didn't find it, so this should be
* impossible. */
log_warn("unexpected: duplicate address: %s", ipstr);
}
}
return node;
}
void
respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node)
{
struct resp_addr* prev;
prev = (struct resp_addr*)rbtree_previous((struct rbnode_type*)node);
lock_rw_destroy(&node->lock);
rbtree_delete(&set->ip_tree, node);
/* no free'ing, all allocated in region */
if(!prev)
addr_tree_init_parents((rbtree_type*)set);
else
addr_tree_init_parents_node(&prev->node);
}
/** returns the node in the address tree for the specified netblock string;
* non-existent node will be created if 'create' is true */
static struct resp_addr*
respip_find_or_create(struct respip_set* set, const char* ipstr, int create)
{
struct resp_addr* node;
struct sockaddr_storage addr;
int net;
socklen_t addrlen;
@ -122,22 +138,8 @@ respip_find_or_create(struct respip_set* set, const char* ipstr, int create)
log_err("cannot parse netblock: '%s'", ipstr);
return NULL;
}
node = (struct resp_addr*)addr_tree_find(&set->ip_tree, &addr, addrlen, net);
if(!node && create) {
node = regional_alloc_zero(set->region, sizeof(*node));
if(!node) {
log_err("out of memory");
return NULL;
}
node->action = respip_none;
if(!addr_tree_insert(&set->ip_tree, &node->node, &addr,
addrlen, net)) {
/* We know we didn't find it, so this should be
* impossible. */
log_warn("unexpected: duplicate address: %s", ipstr);
}
}
return node;
return respip_sockaddr_find_or_create(set, &addr, addrlen, net, create,
ipstr);
}
static int
@ -191,6 +193,10 @@ respip_action_cfg(struct respip_set* set, const char* ipstr,
action = respip_always_refuse;
else if(strcmp(actnstr, "always_nxdomain") == 0)
action = respip_always_nxdomain;
else if(strcmp(actnstr, "always_nodata") == 0)
action = respip_always_nodata;
else if(strcmp(actnstr, "always_deny") == 0)
action = respip_always_deny;
else {
log_err("unknown response-ip action %s", actnstr);
return 0;
@ -232,8 +238,43 @@ new_rrset(struct regional* region, uint16_t rrtype, uint16_t rrclass)
}
/** enter local data as resource records into a response-ip node */
static int
int
respip_enter_rr(struct regional* region, struct resp_addr* raddr,
uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata,
size_t rdata_len, const char* rrstr, const char* netblockstr)
{
struct packed_rrset_data* pd;
struct sockaddr* sa;
sa = (struct sockaddr*)&raddr->node.addr;
if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data) {
log_err("CNAME response-ip data (%s) can not co-exist with other "
"response-ip data for netblock %s", rrstr, netblockstr);
return 0;
} else if (raddr->data &&
raddr->data->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
log_err("response-ip data (%s) can not be added; CNAME response-ip "
"data already in place for netblock %s", rrstr, netblockstr);
return 0;
} else if((rrtype != LDNS_RR_TYPE_CNAME) &&
((sa->sa_family == AF_INET && rrtype != LDNS_RR_TYPE_A) ||
(sa->sa_family == AF_INET6 && rrtype != LDNS_RR_TYPE_AAAA))) {
log_err("response-ip data %s record type does not correspond "
"to netblock %s address family", rrstr, netblockstr);
return 0;
}
if(!raddr->data) {
raddr->data = new_rrset(region, rrtype, rrclass);
if(!raddr->data)
return 0;
}
pd = raddr->data->entry.data;
return rrset_insert_rr(region, pd, rdata, rdata_len, ttl, rrstr);
}
static int
respip_enter_rrstr(struct regional* region, struct resp_addr* raddr,
const char* rrstr, const char* netblock)
{
uint8_t* nm;
@ -244,8 +285,6 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
size_t rdata_len = 0;
char buf[65536];
char bufshort[64];
struct packed_rrset_data* pd;
struct sockaddr* sa;
int ret;
if(raddr->action != respip_redirect
&& raddr->action != respip_inform_redirect) {
@ -265,31 +304,8 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
return 0;
}
free(nm);
sa = (struct sockaddr*)&raddr->node.addr;
if (rrtype == LDNS_RR_TYPE_CNAME && raddr->data) {
log_err("CNAME response-ip data (%s) can not co-exist with other "
"response-ip data for netblock %s", rrstr, netblock);
return 0;
} else if (raddr->data &&
raddr->data->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
log_err("response-ip data (%s) can not be added; CNAME response-ip "
"data already in place for netblock %s", rrstr, netblock);
return 0;
} else if((rrtype != LDNS_RR_TYPE_CNAME) &&
((sa->sa_family == AF_INET && rrtype != LDNS_RR_TYPE_A) ||
(sa->sa_family == AF_INET6 && rrtype != LDNS_RR_TYPE_AAAA))) {
log_err("response-ip data %s record type does not correspond "
"to netblock %s address family", rrstr, netblock);
return 0;
}
if(!raddr->data) {
raddr->data = new_rrset(region, rrtype, rrclass);
if(!raddr->data)
return 0;
}
pd = raddr->data->entry.data;
return rrset_insert_rr(region, pd, rdata, rdata_len, ttl, rrstr);
return respip_enter_rr(region, raddr, rrtype, rrclass, ttl, rdata,
rdata_len, rrstr, netblock);
}
static int
@ -303,7 +319,7 @@ respip_data_cfg(struct respip_set* set, const char* ipstr, const char* rrstr)
"response-ip node for %s not found", rrstr, ipstr);
return 0;
}
return respip_enter_rr(set->region, node, rrstr, ipstr);
return respip_enter_rrstr(set->region, node, rrstr, ipstr);
}
static int
@ -564,9 +580,10 @@ rdata2sockaddr(const struct packed_rrset_data* rd, uint16_t rtype, size_t i,
* rep->rrsets for the RRset that contains the matching IP address record
* (the index is normally 0, but can be larger than that if this is a CNAME
* chain or type-ANY response).
* Returns resp_addr holding read lock.
*/
static const struct resp_addr*
respip_addr_lookup(const struct reply_info *rep, struct rbtree_type* iptree,
static struct resp_addr*
respip_addr_lookup(const struct reply_info *rep, struct respip_set* rs,
size_t* rrset_id)
{
size_t i;
@ -574,6 +591,7 @@ respip_addr_lookup(const struct reply_info *rep, struct rbtree_type* iptree,
struct sockaddr_storage ss;
socklen_t addrlen;
lock_rw_rdlock(&rs->lock);
for(i=0; i<rep->an_numrrsets; i++) {
size_t j;
const struct packed_rrset_data* rd;
@ -585,15 +603,17 @@ respip_addr_lookup(const struct reply_info *rep, struct rbtree_type* iptree,
for(j = 0; j < rd->count; j++) {
if(!rdata2sockaddr(rd, rtype, j, &ss, &addrlen))
continue;
ra = (struct resp_addr*)addr_tree_lookup(iptree, &ss,
addrlen);
ra = (struct resp_addr*)addr_tree_lookup(&rs->ip_tree,
&ss, addrlen);
if(ra) {
*rrset_id = i;
lock_rw_rdlock(&ra->lock);
lock_rw_unlock(&rs->lock);
return ra;
}
}
}
lock_rw_unlock(&rs->lock);
return NULL;
}
@ -642,8 +662,8 @@ make_new_reply_info(const struct reply_info* rep, struct regional* region,
* Note that this function distinguishes error conditions from "success but
* not overridden". This is because we want to avoid accidentally applying
* the "no data" action in case of error.
* @param raddr: address span that requires an action
* @param action: action to apply
* @param data: RRset to use for override
* @param qtype: original query type
* @param rep: original reply message
* @param rrset_id: the rrset ID in 'rep' to which the action should apply
@ -658,14 +678,15 @@ make_new_reply_info(const struct reply_info* rep, struct regional* region,
* @return 1 if overridden, 0 if not overridden, -1 on error.
*/
static int
respip_data_answer(const struct resp_addr* raddr, enum respip_action action,
respip_data_answer(enum respip_action action,
struct ub_packed_rrset_key* data,
uint16_t qtype, const struct reply_info* rep,
size_t rrset_id, struct reply_info** new_repp, int tag,
struct config_strlist** tag_datas, size_t tag_datas_size,
char* const* tagname, int num_tags,
struct ub_packed_rrset_key** redirect_rrsetp, struct regional* region)
{
struct ub_packed_rrset_key* rp = raddr->data;
struct ub_packed_rrset_key* rp = data;
struct reply_info* new_rep;
*redirect_rrsetp = NULL;
@ -703,7 +724,7 @@ respip_data_answer(const struct resp_addr* raddr, enum respip_action action,
* to replace the rrset's dname. Note that, unlike local data, we
* rename the dname for other actions than redirect. This is because
* response-ip-data isn't associated to any specific name. */
if(rp == raddr->data) {
if(rp == data) {
rp = copy_rrset(rp, region);
if(!rp)
return -1;
@ -761,6 +782,7 @@ respip_nodata_answer(uint16_t qtype, enum respip_action action,
return 1;
} else if(action == respip_static || action == respip_redirect ||
action == respip_always_nxdomain ||
action == respip_always_nodata ||
action == respip_inform_redirect) {
/* Since we don't know about other types of the owner name,
* we generally return NOERROR/NODATA unless an NXDOMAIN action
@ -794,16 +816,22 @@ populate_action_info(struct respip_action_info* actinfo,
enum respip_action action, const struct resp_addr* raddr,
const struct ub_packed_rrset_key* ATTR_UNUSED(rrset),
int ATTR_UNUSED(tag), const struct respip_set* ATTR_UNUSED(ipset),
int ATTR_UNUSED(action_only), struct regional* region)
int ATTR_UNUSED(action_only), struct regional* region, int rpz_used,
int rpz_log, char* log_name, int rpz_cname_override)
{
if(action == respip_none || !raddr)
return 1;
actinfo->action = action;
actinfo->rpz_used = rpz_used;
actinfo->rpz_log = rpz_log;
actinfo->log_name = log_name;
actinfo->rpz_cname_override = rpz_cname_override;
/* for inform variants, make a copy of the matched address block for
* later logging. We make a copy to proactively avoid disruption if
* and when we allow a dynamic update to the respip tree. */
if(action == respip_inform || action == respip_inform_deny) {
if(action == respip_inform || action == respip_inform_deny ||
rpz_used) {
struct respip_addr_info* a =
regional_alloc_zero(region, sizeof(*a));
if(!a) {
@ -819,12 +847,39 @@ populate_action_info(struct respip_action_info* actinfo,
return 1;
}
static int
respip_use_rpz(struct resp_addr* raddr, struct rpz* r,
enum respip_action* action,
struct ub_packed_rrset_key** data, int* rpz_log, char** log_name,
int* rpz_cname_override, struct regional* region, int* is_rpz)
{
if(r->action_override == RPZ_DISABLED_ACTION) {
*is_rpz = 0;
return 1;
}
else if(r->action_override == RPZ_NO_OVERRIDE_ACTION)
*action = raddr->action;
else
*action = rpz_action_to_respip_action(r->action_override);
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION &&
r->cname_override) {
*data = r->cname_override;
*rpz_cname_override = 1;
}
*rpz_log = r->log;
if(r->log_name)
if(!(*log_name = regional_strdup(region, r->log_name)))
return 0;
*is_rpz = 1;
return 1;
}
int
respip_rewrite_reply(const struct query_info* qinfo,
const struct respip_client_info* cinfo, const struct reply_info* rep,
struct reply_info** new_repp, struct respip_action_info* actinfo,
struct ub_packed_rrset_key** alias_rrset, int search_only,
struct regional* region)
struct regional* region, struct auth_zones* az)
{
const uint8_t* ctaglist;
size_t ctaglen;
@ -837,9 +892,15 @@ respip_rewrite_reply(const struct query_info* qinfo,
size_t rrset_id = 0;
enum respip_action action = respip_none;
int tag = -1;
const struct resp_addr* raddr = NULL;
struct resp_addr* raddr = NULL;
int ret = 1;
struct ub_packed_rrset_key* redirect_rrset = NULL;
struct rpz* r;
struct ub_packed_rrset_key* data = NULL;
int rpz_used = 0;
int rpz_log = 0;
int rpz_cname_override = 0;
char* log_name = NULL;
if(!cinfo)
goto done;
@ -866,7 +927,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->ip_tree, &rrset_id))) {
view->respip_set, &rrset_id))) {
/** for per-view respip directives the action
* can only be direct (i.e. not tag-based) */
action = raddr->action;
@ -875,7 +936,7 @@ respip_rewrite_reply(const struct query_info* qinfo,
if(!raddr && !view->isfirst)
goto done;
}
if(!raddr && ipset && (raddr = respip_addr_lookup(rep, &ipset->ip_tree,
if(!raddr && ipset && (raddr = respip_addr_lookup(rep, ipset,
&rrset_id))) {
action = (enum respip_action)local_data_find_tag_action(
raddr->taglist, raddr->taglen, ctaglist, ctaglen,
@ -883,6 +944,31 @@ respip_rewrite_reply(const struct query_info* qinfo,
(enum localzone_type)raddr->action, &tag,
ipset->tagname, ipset->num_tags);
}
lock_rw_rdlock(&az->rpz_lock);
for(r = az->rpz_first; r && !raddr; r = r->next) {
if(!r->taglist || taglist_intersect(r->taglist,
r->taglistlen, ctaglist, ctaglen)) {
if((raddr = respip_addr_lookup(rep,
r->respip_set, &rrset_id))) {
}
if(raddr) {
if(!respip_use_rpz(raddr, r, &action, &data,
&rpz_log, &log_name, &rpz_cname_override,
region, &rpz_used)) {
log_err("out of memory");
lock_rw_unlock(&raddr->lock);
lock_rw_unlock(&az->rpz_lock);
return 0;
}
if(!rpz_used) {
lock_rw_unlock(&raddr->lock);
raddr = NULL;
actinfo->rpz_disabled++;
}
}
}
}
lock_rw_unlock(&az->rpz_lock);
if(raddr && !search_only) {
int result = 0;
@ -891,10 +977,13 @@ respip_rewrite_reply(const struct query_info* qinfo,
if(action != respip_always_refuse
&& action != respip_always_transparent
&& action != respip_always_nxdomain
&& (result = respip_data_answer(raddr, action,
qinfo->qtype, rep, rrset_id, new_repp, tag, tag_datas,
tag_datas_size, ipset->tagname, ipset->num_tags,
&redirect_rrset, region)) < 0) {
&& action != respip_always_nodata
&& action != respip_always_deny
&& (result = respip_data_answer(action,
(data) ? data : raddr->data, qinfo->qtype, rep,
rrset_id, new_repp, tag, tag_datas, tag_datas_size,
ipset->tagname, ipset->num_tags, &redirect_rrset,
region)) < 0) {
ret = 0;
goto done;
}
@ -925,8 +1014,11 @@ respip_rewrite_reply(const struct query_info* qinfo,
*alias_rrset = redirect_rrset;
/* on success, populate respip result structure */
ret = populate_action_info(actinfo, action, raddr,
redirect_rrset, tag, ipset, search_only, region);
redirect_rrset, tag, ipset, search_only, region,
rpz_used, rpz_log, log_name, rpz_cname_override);
}
if(raddr)
lock_rw_unlock(&raddr->lock);
return ret;
}
@ -981,14 +1073,15 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA ||
qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) &&
qstate->return_msg && qstate->return_msg->rep) {
struct respip_action_info actinfo = {respip_none, NULL};
struct reply_info* new_rep = qstate->return_msg->rep;
struct ub_packed_rrset_key* alias_rrset = NULL;
struct respip_action_info actinfo = {0};
actinfo.action = respip_none;
if(!respip_rewrite_reply(&qstate->qinfo,
qstate->client_info, qstate->return_msg->rep,
&new_rep, &actinfo, &alias_rrset, 0,
qstate->region)) {
qstate->region, qstate->env->auth_zones)) {
goto servfail;
}
if(actinfo.action != respip_none) {
@ -1004,9 +1097,10 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
} else {
qstate->respip_action_info = NULL;
}
if (new_rep == qstate->return_msg->rep &&
if (actinfo.action == respip_always_deny ||
(new_rep == qstate->return_msg->rep &&
(actinfo.action == respip_deny ||
actinfo.action == respip_inform_deny)) {
actinfo.action == respip_inform_deny))) {
/* for deny-variant actions (unless response-ip
* data is applied), mark the query state so
* the response will be dropped for all
@ -1034,14 +1128,16 @@ int
respip_merge_cname(struct reply_info* base_rep,
const struct query_info* qinfo, const struct reply_info* tgt_rep,
const struct respip_client_info* cinfo, int must_validate,
struct reply_info** new_repp, struct regional* region)
struct reply_info** new_repp, struct regional* region,
struct auth_zones* az)
{
struct reply_info* new_rep;
struct reply_info* tmp_rep = NULL; /* just a placeholder */
struct ub_packed_rrset_key* alias_rrset = NULL; /* ditto */
uint16_t tgt_rcode;
size_t i, j;
struct respip_action_info actinfo = {respip_none, NULL};
struct respip_action_info actinfo = {0};
actinfo.action = respip_none;
/* If the query for the CNAME target would result in an unusual rcode,
* we generally translate it as a failure for the base query
@ -1060,7 +1156,7 @@ respip_merge_cname(struct reply_info* base_rep,
/* see if the target reply would be subject to a response-ip action. */
if(!respip_rewrite_reply(qinfo, cinfo, tgt_rep, &tmp_rep, &actinfo,
&alias_rrset, 1, region))
&alias_rrset, 1, region, az))
return 0;
if(actinfo.action != respip_none) {
log_info("CNAME target of redirect response-ip action would "
@ -1112,7 +1208,8 @@ respip_inform_super(struct module_qstate* qstate, int id,
if(!respip_merge_cname(super->return_msg->rep, &qstate->qinfo,
qstate->return_msg->rep, super->client_info,
super->env->need_to_validate, &new_rep, super->region))
super->env->need_to_validate, &new_rep, super->region,
qstate->env->auth_zones))
goto fail;
super->return_msg->rep = new_rep;
return;
@ -1171,12 +1268,15 @@ respip_set_is_empty(const struct respip_set* set)
}
void
respip_inform_print(struct respip_addr_info* respip_addr, uint8_t* qname,
respip_inform_print(struct respip_action_info* respip_actinfo, uint8_t* qname,
uint16_t qtype, uint16_t qclass, struct local_rrset* local_alias,
struct comm_reply* repinfo)
{
char srcip[128], respip[128], txt[512];
unsigned port;
struct respip_addr_info* respip_addr = respip_actinfo->addrinfo;
size_t txtlen = 0;
const char* actionstr = NULL;
if(local_alias)
qname = local_alias->rrset->rk.dname;
@ -1186,7 +1286,23 @@ respip_inform_print(struct respip_addr_info* respip_addr, uint8_t* qname,
addr_to_str(&repinfo->addr, repinfo->addrlen, srcip, sizeof(srcip));
addr_to_str(&respip_addr->addr, respip_addr->addrlen,
respip, sizeof(respip));
snprintf(txt, sizeof(txt), "%s/%d inform %s@%u", respip,
respip_addr->net, srcip, port);
if(respip_actinfo->rpz_log) {
txtlen += snprintf(txt+txtlen, sizeof(txt)-txtlen, "%s",
"RPZ applied ");
if(respip_actinfo->rpz_cname_override)
actionstr = rpz_action_to_string(
RPZ_CNAME_OVERRIDE_ACTION);
else
actionstr = rpz_action_to_string(
respip_action_to_rpz_action(
respip_actinfo->action));
}
if(respip_actinfo->log_name) {
txtlen += snprintf(txt+txtlen, sizeof(txt)-txtlen,
"[%s] ", respip_actinfo->log_name);
}
snprintf(txt+txtlen, sizeof(txt)-txtlen,
"%s/%d %s %s@%u", respip, respip_addr->net,
(actionstr) ? actionstr : "inform", srcip, port);
log_nametypeclass(NO_VERBOSE, txt, qname, qtype, qclass);
}

View File

@ -14,23 +14,42 @@
#include "util/module.h"
#include "services/localzone.h"
#include "util/locks.h"
/**
* Set of response IP addresses with associated actions and tags.
* Forward declaration only here. Actual definition is hidden within the
* module.
* Conceptual set of IP addresses for response AAAA or A records that should
* trigger special actions.
*/
struct respip_set;
struct respip_set {
struct regional* region;
struct rbtree_type ip_tree;
lock_rw_type lock; /* lock on the respip tree */
char* const* tagname; /* shallow copy of tag names, for logging */
int num_tags; /* number of tagname entries */
};
/** An address span with response control information */
struct resp_addr {
/** 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 respip_action action;
/** "local data" for this node */
struct ub_packed_rrset_key* data;
};
/**
* Forward declaration for the structure that represents a node in the
* respip_set address tree
*/
struct resp_addr;
/**
* Forward declaration for the structure that represents a tree of view data.
*/
struct views;
struct respip_addr_info;
@ -60,6 +79,11 @@ struct respip_client_info {
*/
struct respip_action_info {
enum respip_action action;
int rpz_used;
int rpz_log;
int rpz_disabled;
char* log_name;
int rpz_cname_override;
struct respip_addr_info* addrinfo; /* set only for inform variants */
};
@ -124,12 +148,14 @@ int respip_views_apply_cfg(struct views* vs, struct config_file* cfg,
* @param new_repp: pointer placeholder for the merged reply. will be intact
* on error.
* @param region: allocator to build *new_repp.
* @param az: auth zones containing RPZ information.
* @return 1 on success, 0 on error.
*/
int respip_merge_cname(struct reply_info* base_rep,
const struct query_info* qinfo, const struct reply_info* tgt_rep,
const struct respip_client_info* cinfo, int must_validate,
struct reply_info** new_repp, struct regional* region);
struct reply_info** new_repp, struct regional* region,
struct auth_zones* az);
/**
* See if any IP-based action should apply to any IP address of AAAA/A answer
@ -148,6 +174,7 @@ int respip_merge_cname(struct reply_info* base_rep,
* @param alias_rrset: must not be NULL.
* @param search_only: if true, only check if an action would apply. actionp
* will be set (or intact) accordingly but the modified reply won't be built.
* @param az: auth zones containing RPZ information.
* @param region: allocator to build *new_repp.
* @return 1 on success, 0 on error.
*/
@ -156,7 +183,7 @@ int respip_rewrite_reply(const struct query_info* qinfo,
const struct reply_info *rep, struct reply_info** new_repp,
struct respip_action_info* actinfo,
struct ub_packed_rrset_key** alias_rrset,
int search_only, struct regional* region);
int search_only, struct regional* region, struct auth_zones* az);
/**
* Get the response-ip function block.
@ -213,7 +240,7 @@ int respip_set_is_empty(const struct respip_set* set);
/**
* print log information for a query subject to an inform or inform-deny
* response-ip action.
* @param respip_addr: response-ip information that causes the action
* @param respip_actinfo: response-ip information that causes the action
* @param qname: query name in the context, will be ignored if local_alias is
* non-NULL.
* @param qtype: query type, in host byte order.
@ -223,8 +250,48 @@ int respip_set_is_empty(const struct respip_set* set);
* query name.
* @param repinfo: reply info containing the client's source address and port.
*/
void respip_inform_print(struct respip_addr_info* respip_addr, uint8_t* qname,
uint16_t qtype, uint16_t qclass, struct local_rrset* local_alias,
struct comm_reply* repinfo);
void respip_inform_print(struct respip_action_info* respip_actinfo,
uint8_t* qname, uint16_t qtype, uint16_t qclass,
struct local_rrset* local_alias, struct comm_reply* repinfo);
/**
* Find resp_addr in tree, create and add to tree if it does not exist.
* @param set: struct containing the tree and region to alloc new node on.
* should hold write lock.
* @param addr: address to look up.
* @param addrlen: length of addr.
* @param net: netblock to lookup.
* @param create: create node if it does not exist when 1.
* @param ipstr: human redable ip string, for logging.
* @return newly created of found node, not holding lock.
*/
struct resp_addr*
respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage* addr,
socklen_t addrlen, int net, int create, const char* ipstr);
/**
* Add RR to resp_addr's RRset. Create RRset if not existing.
* @param region: region to alloc RR(set).
* @param raddr: resp_addr containing RRset. Must hold write lock.
* @param rrtype: RR type.
* @param rrclass: RR class.
* @param ttl: TTL.
* @param rdata: RDATA.
* @param rdata_len: length of rdata.
* @param rrstr: RR as string, for logging
* @param netblockstr: netblock as string, for logging
* @return 0 on error
*/
int
respip_enter_rr(struct regional* region, struct resp_addr* raddr,
uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata,
size_t rdata_len, const char* rrstr, const char* netblockstr);
/**
* Delete resp_addr node from tree.
* @param set: struct containing tree. Must hold write lock.
* @param node: node to delete. Not locked.
*/
void
respip_sockaddr_delete(struct respip_set* set, struct resp_addr* node);
#endif /* RESPIP_RESPIP_H */

View File

@ -381,11 +381,25 @@ auth_data_del(rbnode_type* n, void* ATTR_UNUSED(arg))
/** delete an auth zone structure (tree remove must be done elsewhere) */
static void
auth_zone_delete(struct auth_zone* z)
auth_zone_delete(struct auth_zone* z, struct auth_zones* az)
{
if(!z) return;
lock_rw_destroy(&z->lock);
traverse_postorder(&z->data, auth_data_del, NULL);
if(az && z->rpz) {
/* keep RPZ linked list intact */
lock_rw_wrlock(&az->rpz_lock);
if(z->rpz->prev)
z->rpz->prev->next = z->rpz->next;
else
az->rpz_first = z->rpz->next;
if(z->rpz->next)
z->rpz->next->prev = z->rpz->prev;
lock_rw_unlock(&az->rpz_lock);
}
if(z->rpz)
rpz_delete(z->rpz);
free(z->name);
free(z->zonefile);
free(z);
@ -415,7 +429,7 @@ auth_zone_create(struct auth_zones* az, uint8_t* nm, size_t nmlen,
/* z lock protects all, except rbtree itself, which is az->lock */
if(!rbtree_insert(&az->ztree, &z->node)) {
lock_rw_unlock(&z->lock);
auth_zone_delete(z);
auth_zone_delete(z, NULL);
log_warn("duplicate auth zone");
return NULL;
}
@ -660,23 +674,6 @@ domain_remove_rrset(struct auth_data* node, uint16_t rr_type)
}
}
/** find an rr index in the rrset. returns true if found */
static int
az_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
size_t* index)
{
size_t i;
for(i=0; i<d->count; i++) {
if(d->rr_len[i] != len)
continue;
if(memcmp(d->rr_data[i], rdata, len) == 0) {
*index = i;
return 1;
}
}
return 0;
}
/** find an rrsig index in the rrset. returns true if found */
static int
az_rrset_find_rrsig(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
@ -1178,6 +1175,12 @@ az_insert_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len,
log_err("cannot add RR to domain");
return 0;
}
if(z->rpz) {
if(!(rpz_insert_rr(z->rpz, z->namelen, dname, dname_len,
rr_type, rr_class, rr_ttl, rdata, rdatalen, rr,
rr_len)))
return 0;
}
return 1;
}
@ -1192,7 +1195,7 @@ az_domain_remove_rr(struct auth_data* node, uint16_t rr_type,
/* find the plain RR of the given type */
if((rrset=az_domain_rrset(node, rr_type))!= NULL) {
if(az_rrset_find_rr(rrset->data, rdata, rdatalen, &index)) {
if(packed_rrset_find_rr(rrset->data, rdata, rdatalen, &index)) {
if(rrset->data->count == 1 &&
rrset->data->rrsig_count == 0) {
/* last RR, delete the rrset */
@ -1293,6 +1296,10 @@ az_remove_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len,
(void)rbtree_delete(&z->data, node);
auth_data_delete(node);
}
if(z->rpz) {
rpz_remove_rr(z->rpz, z->namelen, dname, dname_len, rr_type,
rr_class, rdata, rdatalen);
}
return 1;
}
@ -1585,6 +1592,9 @@ auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg)
/* clear the data tree */
traverse_postorder(&z->data, auth_data_del, NULL);
rbtree_init(&z->data, &auth_data_cmp);
/* clear the RPZ policies */
if(z->rpz)
rpz_clear(z->rpz);
memset(&state, 0, sizeof(state));
/* default TTL to 3600 */
@ -1604,6 +1614,9 @@ auth_zone_read_zonefile(struct auth_zone* z, struct config_file* cfg)
return 0;
}
fclose(in);
if(z->rpz)
rpz_finish_config(z->rpz);
return 1;
}
@ -1877,6 +1890,18 @@ auth_zones_cfg(struct auth_zones* az, struct config_auth* c)
z->for_downstream = c->for_downstream;
z->for_upstream = c->for_upstream;
z->fallback_enabled = c->fallback_enabled;
if(c->isrpz && !z->rpz){
if(!(z->rpz = rpz_create(c))){
fatal_exit("Could not setup RPZ zones");
return 0;
}
lock_rw_wrlock(&az->rpz_lock);
z->rpz->next = az->rpz_first;
if(az->rpz_first)
az->rpz_first->prev = z->rpz;
az->rpz_first = z->rpz;
lock_rw_unlock(&az->rpz_lock);
}
/* xfer zone */
if(x) {
@ -1947,14 +1972,14 @@ az_delete_deleted_zones(struct auth_zones* az)
auth_xfer_delete(xfr);
}
(void)rbtree_delete(&az->ztree, &z->node);
auth_zone_delete(z);
auth_zone_delete(z, az);
z = next;
}
lock_rw_unlock(&az->lock);
}
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
int setup)
int setup, int* is_rpz)
{
struct config_auth* p;
az_setall_deleted(az);
@ -1963,6 +1988,7 @@ int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
log_warn("auth-zone without a name, skipped");
continue;
}
*is_rpz = (*is_rpz || p->isrpz);
if(!auth_zones_cfg(az, p)) {
log_err("cannot config auth zone %s", p->name);
return 0;
@ -2063,7 +2089,7 @@ static void
auth_zone_del(rbnode_type* n, void* ATTR_UNUSED(arg))
{
struct auth_zone* z = (struct auth_zone*)n->key;
auth_zone_delete(z);
auth_zone_delete(z, NULL);
}
/** helper traverse to delete xfer zones */
@ -4690,6 +4716,10 @@ apply_axfr(struct auth_xfer* xfr, struct auth_zone* z,
/* clear the data tree */
traverse_postorder(&z->data, auth_data_del, NULL);
rbtree_init(&z->data, &auth_data_cmp);
/* clear the RPZ policies */
if(z->rpz)
rpz_clear(z->rpz);
xfr->have_zone = 0;
xfr->serial = 0;
@ -4786,6 +4816,10 @@ apply_http(struct auth_xfer* xfr, struct auth_zone* z,
/* clear the data tree */
traverse_postorder(&z->data, auth_data_del, NULL);
rbtree_init(&z->data, &auth_data_cmp);
/* clear the RPZ policies */
if(z->rpz)
rpz_clear(z->rpz);
xfr->have_zone = 0;
xfr->serial = 0;
@ -4971,6 +5005,9 @@ xfr_process_chunk_list(struct auth_xfer* xfr, struct module_env* env,
if(xfr->have_zone)
xfr->lease_time = *env->now;
if(z->rpz)
rpz_finish_config(z->rpz);
/* unlock */
lock_rw_unlock(&z->lock);

View File

@ -46,6 +46,7 @@
#include "util/rbtree.h"
#include "util/locks.h"
#include "services/mesh.h"
#include "services/rpz.h"
struct ub_packed_rrset_key;
struct regional;
struct config_file;
@ -81,6 +82,11 @@ struct auth_zones {
size_t num_query_up;
/** number of queries downstream */
size_t num_query_down;
/** first rpz item in linked list */
struct rpz* rpz_first;
/** rw lock for rpz linked list, needed when iterating or editing linked
* list. */
lock_rw_type rpz_lock;
};
/**
@ -126,6 +132,8 @@ struct auth_zone {
/** for upstream: this zone answers queries that unbound intends to
* send upstream. */
int for_upstream;
/** RPZ zones */
struct rpz* rpz;
/** zone has been deleted */
int zone_deleted;
/** deletelist pointer, unused normally except during delete */
@ -460,10 +468,11 @@ struct auth_zones* auth_zones_create(void);
* @param az: auth zones structure
* @param cfg: config to apply.
* @param setup: if true, also sets up values in the auth zones structure
* @param is_rpz: set to 1 if at least one RPZ zone is configured.
* @return false on failure.
*/
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
int setup);
int setup, int* is_rpz);
/** initial pick up of worker timeouts, ties events to worker event loop
* @param az: auth zones structure

View File

@ -41,7 +41,6 @@
#include "config.h"
#include "services/localzone.h"
#include "sldns/str2wire.h"
#include "sldns/sbuffer.h"
#include "util/regional.h"
#include "util/config_file.h"
#include "util/data/dname.h"
@ -395,9 +394,30 @@ rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
return 1;
}
/** find a data node by exact name */
static struct local_data*
lz_find_node(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs)
/** Delete RR from local-zone RRset, wastes memory as the deleted RRs cannot be
* free'd (regionally alloc'd) */
int
local_rrset_remove_rr(struct packed_rrset_data* pd, size_t index)
{
log_assert(pd->count > 0);
if(index >= pd->count) {
log_warn("Trying to remove RR with out of bound index");
return 0;
}
if(index + 1 < pd->count) {
/* not removing last element */
size_t nexti = index + 1;
size_t num = pd->count - nexti;
memmove(pd->rr_len+index, pd->rr_len+nexti, sizeof(*pd->rr_len)*num);
memmove(pd->rr_ttl+index, pd->rr_ttl+nexti, sizeof(*pd->rr_ttl)*num);
memmove(pd->rr_data+index, pd->rr_data+nexti, sizeof(*pd->rr_data)*num);
}
pd->count--;
return 1;
}
struct local_data*
local_zone_find_data(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs)
{
struct local_data key;
key.node.key = &key;
@ -412,7 +432,7 @@ static int
lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
int nmlabs, struct local_data** res)
{
struct local_data* ld = lz_find_node(z, nm, nmlen, nmlabs);
struct local_data* ld = local_zone_find_data(z, nm, nmlen, nmlabs);
if(!ld) {
/* create a domain name to store rr. */
ld = (struct local_data*)regional_alloc_zero(z->region,
@ -443,42 +463,19 @@ lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
return 1;
}
/** enter data RR into auth zone */
static int
lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr)
int
local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
int nmlabs, uint16_t rrtype, uint16_t rrclass, time_t ttl,
uint8_t* rdata, size_t rdata_len, const char* rrstr)
{
uint8_t* nm;
size_t nmlen;
int nmlabs;
struct local_data* node;
struct local_rrset* rrset;
struct packed_rrset_data* pd;
uint16_t rrtype = 0, rrclass = 0;
time_t ttl = 0;
uint8_t rr[LDNS_RR_BUF_SIZE];
uint8_t* rdata;
size_t rdata_len;
if(!rrstr_get_rr_content(rrstr, &nm, &rrtype, &rrclass, &ttl, rr,
sizeof(rr), &rdata, &rdata_len)) {
log_err("bad local-data: %s", rrstr);
return 0;
}
log_assert(z->dclass == rrclass);
if((z->type == local_zone_redirect ||
z->type == local_zone_inform_redirect) &&
query_dname_compare(z->name, nm) != 0) {
log_err("local-data in redirect zone must reside at top of zone"
", not at %s", rrstr);
free(nm);
return 0;
}
nmlabs = dname_count_size_labels(nm, &nmlen);
if(!lz_find_create_node(z, nm, nmlen, nmlabs, &node)) {
free(nm);
return 0;
}
log_assert(node);
free(nm);
/* Reject it if we would end up having CNAME and other data (including
* another CNAME) for a redirect zone. */
@ -520,6 +517,39 @@ lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr)
return rrset_insert_rr(z->region, pd, rdata, rdata_len, ttl, rrstr);
}
/** enter data RR into auth zone */
int
lz_enter_rr_into_zone(struct local_zone* z, const char* rrstr)
{
uint8_t* nm;
size_t nmlen;
int nmlabs, ret;
uint16_t rrtype = 0, rrclass = 0;
time_t ttl = 0;
uint8_t rr[LDNS_RR_BUF_SIZE];
uint8_t* rdata;
size_t rdata_len;
if(!rrstr_get_rr_content(rrstr, &nm, &rrtype, &rrclass, &ttl, rr,
sizeof(rr), &rdata, &rdata_len)) {
log_err("bad local-data: %s", rrstr);
return 0;
}
log_assert(z->dclass == rrclass);
if((z->type == local_zone_redirect ||
z->type == local_zone_inform_redirect) &&
query_dname_compare(z->name, nm) != 0) {
log_err("local-data in redirect zone must reside at top of zone"
", not at %s", rrstr);
free(nm);
return 0;
}
nmlabs = dname_count_size_labels(nm, &nmlen);
ret = local_zone_enter_rr(z, nm, nmlen, nmlabs, rrtype, rrclass, ttl,
rdata, rdata_len, rrstr);
free(nm);
return ret;
}
/** enter a data RR into auth data; a zone for it must exist */
static int
lz_enter_rr_str(struct local_zones* zones, const char* rr)
@ -1113,6 +1143,22 @@ local_zones_find(struct local_zones* zones,
return (struct local_zone*)rbtree_search(&zones->ztree, &key);
}
struct local_zone*
local_zones_find_le(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass,
int* exact)
{
struct local_zone key;
rbnode_type *node;
key.node.key = &key;
key.dclass = dclass;
key.name = name;
key.namelen = len;
key.namelabs = labs;
*exact = rbtree_find_less_equal(&zones->ztree, &key, &node);
return (struct local_zone*)node;
}
/** print all RRsets in local zone */
static void
local_zone_out(struct local_zone* z)
@ -1309,8 +1355,7 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
return result;
}
/** answer local data match */
static int
int
local_data_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf,
@ -1362,16 +1407,69 @@ local_data_answer(struct local_zone* z, struct module_env* env,
lz_type == local_zone_inform_redirect) &&
qinfo->qtype != LDNS_RR_TYPE_CNAME &&
lr->rrset->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
uint8_t* ctarget;
size_t ctargetlen = 0;
qinfo->local_alias =
regional_alloc_zero(temp, sizeof(struct local_rrset));
if(!qinfo->local_alias)
return 0; /* out of memory */
qinfo->local_alias->rrset =
regional_alloc_init(temp, lr->rrset, sizeof(*lr->rrset));
qinfo->local_alias->rrset = regional_alloc_init(
temp, lr->rrset, sizeof(*lr->rrset));
if(!qinfo->local_alias->rrset)
return 0; /* out of memory */
qinfo->local_alias->rrset->rk.dname = qinfo->qname;
qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
get_cname_target(lr->rrset, &ctarget, &ctargetlen);
if(!ctargetlen)
return 0; /* invalid cname */
if(dname_is_wild(ctarget)) {
/* synthesize cname target */
struct packed_rrset_data* d;
/* -3 for wildcard label and root label from qname */
size_t newtargetlen = qinfo->qname_len + ctargetlen - 3;
log_assert(ctargetlen >= 3);
log_assert(qinfo->qname_len >= 1);
if(newtargetlen > LDNS_MAX_DOMAINLEN) {
qinfo->local_alias = NULL;
local_error_encode(qinfo, env, edns, repinfo,
buf, temp, LDNS_RCODE_YXDOMAIN,
(LDNS_RCODE_YXDOMAIN|BIT_AA));
return 1;
}
memset(&qinfo->local_alias->rrset->entry, 0,
sizeof(qinfo->local_alias->rrset->entry));
qinfo->local_alias->rrset->entry.key =
qinfo->local_alias->rrset;
qinfo->local_alias->rrset->entry.hash =
rrset_key_hash(&qinfo->local_alias->rrset->rk);
d = (struct packed_rrset_data*)regional_alloc_zero(temp,
sizeof(struct packed_rrset_data) + sizeof(size_t) +
sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t)
+ newtargetlen);
if(!d)
return 0; /* out of memory */
qinfo->local_alias->rrset->entry.data = d;
d->ttl = 0; /* 0 for synthesized CNAME TTL */
d->count = 1;
d->rrsig_count = 0;
d->trust = rrset_trust_ans_noAA;
d->rr_len = (size_t*)((uint8_t*)d +
sizeof(struct packed_rrset_data));
d->rr_len[0] = newtargetlen + sizeof(uint16_t);
packed_rrset_ptr_fixup(d);
d->rr_ttl[0] = d->ttl;
sldns_write_uint16(d->rr_data[0], newtargetlen);
/* write qname */
memmove(d->rr_data[0] + sizeof(uint16_t), qinfo->qname,
qinfo->qname_len - 1);
/* write cname target wilcard wildcard label */
memmove(d->rr_data[0] + sizeof(uint16_t) +
qinfo->qname_len - 1, ctarget + 2,
ctargetlen - 2);
}
return 1;
}
if(lz_type == local_zone_redirect ||
@ -1416,26 +1514,15 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
return (lr == NULL);
}
/**
* Answer in case where no exact match is found.
* @param z: zone for query.
* @param env: module environment.
* @param qinfo: query.
* @param edns: edns from query.
* @param repinfo: source address for checks. may be NULL.
* @param buf: buffer for answer.
* @param temp: temp region for encoding.
* @param ld: local data, if NULL, no such name exists in localdata.
* @param lz_type: type of the local zone.
* @return 1 if a reply is to be sent, 0 if not.
*/
static int
lz_zone_answer(struct local_zone* z, struct module_env* env,
int
local_zones_zone_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
struct local_data* ld, enum localzone_type lz_type)
{
if(lz_type == local_zone_deny || lz_type == local_zone_inform_deny) {
if(lz_type == local_zone_deny ||
lz_type == local_zone_always_deny ||
lz_type == local_zone_inform_deny) {
/** no reply at all, signal caller by clearing buffer. */
sldns_buffer_clear(buf);
sldns_buffer_flip(buf);
@ -1448,7 +1535,8 @@ lz_zone_answer(struct local_zone* z, struct module_env* env,
} else if(lz_type == local_zone_static ||
lz_type == local_zone_redirect ||
lz_type == local_zone_inform_redirect ||
lz_type == local_zone_always_nxdomain) {
lz_type == local_zone_always_nxdomain ||
lz_type == local_zone_always_nodata) {
/* for static, reply nodata or nxdomain
* for redirect, reply nodata */
/* no additional section processing,
@ -1457,7 +1545,8 @@ lz_zone_answer(struct local_zone* z, struct module_env* env,
* or using closest match for returning delegation downwards
*/
int rcode = (ld || lz_type == local_zone_redirect ||
lz_type == local_zone_inform_redirect)?
lz_type == local_zone_inform_redirect ||
lz_type == local_zone_always_nodata)?
LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
if(z->soa)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
@ -1640,6 +1729,8 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
if(lzt != local_zone_always_refuse
&& lzt != local_zone_always_transparent
&& lzt != local_zone_always_nxdomain
&& lzt != local_zone_always_nodata
&& lzt != local_zone_always_deny
&& local_data_answer(z, env, qinfo, edns, repinfo, buf, temp, labs,
&ld, lzt, tag, tag_datas, tag_datas_size, tagname, num_tags)) {
lock_rw_unlock(&z->lock);
@ -1647,7 +1738,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
* a local alias. */
return !qinfo->local_alias;
}
r = lz_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt);
r = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp, ld, lzt);
lock_rw_unlock(&z->lock);
return r && !qinfo->local_alias; /* see above */
}
@ -1669,7 +1760,10 @@ const char* local_zone_type2str(enum localzone_type t)
case local_zone_always_transparent: return "always_transparent";
case local_zone_always_refuse: return "always_refuse";
case local_zone_always_nxdomain: return "always_nxdomain";
case local_zone_always_nodata: return "always_nodata";
case local_zone_always_deny: return "always_deny";
case local_zone_noview: return "noview";
case local_zone_invalid: return "invalid";
}
return "badtyped";
}
@ -1700,6 +1794,10 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
*t = local_zone_always_refuse;
else if(strcmp(type, "always_nxdomain") == 0)
*t = local_zone_always_nxdomain;
else if(strcmp(type, "always_nodata") == 0)
*t = local_zone_always_nodata;
else if(strcmp(type, "always_deny") == 0)
*t = local_zone_always_deny;
else if(strcmp(type, "noview") == 0)
*t = local_zone_noview;
else if(strcmp(type, "nodefault") == 0)
@ -1843,7 +1941,7 @@ del_empty_term(struct local_zone* z, struct local_data* d,
return;
dname_remove_label(&name, &len);
labs--;
d = lz_find_node(z, name, len, labs);
d = local_zone_find_data(z, name, len, labs);
}
}
@ -1876,7 +1974,7 @@ void local_zones_del_data(struct local_zones* zones,
z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS);
if(z) {
lock_rw_wrlock(&z->lock);
d = lz_find_node(z, name, len, labs);
d = local_zone_find_data(z, name, len, labs);
if(d) {
del_local_rrset(d, LDNS_RR_TYPE_DS);
del_empty_term(z, d, name, len, labs);
@ -1897,7 +1995,7 @@ void local_zones_del_data(struct local_zones* zones,
lock_rw_unlock(&zones->lock);
/* find the domain */
d = lz_find_node(z, name, len, labs);
d = local_zone_find_data(z, name, len, labs);
if(d) {
/* no memory recycling for zone deletions ... */
d->rrsets = NULL;

View File

@ -46,6 +46,7 @@
#include "util/storage/dnstree.h"
#include "util/module.h"
#include "services/view.h"
#include "sldns/sbuffer.h"
struct packed_rrset_data;
struct ub_packed_rrset_key;
struct regional;
@ -91,8 +92,14 @@ enum localzone_type {
local_zone_always_refuse,
/** answer with nxdomain, even when there is local data */
local_zone_always_nxdomain,
/** answer with noerror/nodata, even when there is local data */
local_zone_always_nodata,
/** drop query, even when there is local data */
local_zone_always_deny,
/** answer not from the view, but global or no-answer */
local_zone_noview
local_zone_noview,
/** Invalid type, cannot be used to generate answer */
local_zone_invalid
};
/**
@ -310,6 +317,25 @@ int local_zones_answer(struct local_zones* zones, struct module_env* env,
struct config_strlist** tag_datas, size_t tag_datas_size,
char** tagname, int num_tags, struct view* view);
/**
* Answer using the local zone only (not local data used).
* @param z: zone for query.
* @param env: module environment.
* @param qinfo: query.
* @param edns: edns from query.
* @param repinfo: source address for checks. may be NULL.
* @param buf: buffer for answer.
* @param temp: temp region for encoding.
* @param ld: local data, if NULL, no such name exists in localdata.
* @param lz_type: type of the local zone.
* @return 1 if a reply is to be sent, 0 if not.
*/
int
local_zones_zone_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf, struct regional* temp,
struct local_data* ld, enum localzone_type lz_type);
/**
* Parse the string into localzone type.
*
@ -340,6 +366,22 @@ const char* local_zone_type2str(enum localzone_type t);
struct local_zone* local_zones_find(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass);
/**
* Find zone that with exactly or smaller name/class
* User must lock the tree or result zone.
* @param zones: the zones tree
* @param name: dname to lookup
* @param len: length of name.
* @param labs: labelcount of name.
* @param dclass: class to lookup.
* @param exact: 1 on return is this is an exact match.
* @return the exact or smaller local_zone or NULL.
*/
struct local_zone*
local_zones_find_le(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass,
int* exact);
/**
* Add a new zone. Caller must hold the zones lock.
* Adjusts the other zones as well (parent pointers) after insertion.
@ -473,6 +515,15 @@ int rrstr_get_rr_content(const char* str, uint8_t** nm, uint16_t* type,
int rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr);
/**
* Remove RR from rrset that is created using localzone's rrset_insert_rr.
* @param pd: the RRset containing the RR to remove
* @param index: index of RR to remove
* @return: 1 on success; 0 otherwise.
*/
int
local_rrset_remove_rr(struct packed_rrset_data* pd, size_t index);
/**
* Valid response ip actions for the IP-response-driven-action feature;
* defined here instead of in the respip module to enable sharing of enum
@ -501,6 +552,10 @@ enum respip_action {
respip_always_refuse = local_zone_always_refuse,
/** answer with 'no such domain' response */
respip_always_nxdomain = local_zone_always_nxdomain,
/** answer with nodata response */
respip_always_nodata = local_zone_always_nodata,
/** answer with nodata response */
respip_always_deny = local_zone_always_deny,
/* The rest of the values are only possible as
* access-control-tag-action */
@ -513,6 +568,64 @@ enum respip_action {
respip_transparent = local_zone_transparent,
/** gives response data (if any), else nodata answer. */
respip_typetransparent = local_zone_typetransparent,
/** type invalid */
respip_invalid = local_zone_invalid,
};
/**
* Get local data from local zone and encode answer.
* @param z: local zone to use
* @param env: module env
* @param qinfo: qinfo
* @param edns: edns data, for message encoding
* @param repinfo: reply info, for message encoding
* @param buf: commpoint buffer
* @param temp: scratchpad region
* @param labs: number of labels in qname
* @param ldp: where to store local data
* @param lz_type: type of local zone
* @param tag: matching tag index
* @param tag_datas: alc specific tag data list
* @param tag_datas_size: size of tag_datas
* @param tagname: list of names of tags, for logging purpose
* @param num_tags: number of tags
* @return 1 on success
*/
int
local_data_answer(struct local_zone* z, struct module_env* env,
struct query_info* qinfo, struct edns_data* edns,
struct comm_reply* repinfo, sldns_buffer* buf,
struct regional* temp, int labs, struct local_data** ldp,
enum localzone_type lz_type, int tag, struct config_strlist** tag_datas,
size_t tag_datas_size, char** tagname, int num_tags);
/**
* Add RR to local zone.
* @param z: local zone to add RR to
* @param nm: dname of RR
* @param nmlen: length of nm
* @param nmlabs: number of labels of nm
* @param rrtype: RR type
* @param rrclass: RR class
* @param ttl: TTL of RR to add
* @param rdata: RDATA of RR to add
* @param rdata_len: length of rdata
* @param rrstr: RR in string format, for logging
* @return: 1 on success
*/
int
local_zone_enter_rr(struct local_zone* z, uint8_t* nm, size_t nmlen,
int nmlabs, uint16_t rrtype, uint16_t rrclass, time_t ttl,
uint8_t* rdata, size_t rdata_len, const char* rrstr);
/**
* Find a data node by exact name for a local zone
* @param z: local_zone containing data tree
* @param nm: name of local-data element to find
* @param nmlen: length of nm
* @param nmlabs: labs of nm
* @return local_data on exact match, NULL otherwise.
*/
struct local_data*
local_zone_find_data(struct local_zone* z, uint8_t* nm, size_t nmlen, int nmlabs);
#endif /* SERVICES_LOCALZONE_H */

View File

@ -1184,10 +1184,21 @@ void mesh_query_done(struct mesh_state* mstate)
* information should be logged for each client. */
if(mstate->s.respip_action_info &&
mstate->s.respip_action_info->addrinfo) {
respip_inform_print(mstate->s.respip_action_info->addrinfo,
respip_inform_print(mstate->s.respip_action_info,
r->qname, mstate->s.qinfo.qtype,
mstate->s.qinfo.qclass, r->local_alias,
&r->query_reply);
if(mstate->s.env->cfg->stat_extended &&
mstate->s.respip_action_info->rpz_used) {
if(mstate->s.respip_action_info->rpz_disabled)
mstate->s.env->mesh->rpz_action[RPZ_DISABLED_ACTION] +=
mstate->s.respip_action_info->rpz_disabled;
if(mstate->s.respip_action_info->rpz_cname_override)
mstate->s.env->mesh->rpz_action[RPZ_CNAME_OVERRIDE_ACTION]++;
else
mstate->s.env->mesh->rpz_action[respip_action_to_rpz_action(
mstate->s.respip_action_info->action)]++;
}
}
/* if this query is determined to be dropped during the
@ -1581,7 +1592,8 @@ mesh_stats_clear(struct mesh_area* mesh)
timehist_clear(mesh->histogram);
mesh->ans_secure = 0;
mesh->ans_bogus = 0;
memset(&mesh->ans_rcode[0], 0, sizeof(size_t)*16);
memset(&mesh->ans_rcode[0], 0, sizeof(size_t)*UB_STATS_RCODE_NUM);
memset(&mesh->rpz_action[0], 0, sizeof(size_t)*UB_STATS_RPZ_ACTION_NUM);
mesh->ans_nodata = 0;
}

View File

@ -51,6 +51,8 @@
#include "util/data/msgparse.h"
#include "util/module.h"
#include "services/modstack.h"
#include "services/rpz.h"
#include "libunbound/unbound.h"
struct sldns_buffer;
struct mesh_state;
struct mesh_reply;
@ -121,9 +123,11 @@ struct mesh_area {
/** (extended stats) bogus replies */
size_t ans_bogus;
/** (extended stats) rcodes in replies */
size_t ans_rcode[16];
size_t ans_rcode[UB_STATS_RCODE_NUM];
/** (extended stats) rcode nodata in replies */
size_t ans_nodata;
/** (extended stats) type of applied RPZ action */
size_t rpz_action[UB_STATS_RPZ_ACTION_NUM];
/** backup of query if other operations recurse and need the
* network buffers */

1013
services/rpz.c Normal file

File diff suppressed because it is too large Load Diff

201
services/rpz.h Normal file
View File

@ -0,0 +1,201 @@
/*
* services/rpz.h - rpz service
*
* Copyright (c) 2019, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file contains functions to enable RPZ service.
*/
#ifndef SERVICES_RPZ_H
#define SERVICES_RPZ_H
#include "services/localzone.h"
#include "util/locks.h"
#include "util/log.h"
#include "util/config_file.h"
#include "services/authzone.h"
#include "sldns/sbuffer.h"
#include "daemon/stats.h"
#include "respip/respip.h"
/**
* RPZ triggers, only the QNAME trigger is currently supported in Unbound.
*/
enum rpz_trigger {
RPZ_QNAME_TRIGGER = 0,
/* unsupported triggers */
RPZ_CLIENT_IP_TRIGGER, /* rpz-client-ip */
RPZ_RESPONSE_IP_TRIGGER, /* rpz-ip */
RPZ_NSDNAME_TRIGGER, /* rpz-nsdname */
RPZ_NSIP_TRIGGER, /* rpz-nsip */
RPZ_INVALID_TRIGGER, /* dname does not contain valid trigger */
};
/**
* RPZ actions.
*/
enum rpz_action {
RPZ_NXDOMAIN_ACTION = 0,/* CNAME . */
RPZ_NODATA_ACTION, /* CNAME *. */
RPZ_PASSTHRU_ACTION, /* CNAME rpz-passthru. */
RPZ_DROP_ACTION, /* CNAME rpz-drop. */
RPZ_TCP_ONLY_ACTION, /* CNAME rpz-tcp-only. */
RPZ_INVALID_ACTION, /* CNAME with (child of) TLD starting with
"rpz-" in target, SOA, NS, DNAME and
DNSSEC-related records. */
RPZ_LOCAL_DATA_ACTION, /* anything else */
/* RPZ override actions */
RPZ_DISABLED_ACTION, /* RPZ action disabled using override */
RPZ_NO_OVERRIDE_ACTION, /* RPZ action no override*/
RPZ_CNAME_OVERRIDE_ACTION, /* RPZ CNAME action override*/
};
/**
* RPZ containing policies. Pointed to from corresponding auth-zone. Part of a
* linked list to keep configuration order. Iterating or changing the linked
* list requires the rpz_lock from struct auth_zones.
*/
struct rpz {
struct local_zones* local_zones;
struct respip_set* respip_set;
uint8_t* taglist;
size_t taglistlen;
enum rpz_action action_override;
struct ub_packed_rrset_key* cname_override;
int log;
char* log_name;
struct rpz* next;
struct rpz* prev;
struct regional* region;
};
/**
* Create policy from RR and add to this RPZ.
* @param r: the rpz to add the policy to.
* @param aznamelen: the length of the auth-zone name
* @param dname: dname of the RR
* @param dnamelen: length of the dname
* @param rr_type: RR type of the RR
* @param rr_class: RR class of the RR
* @param rr_ttl: TTL of the RR
* @param rdatawl: rdata of the RR, prepended with the rdata size
* @param rdatalen: length if the RR, including the prepended rdata size
* @param rr: the complete RR, for logging purposes
* @param rr_len: the length of the complete RR
* @return: 0 on error
*/
int rpz_insert_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint32_t rr_ttl,
uint8_t* rdatawl, size_t rdatalen, uint8_t* rr, size_t rr_len);
/**
* Delete policy matching RR, used for IXFR.
* @param r: the rpz to add the policy to.
* @param aznamelen: the length of the auth-zone name
* @param dname: dname of the RR
* @param dnamelen: length of the dname
* @param rr_type: RR type of the RR
* @param rr_class: RR class of the RR
* @param rdatawl: rdata of the RR, prepended with the rdata size
* @param rdatalen: length if the RR, including the prepended rdata size
*/
void rpz_remove_rr(struct rpz* r, size_t aznamelen, uint8_t* dname,
size_t dnamelen, uint16_t rr_type, uint16_t rr_class, uint8_t* rdatawl,
size_t rdatalen);
/**
* Walk over the RPZ zones to find and apply a QNAME trigger policy.
* @param az: auth_zones struct, containing first RPZ item and RPZ lock
* @param env: module env
* @param qinfo: qinfo containing qname and qtype
* @param edns: edns data
* @param buf: buffer to write answer to
* @param temp: scratchpad
* @param repinfo: reply info
* @param taglist: taglist to lookup.
* @param taglen: lenth of taglist.
* @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,
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);
/**
* Delete RPZ
* @param r: RPZ struct to delete
*/
void rpz_delete(struct rpz* r);
/**
* Clear local-zones and respip data in RPZ, used after reloading file or
* AXFR/HTTP transfer.
* @param r: RPZ to use
*/
int rpz_clear(struct rpz* r);
/**
* Create RPZ. RPZ must be added to linked list after creation.
* @return: the newly created RPZ
*/
struct rpz* rpz_create(struct config_auth* p);
/**
* String for RPZ action enum
* @param a: RPZ action to get string for
* @return: string for RPZ action
*/
const char* rpz_action_to_string(enum rpz_action a);
enum rpz_action
respip_action_to_rpz_action(enum respip_action a);
/**
* Prepare RPZ after procesing feed content.
* @param r: RPZ to use
*/
void rpz_finish_config(struct rpz* r);
/**
* Classify respip action for RPZ action
* @param a: RPZ action
* @return: the respip action
*/
enum respip_action
rpz_action_to_respip_action(enum rpz_action a);
#endif /* SERVICES_RPZ_H */

View File

@ -80,7 +80,7 @@ static int sldns_str2wire_dname_buf_rel(const char* str, uint8_t* buf,
for (s = str; *s; s++, q++) {
if (q >= buf + *olen)
return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf);
if (q > buf + LDNS_MAX_DOMAINLEN)
if (q >= buf + LDNS_MAX_DOMAINLEN)
return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf);
switch (*s) {
case '.':
@ -117,7 +117,7 @@ static int sldns_str2wire_dname_buf_rel(const char* str, uint8_t* buf,
if(rel) *rel = 1;
if (q >= buf + *olen)
return RET_ERR(LDNS_WIREPARSE_ERR_BUFFER_TOO_SMALL, q-buf);
if (q > buf + LDNS_MAX_DOMAINLEN) {
if (q >= buf + LDNS_MAX_DOMAINLEN) {
return RET_ERR(LDNS_WIREPARSE_ERR_DOMAINNAME_OVERFLOW, q-buf);
}
if (label_len > LDNS_MAX_LABELLEN) {

View File

@ -469,6 +469,7 @@ check_modules_exist(const char* module_conf)
static void
morechecks(struct config_file* cfg)
{
struct config_auth* auth;
warn_hosts("stub-host", cfg->stubs);
warn_hosts("forward-host", cfg->forwards);
interfacechecks(cfg);
@ -534,6 +535,12 @@ morechecks(struct config_file* cfg)
cfg->trusted_keys_file_list, cfg->chrootdir, cfg);
check_chroot_string("dlv-anchor-file", &cfg->dlv_anchor_file,
cfg->chrootdir, cfg);
for(auth = cfg->auths; auth; auth = auth->next) {
char* az = (auth->isrpz) ? "rpz zonefile" :
"auth-zone zonefile";
check_chroot_string(az, &auth->zonefile,
cfg->chrootdir, cfg);
}
#ifdef USE_IPSECMOD
if(cfg->ipsecmod_enabled && strstr(cfg->module_conf, "ipsecmod")) {
/* only check hook if enabled */
@ -676,8 +683,9 @@ check_hints(struct config_file* cfg)
static void
check_auth(struct config_file* cfg)
{
int is_rpz = 0;
struct auth_zones* az = auth_zones_create();
if(!az || !auth_zones_apply_cfg(az, cfg, 0)) {
if(!az || !auth_zones_apply_cfg(az, cfg, 0i, &is_rpz)) {
fatal_exit("Could not setup authority zones");
}
auth_zones_delete(az);

View File

@ -62,6 +62,7 @@
#include "daemon/stats.h"
#include "sldns/wire2str.h"
#include "sldns/pkthdr.h"
#include "services/rpz.h"
#ifdef HAVE_SYS_IPC_H
#include "sys/ipc.h"
@ -374,6 +375,14 @@ static void print_extended(struct ub_stats_info* s)
PR_UL("rrset.cache.count", s->svr.rrset_cache_count);
PR_UL("infra.cache.count", s->svr.infra_cache_count);
PR_UL("key.cache.count", s->svr.key_cache_count);
/* applied RPZ actions */
for(i=0; i<UB_STATS_RPZ_ACTION_NUM; i++) {
if(i == RPZ_NO_OVERRIDE_ACTION)
continue;
if(inhibit_zero && s->svr.rpz_action[i] == 0)
continue;
PR_UL_SUB("num.rpz.action", rpz_action_to_string(i), s->svr.rpz_action[i]);
}
#ifdef USE_DNSCRYPT
PR_UL("dnscrypt_shared_secret.cache.count",
s->svr.shared_secret_cache_count);

View File

@ -794,6 +794,34 @@ dname_test_valid(void)
, 4096) == 0);
}
/** Test dname_has_label */
static void
dname_test_has_label(void)
{
unit_show_func("util/data/dname.c", "dname_has_label");
/* label past root label */
unit_assert(dname_has_label((uint8_t*)"\01a\0\01c", 5, (uint8_t*)"\01c") == 0);
/* label not found */
unit_assert(dname_has_label((uint8_t*)"\02ab\01c\0", 6, (uint8_t*)"\01e") == 0);
/* buffer too short */
unit_assert(dname_has_label((uint8_t*)"\02ab\01c\0", 5, (uint8_t*)"\0") == 0);
unit_assert(dname_has_label((uint8_t*)"\1a\0", 2, (uint8_t*)"\0") == 0);
unit_assert(dname_has_label((uint8_t*)"\0", 0, (uint8_t*)"\0") == 0);
unit_assert(dname_has_label((uint8_t*)"\02ab\01c", 4, (uint8_t*)"\01c") == 0);
unit_assert(dname_has_label((uint8_t*)"\02ab\03qwe\06oqieur\03def\01c\0", 19, (uint8_t*)"\01c") == 0);
/* positive cases */
unit_assert(dname_has_label((uint8_t*)"\0", 1, (uint8_t*)"\0") == 1);
unit_assert(dname_has_label((uint8_t*)"\1a\0", 3, (uint8_t*)"\0") == 1);
unit_assert(dname_has_label((uint8_t*)"\01a\0\01c", 5, (uint8_t*)"\0") == 1);
unit_assert(dname_has_label((uint8_t*)"\02ab\01c", 5, (uint8_t*)"\01c") == 1);
unit_assert(dname_has_label((uint8_t*)"\02ab\01c\0", 10, (uint8_t*)"\0") == 1);
unit_assert(dname_has_label((uint8_t*)"\02ab\01c\0", 7, (uint8_t*)"\0") == 1);
unit_assert(dname_has_label((uint8_t*)"\02ab\03qwe\06oqieur\03def\01c\0", 22, (uint8_t*)"\03def") == 1);
unit_assert(dname_has_label((uint8_t*)"\02ab\03qwe\06oqieur\03def\01c\0", 22, (uint8_t*)"\02ab") == 1);
unit_assert(dname_has_label((uint8_t*)"\02ab\03qwe\06oqieur\03def\01c\0", 22, (uint8_t*)"\01c") == 1);
}
/** test pkt_dname_tolower */
static void
dname_test_pdtl(sldns_buffer* loopbuf, sldns_buffer* boundbuf)
@ -855,6 +883,7 @@ void dname_test(void)
dname_test_canoncmp();
dname_test_topdomain();
dname_test_valid();
dname_test_has_label();
sldns_buffer_free(buff);
sldns_buffer_free(loopbuf);
sldns_buffer_free(boundbuf);

362
testdata/rpz_axfr.rpl vendored Normal file
View File

@ -0,0 +1,362 @@
; config options
server:
module-config: "respip validator iterator"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
rpz:
name: "rpz.example.com."
master: 10.20.30.40
zonefile:
TEMPFILE_NAME rpz.example.com
TEMPFILE_CONTENTS rpz.example.com
$ORIGIN rpz.example.com.
a IN CNAME *.
c IN TXT "hello from initial RPZ"
c IN TXT "another hello from initial RPZ"
d IN CNAME .
32.1.123.0.10.rpz-ip CNAME *.
32.3.123.0.10.rpz-ip A 10.66.0.3
32.3.123.0.10.rpz-ip A 10.66.0.4
32.4.123.0.10.rpz-ip CNAME .
TEMPFILE_END
stub-zone:
name: "."
stub-addr: 10.20.30.40
CONFIG_END
SCENARIO_BEGIN Test RPZ QNAME trigger, loaded using AXFR
RANGE_BEGIN 0 100
ADDRESS 10.20.30.40
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS ns.
SECTION ADDITIONAL
ns. IN NS 10.20.30.40
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
b. IN TXT
SECTION ANSWER
b. TXT "hello from upstream"
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
d. IN TXT
SECTION ANSWER
d. TXT "hello from upstream"
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
a.rpz-ip. IN A
SECTION ANSWER
a.rpz-ip. IN A 10.0.123.1
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
c.rpz-ip. IN A
SECTION ANSWER
c.rpz-ip. IN A 10.0.123.3
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
d.rpz-ip. IN A
SECTION ANSWER
d.rpz-ip. IN A 10.0.123.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN SOA
SECTION ANSWER
rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 1 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN AXFR
SECTION ANSWER
rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 1 3600 900 86400 3600
b.rpz.example.com. TXT "hello from RPZ"
c.rpz.example.com. TXT "hello from RPZ"
a.rpz.example.com. CNAME .
32.1.123.0.10.rpz-ip.rpz.example.com. CNAME .
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.5
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.6
rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 1 3600 900 86400 3600
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
b. IN TXT
ENTRY_END
STEP 2 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
b. IN TXT
SECTION ANSWER
b. IN TXT "hello from upstream"
ENTRY_END
STEP 3 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a. IN TXT
ENTRY_END
STEP 4 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
a. IN TXT
SECTION ANSWER
ENTRY_END
STEP 5 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.rpz-ip. IN A
ENTRY_END
STEP 6 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
a.rpz-ip. IN A
SECTION ANSWER
ENTRY_END
STEP 7 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c. IN TXT
ENTRY_END
STEP 8 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
c. IN TXT
SECTION ANSWER
c. IN TXT "another hello from initial RPZ"
c. IN TXT "hello from initial RPZ"
ENTRY_END
STEP 9 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c.rpz-ip. IN A
ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
c.rpz-ip. IN A
SECTION ANSWER
c.rpz-ip. IN A 10.66.0.4
c.rpz-ip. IN A 10.66.0.3
ENTRY_END
STEP 11 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d. IN TXT
ENTRY_END
STEP 12 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NXDOMAIN
SECTION QUESTION
d. IN TXT
ENTRY_END
STEP 13 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d.rpz-ip. IN A
ENTRY_END
STEP 14 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
d.rpz-ip. IN A
ENTRY_END
STEP 30 TIME_PASSES ELAPSE 10
STEP 40 TRAFFIC
STEP 50 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
b. IN TXT
ENTRY_END
STEP 51 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
b. IN TXT
SECTION ANSWER
b. IN TXT "hello from RPZ"
ENTRY_END
STEP 52 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a. IN TXT
ENTRY_END
STEP 53 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NXDOMAIN
SECTION QUESTION
a. IN TXT
SECTION ANSWER
ENTRY_END
STEP 54 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.rpz-ip. IN A
ENTRY_END
STEP 55 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
a.rpz-ip. IN A
SECTION ANSWER
ENTRY_END
STEP 56 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c. IN TXT
ENTRY_END
STEP 57 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
c. IN TXT
SECTION ANSWER
c. IN TXT "hello from RPZ"
ENTRY_END
STEP 58 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c.rpz-ip. IN A
ENTRY_END
STEP 59 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
c.rpz-ip. IN A
SECTION ANSWER
c.rpz-ip. IN A 10.66.0.6
c.rpz-ip. IN A 10.66.0.5
ENTRY_END
STEP 60 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d. IN TXT
ENTRY_END
STEP 61 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
d. IN TXT
SECTION ANSWER
d. IN TXT "hello from upstream"
ENTRY_END
STEP 62 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d.rpz-ip. IN A
ENTRY_END
STEP 63 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
d.rpz-ip. IN A
SECTION ANSWER
d.rpz-ip. IN A 10.0.123.4
ENTRY_END
SCENARIO_END

378
testdata/rpz_ixfr.rpl vendored Normal file
View File

@ -0,0 +1,378 @@
; config options
server:
module-config: "respip validator iterator"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
rpz:
name: "rpz.example.com."
master: 10.20.30.40
zonefile:
TEMPFILE_NAME rpz.example.com
TEMPFILE_CONTENTS rpz.example.com
rpz.example.com. 3600 IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 1 3600 900 86400 3600
rpz.example.com. 3600 IN NS ns.rpz.example.net.
a.rpz.example.com. IN CNAME *.
c.rpz.example.com. IN TXT "hello from initial RPZ"
c.rpz.example.com. IN TXT "another hello from initial RPZ"
c.rpz.example.com. IN TXT "yet another hello from initial RPZ"
d.rpz.example.com. IN CNAME .
32.1.123.0.10.rpz-ip.rpz.example.com. CNAME *.
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.3
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.4
32.4.123.0.10.rpz-ip.rpz.example.com. CNAME .
TEMPFILE_END
stub-zone:
name: "."
stub-addr: 10.20.30.40
CONFIG_END
SCENARIO_BEGIN Test RPZ QNAME trigger, loaded using IXFR
RANGE_BEGIN 0 100
ADDRESS 10.20.30.40
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS ns.
SECTION ADDITIONAL
ns. IN NS 10.20.30.40
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
b. IN TXT
SECTION ANSWER
b. TXT "hello from upstream"
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
d. IN TXT
SECTION ANSWER
d. TXT "hello from upstream"
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
a.rpz-ip. IN A
SECTION ANSWER
a.rpz-ip. IN A 10.0.123.1
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
c.rpz-ip. IN A
SECTION ANSWER
c.rpz-ip. IN A 10.0.123.3
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR NOERROR AA
SECTION QUESTION
d.rpz-ip. IN A
SECTION ANSWER
d.rpz-ip. IN A 10.0.123.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN SOA
SECTION ANSWER
rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 2 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN IXFR
SECTION ANSWER
rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 2 3600 900 86400 3600
rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 1 3600 900 86400 3600
a.rpz.example.com. IN CNAME *.
c.rpz.example.com. IN TXT "hello from initial RPZ"
c.rpz.example.com. IN TXT "another hello from initial RPZ"
d.rpz.example.com. IN CNAME .
32.1.123.0.10.rpz-ip.rpz.example.com. CNAME *.
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.3
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.4
32.4.123.0.10.rpz-ip.rpz.example.com. CNAME .
rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 2 3600 900 86400 3600
b.rpz.example.com. TXT "hello from RPZ"
c.rpz.example.com. TXT "hello from RPZ"
a.rpz.example.com. CNAME .
32.1.123.0.10.rpz-ip.rpz.example.com. CNAME .
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.5
32.3.123.0.10.rpz-ip.rpz.example.com. A 10.66.0.6
rpz.example.com. IN SOA ns.rpz.example.com. hostmaster.rpz.example.com. 2 3600 900 86400 3600
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
b. IN TXT
ENTRY_END
STEP 2 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
b. IN TXT
SECTION ANSWER
b. IN TXT "hello from upstream"
ENTRY_END
STEP 3 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a. IN TXT
ENTRY_END
STEP 4 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
a. IN TXT
SECTION ANSWER
ENTRY_END
STEP 5 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.rpz-ip. IN A
ENTRY_END
STEP 6 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
a.rpz-ip. IN A
SECTION ANSWER
ENTRY_END
STEP 7 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c. IN TXT
ENTRY_END
STEP 8 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
c. IN TXT
SECTION ANSWER
c. IN TXT "yet another hello from initial RPZ"
c. IN TXT "another hello from initial RPZ"
c. IN TXT "hello from initial RPZ"
ENTRY_END
STEP 9 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c.rpz-ip. IN A
ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
c.rpz-ip. IN A
SECTION ANSWER
c.rpz-ip. IN A 10.66.0.4
c.rpz-ip. IN A 10.66.0.3
ENTRY_END
STEP 11 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d. IN TXT
ENTRY_END
STEP 12 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NXDOMAIN
SECTION QUESTION
d. IN TXT
ENTRY_END
STEP 13 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d.rpz-ip. IN A
ENTRY_END
STEP 15 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
d.rpz-ip. IN A
ENTRY_END
STEP 16 TIME_PASSES ELAPSE 1
STEP 30 TIME_PASSES ELAPSE 3600
STEP 40 TRAFFIC
STEP 50 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
b. IN TXT
ENTRY_END
STEP 51 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
b. IN TXT
SECTION ANSWER
b. IN TXT "hello from RPZ"
ENTRY_END
STEP 52 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a. IN TXT
ENTRY_END
STEP 53 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NXDOMAIN
SECTION QUESTION
a. IN TXT
SECTION ANSWER
ENTRY_END
STEP 54 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.rpz-ip. IN A
ENTRY_END
STEP 55 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
a.rpz-ip. IN A
SECTION ANSWER
ENTRY_END
STEP 56 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c. IN TXT
ENTRY_END
STEP 57 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
c. IN TXT
SECTION ANSWER
c. IN TXT "hello from RPZ"
c. IN TXT "yet another hello from initial RPZ"
ENTRY_END
STEP 58 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c.rpz-ip. IN A
ENTRY_END
STEP 59 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
c.rpz-ip. IN A
SECTION ANSWER
c.rpz-ip. IN A 10.66.0.6
c.rpz-ip. IN A 10.66.0.5
ENTRY_END
STEP 60 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d. IN TXT
ENTRY_END
STEP 61 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
d. IN TXT
SECTION ANSWER
d. IN TXT "hello from upstream"
ENTRY_END
STEP 62 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d.rpz-ip. IN A
ENTRY_END
STEP 63 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
d.rpz-ip. IN A
SECTION ANSWER
d.rpz-ip. IN A 10.0.123.4
ENTRY_END
SCENARIO_END

304
testdata/rpz_qname.rpl vendored Normal file
View File

@ -0,0 +1,304 @@
; 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 CNAME .
a CNAME *. ; duplicate CNAME here on purpose
*.a TXT "wildcard local data"
b.a CNAME *.
c.a CNAME rpz-passthru.
TEMPFILE_END
rpz:
name: "rpz2.example.com."
zonefile:
TEMPFILE_NAME rpz2.example.com
TEMPFILE_CONTENTS rpz2.example.com
$ORIGIN example.com.
rpz2 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 rpz2.example.com.
a TXT "local data 2nd zone"
d TXT "local data 2nd zone"
e CNAME *.a.example.
*.e CNAME *.b.example.
drop CNAME rpz-drop.
TEMPFILE_END
stub-zone:
name: "a."
stub-addr: 10.20.30.40
stub-zone:
name: "example."
stub-addr: 10.20.30.50
CONFIG_END
SCENARIO_BEGIN Test all support RPZ action for QNAME trigger
; a.
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
c.a. IN TXT
SECTION ANSWER
c.a. IN TXT "answer from upstream ns"
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
x.b.a. IN TXT
SECTION ANSWER
x.b.a. IN TXT "answer from upstream ns"
ENTRY_END
RANGE_END
; example.
RANGE_BEGIN 0 100
ADDRESS 10.20.30.50
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
example. IN NS
SECTION ANSWER
example. IN NS ns.example.
SECTION ADDITIONAL
ns.example IN A 10.20.30.50
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
e.a.example. IN TXT
SECTION ANSWER
e.a.example. IN TXT "e.a.example. answer from upstream ns"
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
something.e.b.example. IN TXT
SECTION ANSWER
something.e.b.example. IN TXT "*.b.example. answer from upstream ns"
ENTRY_END
RANGE_END
STEP 10 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a. IN TXT
ENTRY_END
STEP 11 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NXDOMAIN
SECTION QUESTION
a. IN TXT
SECTION ANSWER
ENTRY_END
STEP 20 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a.a. IN TXT
ENTRY_END
STEP 21 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
a.a. IN TXT
SECTION ANSWER
a.a. IN TXT "wildcard local data"
ENTRY_END
STEP 30 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
b.a. IN TXT
ENTRY_END
STEP 31 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
b.a. IN TXT
SECTION ANSWER
ENTRY_END
STEP 40 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
x.a. IN TXT
ENTRY_END
STEP 41 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
x.a. IN TXT
SECTION ANSWER
x.a. IN TXT "wildcard local data"
ENTRY_END
STEP 50 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
x.a.a. IN TXT
ENTRY_END
STEP 51 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
x.a.a. IN TXT
SECTION ANSWER
x.a.a. IN TXT "wildcard local data"
ENTRY_END
STEP 60 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c.a. IN TXT
ENTRY_END
STEP 61 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
c.a. IN TXT
SECTION ANSWER
c.a. IN TXT "answer from upstream ns"
ENTRY_END
STEP 70 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
x.b.a. IN TXT
ENTRY_END
STEP 71 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
x.b.a. IN TXT
SECTION ANSWER
x.b.a. IN TXT "answer from upstream ns"
ENTRY_END
STEP 80 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d. IN TXT
ENTRY_END
STEP 81 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
d. IN TXT
SECTION ANSWER
d. IN TXT "local data 2nd zone"
ENTRY_END
STEP 82 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
e. IN TXT
ENTRY_END
STEP 83 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
e. IN TXT
SECTION ANSWER
e. IN CNAME e.a.example.
e.a.example. IN TXT "e.a.example. answer from upstream ns"
ENTRY_END
STEP 84 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
something.e. IN TXT
ENTRY_END
STEP 85 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
something.e. IN TXT
SECTION ANSWER
something.e. IN CNAME something.e.b.example.
something.e.b.example. IN TXT "*.b.example. answer from upstream ns"
ENTRY_END
; deny zone
STEP 90 QUERY
ENTRY_BEGIN
SECTION QUESTION
drop. IN TXT
ENTRY_END
; no answer is checked at exit of testbound.
SCENARIO_END

197
testdata/rpz_qname_override.rpl vendored Normal file
View File

@ -0,0 +1,197 @@
; config options
server:
module-config: "respip validator iterator"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
rpz:
name: "rpz.example.com."
rpz-action-override: disabled
zonefile:
TEMPFILE_NAME rpz.example.com
TEMPFILE_CONTENTS rpz.example.com
$ORIGIN rpz.example.com.
a TXT "record zone rpz.example.com"
TEMPFILE_END
rpz:
name: "rpz2.example.com."
zonefile:
TEMPFILE_NAME rpz2.example.com
TEMPFILE_CONTENTS rpz2.example.com
$ORIGIN rpz2.example.com.
a TXT "record zone rpz2.example.com"
TEMPFILE_END
rpz:
name: "rpz3.example.com."
rpz-action-override: nodata
zonefile:
TEMPFILE_NAME rpz3.example.com
TEMPFILE_CONTENTS rpz3.example.com
$ORIGIN rpz3.example.com.
b CNAME .
TEMPFILE_END
rpz:
name: "rpz4.example.com."
rpz-action-override: nxdomain
zonefile:
TEMPFILE_NAME rpz4.example.com
TEMPFILE_CONTENTS rpz4.example.com
$ORIGIN rpz4.example.com.
c CNAME *.
TEMPFILE_END
rpz:
name: "rpz5.example.com."
rpz-action-override: passthru
zonefile:
TEMPFILE_NAME rpz5.example.com
TEMPFILE_CONTENTS rpz5.example.com
$ORIGIN rpz5.example.com.
d TXT "should be override by passthru"
TEMPFILE_END
rpz:
name: "rpz6.example.com."
rpz-action-override: cname
rpz-cname-override: "d."
zonefile:
TEMPFILE_NAME rpz6.example.com
TEMPFILE_CONTENTS rpz6.example.com
$ORIGIN rpz6.example.com.
e TXT "should be override by cname"
TEMPFILE_END
rpz:
name: "rpz7.example.com."
rpz-action-override: drop
zonefile:
TEMPFILE_NAME rpz7.example.com
TEMPFILE_CONTENTS rpz7.example.com
$ORIGIN rpz7.example.com.
f TXT "should be override by drop policy"
TEMPFILE_END
stub-zone:
name: "d."
stub-addr: 10.20.30.40
CONFIG_END
SCENARIO_BEGIN Test RPZ action overrides for QNAME trigger
; d.
RANGE_BEGIN 0 100
ADDRESS 10.20.30.40
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
d. IN TXT
SECTION ANSWER
d. IN TXT "answer from upstream ns"
ENTRY_END
RANGE_END
; check disabled override, should be answered using next policy zone
STEP 10 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a. IN TXT
ENTRY_END
STEP 11 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
a. IN TXT
SECTION ANSWER
a TXT "record zone rpz2.example.com"
ENTRY_END
; check nodata override, would be NXDOMAIN without override
STEP 20 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
b. IN TXT
ENTRY_END
STEP 21 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
b. IN TXT
SECTION ANSWER
ENTRY_END
; check nxdomain override, would be NODATA without override
STEP 30 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c. IN TXT
ENTRY_END
STEP 31 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NXDOMAIN
SECTION QUESTION
c. IN TXT
SECTION ANSWER
ENTRY_END
; check passthru override, would be localdata without override
STEP 40 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d. IN TXT
ENTRY_END
STEP 41 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
d. IN TXT
SECTION ANSWER
d. IN TXT "answer from upstream ns"
ENTRY_END
; check cname override, would be localdata without override
STEP 50 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
e. IN TXT
ENTRY_END
STEP 51 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA AA NOERROR
SECTION QUESTION
e. IN TXT
SECTION ANSWER
e. IN CNAME d.
d. IN TXT "answer from upstream ns"
ENTRY_END
; check drop override, would be localdata without override
STEP 60 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
f. IN TXT
ENTRY_END
; no answer is checked at exit of testbound.
SCENARIO_END

449
testdata/rpz_respip.rpl vendored Normal file
View File

@ -0,0 +1,449 @@
; 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.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.
128.1.zz.cc.bb.aa.db8.2001.rpz-ip CNAME rpz-passthru.
128.123.zz.cc.bb.aa.db8.2001.rpz-ip AAAA 2001:db8::123
128.124.0.0.cc.bb.aa.db8.2001.rpz-ip AAAA 2001:db8::124
TEMPFILE_END
rpz:
name: "rpz2.example.com."
zonefile:
TEMPFILE_NAME rpz2.example.com
TEMPFILE_CONTENTS rpz2.example.com
$ORIGIN example.com.
rpz2 3600 IN SOA ns1.rpz2.example.com. hostmaster.rpz2.example.com. (
1379078166 28800 7200 604800 7200 )
3600 IN NS ns1.rpz2.example.com.
3600 IN NS ns2.rpz2.example.com.
$ORIGIN rpz2.example.com.
32.10.10.10.10.rpz-ip A 203.0.113.123
32.123.2.0.192.rpz-ip A 203.0.113.123
128.1.zz.cc.bb.aa.db8.2001.rpz-ip AAAA 2001:db1::123
TEMPFILE_END
stub-zone:
name: "."
stub-addr: 10.20.30.40
CONFIG_END
SCENARIO_BEGIN Test all supported RPZ action for response IP address trigger
; c.
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
a. IN AAAA
SECTION ANSWER
a. IN AAAA 2001:db8::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
b. IN AAAA
SECTION ANSWER
b. IN AAAA 2001:db8:1::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
c. IN AAAA
SECTION ANSWER
c. IN AAAA 2001:db8:ff::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
d. IN AAAA
SECTION ANSWER
d. IN AAAA 2001:db8:aa::123
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
e. IN A
SECTION ANSWER
e. IN A 10.10.10.123
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
e. IN AAAA
SECTION ANSWER
e. IN AAAA 2001:db8:aa:bb::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
f. IN AAAA
SECTION ANSWER
f. IN AAAA 2001:db8:aa:bb:cc::1
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
g. IN A
SECTION ANSWER
g. IN A 192.0.2.123
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
g. IN AAAA
SECTION ANSWER
g. IN AAAA 2001:db8:aa:bb:cc::123
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
h. IN AAAA
SECTION ANSWER
h. IN AAAA 2001:db8:aa:bb:cc::124
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 3 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
a. IN AAAA
ENTRY_END
STEP 4 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
a. IN AAAA
SECTION ANSWER
ENTRY_END
STEP 5 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
b. IN A
ENTRY_END
STEP 6 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
b. IN A
SECTION ANSWER
ENTRY_END
STEP 7 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
b. IN AAAA
ENTRY_END
STEP 8 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
b. IN AAAA
SECTION ANSWER
ENTRY_END
STEP 9 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c. IN A
ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
c. IN A
SECTION ANSWER
ENTRY_END
STEP 11 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c. IN AAAA
ENTRY_END
STEP 12 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
c. IN AAAA
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 15 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d. IN AAAA
ENTRY_END
STEP 16 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
d. IN AAAA
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 19 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
f. IN AAAA
ENTRY_END
STEP 20 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
f. IN AAAA
SECTION ANSWER
f. IN AAAA 2001:db8:aa:bb:cc::1
ENTRY_END
STEP 21 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
g. IN A
ENTRY_END
STEP 22 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
g. IN A
SECTION ANSWER
g. IN A 203.0.113.123
ENTRY_END
STEP 23 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
g. IN AAAA
ENTRY_END
STEP 24 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
g. IN AAAA
SECTION ANSWER
g. IN AAAA 2001:db8::123
ENTRY_END
STEP 25 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
h. IN AAAA
ENTRY_END
STEP 26 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
h. IN AAAA
SECTION ANSWER
h. IN AAAA 2001:db8::124
ENTRY_END
; should be dropped
STEP 27 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
e. IN A
ENTRY_END
STEP 28 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
e. IN AAAA
ENTRY_END
STEP 29 TIME_PASSES ELAPSE 12
SCENARIO_END

265
testdata/rpz_respip_override.rpl vendored Normal file
View File

@ -0,0 +1,265 @@
; config options
server:
module-config: "respip validator iterator"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
rpz:
name: "rpz.example.com."
rpz-action-override: disabled
zonefile:
TEMPFILE_NAME rpz.example.com
TEMPFILE_CONTENTS rpz.example.com
$ORIGIN rpz.example.com.
32.1.113.0.203.rpz-ip A 192.0.2.1
TEMPFILE_END
rpz:
name: "rpz2.example.com."
zonefile:
TEMPFILE_NAME rpz2.example.com
TEMPFILE_CONTENTS rpz2.example.com
$ORIGIN rpz2.example.com.
32.1.113.0.203.rpz-ip A 192.0.2.2
TEMPFILE_END
rpz:
name: "rpz3.example.com."
rpz-action-override: nodata
zonefile:
TEMPFILE_NAME rpz3.example.com
TEMPFILE_CONTENTS rpz3.example.com
$ORIGIN rpz3.example.com.
32.3.113.0.203.rpz-ip CNAME .
TEMPFILE_END
rpz:
name: "rpz4.example.com."
rpz-action-override: nxdomain
zonefile:
TEMPFILE_NAME rpz4.example.com
TEMPFILE_CONTENTS rpz4.example.com
$ORIGIN rpz4.example.com.
32.4.113.0.203.rpz-ip CNAME *.
TEMPFILE_END
rpz:
name: "rpz5.example.com."
rpz-action-override: passthru
zonefile:
TEMPFILE_NAME rpz5.example.com
TEMPFILE_CONTENTS rpz5.example.com
$ORIGIN rpz5.example.com.
32.5.113.0.203.rpz-ip A 192.0.2.5
TEMPFILE_END
rpz:
name: "rpz6.example.com."
rpz-action-override: cname
rpz-cname-override: ns.
zonefile:
TEMPFILE_NAME rpz6.example.com
TEMPFILE_CONTENTS rpz6.example.com
$ORIGIN rpz6.example.com.
32.6.113.0.203.rpz-ip A 192.0.2.6
TEMPFILE_END
rpz:
name: "rpz7.example.com."
rpz-action-override: drop
zonefile:
TEMPFILE_NAME rpz7.example.com
TEMPFILE_CONTENTS rpz7.example.com
$ORIGIN rpz7.example.com.
32.7.113.0.203.rpz-ip A 192.0.2.7
TEMPFILE_END
stub-zone:
name: "."
stub-addr: 10.20.30.40
CONFIG_END
SCENARIO_BEGIN Test all supported RPZ action for response IP address trigger
; c.
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
ns. IN A
SECTION ANSWER
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 203.0.113.1
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
b. IN A
SECTION ANSWER
b. IN A 203.0.113.3
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
c. IN A
SECTION ANSWER
c. IN A 203.0.113.4
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
d. IN A
SECTION ANSWER
d. IN A 203.0.113.5
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
e. IN A
SECTION ANSWER
e. IN A 203.0.113.6
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
f. IN A
SECTION ANSWER
f. IN A 203.0.113.7
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
a. IN A 192.0.2.2
ENTRY_END
STEP 3 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
b. IN A
ENTRY_END
STEP 4 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
b. IN A
SECTION ANSWER
ENTRY_END
STEP 5 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
c. IN A
ENTRY_END
STEP 6 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NXDOMAIN
SECTION QUESTION
c. IN A
SECTION ANSWER
ENTRY_END
STEP 7 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
d. IN A
ENTRY_END
STEP 8 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
d. IN A
SECTION ANSWER
d. IN A 203.0.113.5
ENTRY_END
STEP 9 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
e. IN A
ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
e. IN A
SECTION ANSWER
e. IN CNAME ns.
ns. IN A 10.20.30.40
ENTRY_END
STEP 11 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
f. IN A
ENTRY_END
; no answer is checked at exit of testbound.
STEP 12 TIME_PASSES ELAPSE 10
SCENARIO_END

View File

@ -1279,6 +1279,10 @@ config_delauth(struct config_auth* p)
config_delstrlist(p->urls);
config_delstrlist(p->allow_notify);
free(p->zonefile);
free(p->rpz_taglist);
free(p->rpz_action_override);
free(p->rpz_cname);
free(p->rpz_log_name);
free(p);
}
@ -1942,7 +1946,7 @@ char* config_taglist2str(struct config_file* cfg, uint8_t* taglist,
return strdup(buf);
}
int taglist_intersect(uint8_t* list1, size_t list1len, uint8_t* list2,
int taglist_intersect(uint8_t* list1, size_t list1len, const uint8_t* list2,
size_t list2len)
{
size_t i;

View File

@ -641,6 +641,21 @@ struct config_auth {
/** fallback to recursion to authorities if zone expired and other
* reasons perhaps (like, query bogus) */
int fallback_enabled;
/** this zone is used to create local-zone policies */
int isrpz;
/** rpz tags (or NULL) */
uint8_t* rpz_taglist;
/** length of the taglist (in bytes) */
size_t rpz_taglistlen;
/** Override RPZ action for this zone, regardless of zone content */
char* rpz_action_override;
/** Log when this RPZ policy is applied */
int rpz_log;
/** Display this name in the log when RPZ policy is applied */
char* rpz_log_name;
/** Always reply with this CNAME target if the cname override action is
* used */
char* rpz_cname;
};
/**
@ -1043,7 +1058,7 @@ char* config_taglist2str(struct config_file* cfg, uint8_t* taglist,
* @param list2len: length in bytes of second list.
* @return true if there are tags in common, 0 if not.
*/
int taglist_intersect(uint8_t* list1, size_t list1len, uint8_t* list2,
int taglist_intersect(uint8_t* list1, size_t list1len, const uint8_t* list2,
size_t list2len);
/**

File diff suppressed because it is too large Load Diff

View File

@ -316,6 +316,12 @@ forward-no-cache{COLON} { YDVAR(1, VAR_FORWARD_NO_CACHE) }
forward-ssl-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
forward-tls-upstream{COLON} { YDVAR(1, VAR_FORWARD_SSL_UPSTREAM) }
auth-zone{COLON} { YDVAR(0, VAR_AUTH_ZONE) }
rpz{COLON} { YDVAR(0, VAR_RPZ) }
tags{COLON} { YDVAR(1, VAR_TAGS) }
rpz-action-override{COLON} { YDVAR(1, VAR_RPZ_ACTION_OVERRIDE) }
rpz-cname-override{COLON} { YDVAR(1, VAR_RPZ_CNAME_OVERRIDE) }
rpz-log{COLON} { YDVAR(1, VAR_RPZ_LOG) }
rpz-log-name{COLON} { YDVAR(1, VAR_RPZ_LOG_NAME) }
zonefile{COLON} { YDVAR(1, VAR_ZONEFILE) }
master{COLON} { YDVAR(1, VAR_MASTER) }
url{COLON} { YDVAR(1, VAR_URL) }

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,8 @@
/* A Bison parser, made by GNU Bison 3.4.1. */
/* A Bison parser, made by GNU Bison 3.0.4. */
/* Bison interface for Yacc-like parsers in C
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2019 Free Software Foundation,
Inc.
Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -31,9 +30,6 @@
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/* Undocumented macros, especially those whose name start with YY_,
are private implementation details. Do not rely on them. */
#ifndef YY_YY_UTIL_CONFIGPARSER_H_INCLUDED
# define YY_YY_UTIL_CONFIGPARSER_H_INCLUDED
/* Debug traces. */
@ -312,10 +308,16 @@ extern int yydebug;
VAR_STREAM_WAIT_SIZE = 518,
VAR_TLS_CIPHERS = 519,
VAR_TLS_CIPHERSUITES = 520,
VAR_TLS_SESSION_TICKET_KEYS = 521,
VAR_IPSET = 522,
VAR_IPSET_NAME_V4 = 523,
VAR_IPSET_NAME_V6 = 524
VAR_IPSET = 521,
VAR_IPSET_NAME_V4 = 522,
VAR_IPSET_NAME_V6 = 523,
VAR_TLS_SESSION_TICKET_KEYS = 524,
VAR_RPZ = 525,
VAR_TAGS = 526,
VAR_RPZ_ACTION_OVERRIDE = 527,
VAR_RPZ_CNAME_OVERRIDE = 528,
VAR_RPZ_LOG = 529,
VAR_RPZ_LOG_NAME = 530
};
#endif
/* Tokens. */
@ -582,22 +584,29 @@ extern int yydebug;
#define VAR_STREAM_WAIT_SIZE 518
#define VAR_TLS_CIPHERS 519
#define VAR_TLS_CIPHERSUITES 520
#define VAR_TLS_SESSION_TICKET_KEYS 521
#define VAR_IPSET 522
#define VAR_IPSET_NAME_V4 523
#define VAR_IPSET_NAME_V6 524
#define VAR_IPSET 521
#define VAR_IPSET_NAME_V4 522
#define VAR_IPSET_NAME_V6 523
#define VAR_TLS_SESSION_TICKET_KEYS 524
#define VAR_RPZ 525
#define VAR_TAGS 526
#define VAR_RPZ_ACTION_OVERRIDE 527
#define VAR_RPZ_CNAME_OVERRIDE 528
#define VAR_RPZ_LOG 529
#define VAR_RPZ_LOG_NAME 530
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
union YYSTYPE
{
#line 66 "./util/configparser.y"
#line 66 "./util/configparser.y" /* yacc.c:1909 */
char* str;
#line 599 "util/configparser.h"
#line 608 "util/configparser.h" /* yacc.c:1909 */
};
typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1

View File

@ -166,8 +166,9 @@ extern struct config_parser_state* cfg_parser;
%token VAR_FORWARD_NO_CACHE VAR_STUB_NO_CACHE VAR_LOG_SERVFAIL VAR_DENY_ANY
%token VAR_UNKNOWN_SERVER_TIME_LIMIT VAR_LOG_TAG_QUERYREPLY
%token VAR_STREAM_WAIT_SIZE VAR_TLS_CIPHERS VAR_TLS_CIPHERSUITES
%token VAR_TLS_SESSION_TICKET_KEYS
%token VAR_IPSET VAR_IPSET_NAME_V4 VAR_IPSET_NAME_V6
%token VAR_TLS_SESSION_TICKET_KEYS VAR_RPZ VAR_TAGS VAR_RPZ_ACTION_OVERRIDE
%token VAR_RPZ_CNAME_OVERRIDE VAR_RPZ_LOG VAR_RPZ_LOG_NAME
%%
toplevelvars: /* empty */ | toplevelvars toplevelvar ;
@ -175,7 +176,8 @@ toplevelvar: serverstart contents_server | stubstart contents_stub |
forwardstart contents_forward | pythonstart contents_py |
rcstart contents_rc | dtstart contents_dt | viewstart contents_view |
dnscstart contents_dnsc | cachedbstart contents_cachedb |
ipsetstart contents_ipset | authstart contents_auth
ipsetstart contents_ipset | authstart contents_auth |
rpzstart contents_rpz
;
/* server: declaration */
@ -335,6 +337,7 @@ authstart: VAR_AUTH_ZONE
s->for_downstream = 1;
s->for_upstream = 1;
s->fallback_enabled = 0;
s->isrpz = 0;
} else
yyerror("out of memory");
}
@ -345,6 +348,92 @@ content_auth: auth_name | auth_zonefile | auth_master | auth_url |
auth_for_downstream | auth_for_upstream | auth_fallback_enabled |
auth_allow_notify
;
rpz_tag: VAR_TAGS STRING_ARG
{
uint8_t* bitlist;
size_t len = 0;
OUTYY(("P(server_local_zone_tag:%s)\n", $2));
bitlist = config_parse_taglist(cfg_parser->cfg, $2,
&len);
free($2);
if(!bitlist) {
yyerror("could not parse tags, (define-tag them first)");
}
if(bitlist) {
cfg_parser->cfg->auths->rpz_taglist = bitlist;
cfg_parser->cfg->auths->rpz_taglistlen = len;
}
}
;
rpz_action_override: VAR_RPZ_ACTION_OVERRIDE STRING_ARG
{
OUTYY(("P(rpz_action_override:%s)\n", $2));
if(strcmp($2, "nxdomain")!=0 && strcmp($2, "nodata")!=0 &&
strcmp($2, "passthru")!=0 && strcmp($2, "drop")!=0 &&
strcmp($2, "cname")!=0 && strcmp($2, "disabled")!=0) {
yyerror("rpz-action-override action: expected nxdomain, "
"nodata, passthru, drop, cname or disabled");
free($2);
cfg_parser->cfg->auths->rpz_action_override = NULL;
}
else {
cfg_parser->cfg->auths->rpz_action_override = $2;
}
}
;
rpz_cname_override: VAR_RPZ_CNAME_OVERRIDE STRING_ARG
{
OUTYY(("P(rpz_cname_override:%s)\n", $2));
free(cfg_parser->cfg->auths->rpz_cname);
cfg_parser->cfg->auths->rpz_cname = $2;
}
;
rpz_log: VAR_RPZ_LOG STRING_ARG
{
OUTYY(("P(rpz_log:%s)\n", $2));
if(strcmp($2, "yes") != 0 && strcmp($2, "no") != 0)
yyerror("expected yes or no.");
else cfg_parser->cfg->auths->rpz_log = (strcmp($2, "yes")==0);
free($2);
}
;
rpz_log_name: VAR_RPZ_LOG_NAME STRING_ARG
{
OUTYY(("P(rpz_log_name:%s)\n", $2));
free(cfg_parser->cfg->auths->rpz_log_name);
cfg_parser->cfg->auths->rpz_log_name = $2;
}
;
rpzstart: VAR_RPZ
{
struct config_auth* s;
OUTYY(("\nP(rpz:)\n"));
s = (struct config_auth*)calloc(1, sizeof(struct config_auth));
if(s) {
s->next = cfg_parser->cfg->auths;
cfg_parser->cfg->auths = s;
/* defaults for RPZ auth zone */
s->for_downstream = 0;
s->for_upstream = 0;
s->fallback_enabled = 0;
s->isrpz = 1;
} else
yyerror("out of memory");
}
;
contents_rpz: contents_rpz content_rpz
| ;
content_rpz: auth_name | auth_zonefile | rpz_tag | auth_master | auth_url |
auth_allow_notify | rpz_action_override | rpz_cname_override |
rpz_log | rpz_log_name
;
server_num_threads: VAR_NUM_THREADS STRING_ARG
{
OUTYY(("P(server_num_threads:%s)\n", $2));

View File

@ -558,6 +558,34 @@ dname_lab_startswith(uint8_t* label, char* prefix, char** endptr)
return 1;
}
int
dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label)
{
size_t len;
/* 1 byte needed for the label length */
if(dnamelen < 1)
return 0;
len = *dname;
while(len <= dnamelen) {
if(!(*dname)) {
if(*dname == *label)
return 1; /* empty label match */
/* termination label found, stop iterating */
return 0;
}
if(*dname == *label && *label &&
memlowercmp(dname+1, label+1, *dname) == 0)
return 1;
len += *dname;
dname += *dname;
dname++;
len++;
}
return 0;
}
int
dname_buffer_write(sldns_buffer* pkt, uint8_t* dname)
{

View File

@ -196,6 +196,15 @@ int dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs);
*/
int dname_lab_startswith(uint8_t* label, char* prefix, char** endptr);
/**
* Check if dname contains label
* @param dname: dname
* @param dnamelen: length of dname
* @param label: label to be checked for presence in dname
* @return: 1 if dname has this label, 0 otherwise
*/
int dname_has_label(uint8_t* dname, size_t dnamelen, uint8_t* label);
/**
* See if domain name d1 is a strict subdomain of d2.
* That is a subdomain, but not equal.

View File

@ -386,3 +386,19 @@ packed_rrset_copy_alloc(struct ub_packed_rrset_key* key,
packed_rrset_ttl_add(dd, now);
return dk;
}
int
packed_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
size_t* index)
{
size_t i;
for(i=0; i<d->count; i++) {
if(d->rr_len[i] != len)
continue;
if(memcmp(d->rr_data[i], rdata, len) == 0) {
*index = i;
return 1;
}
}
return 0;
}

View File

@ -446,4 +446,17 @@ struct ub_packed_rrset_key* packed_rrset_copy_alloc(
struct ub_packed_rrset_key* key, struct alloc_cache* alloc,
time_t now);
/**
* Find RR index in packed rrset
* Raw comparison, does not canonicalize RDATA
* @param d: packed rrset
* @param rdata: RDATA of RR to find
* @param len: length of rdata
* @param index: pointer to int to store index of found RR
* @return 1 if RR found, 0 otherwise
*/
int
packed_rrset_find_rr(struct packed_rrset_data* d, uint8_t* rdata, size_t len,
size_t* index);
#endif /* UTIL_DATA_PACKED_RRSET_H */

View File

@ -284,6 +284,113 @@ int netblockstrtoaddr(const char* str, int port, struct sockaddr_storage* addr,
return 1;
}
/* RPZ format address dname to network byte order address */
static int ipdnametoaddr(uint8_t* dname, size_t dnamelen,
struct sockaddr_storage* addr, socklen_t* addrlen, int* af)
{
uint8_t* ia;
size_t dnamelabs = dname_count_labels(dname);
uint8_t lablen;
char* e = NULL;
int z = 0;
size_t len = 0;
int i;
*af = AF_INET;
/* need 1 byte for label length */
if(dnamelen < 1)
return 0;
if(dnamelabs > 6 ||
dname_has_label(dname, dnamelen, (uint8_t*)"\002zz")) {
*af = AF_INET6;
}
len = *dname;
lablen = *dname++;
i = (*af == AF_INET) ? 3 : 15;
if(*af == AF_INET6) {
struct sockaddr_in6* sa = (struct sockaddr_in6*)addr;
*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
memset(sa, 0, *addrlen);
sa->sin6_family = AF_INET6;
ia = (uint8_t*)&sa->sin6_addr;
} else { /* ip4 */
struct sockaddr_in* sa = (struct sockaddr_in*)addr;
*addrlen = (socklen_t)sizeof(struct sockaddr_in);
memset(sa, 0, *addrlen);
sa->sin_family = AF_INET;
ia = (uint8_t*)&sa->sin_addr;
}
while(lablen && i >= 0 && len <= dnamelen) {
char buff[LDNS_MAX_LABELLEN+1];
uint16_t chunk; /* big enough to not overflow on IPv6 hextet */
if((*af == AF_INET && (lablen > 3 || dnamelabs > 6)) ||
(*af == AF_INET6 && (lablen > 4 || dnamelabs > 10))) {
return 0;
}
if(memcmp(dname, "zz", 2) == 0 && *af == AF_INET6) {
/* Add one or more 0 labels. Address is initialised at
* 0, so just skip the zero part. */
int zl = 11 - dnamelabs;
if(z || zl < 0)
return 0;
z = 1;
i -= (zl*2);
} else {
memcpy(buff, dname, lablen);
buff[lablen] = '\0';
chunk = strtol(buff, &e, (*af == AF_INET) ? 10 : 16);
if(!e || *e != '\0' || (*af == AF_INET && chunk > 255))
return 0;
if(*af == AF_INET) {
log_assert(i < 4 && i >= 0);
ia[i] = (uint8_t)chunk;
i--;
} else {
log_assert(i < 16 && i >= 1);
/* ia in network byte order */
ia[i-1] = (uint8_t)(chunk >> 8);
ia[i] = (uint8_t)(chunk & 0x00FF);
i -= 2;
}
}
dname += lablen;
lablen = *dname++;
len += lablen;
}
if(i != -1)
/* input too short */
return 0;
return 1;
}
int netblockdnametoaddr(uint8_t* dname, size_t dnamelen,
struct sockaddr_storage* addr, socklen_t* addrlen, int* net, int* af)
{
char buff[3 /* 3 digit netblock */ + 1];
size_t nlablen;
if(dnamelen < 1 || *dname > 3)
/* netblock invalid */
return 0;
nlablen = *dname;
if(dnamelen < 1 + nlablen)
return 0;
memcpy(buff, dname+1, nlablen);
buff[nlablen] = '\0';
*net = atoi(buff);
if(*net == 0 && strcmp(buff, "0") != 0)
return 0;
dname += nlablen;
dname++;
if(!ipdnametoaddr(dname, dnamelen-1-nlablen, addr, addrlen, af))
return 0;
if((*af == AF_INET6 && *net > 128) || (*af == AF_INET && *net > 32))
return 0;
return 1;
}
int authextstrtoaddr(char* str, struct sockaddr_storage* addr,
socklen_t* addrlen, char** auth_name)
{

View File

@ -471,4 +471,19 @@ int tls_session_ticket_key_cb(void *s, unsigned char* key_name,unsigned char* iv
/** Free memory used for TLS session ticket keys */
void listen_sslctx_delete_ticket_keys(void);
/**
* RPZ format netblock to network byte order address and netblock
* example RPZ netblock format dnames:
* - 24.10.100.51.198.rpz-ip -> 198.51.100.10/24
* - 32.10.zz.db8.2001.rpz-ip -> 2001:db8:0:0:0:0:0:10/32
* @param dname: the dname containing RPZ format netblock
* @param dnamelen: length of dname
* @param addr: where to store sockaddr.
* @param addrlen: length of stored sockaddr is returned.
* @param net: where to store netmask
* @param af: where to store address family.
* @return 0 on error.
*/
int netblockdnametoaddr(uint8_t* dname, size_t dnamelen,
struct sockaddr_storage* addr, socklen_t* addrlen, int* net, int* af);
#endif /* NET_HELP_H */

View File

@ -104,11 +104,12 @@ int addr_tree_insert(rbtree_type* tree, struct addr_tree_node* node,
return rbtree_insert(tree, &node->node) != NULL;
}
void addr_tree_init_parents(rbtree_type* tree)
void addr_tree_init_parents_node(struct addr_tree_node* node)
{
struct addr_tree_node* node, *prev = NULL, *p;
struct addr_tree_node* prev = NULL, *p;
int m;
RBTREE_FOR(node, struct addr_tree_node*, tree) {
for(; (rbnode_type*)node != RBTREE_NULL;
node = (struct addr_tree_node*)rbtree_next((rbnode_type*)node)) {
node->parent = NULL;
if(!prev || prev->addrlen != node->addrlen) {
prev = node;
@ -130,6 +131,12 @@ void addr_tree_init_parents(rbtree_type* tree)
}
}
void addr_tree_init_parents(rbtree_type* tree)
{
addr_tree_init_parents_node(
(struct addr_tree_node*)rbtree_first(tree));
}
void name_tree_init_parents(rbtree_type* tree)
{
struct name_tree_node* node, *prev = NULL, *p;

View File

@ -173,6 +173,13 @@ int addr_tree_insert(rbtree_type* tree, struct addr_tree_node* node,
*/
void addr_tree_init_parents(rbtree_type* tree);
/**
* Initialize parent pointers in partial addr tree.
* Reinitialize pointer for part of tree, used after node deletion
* @param node: node to start parent pointer initialization for.
*/
void addr_tree_init_parents_node(struct addr_tree_node* node);
/**
* Lookup closest encloser in addr tree.
* @param tree: addr tree