skadns
Software
www.skarnet.org
The skadns library interface
Compiling
- Add /package/web/skadns/include to your header directory list
- Use #include "skadns.h"
Linking
- Define a global variable PROG of type const char *
that contains the name of your executable.
- Add /package/web/skadns/library to your library directory list
- Link with (in that order): libskadns.a, libdns.a and
libstddjb.a.
- If you're using skadns_start() and a skadnsd service, add
libwebipc.a before libstddjb.a, and add
`cat /package/prog/skalibs/sysdeps/socket.lib` to your linker's
command line.
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:
- A positive number (the number of pending queries, including the
one you're inquiring about) if the answer has arrived
- 0 if the answer has not arrived yet
- -1 if a hard error occurred
- -2 if there was a DNS error
- -3 if the query timed out
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.