Libext-dns library manual

Libext-dns library manual

Section 1: common API

Section 2: writing a DNS server

Basic concepts before start

Libext-dns has a easy to use API, where some objects are used to start a DNS listener, and over those listeners, you configure a set of handlers that are called to notify various events that happens when a request is received. Here are the list of main objects that you must use:

There are more modules, types and handlers to consider while using libext-dns but these are the most important. Let's see the rest of the API step by step.

How to create a simple DNS listener

In this section, we'll describe how to write a basic DNS listener using libext-dns. Full example can be found at: https://dolphin.aspl.es/svn/publico/ext-dns/test/ext-dns-simple-listener.c

Let's start. No matter if you are writing a client or a listener, you must create and initialize a extDnsCtx context. Here is how it is done.

/* create empty context */
ctx = ext_dns_ctx_new ();
if (ctx == NULL) {
printf ("ERROR: failed to allocate ctx object..\n");
exit (-1);
}
/* init context */
if (! ext_dns_init_ctx (ctx)) {
printf ("ERROR: failed to initiatialize ext-dns server context..\n");
exit (-1);
}

Now you have started a context, you can start listeners or doing requests to other DNS servers. In this case, we are creating a listener, so, we use the following code to start a DNS server on the local 53 port by doing:

/* start a listener running on local 53 UDP port */
listener = ext_dns_listener_new (ctx, "0.0.0.0", "53", extDnsUdpSession, NULL, NULL);
if (! ext_dns_session_is_ok (listener, axl_false)) {
printf ("ERROR: failed to start serving requests..\n");
exit (-1);
} /* end if */

Now, we've got to configure a handler to get a notification every time a DNS request is received so we can do interesting things with it. Here is how to do it:

ext_dns_session_set_on_message (listener, on_received, NULL);

We will see the content of the on received handler a few steps below. For now, we have to place the code that will ensure our listener doesn't finishes and also the code that finishes the context (and all listeners and clients in play) once we signal the context to finish.

Keep in mind this code isn't necessary if you are embeding libext-dns library into an application that has its own waiting loop. That is, calling to ext_dns_ctx_wait will block the calling thread until the server is signaled to unlock due to a call to ext_dns_ctx_unlock. In any case, this is the waiting plus finalization code:

/* block and process all incoming requests */
/* terminate context and release all resources (unless application acquired additional references) */
ext_dns_exit_ctx (ctx, axl_true);

An example of a extDnsOnMessageReceived handler

Now, for the on received handler, you must configure a handler that has the following signature. Look also at the example to see how some replies or actions are handled:

/* For more details about this handler, see extDnsOnMessageReceived */
void on_received (extDnsCtx * ctx,
/* this is listener where we have received the request */
extDnsSession * session,
/* this is the remote peer address */
const char * source_address,
/* this is the remote port address */
int source_port,
/* this is the actual dns message received */
extDnsMessage * message,
/* your user defined pointer configured at the time this handler was setup */
axlPointer _data)
{
extDnsMessage * reply = NULL;
/* skip messages that are queries */
if (! ext_dns_message_is_query (message)) {
printf ("ERROR: received a query message, dropping DNS message..\n");
return;
} /* end if */
/* ok, let's suppose we want to discard all requests comming from certain ip: then just return */
if (axl_cmp (source_address, "192.168.1.100"))
return; /* you don't have to release anything */
printf ("INFO: received a request for name %s (%d)\n",
ext_dns_message_query_name (ctx, message), message->header->answer_count);
/* now let's support we have to rewrite a request from
www.evilcompany.com to www.anotherevilcompany.com and in
the process provide the IP */
if (axl_cmp (ext_dns_message_query_name (ctx, message), "www.evilcompany.com")) {
/* build a forged reply */
reply = ext_dns_message_build_cname_reply (ctx, message, "www.anotherevilcompany.com", 3600);
/* now add an additional answer to also set the IP of that site */
ext_dns_message_add_answer (ctx, reply, extDnsTypeA, extDnsClassIN, "www.anotherevilcompany.com", 3600, "192.168.0.20");
} /* end if */
/* process reply (if defined) */
if (reply) {
/* send reply */
ext_dns_message_send_udp_s (ctx, session, reply, source_address, source_port);
/* release reply reference */
} /* end if */
return;
}