mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-02-11 23:05:46 -05:00
Initial RPZ commit
This commit is contained in:
parent
b43b8d47f8
commit
9274d2630e
2 changed files with 605 additions and 0 deletions
442
services/rpz.c
Normal file
442
services/rpz.c
Normal file
|
|
@ -0,0 +1,442 @@
|
|||
/*
|
||||
* services/rpz.c - 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "services/rpz.h"
|
||||
#include "util/config_file.h"
|
||||
#include "sldns/wire2str.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/log.h"
|
||||
#include "util/data/dname.h"
|
||||
#include "util/locks.h"
|
||||
|
||||
/** string for RPZ action enum */
|
||||
static const char*
|
||||
rpz_action_to_string(enum rpz_action a)
|
||||
{
|
||||
switch(a) {
|
||||
case RPZ_NXDOMAIN_ACTION: return "NXDOMAIN ACTION";
|
||||
case RPZ_NODATA_ACTION: return "NODATA ACTION";
|
||||
case RPZ_PASSTHRU_ACTION: return "PASSTHRU ACTION";
|
||||
case RPZ_DROP_ACTION: return "DROP ACTION";
|
||||
case RPZ_TCP_ONLY_ACTION: return "TCP ONLY ACTION";
|
||||
case RPZ_INVALID_ACTION: return "INVALID ACTION";
|
||||
case RPZ_LOCAL_DATA_ACTION: return "LOCAL DATA ACTION";
|
||||
}
|
||||
return "UNKNOWN RPZ ACTION";
|
||||
}
|
||||
|
||||
/** string for RPZ trigger enum */
|
||||
static const char*
|
||||
rpz_trigger_to_string(enum rpz_trigger r)
|
||||
{
|
||||
switch(r) {
|
||||
case RPZ_QNAME_TRIGGER: return "QNAME TRIGGER";
|
||||
case RPZ_CLIENT_IP_TRIGGER: return "CLIENT IP TRIGGER";
|
||||
case RPZ_RESPONSE_IP_TRIGGER: return "RESPONSE IP TRIGGER";
|
||||
case RPZ_NSDNAME_TRIGGER: return "NSDNAME TRIGGER";
|
||||
case RPZ_NSIP_TRIGGER: return "NSIP TRIGGER";
|
||||
}
|
||||
return "UNKNOWN RPZ TRIGGER";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the label that is just before the root label.
|
||||
* @param dname: dname to work on
|
||||
* @return: pointer to TLD label
|
||||
*/
|
||||
static uint8_t*
|
||||
get_tld_label(uint8_t* dname)
|
||||
{
|
||||
uint8_t* prevlab = dname;
|
||||
|
||||
/* only root label */
|
||||
if(*dname == 0)
|
||||
return NULL;
|
||||
|
||||
while(*dname) {
|
||||
dname = dname+*dname+1;
|
||||
if(*dname != 0)
|
||||
prevlab = dname;
|
||||
}
|
||||
return prevlab;
|
||||
}
|
||||
|
||||
/**
|
||||
* Classify RPZ action for RR type/rdata
|
||||
* @param rr_type: the RR type
|
||||
* @param rdatawl: RDATA with 2 bytes length
|
||||
* @param rdatalen: the length of rdatawl (including its 2 bytes length)
|
||||
* @return: the RPZ action
|
||||
*/
|
||||
static enum rpz_action
|
||||
rpz_rr_to_action(uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
|
||||
{
|
||||
char* endptr;
|
||||
uint8_t* rdata;
|
||||
int rdatalabs;
|
||||
uint8_t* tldlab = NULL;
|
||||
|
||||
switch(rr_type) {
|
||||
case LDNS_RR_TYPE_SOA:
|
||||
case LDNS_RR_TYPE_NS:
|
||||
case LDNS_RR_TYPE_DNAME:
|
||||
/* all DNSSEC-related RRs must be ignored */
|
||||
case LDNS_RR_TYPE_DNSKEY:
|
||||
case LDNS_RR_TYPE_DS:
|
||||
case LDNS_RR_TYPE_RRSIG:
|
||||
case LDNS_RR_TYPE_NSEC:
|
||||
case LDNS_RR_TYPE_NSEC3:
|
||||
return RPZ_INVALID_ACTION;
|
||||
case LDNS_RR_TYPE_CNAME:
|
||||
break;
|
||||
default:
|
||||
return RPZ_LOCAL_DATA_ACTION;
|
||||
}
|
||||
|
||||
/* use CNAME target to determine RPZ action */
|
||||
log_assert(rr_type == LDNS_RR_TYPE_CNAME);
|
||||
if(rdatalen < 3)
|
||||
return RPZ_INVALID_ACTION;
|
||||
|
||||
rdata = rdatawl + 2; /* 2 bytes of rdata length */
|
||||
if(dname_valid(rdata, rdatalen-2) != rdatalen-2)
|
||||
return RPZ_INVALID_ACTION;
|
||||
|
||||
rdatalabs = dname_count_labels(rdata);
|
||||
if(rdatalabs == 1)
|
||||
return RPZ_NXDOMAIN_ACTION;
|
||||
else if(rdatalabs == 2) {
|
||||
if(dname_subdomain_c(rdata, (uint8_t*)&"\001*\000"))
|
||||
return RPZ_NODATA_ACTION;
|
||||
else if(dname_subdomain_c(rdata,
|
||||
(uint8_t*)&"\014rpz-passthru\000"))
|
||||
return RPZ_PASSTHRU_ACTION;
|
||||
else if(dname_subdomain_c(rdata, (uint8_t*)&"\010rpz-drop\000"))
|
||||
return RPZ_DROP_ACTION;
|
||||
else if(dname_subdomain_c(rdata,
|
||||
(uint8_t*)&"\014rpz-tcp-only\000"))
|
||||
return RPZ_TCP_ONLY_ACTION;
|
||||
}
|
||||
|
||||
/* all other TLDs starting with "rpz-" are invalid */
|
||||
tldlab = get_tld_label(rdata);
|
||||
if(tldlab && dname_lab_startswith(tldlab, "rpz-", &endptr))
|
||||
return RPZ_INVALID_ACTION;
|
||||
|
||||
/* no special label found */
|
||||
return RPZ_LOCAL_DATA_ACTION;
|
||||
}
|
||||
|
||||
/** Get RPZ trigger for dname */
|
||||
static enum rpz_trigger
|
||||
rpz_dname_to_trigger(uint8_t* dname)
|
||||
{
|
||||
uint8_t* tldlab;
|
||||
char* endptr;
|
||||
tldlab = get_tld_label(dname);
|
||||
if(!tldlab || !dname_lab_startswith(tldlab, "rpz-", &endptr))
|
||||
return RPZ_QNAME_TRIGGER;
|
||||
|
||||
if(dname_subdomain_c(tldlab,
|
||||
(uint8_t*)&"\015rpz-client-ip\000"))
|
||||
return RPZ_CLIENT_IP_TRIGGER;
|
||||
else if(dname_subdomain_c(tldlab, (uint8_t*)&"\006rpz-ip\000"))
|
||||
return RPZ_RESPONSE_IP_TRIGGER;
|
||||
else if(dname_subdomain_c(tldlab, (uint8_t*)&"\013rpz-nsdname\000"))
|
||||
return RPZ_NSDNAME_TRIGGER;
|
||||
else if(dname_subdomain_c(tldlab, (uint8_t*)&"\010rpz-nsip\000"))
|
||||
return RPZ_NSIP_TRIGGER;
|
||||
|
||||
return RPZ_QNAME_TRIGGER;
|
||||
}
|
||||
|
||||
void rpz_delete(struct rpz* r)
|
||||
{
|
||||
if(!r)
|
||||
return;
|
||||
local_zones_delete(r->local_zones);
|
||||
free(r);
|
||||
}
|
||||
|
||||
int
|
||||
rpz_clear_lz(struct rpz* r)
|
||||
{
|
||||
/* must hold write lock on auth_zone */
|
||||
local_zones_delete(r->local_zones);
|
||||
if(!(r->local_zones = local_zones_create())){
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct rpz*
|
||||
rpz_create(struct config_auth* p)
|
||||
{
|
||||
struct rpz* r = calloc(1, sizeof(*r));
|
||||
if(!r)
|
||||
return 0;
|
||||
|
||||
if(!(r->local_zones = local_zones_create())){
|
||||
free(r);
|
||||
return 0;
|
||||
}
|
||||
r->taglist = memdup(p->rpz_taglist, p->rpz_taglistlen);
|
||||
r->taglistlen = p->rpz_taglistlen;
|
||||
return r;
|
||||
}
|
||||
|
||||
/** Remove RPZ zone name from dname */
|
||||
static size_t
|
||||
strip_dname_origin(uint8_t* dname, size_t dnamelen, size_t originlen,
|
||||
uint8_t* newdname)
|
||||
{
|
||||
size_t newdnamelen;
|
||||
if(dnamelen < originlen)
|
||||
return 0;
|
||||
newdnamelen = dnamelen - originlen;
|
||||
memmove(newdname, dname, newdnamelen);
|
||||
return newdnamelen + 1; /* + 1 for root label */
|
||||
}
|
||||
|
||||
/** Insert RR into RPZ's local-zone */
|
||||
static int
|
||||
rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
|
||||
enum rpz_action a, uint16_t rrtype, uint16_t rrclass, uint32_t ttl,
|
||||
uint8_t* rdata, size_t rdata_len, uint8_t* rr, size_t rr_len)
|
||||
{
|
||||
struct local_zone* z;
|
||||
enum localzone_type tp = local_zone_always_transparent;
|
||||
int dnamelabs = dname_count_labels(dname);
|
||||
char* rrstr;
|
||||
|
||||
if(a == RPZ_NXDOMAIN_ACTION)
|
||||
tp = local_zone_always_nxdomain;
|
||||
else if(a == RPZ_NODATA_ACTION)
|
||||
tp = local_zone_always_nodata;
|
||||
else if(a == RPZ_DROP_ACTION)
|
||||
tp = local_zone_deny;
|
||||
else if(a == RPZ_PASSTHRU_ACTION)
|
||||
tp = local_zone_always_transparent;
|
||||
else if(a == RPZ_LOCAL_DATA_ACTION)
|
||||
tp = local_zone_redirect;
|
||||
else {
|
||||
verbose(VERB_ALGO, "RPZ: skipping unusupported action: %s",
|
||||
rpz_action_to_string(a));
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_rw_wrlock(&r->local_zones->lock);
|
||||
/* exact match */
|
||||
z = local_zones_find(r->local_zones, dname, dnamelen, dnamelabs,
|
||||
LDNS_RR_CLASS_IN);
|
||||
if(z && a != RPZ_LOCAL_DATA_ACTION) {
|
||||
rrstr = sldns_wire2str_rr(rr, rr_len);
|
||||
verbose(VERB_ALGO, "RPZ: skipping duplicate record: '%s'",
|
||||
rrstr);
|
||||
free(rrstr);
|
||||
lock_rw_unlock(&r->local_zones->lock);
|
||||
return 0;
|
||||
}
|
||||
if(!z) {
|
||||
z = local_zones_add_zone(r->local_zones, dname, dnamelen,
|
||||
dnamelabs, rrclass, tp);
|
||||
}
|
||||
if(!z) {
|
||||
log_warn("RPZ create failed");
|
||||
lock_rw_unlock(&r->local_zones->lock);
|
||||
return 0;
|
||||
}
|
||||
if(a == RPZ_LOCAL_DATA_ACTION) {
|
||||
/* insert data. TODO synth wildcard cname target on
|
||||
* lookup */
|
||||
rrstr = sldns_wire2str_rr(rr, rr_len);
|
||||
local_zone_enter_rr(z, dname, dnamelen, dnamelabs,
|
||||
rrtype, rrclass, ttl, rdata, rdata_len, rrstr);
|
||||
free(rrstr);
|
||||
}
|
||||
lock_rw_unlock(&r->local_zones->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void
|
||||
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)
|
||||
{
|
||||
size_t policydnamelen;
|
||||
/* name is free'd in local_zone delete */
|
||||
uint8_t* policydname = calloc(1, LDNS_MAX_DOMAINLEN + 1);
|
||||
enum rpz_trigger t;
|
||||
enum rpz_action a;
|
||||
|
||||
a = rpz_rr_to_action(rr_type, rdatawl, rdatalen);
|
||||
if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen,
|
||||
policydname))) {
|
||||
free(policydname);
|
||||
return;
|
||||
}
|
||||
t = rpz_dname_to_trigger(policydname);
|
||||
if(t == RPZ_QNAME_TRIGGER) {
|
||||
rpz_insert_qname_trigger(r, policydname, policydnamelen,
|
||||
a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
|
||||
rr_len);
|
||||
}
|
||||
else {
|
||||
free(policydname);
|
||||
verbose(VERB_ALGO, "RPZ: skipping unusupported trigger: %s",
|
||||
rpz_trigger_to_string(t));
|
||||
}
|
||||
}
|
||||
|
||||
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, uint8_t* rr, size_t rr_len)
|
||||
{
|
||||
/* TODO: remove RR, used for IXFR */
|
||||
}
|
||||
|
||||
struct local_zone*
|
||||
rpz_find_zone(struct rpz* r, struct query_info* qinfo)
|
||||
{
|
||||
uint8_t* ce;
|
||||
size_t ce_len, ce_labs;
|
||||
uint8_t wc[LDNS_MAX_DOMAINLEN];
|
||||
int exact;
|
||||
struct local_zone* z = NULL;
|
||||
lock_rw_rdlock(&r->local_zones->lock);
|
||||
z = local_zones_find_le(r->local_zones, qinfo->qname,
|
||||
qinfo->qname_len, dname_count_labels(qinfo->qname),
|
||||
LDNS_RR_CLASS_IN, &exact);
|
||||
if(!z) {
|
||||
lock_rw_unlock(&r->local_zones->lock);
|
||||
return NULL;
|
||||
}
|
||||
lock_rw_unlock(&r->local_zones->lock);
|
||||
|
||||
if(exact)
|
||||
return z;
|
||||
|
||||
/* No exact match found, lookup wildcard. closest encloser must
|
||||
* be the shared parent between the qname and the best local
|
||||
* zone match, append '*' to that and do another lookup. */
|
||||
|
||||
ce = dname_get_shared_topdomain(z->name, qinfo->qname);
|
||||
if(!ce /* should not happen */ || !*ce /* root */) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return NULL;
|
||||
}
|
||||
ce_labs = dname_count_size_labels(ce, &ce_len);
|
||||
if(ce_len+2 > sizeof(wc)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return NULL;
|
||||
}
|
||||
wc[0] = 1; /* length of wildcard label */
|
||||
wc[1] = (uint8_t)'*'; /* wildcard label */
|
||||
memmove(wc+2, ce, ce_len);
|
||||
lock_rw_unlock(&z->lock);
|
||||
|
||||
lock_rw_rdlock(&r->local_zones->lock);
|
||||
z = local_zones_find_le(r->local_zones, wc,
|
||||
ce_len+2, ce_labs+1, qinfo->qclass, &exact);
|
||||
if(!z || !exact) {
|
||||
lock_rw_unlock(&r->local_zones->lock);
|
||||
return NULL;
|
||||
}
|
||||
lock_rw_rdlock(&z->lock);
|
||||
lock_rw_unlock(&r->local_zones->lock);
|
||||
return z;
|
||||
}
|
||||
|
||||
/** print log information for an applied RPZ policy. Based on local-zone's
|
||||
* lz_inform_print().
|
||||
*/
|
||||
static void
|
||||
rpz_inform_print(struct local_zone* z, struct query_info* qinfo,
|
||||
struct comm_reply* repinfo)
|
||||
{
|
||||
char ip[128], txt[512];
|
||||
char zname[LDNS_MAX_DOMAINLEN+1];
|
||||
uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
|
||||
dname_str(z->name, zname);
|
||||
addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
|
||||
snprintf(txt, sizeof(txt), "RPZ applied %s %s %s@%u", zname,
|
||||
local_zone_type2str(z->type), ip, (unsigned)port);
|
||||
log_nametypeclass(0, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
|
||||
}
|
||||
|
||||
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 rpz* r;
|
||||
int ret;
|
||||
struct local_zone* z = NULL;
|
||||
struct local_data* ld = NULL;
|
||||
lock_rw_rdlock(&az->rpz_lock);
|
||||
for(r = az->rpz_first; r && !z; r = r->next) {
|
||||
if(!r->taglist || taglist_intersect(r->taglist,
|
||||
r->taglistlen, taglist, taglen))
|
||||
z = rpz_find_zone(r, qinfo);
|
||||
}
|
||||
lock_rw_unlock(&az->rpz_lock);
|
||||
if(!z)
|
||||
return 0;
|
||||
|
||||
if(z->type == local_zone_redirect && local_data_answer(z, env, qinfo,
|
||||
edns, repinfo, buf, temp, dname_count_labels(qinfo->qname),
|
||||
&ld, z->type, -1, NULL, 0, NULL, 0)) {
|
||||
rpz_inform_print(z, qinfo, repinfo);
|
||||
return !qinfo->local_alias;
|
||||
}
|
||||
|
||||
ret = local_zones_zone_answer(z, env, qinfo, edns, repinfo, buf, temp,
|
||||
0 /* no local data used */, z->type);
|
||||
lock_rw_unlock(&z->lock);
|
||||
if(ret)
|
||||
rpz_inform_print(z, qinfo, repinfo);
|
||||
|
||||
return ret;
|
||||
}
|
||||
163
services/rpz.h
Normal file
163
services/rpz.h
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* 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/config_file.h"
|
||||
#include "services/authzone.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
|
||||
/**
|
||||
* RPZ containing policies. Pointed to from corresponding authz-one. 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;
|
||||
uint8_t* taglist;
|
||||
size_t taglistlen;
|
||||
struct rpz* next;
|
||||
struct rpz* prev;
|
||||
/* tags */
|
||||
};
|
||||
|
||||
/**
|
||||
* 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 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 */
|
||||
};
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
void 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
|
||||
* @param rr: the complete RR, for logging purposes
|
||||
* @param rr_len: the length of the complete RR
|
||||
*/
|
||||
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, uint8_t* rr, size_t rr_len);
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* Delete RPZ
|
||||
* @param r: RPZ struct to delete
|
||||
*/
|
||||
void rpz_delete(struct rpz* r);
|
||||
|
||||
/**
|
||||
* Clear local-zones in RPZ, used after reloading file or AXFR/HTTP transfer.
|
||||
* @param r: RPZ to use
|
||||
*/
|
||||
int rpz_clear_lz(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);
|
||||
|
||||
#endif /* SERVICES_RPZ_H */
|
||||
Loading…
Reference in a new issue