I decided to have a go at writing a DNS library from scratch. All of the
libraries I've seen simply mimic the original BSD interfaces (mostly just
gethostbyname(), and BIND's libresolv.

But, I extensively use record types like SRV, AAAA and TXT, and also am
keenly interested in exposing DNSSEC infrastructure. And things like
client-side caching and easier parameterization are nice, as well as Win32
compatability without any build gymnastics. And recursive resolution is a
long-term goal, as well. Does anybody know whether EDNS1 has been
implemented anywhere?

However, I'm not trying to peddle my software, not now at least. Rather, I'm
interested in unconventional uses and requirements, both at the
infrastructure level, and _especially_ API preferences. This is largely
self-serving, because the more feedback I get the better I can
"future-proof" it for my own needs; but I release under an X11-style
license, anyhow. Please send me stories, comments, suggestions, and wishes.

Of course, this library will plug into libevent at some level, so the
outline of the API is somewhat circumscribed by the async pattern. Usually,
though, I like to design these things as restartable state machines, and
then build a light wrapper around that, because its always nice to be able
to use the core functionality in a small program or in a language binding
without any hassles like non-blocking I/O.

Current code is in dns.[ch] from a snapshot tarball of libevnet:

http://25thandclement.com/~william/projects/snapshots/libevnet-snapshot.tgz

I haven't worked on any I/O interfaces yet, nor the myriad layers which will
go above this, just a DNS query message parser. I've kinda gone crazy with
memory optimizations and making things amenable to compile-time
folding/inlining, particularly because message manipulations will be the
most memory intensive aspect of a resolver given the relative number of
dynamic allocations. So, for instance, the type mask is a bit array, rather
than a bit field, so it can handle the full range of values allowed by the
spec, but with -O1 optimization and constant class and type specificiers GCC
is able to precompute the object entirely. (Well, at least with some
additional macro tricks I haven't committed yet; GCC drops out of its
function inliner when faced with variable argument accesses. I'm still
debating whether to go that extra mile.)

But, I hope I have preserved a very use friendly interface, and hidden the
complexity. And really its the interface which is most important.

Here's my regression code, which uses all of the public interfaces so far.
I've snipped out error checking, which is extensive in the library
(including integer overflow checks).

#include <stdio.h>
#include <assert.h>
#include <err.h>

int main(void) {
        struct dns_message *m   = dns_m_open(&dns_defaults);
        unsigned char pkt[4096];
        size_t len;
        struct dns_m_rr *rr;

        /* #!/usr/bin/perl
         *
         * use Net::DNS;
         *
         * my $res      = Net::DNS::Resolver->new;
         * my $so       = $res->bgsend(shift @ARGV || "google.com");
         *
         * print $res->bgread($so)->data;
         */
        len = fread(pkt, 1, sizeof pkt, stdin);

        dns_m_parse(&m, pkt, len, DNS_M_PARSE_FLUSH));

        fprintf(stderr, "id:%hu q:%hu ans:%hu add:%hu auth:%hu\n", m->id, 
m->question.count, m->answers.count, m->authority.count, m->additional.count);

        DNS_M_RR_FOREACH(rr, m, DNS_M_SECTION_ANY, DNS_RR_CLASS(DNS_RR_C_IN), 
DNS_RR_TYPES(DNS_RR_T_A, DNS_RR_T_TXT, DNS_RR_T_NS)) {
                char name[256], rdata[256];
                struct dns_m_txt txt;

                dns_m_dn_expand(m, name, sizeof name, rr->name.base);

                switch (rr->type) {
                case DNS_RR_T_TXT:
                        dns_m_txt_parse(m, &txt, rr);

                        dns_m_txt_print(m, rdata, sizeof rdata, &txt, 
DNS_M_TXT_CONCAT);

                        fprintf(stderr, "%s type:%d  class:%d  ttl:%d  
rdata:(%u) '%s'\n", name, rr->type, rr->class, rr->ttl, txt.count, rdata);

                        break;
                default:
                        fprintf(stderr, "%s type:%d  class:%d  ttl:%d  
rdata:%d\n", name, rr->type, rr->class, rr->ttl, rr->rdata.len);
                }
        }

        return 0;
} /* main() */
_______________________________________________
Libevent-users mailing list
Libevent-users@monkey.org
http://monkeymail.org/mailman/listinfo/libevent-users

Reply via email to