]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix dname loop maximum, reported by Eric Sesterhenn from X41 D-Sec.
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 22 Nov 2019 13:23:00 +0000 (14:23 +0100)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Fri, 22 Nov 2019 13:23:00 +0000 (14:23 +0100)
doc/Changelog
services/authzone.c
sldns/wire2str.c
sldns/wire2str.h
testcode/testpkts.c

index 08fdd996fe2f7f73d3ae778e29579cc5a796a8c5..39f3a99d5344864a57fadd61646edf4904015c76 100644 (file)
@@ -1,3 +1,6 @@
+22 November 2019: Wouter
+       - Fix dname loop maximum, reported by Eric Sesterhenn from X41 D-Sec.
+
 20 November 2019: Wouter
        - Fix Out of Bounds Read in rrinternal_get_owner(),
          reported by X41 D-Sec.
index 52a19d32c5400e2e82155acaa3b40b9020941356..b59a7334cb876f272ecafe3d495eeae700cb7326 100644 (file)
@@ -1636,7 +1636,7 @@ auth_rr_to_string(uint8_t* nm, size_t nmlen, uint16_t tp, uint16_t cl,
        if(i >= data->count) tp = LDNS_RR_TYPE_RRSIG;
        dat = nm;
        datlen = nmlen;
-       w += sldns_wire2str_dname_scan(&dat, &datlen, &s, &slen, NULL, 0);
+       w += sldns_wire2str_dname_scan(&dat, &datlen, &s, &slen, NULL, 0, NULL);
        w += sldns_str_print(&s, &slen, "\t");
        w += sldns_str_print(&s, &slen, "%lu\t", (unsigned long)data->rr_ttl[i]);
        w += sldns_wire2str_class_print(&s, &slen, cl);
@@ -1645,7 +1645,7 @@ auth_rr_to_string(uint8_t* nm, size_t nmlen, uint16_t tp, uint16_t cl,
        w += sldns_str_print(&s, &slen, "\t");
        datlen = data->rr_len[i]-2;
        dat = data->rr_data[i]+2;
-       w += sldns_wire2str_rdata_scan(&dat, &datlen, &s, &slen, tp, NULL, 0);
+       w += sldns_wire2str_rdata_scan(&dat, &datlen, &s, &slen, tp, NULL, 0, NULL);
 
        if(tp == LDNS_RR_TYPE_DNSKEY) {
                w += sldns_str_print(&s, &slen, " ;{id = %u}",
index f4f52abeb31ff1ad8c586a02569ade7c28b6037a..ddff33a283f84dc11451f202e9ae28661650dbc2 100644 (file)
@@ -252,13 +252,13 @@ int sldns_wire2str_pkt_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
 int sldns_wire2str_rr_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
 {
        /* use arguments as temporary variables */
-       return sldns_wire2str_rr_scan(&d, &dlen, &s, &slen, NULL, 0);
+       return sldns_wire2str_rr_scan(&d, &dlen, &s, &slen, NULL, 0, NULL);
 }
 
 int sldns_wire2str_rrquestion_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
 {
        /* use arguments as temporary variables */
-       return sldns_wire2str_rrquestion_scan(&d, &dlen, &s, &slen, NULL, 0);
+       return sldns_wire2str_rrquestion_scan(&d, &dlen, &s, &slen, NULL, 0, NULL);
 }
 
 int sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str,
@@ -266,13 +266,13 @@ int sldns_wire2str_rdata_buf(uint8_t* rdata, size_t rdata_len, char* str,
 {
        /* use arguments as temporary variables */
        return sldns_wire2str_rdata_scan(&rdata, &rdata_len, &str, &str_len,
-               rrtype, NULL, 0);
+               rrtype, NULL, 0, NULL);
 }
 
 int sldns_wire2str_rr_unknown_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
 {
        /* use arguments as temporary variables */
-       return sldns_wire2str_rr_unknown_scan(&d, &dlen, &s, &slen, NULL, 0);
+       return sldns_wire2str_rr_unknown_scan(&d, &dlen, &s, &slen, NULL, 0, NULL);
 }
 
 int sldns_wire2str_rr_comment_buf(uint8_t* rr, size_t rrlen, size_t dname_len,
@@ -310,7 +310,7 @@ int sldns_wire2str_opcode_buf(int opcode, char* s, size_t slen)
 int sldns_wire2str_dname_buf(uint8_t* d, size_t dlen, char* s, size_t slen)
 {
        /* use arguments as temporary variables */
-       return sldns_wire2str_dname_scan(&d, &dlen, &s, &slen, NULL, 0);
+       return sldns_wire2str_dname_scan(&d, &dlen, &s, &slen, NULL, 0, NULL);
 }
 
 int sldns_str_vprint(char** str, size_t* slen, const char* format, va_list args)
@@ -365,7 +365,7 @@ static int print_remainder_hex(const char* pref, uint8_t** d, size_t* dlen,
 
 int sldns_wire2str_pkt_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
 {
-       int w = 0;
+       int w = 0, comprloop = 0;
        unsigned qdcount, ancount, nscount, arcount, i;
        uint8_t* pkt = *d;
        size_t pktlen = *dlen;
@@ -382,25 +382,25 @@ int sldns_wire2str_pkt_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
        w += sldns_str_print(s, slen, ";; QUESTION SECTION:\n");
        for(i=0; i<qdcount; i++) {
                w += sldns_wire2str_rrquestion_scan(d, dlen, s, slen,
-                       pkt, pktlen);
+                       pkt, pktlen, &comprloop);
                if(!*dlen) break;
        }
        w += sldns_str_print(s, slen, "\n");
        w += sldns_str_print(s, slen, ";; ANSWER SECTION:\n");
        for(i=0; i<ancount; i++) {
-               w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
+               w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen, &comprloop);
                if(!*dlen) break;
        }
        w += sldns_str_print(s, slen, "\n");
        w += sldns_str_print(s, slen, ";; AUTHORITY SECTION:\n");
        for(i=0; i<nscount; i++) {
-               w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
+               w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen, &comprloop);
                if(!*dlen) break;
        }
        w += sldns_str_print(s, slen, "\n");
        w += sldns_str_print(s, slen, ";; ADDITIONAL SECTION:\n");
        for(i=0; i<arcount; i++) {
-               w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen);
+               w += sldns_wire2str_rr_scan(d, dlen, s, slen, pkt, pktlen, &comprloop);
                if(!*dlen) break;
        }
        /* other fields: WHEN(time), SERVER(IP) not available here. */
@@ -449,7 +449,7 @@ static int sldns_rr_tcttl_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
 }
 
 int sldns_wire2str_rr_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
-       uint8_t* pkt, size_t pktlen)
+       uint8_t* pkt, size_t pktlen, int* comprloop)
 {
        int w = 0;
        uint8_t* rr = *d;
@@ -464,7 +464,7 @@ int sldns_wire2str_rr_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
 
        /* try to scan the rdata with pretty-printing, but if that fails, then
         * scan the rdata as an unknown RR type */
-       w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+       w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen, comprloop);
        w += sldns_str_print(s, slen, "\t");
        dname_off = rrlen-(*dlen);
        if(*dlen == 4) {
@@ -508,7 +508,8 @@ int sldns_wire2str_rr_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
                w += print_remainder_hex(";Error partial rdata 0x", d, dlen, s, slen);
                return w + sldns_str_print(s, slen, "\n");
        }
