/** test pkt_dname_tolower */ static void dname_test_pdtl(sldns_buffer* loopbuf, sldns_buffer* boundbuf) { unit_show_func("util/data/dname.c", "pkt_dname_tolower"); pkt_dname_tolower(loopbuf, sldns_buffer_at(loopbuf, 12)); pkt_dname_tolower(boundbuf, sldns_buffer_at(boundbuf, 12)); }
/** perf test a packet */ static void perftestpkt(sldns_buffer* pkt, struct alloc_cache* alloc, sldns_buffer* out, const char* hex) { struct query_info qi; struct reply_info* rep = 0; int ret; uint16_t id; uint16_t flags; time_t timenow = 0; struct regional* region = regional_create(); struct edns_data edns; hex_to_buf(pkt, hex); memmove(&id, sldns_buffer_begin(pkt), sizeof(id)); if(sldns_buffer_limit(pkt) < 2) flags = 0; else memmove(&flags, sldns_buffer_at(pkt, 2), sizeof(flags)); flags = ntohs(flags); ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns); if(ret != 0) { char rbuf[16]; sldns_wire2str_rcode_buf(ret, rbuf, sizeof(rbuf)); if(vbmp) printf("parse code %d: %s\n", ret, rbuf); if(ret == LDNS_RCODE_FORMERR) checkformerr(pkt); unit_assert(ret != LDNS_RCODE_SERVFAIL); } else { perf_encode(&qi, rep, id, flags, out, timenow, &edns); } query_info_clear(&qi); reply_info_parsedelete(rep, alloc); regional_destroy(region); }
void dname_print(FILE* out, struct sldns_buffer* pkt, uint8_t* dname) { uint8_t lablen; if(!out) out = stdout; if(!dname) return; lablen = *dname++; if(!lablen) fputc('.', out); while(lablen) { if(LABEL_IS_PTR(lablen)) { /* follow pointer */ if(!pkt) { fputs("??compressionptr??", out); return; } dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); lablen = *dname++; continue; } if(lablen > LDNS_MAX_LABELLEN) { fputs("??extendedlabel??", out); return; } while(lablen--) fputc((int)*dname++, out); fputc('.', out); lablen = *dname++; } }
void dname_pkt_copy(sldns_buffer* pkt, uint8_t* to, uint8_t* dname) { /* copy over the dname and decompress it at the same time */ size_t len = 0; uint8_t lablen; lablen = *dname++; while(lablen) { if(LABEL_IS_PTR(lablen)) { /* follow pointer */ dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); lablen = *dname++; continue; } log_assert(lablen <= LDNS_MAX_LABELLEN); len += (size_t)lablen+1; if(len >= LDNS_MAX_DOMAINLEN) { *to = 0; /* end the result prematurely */ log_err("bad dname in dname_pkt_copy"); return; } *to++ = lablen; memmove(to, dname, lablen); dname += lablen; to += lablen; lablen = *dname++; } /* copy last \0 */ *to = 0; }
hashvalue_t dname_pkt_hash(sldns_buffer* pkt, uint8_t* dname, hashvalue_t h) { uint8_t labuf[LDNS_MAX_LABELLEN+1]; uint8_t lablen; int i; /* preserve case of query, make hash label by label */ lablen = *dname++; while(lablen) { if(LABEL_IS_PTR(lablen)) { /* follow pointer */ dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); lablen = *dname++; continue; } log_assert(lablen <= LDNS_MAX_LABELLEN); labuf[0] = lablen; i=0; while(lablen--) labuf[++i] = (uint8_t)tolower((int)*dname++); h = hashlittle(labuf, labuf[0] + 1, h); lablen = *dname++; } return h; }
void pkt_dname_tolower(sldns_buffer* pkt, uint8_t* dname) { uint8_t lablen; int count = 0; if(dname >= sldns_buffer_end(pkt)) return; lablen = *dname++; while(lablen) { if(LABEL_IS_PTR(lablen)) { if((size_t)PTR_OFFSET(lablen, *dname) >= sldns_buffer_limit(pkt)) return; dname = sldns_buffer_at(pkt, PTR_OFFSET(lablen, *dname)); lablen = *dname++; if(count++ > MAX_COMPRESS_PTRS) return; continue; } if(dname+lablen >= sldns_buffer_end(pkt)) return; while(lablen--) { *dname = (uint8_t)tolower((int)*dname); dname++; } if(dname >= sldns_buffer_end(pkt)) return; lablen = *dname++; } }
int dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2) { uint8_t len1, len2; log_assert(pkt && d1 && d2); len1 = *d1++; len2 = *d2++; while( len1 != 0 || len2 != 0 ) { /* resolve ptrs */ if(LABEL_IS_PTR(len1)) { d1 = sldns_buffer_at(pkt, PTR_OFFSET(len1, *d1)); len1 = *d1++; continue; } if(LABEL_IS_PTR(len2)) { d2 = sldns_buffer_at(pkt, PTR_OFFSET(len2, *d2)); len2 = *d2++; continue; } /* check label length */ log_assert(len1 <= LDNS_MAX_LABELLEN); log_assert(len2 <= LDNS_MAX_LABELLEN); if(len1 != len2) { if(len1 < len2) return -1; return 1; } log_assert(len1 == len2 && len1 != 0); /* compare labels */ while(len1--) { if(tolower((int)*d1++) != tolower((int)*d2++)) { if(tolower((int)d1[-1]) < tolower((int)d2[-1])) return -1; return 1; } } len1 = *d1++; len2 = *d2++; } return 0; }
/** smart comparison of (compressed, valid) dnames from packet */ static int smart_compare(sldns_buffer* pkt, uint8_t* dnow, uint8_t* dprfirst, uint8_t* dprlast) { if(LABEL_IS_PTR(*dnow)) { /* ptr points to a previous dname */ uint8_t* p = sldns_buffer_at(pkt, PTR_OFFSET(dnow[0], dnow[1])); if( p == dprfirst || p == dprlast ) return 0; /* prev dname is also a ptr, both ptrs are the same. */ if(LABEL_IS_PTR(*dprlast) && dprlast[0] == dnow[0] && dprlast[1] == dnow[1]) return 0; } return dname_pkt_compare(pkt, dnow, dprlast); }
/** see if buffers contain the same packet */ static int test_buffers(sldns_buffer* pkt, sldns_buffer* out) { /* check binary same */ if(sldns_buffer_limit(pkt) == sldns_buffer_limit(out) && memcmp(sldns_buffer_begin(pkt), sldns_buffer_begin(out), sldns_buffer_limit(pkt)) == 0) { if(vbmp) printf("binary the same (length=%u)\n", (unsigned)sldns_buffer_limit(pkt)); return 1; } if(vbmp) { size_t sz = 16; size_t count; size_t lim = sldns_buffer_limit(out); if(sldns_buffer_limit(pkt) < lim) lim = sldns_buffer_limit(pkt); for(count=0; count<lim; count+=sz) { size_t rem = sz; if(lim-count < sz) rem = lim-count; if(memcmp(sldns_buffer_at(pkt, count), sldns_buffer_at(out, count), rem) == 0) { log_info("same %d %d", (int)count, (int)rem); log_hex("same: ", sldns_buffer_at(pkt, count), rem); } else { log_info("diff %d %d", (int)count, (int)rem); log_hex("difp: ", sldns_buffer_at(pkt, count), rem); log_hex("difo: ", sldns_buffer_at(out, count), rem); } } } /* check if it 'means the same' */ if(vbmp) { char* s1, *s2; log_buf(0, "orig in hex", pkt); log_buf(0, "unbound out in hex", out); printf("\npacket from unbound (%d):\n", (int)sldns_buffer_limit(out)); s1 = sldns_wire2str_pkt(sldns_buffer_begin(out), sldns_buffer_limit(out)); printf("%s\n", s1?s1:"null"); free(s1); printf("\npacket original (%d):\n", (int)sldns_buffer_limit(pkt)); s2 = sldns_wire2str_pkt(sldns_buffer_begin(pkt), sldns_buffer_limit(pkt)); printf("%s\n", s2?s2:"null"); free(s2); printf("\n"); } /* if it had two EDNS sections, skip comparison */ if(1) { char* s = sldns_wire2str_pkt(sldns_buffer_begin(pkt), sldns_buffer_limit(pkt)); char* e1 = strstr(s, "; EDNS:"); if(e1 && strstr(e1+4, "; EDNS:")) { free(s); return 0; } free(s); } /* compare packets */ unit_assert(match_all(sldns_buffer_begin(pkt), sldns_buffer_limit(pkt), sldns_buffer_begin(out), sldns_buffer_limit(out), 1, matches_nolocation)); return 0; }
/** test a packet */ static void testpkt(sldns_buffer* pkt, struct alloc_cache* alloc, sldns_buffer* out, const char* hex) { struct query_info qi; struct reply_info* rep = 0; int ret; uint16_t id; uint16_t flags; uint32_t timenow = 0; struct regional* region = regional_create(); struct edns_data edns; hex_to_buf(pkt, hex); memmove(&id, sldns_buffer_begin(pkt), sizeof(id)); if(sldns_buffer_limit(pkt) < 2) flags = 0; else memmove(&flags, sldns_buffer_at(pkt, 2), sizeof(flags)); flags = ntohs(flags); ret = reply_info_parse(pkt, alloc, &qi, &rep, region, &edns); if(ret != 0) { char rbuf[16]; sldns_wire2str_rcode_buf(ret, rbuf, sizeof(rbuf)); if(vbmp) printf("parse code %d: %s\n", ret, rbuf); if(ret == LDNS_RCODE_FORMERR) { unit_assert(!check_formerr_gone); checkformerr(pkt); } unit_assert(ret != LDNS_RCODE_SERVFAIL); } else if(!check_formerr_gone) { const size_t lim = 512; ret = reply_info_encode(&qi, rep, id, flags, out, timenow, region, 65535, (int)(edns.bits & EDNS_DO) ); unit_assert(ret != 0); /* udp packets should fit */ attach_edns_record(out, &edns); if(vbmp) printf("inlen %u outlen %u\n", (unsigned)sldns_buffer_limit(pkt), (unsigned)sldns_buffer_limit(out)); if(!check_nosameness) test_buffers(pkt, out); if(check_rrsigs) check_the_rrsigs(&qi, rep); if(sldns_buffer_limit(out) > lim) { ret = reply_info_encode(&qi, rep, id, flags, out, timenow, region, lim - calc_edns_field_size(&edns), (int)(edns.bits & EDNS_DO)); unit_assert(ret != 0); /* should fit, but with TC */ attach_edns_record(out, &edns); if( LDNS_QDCOUNT(sldns_buffer_begin(out)) != LDNS_QDCOUNT(sldns_buffer_begin(pkt)) || LDNS_ANCOUNT(sldns_buffer_begin(out)) != LDNS_ANCOUNT(sldns_buffer_begin(pkt)) || LDNS_NSCOUNT(sldns_buffer_begin(out)) != LDNS_NSCOUNT(sldns_buffer_begin(pkt))) unit_assert( LDNS_TC_WIRE(sldns_buffer_begin(out))); /* must set TC bit if shortened */ unit_assert(sldns_buffer_limit(out) <= lim); } } query_info_clear(&qi); reply_info_parsedelete(rep, alloc); regional_destroy(region); }