/** * Fill CH class answer into buffer. Keeps query. * @param pkt: buffer * @param str: string to put into text record (<255). * @param edns: edns reply information. * @param worker: worker with scratch region. */ static void chaos_replystr(sldns_buffer* pkt, const char* str, struct edns_data* edns, struct worker* worker) { size_t len = strlen(str); unsigned int rd = LDNS_RD_WIRE(sldns_buffer_begin(pkt)); unsigned int cd = LDNS_CD_WIRE(sldns_buffer_begin(pkt)); if(len>255) len=255; /* cap size of TXT record */ sldns_buffer_clear(pkt); sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip id */ sldns_buffer_write_u16(pkt, (uint16_t)(BIT_QR|BIT_RA)); if(rd) LDNS_RD_SET(sldns_buffer_begin(pkt)); if(cd) LDNS_CD_SET(sldns_buffer_begin(pkt)); sldns_buffer_write_u16(pkt, 1); /* qdcount */ sldns_buffer_write_u16(pkt, 1); /* ancount */ sldns_buffer_write_u16(pkt, 0); /* nscount */ sldns_buffer_write_u16(pkt, 0); /* arcount */ (void)query_dname_len(pkt); /* skip qname */ sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qtype */ sldns_buffer_skip(pkt, (ssize_t)sizeof(uint16_t)); /* skip qclass */ sldns_buffer_write_u16(pkt, 0xc00c); /* compr ptr to query */ sldns_buffer_write_u16(pkt, LDNS_RR_TYPE_TXT); sldns_buffer_write_u16(pkt, LDNS_RR_CLASS_CH); sldns_buffer_write_u32(pkt, 0); /* TTL */ sldns_buffer_write_u16(pkt, sizeof(uint8_t) + len); sldns_buffer_write_u8(pkt, len); sldns_buffer_write(pkt, str, len); sldns_buffer_flip(pkt); edns->edns_version = EDNS_ADVERTISED_VERSION; edns->udp_size = EDNS_ADVERTISED_SIZE; edns->bits &= EDNS_DO; if(!edns_opt_inplace_reply(edns, worker->scratchpad)) edns->opt_list = NULL; attach_edns_record(pkt, edns); }
/** calculate the size of one rr */ static int calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr) { const sldns_rr_descriptor* desc; uint16_t pkt_len; /* length of rr inside the packet */ rr->size = sizeof(uint16_t); /* the rdatalen */ sldns_buffer_skip(pkt, 4); /* skip ttl */ pkt_len = sldns_buffer_read_u16(pkt); if(sldns_buffer_remaining(pkt) < pkt_len) return 0; desc = sldns_rr_descript(type); if(pkt_len > 0 && desc && desc->_dname_count > 0) { int count = (int)desc->_dname_count; int rdf = 0; size_t len; size_t oldpos; /* skip first part. */ while(pkt_len > 0 && count) { switch(desc->_wireformat[rdf]) { case LDNS_RDF_TYPE_DNAME: /* decompress every domain name */ oldpos = sldns_buffer_position(pkt); if((len = pkt_dname_len(pkt)) == 0) return 0; /* malformed dname */ if(sldns_buffer_position(pkt)-oldpos > pkt_len) return 0; /* dname exceeds rdata */ pkt_len -= sldns_buffer_position(pkt)-oldpos; rr->size += len; count--; len = 0; break; case LDNS_RDF_TYPE_STR: if(pkt_len < 1) { /* NOTREACHED, due to 'while(>0)' */ return 0; /* len byte exceeds rdata */ } len = sldns_buffer_current(pkt)[0] + 1; break; default: len = get_rdf_size(desc->_wireformat[rdf]); } if(len) { if(pkt_len < len) return 0; /* exceeds rdata */ pkt_len -= len; sldns_buffer_skip(pkt, (ssize_t)len); rr->size += len; } rdf++; } } /* remaining rdata */ rr->size += pkt_len; sldns_buffer_skip(pkt, (ssize_t)pkt_len); return 1; }
/** skip rr ttl and rdata */ static int skip_ttl_rdata(sldns_buffer* pkt) { uint16_t rdatalen; if(sldns_buffer_remaining(pkt) < 6) /* ttl + rdatalen */ return 0; sldns_buffer_skip(pkt, 4); /* ttl */ rdatalen = sldns_buffer_read_u16(pkt); if(sldns_buffer_remaining(pkt) < rdatalen) return 0; sldns_buffer_skip(pkt, (ssize_t)rdatalen); return 1; }
/** compress domain names in rdata, return RETVAL_* */ static int compress_rdata(sldns_buffer* pkt, uint8_t* rdata, size_t todolen, struct regional* region, struct compress_tree_node** tree, const sldns_rr_descriptor* desc) { int labs, r, rdf = 0; size_t dname_len, len, pos = sldns_buffer_position(pkt); uint8_t count = desc->_dname_count; sldns_buffer_skip(pkt, 2); /* rdata len fill in later */ /* space for rdatalen checked for already */ rdata += 2; todolen -= 2; while(todolen > 0 && count) { switch(desc->_wireformat[rdf]) { case LDNS_RDF_TYPE_DNAME: labs = dname_count_size_labels(rdata, &dname_len); if((r=compress_any_dname(rdata, pkt, labs, region, tree)) != RETVAL_OK) return r; rdata += dname_len; todolen -= dname_len; count--; len = 0; break; case LDNS_RDF_TYPE_STR: len = *rdata + 1; break; default: len = get_rdf_size(desc->_wireformat[rdf]); } if(len) { /* copy over */ if(sldns_buffer_remaining(pkt) < len) return RETVAL_TRUNC; sldns_buffer_write(pkt, rdata, len); todolen -= len; rdata += len; } rdf++; } /* copy remainder */ if(todolen > 0) { if(sldns_buffer_remaining(pkt) < todolen) return RETVAL_TRUNC; sldns_buffer_write(pkt, rdata, todolen); } /* set rdata len */ sldns_buffer_write_u16_at(pkt, pos, sldns_buffer_position(pkt)-pos-2); return RETVAL_OK; }
/** analyze rdata in packet */ static void analyze_rdata(sldns_buffer*pkt, const sldns_rr_descriptor* desc, uint16_t rdlen) { int rdf = 0; int count = (int)desc->_dname_count; size_t len, oldpos; while(rdlen > 0 && count) { switch(desc->_wireformat[rdf]) { case LDNS_RDF_TYPE_DNAME: oldpos = sldns_buffer_position(pkt); analyze_dname(pkt); rdlen -= sldns_buffer_position(pkt)-oldpos; count --; len = 0; break; case LDNS_RDF_TYPE_STR: len = sldns_buffer_current(pkt)[0] + 1; break; default: len = get_rdf_size(desc->_wireformat[rdf]); } if(len) { printf(" wf[%d]", (int)len); sldns_buffer_skip(pkt, (ssize_t)len); rdlen -= len; } rdf++; } if(rdlen) { size_t i; printf(" remain[%d]\n", (int)rdlen); for(i=0; i<rdlen; i++) printf(" %2.2X", (unsigned)sldns_buffer_current(pkt)[i]); printf("\n"); } else printf("\n"); sldns_buffer_skip(pkt, (ssize_t)rdlen); }
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; }
void qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo) { uint16_t flags = 0; /* QUERY, NOERROR */ sldns_buffer_clear(pkt); log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/); sldns_buffer_skip(pkt, 2); /* id done later */ sldns_buffer_write_u16(pkt, flags); sldns_buffer_write_u16(pkt, 1); /* query count */ sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */ sldns_buffer_write(pkt, qinfo->qname, qinfo->qname_len); sldns_buffer_write_u16(pkt, qinfo->qtype); sldns_buffer_write_u16(pkt, qinfo->qclass); sldns_buffer_flip(pkt); }
/** return type networkformat that rrsig in packet covers */ static int pkt_rrsig_covered(sldns_buffer* pkt, uint8_t* here, uint16_t* type) { size_t pos = sldns_buffer_position(pkt); sldns_buffer_set_position(pkt, (size_t)(here-sldns_buffer_begin(pkt))); /* ttl + len + size of small rrsig(rootlabel, no signature) */ if(sldns_buffer_remaining(pkt) < 4+2+19) return 0; sldns_buffer_skip(pkt, 4); /* ttl */ if(sldns_buffer_read_u16(pkt) < 19) /* too short */ { sldns_buffer_set_position(pkt, pos); return 0; } *type = sldns_buffer_read_u16(pkt); sldns_buffer_set_position(pkt, pos); return 1; }
/** store query section in wireformat buffer, return RETVAL */ static int insert_query(struct query_info* qinfo, struct compress_tree_node** tree, sldns_buffer* buffer, struct regional* region) { if(sldns_buffer_remaining(buffer) < qinfo->qname_len+sizeof(uint16_t)*2) return RETVAL_TRUNC; /* buffer too small */ /* the query is the first name inserted into the tree */ if(!compress_tree_store(qinfo->qname, dname_count_labels(qinfo->qname), sldns_buffer_position(buffer), region, NULL, tree)) return RETVAL_OUTMEM; if(sldns_buffer_current(buffer) == qinfo->qname) sldns_buffer_skip(buffer, (ssize_t)qinfo->qname_len); else sldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len); sldns_buffer_write_u16(buffer, qinfo->qtype); sldns_buffer_write_u16(buffer, qinfo->qclass); return RETVAL_OK; }
void error_encode(sldns_buffer* buf, int r, struct query_info* qinfo, uint16_t qid, uint16_t qflags, struct edns_data* edns) { uint16_t flags; sldns_buffer_clear(buf); sldns_buffer_write(buf, &qid, sizeof(uint16_t)); flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/ flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */ sldns_buffer_write_u16(buf, flags); if(qinfo) flags = 1; else flags = 0; sldns_buffer_write_u16(buf, flags); flags = 0; sldns_buffer_write(buf, &flags, sizeof(uint16_t)); sldns_buffer_write(buf, &flags, sizeof(uint16_t)); sldns_buffer_write(buf, &flags, sizeof(uint16_t)); if(qinfo) { const uint8_t* qname = qinfo->local_alias ? qinfo->local_alias->rrset->rk.dname : qinfo->qname; size_t qname_len = qinfo->local_alias ? qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; if(sldns_buffer_current(buf) == qname) sldns_buffer_skip(buf, (ssize_t)qname_len); else sldns_buffer_write(buf, qname, qname_len); sldns_buffer_write_u16(buf, qinfo->qtype); sldns_buffer_write_u16(buf, qinfo->qclass); } sldns_buffer_flip(buf); if(edns) { struct edns_data es = *edns; es.edns_version = EDNS_ADVERTISED_VERSION; es.udp_size = EDNS_ADVERTISED_SIZE; es.ext_rcode = 0; es.bits &= EDNS_DO; if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) > edns->udp_size) return; attach_edns_record(buf, &es); } }
void qinfo_query_encode(sldns_buffer* pkt, struct query_info* qinfo) { uint16_t flags = 0; /* QUERY, NOERROR */ const uint8_t* qname = qinfo->local_alias ? qinfo->local_alias->rrset->rk.dname : qinfo->qname; size_t qname_len = qinfo->local_alias ? qinfo->local_alias->rrset->rk.dname_len : qinfo->qname_len; sldns_buffer_clear(pkt); log_assert(sldns_buffer_remaining(pkt) >= 12+255+4/*max query*/); sldns_buffer_skip(pkt, 2); /* id done later */ sldns_buffer_write_u16(pkt, flags); sldns_buffer_write_u16(pkt, 1); /* query count */ sldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */ sldns_buffer_write(pkt, qname, qname_len); sldns_buffer_write_u16(pkt, qinfo->qtype); sldns_buffer_write_u16(pkt, qinfo->qclass); sldns_buffer_flip(pkt); }
/** See if next rrset is nsec at zone apex */ static int nsec_at_apex(sldns_buffer* pkt) { /* we are at ttl position in packet. */ size_t pos = sldns_buffer_position(pkt); uint16_t rdatalen; if(sldns_buffer_remaining(pkt) < 7) /* ttl+len+root */ return 0; /* eek! */ sldns_buffer_skip(pkt, 4); /* ttl */; rdatalen = sldns_buffer_read_u16(pkt); if(sldns_buffer_remaining(pkt) < rdatalen) { sldns_buffer_set_position(pkt, pos); return 0; /* parse error happens later */ } /* must validate the nsec next domain name format */ if(pkt_dname_len(pkt) == 0) { sldns_buffer_set_position(pkt, pos); return 0; /* parse error */ } /* see if SOA bit is set. */ if(sldns_buffer_position(pkt) < pos+4+rdatalen) { /* nsec type bitmap contains items */ uint8_t win, blen, bits; /* need: windownum, bitmap len, firstbyte */ if(sldns_buffer_position(pkt)+3 > pos+4+rdatalen) { sldns_buffer_set_position(pkt, pos); return 0; /* malformed nsec */ } win = sldns_buffer_read_u8(pkt); blen = sldns_buffer_read_u8(pkt); bits = sldns_buffer_read_u8(pkt); /* 0window always first window. bitlen >=1 or parse error really. bit 0x2 is SOA. */ if(win == 0 && blen >= 1 && (bits & 0x02)) { sldns_buffer_set_position(pkt, pos); return 1; } } sldns_buffer_set_position(pkt, pos); return 0; }
int query_info_parse(struct query_info* m, sldns_buffer* query) { uint8_t* q = sldns_buffer_begin(query); /* minimum size: header + \0 + qtype + qclass */ if(sldns_buffer_limit(query) < LDNS_HEADER_SIZE + 5) return 0; if(LDNS_OPCODE_WIRE(q) != LDNS_PACKET_QUERY || LDNS_QDCOUNT(q) != 1 || sldns_buffer_position(query) != 0) return 0; sldns_buffer_skip(query, LDNS_HEADER_SIZE); m->qname = sldns_buffer_current(query); if((m->qname_len = query_dname_len(query)) == 0) return 0; /* parse error */ if(sldns_buffer_remaining(query) < 4) return 0; /* need qtype, qclass */ m->qtype = sldns_buffer_read_u16(query); m->qclass = sldns_buffer_read_u16(query); return 1; }
/* determine length of a dname in buffer, no compression pointers allowed */ size_t query_dname_len(sldns_buffer* query) { size_t len = 0; size_t labellen; while(1) { if(sldns_buffer_remaining(query) < 1) return 0; /* parse error, need label len */ labellen = sldns_buffer_read_u8(query); if(labellen&0xc0) return 0; /* no compression allowed in queries */ len += labellen + 1; if(len > LDNS_MAX_DOMAINLEN) return 0; /* too long */ if(labellen == 0) return len; if(sldns_buffer_remaining(query) < labellen) return 0; /* parse error, need content */ sldns_buffer_skip(query, (ssize_t)labellen); } }
/** see if RRSIG is a duplicate of another */ static int sig_is_double(sldns_buffer* pkt, struct rrset_parse* rrset, uint8_t* ttldata) { uint16_t rlen, siglen; size_t pos = sldns_buffer_position(pkt); struct rr_parse* sig; if(sldns_buffer_remaining(pkt) < 6) return 0; sldns_buffer_skip(pkt, 4); /* ttl */ rlen = sldns_buffer_read_u16(pkt); if(sldns_buffer_remaining(pkt) < rlen) { sldns_buffer_set_position(pkt, pos); return 0; } sldns_buffer_set_position(pkt, pos); sig = rrset->rrsig_first; while(sig) { /* check if rdatalen is same */ memmove(&siglen, sig->ttl_data+4, sizeof(siglen)); siglen = ntohs(siglen); /* checks if data in packet is exactly the same, this means * also dname in rdata is the same, but rrsig is not allowed * to have compressed dnames anyway. If it is compressed anyway * it will lead to duplicate rrs for qtype=RRSIG. (or ANY). * * Cannot use sig->size because size of the other one is not * calculated yet. */ if(siglen == rlen) { if(siglen>0 && memcmp(sig->ttl_data+6, ttldata+6, siglen) == 0) { /* same! */ return 1; } } sig = sig->next; } return 0; }
/** analyze rr in packet */ static void analyze_rr(sldns_buffer* pkt, int q) { uint16_t type, dclass, len; uint32_t ttl; analyze_dname(pkt); type = sldns_buffer_read_u16(pkt); dclass = sldns_buffer_read_u16(pkt); printf("type %s(%d)", sldns_rr_descript(type)? sldns_rr_descript(type)->_name: "??" , (int)type); printf(" class %s(%d) ", sldns_lookup_by_id(sldns_rr_classes, (int)dclass)?sldns_lookup_by_id(sldns_rr_classes, (int)dclass)->name:"??", (int)dclass); if(q) { printf("\n"); } else { ttl = sldns_buffer_read_u32(pkt); printf(" ttl %d (0x%x)", (int)ttl, (unsigned)ttl); len = sldns_buffer_read_u16(pkt); printf(" rdata len %d:\n", (int)len); if(sldns_rr_descript(type)) analyze_rdata(pkt, sldns_rr_descript(type), len); else sldns_buffer_skip(pkt, (ssize_t)len); } }
/** * read contents of trusted-keys{ ... ; clauses and insert keys into storage. * @param anchors: where to store keys * @param buf: buffer to use * @param line: line number in file * @param in: file to read from. * @return 0 on error. */ static int process_bind_contents(struct val_anchors* anchors, sldns_buffer* buf, int* line, FILE* in) { /* loop over contents, collate strings before ; */ /* contents is (numbered): 0 1 2 3 4 5 6 7 8 */ /* name. 257 3 5 base64 base64 */ /* quoted value: 0 "111" 0 0 0 0 0 0 0 */ /* comments value: 1 "000" 1 1 1 "0 0 0 0" 1 */ int contnum = 0; int quoted = 0; int comments = 1; int rdlen; char* str = 0; sldns_buffer_clear(buf); while((rdlen=readkeyword_bindfile(in, buf, line, comments))) { if(rdlen == 1 && sldns_buffer_position(buf) == 1 && isspace((unsigned char)*sldns_buffer_begin(buf))) { /* starting whitespace is removed */ sldns_buffer_clear(buf); continue; } else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == '"') { /* remove " from the string */ if(contnum == 0) { quoted = 1; comments = 0; } sldns_buffer_skip(buf, -1); if(contnum > 0 && quoted) { if(sldns_buffer_remaining(buf) < 8+1) { log_err("line %d, too long", *line); return 0; } sldns_buffer_write(buf, " DNSKEY ", 8); quoted = 0; comments = 1; } else if(contnum > 0) comments = !comments; continue; } else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == ';') { if(contnum < 5) { sldns_buffer_write_u8(buf, 0); log_err("line %d, bad key", *line); return 0; } sldns_buffer_skip(buf, -1); sldns_buffer_write_u8(buf, 0); str = strdup((char*)sldns_buffer_begin(buf)); if(!str) { log_err("line %d, allocation failure", *line); return 0; } if(!anchor_store_str(anchors, buf, str)) { log_err("line %d, bad key", *line); free(str); return 0; } free(str); sldns_buffer_clear(buf); contnum = 0; quoted = 0; comments = 1; continue; } else if(rdlen == 1 && sldns_buffer_current(buf)[-1] == '}') { if(contnum > 0) { sldns_buffer_write_u8(buf, 0); log_err("line %d, bad key before }", *line); return 0; } return 1; } else if(rdlen == 1 && isspace((unsigned char)sldns_buffer_current(buf)[-1])) { /* leave whitespace here */ } else { /* not space or whatnot, so actual content */ contnum ++; if(contnum == 1 && !quoted) { if(sldns_buffer_remaining(buf) < 8+1) { log_err("line %d, too long", *line); return 0; } sldns_buffer_write(buf, " DNSKEY ", 8); } } } log_err("line %d, EOF before }", *line); return 0; }
/** * Read a keyword skipping bind comments; spaces, specials, restkeywords. * The file is split into the following tokens: * * special characters, on their own, rdlen=1, { } doublequote ; * * whitespace becomes a single ' ' or tab. Newlines become spaces. * * other words ('keywords') * * comments are skipped if desired * / / C++ style comment to end of line * # to end of line * / * C style comment * / * @param in: file to read from. * @param buf: buffer, what is read is stored after current buffer position. * Space is left in the buffer to write a terminating 0. * @param line: line number is increased per line, for error reports. * @param comments: if 0, comments are not possible and become text. * if 1, comments are skipped entirely. * In BIND files, this is when reading quoted strings, for example * " base 64 text with / / in there " * @return the number of character written to the buffer. * 0 on end of file. */ static int readkeyword_bindfile(FILE* in, sldns_buffer* buf, int* line, int comments) { int c; int numdone = 0; while((c = getc(in)) != EOF ) { if(comments && c == '#') { /* # blabla */ skip_to_eol(in); (*line)++; continue; } else if(comments && c=='/' && numdone>0 && /* /_/ bla*/ sldns_buffer_read_u8_at(buf, sldns_buffer_position(buf)-1) == '/') { sldns_buffer_skip(buf, -1); numdone--; skip_to_eol(in); (*line)++; continue; } else if(comments && c=='*' && numdone>0 && /* /_* bla *_/ */ sldns_buffer_read_u8_at(buf, sldns_buffer_position(buf)-1) == '/') { sldns_buffer_skip(buf, -1); numdone--; /* skip to end of comment */ while(c != EOF && (c=getc(in)) != EOF ) { if(c == '*') { if((c=getc(in)) == '/') break; } if(c == '\n') (*line)++; } continue; } /* not a comment, complete the keyword */ if(numdone > 0) { /* check same type */ if(isspace((unsigned char)c)) { ungetc(c, in); return numdone; } if(is_bind_special(c)) { ungetc(c, in); return numdone; } } if(c == '\n') { c = ' '; (*line)++; } /* space for 1 char + 0 string terminator */ if(sldns_buffer_remaining(buf) < 2) { fatal_exit("trusted-keys, %d, string too long", *line); } sldns_buffer_write_u8(buf, (uint8_t)c); numdone++; if(isspace((unsigned char)c)) { /* collate whitespace into ' ' */ while((c = getc(in)) != EOF ) { if(c == '\n') (*line)++; if(!isspace((unsigned char)c)) { ungetc(c, in); break; } } return numdone; } if(is_bind_special(c)) return numdone; } return numdone; }
/** do the rdata copy */ static int rdata_copy(sldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, struct rr_parse* rr, time_t* rr_ttl, uint16_t type, sldns_pkt_section section) { uint16_t pkt_len; const sldns_rr_descriptor* desc; *rr_ttl = sldns_read_uint32(rr->ttl_data); /* RFC 2181 Section 8. if msb of ttl is set treat as if zero. */ if(*rr_ttl & 0x80000000U) *rr_ttl = 0; if(type == LDNS_RR_TYPE_SOA && section == LDNS_SECTION_AUTHORITY) { /* negative response. see if TTL of SOA record larger than the * minimum-ttl in the rdata of the SOA record */ if(*rr_ttl > soa_find_minttl(rr)) *rr_ttl = soa_find_minttl(rr); if(*rr_ttl > MAX_NEG_TTL) *rr_ttl = MAX_NEG_TTL; } if(*rr_ttl < MIN_TTL) *rr_ttl = MIN_TTL; if(*rr_ttl < data->ttl) data->ttl = *rr_ttl; if(rr->outside_packet) { /* uncompressed already, only needs copy */ memmove(to, rr->ttl_data+sizeof(uint32_t), rr->size); return 1; } sldns_buffer_set_position(pkt, (size_t) (rr->ttl_data - sldns_buffer_begin(pkt) + sizeof(uint32_t))); /* insert decompressed size into rdata len stored in memory */ /* -2 because rdatalen bytes are not included. */ pkt_len = htons(rr->size - 2); memmove(to, &pkt_len, sizeof(uint16_t)); to += 2; /* read packet rdata len */ pkt_len = sldns_buffer_read_u16(pkt); if(sldns_buffer_remaining(pkt) < pkt_len) return 0; desc = sldns_rr_descript(type); if(pkt_len > 0 && desc && desc->_dname_count > 0) { int count = (int)desc->_dname_count; int rdf = 0; size_t len; size_t oldpos; /* decompress dnames. */ while(pkt_len > 0 && count) { switch(desc->_wireformat[rdf]) { case LDNS_RDF_TYPE_DNAME: oldpos = sldns_buffer_position(pkt); dname_pkt_copy(pkt, to, sldns_buffer_current(pkt)); to += pkt_dname_len(pkt); pkt_len -= sldns_buffer_position(pkt)-oldpos; count--; len = 0; break; case LDNS_RDF_TYPE_STR: len = sldns_buffer_current(pkt)[0] + 1; break; default: len = get_rdf_size(desc->_wireformat[rdf]); break; } if(len) { memmove(to, sldns_buffer_current(pkt), len); to += len; sldns_buffer_skip(pkt, (ssize_t)len); log_assert(len <= pkt_len); pkt_len -= len; } rdf++; } } /* copy remaining rdata */ if(pkt_len > 0) memmove(to, sldns_buffer_current(pkt), pkt_len); return 1; }