-       w += sldns_wire2str_rdata_scan(d, &rdlen, s, slen, rrtype, pkt, pktlen);
+       w += sldns_wire2str_rdata_scan(d, &rdlen, s, slen, rrtype, pkt, pktlen,
+               comprloop);
        (*dlen) -= (ordlen-rdlen);
 
        /* default comment */
@@ -519,11 +520,11 @@ int sldns_wire2str_rr_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
 }
 
 int sldns_wire2str_rrquestion_scan(uint8_t** d, size_t* dlen, char** s,
-       size_t* slen, uint8_t* pkt, size_t pktlen)
+       size_t* slen, uint8_t* pkt, size_t pktlen, int* comprloop)
 {
        int w = 0;
        uint16_t t, c;
-       w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+       w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen, comprloop);
        w += sldns_str_print(s, slen, "\t");
        if(*dlen < 4) {
                if(*dlen == 0)
@@ -543,11 +544,11 @@ int sldns_wire2str_rrquestion_scan(uint8_t** d, size_t* dlen, char** s,
 }
 
 int sldns_wire2str_rr_unknown_scan(uint8_t** d, size_t* dlen, char** s,
-       size_t* slen, uint8_t* pkt, size_t pktlen)
+       size_t* slen, uint8_t* pkt, size_t pktlen, int* comprloop)
 {
        size_t rdlen, ordlen;
        int w = 0;
-       w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+       w += sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen, comprloop);
        w += sldns_str_print(s, slen, "\t");
        w += sldns_rr_tcttl_scan(d, dlen, s, slen);
        w += sldns_str_print(s, slen, "\t");
