]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- rpz-zone-load, rpz load does not pass unwanted string, and rr data.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 23 Jan 2026 15:40:52 +0000 (16:40 +0100)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 23 Jan 2026 15:40:52 +0000 (16:40 +0100)
respip/respip.c
respip/respip.h
services/localzone.c
services/localzone.h
services/rpz.c

index f39ce58055049685927f6b7c42765cda1fcf636e..32cf98a72a63381a17760cc6635c0d2298a9fc26 100644 (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, 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, 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, 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)
index 83b6414737f7a878c2739cf672c035af6bca4a2c..bc5b2e36f9aed5af0732cdc1a9a59af8eb8f276e 100644 (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.
index 9ea98c250907a03f2fc3e025e4febc62b1cfe9ab..867e0c47cc68da160474a37e5e947b7c555e7b9e 100644 (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, 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);
+               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, 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,
index 66102fd98f7e72de4bb7ff3978c6a8f8e51d5a68..6c5db2fb95ffe9f1a72243fb9ee01a651f27be9e 100644 (file)
@@ -526,6 +526,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: 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 +643,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 +704,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 */
index cd160248887331c8b059a8ae5ddbf86856d050de..cc8e663a2929eaef2bcd19bcd5bf39f3939d3928 100644 (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;
@@ -689,16 +702,9 @@ rpz_insert_local_zones_trigger(struct local_zones* lz, uint8_t* dname,
        /* 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);
                free(rrstr);
                free(dname);
                lock_rw_unlock(&lz->lock);
@@ -717,18 +723,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 +746,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 +755,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 +797,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 +812,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 +837,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 +877,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 +934,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 +948,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);
+               free(rrstr);
                return 0;
        }
 
@@ -1000,7 +981,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 +997,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 +1019,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,7 +1051,7 @@ 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
@@ -1110,7 +1091,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 +1106,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);