specification of dns_stub_* interface (to lwresd?)

-----BEGIN PGP SIGNED MESSAGE-----
What FreeSWAN needs from libdns.
Problem
=======
FreeSWAN's keying deamon (pluto) does DNS lookups while processing
other requests from other protocols. FreeSWAN needs to know if DNS requests have
occured, have succeeded, failed, etc. At the same time, DNS requests over UDP
are not reliable, and may need to be retransmitted, switched over to TCP, etc.
The current (bind4 era) resolver is a blocking call to gethostbyname(3),
and friends. bind8 introduced a thread based non-blocking resolver, but
programming with threads is fundamentally more dangerous to do, and the
FreeS/WAN team prefers to avoid this.
Background
==========
FreeS/WAN currently uses an interface to an external program. The external
program makes the appropriate blocking resolver calls, communicating to the
parent program via local IPC. The IPC provides the appropriate asynchronous
nature for pluto.
This solution is sub-optimal to us, as we must have a "worker" process for
each outstanding request that we do, and our protocol is not necessarily rich
enough to provide all the information that we might like to receive. While
the protocol is easily extensible, it seems that there is already such a
protocol being developed.
Additional Complications
========================
As the primary target for FreeS/WAN is for implementing Opportunistic
Encryption (see OE draft), and policies for communicating with other nodes
may be stringent - use encryption or fail, it is very important the pluto
understand precisely what communications are involved in communicating with
domain name servers such that they can properly treated.
FreeS/WAN will generally use a stub resolver to communicate to either a
local full recursive resolver or one of several remote ones. If communicating
remotely, we would prefer that we use Opportunistic Encryption for the DNS
communication as well.
If communicating to a local recursive resolver, this resolver itself may
cause lots of traffic that may we may desire to have to be OE
protected. There are bootstrapping issues that are not entirely resolveable,
nor do we propose to resolve them here.
At a minimum, in all cases that the stub resolver communicates over IP (vs
using a machine local transport, e.g. Unix domain sockets) we would like to
be aware of which address it is currently communicating with so that we might
(optionally) apply slightly different policy for this communication.
Outline of API desired
======================
1) initialize the API.
struct dns_async_context *dac;
dac = dns_stub_init();
2) initialize a request. Let the caller provide the memory.
struct dns_async_req_context *darq;
darq = malloc(dns_stub_req_size(dac));
dns_stub_req_init(dac, darq, 0); // third arg is size of space, error if too small.
3) make a request.
dns_stub_mkquery(darq, context, op, dname, class, type, data, dadalen, newrr)
// context is for our use, and is just stored for duration.
// like res_mkquery, but buf and buflen are internal to darq.
4) send the query.
dns_stub_start(darq);
5) set timer and wait FD(s).
struct timeval tv;
int fd, fdcount;
// do appropriate mucking with tv for local use.
// settimeout will make tv interval smaller if necessary, but won't touch
// it if tv is non-zero but smaller than desired timeout.
dns_stub_settimeout(dac, &tv);
// get number of file descriptors involve
fdcount = dns_stub_fd_read_count(dac);
for(i=0; i<fdcount; i++) {
fd = dns_stub_fd_read_get(dac, i);
// do FDSET or pollfd mucking.
}
6) event loop.
workready=0;
call select(2) or poll(2).
7) upon timeout
workready|=dns_stub_timeout(dac);
8) upon fd ready
workready|=dns_stub_readready(dac, fd);
for each FD ready.
9) if(workready) {
struct dns_async_req_context *darq;
while((darq = dns_stub_req_done(dac))!=NULL) {
// request is finished in someway, decode results.
}
10) goto step 5.
A number of inquiry functions would be needed as well to get data out of the
darq structure once a result has been found. The context element in the darq
should be used by the client to determine which darq goes with which request.
It is assumed here that no write flow control is necessary.
Security Policy on DNS requests
===============================
It should be decided how to best deal with providing knowledge back and forth
relating to security policy on DNS flows. There are several ways that this
could be done:
1) the application could use the dns_stub_fd_write_*() to get a list
of file descriptors, call setsockopt() on them directly to set
security policy and/or call getpeername() to discover where the
sockets would talk to and do appropriate lower layer juggling.
2) the application could provide with an initialization function
that would do the above operations after the sockets are opened by
dns_stub().
3) note that the above may not work if a UDP socket is used for talking
to multiple peers in an unconnected fashion. Unclear if this
matters. In this case, the IP address(es) involved must be provided
to the application so that it may set the right policy.
4) all sends/receives could be handled directly by the application,
with dns_stub_*() no longer responsible for the raw I/O at all.
(but it would remain responsible for the timeouts).
responsabilities
================
the dns_stub_* functions take care of
1) determining what timeouts are necessary, and if the timeout
time has actually been reached.
2) failing over when there is no response from a server.
3) failing over to TCP when the results do not fit.
4) caching connections to servers
5) dealing with v4 and v6 sockets.
6) indicating clearly if RR was DNSSEC signed.
dns_stub.h header file to follow soon.
$Id: requirements,v 1.1 2002/04/30 21:08:34 mcr Exp $
-----BEGIN PGP SIGNATURE-----
Version: 2.6.3ia
Charset: latin1
Comment: Finger me for keys
iQCVAwUBPM73+IqHRg3pndX9AQGhmwP/WrkJAGnewd1SQDLTqaDKV1c6StQsDMPn
+O76Fyi6YZOxEGNyqyaHny3q8fcVE4fHgNd/0bT6M5E7cPbZDgtKIxUUnIyF6Vs8
1DgVZ1veRJUBKLVGHdFzi6KZtPVDacaI2tRJZUtPipfxUuBcoefaT+meeOm3LY+A
nEtxn7PzhrA=
=pLEa
-----END PGP SIGNATURE-----