@@ -699,7 +700,8 @@ int sldns_wire2str_header_scan(uint8_t** d, size_t* dlen, char** s,
 }
 
 int sldns_wire2str_rdata_scan(uint8_t** d, size_t* dlen, char** s,
-       size_t* slen, uint16_t rrtype, uint8_t* pkt, size_t pktlen)
+       size_t* slen, uint16_t rrtype, uint8_t* pkt, size_t pktlen,
+       int* comprloop)
 {
        /* try to prettyprint, but if that fails, use unknown format */
        uint8_t* origd = *d;
@@ -725,7 +727,7 @@ int sldns_wire2str_rdata_scan(uint8_t** d, size_t* dlen, char** s,
                if(r_cnt != 0)
                        w += sldns_str_print(s, slen, " ");
                n = sldns_wire2str_rdf_scan(d, dlen, s, slen, rdftype,
-                       pkt, pktlen);
+                       pkt, pktlen, comprloop);
                if(n == -1) {
                failed:
                        /* failed, use unknown format */
@@ -776,14 +778,20 @@ static int dname_char_print(char** s, size_t* slen, uint8_t c)
 }
 
 int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
-       uint8_t* pkt, size_t pktlen)
+       uint8_t* pkt, size_t pktlen, int* comprloop)
 {
        int w = 0;
        /* spool labels onto the string, use compression if its there */
        uint8_t* pos = *d;
        unsigned i, counter=0;
-       const unsigned maxcompr = 1000; /* loop detection, max compr ptrs */
+       unsigned maxcompr = 1000; /* loop detection, max compr ptrs */
        int in_buf = 1;
+       if(comprloop) {
+               if(*comprloop != 0)
+                       maxcompr = 30; /* for like ipv6 reverse name, per label */
+               if(*comprloop > 4)
+                       maxcompr = 4; /* just don't want to spend time, any more */
+       }
        if(*dlen == 0) return sldns_str_print(s, slen, "ErrorMissingDname");
        if(*pos == 0) {
                (*d)++;
@@ -811,9 +819,12 @@ int sldns_wire2str_dname_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
                        if(!pkt || target >= pktlen)
                                return w + sldns_str_print(s, slen,
                                        "ErrorComprPtrOutOfBounds");
-                       if(counter++ > maxcompr)
+                       if(counter++ > maxcompr) {
+                               if(comprloop && *comprloop < 10)
+                                       (*comprloop)++;
                                return w + sldns_str_print(s, slen,
                                        "ErrorComprPtrLooped");
+                       }
                        in_buf = 0;
                        pos = pkt+target;
                        continue;
@@ -929,14 +940,14 @@ int sldns_wire2str_ttl_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen)
 }
 
 int sldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
