mirror of
https://github.com/NLnetLabs/unbound.git
synced 2024-09-21 14:47:09 +00:00
Merge branch 'master' into framestreams
This commit is contained in:
commit
8dd683768b
784
Makefile.in
784
Makefile.in
File diff suppressed because it is too large
Load Diff
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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)) {
|
||||
|
@ -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
|
||||
|
@ -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"
|
||||
|
@ -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@
|
||||
|
@ -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
|
||||
|
@ -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)) {
|
||||
|
@ -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];
|
||||
};
|
||||
|
||||
/**
|
||||
|
318
respip/respip.c
318
respip/respip.c
@ -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);
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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
1013
services/rpz.c
Normal file
File diff suppressed because it is too large
Load Diff
201
services/rpz.h
Normal file
201
services/rpz.h
Normal 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 */
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
362
testdata/rpz_axfr.rpl
vendored
Normal 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
378
testdata/rpz_ixfr.rpl
vendored
Normal 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
304
testdata/rpz_qname.rpl
vendored
Normal 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
197
testdata/rpz_qname_override.rpl
vendored
Normal 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
449
testdata/rpz_respip.rpl
vendored
Normal 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
265
testdata/rpz_respip_override.rpl
vendored
Normal 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
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
/**
|
||||
|
4576
util/configlexer.c
4576
util/configlexer.c
File diff suppressed because it is too large
Load Diff
@ -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) }
|
||||
|
2961
util/configparser.c
2961
util/configparser.c
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
107
util/net_help.c
107
util/net_help.c
@ -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)
|
||||
{
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user