This commit is contained in:
Wouter Wijngaards 2026-01-29 08:13:48 +00:00 committed by GitHub
commit 26052ea3ef
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 423 additions and 142 deletions

View file

@ -1339,7 +1339,7 @@ perform_zone_add(RES* ssl, struct local_zones* zones, char* arg)
return 1;
}
if(!local_zones_add_zone(zones, nm, nmlen,
nmlabs, LDNS_RR_CLASS_IN, t)) {
nmlabs, LDNS_RR_CLASS_IN, t, NULL)) {
lock_rw_unlock(&zones->lock);
ssl_printf(ssl, "error out of memory\n");
return 0;

View file

@ -1385,7 +1385,7 @@ int ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name,
return UB_NOERROR;
}
if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs,
LDNS_RR_CLASS_IN, t)) {
LDNS_RR_CLASS_IN, t, NULL)) {
lock_rw_unlock(&ctx->local_zones->lock);
return UB_NOMEM;
}

View file

@ -102,7 +102,7 @@ respip_set_get_tree(struct respip_set* set)
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)
socklen_t addrlen, int net, int create)
{
struct resp_addr* node;
log_assert(set);
@ -119,7 +119,10 @@ respip_sockaddr_find_or_create(struct respip_set* set, struct sockaddr_storage*
addrlen, net)) {
/* We know we didn't find it, so this should be
* impossible. */
log_warn("unexpected: duplicate address: %s", ipstr);
char a[128];
addr_to_str(addr, addrlen, a, sizeof(a));
log_warn("unexpected: duplicate address: %s/%d",
a, net);
}
}
return node;
@ -154,8 +157,7 @@ respip_find_or_create(struct respip_set* set, const char* ipstr, int create)
log_err("cannot parse netblock: '%s'", ipstr);
return NULL;
}
return respip_sockaddr_find_or_create(set, &addr, addrlen, net, create,
ipstr);
return respip_sockaddr_find_or_create(set, &addr, addrlen, net, create);
}
static int
@ -291,6 +293,49 @@ respip_enter_rr(struct regional* region, struct resp_addr* raddr,
return rrset_insert_rr(region, pd, rdata, rdata_len, ttl, rrstr);
}
int
respip_enter_rr_wol(struct regional* region, struct resp_addr* raddr,
uint16_t rrtype, uint16_t rrclass, time_t ttl, uint8_t* rdata_wol,
size_t rdata_len, 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) {
char* rrstr = dname_rdata_to_str(NULL, 0, rrtype,
rrclass, ttl, rdata_wol, rdata_len);
log_err("CNAME response-ip data (%s) can not co-exist with other "
"response-ip data for netblock %s", (rrstr?rrstr:"<out of memory>"), netblockstr);
free(rrstr);
return 0;
} else if (raddr->data &&
raddr->data->rk.type == htons(LDNS_RR_TYPE_CNAME)) {
char* rrstr = dname_rdata_to_str(NULL, 0, rrtype,
rrclass, ttl, rdata_wol, rdata_len);
log_err("response-ip data (%s) can not be added; CNAME response-ip "
"data already in place for netblock %s", (rrstr?rrstr:"<out of memory>"), netblockstr);
free(rrstr);
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))) {
char* rrstr = dname_rdata_to_str(NULL, 0, rrtype,
rrclass, ttl, rdata_wol, rdata_len);
log_err("response-ip data %s record type does not correspond "
"to netblock %s address family", (rrstr?rrstr:"<out of memory>"), netblockstr);
free(rrstr);
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_wol(region, pd, rdata_wol, rdata_len, ttl);
}
static int
respip_enter_rrstr(struct regional* region, struct resp_addr* raddr,
const char* rrstr, const char* netblock)

View file