-       int rdftype, uint8_t* pkt, size_t pktlen)
+       int rdftype, uint8_t* pkt, size_t pktlen, int* comprloop)
 {
        if(*dlen == 0) return 0;
        switch(rdftype) {
        case LDNS_RDF_TYPE_NONE:
                return 0;
        case LDNS_RDF_TYPE_DNAME:
-               return sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen);
+               return sldns_wire2str_dname_scan(d, dlen, s, slen, pkt, pktlen, comprloop);
        case LDNS_RDF_TYPE_INT8:
                return sldns_wire2str_int8_scan(d, dlen, s, slen);
        case LDNS_RDF_TYPE_INT16:
@@ -988,7 +999,7 @@ int sldns_wire2str_rdf_scan(uint8_t** d, size_t* dlen, char** s, size_t* slen,
                return sldns_wire2str_atma_scan(d, dlen, s, slen);
        case LDNS_RDF_TYPE_IPSECKEY:
                return sldns_wire2str_ipseckey_scan(d, dlen, s, slen, pkt,
-                       pktlen);
+                       pktlen, comprloop);
        case LDNS_RDF_TYPE_HIP:
                return sldns_wire2str_hip_scan(d, dlen, s, slen);
        case LDNS_RDF_TYPE_INT16_DATA:
@@ -1530,7 +1541,7 @@ int sldns_wire2str_atma_scan(uint8_t** d, size_t* dl, char** s, size_t* sl)
 
 /* internal scan routine that can modify arguments on failure */
 static int sldns_wire2str_ipseckey_scan_internal(uint8_t** d, size_t* dl,
-       char** s, size_t* sl, uint8_t* pkt, size_t pktlen)
+       char** s, size_t* sl, uint8_t* pkt, size_t pktlen, int* comprloop)
 {
        /* http://www.ietf.org/internet-drafts/draft-ietf-ipseckey-rr-12.txt*/
        uint8_t precedence, gateway_type, algorithm;
@@ -1558,7 +1569,7 @@ static int sldns_wire2str_ipseckey_scan_internal(uint8_t** d, size_t* dl,
                w += sldns_wire2str_aaaa_scan(d, dl, s, sl);
                break;
        case 3: /* dname */
-               w += sldns_wire2str_dname_scan(d, dl, s, sl, pkt, pktlen);
+               w += sldns_wire2str_dname_scan(d, dl, s, sl, pkt, pktlen, comprloop);
                break;
        default: /* unknown */
                return -1;
@@ -1572,12 +1583,12 @@ static int sldns_wire2str_ipseckey_scan_internal(uint8_t** d, size_t* dl,
 }
 
 int sldns_wire2str_ipseckey_scan(uint8_t** d, size_t* dl, char** s, size_t* sl,
-       uint8_t* pkt, size_t pktlen)
+       uint8_t* pkt, size_t pktlen, int* comprloop)
 {
        uint8_t* od = *d;
        char* os = *s;
        size_t odl = *dl, osl = *sl;
-       int w=sldns_wire2str_ipseckey_scan_internal(d, dl, s, sl, pkt, pktlen);
+       int w=sldns_wire2str_ipseckey_scan_internal(d, dl, s, sl, pkt, pktlen, comprloop);
        if(w == -1) {
                *d = od;
                *s = os;
index a64f5807269ce65010197c3e1680cb444dcd4235..0167fe7c1e2d2fdc23b67a38fe54c29e2183a638 100644 (file)
@@ -156,10 +156,11 @@ int sldns_wire2str_pkt_scan(uint8_t** data, size_t* data_len, char** str,
  * @param str_len: length of string buffer.
  * @param pkt: packet for decompression, if NULL no decompression.
  * @param pktlen: length of packet buffer.
+ * @param comprloop: if pkt, bool detects compression loops.
  * @return number of characters (except null) needed to print.
  */
 int sldns_wire2str_rr_scan(uint8_t** data, size_t* data_len, char** str,
-       size_t* str_len, uint8_t* pkt, size_t pktlen);
+       size_t* str_len, uint8_t* pkt, size_t pktlen, int* comprloop);
 
 /**
  * Scan wireformat question rr to string, with user buffers.
@@ -170,10 +171,11 @@ int sldns_wire2str_rr_scan(uint8_t** data, size_t* data_len, char** str,
  * @param str_len: length of string buffer.
  * @param pkt: packet for decompression, if NULL no decompression.
  * @param pktlen: length of packet buffer.
+ * @param comprloop: if pkt, bool detects compression loops.
  * @return number of characters (except null) needed to print.
  */
 int sldns_wire2str_rrquestion_scan(uint8_t** data, size_t* data_len, char** str,
-       size_t* str_len, uint8_t* pkt, size_t pktlen);
+       size_t* str_len, uint8_t* pkt, size_t pktlen, int* comprloop);
 
 /**
  * Scan wireformat RR to string in unknown RR format, with user buffers.
@@ -184,10 +186,11 @@ int sldns_wire2str_rrquestion_scan(uint8_t** data, size_t* data_len, char** str,
  * @param str_len: length of string buffer.
  * @param pkt: packet for decompression, if NULL no decompression.
  * @param pktlen: length of packet buffer.
+ * @param comprloop: if pkt, bool detects compression loops.
  * @return number of characters (except null) needed to print.
  */
 int sldns_wire2str_rr_unknown_scan(uint8_t** data, size_t* data_len, char** str,
-       size_t* str_len, uint8_t* pkt, size_t pktlen);
+       size_t* str_len, uint8_t* pkt, size_t pktlen, int* comprloop);
 
 /**
  * Print to string the RR-information comment in default format,
@@ -228,10 +231,12 @@ int sldns_wire2str_header_scan(uint8_t** data, size_t* data_len, char** str,
  * @param rrtype: RR type of Rdata, host format.
  * @param pkt: packet for decompression, if NULL no decompression.
  * @param pktlen: length of packet buffer.
+ * @param comprloop: if pkt, bool detects compression loops.
  * @return number of characters (except null) needed to print.
  */
 int sldns_wire2str_rdata_scan(uint8_t** data, size_t* data_len, char** str,
-       size_t* str_len, uint16_t rrtype, uint8_t* pkt, size_t pktlen);
+       size_t* str_len, uint16_t rrtype, uint8_t* pkt, size_t pktlen,
+       int* comprloop);
 
 /**
  * Scan wireformat rdata to string in unknown format, with user buffers.
@@ -254,10 +259,17 @@ int sldns_wire2str_rdata_unknown_scan(uint8_t** data, size_t* data_len,
  * @param str_len: length of string buffer.
  * @param pkt: packet for decompression, if NULL no decompression.
  * @param pktlen: length of packet buffer.
+ * @param comprloop: inout bool, that is set true if compression loop failure
+ *     happens.  Pass in 0, if passsed in as true, a lower bound is set
+ *     on compression loops to stop arbitrary long packet parse times.
+ *     This is meant so you can set it to 0 at the start of a list of dnames,
+ *     and then scan all of them in sequence, if a loop happens, it becomes
+ *     true and then it becomes more strict for the next dnames in the list.
+ *     You can leave it at NULL if there is no pkt (pkt is NULL too).
  * @return number of characters (except null) needed to print.
  */
 int sldns_wire2str_dname_scan(uint8_t** data, size_t* data_len, char** str,
-       size_t* str_len, uint8_t* pkt, size_t pktlen);
+       size_t* str_len, uint8_t* pkt, size_t pktlen, int* comprloop);
 
 /**
  * Scan wireformat rr type to string, with user buffers.
@@ -492,11 +504,13 @@ int sldns_wire2str_dname_buf(uint8_t* dname, size_t dname_len, char* str,
  * @param rdftype: the type of the rdata field, enum sldns_rdf_type.
  * @param pkt: packet for decompression, if NULL no decompression.
  * @param pktlen: length of packet buffer.
+ * @param comprloop: if pkt, bool detects compression loops.
  * @return number of characters (except null) needed to print.
  *     Can return -1 on failure.
  */
 int sldns_wire2str_rdf_scan(uint8_t** data, size_t* data_len, char** str,
-       size_t* str_len, int rdftype, uint8_t* pkt, size_t pktlen);
+       size_t* str_len, int rdftype, uint8_t* pkt, size_t pktlen,
+       int* comprloop);
 
 /**
  * Scan wireformat int8 field to string, with user buffers.
@@ -793,11 +807,12 @@ int sldns_wire2str_atma_scan(uint8_t** data, size_t* data_len, char** str,
  * @param str_len: length of string buffer.
  * @param pkt: packet for decompression, if NULL no decompression.
  * @param pktlen: length of packet buffer.
+ * @param comprloop: if pkt, bool detects compression loops.
  * @return number of characters (except null) needed to print.
  *     Can return -1 on failure.
  */
 int sldns_wire2str_ipseckey_scan(uint8_t** data, size_t* data_len, char** str,
-       size_t* str_len, uint8_t* pkt, size_t pktlen);
+       size_t* str_len, uint8_t* pkt, size_t pktlen, int* comprloop);
 
 /**
  * Scan wireformat HIP (algo, HIT, pubkey) field to string, with user buffers.
index 6c90567aa321a772410f139ca4657edcd6f387e6..82c1439677c01295511334ce3b46ff982bcf9f68 100644 (file)
@@ -704,6 +704,7 @@ static sldns_rr_type get_qtype(uint8_t* pkt, size_t pktlen)
        uint8_t* d;
        size_t dl, sl=0;
        char* snull = NULL;
+       int comprloop = 0;
        if(pktlen < LDNS_HEADER_SIZE)
                return 0;
        if(LDNS_QDCOUNT(pkt) == 0)
@@ -711,7 +712,7 @@ static sldns_rr_type get_qtype(uint8_t* pkt, size_t pktlen)
        /* skip over dname with dname-scan routine */
        d = pkt+LDNS_HEADER_SIZE;
        dl = pktlen-LDNS_HEADER_SIZE;
