TCP fallback if forwarder sends TC bit.

git-svn-id: file:///svn/unbound/trunk@295 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2007-05-09 07:00:10 +00:00
parent 6c3c370b2a
commit d0908148d6
8 changed files with 129 additions and 10 deletions

View file

@ -63,6 +63,8 @@
#define DNS_ID_AND_FLAGS 4
/** timeout in seconds for UDP queries to auth servers. TODO: proper rtt */
#define UDP_QUERY_TIMEOUT 4
/** timeout in seconds for TCP queries to auth servers. TODO: proper rtt */
#define TCP_QUERY_TIMEOUT 30
/** Advertised version of EDNS capabilities */
#define EDNS_ADVERTISED_VERSION 0
/** Advertised size of EDNS capabilities */
@ -237,6 +239,11 @@ worker_handle_reply(struct comm_point* c, void* arg, int error,
/* see if it is truncated */
if(LDNS_TC_WIRE(ldns_buffer_begin(c->buffer)) && c->type == comm_udp) {
log_info("TC: truncated. retry in TCP mode.");
qinfo_query_encode(w->worker->back->udp_buff, &w->qinfo);
pending_tcp_query(w->worker->back, w->worker->back->udp_buff,
&w->worker->fwd_addr, w->worker->fwd_addrlen,
TCP_QUERY_TIMEOUT, worker_handle_reply, w,
w->worker->rndstate);
return 0;
}
/* woohoo a reply! */

View file

@ -1,3 +1,7 @@
9 May 2007: Wouter
- outside network cleans up waiting tcp queries on exit.
- fallback to TCP.
8 May 2007: Wouter
- outgoing network keeps list of available tcp buffers for outgoing
tcp queries.

View file

@ -109,6 +109,18 @@ pending_cmp(const void* key1, const void* key2)
}
}
/** delete waiting_tcp entry. Does not unlink from waiting list.
* @param w: to delete.
*/
static void
waiting_tcp_delete(struct waiting_tcp* w)
{
if(!w) return;
if(w->timer)
comm_timer_delete(w->timer);
free(w);
}
/** use next free buffer to service a tcp query */
static void
outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt)
@ -128,7 +140,7 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt)
log_err("outgoing tcp: socket: %s", strerror(errno));
log_addr(&w->addr, w->addrlen);
(void)(*w->cb)(NULL, w->cb_arg, NETEVENT_CLOSED, NULL);
free(w);
waiting_tcp_delete(w);
return;
}
fd_set_nonblock(s);
@ -138,13 +150,13 @@ outnet_tcp_take_into_use(struct waiting_tcp* w, uint8_t* pkt)
log_addr(&w->addr, w->addrlen);
close(s);
(void)(*w->cb)(NULL, w->cb_arg, NETEVENT_CLOSED, NULL);
free(w);
waiting_tcp_delete(w);
return;
}
}
w->pkt = NULL;
w->next_waiting = (void*)pend;
memmove(&pend->id, pkt, sizeof(uint16_t));
pend->id = LDNS_ID_WIRE(pkt);
w->outnet->tcp_free = pend->next_free;
pend->next_free = NULL;
pend->query = w;
@ -186,7 +198,7 @@ outnet_tcp_cb(struct comm_point* c, void* arg, int error,
/* check ID */
if(ldns_buffer_limit(c->buffer) < sizeof(uint16_t) ||
LDNS_ID_WIRE(ldns_buffer_begin(c->buffer))!=pend->id) {
log_info("outnettcp: bad ID in reply");
log_info("outnettcp: bad ID in reply, from:");
log_addr(&pend->query->addr, pend->query->addrlen);
error = NETEVENT_CLOSED;
}
@ -195,7 +207,7 @@ outnet_tcp_cb(struct comm_point* c, void* arg, int error,
comm_point_close(c);
pend->next_free = outnet->tcp_free;
outnet->tcp_free = pend;
free(pend->query);
waiting_tcp_delete(pend->query);
pend->query = NULL;
use_free_buffer(outnet);
return 0;
@ -380,7 +392,8 @@ create_pending_tcp(struct outside_network* outnet, size_t bufsize)
outnet->tcp_conns[i]->next_free = outnet->tcp_free;
outnet->tcp_free = outnet->tcp_conns[i];
outnet->tcp_conns[i]->c = comm_point_create_tcp_out(
bufsize, outnet_tcp_cb, outnet->tcp_conns[i]);
outnet->base, bufsize, outnet_tcp_cb,
outnet->tcp_conns[i]);
if(!outnet->tcp_conns[i]->c)
return 0;
}
@ -499,10 +512,20 @@ outside_network_delete(struct outside_network* outnet)
for(i=0; i<outnet->num_tcp; i++)
if(outnet->tcp_conns[i]) {
comm_point_delete(outnet->tcp_conns[i]->c);
waiting_tcp_delete(outnet->tcp_conns[i]->query);
free(outnet->tcp_conns[i]);
}
free(outnet->tcp_conns);
}
if(outnet->tcp_wait_first) {
struct waiting_tcp* p = outnet->tcp_wait_first, *np;
while(p) {
np = p->next_waiting;
waiting_tcp_delete(p);
p = np;
}
}
free(outnet);
}
@ -687,7 +710,7 @@ outnet_tcptimer(void* arg)
outnet->tcp_free = pend;
}
(void)(*w->cb)(NULL, w->cb_arg, NETEVENT_TIMEOUT, NULL);
free(w);
waiting_tcp_delete(w);
use_free_buffer(outnet);
}

View file

@ -703,6 +703,53 @@ pending_udp_query(struct outside_network* outnet, ldns_buffer* packet,
runtime->pending_list = pend;
}
void
pending_tcp_query(struct outside_network* outnet, ldns_buffer* packet,
struct sockaddr_storage* addr, socklen_t addrlen, int timeout,
comm_point_callback_t* callback, void* callback_arg,
struct ub_randstate* ATTR_UNUSED(rnd))
{
struct replay_runtime* runtime = (struct replay_runtime*)outnet->base;
struct fake_pending* pend = (struct fake_pending*)calloc(1,
sizeof(struct fake_pending));
ldns_status status;
log_assert(pend);
pend->buffer = ldns_buffer_new(ldns_buffer_capacity(packet));
log_assert(pend->buffer);
ldns_buffer_write(pend->buffer, ldns_buffer_begin(packet),
ldns_buffer_limit(packet));
ldns_buffer_flip(pend->buffer);
memcpy(&pend->addr, addr, addrlen);
pend->addrlen = addrlen;
pend->callback = callback;
pend->cb_arg = callback_arg;
pend->timeout = timeout;
pend->transport = transport_tcp;
pend->pkt = NULL;
status = ldns_buffer2pkt_wire(&pend->pkt, packet);
if(status != LDNS_STATUS_OK) {
log_err("ldns error parsing tcp output packet: %s",
ldns_get_errorstr_by_id(status));
fatal_exit("Sending unparseable DNS packets to servers!");
}
log_pkt("pending tcp pkt: ", pend->pkt);
/* see if it matches the current moment */
if(runtime->now && runtime->now->evt_type == repevt_back_query &&
find_match(runtime->now->match, pend->pkt, pend->transport)) {
log_info("testbound: matched pending to event. "
"advance time between events.");
log_info("testbound: do STEP %d %s", runtime->now->time_step,
repevt_string(runtime->now->evt_type));
advance_moment(runtime);
/* still create the pending, because we need it to callback */
}
log_info("testbound: created fake pending");
/* add to list */
pend->next = runtime->pending_list;
runtime->pending_list = pend;
}
struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg))
{
return calloc(1, 1);

View file

@ -1145,3 +1145,21 @@ query_info_entrysetup(struct query_info* q, struct reply_info* r,
q->qname = NULL;
return e;
}
void
qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo)
{
uint16_t flags = 0; /* QUERY, NOERROR */
if(qinfo->has_cd)
flags |= BIT_CD;
ldns_buffer_clear(pkt);
log_assert(ldns_buffer_remaining(pkt) >= 12+255+4/*max query*/);
ldns_buffer_skip(pkt, 2); /* id done later */
ldns_buffer_write_u16(pkt, flags);
ldns_buffer_write_u16(pkt, 1); /* query count */
ldns_buffer_write(pkt, "\000\000\000\000\000\000", 6); /* counts */
ldns_buffer_write(pkt, qinfo->qname, qinfo->qnamesize);
ldns_buffer_write_u16(pkt, qinfo->qtype);
ldns_buffer_write_u16(pkt, qinfo->qclass);
ldns_buffer_flip(pkt);
}

View file

@ -288,6 +288,13 @@ int reply_info_encode(struct query_info* qinfo, struct reply_info* rep,
uint16_t id, uint16_t flags, ldns_buffer* buffer, uint32_t timenow,
struct region* region, uint16_t udpsize);
/**
* Encode query packet. Assumes the buffer is large enough.
* @param pkt: where to store the packet.
* @param qinfo: query info.
*/
void qinfo_query_encode(ldns_buffer* pkt, struct query_info* qinfo);
/**
* Setup query info entry
* @param q: query info to copy. Emptied as if clear is called.

View file

@ -712,11 +712,12 @@ comm_point_create_tcp(struct comm_base *base, int fd, int num, size_t bufsize,
}
struct comm_point*
comm_point_create_tcp_out(size_t bufsize,
comm_point_create_tcp_out(struct comm_base *base, size_t bufsize,
comm_point_callback_t* callback, void* callback_arg)
{
struct comm_point* c = (struct comm_point*)calloc(1,
sizeof(struct comm_point));
short evbits;
if(!c)
return NULL;
c->ev = (struct internal_event*)calloc(1,
@ -746,6 +747,17 @@ comm_point_create_tcp_out(size_t bufsize,
c->tcp_check_nb_connect = 1;
c->callback = callback;
c->cb_arg = callback_arg;
evbits = EV_PERSIST | EV_WRITE;
event_set(&c->ev->ev, c->fd, evbits, comm_point_tcp_handle_callback, c);
if(event_base_set(base->eb->base, &c->ev->ev) != 0)
{
log_err("could not basetset tcpout event");
ldns_buffer_free(c->buffer);
free(c->ev);
free(c);
return NULL;
}
return c;
}

View file

@ -293,13 +293,14 @@ struct comm_point* comm_point_create_tcp(struct comm_base* base,
/**
* Create an outgoing TCP commpoint. No file descriptor is opened, left at -1.
* @param base: in which base to alloc the commpoint.
* @param bufsize: size of buffer to create for handlers.
* @param callback: callback function pointer for the handler.
* @param callback_arg: will be passed to your callback function.
* @return: the commpoint or NULL on error.
*/
struct comm_point* comm_point_create_tcp_out(size_t bufsize,
comm_point_callback_t* callback, void* callback_arg);
struct comm_point* comm_point_create_tcp_out(struct comm_base* base,
size_t bufsize, comm_point_callback_t* callback, void* callback_arg);
/**
* Create commpoint to listen to a local domain file descriptor.