- Fix EDNS probe for .de DNSSEC testbed failure, where the infra

cache timeout coincided with a server update, the current EDNS 
  backoff is less sensitive, and does not cache the backoff unless 
  the backoff actually works and the domain is not expecting DNSSEC.


git-svn-id: file:///svn/unbound/trunk@2063 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2010-04-06 08:35:37 +00:00
parent 9717ad2be8
commit 18a7df3d5c
12 changed files with 111 additions and 60 deletions

View file

@ -1248,7 +1248,7 @@ outbound_entry_compare(void* a, void* b)
struct outbound_entry*
worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
uint16_t qclass, uint16_t flags, int dnssec,
uint16_t qclass, uint16_t flags, int dnssec, int want_dnssec,
struct sockaddr_storage* addr, socklen_t addrlen,
struct module_qstate* q)
{
@ -1259,9 +1259,9 @@ worker_send_query(uint8_t* qname, size_t qnamelen, uint16_t qtype,
return NULL;
e->qstate = q;
e->qsent = outnet_serviced_query(worker->back, qname,
qnamelen, qtype, qclass, flags, dnssec, addr, addrlen,
worker_handle_service_reply, e, worker->back->udp_buff,
&outbound_entry_compare);
qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
addr, addrlen, worker_handle_service_reply, e,
worker->back->udp_buff, &outbound_entry_compare);
if(!e->qsent) {
return NULL;
}

View file

@ -189,6 +189,7 @@ int worker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
* @param qclass: query class. (host order)
* @param flags: host order flags word, with opcode and CD bit.
* @param dnssec: if set, EDNS record will have DO bit set.
* @param want_dnssec: signatures needed.
* @param addr: where to.
* @param addrlen: length of addr.
* @param q: wich query state to reactivate upon return.
@ -197,7 +198,7 @@ int worker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
*/
struct outbound_entry* worker_send_query(uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
struct sockaddr_storage* addr, socklen_t addrlen,
int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
struct module_qstate* q);
/**

View file

@ -1521,7 +1521,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->qchase.qname, iq->qchase.qname_len,
iq->qchase.qtype, iq->qchase.qclass,
iq->chase_flags | (iq->chase_to_rd?BIT_RD:0), EDNS_DO|BIT_CD,
&target->addr, target->addrlen, qstate);
iq->dnssec_expected, &target->addr, target->addrlen, qstate);
if(!outq) {
log_addr(VERB_DETAIL, "error sending query to auth server",
&target->addr, target->addrlen);

View file

@ -696,7 +696,7 @@ outbound_entry_compare(void* a, void* b)
struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
struct sockaddr_storage* addr, socklen_t addrlen,
int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
struct module_qstate* q)
{
struct libworker* w = (struct libworker*)q->env->worker;
@ -706,9 +706,9 @@ struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
return NULL;
e->qstate = q;
e->qsent = outnet_serviced_query(w->back, qname,
qnamelen, qtype, qclass, flags, dnssec, addr, addrlen,
libworker_handle_service_reply, e, w->back->udp_buff,
&outbound_entry_compare);
qnamelen, qtype, qclass, flags, dnssec, want_dnssec,
addr, addrlen, libworker_handle_service_reply, e,
w->back->udp_buff, &outbound_entry_compare);
if(!e->qsent) {
return NULL;
}

View file

@ -129,6 +129,7 @@ int libworker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
* @param qclass: query class. (host order)
* @param flags: host order flags word, with opcode and CD bit.
* @param dnssec: if set, EDNS record will have DO bit set.
* @param want_dnssec: signatures needed.
* @param addr: where to.
* @param addrlen: length of addr.
* @param q: wich query state to reactivate upon return.
@ -137,7 +138,7 @@ int libworker_send_packet(ldns_buffer* pkt, struct sockaddr_storage* addr,
*/
struct outbound_entry* libworker_send_query(uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
struct sockaddr_storage* addr, socklen_t addrlen,
int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen,
struct module_qstate* q);
/** process incoming replies from the network */

View file

@ -1077,7 +1077,7 @@ lookup_serviced(struct outside_network* outnet, ldns_buffer* buff, int dnssec,
/** Create new serviced entry */
static struct serviced_query*
serviced_create(struct outside_network* outnet, ldns_buffer* buff, int dnssec,
struct sockaddr_storage* addr, socklen_t addrlen)
int want_dnssec, struct sockaddr_storage* addr, socklen_t addrlen)
{
struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq));
rbnode_t* ins;
@ -1091,6 +1091,7 @@ serviced_create(struct outside_network* outnet, ldns_buffer* buff, int dnssec,
}
sq->qbuflen = ldns_buffer_limit(buff);
sq->dnssec = dnssec;
sq->want_dnssec = want_dnssec;
memcpy(&sq->addr, addr, addrlen);
sq->addrlen = addrlen;
sq->outnet = outnet;
@ -1132,7 +1133,8 @@ serviced_delete(struct serviced_query* sq)
/* clear up the pending query */
if(sq->status == serviced_query_UDP_EDNS ||
sq->status == serviced_query_UDP ||
sq->status == serviced_query_PROBE_EDNS) {
sq->status == serviced_query_PROBE_EDNS ||
sq->status == serviced_query_UDP_EDNS_fallback) {
struct pending* p = (struct pending*)sq->pending;
if(p->pc)
portcomm_loweruse(sq->outnet, p->pc);
@ -1409,12 +1411,25 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error,
(LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) ==
LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE(ldns_buffer_begin(
c->buffer)) == LDNS_RCODE_NOTIMPL) ) {
if(!infra_edns_update(sq->outnet->infra, &sq->addr,
/* attempt to fallback to nonEDNS */
sq->status = serviced_query_TCP_EDNS_fallback;
serviced_tcp_initiate(sq->outnet, sq, c->buffer);
return 0;
} else if(error==NETEVENT_NOERROR &&
sq->status == serviced_query_TCP_EDNS_fallback &&
(LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) ==
LDNS_RCODE_NOERROR || LDNS_RCODE_WIRE(
ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NXDOMAIN
|| LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
== LDNS_RCODE_YXDOMAIN)) {
/* the fallback produced a result that looks promising, note
* that this server should be approached without EDNS */
/* only store noEDNS in cache if domain is noDNSSEC */
if(!sq->want_dnssec)
if(!infra_edns_update(sq->outnet->infra, &sq->addr,
sq->addrlen, -1, *sq->outnet->now_secs))
log_err("Out of memory caching no edns for host");
sq->status = serviced_query_TCP;
serviced_tcp_initiate(sq->outnet, sq, c->buffer);
return 0;
}
/* insert address into reply info */
if(!rep) {
@ -1504,43 +1519,33 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
serviced_callbacks(sq, NETEVENT_TIMEOUT, c, rep);
return 0;
}
} else if(error != NETEVENT_NOERROR) {
/* udp returns error (due to no ID or interface available) */
serviced_callbacks(sq, error, c, rep);
return 0;
}
if(error == NETEVENT_NOERROR && sq->status == serviced_query_UDP_EDNS
if(sq->status == serviced_query_UDP_EDNS
&& (LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer))
== LDNS_RCODE_FORMERR || LDNS_RCODE_WIRE(
ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOTIMPL)) {
/* note no EDNS, fallback without EDNS */
if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
-1, (uint32_t)now.tv_sec)) {
log_err("Out of memory caching no edns for host");
}
sq->status = serviced_query_UDP;
/* try to get an answer by falling back without EDNS */
sq->status = serviced_query_UDP_EDNS_fallback;
sq->retry = 0;
if(!serviced_udp_send(sq, c->buffer)) {
serviced_callbacks(sq, NETEVENT_CLOSED, c, rep);
}
return 0;
}
if(LDNS_TC_WIRE(ldns_buffer_begin(c->buffer)) ||
(error != NETEVENT_NOERROR && fallback_tcp) ) {
/* fallback to TCP */
/* this discards partial UDP contents */
if(sq->status == serviced_query_UDP_EDNS)
sq->status = serviced_query_TCP_EDNS;
else sq->status = serviced_query_TCP;
serviced_tcp_initiate(outnet, sq, c->buffer);
return 0;
}
/* yay! an answer */
if(sq->status == serviced_query_PROBE_EDNS) {
} else if(sq->status == serviced_query_PROBE_EDNS) {
/* probe without EDNS succeeds, so we conclude that this
* host likely has EDNS packets dropped */
log_addr(VERB_DETAIL, "timeouts, concluded that connection to "
"host drops EDNS packets", &sq->addr, sq->addrlen);
if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
/* only store noEDNS in cache if domain is noDNSSEC */
if(!sq->want_dnssec)
if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
-1, (uint32_t)now.tv_sec)) {
log_err("Out of memory caching no edns for host");
}
}
sq->status = serviced_query_UDP;
} else if(sq->status == serviced_query_UDP_EDNS &&
!sq->edns_lame_known) {
@ -1550,6 +1555,21 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
log_err("Out of memory caching edns works");
}
sq->edns_lame_known = 1;
} else if(sq->status == serviced_query_UDP_EDNS_fallback &&
!sq->edns_lame_known && (LDNS_RCODE_WIRE(
ldns_buffer_begin(c->buffer)) == LDNS_RCODE_NOERROR ||
LDNS_RCODE_WIRE(ldns_buffer_begin(c->buffer)) ==
LDNS_RCODE_NXDOMAIN || LDNS_RCODE_WIRE(ldns_buffer_begin(
c->buffer)) == LDNS_RCODE_YXDOMAIN)) {
/* the fallback produced a result that looks promising, note
* that this server should be approached without EDNS */
/* only store noEDNS in cache if domain is noDNSSEC */
if(!sq->want_dnssec)
if(!infra_edns_update(outnet->infra, &sq->addr, sq->addrlen,
-1, (uint32_t)now.tv_sec)) {
log_err("Out of memory caching no edns for host");
}
sq->status = serviced_query_UDP;
}
if(now.tv_sec > sq->last_sent_time.tv_sec ||
(now.tv_sec == sq->last_sent_time.tv_sec &&
@ -1563,6 +1583,20 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
roundtime, sq->last_rtt, (uint32_t)now.tv_sec))
log_err("out of memory noting rtt.");
}
/* perform TC flag check and TCP fallback after updating our
* cache entries for EDNS status and RTT times */
if(LDNS_TC_WIRE(ldns_buffer_begin(c->buffer)) || fallback_tcp) {
/* fallback to TCP */
/* this discards partial UDP contents */
if(sq->status == serviced_query_UDP_EDNS ||
sq->status == serviced_query_UDP_EDNS_fallback)
/* if we have unfinished EDNS_fallback, start again */
sq->status = serviced_query_TCP_EDNS;
else sq->status = serviced_query_TCP;
serviced_tcp_initiate(outnet, sq, c->buffer);
return 0;
}
/* yay! an answer */
serviced_callbacks(sq, error, c, rep);
return 0;
}
@ -1583,10 +1617,10 @@ callback_list_find(struct serviced_query* sq, void* cb_arg,
struct serviced_query*
outnet_serviced_query(struct outside_network* outnet,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, struct sockaddr_storage* addr,
socklen_t addrlen, comm_point_callback_t* callback,
void* callback_arg, ldns_buffer* buff,
int (*arg_compare)(void*,void*))
uint16_t flags, int dnssec, int want_dnssec,
struct sockaddr_storage* addr, socklen_t addrlen,
comm_point_callback_t* callback, void* callback_arg,
ldns_buffer* buff, int (*arg_compare)(void*,void*))
{
struct serviced_query* sq;
struct service_callback* cb;
@ -1602,7 +1636,8 @@ outnet_serviced_query(struct outside_network* outnet,
return NULL;
if(!sq) {
/* make new serviced query entry */
sq = serviced_create(outnet, buff, dnssec, addr, addrlen);
sq = serviced_create(outnet, buff, dnssec, want_dnssec,
addr, addrlen);
if(!sq) {
free(cb);
return NULL;
@ -1754,7 +1789,8 @@ serviced_get_mem(struct serviced_query* sq)
s += sizeof(*sb);
if(sq->status == serviced_query_UDP_EDNS ||
sq->status == serviced_query_UDP ||
sq->status == serviced_query_PROBE_EDNS) {
sq->status == serviced_query_PROBE_EDNS ||
sq->status == serviced_query_UDP_EDNS_fallback) {
s += sizeof(struct pending);
s += comm_timer_get_mem(NULL);
} else {

View file

@ -291,6 +291,8 @@ struct serviced_query {
size_t qbuflen;
/** If an EDNS section is included, the DO/CD bit will be turned on. */
int dnssec;
/** We want signatures, or else the answer is likely useless */
int want_dnssec;
/** where to send it */
struct sockaddr_storage addr;
/** length of addr field in use. */
@ -308,7 +310,11 @@ struct serviced_query {
/** TCP without EDNS sent */
serviced_query_TCP,
/** probe to test EDNS lameness (EDNS is dropped) */
serviced_query_PROBE_EDNS
serviced_query_PROBE_EDNS,
/** probe to test noEDNS0 (EDNS gives FORMERRorNOTIMP) */
serviced_query_UDP_EDNS_fallback,
/** probe to test TCP noEDNS0 (EDNS gives FORMERRorNOTIMP) */
serviced_query_TCP_EDNS_fallback
}
/** variable with current status */
status;
@ -427,6 +433,8 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
* @param dnssec: if set, DO bit is set in EDNS queries.
* If the value includes BIT_CD, CD bit is set when in EDNS queries.
* If the value includes BIT_DO, DO bit is set when in EDNS queries.
* @param want_dnssec: signatures are needed, without EDNS the answer is
* likely to be useless.
* @param callback: callback function.
* @param callback_arg: user argument to callback function.
* @param addr: to which server to send the query.
@ -439,10 +447,10 @@ void pending_delete(struct outside_network* outnet, struct pending* p);
*/
struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, struct sockaddr_storage* addr,
socklen_t addrlen, comm_point_callback_t* callback,
void* callback_arg, ldns_buffer* buff,
int (*arg_compare)(void*,void*));
uint16_t flags, int dnssec, int want_dnssec,
struct sockaddr_storage* addr, socklen_t addrlen,
comm_point_callback_t* callback, void* callback_arg,
ldns_buffer* buff, int (*arg_compare)(void*,void*));
/**
* Remove service query callback.

View file

@ -112,7 +112,8 @@ int worker_send_packet(ldns_buffer* ATTR_UNUSED(pkt),
struct outbound_entry* worker_send_query(uint8_t* ATTR_UNUSED(qname),
size_t ATTR_UNUSED(qnamelen), uint16_t ATTR_UNUSED(qtype),
uint16_t ATTR_UNUSED(qclass), uint16_t ATTR_UNUSED(flags),
int ATTR_UNUSED(dnssec), struct sockaddr_storage* ATTR_UNUSED(addr),
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
struct sockaddr_storage* ATTR_UNUSED(addr),
socklen_t ATTR_UNUSED(addrlen), struct module_qstate* ATTR_UNUSED(q))
{
log_assert(0);

View file

@ -988,10 +988,10 @@ pending_tcp_query(struct outside_network* outnet, ldns_buffer* packet,
struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, struct sockaddr_storage* addr,
socklen_t addrlen, comm_point_callback_t* callback,
void* callback_arg, ldns_buffer* ATTR_UNUSED(buff),
int (*arg_compare)(void*,void*))
uint16_t flags, int dnssec, int ATTR_UNUSED(want_dnssec),
struct sockaddr_storage* addr, socklen_t addrlen,
comm_point_callback_t* callback, void* callback_arg,
ldns_buffer* ATTR_UNUSED(buff), int (*arg_compare)(void*,void*))
{
struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
struct fake_pending* pend = (struct fake_pending*)calloc(1,

View file

@ -258,8 +258,9 @@ fptr_whitelist_modenv_send_packet(int (*fptr)(ldns_buffer* pkt,
int
fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, struct sockaddr_storage* addr,
socklen_t addrlen, struct module_qstate* q))
uint16_t flags, int dnssec, int want_dnssec,
struct sockaddr_storage* addr, socklen_t addrlen,
struct module_qstate* q))
{
if(fptr == &worker_send_query) return 1;
else if(fptr == &libworker_send_query) return 1;

View file

@ -201,8 +201,9 @@ int fptr_whitelist_modenv_send_packet(int (*fptr)(ldns_buffer* pkt,
*/
int fptr_whitelist_modenv_send_query(struct outbound_entry* (*fptr)(
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
uint16_t flags, int dnssec, struct sockaddr_storage* addr,
socklen_t addrlen, struct module_qstate* q));
uint16_t flags, int dnssec, int want_dnssec,
struct sockaddr_storage* addr, socklen_t addrlen,
struct module_qstate* q));
/**
* Check function pointer whitelist for module_env detach_subs callback values.

View file

@ -114,6 +114,8 @@ struct module_env {
* @param dnssec: if set, EDNS record will have bits set.
* If EDNS_DO bit is set, DO bit is set in EDNS records.
* If BIT_CD is set, CD bit is set in queries with EDNS records.
* @param want_dnssec: if set, the validator wants DNSSEC. Without
* EDNS, the answer is likely to be useless for this domain.
* @param addr: where to.
* @param addrlen: length of addr.
* @param q: wich query state to reactivate upon return.
@ -124,8 +126,8 @@ struct module_env {
*/
struct outbound_entry* (*send_query)(uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint16_t flags, int dnssec,
struct sockaddr_storage* addr, socklen_t addrlen,
struct module_qstate* q);
int want_dnssec, struct sockaddr_storage* addr,
socklen_t addrlen, struct module_qstate* q);
/**
* Detach-subqueries.