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; }
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++; } }
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++; } }
/** 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); }
int dname_is_root(uint8_t* dname) { uint8_t len; log_assert(dname); len = dname[0]; log_assert(!LABEL_IS_PTR(len)); return (len == 0); }
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; }
void dname_remove_label(uint8_t** dname, size_t* len) { size_t lablen; log_assert(dname && *dname && len); lablen = (*dname)[0]; log_assert(!LABEL_IS_PTR(lablen)); log_assert(*len > lablen); if(lablen == 0) return; /* do not modify root label */ *len -= lablen+1; *dname += lablen+1; }
size_t pkt_dname_len(sldns_buffer* pkt) { size_t len = 0; int ptrcount = 0; uint8_t labellen; size_t endpos = 0; /* read dname and determine length */ /* check compression pointers, loops, out of bounds */ while(1) { /* read next label */ if(sldns_buffer_remaining(pkt) < 1) return 0; labellen = sldns_buffer_read_u8(pkt); if(LABEL_IS_PTR(labellen)) { /* compression ptr */ uint16_t ptr; if(sldns_buffer_remaining(pkt) < 1) return 0; ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt)); if(ptrcount++ > MAX_COMPRESS_PTRS) return 0; /* loop! */ if(sldns_buffer_limit(pkt) <= ptr) return 0; /* out of bounds! */ if(!endpos) endpos = sldns_buffer_position(pkt); sldns_buffer_set_position(pkt, ptr); } else { /* label contents */ if(labellen > 0x3f) return 0; /* label too long */ len += 1 + labellen; if(len > LDNS_MAX_DOMAINLEN) return 0; if(labellen == 0) { /* end of dname */ break; } if(sldns_buffer_remaining(pkt) < labellen) return 0; sldns_buffer_skip(pkt, (ssize_t)labellen); } } if(endpos) sldns_buffer_set_position(pkt, endpos); return len; }