skadns
Software
www.skarnet.org

The skadns library interface

Compiling

Linking

Programming

Starting a session

 skadnsinfo_ref a ;
 a = skadns_start() ;
 a = skadns_startf() ;
Those functions create an instance of the skadnsd program that will perform the resolutions; and they return a pointer to an opaque skadnsinfo structure that holds all the internal skadns information. If a is null then the call failed: most likely, you're out of memory, or (for skadns_start()) the skadnsd service isn't running.
skadns_start() tries to spawn the skadnsd instance from a skadnsd service: it connects to a Unix domain socket whose location is given in SKADNS_IPCPATH, expecting to find a Unix superserver listening there.
skadns_startf(), which you should use instead, simply forks a skadnsd child from the current process.

Sending DNS queries

 uint16 id ;
 skadnsinfo_ref a ;
 const char *query ;
 const char qtype[2] ;
 id = skadns_send(a, query, qtype) ;
skadns_send sends query, of type qtype. query must be in packet-encoded format: you can use dns_domain_fromdot() to convert a dot-encoded domain to a packet-encoded one.
You can include the dns.h header, which defines macros for qtype.
skadns_send returns immediately: 0 if an error occurred, or a non-zero, 16-bit integer if it succeeds. Keep this integer: you will use it as an identification number for the query.

You cannot send more than SKADNS_MAXCONCURRENCY (default: 1000) queries at a time, without reading the answers.

Being notified of answers

 int fd ;
 int count ;
 uint16 *list ;
 skadnsinfo_ref a ;
 fd = skadns_fd(a) ;
 count = skadns_readanswers(a) ;
 list = skadns_recvlist(a) ;
skadns_fd returns a file descriptor you can select() or poll(): it will be readable if answers have arrived. Do not read() it though, but call skadns_readanswers(). You should perform this call as soon as possible - else answers indefinitely queue up in the skadnsd daemon, eating up memory (and risking failure if you have set up a tight memory limit on the daemon).
skadns_readanswers returns -1 on failure, and a non-negative number on success - which is the number of answers that have arrived. In that case, skadns_recvlist will return a pointer to count 16-bit integers, which are the IDs of the queries that have returned.

Getting the answers

 int r ;
 skadnsinfo_ref a ;
 uint16 id ;
 stralloc sa = GEN_ALLOC_ZERO ;
 r = skadns_recv(a, id, &sa) ;
skadns_recv looks for the answer to the query that has the id you gave as argument. It returns: If an answer has arrived, it is stored in sa. This answer is in packet-encoded format; it is not directly user-readable.

The stralloc type is documented here; I have added a call, stralloc_free, that frees the memory used by a stralloc.
Note that you must always declare and initialize a stralloc to zero. Never declare stralloc *foo ; but instead declare stralloc foo = GEN_ALLOC_ZERO ; and use &foo everytime.

Specific query type support

skadns_send and skadns_recv are low-level application interfaces. Most of the time, programmers will not want to deal with DNS packets directly, but would rather handle domains as text and IP adresses as a sequence of numbers, for instance. skadns provides them with some high-level inferfaces: the foobar-send functions return an ID as skadns-send does, and the foobar-recv functions returns an int with the same meaning as skadns-recv.
Note that you must still call skadns-readanswers before calling foobar-recv.

name to IP

 skadnsinfo_ref a ;
 const char *s ;
 unsigned int len ;
 uint16 id ;
 stralloc out = GEN_ALLOC_ZERO ;
 int r ;
 id = skadns_ip4_send(a, s, len) ;
 r = skadns_ip4_recv(a, id, &out) ;
s contains a text FQDN, of length len.
On success, out.s will contain zero or more sequences of 4 bytes, every sequence representing an IP address. out.len/4 is the number of answers (0 for NXDOMAIN).

IP to name

 skadnsinfo_ref a ;
 const char *s ;
 unsigned int len ;
 const char ip[4] ;
 uint16 id ;
 stralloc out = GEN_ALLOC_ZERO ;
 int r ;
 id = skadns_ptr_send(a, s, len) ;
 id = skadns_name4_send(a, ip) ;
 r = skadns_ptr_recv(a, id, &out) ;
s contains a text FQDN - probably ending in .in-addr.arpa.
ip is an IP address, encoded as a sequence of 4 bytes.
On success, out.s will contain the name looked up, of length out.len (0 for NXDOMAIN).
skadns_name4_recv is an alias for skadns_ptr_recv.

MX

 skadnsinfo_ref a ;
 const char *s ;
 unsigned int len ;
 uint16 id ;
 stralloc out = GEN_ALLOC_ZERO ;
 int r ;
 id = skadns_mx_send(a, s, len) ;
 r = skadns_mx_recv(a, id, &out) ;
s contains a text FQDN, of length len.
On success, out.s will contain a series of MX fields encoded as follows: 2 big-endian bytes for the preference, then a null-terminated fqdn. out.len is the total length of out.s.

TXT

 skadnsinfo_ref a ;
 const char *s ;
 unsigned int len ;
 uint16 id ;
 stralloc out = GEN_ALLOC_ZERO ;
 int r ;
 id = skadns_txt_send(a, s, len) ;
 r = skadns_txt_recv(a, id, &out) ;
s contains a text FQDN, of length len.
On success, out.s will contain a series of TXT fields.

Ending a session

 skadnsinfo_ref a ;
 skadns_end(a) ;
skadns_end() closes and frees everything associated to the a session. The a pointer is not valid anymore afterwards.
You should call this function as soon as you're done with skadns, unless your application terminates immediately.