/** store msg section in wireformat buffer, return RETVAL_* */ static int insert_section(struct reply_info* rep, size_t num_rrsets, uint16_t* num_rrs, ldns_buffer* pkt, size_t rrsets_before, uint32_t timenow, struct regional* region, struct compress_tree_node** tree, ldns_pkt_section s, uint16_t qtype, int dnssec, size_t rr_offset) { int r; size_t i, setstart; *num_rrs = 0; if(s != LDNS_SECTION_ADDITIONAL) { if(s == LDNS_SECTION_ANSWER && qtype == LDNS_RR_TYPE_ANY) dnssec = 1; /* include all types in ANY answer */ for(i=0; i<num_rrsets; i++) { setstart = ldns_buffer_position(pkt); if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], pkt, num_rrs, timenow, region, 1, 1, tree, s, qtype, dnssec, rr_offset)) != RETVAL_OK) { /* Bad, but if due to size must set TC bit */ /* trim off the rrset neatly. */ ldns_buffer_set_position(pkt, setstart); return r; } } } else { for(i=0; i<num_rrsets; i++) { setstart = ldns_buffer_position(pkt); if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], pkt, num_rrs, timenow, region, 1, 0, tree, s, qtype, dnssec, rr_offset)) != RETVAL_OK) { ldns_buffer_set_position(pkt, setstart); return r; } } if(dnssec) for(i=0; i<num_rrsets; i++) { setstart = ldns_buffer_position(pkt); if((r=packed_rrset_encode(rep->rrsets[rrsets_before+i], pkt, num_rrs, timenow, region, 0, 1, tree, s, qtype, dnssec, rr_offset)) != RETVAL_OK) { ldns_buffer_set_position(pkt, setstart); return r; } } } return RETVAL_OK; }
size_t pkt_dname_len(ldns_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(ldns_buffer_remaining(pkt) < 1) return 0; labellen = ldns_buffer_read_u8(pkt); if(LABEL_IS_PTR(labellen)) { /* compression ptr */ uint16_t ptr; if(ldns_buffer_remaining(pkt) < 1) return 0; ptr = PTR_OFFSET(labellen, ldns_buffer_read_u8(pkt)); if(ptrcount++ > MAX_COMPRESS_PTRS) return 0; /* loop! */ if(ldns_buffer_limit(pkt) <= ptr) return 0; /* out of bounds! */ if(!endpos) endpos = ldns_buffer_position(pkt); ldns_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(ldns_buffer_remaining(pkt) < labellen) return 0; ldns_buffer_skip(pkt, (ssize_t)labellen); } } if(endpos) ldns_buffer_set_position(pkt, endpos); return len; }
int reply_info_parse(ldns_buffer* pkt, struct alloc_cache* alloc, struct query_info* qinf, struct reply_info** rep, struct regional* region, struct edns_data* edns) { /* use scratch pad region-allocator during parsing. */ struct msg_parse* msg; int ret; qinf->qname = NULL; *rep = NULL; if(!(msg = regional_alloc(region, sizeof(*msg)))) { return LDNS_RCODE_SERVFAIL; } memset(msg, 0, sizeof(*msg)); ldns_buffer_set_position(pkt, 0); if((ret = parse_packet(pkt, msg, region)) != 0) { return ret; } if((ret = parse_extract_edns(msg, edns)) != 0) return ret; /* parse OK, allocate return structures */ /* this also performs dname decompression */ if(!parse_create_msg(pkt, msg, alloc, qinf, rep, NULL)) { query_info_clear(qinf); reply_info_parsedelete(*rep, alloc); *rep = NULL; return LDNS_RCODE_SERVFAIL; } return 0; }
int ldns_bgetc(ldns_buffer *buffer) { if (!ldns_buffer_available_at(buffer, buffer->_position, sizeof(uint8_t))) { ldns_buffer_set_position(buffer, ldns_buffer_limit(buffer)); /* ldns_buffer_rewind(buffer);*/ return EOF; } return (int)ldns_buffer_read_u8(buffer); }
/* Create response according to the ldns packet content */ int createResponse(struct module_qstate* qstate, ldns_buffer* pkt) { struct msg_parse* prs; struct edns_data edns; /* parse message */ prs = (struct msg_parse*) regional_alloc(qstate->env->scratch, sizeof(struct msg_parse)); if (!prs) { log_err("storeResponse: out of memory on incoming message"); return 0; } memset(prs, 0, sizeof(*prs)); memset(&edns, 0, sizeof(edns)); ldns_buffer_set_position(pkt, 0); if (parse_packet(pkt, prs, qstate->env->scratch) != LDNS_RCODE_NOERROR) { verbose(VERB_ALGO, "storeResponse: parse error on reply packet"); return 0; } /* edns is not examined, but removed from message to help cache */ if(parse_extract_edns(prs, &edns) != LDNS_RCODE_NOERROR) return 0; /* remove CD-bit, we asked for in case we handle validation ourself */ prs->flags &= ~BIT_CD; /* allocate response dns_msg in region */ qstate->return_msg = (struct dns_msg*)regional_alloc(qstate->region, sizeof(struct dns_msg)); if (!qstate->return_msg) return 0; memset(qstate->return_msg, 0, sizeof(*qstate->return_msg)); if(!parse_create_msg(pkt, prs, NULL, &(qstate->return_msg)->qinfo, &(qstate->return_msg)->rep, qstate->region)) { log_err("storeResponse: malloc failure: allocating incoming dns_msg"); return 0; } /* Make sure that the RA flag is set (since the presence of * this module means that recursion is available) */ /* qstate->return_msg->rep->flags |= BIT_RA; */ /* Clear the AA flag */ /* FIXME: does this action go here or in some other module? */ /*qstate->return_msg->rep->flags &= ~BIT_AA; */ /* make sure QR flag is on */ /*qstate->return_msg->rep->flags |= BIT_QR; */ if(verbosity >= VERB_ALGO) log_dns_msg("storeResponse: packet:", &qstate->return_msg->qinfo, qstate->return_msg->rep); return 1; }
/** get additional name from rrset RR, return false if no name present */ static int get_additional_name(struct rrset_parse* rrset, struct rr_parse* rr, uint8_t** nm, size_t* nmlen, ldns_buffer* pkt) { size_t offset = 0; size_t len, oldpos; switch(rrset->type) { case LDNS_RR_TYPE_MB: case LDNS_RR_TYPE_MD: case LDNS_RR_TYPE_MF: case LDNS_RR_TYPE_NS: offset = 0; break; case LDNS_RR_TYPE_MX: case LDNS_RR_TYPE_KX: offset = 2; break; case LDNS_RR_TYPE_SRV: offset = 6; break; case LDNS_RR_TYPE_NAPTR: /* TODO: NAPTR not supported, glue stripped off */ return 0; default: return 0; } len = ldns_read_uint16(rr->ttl_data+sizeof(uint32_t)); if(len < offset+1) return 0; /* rdata field too small */ *nm = rr->ttl_data+sizeof(uint32_t)+sizeof(uint16_t)+offset; oldpos = ldns_buffer_position(pkt); ldns_buffer_set_position(pkt, (size_t)(*nm - ldns_buffer_begin(pkt))); *nmlen = pkt_dname_len(pkt); ldns_buffer_set_position(pkt, oldpos); if(*nmlen == 0) return 0; return 1; }
/** get msg reply struct (in temp region) */ static struct reply_info* parse_reply(ldns_buffer* pkt, struct regional* region, struct query_info* qi) { struct reply_info* rep; struct msg_parse* msg; if(!(msg = regional_alloc(region, sizeof(*msg)))) { return NULL; } memset(msg, 0, sizeof(*msg)); ldns_buffer_set_position(pkt, 0); if(parse_packet(pkt, msg, region) != 0) return 0; if(!parse_create_msg(pkt, msg, NULL, qi, &rep, region)) { return 0; } return rep; }
ldns_buffer * read_hex_buffer(char *filename) { uint8_t *wire; size_t wiresize; ldns_buffer *result_buffer = NULL; wire = xmalloc(LDNS_MAX_PACKETLEN); wiresize = packetbuffromfile(filename, wire); result_buffer = LDNS_MALLOC(ldns_buffer); ldns_buffer_new_frm_data(result_buffer, wire, wiresize); ldns_buffer_set_position(result_buffer, ldns_buffer_capacity(result_buffer)); xfree(wire); return result_buffer; }
void attach_edns_record(ldns_buffer* pkt, struct edns_data* edns) { size_t len; if(!edns || !edns->edns_present) return; /* inc additional count */ ldns_buffer_write_u16_at(pkt, 10, ldns_buffer_read_u16_at(pkt, 10) + 1); len = ldns_buffer_limit(pkt); ldns_buffer_clear(pkt); ldns_buffer_set_position(pkt, len); /* write EDNS record */ ldns_buffer_write_u8(pkt, 0); /* '.' label */ ldns_buffer_write_u16(pkt, LDNS_RR_TYPE_OPT); /* type */ ldns_buffer_write_u16(pkt, edns->udp_size); /* class */ ldns_buffer_write_u8(pkt, edns->ext_rcode); /* ttl */ ldns_buffer_write_u8(pkt, edns->edns_version); ldns_buffer_write_u16(pkt, edns->bits); ldns_buffer_write_u16(pkt, 0); /* rdatalen */ ldns_buffer_flip(pkt); }
/** do the rdata copy */ static int rdata_copy(ldns_buffer* pkt, struct packed_rrset_data* data, uint8_t* to, struct rr_parse* rr, uint32_t* rr_ttl, uint16_t type) { uint16_t pkt_len; const ldns_rr_descriptor* desc; *rr_ttl = ldns_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(*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; } ldns_buffer_set_position(pkt, (size_t) (rr->ttl_data - ldns_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 = ldns_buffer_read_u16(pkt); if(ldns_buffer_remaining(pkt) < pkt_len) return 0; desc = ldns_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 = ldns_buffer_position(pkt); dname_pkt_copy(pkt, to, ldns_buffer_current(pkt)); to += pkt_dname_len(pkt); pkt_len -= ldns_buffer_position(pkt)-oldpos; count--; len = 0; break; case LDNS_RDF_TYPE_STR: len = ldns_buffer_current(pkt)[0] + 1; break; default: len = get_rdf_size(desc->_wireformat[rdf]); break; } if(len) { memmove(to, ldns_buffer_current(pkt), len); to += len; ldns_buffer_skip(pkt, (ssize_t)len); log_assert(len <= pkt_len); pkt_len -= len; } rdf++; } } /* copy remaining rdata */ if(pkt_len > 0) memmove(to, ldns_buffer_current(pkt), pkt_len); return 1; }