/* locked and ids and ttls are OK. */
if(!reply_info_answer_encode(&mrentry->key, rep, id, flags,
repinfo->c->buffer, timenow, 1, worker->scratchpad,
- udpsize, edns)) {
+ udpsize, edns, (int)(edns->bits & EDNS_DO) )) {
replyerror_fillbuf(LDNS_RCODE_SERVFAIL, repinfo, id,
flags, &mrentry->key);
}
struct work_query* w;
struct edns_data edns;
- verbose(VERB_DETAIL, "worker handle request");
if(error != NETEVENT_NOERROR) {
- log_err("called with err=%d", error);
+ log_err("handle request called with err=%d", error);
return 0;
}
if((ret=worker_check_request(c->buffer)) != 0) {
+ verbose(VERB_ALGO, "worker check request: bad query.");
if(ret != -1) {
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret);
worker->stats.num_queries++;
/* see if query is in the cache */
if(!query_info_parse(&qinfo, c->buffer)) {
+ verbose(VERB_ALGO, "worker parse request: formerror.");
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
}
h = query_info_hash(&qinfo);
if((ret=parse_edns_from_pkt(c->buffer, &edns)) != 0) {
+ verbose(VERB_ALGO, "worker parse edns: formerror.");
LDNS_QR_SET(ldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(ldns_buffer_begin(c->buffer), ret);
return 1;
edns.edns_version = EDNS_ADVERTISED_VERSION;
edns.udp_size = EDNS_ADVERTISED_SIZE;
edns.bits &= EDNS_DO;
+ verbose(VERB_ALGO, "query with bad edns version.");
replyerror_fillbuf(EDNS_RCODE_BADVERS&0xf, repinfo,
*(uint16_t*)ldns_buffer_begin(c->buffer),
ldns_buffer_read_u16_at(c->buffer, 2), &qinfo);
edns.udp_size = 65535; /* max size for TCP replies */
if((e=slabhash_lookup(worker->env.msg_cache, h, &qinfo, 0))) {
/* answer from cache - we have acquired a readlock on it */
- verbose(VERB_DETAIL, "answer from the cache");
if(answer_from_cache(worker, e,
*(uint16_t*)ldns_buffer_begin(c->buffer),
ldns_buffer_read_u16_at(c->buffer, 2), repinfo,
+11 June 2007: Wouter
+ - replies on TCP queries have the address field set in replyinfo,
+ for serviced queries, because the initiator does not know that
+ a TCP fallback has occured.
+ - omit DNSSEC types from nonDO replies, except if qtype is ANY or
+ if qtype directly queries for the type (and then only show that
+ 'unknown type' in the answer section).
+ - fixed message parsing where rrsigs on their own would be put
+ in the signature list over the rrsig type.
+
7 June 2007: Wouter
- fixup error in double linked list insertion for subqueries and
for outbound list of serviced queries for iterator module.
qstate->edns.bits &= EDNS_DO;
if(!reply_info_answer_encode(&reply_qinfo, reply_msg, 0,
qstate->query_flags, qstate->buf, 0, 0,
- qstate->scratch, us, &qstate->edns))
+ qstate->scratch, us, &qstate->edns,
+ (int)(qstate->edns.bits&EDNS_DO)))
return 0;
dns_cache_store_msg(qstate->env, &reply_qinfo, qstate->query_hash,
reply_msg);
edns.bits = qstate->edns.bits & EDNS_DO;
if(!reply_info_answer_encode(&qinf, msg->rep, 0, iq->orig_qflags,
qstate->buf, 0, 1, qstate->scratch, qstate->edns.udp_size,
- &edns)) {
+ &edns, (int)(qstate->edns.bits & EDNS_DO))) {
/* encode servfail */
error_response(qstate, id, LDNS_RCODE_SERVFAIL);
return;
serviced_tcp_initiate(sq->outnet, sq, c->buffer);
return 0;
}
-
+ /* insert address into reply info */
+ memcpy(&rep->addr, &sq->addr, sq->addrlen);
+ rep->addrlen = sq->addrlen;
(void)rbtree_delete(sq->outnet->serviced, sq);
serviced_callbacks(sq, error, c, rep);
serviced_delete(sq);
} else {
const size_t lim = 512;
ret = reply_info_encode(&qi, rep, id, flags, out, timenow,
- region, 65535);
+ region, 65535, (int)(edns.bits & EDNS_DO) );
unit_assert(ret != 0); /* udp packets should fit */
attach_edns_record(out, &edns);
if(vbmp) printf("inlen %u outlen %u\n",
if(ldns_buffer_limit(out) > lim) {
ret = reply_info_encode(&qi, rep, id, flags, out,
timenow, region,
- lim - calc_edns_field_size(&edns));
+ lim - calc_edns_field_size(&edns),
+ (int)(edns.bits & EDNS_DO));
unit_assert(ret != 0); /* should fit, but with TC */
attach_edns_record(out, &edns);
if( LDNS_QDCOUNT(ldns_buffer_begin(out)) !=
return RETVAL_OK;
}
+/** Returns true if RR type should be included */
+static int
+rrset_belongs_in_reply(ldns_pkt_section s, uint16_t rrtype, uint16_t qtype,
+ int dnssec)
+{
+ if(dnssec)
+ return 1;
+ /* skip non DNSSEC types, except if directly queried for */
+ if(s == LDNS_SECTION_ANSWER) {
+ if(qtype == LDNS_RR_TYPE_ANY || qtype == rrtype)
+ return 1;
+ }
+ /* check DNSSEC-ness */
+ switch(rrtype) {
+ case LDNS_RR_TYPE_SIG:
+ case LDNS_RR_TYPE_KEY:
+ case LDNS_RR_TYPE_NXT:
+ case LDNS_RR_TYPE_DS:
+ case LDNS_RR_TYPE_RRSIG:
+ case LDNS_RR_TYPE_NSEC:
+ case LDNS_RR_TYPE_DNSKEY:
+ /* FIXME: include NSEC3 here. */
+ return 0;
+ }
+ return 1;
+}
+
/** store rrset in buffer in wireformat, return RETVAL_* */
static int
packed_rrset_encode(struct ub_packed_rrset_key* key, ldns_buffer* pkt,
uint16_t* num_rrs, uint32_t timenow, region_type* region,
- int do_data, int do_sig, struct compress_tree_node** tree)
+ int do_data, int do_sig, struct compress_tree_node** tree,
+ ldns_pkt_section s, uint16_t qtype, int dnssec)
{
size_t i, owner_pos;
int r, owner_labs;
uint16_t owner_ptr = 0;
struct packed_rrset_data* data = (struct packed_rrset_data*)
key->entry.data;
+
+ /* does this RR type belong in the answer? */
+ if(!rrset_belongs_in_reply(s, ntohs(key->rk.type), qtype, dnssec))
+ return RETVAL_OK;
owner_labs = dname_count_labels(key->rk.dname);
owner_pos = ldns_buffer_position(pkt);
}
}
/* insert rrsigs */
- if(do_sig) {
+ if(do_sig && dnssec) {
size_t total = data->count+data->rrsig_count;
for(i=data->count; i<total; i++) {
if(owner_ptr && owner_labs != 1) {
/* change rrnum only after we are sure it fits */
if(do_data)
*num_rrs += data->count;
- if(do_sig)
+ if(do_sig && dnssec)
*num_rrs += data->rrsig_count;
return RETVAL_OK;
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,
- region_type* region, int addit, struct compress_tree_node** tree)
+ region_type* region, struct compress_tree_node** tree,
+ ldns_pkt_section s, uint16_t qtype, int dnssec)
{
int r;
size_t i, setstart;
*num_rrs = 0;
- if(!addit) {
+ if(s != LDNS_SECTION_ADDITIONAL) {
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))
+ pkt, num_rrs, timenow, region, 1, 1, tree,
+ s, qtype, dnssec))
!= RETVAL_OK) {
/* Bad, but if due to size must set TC bit */
/* trim off the rrset neatly. */
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))
+ pkt, num_rrs, timenow, region, 1, 0, tree,
+ s, qtype, dnssec))
!= RETVAL_OK) {
ldns_buffer_set_position(pkt, setstart);
return r;
}
}
- for(i=0; i<num_rrsets; i++) {
+ 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))
+ pkt, num_rrs, timenow, region, 0, 1, tree,
+ s, qtype, dnssec))
!= RETVAL_OK) {
ldns_buffer_set_position(pkt, setstart);
return r;
}
- }
+ }
}
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)
+ region_type* region, uint16_t udpsize, int dnssec)
{
uint16_t ancount=0, nscount=0, arcount=0;
struct compress_tree_node* tree = 0;
/* insert answer section */
if((r=insert_section(rep, rep->an_numrrsets, &ancount, buffer,
- 0, timenow, region, 0, &tree)) != RETVAL_OK) {
+ 0, timenow, region, &tree, LDNS_SECTION_ANSWER, qinfo->qtype,
+ dnssec)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* create truncated message */
ldns_buffer_write_u16_at(buffer, 6, ancount);
/* insert auth section */
if((r=insert_section(rep, rep->ns_numrrsets, &nscount, buffer,
- rep->an_numrrsets, timenow, region, 0, &tree)) != RETVAL_OK) {
+ rep->an_numrrsets, timenow, region, &tree,
+ LDNS_SECTION_AUTHORITY, qinfo->qtype, dnssec)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* create truncated message */
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,
- 1, &tree)) != RETVAL_OK) {
+ &tree, LDNS_SECTION_ADDITIONAL, qinfo->qtype,
+ dnssec)) != RETVAL_OK) {
if(r == RETVAL_TRUNC) {
/* no need to set TC bit, this is the additional */
ldns_buffer_write_u16_at(buffer, 10, arcount);
reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
uint16_t id, uint16_t qflags, ldns_buffer* pkt, uint32_t timenow,
int cached, struct region* region, uint16_t udpsize,
- struct edns_data* edns)
+ struct edns_data* edns, int dnssec)
{
uint16_t flags;
return 0; /* packet too small to contain edns... */
udpsize -= calc_edns_field_size(edns);
if(!reply_info_encode(qinf, rep, id, flags, pkt, timenow, region,
- udpsize)) {
+ udpsize, dnssec)) {
log_err("reply encode: out of memory");
return 0;
}
* @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
* @param edns: EDNS data included in the answer, NULL for none.
* or if edns_present = 0, it is not included.
+ * @param dnssec: if 0 DNSSEC records are omitted from the answer.
* @return: 0 on error (server failure).
*/
int reply_info_answer_encode(struct query_info* qinf, struct reply_info* rep,
uint16_t id, uint16_t qflags, ldns_buffer* dest, uint32_t timenow,
int cached, struct region* region, uint16_t udpsize,
- struct edns_data* edns);
+ struct edns_data* edns, int dnssec);
/**
* Regenerate the wireformat from the stored msg reply.
* @param timenow: time now, to adjust ttl values.
* @param region: to store temporary data in.
* @param udpsize: size of the answer, 512, from EDNS, or 64k for TCP.
+ * @param dnssec: if 0 DNSSEC records are omitted from the answer.
* @return: nonzero is success, or
* 0 on error: malloc failure (no log_err has been done).
*/
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 region* region, uint16_t udpsize);
+ struct region* region, uint16_t udpsize, int dnssec);
/**
* Encode query packet. Assumes the buffer is large enough.
return LDNS_RCODE_SERVFAIL;
rr->ttl_data = ldns_buffer_current(pkt);
rr->next = 0;
- if(type == LDNS_RR_TYPE_RRSIG) {
+ if(type == LDNS_RR_TYPE_RRSIG && rrset->type != LDNS_RR_TYPE_RRSIG) {
if(rrset->rrsig_last)
rrset->rrsig_last->next = rr;
else rrset->rrsig_first = rr;
ldns_buffer* buf = ldns_buffer_new(65535);
struct region* region = region_create(malloc, free);
if(!reply_info_encode(qinfo, rep, 0, rep->flags, buf, 0,
- region, 65535)) {
+ region, 65535, 1)) {
log_info("%s: log_dns_msg: out of memory", str);
} else {
ldns_status s;
rep.c = (struct comm_point*)arg;
log_assert(rep.c->type == comm_udp);
- verbose(VERB_ALGO, "callback udp");
if(!(event&EV_READ))
return;
log_assert(rep.c && rep.c->buffer && rep.c->fd == fd);