-       (void)sldns_wire2str_dname_scan(&d, &dl, &snull, &sl, pkt, pktlen);
+       (void)sldns_wire2str_dname_scan(&d, &dl, &snull, &sl, pkt, pktlen, &comprloop);
        if(dl < 2)
                return 0;
        return sldns_read_uint16(d);
@@ -723,6 +724,7 @@ static size_t get_qname_len(uint8_t* pkt, size_t pktlen)
        uint8_t* d;
        size_t dl, sl=0;
        char* snull = NULL;
+       int comprloop = 0;
        if(pktlen < LDNS_HEADER_SIZE)
                return 0;
        if(LDNS_QDCOUNT(pkt) == 0)
@@ -730,7 +732,7 @@ static size_t get_qname_len(uint8_t* pkt, size_t pktlen)
        /* skip over dname with dname-scan routine */
        d = pkt+LDNS_HEADER_SIZE;
        dl = pktlen-LDNS_HEADER_SIZE;
-       (void)sldns_wire2str_dname_scan(&d, &dl, &snull, &sl, pkt, pktlen);
+       (void)sldns_wire2str_dname_scan(&d, &dl, &snull, &sl, pkt, pktlen, &comprloop);
        return pktlen-dl-LDNS_HEADER_SIZE;
 }
 
