Tuesday, March 9, 2010

How Deadwood stores pending remote connections

To implement full recursion, I will have to do an overhaul of how Deadwood stores pending remote connections. In more detail: A pending local connection is when a DNS stub resolver sends a query for Deadwood and is waiting for a reply. A pending remote connection is when Deadwood sends a DNS query to another DNS server and is waiting for a reply.

Here is the structure for basic UDP remote connections:

typedef struct {
SOCKET socket;
int64_t die;
uint16_t remote_id;
int retries;
dw_str *query;
uint16_t num_locals;
local_T **local;
} remote_T;

Note that, in the actual source code, this is commented. To expand on the comments:
  • socket is the number for open socket which will get the UDP data. It’s called a “SOCKET” here because Windows, unlike UNIX, doesn’t use integers for sockets.
  • die is a timestamp for when this connection will be timed out and needs to be discarded. Note that this is a 64-bit number; Deadwood uses 64-bit timestamps to minimize Y2038 problems
  • remote_id is the 16-bit randomly created query ID generated by Deadwood using a cryptographically strong pseudo random number generator. If the reply doesn’t have the same query ID, it might be a DNS spoof attempt.
  • retries is the number of remaining times we will retry if the remote server doesn’t reply to our query when it runs out of time (when our time is the same or greater than the die time)
  • query is the query (name, DNS record type) we sent to the remote server; we keep a copy of it here because we need to make sure the query we get is the same as the query we sent them (again, to make spoofing harder).
  • num_locals is the number of local connections we send an answer to once we get a reply from the upstream server. This was added when I implemented the merging of multiple in-flight requests with the 2.4.07 release of Deadwood (August 31, 2009). When one program asks for, say, www.google.com and another program or computer asks for www.google.com while we’re still waiting for the first reply, Deadwood will merge the second request in to the first request, and send the reply to both clients once we get the reply upstream.
  • locals is a list of “local” connections (which can be either UDP or TCP connections); there are the connections we send a reply to downstream once we get a reply upstream
Now, this structure is a simple structure which is fine when the upstream server does the heavy lifting and we’re just caching and forwarding the reply they send us, but this will need to become a lot more fancy in order to make full recursion a reality.

I will discuss what changes I plan to make to this to make recursion possible in a future blog entry.