The full source code can be found in examples/ldns-mx.c
ldns-mx is a simple tool that queries your default caching forwarder for the MX (Mail exchange) record of the given domain.
% ldns-mx nlnetlabs.nl nlnetlabs.nl. 86400 IN MX 100 omval.tednet.nl. nlnetlabs.nl. 86400 IN MX 50 open.nlnetlabs.nl.
First of all, we need to include the correct header files, so that all functions are available to us:
#include "config.h" #include <ldns/ldns.h>
In this case we have used a configure script to generate a config.h file that does all our inclusions for us, so that it can be compiled on multiple platforms. If your platform supports the include files
stdlib.h, you can include these instead of using a configure script.
The first included files are prerequisites that ldns needs to function. The last one, of course, includes the functions of ldns itself.
In our main function, we declare some variables that we are going to use:
ldns_resolverstructure keeps a list of nameservers, and can perform queries for us
ldns_rdfis a basic data type of dns, the RDATA. See Design for a description about the building blocks of DNS. In this case,
domainwill be used to store the name the user specifies when calling the program
ldns_pktis a DNS packet, for instance a complete query, or an answer
ldns_rr_liststructure contains a list of DNS Resource Records (RRs). In this case, we will store the MX records we find in the list.
ldns_statusis the basic type for status messages in ldns. Most functions will return a value of this type.
First, we parse the command line argument (checks omitted on this page, see full source code), and store it in our
domain = ldns_dname_new_frm_str(argv);
This function takes a string containing a domain name (like "nlnetlabs.nl") and returns an
ldns_rdf representing that name. If somehow the given string can not be parsed it returns NULL.
Then, we create the resolver structure:
s = ldns_resolver_new_frm_file(&res, NULL);
Most of the functions work like this, the first argument is a pointer to the structure where ldns should store its results (which is also a pointer). The function returns a status code indicating success (LDNS_STATUS_OK) or an error number. Remember that these types of functions allocate memory that you should free later (using the ldns_free_<type> functions).
The second argument is the filename that contains information about the resolver structure that is to be created. If this argument is NULL, /etc/resolv.conf is used. The syntax of the file is like that of /etc/resolv.conf.
We tell the resolver to query for our domain, type MX, of class IN:
The last argument contains flags to influence the type of query the resolver structure sends. In this case, we want the nameserver to use recursion, so that we'll get the final answer. Therefore, we specify the LDNS_RD (Recursion Desired) flag.
This should return a packet if everything goes well.
We get all RRs of type MX from the answer packet and store them in our list:
If this list is not empty, we sort and print it:
And finally, just to be proper, we free our allocated data:
For structures that can contain other ldns structures, there are two types of free() function available
ldns_free_<type>frees only the allocated data for the structure itself.
ldns_deep_free_<type>frees the structure, and ALL structures that are nested in it. For example, of you
deep_freean ldns_rr_list, all
ldns_rrstructures that were present in the list are also freed.