struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */
struct respip_client_info* cinfo = NULL, cinfo_tmp;
memset(&qinfo, 0, sizeof(qinfo));
- memset(&edns, 0, sizeof(edns));
- edns.udp_size = 512;
if((error != NETEVENT_NOERROR && error != NETEVENT_DONE)|| !repinfo) {
/* some bad tcp query DNS formats give these error calls */
memset(&reply_edns, 0, sizeof(reply_edns));
reply_edns.edns_present = 1;
reply_edns.udp_size = EDNS_ADVERTISED_SIZE;
- LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
error_encode(c->buffer, ret, &qinfo,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns);
regional_free_all(worker->scratchpad);
goto send_reply;
}
- if(edns.edns_present && edns.edns_version != 0) {
- edns.opt_list_in = NULL;
- edns.opt_list_out = NULL;
- edns.opt_list_inplace_cb_out = NULL;
- edns.padding_block_size = 0;
- edns.cookie_present = 0;
- edns.cookie_valid = 0;
- verbose(VERB_ALGO, "query with bad edns version.");
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
- error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo,
- *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
- sldns_buffer_read_u16_at(c->buffer, 2), &edns);
- regional_free_all(worker->scratchpad);
- goto send_reply;
- }
- if(edns.udp_size < NORMAL_UDP_SIZE &&
- worker->daemon->cfg->harden_short_bufsize) {
- verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
- (int)edns.udp_size);
- log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
- edns.udp_size = NORMAL_UDP_SIZE;
+ if(edns.edns_present) {
+ if(edns.edns_version != 0) {
+ edns.opt_list_in = NULL;
+ edns.opt_list_out = NULL;
+ edns.opt_list_inplace_cb_out = NULL;
+ verbose(VERB_ALGO, "query with bad edns version.");
+ log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo,
+ *(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
+ sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns);
+ regional_free_all(worker->scratchpad);
+ goto send_reply;
+ }
+ if(edns.udp_size < NORMAL_UDP_SIZE &&
+ worker->daemon->cfg->harden_short_bufsize) {
+ verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
+ (int)edns.udp_size);
+ log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
+ edns.udp_size = NORMAL_UDP_SIZE;
+ }
}
/* "if, else if" sequence below deals with downstream DNS Cookies */
if (acl != acl_allow_cookie)
else if (edns.cookie_present) {
/* Cookie present, but not valid: Cookie was bad! */
- error_encode(c->buffer,
+ extended_error_encode(c->buffer,
LDNS_EXT_RCODE_BADCOOKIE, &qinfo,
*(uint16_t*)(void *)
sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2),
- &edns);
+ 0, &edns);
regional_free_all(worker->scratchpad);
goto send_reply;
} else {
worker->scratchpad, LDNS_EDE_OTHER,
"DNS Cookie needed for UDP replies");
error_encode(c->buffer,
- LDNS_RCODE_REFUSED, &qinfo,
+ (LDNS_RCODE_REFUSED|BIT_TC), &qinfo,
*(uint16_t*)(void *)
sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2),
&edns);
- LDNS_TC_SET(sldns_buffer_begin(c->buffer));
regional_free_all(worker->scratchpad);
goto send_reply;
}
sldns_buffer_flip(pkt);
}
+
void
-error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
- uint16_t qid, uint16_t qflags, struct edns_data* edns)
+extended_error_encode(sldns_buffer* buf, uint16_t rcode, struct query_info* qinfo,
+ uint16_t qid, uint16_t qflags, uint16_t xflags, 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 & 0xF)); /* QR and retcode*/
+ flags = (uint16_t)(BIT_QR | BIT_RA | (rcode & 0xF)); /* QR and retcode*/
+ flags |= xflags;
flags |= (qflags & (BIT_RD|BIT_CD)); /* copy RD and CD bit */
sldns_buffer_write_u16(buf, flags);
if(qinfo) flags = 1;
sldns_buffer_flip(buf);
if(edns) {
struct edns_data es = *edns;
- size_t edns_field_size = calc_edns_field_size(&es);
es.edns_version = EDNS_ADVERTISED_VERSION;
es.udp_size = EDNS_ADVERTISED_SIZE;
- es.ext_rcode = r >= 0x10 ? 1 : 0;
+ es.ext_rcode = (uint8_t)(rcode >> 4);
es.bits &= EDNS_DO;
- if(sldns_buffer_limit(buf) + edns_field_size > edns->udp_size)
+ if(sldns_buffer_limit(buf) + calc_edns_field_size(&es) >
+ edns->udp_size)
return;
attach_edns_record(buf, &es);
}
}
+
+void
+error_encode(sldns_buffer* buf, int r, struct query_info* qinfo,
+ uint16_t qid, uint16_t qflags, struct edns_data* edns)
+{
+ extended_error_encode(buf, (r & 0x000F), qinfo, qid, qflags
+ , (r & 0xFFF0), edns);
+}
+
* Encode an error. With QR and RA set.
*
* @param pkt: where to store the packet.
- * @param r: RCODE value to encode.
+ * @param r: RCODE value to encode (may contain extra flags).
* @param qinfo: if not NULL, the query is included.
* @param qid: query ID to set in packet. network order.
* @param qflags: original query flags (to copy RD and CD bits). host order.
void error_encode(struct sldns_buffer* pkt, int r, struct query_info* qinfo,
uint16_t qid, uint16_t qflags, struct edns_data* edns);
+/**
+ * Encode an extended error. With QR and RA set.
+ *
+ * @param pkt: where to store the packet.
+ * @param rcode: Extended RCODE value to encode.
+ * @param qinfo: if not NULL, the query is included.
+ * @param qid: query ID to set in packet. network order.
+ * @param qflags: original query flags (to copy RD and CD bits). host order.
+ * @param xflags: extra flags to set (such as for example BIT_AA and/or BIT_TC)
+ * @param edns: if not NULL, this is the query edns info,
+ * and an edns reply is attached. Only attached if EDNS record fits reply.
+ * Without edns extended errors (i.e. > 15 )will not be conveyed.
+ */
+void extended_error_encode(struct sldns_buffer* pkt, uint16_t rcode,
+ struct query_info* qinfo, uint16_t qid, uint16_t qflags,
+ uint16_t xflags, struct edns_data* edns);
+
#endif /* UTIL_DATA_MSGENCODE_H */