@@ -767,6 +769,7 @@ static uint32_t get_serial(uint8_t* p, size_t plen)
        size_t walk_len = plen, sl=0;
        char* snull = NULL;
        uint16_t i;
+       int comprloop = 0;
 
        if(walk_len < LDNS_HEADER_SIZE)
                return 0;
@@ -776,10 +779,10 @@ static uint32_t get_serial(uint8_t* p, size_t plen)
        /* skip other records with wire2str_scan */
        for(i=0; i < LDNS_QDCOUNT(p); i++)
                (void)sldns_wire2str_rrquestion_scan(&walk, &walk_len,
-                       &snull, &sl, p, plen);
+                       &snull, &sl, p, plen, &comprloop);
        for(i=0; i < LDNS_ANCOUNT(p); i++)
                (void)sldns_wire2str_rr_scan(&walk, &walk_len, &snull, &sl,
-                       p, plen);
+                       p, plen, &comprloop);
 
        /* walk through authority section */
        for(i=0; i < LDNS_NSCOUNT(p); i++) {
@@ -787,7 +790,7 @@ static uint32_t get_serial(uint8_t* p, size_t plen)
                uint8_t* dstart = walk;
                size_t dlen = walk_len;
                (void)sldns_wire2str_dname_scan(&dstart, &dlen, &snull, &sl,
-                       p, plen);
+                       p, plen, &comprloop);
                if(dlen >= 2 && sldns_read_uint16(dstart) == LDNS_RR_TYPE_SOA) {
                        /* skip type, class, TTL, rdatalen */
                        if(dlen < 10)
@@ -798,9 +801,9 @@ static uint32_t get_serial(uint8_t* p, size_t plen)
                        dlen -= 10;
                        /* check third rdf */
                        (void)sldns_wire2str_dname_scan(&dstart, &dlen, &snull,
-                               &sl, p, plen);
+                               &sl, p, plen, &comprloop);
                        (void)sldns_wire2str_dname_scan(&dstart, &dlen, &snull,
-                               &sl, p, plen);
+                               &sl, p, plen, &comprloop);
                        if(dlen < 4)
                                return 0;
                        verbose(3, "found serial %u in msg. ",
@@ -809,7 +812,7 @@ static uint32_t get_serial(uint8_t* p, size_t plen)
                }
                /* move to next RR */
                (void)sldns_wire2str_rr_scan(&walk, &walk_len, &snull, &sl,
-                       p, plen);
+                       p, plen, &comprloop);
        }
        return 0;
 }
@@ -823,6 +826,7 @@ pkt_find_edns_opt(uint8_t** p, size_t* plen)
        size_t wlen = *plen, sl=0;
        char* snull = NULL;
        uint16_t i;
+       int comprloop = 0;
 
        if(wlen < LDNS_HEADER_SIZE)
                return 0;
@@ -832,11 +836,11 @@ pkt_find_edns_opt(uint8_t** p, size_t* plen)
        /* skip other records with wire2str_scan */
        for(i=0; i < LDNS_QDCOUNT(*p); i++)
                (void)sldns_wire2str_rrquestion_scan(&w, &wlen, &snull, &sl,
-                       *p, *plen);
+                       *p, *plen, &comprloop);
        for(i=0; i < LDNS_ANCOUNT(*p); i++)
