#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 */
/* 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! */
+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.
}
}
+/** 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)
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);
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;
/* 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;
}
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;
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;
}
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);
}
outnet->tcp_free = pend;
}
(void)(*w->cb)(NULL, w->cb_arg, NETEVENT_TIMEOUT, NULL);
- free(w);
+ waiting_tcp_delete(w);
use_free_buffer(outnet);
}
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);
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);
+}
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.
}
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,
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;
}
/**
* 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.