mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-01-24 15:42:56 -05:00
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:
parent
6c3c370b2a
commit
d0908148d6
8 changed files with 129 additions and 10 deletions
|
|
@ -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! */
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue