msg->rep, LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
worker->env.now_tv))
return 0;
- EDNS_OPT_APPEND_EDE(edns, worker->scratchpad,
- LDNS_EDE_DNSSEC_BOGUS, "");
++ EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out,
++ worker->scratchpad, LDNS_EDE_DNSSEC_BOGUS, "");
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
&msg->qinfo, id, flags, edns);
if(worker->stats.extended) {
secure = 1;
break;
case sec_status_indeterminate:
- EDNS_OPT_APPEND_EDE(edns, worker->scratchpad,
- LDNS_EDE_DNSSEC_INDETERMINATE, "");
++ EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out,
++ worker->scratchpad, LDNS_EDE_DNSSEC_INDETERMINATE, "");
++
case sec_status_insecure:
default:
/* not secure */
LDNS_RCODE_SERVFAIL, edns, repinfo, worker->scratchpad,
worker->env.now_tv))
goto bail_out;
- EDNS_OPT_APPEND_EDE(edns, worker->scratchpad,
- LDNS_EDE_DNSSEC_BOGUS, "");
++ EDNS_OPT_LIST_APPEND_EDE(&edns->opt_list_out,
++ worker->scratchpad, LDNS_EDE_DNSSEC_BOGUS, "");
error_encode(repinfo->c->buffer, LDNS_RCODE_SERVFAIL,
qinfo, id, flags, edns);
rrset_array_unlock_touch(worker->env.rrset_cache,
* ACLs allow the snooping. */
if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) &&
acl != acl_allow_snoop ) {
- EDNS_OPT_APPEND_EDE(&edns, worker->scratchpad,
- LDNS_EDE_NOT_AUTHORITATIVE, "");
+ edns.opt_list = NULL;
++ EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
++ worker->scratchpad, LDNS_EDE_NOT_AUTHORITATIVE, "");
error_encode(c->buffer, LDNS_RCODE_REFUSED, &qinfo,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
- sldns_buffer_read_u16_at(c->buffer, 2), NULL);
+ sldns_buffer_read_u16_at(c->buffer, 2), &edns);
regional_free_all(worker->scratchpad);
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
&repinfo->addr, repinfo->addrlen);
< *worker->env.now)
leeway = 0;
lock_rw_unlock(&e->lock);
- // EDNS_OPT_APPEND_EDE(&edns, worker->scratchpad,
+
+ // // stale answer?
+ // if (worker->env.cfg->serve_expired &&
+ // *worker->env.now >= ((struct reply_info*)e->data)->ttl) {
+ // // EDE Error Code 3 - Stale Answer
++ // EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out, worker->scratchpad,
+ // LDNS_EDE_STALE_ANSWER, "");
+ // }
+
+ // add EDNS struct?
reply_and_prefetch(worker, lookup_qinfo,
sldns_buffer_read_u16_at(c->buffer, 2),
repinfo, leeway,
return 1;
}
- edns_opt_append_ede(edns, temp, ede_code, ede_txt);
+/** encode answer consisting of 1 rrset (with EDE code) */
+static int
+local_encode_ede(struct query_info* qinfo, struct module_env* env,
+ struct edns_data* edns, struct comm_reply* repinfo, sldns_buffer* buf,
+ struct regional* temp, struct ub_packed_rrset_key* rrset, int ansec,
+ int rcode, sldns_ede_code ede_code, const char* ede_txt)
+{
+ struct reply_info rep;
+ uint16_t udpsize;
+ /* make answer with time=0 for fixed TTL values */
+ memset(&rep, 0, sizeof(rep));
+ rep.flags = (uint16_t)((BIT_QR | BIT_AA | BIT_RA) | rcode);
+ rep.qdcount = 1;
+ if(ansec)
+ rep.an_numrrsets = 1;
+ else rep.ns_numrrsets = 1;
+ rep.rrset_count = 1;
+ rep.rrsets = &rrset;
+ udpsize = edns->udp_size;
+ edns->edns_version = EDNS_ADVERTISED_VERSION;
+ edns->udp_size = EDNS_ADVERTISED_SIZE;
+ edns->ext_rcode = 0;
+ edns->bits &= EDNS_DO;
+ if(!inplace_cb_reply_local_call(env, qinfo, NULL, &rep, rcode, edns,
+ repinfo, temp, env->now_tv)) {
+ error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
+ *(uint16_t*)sldns_buffer_begin(buf),
+ sldns_buffer_read_u16_at(buf, 2), edns);
+ } else {
++ edns_opt_list_append_ede(&edns->opt_list_out, temp, ede_code, ede_txt);
+
+ if(!reply_info_answer_encode(qinfo, &rep,
+ *(uint16_t*)sldns_buffer_begin(buf), sldns_buffer_read_u16_at(buf, 2),
+ buf, 0, 0, temp, udpsize, edns, (int)(edns->bits&EDNS_DO), 0)) {
+ error_encode(buf, (LDNS_RCODE_SERVFAIL|BIT_AA), qinfo,
+ *(uint16_t*)sldns_buffer_begin(buf),
+ sldns_buffer_read_u16_at(buf, 2), edns);
+ }
+ }
+ return 1;
+}
+
/** encode local error answer */
static void
local_error_encode(struct query_info* qinfo, struct module_env* env,
if(!inplace_cb_reply_local_call(env, qinfo, NULL, NULL,
rcode, edns, repinfo, temp, env->now_tv))
- edns->opt_list = NULL;
+ edns->opt_list_inplace_cb_out = NULL;
+ if(ede_code >= 0 && env->cfg->local_data_do_ede)
- edns_opt_append_ede(edns, temp, ede_code, ede_txt);
++ edns_opt_list_append_ede(&edns->opt_list_out, temp, ede_code, ede_txt);
error_encode(buf, r, qinfo, *(uint16_t*)sldns_buffer_begin(buf),
sldns_buffer_read_u16_at(buf, 2), edns);
}
*/
int rcode = (ld || lz_type == local_zone_redirect ||
lz_type == local_zone_inform_redirect ||
- lz_type == local_zone_always_nodata)?
+ lz_type == local_zone_always_nodata ||
+ lz_type == local_zone_truncate)?
LDNS_RCODE_NOERROR:LDNS_RCODE_NXDOMAIN;
- if(z->soa && z->soa_negative)
+ rcode = (lz_type == local_zone_truncate ? (rcode|BIT_TC) : rcode);
+ if(z != NULL && z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa_negative, 0, rcode);
- local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
- (rcode|BIT_AA));
+ local_error_encode(qinfo, env, edns, repinfo, buf, temp,
+ rcode, (rcode|BIT_AA), LDNS_EDE_BLOCKED, "");
return 1;
} else if(lz_type == local_zone_typetransparent
|| lz_type == local_zone_always_transparent) {
* does not, then we should make this noerror/nodata */
if(ld && ld->rrsets) {
int rcode = LDNS_RCODE_NOERROR;
- if(z->soa && z->soa_negative)
+ if(z != NULL && z->soa && z->soa_negative)
return local_encode(qinfo, env, edns, repinfo, buf, temp,
z->soa_negative, 0, rcode);
+ /* NODATA: No EDE needed */
local_error_encode(qinfo, env, edns, repinfo, buf, temp, rcode,
- (rcode|BIT_AA));
+ (rcode|BIT_AA), -1, NULL);
return 1;
}
} else {
if(!inplace_cb_reply_call(m->s.env, &m->s.qinfo, &m->s, rep, rcode,
&r->edns, &r->query_reply, m->s.region, &r->start_time))
- r->edns.opt_list = NULL;
+ r->edns.opt_list_inplace_cb_out = NULL;
}
- edns_opt_append_ede(&r->edns, m->s.region,
+ /* Send along EDE BOGUS EDNS0 option when answer is bogus */
+ if(rcode == LDNS_RCODE_SERVFAIL &&
+ m->s.env->need_to_validate && (!(r->qflags&BIT_CD) ||
+ m->s.env->cfg->ignore_cd) && rep &&
+ (rep->security <= sec_status_bogus ||
+ rep->security == sec_status_secure_sentinel_fail)) {
+
+ char *reason = m->s.env->cfg->val_log_level >= 2
+ ? errinf_to_str_bogus(&m->s) : NULL;
+ sldns_ede_code reason_bogus = rep->reason_bogus != LDNS_EDE_DNSSEC_BOGUS
+ ? rep->reason_bogus : errinf_to_reason_bogus(&m->s);
+
++ edns_opt_list_append_ede(&r->edns.opt_list_out, m->s.region,
+ reason_bogus, reason);
+ free(reason);
+ }
error_encode(r_buffer, rcode, &m->s.qinfo, r->qid,
r->qflags, &r->edns);
m->reply_list = NULL;
{
if(!inplace_cb_reply_servfail_call(m->s.env, &m->s.qinfo, &m->s,
rep, LDNS_RCODE_SERVFAIL, &r->edns, &r->query_reply, m->s.region, &r->start_time))
- r->edns.opt_list = NULL;
+ r->edns.opt_list_inplace_cb_out = NULL;
+ // @TODO EDE?
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
&m->s.qinfo, r->qid, r->qflags, &r->edns);
}
* @return: 0 on success. or an RCODE on an error.
* RCODE formerr if OPT in wrong section, and so on.
*/
- int parse_extract_edns(struct msg_parse* msg, struct edns_data* edns,
- struct regional* region);
+ int parse_extract_edns_from_response_msg(struct msg_parse* msg,
+ struct edns_data* edns, struct regional* region);
+/**
+ * Skip RRs from packet
+ * @param pkt:the packet. position at start must be right after the query
+ * section. At end, right after EDNS data or no movement if failed.
+ * @param num: Limit of the number of records we want to parse.
+ * @return: 0 on success, 1 on failure*/
+int skip_pkt_rrs(struct sldns_buffer* pkt, int num);
+
/**
* If EDNS data follows a query section, extract it and initialize edns struct.
* @param pkt: the packet. position at start must be right after the query
return rep;
}
- int edns_opt_append(struct edns_data* edns, struct regional* region,
- uint16_t code, size_t len, uint8_t* data)
- {
- struct edns_option** prevp;
- struct edns_option* opt;
-
- /* allocate new element */
- opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
- if(!opt)
- return 0;
- opt->next = NULL;
- opt->opt_code = code;
- opt->opt_len = len;
- opt->opt_data = NULL;
- if(len > 0) {
- opt->opt_data = regional_alloc_init(region, data, len);
- if(!opt->opt_data)
- return 0;
- }
-
- /* append at end of list */
- prevp = &edns->opt_list;
- while(*prevp != NULL)
- prevp = &((*prevp)->next);
- *prevp = opt;
- return 1;
- }
-
- int edns_opt_append_ede(struct edns_data* edns, struct regional* region,
++int edns_opt_list_append_ede(struct edns_option** list, struct regional* region,
+ sldns_ede_code code, const char *txt)
+{
+ struct edns_option** prevp;
+ struct edns_option* opt;
+ size_t txt_len = txt ? strlen(txt) : 0;
+
+ /* allocate new element */
+ opt = (struct edns_option*)regional_alloc(region, sizeof(*opt));
+ if(!opt)
+ return 0;
+ opt->next = NULL;
+ opt->opt_code = LDNS_EDNS_EDE;
+ opt->opt_len = txt_len + sizeof(uint16_t);
+ opt->opt_data = regional_alloc(region, txt_len + sizeof(uint16_t));
+ if(!opt->opt_data)
+ return 0;
+ sldns_write_uint16(opt->opt_data, (uint16_t)code);
+ if (txt_len)
+ memmove(opt->opt_data + 2, txt, txt_len);
+
+ /* append at end of list */
- prevp = &edns->opt_list;
++ prevp = list;
+ while(*prevp != NULL)
+ prevp = &((*prevp)->next);
+ *prevp = opt;
+ return 1;
+}
+
int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
uint8_t* data, struct regional* region)
{
* @param code: the edns option's code.
* @param len: the edns option's length.
* @param data: the edns option's data.
+ * @param region: region to allocate the new edns option.
* @return false on failure.
*/
- int edns_opt_append(struct edns_data* edns, struct regional* region,
- uint16_t code, size_t len, uint8_t* data);
+ int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
+ uint8_t* data, struct regional* region);
- * @param EDNS: the edns data structure to append the edns option to.
+/**
+ * Append edns EDE option to edns options list
- #define EDNS_OPT_APPEND_EDE(EDNS, REGION, CODE, TXT) \
++ * @param LIST: the edns option list to append the edns option to.
+ * @param REGION: region to allocate the new edns option.
+ * @param CODE: the EDE code.
+ * @param TXT: Additional text for the option
+ */
- edns_opt_append((EDNS), (REGION), LDNS_EDNS_EDE, \
++#define EDNS_OPT_LIST_APPEND_EDE(LIST, REGION, CODE, TXT) \
+ do { \
+ struct { \
+ uint16_t code; \
+ char text[sizeof(TXT) - 1]; \
+ } ede = { htons(CODE), TXT }; \
- * @param edns: the edns data structure to append the edns option to.
++ edns_opt_list_append((LIST), (REGION), LDNS_EDNS_EDE, \
+ sizeof(uint16_t) + sizeof(TXT) - 1, \
+ (void *)&ede); \
+ } while(0)
+
+/**
+ * Append edns EDE option to edns options list
- int edns_opt_append_ede(struct edns_data* edns, struct regional* region,
++ * @param list: the edns option list to append the edns option to.
+ * @param region: region to allocate the new edns option.
+ * @param code: the EDE code.
+ * @param txt: Additional text for the option
+ * @return false on failure.
+ */
- /**
- * Append edns option to edns option list
- * @param list: the edns option list to append the edns option to.
- * @param code: the edns option's code.
- * @param len: the edns option's length.
- * @param data: the edns option's data.
- * @param region: region to allocate the new edns option.
- * @return false on failure.
- */
- int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
- uint8_t* data, struct regional* region);
-
++int edns_opt_append_ede(struct edns_option* list, struct regional* region,
+ sldns_ede_code code, const char *txt);
+
/**
* Remove any option found on the edns option list that matches the code.
* @param list: the list of edns options.