ldns_buffer_clear(buf);
ldns_buffer_write(buf, &id, sizeof(uint16_t));
- flags = (uint16_t)(BIT_QR | r); /* QR and retcode*/
+ flags = (uint16_t)(BIT_QR | BIT_RA | r); /* QR and retcode*/
flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
ldns_buffer_write_u16(buf, flags);
flags = 1;
attach_edns_record(c->buffer, &edns);
return 1;
}
+ if(edns.edns_present && edns.udp_size < LDNS_HEADER_SIZE) {
+ verbose(VERB_ALGO, "worker request: edns is too small.");
+ LDNS_QR_SET(ldns_buffer_begin(c->buffer));
+ LDNS_TC_SET(ldns_buffer_begin(c->buffer));
+ LDNS_RCODE_SET(ldns_buffer_begin(c->buffer),
+ LDNS_RCODE_SERVFAIL);
+ ldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
+ ldns_buffer_flip(c->buffer);
+ return 1;
+ }
if(c->type != comm_udp)
edns.udp_size = 65535; /* max size for TCP replies */
if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) {
verbose(VERB_DETAIL, "return error response %s",
ldns_lookup_by_id(ldns_rcodes, rcode)?
ldns_lookup_by_id(ldns_rcodes, rcode)->name:"??");
- if(iq && iq->orig_qname) {
- /* encode original query */
- qstate->qinfo.qname = iq->orig_qname;
- qstate->qinfo.qname_len = iq->orig_qnamelen;
+ if(iq) {
+ if(iq->orig_qname) {
+ /* encode original query */
+ qstate->qinfo.qname = iq->orig_qname;
+ qstate->qinfo.qname_len = iq->orig_qnamelen;
+ }
qstate->query_flags = iq->orig_qflags;
}
qinfo_query_encode(qstate->buf, &qstate->qinfo);
return RETVAL_OK;
}
-int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
+/** store query section in wireformat buffer, return RETVAL */
+static int
+insert_query(struct query_info* qinfo, struct compress_tree_node* tree,
+ ldns_buffer* buffer, struct region* region)
+{
+ if(ldns_buffer_remaining(buffer) <
+ qinfo->qname_len+sizeof(uint16_t)*2)
+ return RETVAL_TRUNC; /* buffer too small */
+ if(!compress_tree_store(&tree, qinfo->qname,
+ dname_count_labels(qinfo->qname),
+ ldns_buffer_position(buffer), region, NULL))
+ return RETVAL_OUTMEM;
+ ldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len);
+ ldns_buffer_write_u16(buffer, qinfo->qtype);
+ ldns_buffer_write_u16(buffer, qinfo->qclass);
+ return RETVAL_OK;
+}
+
+int
+reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow,
region_type* region, uint16_t udpsize, int dnssec)
{
/* insert query section */
if(rep->qdcount) {
- if(ldns_buffer_remaining(buffer) <
- qinfo->qname_len+sizeof(uint16_t)*2)
- return 0; /* buffer too small */
- if(!compress_tree_store(&tree, qinfo->qname,
- dname_count_labels(qinfo->qname),
- ldns_buffer_position(buffer), region, NULL))
+ 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;
- ldns_buffer_write(buffer, qinfo->qname, qinfo->qname_len);
- ldns_buffer_write_u16(buffer, qinfo->qtype);
- ldns_buffer_write_u16(buffer, qinfo->qclass);
+ }
}
/* insert answer section */
struct edns_data* edns, int dnssec)
{
uint16_t flags;
+ int attach_edns = 1;
if(!cached) {
/* original flags, copy RD bit from query. */
flags = (rep->flags & ~BIT_AA) | (qflags & (BIT_RD|BIT_CD));
}
log_assert(flags & BIT_QR); /* QR bit must be on in our replies */
- if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns))
- return 0; /* packet too small to contain edns... */
- udpsize -= calc_edns_field_size(edns);
+ if(udpsize < LDNS_HEADER_SIZE)
+ return 0;
+ if(udpsize < LDNS_HEADER_SIZE + calc_edns_field_size(edns)) {
+ /* packet too small to contain edns, omit it. */
+ attach_edns = 0;
+ } else {
+ /* reserve space for edns record */
+ udpsize -= calc_edns_field_size(edns);
+ }
+
if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
udpsize, dnssec)) {
log_err("reply encode: out of memory");
return 0;
}
- attach_edns_record(pkt, edns);
+ if(attach_edns)
+ attach_edns_record(pkt, edns);
return 1;
}