-               (void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen);
+               (void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen, &comprloop);
        for(i=0; i < LDNS_NSCOUNT(*p); i++)
-               (void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen);
+               (void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen, &comprloop);
 
        /* walk through additional section */
        for(i=0; i < LDNS_ARCOUNT(*p); i++) {
@@ -844,14 +848,14 @@ pkt_find_edns_opt(uint8_t** p, size_t* plen)
                uint8_t* dstart = w;
                size_t dlen = wlen;
                (void)sldns_wire2str_dname_scan(&dstart, &dlen, &snull, &sl,
-                       *p, *plen);
+                       *p, *plen, &comprloop);
                if(dlen >= 2 && sldns_read_uint16(dstart) == LDNS_RR_TYPE_OPT) {
                        *p = dstart+2;
                        *plen = dlen-2;
                        return 1;
                }
                /* move to next RR */
-               (void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen);
+               (void)sldns_wire2str_rr_scan(&w, &wlen, &snull, &sl, *p, *plen, &comprloop);
        }
        return 0;
 }
@@ -889,25 +893,26 @@ zerottls(uint8_t* pkt, size_t pktlen)
        char* snull = NULL;
        uint16_t i;
        uint16_t num = LDNS_ANCOUNT(pkt)+LDNS_NSCOUNT(pkt)+LDNS_ARCOUNT(pkt);
+       int comprloop = 0;
        if(walk_len < LDNS_HEADER_SIZE)
                return;
        walk += LDNS_HEADER_SIZE;
        walk_len -= LDNS_HEADER_SIZE;
        for(i=0; i < LDNS_QDCOUNT(pkt); i++)
                (void)sldns_wire2str_rrquestion_scan(&walk, &walk_len,
-                       &snull, &sl, pkt, pktlen);
+                       &snull, &sl, pkt, pktlen, &comprloop);
        for(i=0; i < num; i++) {
                /* wipe TTL */
                uint8_t* dstart = walk;
                size_t dlen = walk_len;
                (void)sldns_wire2str_dname_scan(&dstart, &dlen, &snull, &sl,
-                       pkt, pktlen);
+                       pkt, pktlen, &comprloop);
                if(dlen < 8)
                        return;
                sldns_write_uint32(dstart+4, 0);
                /* go to next RR */
                (void)sldns_wire2str_rr_scan(&walk, &walk_len, &snull, &sl,
-                       pkt, pktlen);
+                       pkt, pktlen, &comprloop);
        }
 }
 
@@ -1347,10 +1352,11 @@ static int equal_dname(uint8_t* q, size_t qlen, uint8_t* p, size_t plen)
        char qs[512], ps[512];
        size_t qslen = sizeof(qs), pslen = sizeof(ps);
        char* qss = qs, *pss = ps;
+       int comprloop = 0;
        if(!qn || !pn)
                return 0;
-       (void)sldns_wire2str_dname_scan(&qn, &qlen, &qss, &qslen, q, qlen);
-       (void)sldns_wire2str_dname_scan(&pn, &plen, &pss, &pslen, p, plen);
+       (void)sldns_wire2str_dname_scan(&qn, &qlen, &qss, &qslen, q, qlen, &comprloop);
+       (void)sldns_wire2str_dname_scan(&pn, &plen, &pss, &pslen, p, plen, &comprloop);
        return (strcmp(qs, ps) == 0);
 }
 
@@ -1364,11 +1370,12 @@ static int subdomain_dname(uint8_t* q, size_t qlen, uint8_t* p, size_t plen)
        char qs[5120], ps[5120];
        size_t qslen = sizeof(qs), pslen = sizeof(ps);
        char* qss = qs, *pss = ps;
+       int comprloop = 0;
        if(!qn || !pn)
                return 0;
        /* decompresses domain names */
-       (void)sldns_wire2str_dname_scan(&qn, &qlen, &qss, &qslen, q, qlen);
-       (void)sldns_wire2str_dname_scan(&pn, &plen, &pss, &pslen, p, plen);
+       (void)sldns_wire2str_dname_scan(&qn, &qlen, &qss, &qslen, q, qlen, &comprloop);
+       (void)sldns_wire2str_dname_scan(&pn, &plen, &pss, &pslen, p, plen, &comprloop);
        /* same: false, (strict subdomain check)??? */
        if(strcmp(qs, ps) == 0)
                return 1;