@ -276,12 +276,11 @@ void respip_inform_print(struct respip_action_info* respip_actinfo,
* @param addrlen: length of addr.
* @param net: netblock to lookup.
* @param create: create node if it does not exist when 1.
* @param ipstr: human readable 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);
socklen_t addrlen, int net, int create);
/**
* Add RR to resp_addr's RRset. Create RRset if not existing.
@ -301,6 +300,22 @@ 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);
/**
* 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. Without prefix len.
* @param rdata_len: length of rdata.
* @param netblockstr: netblock as string, for logging
* @return 0 on error
*/
int respip_enter_rr_wol(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* netblockstr);
/**
* Delete resp_addr node from tree.
* @param set: struct containing tree. Must hold write lock.

View file

@ -1189,8 +1189,7 @@ az_domain_add_rr(struct auth_data* node, uint16_t rr_type, uint32_t rr_ttl,
static int
az_insert_rr_as_rdata(struct auth_zone* z, uint8_t* dname, size_t dname_len,
uint16_t rr_type, uint16_t rr_class, uint32_t rr_ttl,
uint8_t* rdata_wol, size_t rdatalen, int* duplicate,
uint8_t* rr, size_t rr_len)
uint8_t* rdata_wol, size_t rdatalen, int* duplicate)
{
struct auth_data* node;
if(rr_class != z->dclass) {
@ -1207,35 +1206,9 @@ az_insert_rr_as_rdata(struct auth_zone* z, uint8_t* dname, size_t dname_len,
return 0;
}
if(z->rpz) {
uint8_t* rdata_wl;
uint8_t buf[65536];
if(rr == NULL) {
/* spool it into buffer. */
log_assert(dname);
if(dname_len + 10 /* type, class, ttl, rdlength */ +
rdatalen > sizeof(buf)) {
char dstr[LDNS_MAX_DOMAINLEN], t[16], c[16];
dname_str(dname, dstr);
sldns_wire2str_type_buf(rr_type, t, sizeof(t));
sldns_wire2str_class_buf(rr_class, c, sizeof(c));
log_err("record exceeds buffer length, %s %s %s", dstr, c, t);
return 0;
}
rr = buf;
rr_len = dname_len
+ 10 /* type, class, ttl, rdlength */ +
rdatalen;
memcpy(buf, dname, dname_len);
sldns_write_uint16(buf+dname_len, rr_type);
sldns_write_uint16(buf+dname_len+2, rr_class);
sldns_write_uint32(buf+dname_len+4, rr_ttl);
sldns_write_uint16(buf+dname_len+8, rdatalen);
memmove(buf+dname_len+10, rdata_wol, rdatalen);
}
rdata_wl = sldns_wirerr_get_rdatawl(rr, rr_len, dname_len);
if(!(rpz_insert_rr(z->rpz, z->name, z->namelen, dname,
dname_len, rr_type, rr_class, rr_ttl, rdata_wl,
rdatalen+2, rr, rr_len)))
dname_len, rr_type, rr_class, rr_ttl, rdata_wol,
rdatalen)))
return 0;
}
return 1;
@ -1256,7 +1229,7 @@ az_insert_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len,
uint8_t* rdata_wol = sldns_wirerr_get_rdata(rr, rr_len, dname_len);
return az_insert_rr_as_rdata(z, dname, dname_len, rr_type, rr_class,
rr_ttl, rdata_wol, rdatalen, duplicate, rr, rr_len);
rr_ttl, rdata_wol, rdatalen, duplicate);
}
/** Remove rr from node, ignores nonexisting RRs,
@ -1690,7 +1663,7 @@ az_parse_accept(zone_parser_t *parser, const zone_name_t *owner,
/* Duplicates can be ignored, do not insert them twice. */
if(!az_insert_rr_as_rdata(state->z, (uint8_t*)owner->octets,
owner->length, type, dclass, ttl, (uint8_t*)rdata, rdlength,
NULL, NULL, 0)) {
NULL)) {
char dname[LDNS_MAX_DOMAINLEN], t[16], c[16];
dname_str((uint8_t*)owner->octets, dname);
sldns_wire2str_type_buf(type, t, sizeof(t));

View file

@ -41,6 +41,7 @@
#include "config.h"
#include "services/localzone.h"
#include "sldns/str2wire.h"
#include "sldns/wire2str.h"
#include "util/regional.h"
#include "util/config_file.h"
#include "util/data/dname.h"
@ -356,6 +357,22 @@ rr_is_duplicate(struct packed_rrset_data* pd, uint8_t* rdata, size_t rdata_len)
return 0;
}
/** see if rdata is duplicate */
static int
rr_is_duplicate_wol(struct packed_rrset_data* d, uint8_t* rdata_wol, size_t len)
{
size_t i, rdatawl_len = len+2;
uint16_t len16 = htons(len);
for(i=0; i<d->count + d->rrsig_count; i++) {
if(d->rr_len[i] != rdatawl_len)
continue;
if(memcmp(d->rr_data[i], &len16, 2) == 0 &&
memcmp(d->rr_data[i]+2, rdata_wol, len) == 0)
return 1;
}
return 0;
}
/** new local_rrset */
static struct local_rrset*
new_local_rrset(struct regional* region, struct local_data* node,
@ -393,6 +410,49 @@ new_local_rrset(struct regional* region, struct local_data* node,
return rrset;
}
/** insert RR into RRset data structure; Wastes a couple of bytes */
int
rrset_insert_rr_wol(struct regional* region, struct packed_rrset_data* pd,
uint8_t* rdata_wol, size_t rdata_len, time_t ttl)
{
size_t* oldlen = pd->rr_len;
time_t* oldttl = pd->rr_ttl;
uint8_t** olddata = pd->rr_data;
/* add RR to rrset */
if(pd->count > LOCALZONE_RRSET_COUNT_MAX) {
log_warn("RRset has more than %d records, record ignored",
LOCALZONE_RRSET_COUNT_MAX);
return 1;
}
pd->count++;
pd->rr_len = regional_alloc(region, sizeof(*pd->rr_len)*pd->count);
pd->rr_ttl = regional_alloc(region, sizeof(*pd->rr_ttl)*pd->count);
pd->rr_data = regional_alloc(region, sizeof(*pd->rr_data)*pd->count);
if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) {
log_err("out of memory");
return 0;
}
if(pd->count > 1) {
memcpy(pd->rr_len+1, oldlen,
sizeof(*pd->rr_len)*(pd->count-1));
memcpy(pd->rr_ttl+1, oldttl,
sizeof(*pd->rr_ttl)*(pd->count-1));
memcpy(pd->rr_data+1, olddata,
sizeof(*pd->rr_data)*(pd->count-1));
}
pd->rr_len[0] = rdata_len+2;
pd->rr_ttl[0] = ttl;
pd->rr_data[0] = regional_alloc(region, rdata_len+2);
if(!pd->rr_data[0]) {
log_err("out of memory");
return 0;
}
sldns_write_uint16(pd->rr_data[0], rdata_len);
memmove(pd->rr_data[0]+2, rdata_wol, rdata_len);
return 1;
}
/** insert RR into RRset data structure; Wastes a couple of bytes */
int
rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
@ -503,6 +563,48 @@ lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
return 1;
}
/* Mark the SOA record for the zone. This only marks the SOA rrset; the data
* for the RR is entered later on local_zone_enter_rr() as with the other
* records. An artificial soa_negative record with a modified TTL (minimum of
* the TTL and the SOA.MINIMUM) is also created and marked for usage with
* negative answers and to avoid allocations during those answers. */
static int
lz_mark_soa_for_zone_wol(struct local_zone* z, struct ub_packed_rrset_key* soa_rrset,
uint8_t* rdata_wol, size_t rdata_len, time_t ttl)
{
struct packed_rrset_data* pd = (struct packed_rrset_data*)
regional_alloc_zero(z->region, sizeof(*pd));
struct ub_packed_rrset_key* rrset_negative = (struct ub_packed_rrset_key*)
regional_alloc_zero(z->region, sizeof(*rrset_negative));
time_t minimum;
if(!rrset_negative||!pd) {
log_err("out of memory");
return 0;
}
/* Mark the original SOA record and then continue with the negative one. */
z->soa = soa_rrset;
rrset_negative->entry.key = rrset_negative;
pd->trust = rrset_trust_prim_noglue;
pd->security = sec_status_insecure;
rrset_negative->entry.data = pd;
rrset_negative->rk.dname = soa_rrset->rk.dname;
rrset_negative->rk.dname_len = soa_rrset->rk.dname_len;
rrset_negative->rk.type = soa_rrset->rk.type;
rrset_negative->rk.rrset_class = soa_rrset->rk.rrset_class;
if(!rrset_insert_rr_wol(z->region, pd, rdata_wol, rdata_len, ttl))
return 0;
/* last 4 bytes are minimum ttl in network format */
if(pd->count == 0 || pd->rr_len[0] < 2+4)
return 0;
minimum = (time_t)sldns_read_uint32(pd->rr_data[0]+(pd->rr_len[0]-4));
minimum = ttl<minimum?ttl:minimum;
pd->ttl = minimum;
pd->rr_ttl[0] = minimum;
z->soa_negative = rrset_negative;
return 1;
}
/* Mark the SOA record for the zone. This only marks the SOA rrset; the data
* for the RR is entered later on local_zone_enter_rr() as with the other
* records. An artificial soa_negative record with a modified TTL (minimum of
@ -545,6 +647,96 @@ lz_mark_soa_for_zone(struct local_zone* z, struct ub_packed_rrset_key* soa_rrset
return 1;
}
/**
* Convert dname, type, class, ttl, rdata to an rr string.
* rdata without prefixed length. returned string is malloced.
*/
char* dname_rdata_to_str(uint8_t* dname, size_t dnamelen, uint16_t rrtype,
uint16_t rrclass, uint32_t ttl, uint8_t* rdata, size_t rdata_len)
{
char buf[65536], t[32], c[32], d[1024], result[65536+32+32+1024+1024];
buf[0]=0; buf[sizeof(buf)-1]=0;
d[0]=0; d[sizeof(d)-1]=0;
(void)sldns_wire2str_rdata_buf(rdata, rdata_len, buf, sizeof(buf),
rrtype);
(void)sldns_wire2str_type_buf(rrtype, t, sizeof(t));
(void)sldns_wire2str_class_buf(rrclass, c, sizeof(c));
if(dname)
(void)sldns_wire2str_dname_buf(dname, dnamelen, d, sizeof(d));
snprintf(result, sizeof(result), "%s%s%u %s %s %s",
dname, (dname?" ":""), (unsigned)ttl, c, t, d);
return strdup(result);
}
int
local_zone_enter_rr_wol(struct local_zone* z, uint8_t* nm, size_t nmlen,
int nmlabs, uint16_t rrtype, uint16_t rrclass, time_t ttl,
uint8_t* rdata_wol, size_t rdata_len)
{
struct local_data* node;
struct local_rrset* rrset;
struct packed_rrset_data* pd;
if(!lz_find_create_node(z, nm, nmlen, nmlabs, &node)) {
return 0;
}
log_assert(node);
/* Reject it if we would end up having CNAME and other data (including
* another CNAME) for a redirect zone. */
if((z->type == local_zone_redirect ||
z->type == local_zone_inform_redirect) && node->rrsets) {
const char* othertype = NULL;
if (rrtype == LDNS_RR_TYPE_CNAME)
othertype = "other";
else if (node->rrsets->rrset->rk.type ==
htons(LDNS_RR_TYPE_CNAME)) {
othertype = "CNAME";
}
if(othertype) {
char* rrstr = dname_rdata_to_str(nm, nmlen, rrtype,
rrclass, ttl, rdata_wol, rdata_len);
log_err("local-data '%s' in redirect zone must not "
"coexist with %s local-data", (rrstr?rrstr:"<out of memory>"), othertype);
free(rrstr);
return 0;
}
}
rrset = local_data_find_type(node, rrtype, 0);
if(!rrset) {
rrset = new_local_rrset(z->region, node, rrtype, rrclass);
if(!rrset)
return 0;
if(query_dname_compare(node->name, z->name) == 0) {
if(rrtype == LDNS_RR_TYPE_NSEC)
rrset->rrset->rk.flags = PACKED_RRSET_NSEC_AT_APEX;
if(rrtype == LDNS_RR_TYPE_SOA &&
!lz_mark_soa_for_zone_wol(z, rrset->rrset, rdata_wol, rdata_len, ttl))
return 0;
}
}
pd = (struct packed_rrset_data*)rrset->rrset->entry.data;
log_assert(rrset && pd);
/* check for duplicate RR */
if(rr_is_duplicate_wol(pd, rdata_wol, rdata_len)) {
char* rrstr = dname_rdata_to_str(nm, nmlen, rrtype,
rrclass, ttl, rdata_wol, rdata_len);
verbose(VERB_ALGO, "ignoring duplicate RR: %s", (rrstr?rrstr:"<out of memory>"));
free(rrstr);
return 1;
}
if(pd->count > LOCALZONE_RRSET_COUNT_MAX) {
char* rrstr = dname_rdata_to_str(nm, nmlen, rrtype,
rrclass, ttl, rdata_wol, rdata_len);
log_warn("RRset %s has more than %d records, record ignored",
(rrstr?rrstr:"<out of memory>"), LOCALZONE_RRSET_COUNT_MAX);
free(rrstr);
return 1;
}
return rrset_insert_rr_wol(z->region, pd, rdata_wol, rdata_len, ttl);
}
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,
@ -2039,7 +2231,7 @@ set_kiddo_parents(struct local_zone* z, struct local_zone* match,
struct local_zone* local_zones_add_zone(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass,
enum localzone_type tp)
enum localzone_type tp, int* duplicate)
{
int exact;
/* create */
@ -2047,6 +2239,7 @@ struct local_zone* local_zones_add_zone(struct local_zones* zones,
struct local_zone* z = local_zone_create(name, len, labs, tp, dclass);
if(!z) {
free(name);
if(duplicate) *duplicate = 0;
return NULL;
}
lock_rw_wrlock(&z->lock);
@ -2060,8 +2253,14 @@ struct local_zone* local_zones_add_zone(struct local_zones* zones,
if(exact||!rbtree_insert(&zones->ztree, &z->node)) {
/* duplicate entry! */
lock_rw_unlock(&z->lock);
if(duplicate) {
*duplicate = 1;
z->name = NULL; /* Do not delete the name in
local_zone_delete. */
}
local_zone_delete(z);
log_err("internal: duplicate entry in local_zones_add_zone");
if(duplicate == NULL)
log_err("internal: duplicate entry in local_zones_add_zone");
return NULL;
}
@ -2105,7 +2304,7 @@ local_zones_add_RR(struct local_zones* zones, const char* rr)
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
if(!z) {
z = local_zones_add_zone(zones, rr_name, len, labs, rr_class,
local_zone_transparent);
local_zone_transparent, NULL);
if(!z) {
lock_rw_unlock(&zones->lock);
return 0;

View file

@ -403,11 +403,17 @@ local_zones_find_le(struct local_zones* zones,
* @param labs: labelcount of name.
* @param dclass: class to add.
* @param tp: type.
* @param duplicate: Allows to check if a NULL return from the function is a
* memory error, or a duplicate entry. Pass NULL to have it not returned,
* the name is freed on errors, and for a duplicate a log message is
* printed. Pass not NULL, and when the error is a duplicate, the function
* returns NULL, and the variable is set true. The name is not freed
* when there is a duplicate, no error is printed by this function.
* @return local_zone or NULL on error, caller must printout memory error.
*/
struct local_zone* local_zones_add_zone(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass,
enum localzone_type tp);
enum localzone_type tp, int* duplicate);
/**
* Delete a zone. Caller must hold the zones lock.
@ -526,6 +532,18 @@ 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);
/**
* Insert specified rdata into the specified resource record.
* @param region: allocator
* @param pd: data portion of the destination resource record
* @param rdata_wol: source rdata, without prefix len.
* @param rdata_len: source rdata length
* @param ttl: time to live
* @return 1 on success; 0 otherwise.
*/
int rrset_insert_rr_wol(struct regional* region, struct packed_rrset_data* pd,
uint8_t* rdata_wol, size_t rdata_len, time_t ttl);
/**
* Remove RR from rrset that is created using localzone's rrset_insert_rr.
* @param pd: the RRset containing the RR to remove
@ -631,6 +649,24 @@ 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);
/**
* Add RR to local zone. Without prefix length on rdata.
* @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_wol: RDATA of RR to add, without prefix length.
* @param rdata_len: length of rdata, without prefix length.
* @return: 1 on success
*/
int
local_zone_enter_rr_wol(struct local_zone* z, uint8_t* nm, size_t nmlen,
int nmlabs, uint16_t rrtype, uint16_t rrclass, time_t ttl,
uint8_t* rdata_wol, size_t rdata_len);
/**
* Find a data node by exact name for a local zone
* @param z: local_zone containing data tree
@ -674,4 +710,12 @@ lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
*/
void
lz_init_parents(struct local_zones* zones);
/**
* Convert dname, type, class, ttl, rdata to an rr string.
* rdata without prefixed length. returned string is malloced.
*/
char* dname_rdata_to_str(uint8_t* dname, size_t dnamelen, uint16_t rrtype,
uint16_t rrclass, uint32_t ttl, uint8_t* rdata, size_t rdata_len);
#endif /* SERVICES_LOCALZONE_H */

View file

@ -170,15 +170,14 @@ rpz_type_ignored(uint16_t rr_type)
/**
* 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)
* @param rdata: RDATA without 2 bytes length
* @param rdatalen: the length of rdatawl (not 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)
rpz_rr_to_action_wol(uint16_t rr_type, uint8_t* rdata, size_t rdatalen)
{
char* endptr;
uint8_t* rdata;
int rdatalabs;
uint8_t* tldlab = NULL;
@ -202,11 +201,10 @@ rpz_rr_to_action(uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
/* use CNAME target to determine RPZ action */
log_assert(rr_type == LDNS_RR_TYPE_CNAME);
if(rdatalen < 3)
if(rdatalen < 1)
return RPZ_INVALID_ACTION;
rdata = rdatawl + 2; /* 2 bytes of rdata length */
if(dname_valid(rdata, rdatalen-2) != rdatalen-2)
if(dname_valid(rdata, rdatalen) != rdatalen)
return RPZ_INVALID_ACTION;
rdatalabs = dname_count_labels(rdata);
@ -226,7 +224,7 @@ rpz_rr_to_action(uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
}
/* all other TLDs starting with "rpz-" are invalid */
tldlab = get_tld_label(rdata, rdatalen-2);
tldlab = get_tld_label(rdata, rdatalen);
if(tldlab && dname_lab_startswith(tldlab, "rpz-", &endptr))
return RPZ_INVALID_ACTION;
@ -234,6 +232,21 @@ rpz_rr_to_action(uint16_t rr_type, uint8_t* rdatawl, size_t rdatalen)
return RPZ_LOCAL_DATA_ACTION;
}
/**
* 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)
{
if(rdatalen < 2)
return RPZ_INVALID_ACTION;
return rpz_rr_to_action_wol(rr_type, rdatawl+2, rdatalen-2);
}
static enum localzone_type
rpz_action_to_localzone_type(enum rpz_action a)
{
@ -658,7 +671,7 @@ strip_dname_origin(uint8_t* dname, size_t dnamelen, size_t originlen,
static void
rpz_insert_local_zones_trigger(struct local_zones* lz, 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)
uint32_t ttl, uint8_t* rdata, size_t rdata_len)
{
struct local_zone* z;
enum localzone_type tp = local_zone_always_transparent;
@ -685,20 +698,41 @@ rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname,
return;
}
/* For not a local-data action.
* Insert the zone, then detect a duplicate, instead of find it first,
* for speed of searching the tree once. */
if(a != RPZ_LOCAL_DATA_ACTION) {
int duplicate = 0;
lock_rw_wrlock(&lz->lock);
tp = rpz_action_to_localzone_type(a);
z = local_zones_add_zone(lz, dname, dnamelen,
dnamelabs, rrclass, tp, &duplicate);
if(z == NULL) {
if(duplicate) {
char* rrstr = dname_rdata_to_str(dname, dnamelen, rrtype,
rrclass, ttl, rdata, rdata_len);
verbose(VERB_ALGO, "rpz: skipping duplicate record: %s", (rrstr?rrstr:"<out of memory>"));
free(rrstr);
free(dname);
lock_rw_unlock(&lz->lock);
return;
}
log_warn("rpz: create failed, out of memory");
lock_rw_unlock(&lz->lock);
/* dname will be free'd in failed local_zone_create() */
return;
}
lock_rw_unlock(&lz->lock);
return;
}
lock_rw_wrlock(&lz->lock);
/* exact match */
z = local_zones_find(lz, dname, dnamelen, dnamelabs, LDNS_RR_CLASS_IN);
if(z != NULL && a != RPZ_LOCAL_DATA_ACTION) {
char* rrstr = sldns_wire2str_rr(rr, rr_len);
if(rrstr == NULL) {
log_err("malloc error while inserting rpz nsdname trigger");
free(dname);
lock_rw_unlock(&lz->lock);
return;
}
if(rrstr[0])
rrstr[strlen(rrstr)-1]=0; /* remove newline */
verbose(VERB_ALGO, "rpz: skipping duplicate record: '%s'", rrstr);
char* rrstr = dname_rdata_to_str(dname, dnamelen, rrtype,
rrclass, ttl, rdata, rdata_len);
verbose(VERB_ALGO, "rpz: skipping duplicate record: %s", (rrstr?rrstr:"<out of memory>"));
free(rrstr);
free(dname);
lock_rw_unlock(&lz->lock);
@ -707,7 +741,7 @@ rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname,
if(z == NULL) {
tp = rpz_action_to_localzone_type(a);
z = local_zones_add_zone(lz, dname, dnamelen,
dnamelabs, rrclass, tp);
dnamelabs, rrclass, tp, NULL);
if(z == NULL) {
log_warn("rpz: create failed");
lock_rw_unlock(&lz->lock);
@ -717,18 +751,10 @@ rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname,
newzone = 1;
}
if(a == RPZ_LOCAL_DATA_ACTION) {
char* rrstr = sldns_wire2str_rr(rr, rr_len);
if(rrstr == NULL) {
log_err("malloc error while inserting rpz nsdname trigger");
free(dname);
lock_rw_unlock(&lz->lock);
return;
}
lock_rw_wrlock(&z->lock);
local_zone_enter_rr(z, dname, dnamelen, dnamelabs, rrtype,
rrclass, ttl, rdata, rdata_len, rrstr);
local_zone_enter_rr_wol(z, dname, dnamelen, dnamelabs, rrtype,
rrclass, ttl, rdata, rdata_len);
lock_rw_unlock(&z->lock);
free(rrstr);
}
if(!newzone) {
free(dname);
@ -748,7 +774,7 @@ rpz_log_dname(char const* msg, uint8_t* dname, size_t dname_len)
static void
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)
uint8_t* rdata, size_t rdata_len)
{
if(a == RPZ_INVALID_ACTION) {
verbose(VERB_ALGO, "rpz: skipping invalid action");
@ -757,7 +783,7 @@ rpz_insert_qname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
}
rpz_insert_local_zones_trigger(r->local_zones, dname, dnamelen, a, rrtype,
rrclass, ttl, rdata, rdata_len, rr, rr_len);
rrclass, ttl, rdata, rdata_len);
}
static int
@ -799,7 +825,7 @@ rpz_strip_nsdname_suffix(uint8_t* dname, size_t maxdnamelen,
static void
rpz_insert_nsdname_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)
uint8_t* rdata, size_t rdata_len)
{
uint8_t* dname_stripped = NULL;
size_t dnamelen_stripped = 0;
@ -814,32 +840,22 @@ rpz_insert_nsdname_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
/* dname_stripped is consumed or freed by the insert routine */
rpz_insert_local_zones_trigger(r->nsdname_zones, dname_stripped,
dnamelen_stripped, a, rrtype, rrclass, ttl, rdata, rdata_len,
rr, rr_len);
dnamelen_stripped, a, rrtype, rrclass, ttl, rdata, rdata_len);
}
static int
rpz_insert_ipaddr_based_trigger(struct respip_set* set, struct sockaddr_storage* addr,
socklen_t addrlen, int net, 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)
uint16_t rrclass, uint32_t ttl, uint8_t* rdata, size_t rdata_len)
{
struct resp_addr* node;
char* rrstr;
enum respip_action respa = rpz_action_to_respip_action(a);
lock_rw_wrlock(&set->lock);
rrstr = sldns_wire2str_rr(rr, rr_len);
if(rrstr == NULL) {
log_err("malloc error while inserting rpz ipaddr based trigger");
lock_rw_unlock(&set->lock);
return 0;
}
node = respip_sockaddr_find_or_create(set, addr, addrlen, net, 1, rrstr);
node = respip_sockaddr_find_or_create(set, addr, addrlen, net, 1);
if(node == NULL) {
lock_rw_unlock(&set->lock);
free(rrstr);
return 0;
}
@ -849,12 +865,11 @@ rpz_insert_ipaddr_based_trigger(struct respip_set* set, struct sockaddr_storage*
node->action = respa;
if(a == RPZ_LOCAL_DATA_ACTION) {
respip_enter_rr(set->region, node, rrtype,
rrclass, ttl, rdata, rdata_len, rrstr, "");
respip_enter_rr_wol(set->region, node, rrtype,
rrclass, ttl, rdata, rdata_len, "");
}
lock_rw_unlock(&node->lock);
free(rrstr);
return 1;
}
@ -890,17 +905,6 @@ rpz_clientip_ensure_entry(struct clientip_synthesized_rrset* set,
return node;
}
static void
rpz_report_rrset_error(const char* msg, uint8_t* rr, size_t rr_len) {
char* rrstr = sldns_wire2str_rr(rr, rr_len);
if(rrstr == NULL) {
log_err("malloc error while inserting rpz clientip based record");
return;
}
log_err("rpz: unexpected: unable to insert %s: %s", msg, rrstr);
free(rrstr);
}
/* from localzone.c; difference is we don't have a dname */
static struct local_rrset*
rpz_clientip_new_rrset(struct regional* region,
@ -958,14 +962,13 @@ rpz_clientip_enter_rr(struct regional* region, struct clientip_synthesized_rr* r
return 0;
}
return rrset_insert_rr(region, rrset->rrset->entry.data, rdata, rdata_len, ttl, "");
return rrset_insert_rr_wol(region, rrset->rrset->entry.data, rdata, rdata_len, ttl);
}
static int
rpz_clientip_insert_trigger_rr(struct clientip_synthesized_rrset* set, struct sockaddr_storage* addr,
socklen_t addrlen, int net, 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)
uint16_t rrclass, uint32_t ttl, uint8_t* rdata, size_t rdata_len)
{
struct clientip_synthesized_rr* node;
@ -973,8 +976,14 @@ rpz_clientip_insert_trigger_rr(struct clientip_synthesized_rrset* set, struct so
node = rpz_clientip_ensure_entry(set, addr, addrlen, net);
if(node == NULL) {
char as[64], *rrstr;
lock_rw_unlock(&set->lock);
rpz_report_rrset_error("client ip address", rr, rr_len);
addr_to_str(addr, addrlen, as, sizeof(as));
rrstr = dname_rdata_to_str(NULL, 0, rrtype, rrclass, ttl,
rdata, rdata_len);
log_err("rpz: unexpected: unable to insert %s: %s/%d %s",
"client ip address", as, net, (rrstr?rrstr:"<out of memory>"));
free(rrstr);
return 0;
}
@ -1000,7 +1009,7 @@ rpz_clientip_insert_trigger_rr(struct clientip_synthesized_rrset* set, struct so
static int
rpz_insert_clientip_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)
uint8_t* rdata, size_t rdata_len)
{
struct sockaddr_storage addr;
socklen_t addrlen;
@ -1016,13 +1025,13 @@ rpz_insert_clientip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
}
return rpz_clientip_insert_trigger_rr(r->client_set, &addr, addrlen, net,
a, rrtype, rrclass, ttl, rdata, rdata_len, rr, rr_len);
a, rrtype, rrclass, ttl, rdata, rdata_len);
}
static int
rpz_insert_nsip_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)
uint8_t* rdata, size_t rdata_len)
{
struct sockaddr_storage addr;
socklen_t addrlen;
@ -1038,14 +1047,14 @@ rpz_insert_nsip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
}
return rpz_clientip_insert_trigger_rr(r->ns_set, &addr, addrlen, net,
a, rrtype, rrclass, ttl, rdata, rdata_len, rr, rr_len);
a, rrtype, rrclass, ttl, rdata, rdata_len);
}
/** Insert RR into RPZ's respip_set */
static int
rpz_insert_response_ip_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)
uint8_t* rdata, size_t rdata_len)
{
struct sockaddr_storage addr;
socklen_t addrlen;
@ -1070,13 +1079,13 @@ rpz_insert_response_ip_trigger(struct rpz* r, uint8_t* dname, size_t dnamelen,
}
return rpz_insert_ipaddr_based_trigger(r->respip_set, &addr, addrlen, net,
a, rrtype, rrclass, ttl, rdata, rdata_len, rr, rr_len);
a, rrtype, rrclass, ttl, rdata, rdata_len);
}
int
rpz_insert_rr(struct rpz* r, uint8_t* azname, 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)
uint8_t* rdatawol, size_t rdatalen)
{
size_t policydnamelen;
/* name is free'd in local_zone delete */
@ -1110,7 +1119,7 @@ rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname,
return 0;
}
a = rpz_rr_to_action(rr_type, rdatawl, rdatalen);
a = rpz_rr_to_action_wol(rr_type, rdatawol, rdatalen);
if(!(policydnamelen = strip_dname_origin(dname, dnamelen, aznamelen,
policydname, (dnamelen-aznamelen)+1))) {
free(policydname);
@ -1125,27 +1134,22 @@ rpz_insert_rr(struct rpz* r, uint8_t* azname, size_t aznamelen, uint8_t* dname,
if(t == RPZ_QNAME_TRIGGER) {
/* policydname will be consumed, no free */
rpz_insert_qname_trigger(r, policydname, policydnamelen,
a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
rr_len);
a, rr_type, rr_class, rr_ttl, rdatawol, rdatalen);
} else if(t == RPZ_RESPONSE_IP_TRIGGER) {
rpz_insert_response_ip_trigger(r, policydname, policydnamelen,
a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
rr_len);
a, rr_type, rr_class, rr_ttl, rdatawol, rdatalen);
free(policydname);
} else if(t == RPZ_CLIENT_IP_TRIGGER) {
rpz_insert_clientip_trigger(r, policydname, policydnamelen,
a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
rr_len);
a, rr_type, rr_class, rr_ttl, rdatawol, rdatalen);
free(policydname);
} else if(t == RPZ_NSIP_TRIGGER) {
rpz_insert_nsip_trigger(r, policydname, policydnamelen,
a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
rr_len);
a, rr_type, rr_class, rr_ttl, rdatawol, rdatalen);
free(policydname);
} else if(t == RPZ_NSDNAME_TRIGGER) {
rpz_insert_nsdname_trigger(r, policydname, policydnamelen,
a, rr_type, rr_class, rr_ttl, rdatawl, rdatalen, rr,
rr_len);
a, rr_type, rr_class, rr_ttl, rdatawol, rdatalen);
free(policydname);
} else {
free(policydname);

View file

@ -136,15 +136,13 @@ struct rpz {
* @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
* @param rdatawol: rdata of the RR, not prepended with the rdata size
* @param rdatalen: length if the RR, not including the prepended rdata size
* @return: 0 on error
*/
int rpz_insert_rr(struct rpz* r, uint8_t* azname, 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);
uint8_t* rdatawol, size_t rdatalen);
/**
* Delete policy matching RR, used for IXFR.

View file

@ -1265,7 +1265,7 @@ static void localzone_parents_test(void)
nmlabs = dname_count_size_labels(nm, &nmlen);
lock_rw_wrlock(&z2->lock);
local_zones_add_zone(z2, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN,
local_zone_always_nxdomain);
local_zone_always_nxdomain, NULL);
lock_rw_unlock(&z2->lock);
}
/* The trees should be the same, iterate and check the nodes */

View file

@ -100,6 +100,7 @@ int
query_dname_compare(register uint8_t* d1, register uint8_t* d2)
{
register uint8_t lab1, lab2;
register uint8_t ld1, ld2;
log_assert(d1 && d2);
lab1 = *d1++;
lab2 = *d2++;
@ -116,8 +117,8 @@ query_dname_compare(register uint8_t* d1, register uint8_t* d2)
while(lab1--) {
/* compare bytes first for speed */
if(*d1 != *d2 &&
tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
(ld1=tolower((unsigned char)*d1)) != (ld2=tolower((unsigned char)*d2))) {
if(ld1 < ld2)
return -1;
return 1;
}
@ -233,6 +234,7 @@ int
dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
{
uint8_t len1, len2;
register uint8_t ld1, ld2;
int count1 = 0, count2 = 0;
log_assert(pkt && d1 && d2);
len1 = *d1++;
@ -269,8 +271,8 @@ dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
log_assert(len1 == len2 && len1 != 0);
/* compare labels */
while(len1--) {
if(tolower((unsigned char)*d1) != tolower((unsigned char)*d2)) {
if(tolower((unsigned char)*d1) < tolower((unsigned char)*d2))
if((ld1=tolower((unsigned char)*d1)) != (ld2=tolower((unsigned char)*d2))) {
if(ld1 < ld2)
return -1;
return 1;
}
@ -470,9 +472,10 @@ dname_count_size_labels(uint8_t* dname, size_t* size)
static int
memlowercmp(uint8_t* p1, uint8_t* p2, uint8_t len)
{
register uint8_t lp1, lp2;
while(len--) {
if(*p1 != *p2 && tolower((unsigned char)*p1) != tolower((unsigned char)*p2)) {
if(tolower((unsigned char)*p1) < tolower((unsigned char)*p2))
if(*p1 != *p2 && (lp1=tolower((unsigned char)*p1)) != (lp2=tolower((unsigned char)*p2))) {
if(lp1 < lp2)
return -1;
return 1;
}
@ -523,15 +526,15 @@ dname_lab_cmp(uint8_t* d1, int labs1, uint8_t* d2, int labs2, int* mlabs)
d1 += len1;
d2 += len2;
} else {
register uint8_t ld1, ld2;
/* memlowercmp is inlined here; or just like
* if((c=memlowercmp(d1, d2, len1)) != 0) {
* lastdiff = c;
* lastmlabs = atlabel; } apart from d1++,d2++ */
while(len1) {
if(*d1 != *d2 && tolower((unsigned char)*d1)
!= tolower((unsigned char)*d2)) {
if(tolower((unsigned char)*d1) <
tolower((unsigned char)*d2)) {
if(*d1 != *d2 && (ld1=tolower((unsigned char)*d1))
!= (ld2=tolower((unsigned char)*d2))) {
if(ld1 < ld2) {
lastdiff = -1;
lastmlabs = atlabel;
d1 += len1;