e.qsent = NULL;
if(error != 0) {
- mesh_report_reply(worker->env.mesh, &e, 0, reply_info);
+ mesh_report_reply(worker->env.mesh, &e, reply_info, error);
worker_mem_report(worker, NULL);
return 0;
}
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
/* error becomes timeout for the module as if this reply
* never arrived. */
- mesh_report_reply(worker->env.mesh, &e, 0, reply_info);
+ mesh_report_reply(worker->env.mesh, &e, reply_info,
+ NETEVENT_TIMEOUT);
worker_mem_report(worker, NULL);
return 0;
}
- mesh_report_reply(worker->env.mesh, &e, 1, reply_info);
+ mesh_report_reply(worker->env.mesh, &e, reply_info, NETEVENT_NOERROR);
worker_mem_report(worker, NULL);
return 0;
}
verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate);
if(error != 0) {
- mesh_report_reply(worker->env.mesh, e, 0, reply_info);
+ mesh_report_reply(worker->env.mesh, e, reply_info, error);
worker_mem_report(worker, sq);
return 0;
}
/* error becomes timeout for the module as if this reply
* never arrived. */
verbose(VERB_ALGO, "worker: bad reply handled as timeout");
- mesh_report_reply(worker->env.mesh, e, 0, reply_info);
+ mesh_report_reply(worker->env.mesh, e, reply_info,
+ NETEVENT_TIMEOUT);
worker_mem_report(worker, sq);
return 0;
}
- mesh_report_reply(worker->env.mesh, e, 1, reply_info);
+ mesh_report_reply(worker->env.mesh, e, reply_info, NETEVENT_NOERROR);
worker_mem_report(worker, sq);
return 0;
}
6 October 2008: Wouter
- jostle-timeout option, so you can config for slow links.
+ - 0x20 fallback code. Tries 3xnumber of nameserver addresses
+ queries that must all be the same. Sent to random nameservers.
2 October 2008: Wouter
- fixup unlink of pidfile.
return 1;
return 0;
}
+
+/**
+ * check equality of two rrsets
+ * @param k1: rrset
+ * @param k2: rrset
+ * @return true if equal
+ */
+static int
+rrset_equal(struct ub_packed_rrset_key* k1, struct ub_packed_rrset_key* k2)
+{
+ struct packed_rrset_data* d1 = (struct packed_rrset_data*)
+ k1->entry.data;
+ struct packed_rrset_data* d2 = (struct packed_rrset_data*)
+ k2->entry.data;
+ size_t i, t;
+ if(k1->rk.dname_len != k2->rk.dname_len ||
+ k1->rk.flags != k2->rk.flags ||
+ k1->rk.type != k2->rk.type ||
+ k1->rk.rrset_class != k2->rk.rrset_class ||
+ query_dname_compare(k1->rk.dname, k2->rk.dname) != 0)
+ return 0;
+ if(d1->ttl != d2->ttl ||
+ d1->count != d2->count ||
+ d1->rrsig_count != d2->rrsig_count ||
+ d1->trust != d2->trust ||
+ d1->security != d2->security)
+ return 0;
+ t = d1->count + d1->rrsig_count;
+ for(i=0; i<t; i++) {
+ if(d1->rr_len[i] != d2->rr_len[i] ||
+ d1->rr_ttl[i] != d2->rr_ttl[i] ||
+ memcmp(d1->rr_data[i], d2->rr_data[i],
+ d1->rr_len[i]) != 0)
+ return 0;
+ }
+ return 1;
+}
+
+int
+reply_equal(struct reply_info* p, struct reply_info* q)
+{
+ size_t i;
+ if(p->flags != q->flags ||
+ p->qdcount != q->qdcount ||
+ p->ttl != q->ttl ||
+ p->security != q->security ||
+ p->an_numrrsets != q->an_numrrsets ||
+ p->ns_numrrsets != q->ns_numrrsets ||
+ p->ar_numrrsets != q->ar_numrrsets ||
+ p->rrset_count != q->rrset_count)
+ return 0;
+ for(i=0; i<p->rrset_count; i++) {
+ if(!rrset_equal(p->rrsets[i], q->rrsets[i]))
+ return 0;
+ }
+ return 1;
+}
int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
enum response_type type, uint16_t dclass);
+/**
+ * Check if two replies are equal
+ * For fallback procedures
+ * @param p: reply one. The reply has rrset data pointers in region.
+ * Does not check rrset-IDs
+ * @param q: reply two
+ * @return if one and two are equal.
+ */
+int reply_equal(struct reply_info* p, struct reply_info* q);
+
#endif /* ITERATOR_ITER_UTILS_H */
tf_policy = ie->target_fetch_policy[iq->depth];
}
+ /* if in 0x20 fallback get as many targets as possible */
+ if(iq->caps_fallback) {
+ int extra = 0;
+ size_t naddr, nres, navail;
+ if(!query_for_targets(qstate, iq, ie, id, -1, &extra)) {
+ return error_response(qstate, id, LDNS_RCODE_SERVFAIL);
+ }
+ iq->num_target_queries += extra;
+ if(iq->num_target_queries > 0) {
+ /* wait to get all targets, we want to try em */
+ verbose(VERB_ALGO, "wait for all targets for fallback");
+ return 0;
+ }
+ /* did we do enough fallback queries already? */
+ delegpt_count_addr(iq->dp, &naddr, &nres, &navail);
+ /* the current caps_server is the number of fallbacks sent.
+ * the original query is one that matched too, so we have
+ * caps_server+1 number of matching queries now */
+ if(iq->caps_server+1 >= naddr*3) {
+ /* we're done, process the response */
+ verbose(VERB_ALGO, "0x20 fallback had %d responses "
+ "match for %d wanted, done.",
+ (int)iq->caps_server+1, (int)naddr*3);
+ iq->caps_fallback = 0;
+ iq->state = QUERY_RESP_STATE;
+ return 1;
+ }
+ verbose(VERB_ALGO, "0x20 fallback number %d",
+ (int)iq->caps_server);
+
/* if there is a policy to fetch missing targets
* opportunistically, do it. we rely on the fact that once a
* query (or queries) for a missing name have been issued,
* they will not be show up again. */
- if(tf_policy != 0) {
+ } else if(tf_policy != 0) {
int extra = 0;
verbose(VERB_ALGO, "attempt to get extra %d targets",
tf_policy);
if(event == module_event_noreply || event == module_event_error) {
goto handle_it;
}
- if(event != module_event_reply || !qstate->reply) {
+ if( (event != module_event_reply && event != module_event_capsfail)
+ || !qstate->reply) {
log_err("Bad event combined with response");
outbound_list_remove(&iq->outlist, outbound);
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
if(verbosity >= VERB_ALGO)
log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo,
iq->response->rep);
+
+ if(event == module_event_capsfail) {
+ if(!iq->caps_fallback) {
+ /* start fallback */
+ iq->caps_fallback = 1;
+ iq->caps_server = 0;
+ iq->caps_reply = iq->response->rep;
+ iq->state = QUERYTARGETS_STATE;
+ iq->num_current_queries--;
+ verbose(VERB_DETAIL, "Capsforid: starting fallback");
+ goto handle_it;
+ } else {
+ /* check if reply is the same, otherwise, fail */
+ if(!reply_equal(iq->response->rep, iq->caps_reply)) {
+ verbose(VERB_DETAIL, "Capsforid fallback: "
+ "getting different replies, failed");
+ outbound_list_remove(&iq->outlist, outbound);
+ (void)error_response(qstate, id,
+ LDNS_RCODE_SERVFAIL);
+ return;
+ }
+ /* continue the fallback procedure at next server */
+ iq->caps_server++;
+ iq->state = QUERYTARGETS_STATE;
+ iq->num_current_queries--;
+ verbose(VERB_DETAIL, "Capsforid: reply is equal. "
+ "go to next fallback");
+ goto handle_it;
+ }
+ }
+ iq->caps_fallback = 0; /* if we were in fallback, 0x20 is OK now */
handle_it:
outbound_list_remove(&iq->outlist, outbound);
*/
struct delegpt* dp;
+ /** state for 0x20 fallback when capsfail happens, 0 not a fallback */
+ int caps_fallback;
+ /** state for capsfail: current server number to try */
+ size_t caps_server;
+ /** state for capsfail: stored query for comparisons */
+ struct reply_info* caps_reply;
+
/** Current delegation message - returned for non-RD queries */
struct dns_msg* deleg_msg;
e.qsent = NULL;
if(error != 0) {
- mesh_report_reply(lw->env->mesh, &e, 0, reply_info);
+ mesh_report_reply(lw->env->mesh, &e, reply_info, error);
return 0;
}
/* sanity check. */
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
/* error becomes timeout for the module as if this reply
* never arrived. */
- mesh_report_reply(lw->env->mesh, &e, 0, reply_info);
+ mesh_report_reply(lw->env->mesh, &e, reply_info,
+ NETEVENT_TIMEOUT);
return 0;
}
- mesh_report_reply(lw->env->mesh, &e, 1, reply_info);
+ mesh_report_reply(lw->env->mesh, &e, reply_info, NETEVENT_NOERROR);
return 0;
}
struct libworker* lw = (struct libworker*)e->qstate->env->worker;
if(error != 0) {
- mesh_report_reply(lw->env->mesh, e, 0, reply_info);
+ mesh_report_reply(lw->env->mesh, e, reply_info, error);
return 0;
}
/* sanity check. */
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
/* error becomes timeout for the module as if this reply
* never arrived. */
- mesh_report_reply(lw->env->mesh, e, 0, reply_info);
+ mesh_report_reply(lw->env->mesh, e, reply_info,
+ NETEVENT_TIMEOUT);
return 0;
}
- mesh_report_reply(lw->env->mesh, e, 1, reply_info);
+ mesh_report_reply(lw->env->mesh, e, reply_info, NETEVENT_NOERROR);
return 0;
}
}
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
- int is_ok, struct comm_reply* reply)
+ struct comm_reply* reply, int what)
{
+ enum module_ev event = module_event_reply;
e->qstate->reply = reply;
- mesh_run(mesh, e->qstate->mesh_info,
- is_ok?module_event_reply:module_event_noreply, e);
+ if(what != NETEVENT_NOERROR) {
+ event = module_event_noreply;
+ if(what == NETEVENT_CAPSFAIL)
+ event = module_event_capsfail;
+ }
+ mesh_run(mesh, e->qstate->mesh_info, event, e);
}
struct mesh_state*
*
* @param mesh: the query mesh.
* @param e: outbound entry, with query state to run and reply pointer.
- * @param is_ok: if true, reply is OK, otherwise a timeout happened.
* @param reply: the comm point reply info.
+ * @param what: NETEVENT_* error code (if not 0, what is wrong, TIMEOUT).
*/
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
- int is_ok, struct comm_reply* reply);
+ struct comm_reply* reply, int what);
/* ------------------- Functions for module environment --------------- */
== LDNS_RCODE_NOERROR ||
LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
== LDNS_RCODE_NXDOMAIN)) {
- verbose(VERB_OPS, "no qname in reply to check 0x20ID");
- log_addr(VERB_OPS, "from server",
+ verbose(VERB_DETAIL, "no qname in reply to check 0x20ID");
+ log_addr(VERB_DETAIL, "from server",
&sq->addr, sq->addrlen);
- log_buf(VERB_OPS, "for packet", c->buffer);
+ log_buf(VERB_DETAIL, "for packet", c->buffer);
error = NETEVENT_CLOSED;
c = NULL;
} else if(ldns_buffer_read_u16_at(c->buffer, 4) > 0 &&
!serviced_check_qname(c->buffer, sq->qbuf,
sq->qbuflen)) {
- verbose(VERB_OPS, "wrong 0x20-ID in reply qname, "
- "answer dropped");
- log_addr(VERB_OPS, "from server",
+ verbose(VERB_DETAIL, "wrong 0x20-ID in reply qname");
+ log_addr(VERB_DETAIL, "from server",
&sq->addr, sq->addrlen);
- log_buf(VERB_OPS, "for packet", c->buffer);
- error = NETEVENT_CLOSED;
- c = NULL;
+ log_buf(VERB_DETAIL, "for packet", c->buffer);
+ error = NETEVENT_CAPSFAIL;
+ /* and cleanup too */
+ pkt_dname_tolower(c->buffer,
+ ldns_buffer_at(c->buffer, 12));
} else {
verbose(VERB_ALGO, "good 0x20-ID in reply qname");
/* cleanup caps, prettier cache contents. */
case module_event_pass: return "module_event_pass";
case module_event_reply: return "module_event_reply";
case module_event_noreply: return "module_event_noreply";
+ case module_event_capsfail: return "module_event_capsfail";
case module_event_moddone: return "module_event_moddone";
case module_event_error: return "module_event_error";
}
module_event_reply,
/** no reply, timeout or other error */
module_event_noreply,
+ /** reply is there, but capitalisation check failed */
+ module_event_capsfail,
/** next module is done, and its reply is awaiting you */
module_event_moddone,
/** error */
#define NETEVENT_CLOSED -1
/** to pass timeout happened to callback function */
#define NETEVENT_TIMEOUT -2
+/** to pass fallback from capsforID to callback function; 0x20 failed */
+#define NETEVENT_CAPSFAIL -3
/**
* A communication point dispatcher. Thread specific.