0x20 fallback code.

git-svn-id: file:///svn/unbound/trunk@1285 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2008-10-06 14:46:22 +00:00
parent 3ddabf26f3
commit 939fabd809
15 changed files with 181 additions and 28 deletions

View file

@ -211,7 +211,7 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
e.qsent = NULL; e.qsent = NULL;
if(error != 0) { 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); worker_mem_report(worker, NULL);
return 0; return 0;
} }
@ -222,11 +222,12 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
/* error becomes timeout for the module as if this reply /* error becomes timeout for the module as if this reply
* never arrived. */ * 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); worker_mem_report(worker, NULL);
return 0; 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); worker_mem_report(worker, NULL);
return 0; return 0;
} }
@ -241,7 +242,7 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate); verbose(VERB_ALGO, "worker svcd callback for qstate %p", e->qstate);
if(error != 0) { 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); worker_mem_report(worker, sq);
return 0; return 0;
} }
@ -253,11 +254,12 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
/* error becomes timeout for the module as if this reply /* error becomes timeout for the module as if this reply
* never arrived. */ * never arrived. */
verbose(VERB_ALGO, "worker: bad reply handled as timeout"); 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); worker_mem_report(worker, sq);
return 0; 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); worker_mem_report(worker, sq);
return 0; return 0;
} }

View file

@ -1,5 +1,7 @@
6 October 2008: Wouter 6 October 2008: Wouter
- jostle-timeout option, so you can config for slow links. - 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 2 October 2008: Wouter
- fixup unlink of pidfile. - fixup unlink of pidfile.

View file

@ -484,3 +484,60 @@ int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
return 1; return 1;
return 0; 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;
}

View file

@ -180,4 +180,14 @@ int iter_msg_has_dnssec(struct dns_msg* msg);
int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp, int iter_msg_from_zone(struct dns_msg* msg, struct delegpt* dp,
enum response_type type, uint16_t dclass); 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 */ #endif /* ITERATOR_ITER_UTILS_H */

View file

@ -1153,11 +1153,41 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
tf_policy = ie->target_fetch_policy[iq->depth]; 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 /* if there is a policy to fetch missing targets
* opportunistically, do it. we rely on the fact that once a * opportunistically, do it. we rely on the fact that once a
* query (or queries) for a missing name have been issued, * query (or queries) for a missing name have been issued,
* they will not be show up again. */ * they will not be show up again. */
if(tf_policy != 0) { } else if(tf_policy != 0) {
int extra = 0; int extra = 0;
verbose(VERB_ALGO, "attempt to get extra %d targets", verbose(VERB_ALGO, "attempt to get extra %d targets",
tf_policy); tf_policy);
@ -1760,7 +1790,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
if(event == module_event_noreply || event == module_event_error) { if(event == module_event_noreply || event == module_event_error) {
goto handle_it; 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"); log_err("Bad event combined with response");
outbound_list_remove(&iq->outlist, outbound); outbound_list_remove(&iq->outlist, outbound);
(void)error_response(qstate, id, LDNS_RCODE_SERVFAIL); (void)error_response(qstate, id, LDNS_RCODE_SERVFAIL);
@ -1804,6 +1835,37 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
if(verbosity >= VERB_ALGO) if(verbosity >= VERB_ALGO)
log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo, log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo,
iq->response->rep); 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: handle_it:
outbound_list_remove(&iq->outlist, outbound); outbound_list_remove(&iq->outlist, outbound);

View file

@ -218,6 +218,13 @@ struct iter_qstate {
*/ */
struct delegpt* dp; 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 */ /** Current delegation message - returned for non-RD queries */
struct dns_msg* deleg_msg; struct dns_msg* deleg_msg;

View file

@ -695,7 +695,7 @@ libworker_handle_reply(struct comm_point* c, void* arg, int error,
e.qsent = NULL; e.qsent = NULL;
if(error != 0) { 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; return 0;
} }
/* sanity check. */ /* sanity check. */
@ -705,10 +705,11 @@ libworker_handle_reply(struct comm_point* c, void* arg, int error,
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
/* error becomes timeout for the module as if this reply /* error becomes timeout for the module as if this reply
* never arrived. */ * 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; 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; return 0;
} }
@ -720,7 +721,7 @@ libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
struct libworker* lw = (struct libworker*)e->qstate->env->worker; struct libworker* lw = (struct libworker*)e->qstate->env->worker;
if(error != 0) { 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; return 0;
} }
/* sanity check. */ /* sanity check. */
@ -730,10 +731,11 @@ libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
|| LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) { || LDNS_QDCOUNT(ldns_buffer_begin(c->buffer)) > 1) {
/* error becomes timeout for the module as if this reply /* error becomes timeout for the module as if this reply
* never arrived. */ * 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; 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; return 0;
} }

