This man page describes the getdns library, the general concepts behind the API and some of the common elements of the public interface to the library. Each of the public entry points and more complex data types are captured in separate man pages.
getdns is modern asynchronous DNS API intended to be useful to application developers and operating system distributors as a way of making all types of DNS information easily available in many types of programs. The major features of this new API are:
Each of the entry points is offered with both asynchronous and synchronous signatures. The asynchronous functions rely on event handling and callback via libevent.
Functions are thread safe.
.LP
A context structure maintains DNS query and response data and is used to maintain state during calls to the public entry points.
The API uses a few data structures to pass data into and return data from the public
entry points.
.IPlist
an ordered list, the members of the list can be any of the four data types.
.IPdict
a name-value pair. The name is a string literal, and the value can be any of the four data types. The order of the name-value pairs in a dict is not important.
.IPint
an integer compatible with uint32_t.
.IPbindata
a struct used to hold binary data defined as { size_t size; uint8_t *binary_stuff; }.
The getdns specification emphasizes the asynchronous nature of the API and
allows implementations to define their own approach. This page documents this
implementation's decisions and facilities provided to the developer.
.LP
This implementation provides asynchronous support via the following mechanisms:
.RS3
File Descriptor Polling
.br
Event Loop Integrations:
.RS3
libevent
.br
libuv
.br
libev
.RE
Custom Event Loop Integrations
.RE
.LP
All functions and types discussed in this page are declared in getdns_extra.h
.SS"File Descriptor Polling"
A common approach used in asynchronous applications is to poll a file
descriptor via system calls like select and poll and then yielding CPU when
ready. The API provides the following functions to support this approach:
.HP3
int getdns_context_fd(getdns_context* context)
Get the file descriptor to poll for a given context. Callers should never read from this result. It is meant strictly for polling.Returns -1 if the context is NULL.
Get the number of outstanding asynchronous requests for a given context as well as the the amount of time until the next timeout. The next_timeout struct can be NULL. If supplied and the number of outstanding requests is > 0, then the timeout represents the relative time until the next timeout.
Inform the context to process its outstanding requests. Users should call this when either a timeout has occurred or the file descriptor signals that it is ready. User callbacks are fired during this call.
.SS"Example Event Loop"
The following is an example event loop leveraging select:
.Bd-literal-compact
struct timeval tv;
/* Keep looping while there are outstanding requests */
while (getdns_context_get_num_pending_requests(context, &tv) > 0)
{
/* setup the read FD_SET to pass to select */
int fd = getdns_context_fd(context);
fd_set read_fds;
FD_ZERO(&read_fds);
FD_SET(fd, &read_fds);
/* Wait on the FD or for a timeout */
select(fd + 1, &read_fds, NULL, NULL, &tv);
getdns_context_process_async(context);
}
.Ed
.SS"Included Event Loop Integrations"
.LP
A number of applications achieve asynchronous behavior by leveraging event loop abstraction libraries. If the build system discovers a supported event loop, the event loop extension is built in addition to the getdns library. Extensions are built as an additional shared library. The following event loop libraries are supported:
.B
libevent1 and libevent2
.LP
The libevent extension allows a context to attach to a event_base. The event loop is then run like any other application using libevent via event_base_dispatch or event_base_loop and expect getdns callbacks to fire.
.LP
Note that if both libevent1 and libevent2 reside on system, the extension uses libevent2.
The libuv extension allows a context to attach to a uv_loop_s. The event loop can then be run like any other application using libuv via uv_run and expect getdns callbacks to fire.
The libev extension allows a context to attach to a ev_loop. The event loop can then be run like any other application using libev via ev_run and expect getdns callbacks to fire.
The event loop integrations documented above all leverage the same event loop extension API provided by this library. The mechanism is exposed to developers who wish to integrate their own event loop. And includes the following functions and structures:
.LP
The application provides a callback to indicate that a timeout has occurred.
The application calls the extension to free a timer. The timer passed in is the same as that returned in the schedule timeout. This is the only place where it is safe to free timer data. Extensions can expect this will be called for every schedule_timeout call.
The application informs the extension that the number of outbound requests has changed. This is called when an asynchronous request is submitted or canceled by the user.
The application tell the extension to free up any data associated with the extension functions. This is called when a context is destroyed, or the extension is being detached.
The following are functions used by the extension entry point to attach to a particular context.
.LP
The application sets an event loop extension on a context. The extension_data is optional data that is passed into the extension methods. If an event loop is already set on a context then it is cleaned up. All outstanding requests are also canceled.
Applications may populate an extension dictionary when making a call to the public entry points. To use an extension add it to the extension dictionary prior to making the call to the public entry point and set the value depending on the behavior you expect. These extensions include:
.HP3
dnssec_return_status (int)
Set to GETDNS_EXTENSION_TRUE to include the DNSSEC status for each DNS record in the replies_tree
.HP3
dnssec_return_only_secure (int)
Set to GETDNS_EXTENSION_TRUE to cause only records that the API can validate as secure withe DNSSEC to be returned in the
.Ireplies_tree
and
.Ireplies_fulllists
.HP3
dnssec_return_supporting_responses (int)
Set to GETDNS_EXTENSION_TRUE to cause the set of additional DNSSEC-related records needed for validation to be returned in the response object as the list named
.Iadditional_dnssec
at the top level of the response object
.HP3
return_both_v4_and_v6 (int)
Set to GETDNS_EXTENSION_TRUE to cause the results of both A and AAAA records for the queried name to be included in the response object.
.HP3
add_opt_parameters (dict)
TBD (complicated)
.HP3
add_warning_for_bad_dns
Set to GETDNS_EXTENSION_TRUE to cause each reply in the
.Ireplies_tree
to contain an additional name whose data type is a list,
.Ibad_dns
which contains zero or more ints that indicate the types of bad DNS found in the reply.
.RS6
.br
GETDNS_BAD_DNS_CNAME_IN_TARGET: query type does not allow a CNAME pointed to a CNAME
.br
GETDNS_BAD_DNS_ALL_NUMERIC_LABEL: one or more labels is all numeric
.br
GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE: query type for other than CNAME returned a CNAME
.RE
.HP3
specify_class (int)
Set to the DNS class number (other than Internet (IN) class desired in query.
.HP3
return_api_information (int)
Set to GETDNS_EXTENSION_TRUE to add the following to the top level of the response object:
.RS6
.br
.Iversion_string
(bindata) : the version string for this version of the getdns API
.br
.Iimplementation_string
(bindata) : string set by this library's implementer as a build or version indicator
.br
.Iresolver_type
(int) : GETDNS_CONTEXT_RECURSING or GETDNS_CONTEXT_STUB depending on how the context is configured
.br
.Iall_context
(dict) : includes names from the context, use with
.Igetdns_pretty_print_dict
(3) for debugging
.RE
.HP3
return_call_debugging (int)
Set to GETDNS_EXTENSION_TRUE to add the name
.Icall_debugging
(list) to the top level of the response object that includes a dict for each call made to the API. TBD: more detail
The callback function contains a pointer to a response object. A response
object is always a dict. The response object always contains at least three
names: replies_full (a list) and replies_tree (a list), and status (an int).
replies_full is a list of DNS replies (each is bindata) as they appear on the
wire. replies_tree is a list of DNS replies (each is a dict) with the various
part of the reply parsed out. status is a status code for the query.
.LP
Because the API might be extended in the future, a response object might also
contain names other than replies_full, replies_tree, and status. Similarly, any
of the dicts described here might be extended in later versions of the API.
Thus, an application using the API must not assume that it knows all possible
names in a dict.
.LP
The following lists the status codes for response objects. Note that, if the
status is that there are no responses for the query, the lists in replies_full
and replies_tree will have zero length.
.HP3
.BGETDNS_RESPSTATUS_GOOD
At least one response was returned
.HP3
.BGETDNS_RESPSTATUS_NO_NAME
Queries for the name yielded all negative responses
.HP3
.BGETDNS_RESPSTATUS_ALL_TIMEOUT
All queries for the name timed out
.HP3
.BGETDNS_RESPSTATUS_NO_SECURE_ANSWERS
The context setting for getting only secure responses was specified, and at least one DNS response was received, but no DNS response was determined to be secure through DNSSEC.
.LP
The top level of replies_tree can optionally have the following names: canonical_name (a bindata), intermediate_aliases (a list), answer_ipv4_address (a bindata), answer_ipv6_address (a bindata), and answer_type (an int).
.LP
The value of canonical_name is the name that the API used for its lookup. It is
in FQDN presentation format. The values in the intermediate_aliases list are
domain names from any CNAME or unsynthesized DNAME found when resolving the
original query. The list might have zero entries if there were no CNAMEs in the
path. These may be useful, for example, for name comparisons when following the
rules in RFC 6125. The value of answer_ipv4_address and answer_ipv6_address
are the addresses of the server from which the answer was received. The value
of answer_type is the type of name service that generated the response. The
values are:
.RS3
GETDNS_NAMETYPE_DNS
Normal DNS (RFC 1035)
GETDNS_NAMETYPE_WINS
The WINS name service (some reference needed)
.RE
.LP
If the call was getdns_address or getdns_address_sync, the top level of
replies_tree has an additional name, just_address_answers (a list). The value
of just_address_answers is a list that contains all of the A and AAAA records
from the answer sections of any of the replies, in the order they appear in the
replies. Each item in the list is a dict with at least two names: address_type
(whose value is a bindata; it is currently either "IPv4" or "IPv6") and
address_data (whose value is a bindata). Note that the
dnssec_return_only_secure extension affects what will appear in the
just_address_answers list. If the DNS returns other
address types, those types will appear in this list as well.
.LP
The API can make service discovery through SRV records easier. If the call was
getdns_service or getdns_service_sync, the top level of replies_tree has an
additional name, srv_addresses (a list). The list is ordered by priority and
weight based on the weighting algorithm in RFC 2782, lowest priority value
first. Each element of the list is dict has at least two names: port and
domain_name. If the API was able to determine the address of the target domain
name (such as from its cache or from the Additional section of responses), the
dict for an element will also contain address_type (whose value is a bindata;
it is currently either "IPv4" or "IPv6") and address_data (whose value is a
bindata). Note that the dnssec_return_only_secure extension affects what will