SPCDNS icon indicating copy to clipboard operation
SPCDNS copied to clipboard

An easy to use DNS library with C and Lua bindings

SPCDNS: The sane DNS encoding/decoding library

SPCDNS implements a simple yet sane API to encode DNS queries and to decode DNS replies. The library (v2.0.0) currently supports the encoding and decoding of 30 DNS resource records, which is more than just about all other DNS resolving libraries I've seen (c-ares, udns, adns, libdns and djbdns [1]).

SPCDNS is NOT a general purpose DNS resolving library (although code is provided to make DNS queries, it is simple and fairly stupid). This code exists to provide a simple method of encoding and decoding the DNS protocol and thus the network side of things is a bit lacking I'll admit. But that is beyond what I wanted for this project anyway.

In the "src/" directory you'll find the following:

dns.h 

	Defines the various DNS RR types, a structure for an
	in-memory representation of each RR type (which is what
	you'll get back when you call the decoding routine), and the
	definitions for two functions, dns_encode() and dns_decode()
	which pretty much do what they say.

codec.c

	The actual implementations of dns_encode() and dns_decode().
	This is the only file that's needed to encode and decode the
	raw DNS protocol.  The routines are thread safe, do *not*
	allocate memory (see below for more details) and do not use
	signals.  It also does not use code from any other file in
	this package.

mappings.h
mappings.c

	These files provide definitions and implementation of a few
	helpful routines that return string representations of the
	DNS RR types, classes, opcodes and errors.  Again, thread
	safe and no memory allocations made.

netsimple.h
netsimple.c

	These files provide definitions and implementations for
	making simple DNS queries to a given server.  This code is
	*simple* and *dumb*, it may be good for light usage but was
	written to get actual DNS packets from a DNS server for
	testing.  This uses UDP and is thus limited to a query of
	512 bytes or less.

output.h
output.c

	These files provide definitions and implementations for
	utility functions to print query results using C stdio.
	It was factored out of the unit tests for debugging client
	applications making using of libspcdns.a and libspcdns.so. 
	They are found in the libspcdnsmisc.a and libspcdnsmisc.so
	libraries.

luadns.c

	Lua [2] bindings for this library.  It exports the routines
	found in codec.c, mappings.c and netsimple.c.

dotest.c

	An example program showing how to use the API to construct
	and send a query, and to decode the response.

You'll probably want to check the Makefile to make sure the right compiler and locations are set. Or not. You don't HAVE to use the included Makefile. It's really just a set of suggestions anyway.

A NOTE ABOUT MEMORY ALLOCATIONS

The dns_encode() and dns_decode() functions do no memory allocation; they use what you give them. In the case of dns_decode(), the block of memory passed in must be big enough to handle not only the dns_query_t structure, but multiple dns_answer_t structures and text strings representing domain names and the occasional string or two (say, for TXT or NAPTR records). In testing, I've found that 4K for decoding appears to be enough memory to handle DNS requests made via UDP (although the test.c program uses an 8K buffer).

This block of memory should be properly aligned and to help make that easier I've defined two data types that should allow proper alignment, along with some useful constants to declare buffers of proper alignment and size.

dns_packet_t   reply  [DNS_BUFFER_UDP];
dns_decoded_t  decoded[DNS_DECODEBUF_4K];
dns_query_t   *result;
dns_rcode      rc;
    size_t         replysize;
    size_t         decodesize;

/* assume reply contains a DNS packet, and replysize is set */

decodesize = sizeof(decoded);
rc = dns_decode(decoded,&decodesize,reply,replysize);

if (rc != RCODE_OKAY)
{
 /* handle error */
}

result = (dns_query_t *)decoded;

/* go with processing the result */

Do NOT assume that DNS_DECODEBUF_4K is equal to 4096---it's not. It DOES, however, result in at least a 4K block of memory made up of DNS_DECODEBUF_4K worth of dns_decoded_t types. By the same token, do NOT assume that DNS_BUFFER_UDP is 512, but it too, does result in a buffer of at least 512 bytes made up of DNS_BUFFER_UDP dns_packet_t types.

And while passing in a char * declared buffer to dns_decode() may appear to work, it only works on YOUR system; it may not work on other systems.

A NOTE ABOUT DOMAIN NAMES

The dns_encode() function assumes the domain passed is a fully qualified domain name. If you see an RCODE_NAME_ERROR when calling this function, you are probably not passing in a FQDN (if you are and are still getting that error, it's most likely a domain name segment exceeding the 63 character DNS limit).

SOME NOTES ABOUT THE LUA BINDINGS

The Lua bindings (for Lua 5.1-5.4) are loaded into a Lua script with the following:

local dns = require "org.conman.dns"

Doing a "make install-lua" will install this file under:

/usr/local/lib/lua/<Lua version>/org/conman/

(assuming you didn't change the LUA setting in the Makefile)

and thus place it under the appropriate namespace so Lua can find it.

The file "lua/test.lua" shows the best use of the Lua bindings (and is close enough to what "src/test.c" does). Better network handling could be done using LuaSocket, but for that, you are on your own.

UNIT TESTING

The dotest program allows unit-testing SPCDNS when making changes or integrating it with client applications.

Note: the unit test program, dotest, requires a fully-qualified canonical DNS name. This means "www.example.com." NOT "www.example.com". If this is not present, the dns_encode_domain function returns RCODE_NAME_ERROR and the test will fail with a mysterious error message.

Sample Output:

This is an example of a working run, querying for Google's web server, using a Google Public DNS Server [4].

$ ./dotest -d -s 8.8.8.8 www.google.com. OUTGOING:

... MEMORY DUMP...

INCOMING:

... MEMORY DUMP...

Bytes used: 680

; Questions = 1 ; Answers = 5 ; Name Servers = 0 ; Additional Records = 0 ; Authoritative Result = false ; Truncated Result = false ; Recursion Desired = true ; Recursion Available = true ; Result = No error

;;; QUESTIONS

;www.google.com. IN A

;;; ANSWERS

www.google.com. 185 IN A 74.125.239.49 www.google.com. 185 IN A 74.125.239.52 www.google.com. 185 IN A 74.125.239.50 www.google.com. 185 IN A 74.125.239.51 www.google.com. 185 IN A 74.125.239.48

;;; NAMESERVERS

;;; ADDITIONAL

A FINAL NOTE

If you have any problems, questions or enhancements, please send them my way, to [email protected].

Thank you.

Other contributors include, but are not limited to:

Matthew Hall [email protected]

[1] http://c-ares.haxx.se/ http://www.corpit.ru/mjt/udns.html http://www.chiark.greenend.org.uk/~ian/adns/ http://www.25thandclement.com/~william/projects/dns.c.html http://cr.yp.to/djbdns.html

[2] http://www.lua.org/

[3] http://w3.impa.br/~diego/software/luasocket/

[4] https://developers.google.com/speed/public-dns/