View file

@ -363,11 +363,16 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
} }
void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e, 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; e->qstate->reply = reply;
mesh_run(mesh, e->qstate->mesh_info, if(what != NETEVENT_NOERROR) {
is_ok?module_event_reply:module_event_noreply, e); event = module_event_noreply;
if(what == NETEVENT_CAPSFAIL)
event = module_event_capsfail;
}
mesh_run(mesh, e->qstate->mesh_info, event, e);
} }
struct mesh_state* struct mesh_state*

View file

@ -289,11 +289,11 @@ int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
* *
* @param mesh: the query mesh. * @param mesh: the query mesh.
* @param e: outbound entry, with query state to run and reply pointer. * @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 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, 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 --------------- */ /* ------------------- Functions for module environment --------------- */

View file

@ -1284,22 +1284,23 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
== LDNS_RCODE_NOERROR || == LDNS_RCODE_NOERROR ||
LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
== LDNS_RCODE_NXDOMAIN)) { == LDNS_RCODE_NXDOMAIN)) {
verbose(VERB_OPS, "no qname in reply to check 0x20ID"); verbose(VERB_DETAIL, "no qname in reply to check 0x20ID");
log_addr(VERB_OPS, "from server", log_addr(VERB_DETAIL, "from server",
&sq->addr, sq->addrlen); &sq->addr, sq->addrlen);
log_buf(VERB_OPS, "for packet", c->buffer); log_buf(VERB_DETAIL, "for packet", c->buffer);
error = NETEVENT_CLOSED; error = NETEVENT_CLOSED;
c = NULL; c = NULL;
} else if(ldns_buffer_read_u16_at(c->buffer, 4) > 0 && } else if(ldns_buffer_read_u16_at(c->buffer, 4) > 0 &&
!serviced_check_qname(c->buffer, sq->qbuf, !serviced_check_qname(c->buffer, sq->qbuf,
sq->qbuflen)) { sq->qbuflen)) {
verbose(VERB_OPS, "wrong 0x20-ID in reply qname, " verbose(VERB_DETAIL, "wrong 0x20-ID in reply qname");
"answer dropped"); log_addr(VERB_DETAIL, "from server",
log_addr(VERB_OPS, "from server",
&sq->addr, sq->addrlen); &sq->addr, sq->addrlen);
log_buf(VERB_OPS, "for packet", c->buffer); log_buf(VERB_DETAIL, "for packet", c->buffer);
error = NETEVENT_CLOSED; error = NETEVENT_CAPSFAIL;
c = NULL; /* and cleanup too */
pkt_dname_tolower(c->buffer,
ldns_buffer_at(c->buffer, 12));
} else { } else {
verbose(VERB_ALGO, "good 0x20-ID in reply qname"); verbose(VERB_ALGO, "good 0x20-ID in reply qname");
/* cleanup caps, prettier cache contents. */ /* cleanup caps, prettier cache contents. */

BIN
testdata/fwd_capsid.tpkg vendored Normal file

Binary file not shown.

BIN
testdata/fwd_capsid_fallback.tpkg vendored Normal file

Binary file not shown.

View file

@ -62,6 +62,7 @@ strmodulevent(enum module_ev e)
case module_event_pass: return "module_event_pass"; case module_event_pass: return "module_event_pass";
case module_event_reply: return "module_event_reply"; case module_event_reply: return "module_event_reply";
case module_event_noreply: return "module_event_noreply"; 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_moddone: return "module_event_moddone";
case module_event_error: return "module_event_error"; case module_event_error: return "module_event_error";
} }

View file

@ -239,6 +239,8 @@ enum module_ev {
module_event_reply, module_event_reply,
/** no reply, timeout or other error */ /** no reply, timeout or other error */
module_event_noreply, module_event_noreply,
/** reply is there, but capitalisation check failed */
module_event_capsfail,
/** next module is done, and its reply is awaiting you */ /** next module is done, and its reply is awaiting you */
module_event_moddone, module_event_moddone,
/** error */ /** error */

View file

@ -80,6 +80,8 @@ typedef int comm_point_callback_t(struct comm_point*, void*, int,
#define NETEVENT_CLOSED -1 #define NETEVENT_CLOSED -1
/** to pass timeout happened to callback function */ /** to pass timeout happened to callback function */
#define NETEVENT_TIMEOUT -2 #define NETEVENT_TIMEOUT -2
/** to pass fallback from capsforID to callback function; 0x20 failed */
#define NETEVENT_CAPSFAIL -3
/** /**
* A communication point dispatcher. Thread specific. * A communication point dispatcher. Thread specific.