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