int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, uint16_t id, uint16_t flags, sldns_buffer* buffer, time_t timenow, struct regional* region, uint16_t udpsize, int dnssec) { uint16_t ancount=0, nscount=0, arcount=0; struct compress_tree_node* tree = 0; int r; size_t rr_offset; sldns_buffer_clear(buffer); if(udpsize < sldns_buffer_limit(buffer)) sldns_buffer_set_limit(buffer, udpsize); if(sldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE) return 0; sldns_buffer_write(buffer, &id, sizeof(uint16_t)); sldns_buffer_write_u16(buffer, flags); sldns_buffer_write_u16(buffer, rep->qdcount); /* set an, ns, ar counts to zero in case of small packets */ sldns_buffer_write(buffer, "\000\000\000\000\000\000", 6); /* insert query section */ if(rep->qdcount) { if((r=insert_query(qinfo, &tree, buffer, region)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ sldns_buffer_write_u16_at(buffer, 4, 0); LDNS_TC_SET(sldns_buffer_begin(buffer)); sldns_buffer_flip(buffer); return 1; } return 0; } } /* roundrobin offset. using query id for random number. With ntohs * for different roundrobins for sequential id client senders. */ rr_offset = RRSET_ROUNDROBIN?ntohs(id):0; /* "prepend" any local alias records in the answer section if this * response is supposed to be authoritative. Currently it should * be a single CNAME record (sanity-checked in worker_handle_request()) * but it can be extended if and when we support more variations of * aliases. */ if(qinfo->local_alias && (flags & BIT_AA)) { struct reply_info arep; time_t timezero = 0; /* to use the 'authoritative' TTL */ memset(&arep, 0, sizeof(arep)); arep.flags = rep->flags; arep.an_numrrsets = 1; arep.rrset_count = 1; arep.rrsets = &qinfo->local_alias->rrset; if((r=insert_section(&arep, 1, &ancount, buffer, 0, timezero, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ sldns_buffer_write_u16_at(buffer, 6, ancount); LDNS_TC_SET(sldns_buffer_begin(buffer)); sldns_buffer_flip(buffer); return 1; } return 0; } } /* insert answer section */ if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ sldns_buffer_write_u16_at(buffer, 6, ancount); LDNS_TC_SET(sldns_buffer_begin(buffer)); sldns_buffer_flip(buffer); return 1; } return 0; } sldns_buffer_write_u16_at(buffer, 6, ancount); /* if response is positive answer, auth/add sections are not required */ if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) { /* insert auth section */ if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, rep->an_numrrsets, timenow, region, &tree, LDNS_SECTION_AUTHORITY, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ sldns_buffer_write_u16_at(buffer, 8, nscount); LDNS_TC_SET(sldns_buffer_begin(buffer)); sldns_buffer_flip(buffer); return 1; } return 0; } sldns_buffer_write_u16_at(buffer, 8, nscount); /* insert add section */ if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, rep->an_numrrsets + rep->ns_numrrsets, timenow, region, &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* no need to set TC bit, this is the additional */ sldns_buffer_write_u16_at(buffer, 10, arcount); sldns_buffer_flip(buffer); return 1; } return 0; } sldns_buffer_write_u16_at(buffer, 10, arcount); } sldns_buffer_flip(buffer); return 1; }
int reply_info_encode(struct query_info* qinfo, struct reply_info* rep, uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow, struct regional* region, uint16_t udpsize, int dnssec) { uint16_t ancount=0, nscount=0, arcount=0; struct compress_tree_node* tree = 0; int r; size_t rr_offset; ldns_buffer_clear(buffer); if(udpsize < ldns_buffer_limit(buffer)) ldns_buffer_set_limit(buffer, udpsize); if(ldns_buffer_remaining(buffer) < LDNS_HEADER_SIZE) return 0; ldns_buffer_write(buffer, &id, sizeof(uint16_t)); ldns_buffer_write_u16(buffer, flags); ldns_buffer_write_u16(buffer, rep->qdcount); /* set an, ns, ar counts to zero in case of small packets */ ldns_buffer_write(buffer, "\000\000\000\000\000\000", 6); /* insert query section */ if(rep->qdcount) { if((r=insert_query(qinfo, &tree, buffer, region)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ ldns_buffer_write_u16_at(buffer, 4, 0); LDNS_TC_SET(ldns_buffer_begin(buffer)); ldns_buffer_flip(buffer); return 1; } return 0; } } /* roundrobin offset. using query id for random number */ rr_offset = RRSET_ROUNDROBIN?id:0; /* insert answer section */ if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer, 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ ldns_buffer_write_u16_at(buffer, 6, ancount); LDNS_TC_SET(ldns_buffer_begin(buffer)); ldns_buffer_flip(buffer); return 1; } return 0; } ldns_buffer_write_u16_at(buffer, 6, ancount); /* if response is positive answer, auth/add sections are not required */ if( ! (MINIMAL_RESPONSES && positive_answer(rep, qinfo->qtype)) ) { /* insert auth section */ if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer, rep->an_numrrsets, timenow, region, &tree, LDNS_SECTION_AUTHORITY, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* create truncated message */ ldns_buffer_write_u16_at(buffer, 8, nscount); LDNS_TC_SET(ldns_buffer_begin(buffer)); ldns_buffer_flip(buffer); return 1; } return 0; } ldns_buffer_write_u16_at(buffer, 8, nscount); /* insert add section */ if((r=insert_section(rep, rep->ar_numrrsets, &arcount, buffer, rep->an_numrrsets + rep->ns_numrrsets, timenow, region, &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype, dnssec, rr_offset)) != RETVAL_OK) { if(r == RETVAL_TRUNC) { /* no need to set TC bit, this is the additional */ ldns_buffer_write_u16_at(buffer, 10, arcount); ldns_buffer_flip(buffer); return 1; } return 0; } ldns_buffer_write_u16_at(buffer, 10, arcount); } else { ldns_buffer_write_u16_at(buffer, 8, nscount); ldns_buffer_write_u16_at(buffer, 10, arcount); } ldns_buffer_flip(buffer); return 1; }