diff --git a/src/getdns/index.html b/src/getdns/index.html deleted file mode 100644 index 6f67b14c..00000000 --- a/src/getdns/index.html +++ /dev/null @@ -1,2277 +0,0 @@ - -DNS API Description - - - - - - - -

Description of the getdns API

-

Paul Hoffman, Editor

-

Document version: "getdns December 2013"

- -

This document describes a modern asynchronous DNS API. This new API is 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:

- - - -

There is more background into the design and future goals of this API -later in this document.

- -

This document was discussed on the -getdns-api mailing list; future versions of the API might be discussed there as well. -(If you -want to contact the editor off-list, please send mail to paul.hoffman@vpnc.org.)

- -

1. The getdns Async Functions

- -

The API has four async functions:

- - - -

1.1 getdns_general()

- -
getdns_return_t -getdns_general( - struct getdns_context *context, - const char *name, - uint16_t request_type, - struct getdns_dict *extensions, - void *userarg, - getdns_transaction_t *transaction_id, - getdns_callback_t callbackfn -); -
- -

context

-

A pointer to the DNS context that is to be used with this call. DNS contexts are -described later in this document. Note that a context must be created -before calling the function.

- -

*name

-

This is a null-terminted string consisting of either an -ASCII-based domain name to be looked up, or a null-terminted text string that is an IPv4 or IPv6 address. -The values here follow the rules in section 2.1 of RFC 4343 -to allow non-ASCII octets and special characters in labels.

- -

request_type

-

Specifies the RRtype for the query; the RRtype numbers are listed in the IANA -registry. For example, to get the NS records, request_type would be 2. The API also has -defined macros for most of the RRtypes by name; the definition names all start with -"GETDNS_RRTYPE_". For example, to get the NS records, you can also set the -request_type to GETDNS_RRTYPE_NS. -(The full list of request types is always -here.)

- -

*extensions

-

Specifies the extensions for this request; the value may be NULL if there are no -extensions. See the section below for information on how to specify -the extensions used for a request.

- -

*userarg

-

A void* that is passed to the function, which the funciton -returns to the callback function untouched. userarg can be used by the callback -function for any user-specific data needed. This can be NULL.

- -

*transaction_id

-

A pointer to a value that is filled in by the -function to identify the callback being made. -This pointer can be NULL, in which case it is ignored and no value is assigned. -The getdns_cancel_callback() function uses the -transaction_id to determine which callback is to be cancelled. -If the function fails, -transaction_id is set to 0.

- -

*callbackfn

-

A pointer to a callback function that is defined by the application. -Typically, the callback function will do all the processing on the results from -the API. The parameters of the callback are defined below. This really needs -to be a pointer to a function (and not something like NULL); otherwise, the -results are unpredictable.

- -

The async getdns functions return GETDNS_RETURN_GOOD if the call was properly formatted. -It returns GETDNS_RETURN_BAD_DOMAIN_NAME if the API determines that the name passed to -the function was bad, GETDNS_RETURN_BAD_CONTEXT if the context pointer is bad, -GETDNS_RETURN_NO_SUCH_EXTENSION if one or more extensions do not exist, or -GETDNS_RETURN_EXTENSION_MISFORMAT if the contents of one or more of the -extensions is incorrect. All of the return values are given later in this document.

- -

1.2 getdns_address()

- -
getdns_return_t -getdns_address( - struct getdns_context *context, - const char *name, - struct getdns_dict *extensions, - void *userarg, - getdns_transaction_t *transaction_id, - getdns_callback_t callbackfn -); -
- -

There are three critical differences between getdns_address() and -getdns_general() beyond the missing request_type argument:

- - - -

1.3 getdns_hostname()

- -
getdns_return_t -getdns_hostname( - struct getdns_context *context, - struct getdns_dict *address, - struct getdns_dict *extensions, - void *userarg, - getdns_transaction_t *transaction_id, - getdns_callback_t callbackfn -); -
- -

The address is given as a getdns_dict data structure (defined below). The list must -have two names: address_type (whose value is a bindata; it is currently either "IPv4" -or "IPv6" (which are case-sensitive)) and address_data (whose value is a bindata).

- -

1.4 getdns_service()

- -
getdns_return_t -getdns_service( - struct getdns_context *context, - const char *name, - struct getdns_dict *extensions, - void *userarg, - getdns_transaction_t *transaction_id, - getdns_callback_t callbackfn -); -
- -

name must be a domain name for an SRV lookup; the call returns the -relevant SRV information for the name.

- -

1.5 Callback Functions for getdns

- -

A call to the async getdns functions typically returns before any network or file I/O occurs. After -the API marshalls all the needed information, it calls the callback function that was passed by the -application. The callback function might be called at any time, even before the calling function -has returned. The API guarantees that the callback will be called exactly once unless the calling function -returned an error, in which case the callback function is never called.

- -

The getdns calling function calls the callback with the parameters defined -as follows:

-
-typedef void (*getdns_callback_t)( - struct getdns_context *context, - uint16_t callback_type, - struct getdns_dict *response, - void *userarg, - getdns_transaction_t transaction_id); -
- -

context

-

The DNS context that was used in the calling function. See below for a description of the basic use of contexts, and later for more advanced use.

- -

callback_type

-

Supplies the reason for the callback. See below for the codes and reasons.

- -

*response

-

A response object with the response data. This is described below. The response -object is part of the API's memory space, and will be freed by the API with the callback returns.

- -

*userarg

-

Identical to the *userarg passed to the calling function.

- -

transaction_id

-

The transaction identifier that was assigned by the calling function.

- -

The following are the values for callback_type.

- -

GETDNS_CALLBACK_COMPLETE

-

The response has the requested data in it

-

GETDNS_CALLBACK_CANCEL

-

The calling program cancelled the callback; response is NULL

-

GETDNS_CALLBACK_TIMEOUT

-

The requested action timed out; response is NULL

-

GETDNS_CALLBACK_ERROR

-

The requested action had an error; response is NULL

- - -

1.6 Setting Up The DNS Context

- -

Calls to getdns functions require a DNS context, which is a group of API settings -that affect how DNS calls are made. For most applications, a default context is sufficient.

- -

To create a new DNS context, use the function:

- -
getdns_return_t -getdns_context_create( - struct getdns_context **context, - int set_from_os -); -
- -

The call to getdns_context_create immediately returns a context that can -be used with other API calls; that context contains the API's default values. Most applications will -want set_from_os set to 1.

- -
getdns_return_t -getdns_context_create_with_memory_functions( - struct getdns_context **context, - int set_from_os, - void *(*malloc)(size_t), - void *(*realloc)(void *, size_t), - void (*free)(void *) -); -getdns_return_t -getdns_context_create_with_extended_memory_functions( - struct getdns_context **context, - int set_from_os, - void *userarg, - void *(*malloc)(void *userarg, size_t), - void *(*realloc)(void *userarg, void *, size_t), - void (*free)(void *userarg, void *) -); -
- -

To clean up the context, including cleaning up all outstanding transactions that were called -using this context, use the function:

- -
void -getdns_context_destroy( - struct getdns_context *context -); -
- -

When getdns_context_destroy() returns, the -application knows that all outstanding transactions associated with this -context will have been called; callbacks that had not been called before -getdns_context_destroy() was called will be called with a callback_type of -GETDNS_CALLBACK_CANCEL. getdns_context_destroy() returns after -all of the needed cleanup is done and callbacks are made.

- -

1.7 Canceling a Callback

- -

To cancel an outstanding callback, use the following function.

- -
getdns_return_t -getdns_cancel_callback( - struct getdns_context *context, - getdns_transaction_t transaction_id -); -
- -

This causes the API to call the callback with a callback_type of -GETDNS_CALLBACK_CANCEL if the callback for this transaction_id has not -already been called. This will cancel the callback regardless of what the original call was -doing (such as in the middle of a DNS request, while DNSSEC validation is happening, and so on). -The callback code for cancellation should clean up any memory related to the -identified call, such as to deallocate the memory for the userarg. -getdns_cancel_callback() may return immediately, even before the callback finishes its -work and returns. Calling getdns_cancel_callback() with a transaction_id -of a callback that has already been called or an unknown transaction_id returns -GETDNS_RETURN_UNKNOWN_TRANSACTION; otherwise, getdns_cancel_callback() -returns GETDNS_RETURN_GOOD.

- -

1.8 Event-driven Programs

- -

Event-driven programs (sometimes called "async programs") require an event -base and event loop (among other things). Different event libraries have -different structures or the event base. Because of this, there is no standard -method to set the event base in the DNS API: those are all added as -extensions. The API is distributed as a core package and one or more sets of -extensions to align with event libraries. It is mandatory to use one of the extension -functions to set the event base in the DNS context; this is required before -calling any event-driven calls like the getdns functions.

- -

Each implementation of the DNS API will specify an extension function that -tells the DNS context which event base is being used. For example, one -implementation of this API that uses the libevent event library might name -this function "getdns_extension_set_libevent_base()" while -another might name it -"getdns_extension_set_eventbase_for_libevent()"; the two -extension functions could have very different calling patterns and return -values. Thus, the application developer must read the API documentation -(not just this design document) in order to determine what extension function -to use to tell the API the event base to use.

- -

The structure of a typical event-driven application might look like the following pseudocode. -The code in italics is specific to the event mechanism.

- -
-Includes for one or more regular C libraries
-An include for the getdns library specific to the event library you use
-Definition of your callback function
-    Get the DNS data from the allocated pointer
-    Process that data
-    Check for errors
-Definition of main()
-    Create context
-    Set up your event base
-    Point the context to your event base
-    Set up the getdns call arguments
-    Make the getdns call
-    Check if the getdns return is good
-    Destroy the context
-    Exit
-
- -

The API does not have direct support for a polling interface. Instead, the callback interface is -specifically designed to allow an application that wants to process results in polling instead of in -callbacks to be able to create its own polling interface fairly trivially. Such a program would -create a data structure for the calls, including their transaction_id and -userarg. The userarg could be the polling data structure or have a pointer to it. -The application would have just -one callback function for all requests, and that function would copy the response into -application memory, update the data structure based on the transaction_id index, -and return from the callback. The polling code could then check the data structure for any updates -at its leisure.

- -

1.9 Calling the API Synchronously (Without Events)

- -

Thare are functions parallel to the four getdns async functions, -except that there is no callback. That is, when an application calls one of these -synchronous functions, the -API gathers all the required information and then returns the result. The value returned is exactly the -same as the response returned in the callback if you had used the async version of the function.

- -
getdns_return_t -getdns_general_sync( - struct getdns_context *context, - const char *name, - uint16_t request_type, - struct getdns_dict *extensions, - struct getdns_dict **response -); -
- -
getdns_return_t -getdns_address_sync( - struct getdns_context *context, - const char *name, - struct getdns_dict *extensions, - struct getdns_dict **response -); -
- -
getdns_return_t -getdns_hostname_sync( - struct getdns_context *context, - struct getdns_dict *address, - struct getdns_dict *extensions, - struct getdns_dict **response -); -
- -
getdns_return_t -getdns_service_sync( - struct getdns_context *context, - const char *name, - struct getdns_dict *extensions, - struct getdns_dict **response -); -
- -

When you are done with the data in the response, use the following function so that the API can -free the memory from its internal pool.

- -
void
-getdns_dict_destroy(
-  struct getdns_dict     *response
-);
-
- -

2. Data structures in the API

- -

The API returns data structures. The data structure is not a representational language like JSON: -it is really just a data structure. Data structures can have four types of members:

- - - -

The API comes with helper functions to get data from the list and dict data types:

- -
-/* Lists: get the length, get the data_type of the value at a given - position, and get the data at a given position */ -getdns_return_t getdns_list_get_length(struct getdns_list *this_list, size_t *answer); -getdns_return_t getdns_list_get_data_type(struct getdns_list *this_list, size_t index, getdns_data_type *answer); -getdns_return_t getdns_list_get_dict(struct getdns_list *this_list, size_t index, struct getdns_dict **answer); -getdns_return_t getdns_list_get_list(struct getdns_list *this_list, size_t index, struct getdns_list **answer); -getdns_return_t getdns_list_get_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata **answer); -getdns_return_t getdns_list_get_int(struct getdns_list *this_list, size_t index, uint32_t *answer); - -/* Dicts: get the list of names, get the data_type of the - value at a given name, and get the data at a given name */ -getdns_return_t getdns_dict_get_names(struct getdns_dict *this_dict, struct getdns_list **answer); -getdns_return_t getdns_dict_get_data_type(struct getdns_dict *this_dict, char *name, getdns_data_type *answer); -getdns_return_t getdns_dict_get_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict **answer); -getdns_return_t getdns_dict_get_list(struct getdns_dict *this_dict, char *name, struct getdns_list **answer); -getdns_return_t getdns_dict_get_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata **answer); -getdns_return_t getdns_dict_get_int(struct getdns_dict *this_dict, char *name, uint32_t *answer); -
- -

All of these helper getter functions return GETDNS_RETURN_GOOD if the call is successful. -The list functions will return GETDNS_RETURN_NO_SUCH_LIST_ITEM if the index argument is -out of range; the dict functions will return GETDNS_RETURN_NO_SUCH_DICT_NAME if the name -argument doesn't exist in the dict. The functions also return GETDNS_RETURN_WRONG_TYPE_REQUESTED -if the requested data type doesn't match the contents of the indexed argument or name.

- -

This document uses graphical representations of data structures. It is important to note that -this is only a graphical representation; the brackets, commas, quotation marks, comments, and so on -are not part of the data. Also, this document uses macro names instead of some of the int -arguments; of course, the data structures have the actual int in them.

- -

2.1 Creating Data Structures

- -

Some of the features of the API require that you create your own data structures to be used in -arguments passed to the API. For example, if you want to use any extensions for the calling functions, -you need to create a dict. The requisite functions are:

- -
-/* Lists: create, destroy, and set the data at a given position */ -struct getdns_list * getdns_list_create(); -struct getdns_list * getdns_list_create_with_context( - struct getdns_context *context -); -struct getdns_list * getdns_list_create_with_memory_functions( - void *(*malloc)(size_t), - void *(*realloc)(void *, size_t), - void (*free)(void *) -); -struct getdns_list * getdns_list_create_with_extended_memory_functions( - void *userarg, - void *(*malloc)(void *userarg, size_t), - void *(*realloc)(void *userarg, void *, size_t), - void (*free)(void *userarg, void *) -); -void getdns_list_destroy(struct getdns_list *this_list); -getdns_return_t getdns_list_set_dict(struct getdns_list *this_list, size_t index, struct getdns_dict *child_dict); -getdns_return_t getdns_list_set_list(struct getdns_list *this_list, size_t index, struct getdns_list *child_list); -getdns_return_t getdns_list_set_bindata(struct getdns_list *this_list, size_t index, struct getdns_bindata *child_bindata); -getdns_return_t getdns_list_set_int(struct getdns_list *this_list, size_t index, uint32_t child_uint32); - -/* Dicts: create, destroy, and set the data at a given name */ -struct getdns_dict * getdns_dict_create(); -struct getdns_dict * getdns_dict_create_with_context( - struct getdns_context *context -); -struct getdns_dict * getdns_dict_create_with_memory_functions( - void *(*malloc)(size_t), - void *(*realloc)(void *, size_t), - void (*free)(void *) -); -struct getdns_dict * getdns_dict_create_with_extended_memory_functions( - void *userarg, - void *(*malloc)(void *userarg, size_t), - void *(*realloc)(void *userarg, void *, size_t), - void (*free)(void *userarg, void *) -); -void getdns_dict_destroy(struct getdns_dict *this_dict); -getdns_return_t getdns_dict_set_dict(struct getdns_dict *this_dict, char *name, struct getdns_dict *child_dict); -getdns_return_t getdns_dict_set_list(struct getdns_dict *this_dict, char *name, struct getdns_list *child_list); -getdns_return_t getdns_dict_set_bindata(struct getdns_dict *this_dict, char *name, struct getdns_bindata *child_bindata); -getdns_return_t getdns_dict_set_int(struct getdns_dict *this_dict, char *name, uint32_t child_uint32); -getdns_return_t getdns_dict_remove_name(struct getdns_dict *this_dict, char *name); -
- -

Lists are extended with the getdns_list_set_ calls with the index set to the -size of the list (such as 0 for an empty list). Dicts are extended with the getdns_dict_set_ calls -with the name set to a name that does not yet exist. Name-value pairs are removed with -getdns_dict_remove_name().

- -

These helper setter functions return GETDNS_RETURN_GOOD if the call is successful. -The functions return GETDNS_RETURN_WRONG_TYPE_REQUESTED if the requested data type -doesn't match the contents of the indexed argument or name. The list functions will return -GETDNS_RETURN_NO_SUCH_LIST_ITEM if the index argument is higher than the length of the -list. getdns_dict_remove_name() will return -GETDNS_RETURN_NO_SUCH_DICT_NAME if the name argument doesn't exist in the dict.

- -

3. Extensions

- -

Extensions are dict data structures. The names in the dict are the names of the extensions. -The definition of each extension describes the value associated with the name. For most extensions, -it is an on-off boolean, and the value is GETDNS_EXTENSION_TRUE. (There is -not currently a good reason to specify an extension name and give it a value of GETDNS_EXTENSION_FALSE, -but that is allowed by the API.)

- -

For example, to create a dict for extensions and specify the extension to only return -results that have been validated with DNSSEC, you might use:

- -
-/* . . . */
-struct getdns_dict * this_extensions = getdns_dict_create();
-this_ret = getdns_dict_set_int(this_extensions, "dnssec_return_only_secure", GETDNS_EXTENSION_TRUE);
-/* . . . Do some processing with the extensions and results . . . */
-/* Remember to clean up memory*/
-getdns_dict_destroy(this_extensions);
-
- -

The extensions described in this section are are: - -

- -

3.1 Extensions for DNSSEC

- -

If an application wants the API to do DNSSEC validation for a request, it must set one or more -DNSSEC-related extensions. Note that the default is for none of these extensions to be set and -the API will not perform DNSSEC, and thus will return results sooner.

- -

To return the DNSSEC status for each DNS record in the replies_tree list, use the -dnssec_return_status extension. The extension's value (an int) is set to -GETDNS_EXTENSION_TRUE to cause the returned status to have the name -dnssec_status (an int) added to the other names in the record's dict ("header", -"question", and so on). The values for that name are GETDNS_DNSSEC_SECURE, -GETDNS_DNSSEC_BOGUS, GETDNS_DNSSEC_INDETERMINATE, and -GETDNS_DNSSEC_INSECURE. Thus, a reply might look like:

- -
-    {     # This is the first reply
-      "dnssec_status": GETDNS_DNSSEC_INDETERMINATE,
-      "header": { "id": 23456, "qr": 1, "opcode": 0, ... },
-      . . .
-
- -

If instead of returning the status, you want to only see secure results, use the -dnssec_return_only_secure extension. The extension's value (an int) is set to -GETDNS_EXTENSION_TRUE to cause only records that the API can validate as secure with -DNSSEC to be returned in the replies_tree and replies_full lists. No -additional names are added to the dict of the record; the change is that some records might not -appear in the results. When this context option is set, if the API receives DNS replies but none -are determined to be secure, the error code at the top level of the response object is -GETDNS_RESPSTATUS_NO_SECURE_ANSWERS.

- -

Applications that want to do their own validation will want to have the DNSSEC-related records -for a particular response. Use the dnssec_return_supporting_responses extension. The -extension's value (an int) is set to GETDNS_EXTENSION_TRUE to cause a set -of additional DNSSEC-related records needed for validation to be returned in the response object. -This set comes as additional_dnssec (a list) at the top level of the response object. -This list includes any trust anchors needed for the validation. Thus, a reply might look like:

- -
-{     # This is the response object
-  "additional_dnssec": [ <bindata of the first DNSSEC record>, <bindata of the second DNSSEC record> ... ],
-  "replies_tree":
-  [
-  . . .
-
- -

If a request is using a context in which stub resolution is set, and that request also has -any of the dnssec_return_status, dnssec_return_only_secure, or -dnssec_return_supporting_responses extensions specified, the API will not perform -the request and will instead return an error of GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED.

- -

3.2 Returning Both IPv4 and IPv6 Responses

- -

Many applications want to get both IPv4 and IPv6 addresses in a single call so that the results -can be processed together. The getdns_address and getdns_address_sync -functions are able to do this automatically. If you are using the getdns_general or -getdns_general_sync function, you can enable this with the -return_both_v4_and_v6 extension. The extension's value (an int) is set to -GETDNS_EXTENSION_TRUE to cause the results to be the lookup of either A or AAAA records -to include any A and AAAA records for the queried name (otherwise, the extension does nothing). -These results are expected to be used with Happy Eyeballs systems that will find the best socket for -an application.

- -

3.3 Setting Up OPT Resource Records

- -

For lookups that need an OPT resource record in the Additional Data section, use the -add_opt_parameters extension. The extension's value (a dict) contains the -parameters; these are described in more detail in RFC 2671. They are:

- - - -

It is very important to note that the OPT resource record specified in the -add_opt_parameters extension might not be the same the one that the API sends in the -query. For example, if the application also includes any of the DNSSEC extensions, the API will make -sure that the OPT resource record sets the resource record appropriately, making the needed changes -to the settings from the add_opt_parameters extension.

- -

The use of this extension can conflict with the values in the DNS context. For example, -the default for an OS might be a maximum payload size of 65535, but the extension might specify -1550. In such a case, the API will honor the values stated in the extension, but will honor the -values from the DNS context if values are not given in the extension.

- -

3.4 Getting Warnings for Responses that Violate the DNS Standard

- -

To receive a warning if a particular response violates some parts of the DNS standard, use -the add_warning_for_bad_dns extension. The extension's value (an int) is set to -GETDNS_EXTENSION_TRUE to cause each reply in the replies_tree -to contain an additional name, bad_dns (a list). The list is zero or more -ints that indicate types of bad DNS found in that reply. The list of values is: - -

GETDNS_BAD_DNS_CNAME_IN_TARGET

-

A DNS query type that does not allow a target to be a CNAME pointed to a CNAME

-

GETDNS_BAD_DNS_ALL_NUMERIC_LABEL

-

One or more labels in a returned domain name is all-numeric; this is not legal for a hostname

-

GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE

-

A DNS query for a type other than CNAME returned a CNAME response

- - -

3.5 Using Other Class Types

- -

The vast majority of DNS requests are made with the Internet (IN) class. To make a request in a -different DNS class, use, the specify_class extension. The extension's value (an int) -contains the class number. Few applications will ever use this extension.

- -

3.6 Extensions Relating to the API

- -

An application might want to see information about the API itself. Use the -return_api_information extension. An application that wants to get this information -before a "real" query is issued can add this extension to a PTR query for 127.0.0.1. -The extension's value (an int) is set to -GETDNS_EXTENSION_TRUE to add the following to the top level of the response object:

- - - -

An application might want to see debugging information for queries such as the length of time it -takes for each query to return to the API. Use the return_call_debugging extension. The -extension's value (an int) is set to GETDNS_EXTENSION_TRUE to add the name -call_debugging (a list) to the top level of the response object. Each member of the -list is a dict that represents one call made for the call to the API. Each member has the following -names:

- - - -

4. Response Data from Queries

- -

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.

- -

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.

- -

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.

- -

GETDNS_RESPSTATUS_GOOD

-

At least one response was returned

-

GETDNS_RESPSTATUS_NO_NAME

-

Queries for the name yielded all negative responses

-

GETDNS_RESPSTATUS_ALL_TIMEOUT

-

All queries for the name timed out

-

GETDNS_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.

- - -

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).

- - - -

GETDNS_NAMETYPE_DNS

-

Normal DNS (RFC 1035)

-

GETDNS_NAMETYPE_WINS

-

The WINS name service (some reference needed)

- - -

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. Also note if later versions of the -DNS return other address types, those types will appear in this list as well.

- -

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 appear in the -srv_addresses list.

- -

4.1 Structure of DNS replies_tree

- -

The names in each entry in the the replies_tree list for DNS responses include -header (a dict), question (a dict), answer (a list), -authority (a list), and additional (a list), corresponding to the sections -in the DNS message format. The answer, authority, and additional lists each contain zero or more -dicts, with each dict in each list representing a resource record.

- -

The names in the header dict are all the fields from Section 4.1.1. of RFC 1035. -They are: id, qr, opcode, aa, tc, -rd, ra, z, rcode, qdcount, -ancount, nscount, and arcount. All are ints.

- -

The names in the question dict are the three fields from Section 4.1.2. of RFC 1035: -qname (a bindata), qtype (an int), and qclass (an int).

- -

Resource records are a bit different than headers and question sections in that the RDATA portion -often has its own structure. The other names in the resource record dicts are name (a -bindata), type (an int), class (an int), ttl (an int) and -rdata (a dict); there is no name equivalent to the RDLENGTH field.

- -

The rdata dict has different names for each response type. There is a complete list of the types defined in the API. For names that end in -"-obsolete" or "-unknown", the bindata is the entire RDATA field. For example, the -rdata for an A record has a name ipv4_address (a bindata); the -rdata for an SRV record has the names priority (an int), -weight (an int), port (an int), and target (a bindata).

- -

Each rdata dict also has a rdata_raw field (a bindata). This is useful -for types not defined in this version of the API. It also might be of value if a later version of -the API allows for additional parsers. Thus, doing a query for types not known by the API still will -return a result: an rdata with just a rdata_raw.

- -

It is expected that later extensions to the API will give some DNS types different names. It is -also possible that later extensions will change the names for some of the DNS types listed above.

- -

For example, a response to a getdns_address() call for www.example.com would -look something like this:

- -
-{     # This is the response object
-  "replies_full": [ <bindata of the first response>, <bindata of the second response> ],
-  "just_address_answers": [ <bindata of 0x0a0b0c01>, <bindata of 0x33445566334455663344556633445566> ],
-  "canonical_name": <bindata of "www.example.com">,
-  "answer_type": GETDNS_NAMETYPE_DNS,
-  "intermediate_aliases": [],
-  "replies_tree":
-  [
-    {     # This is the first reply
-      "header": { "id": 23456, "qr": 1, "opcode": 0, ... },
-      "question": { "qname": <bindata of "www.example.com">, "qtype": 1, "qclass": 1 },
-      "answer":
-      [
-        {
-          "name": <bindata of "www.example.com">,
-          "type": 1,
-          "class": 1,
-          "ttl": 33000,
-          "rdata":
-          {
-            "ipv4_address": <bindata of 0x0a0b0c01>
-            "rdata_raw": <bindata of 0x0a0b0c01>
-          }
-        }
-      ],
-      "authority":
-      [
-        {
-          "name": <bindata of "ns1.example.com">,
-          "type": 1,
-          "class": 1,
-          "ttl": 600,
-          "rdata":
-          {
-            "ipv4_address": <bindata of 0x65439876>
-            "rdata_raw": <bindata of 0x65439876>
-          }
-        }
-      ]
-      "additional": [],
-      "canonical_name": <bindata of "www.example.com">,
-      "answer_type": GETDNS_NAMETYPE_DNS
-    },
-    {     # This is the second reply
-      "header": { "id": 47809, "qr": 1, "opcode": 0, ... },
-      "question": { "qname": <bindata of "www.example.com">, "qtype": 28, "qclass": 1 },
-      "answer":
-      [
-        {
-          "name": <bindata of "www.example.com">,
-          "type": 28,
-          "class": 1,
-          "ttl": 1000,
-          "rdata":
-          {
-            "ipv6_address": <bindata of 0x33445566334455663344556633445566>
-            "rdata_raw": <bindata of 0x33445566334455663344556633445566>
-          }
-       }
-      ],
-      "authority": [  # Same as for other record... ]
-      "additional": [],
-    },
-  ]
-}
-
- -

In DNS responses, domain names are treated special. RFC 1035 describes a form of name compression -that requires that the entire record be available for analysis. The API deals with this by -converting compressed names into full names when returning names in the replies_tree. -This conversion happens for qname in question; name in the -answer, authority, and additional; and in domain names in the -data in names under rdata where the response type is AFSDB, CNAME, MX, NS, PTR, RP, RT, and SOA.

- -

4.2 Converting Domain Names

- -

Names in DNS fields are stored in a fashion very different from the normal presentation format -normally used in applications. The DNS format is described in the first paragraph in Section 3.1 of -RFC 1035; the presentation format here is a null-terminated string with interior dots. These helper -functions only work with names in the DNS format that are not compressed. They are useful for -converting domain names in the replies_tree to and from the FQDN presentation -format.

- -

getdns_convert_dns_name_to_fqdn() converts a domain name in DNS format to the -presentation format. For example, the hex sequence 03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 -6f 6d 00 would be converted to "www.example.com". -getdns_convert_fqdn_to_dns_name() does the reverse: it converts a null-terminated -string in FQDN format to bytes in DNS format.

- -
-char * -getdns_convert_dns_name_to_fqdn( - char *name_from_dns_response -); - -char * -getdns_convert_fqdn_to_dns_name( - char *fqdn_as_string -); -
- -

5. Additional Definitions and Descriptions

- -

5.1 A Few Needed Definitions

- -
struct getdns_context; -typedef uint16_t getdns_return_t; -typedef uint64_t getdns_transaction_t; -typedef enum getdns_data_type { - t_dict, t_list, t_int, t_bindata -} getdns_data_type; -struct getdns_bindata { - size_t size; - uint8_t *data; -}; -struct getdns_dict; -struct getdns_list; -
- -

5.2 Return Codes

- -

The return codes for all the functions are:

- -

GETDNS_RETURN_GOOD

-

Good

-

GETDNS_RETURN_GENERIC_ERROR

-

Generic error

-

GETDNS_RETURN_BAD_DOMAIN_NAME

-

Badly-formed domain name in first argument

-

GETDNS_RETURN_BAD_CONTEXT

-

Bad value for a context type

-

GETDNS_RETURN_CONTEXT_UPDATE_FAIL

-

Did not update the context

-

GETDNS_RETURN_UNKNOWN_TRANSACTION

-

An attempt was made to cancel a callback with a transaction_id that is not recognized

-

GETDNS_RETURN_NO_SUCH_LIST_ITEM

-

A helper function for lists had an index argument that was too high.

-

GETDNS_RETURN_NO_SUCH_DICT_NAME

-

A helper function for dicts had a name argument that for a name that is not in the dict.

-

GETDNS_RETURN_WRONG_TYPE_REQUESTED

-

A helper function was supposed to return a certain type for an item, but the wrong type was given.

-

GETDNS_RETURN_NO_SUCH_EXTENSION

-

A name in the extensions dict is not a valid extension.

-

GETDNS_RETURN_EXTENSION_MISFORMAT

-

One or more of the extensions have a bad format.

-

GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED

-

A query was made with a context that is using stub resolution and a DNSSEC extension specified.

-

GETDNS_RETURN_MEMORY_ERROR

-

Unable to allocate the memory required.

- - -

5.3 Types of RDATA Returned in the API

- -

The names in the rdata dicts in replies are:

- - -

A (1)

-

ipv4_address (a bindata)

- -

NS (2)

-

nsdname (a bindata)

- -

MD (3)

-

madname (a bindata)

- -

MF (4)

-

madname (a bindata)

- -

CNAME (5)

-

cname (a bindata)

- -

SOA (6)

-

mname (a bindata), rname (a bindata), -serial (an int), refresh (an int), refresh (an int), -retry (an int), and expire (an int)

- -

MB (7)

-

madname (a bindata)

- -

MG (8)

-

mgmname (a bindata)

- -

MR (9)

-

newname (a bindata)

- -

NULL (10)

-

anything (a bindata)

- -

WKS (11)

-

address (a bindata), protocol (an int), -and bitmap (a bindata)

- -

PTR (12)

-

ptrdname (a bindata)

- -

HINFO (13)

-

cpu (a bindata) and os (a bindata)

- -

MINFO (14)

-

rmailbx (a bindata) and emailbx (a bindata)

- -

MX (15)

-

preference (an int) and exchange (a bindata)

- -

TXT (16)

-

txt_strings (a list) which contains zero or more bindata elements -that are text strings

- -

RP (17)

-

mbox_dname (a bindata) and txt_dname (a bindata)

- -

AFSDB (18)

-

subtype (an int) and hostname (a bindata)

- -

X25 (19)

-

psdn_address (a bindata)

- -

ISDN (20)

-

isdn_address (a bindata) and sa (a bindata)

- -

RT (21)

-

preference (an int) and intermediate_host (a bindata)

- -

NSAP (22)

-

nsap (a bindata)

- -

SIG (24)

-

sig_obsolete (a bindata)

- -

KEY (25)

-

key_obsolete (a bindata)

- -

PX (26)

-

preference (an int), map822 (a bindata), and mapx400 (a bindata)

- -

GPOS (27)

-

longitude (a bindata), latitude (a bindata), and altitude (a bindata)

- -

AAAA (28)

-

ipv6_address (a bindata)

- -

LOC (29)

-

loc_obsolete (a bindata)

- -

NXT (30)

-

nxt_obsolete (a bindata)

- -

EID (31)

-

eid_unknown (a bindata)

- -

NIMLOC (32)

-

nimloc_unknown (a bindata)

- -

SRV (33)

-

priority (an int), weight (an int), -port (an int), and target (a bindata)

- -

ATMA (34)

-

format (an int) and address (a bindata)

- -

NAPTR (35)

-

order (an int), preference (an int), flags -(a bindata), service (a bindata), regexp (a bindata), and -replacement (a bindata).

- -

KX (36)

-

preference (an int) and exchanger (a bindata)

- -

CERT (37)

-

type (an int), key_tag (an int), algorithm (an int), -and certificate_or_crl (a bindata)

- -

A6 (38)

-

a6_obsolete (a bindata)

- -

DNAME (39)

-

target (a bindata)

- -

SINK (40)

-

sink_unknown (a bindata)

- -

OPT (41)

-

options (a list). Each element of the options list is a -dict with two names: option_code (an int) and option_data (a bindata).

- -

APL (42)

-

apitems (a list). -Each element of the apitems list is a dict with four names: -address_family (an int), prefix (an int), -n (an int), and afdpart (a bindata)

- -

DS (43)

-

key_tag (an int), algorithm (an int), digest_type (an int), -and digest (a bindata)

- -

SSHFP (44)

-

algorithm (an int), fp_type (an int), -and fingerprint (a bindata)

- -

IPSECKEY (45)

-

algorithm (an int), gateway_type (an int), precedence (an int), -gateway, and public_key (a bindata)

- -

RRSIG (46)

-

type_covered (an int), algorithm (an int), -labels (an int), original_ttl (an int), signature_expiration -(an int), signature_inception (an int), key_tag (an int), -signers_name (a bindata), and signature (a bindata)

- -

NSEC (47)

-

next_domain_name (a bindata) and type_bit_maps (a bindata)

- -

DNSKEY (48)

-

flags (an int), protocol (an int), algorithm (an int), -and public_key (a bindata)

- -

DHCID (49)

-

dhcid_opaque (a bindata)

- -

NSEC3 (50)

-

hash_algorithm (an int), flags (an int), -iterations (an int), salt (a bindata), -next_hashed_owner_name (a bindata), and -type_bit_maps (a bindata)

- -

NSEC3PARAM (51)

-

hash_algorithm (an int), flags (an int), -iterations (an int), and -salt (a bindata)

- -

TLSA (52)

-

certificate_usage (an int), selector (an int), -matching_type (an int), and certificate_association_data (a -bindata).

- -

HIP (55)

-

pk_algorithm (an int), -hit (a bindata), public_key -(a bindata), and rendezvous_servers (a list) with each element a bindata with the dname of the rendezvous_server.

- -

NINFO (56)

-

ninfo_unknown (a bindata)

- -

RKEY (57)

-

rkey_unknown (a bindata)

- -

TALINK (58)

-

talink_unknown (a bindata)

- -

CDS (59)

-

cds_unknown (a bindata)

- -

SPF (99)

-

text (a bindata)

- -

UINFO (100)

-

uinfo_unknown (a bindata)

- -

UID (101)

-

uid_unknown (a bindata)

- -

GID (102)

-

gid_unknown (a bindata)

- -

UNSPEC (103)

-

unspec_unknown (a bindata)

- -

NID (104)

-

preference (an int) and -node_id (a bindata)

- -

L32 (105)

-

preference (an int) and locator32 (a bindata)

- -

L64 (106)

-

preference (an int) and locator64 (a bindata)

- -

LP (107)

-

preference (an int) and fqdn (a bindata)

- -

EUI48 (108)

-

eui48_address (a bindata)

- -

EUI64 (109)

-

eui64_address (a bindata)

- -

TKEY (249)

-

algorithm (a bindata), inception (an int), -expiration (an int), mode (an int), error (an int), -key_data (a bindata), and other_data (a bindata)

- -

TSIG (250)

-

algorithm (a bindata), time_signed (a bindata), -fudge (an int), mac (a bindata), original_id (an int), -error (an int), and other_data (a bindata)

- -

MAILB (253)

-

mailb-unknown (a bindata)

- -

MAILA (254)

-

maila-unknown (a bindata)

- -

URI (256)

-

priority (an int), weight (an int), -and target (a bindata)

- -

CAA (257)

-

flags (an int), tag (a bindata), and value (a bindata)

- -

TA (32768)

-

ta_unknown (a bindata)

- -

DLV (32769)

-

Identical to DS (43)

- - -

6. Examples

- -

This section gives examples of code that calls the API to do many common tasks. -The purpose of the code here is to give application developers a quick hands-on -demo of using the API.

- -

Note that the examples here all use getdns_libevent.h as the include that will call in the API -code as well as calling in libevent as the event library. They also use -getdns_context_set_libevent_base() as the name of the function to set the event base in -the DNS context. If you are using a different event library, you will of course use a different -#include at the beginning of your code, and a different name for the event base -function.

- -

6.1 Get Both IPv4 and IPv6 Addresses for a Domain Name Using Quick Results

- -

This is an example of a common call to getdns_address().

- -
#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <getdns_libevent.h>
-
-#define UNUSED_PARAM(x) ((void)(x))
-
-/* Set up the callback function, which will also do the processing of the results */
-void this_callbackfn(struct getdns_context *this_context,
-                     uint16_t     this_callback_type,
-                     struct getdns_dict *this_response, 
-                     void *this_userarg,
-                     getdns_transaction_t this_transaction_id)
-{
-    UNUSED_PARAM(this_userarg);  /* Not looking at the userarg for this example */
-    UNUSED_PARAM(this_context);  /* Not looking at the context for this example */
-    getdns_return_t this_ret;  /* Holder for all function returns */
-    if (this_callback_type == GETDNS_CALLBACK_COMPLETE)  /* This is a callback with data */
-    {
-        /* Be sure the search returned something */
-        uint32_t this_error;
-        this_ret = getdns_dict_get_int(this_response, "status", &this_error);  // Ignore any error
-        if (this_error != GETDNS_RESPSTATUS_GOOD)  // If the search didn't return "good"
-        {
-            fprintf(stderr, "The search had no results, and a return value of %d. Exiting.\n", this_error);
-            getdns_dict_destroy(this_response);
-            return;
-        }
-        struct getdns_list * just_the_addresses_ptr;
-        this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr);
-        if (this_ret != GETDNS_RETURN_GOOD)  // This check is really not needed, but prevents a compiler error under "pedantic"
-        {
-            fprintf(stderr, "Trying to get the answers failed: %d\n", this_ret);
-            getdns_dict_destroy(this_response);
-            return;
-        }
-        size_t num_addresses;
-        this_ret = getdns_list_get_length(just_the_addresses_ptr, &num_addresses);  // Ignore any error
-        /* Go through each record */
-        for ( size_t rec_count = 0; rec_count < num_addresses; ++rec_count )
-        {
-            struct getdns_dict * this_address;
-            this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address);  // Ignore any error
-            /* Just print the address */
-            struct getdns_bindata * this_address_data;
-            this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data); // Ignore any error
-            char *this_address_str = getdns_display_ip_address(this_address_data);
-            printf("The address is %s\n", this_address_str);
-            free(this_address_str);
-        }
-    }
-    else if (this_callback_type == GETDNS_CALLBACK_CANCEL)
-        fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.\n", this_transaction_id);
-    else
-        fprintf(stderr, "The callback got a callback_type of %d. Exiting.\n", this_callback_type);
-    getdns_dict_destroy(this_response);
-}
-
-int main()
-{
-    /* Create the DNS context for this call */
-    struct getdns_context *this_context = NULL;
-    getdns_return_t context_create_return = getdns_context_create(&this_context, 1);
-    if (context_create_return != GETDNS_RETURN_GOOD)
-    {
-        fprintf(stderr, "Trying to create the context failed: %d", context_create_return);
-        return(GETDNS_RETURN_GENERIC_ERROR);
-    }
-    /* Create an event base and put it in the context using the unknown function name */
-    struct event_base *this_event_base;
-    this_event_base = event_base_new();
-    if (this_event_base == NULL)
-    {
-        fprintf(stderr, "Trying to create the event base failed.\n");
-        getdns_context_destroy(this_context);
-        return(GETDNS_RETURN_GENERIC_ERROR);
-    }
-    (void)getdns_extension_set_libevent_base(this_context, this_event_base);
-    /* Set up the getdns call */
-    const char * this_name  = "www.example.com";
-    char* this_userarg = "somestring"; // Could add things here to help identify this call
-    getdns_transaction_t this_transaction_id = 0;
-
-    /* Make the call */
-    getdns_return_t dns_request_return = getdns_address(this_context, this_name,
-        NULL, this_userarg, &this_transaction_id, this_callbackfn);
-    if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
-    {
-        fprintf(stderr, "A bad domain name was used: %s. Exiting.\n", this_name);
-        event_base_free(this_event_base);
-        getdns_context_destroy(this_context);
-        return(GETDNS_RETURN_GENERIC_ERROR);
-    }
-    else
-    {
-        /* Call the event loop */
-        int dispatch_return = event_base_dispatch(this_event_base);
-        UNUSED_PARAM(dispatch_return);
-        // TODO: check the return value above
-    }
-    /* Clean up */
-    event_base_free(this_event_base);
-    getdns_context_destroy(this_context);
-    /* Assuming we get here, leave gracefully */
-    exit(EXIT_SUCCESS);
-}
-
- - - -

6.2 Get IPv4 and IPv6 Addresses for a Domain Name

- -

This example is similar to the previous one, except that it retrieves more information than just -the addresses, so it traverses the replies_tree. In this case, it gets both the addresses and -their TTLs.

- -
#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <getdns_libevent.h>
-
-#define UNUSED_PARAM(x) ((void)(x))
-
-/* Set up the callback function, which will also do the processing of the results */
-void this_callbackfn(struct getdns_context *this_context,
-                     getdns_return_t this_callback_type,
-                     struct getdns_dict *this_response, 
-                     void *this_userarg,
-                     getdns_transaction_t this_transaction_id)
-{
-    UNUSED_PARAM(this_userarg);  /* Not looking at the userarg for this example */
-    UNUSED_PARAM(this_context);  /* Not looking at the context for this example */
-    getdns_return_t this_ret;  /* Holder for all function returns */
-    if (this_callback_type == GETDNS_CALLBACK_COMPLETE)  /* This is a callback with data */
-    {
-        /* Be sure the search returned something */
-        uint32_t this_error;
-        this_ret = getdns_dict_get_int(this_response, "status", &this_error);  // Ignore any error
-        if (this_error != GETDNS_RESPSTATUS_GOOD)  // If the search didn't return "good"
-        {
-            fprintf(stderr, "The search had no results, and a return value of %d. Exiting.\n", this_error);
-            getdns_dict_destroy(this_response);
-            return;
-        }
-        /* Find all the answers returned */
-        struct getdns_list * these_answers;
-        this_ret = getdns_dict_get_list(this_response, "replies_tree", &these_answers);
-        if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME)
-        {
-            fprintf(stderr, "Weird: the response had no error, but also no replies_tree. Exiting.\n");
-            getdns_dict_destroy(this_response);
-            return;
-        }
-        size_t num_answers;
-        this_ret = getdns_list_get_length(these_answers, &num_answers);
-        /* Go through each answer */
-        for ( size_t rec_count = 0; rec_count < num_answers; ++rec_count )
-        {
-            struct getdns_dict * this_record;
-            this_ret = getdns_list_get_dict(these_answers, rec_count, &this_record);  // Ignore any error
-            /* Get the answer section */
-            struct getdns_list * this_answer;
-            this_ret = getdns_dict_get_list(this_record, "answer", &this_answer);  // Ignore any error
-            /* Get each RR in the answer section */
-            size_t num_rrs;
-            this_ret = getdns_list_get_length(this_answer, &num_rrs);
-            for ( size_t rr_count = 0; rr_count < num_rrs; ++rr_count )
-            {
-                struct getdns_dict *this_rr = NULL;
-                this_ret = getdns_list_get_dict(this_answer, rr_count, &this_rr);  // Ignore any error
-                /* Get the RDATA */
-                struct getdns_dict * this_rdata = NULL;
-                this_ret = getdns_dict_get_dict(this_rr, "rdata", &this_rdata);  // Ignore any error
-                /* Get the RDATA type */
-                uint32_t this_type;
-                this_ret = getdns_dict_get_int(this_rr, "type", &this_type);  // Ignore any error
-                /* If it is type A or AAAA, print the value */
-                if (this_type == GETDNS_RRTYPE_A)
-                {
-                    struct getdns_bindata * this_a_record = NULL;
-                    this_ret = getdns_dict_get_bindata(this_rdata, "ipv4_address", &this_a_record);
-                    if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME)
-                    {
-                        fprintf(stderr, "Weird: the A record at %d in record at %d had no address. Exiting.\n",
-                            (int) rr_count, (int) rec_count);
-                        getdns_dict_destroy(this_response);
-                        return;
-                    }
-                    char *this_address_str = getdns_display_ip_address(this_a_record);
-                    printf("The IPv4 address is %s\n", this_address_str);
-                    free(this_address_str);
-                }
-                else if (this_type == GETDNS_RRTYPE_AAAA)
-                {
-                    struct getdns_bindata * this_aaaa_record = NULL;
-                    this_ret = getdns_dict_get_bindata(this_rdata, "ipv6_address", &this_aaaa_record);
-                    if (this_ret == GETDNS_RETURN_NO_SUCH_DICT_NAME)
-                    {
-                        fprintf(stderr, "Weird: the AAAA record at %d in record at %d had no address. Exiting.\n",
-                            (int) rr_count, (int) rec_count);
-                        getdns_dict_destroy(this_response);
-                        return;
-                    }
-                    char *this_address_str = getdns_display_ip_address(this_aaaa_record);
-                    printf("The IPv6 address is %s\n", this_address_str);
-                    free(this_address_str);
-                }
-            }
-        }
-    }
-    else if (this_callback_type == GETDNS_CALLBACK_CANCEL)
-        fprintf(stderr, "The callback with ID %"PRIu64" was cancelled. Exiting.\n", this_transaction_id);
-    else
-        fprintf(stderr, "The callback got a callback_type of %d. Exiting.\n", this_callback_type);
-    getdns_dict_destroy(this_response);
-}
-
-int main()
-{
-    /* Create the DNS context for this call */
-    struct getdns_context *this_context = NULL;
-    getdns_return_t context_create_return = getdns_context_create(&this_context, 1);
-    if (context_create_return != GETDNS_RETURN_GOOD)
-    {
-        fprintf(stderr, "Trying to create the context failed: %d\n", context_create_return);
-        return(GETDNS_RETURN_GENERIC_ERROR);
-    }
-    /* Create an event base and put it in the context using the unknown function name */
-    struct event_base *this_event_base;
-    this_event_base = event_base_new();
-    if (this_event_base == NULL)
-    {
-        fprintf(stderr, "Trying to create the event base failed.\n");
-        getdns_context_destroy(this_context);
-        return(GETDNS_RETURN_GENERIC_ERROR);
-    }
-    (void)getdns_extension_set_libevent_base(this_context, this_event_base);
-    /* Set up the getdns call */
-    const char * this_name  = "www.example.com";
-    char* this_userarg = "somestring"; // Could add things here to help identify this call
-    getdns_transaction_t this_transaction_id = 0;
-
-    /* Make the call */
-    getdns_return_t dns_request_return = getdns_address(this_context, this_name,
-        NULL, this_userarg, &this_transaction_id, this_callbackfn);
-    if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
-    {
-        fprintf(stderr, "A bad domain name was used: %s. Exiting.\n", this_name);
-        event_base_free(this_event_base);
-        getdns_context_destroy(this_context);
-        return(GETDNS_RETURN_GENERIC_ERROR);
-    }
-    else
-    {
-        /* Call the event loop */
-        int dispatch_return = event_base_dispatch(this_event_base);
-        UNUSED_PARAM(dispatch_return);
-        // TODO: check the return value above
-    }
-    /* Clean up */
-    event_base_free(this_event_base);
-    getdns_context_destroy(this_context);
-    /* Assuming we get here, leave gracefully */
-    exit(EXIT_SUCCESS);
-}
-
- - - -

6.3 Get Addresses for a Domain Name And Their Associated DNSSEC Validation Status

- -

This example shows how to check for secure DNSSEC results using the -dnssec_return_status extension. In the innermost loop of the -callback function, add a check for the DNSSEC status. It shows how to add two -extensions to the extensions argument of the call.

- -
-struct getdns_dict * this_extensions = getdns_dict_create();
-this_ret = getdns_dict_set_int(this_extensions, "return_both_v4_and_v6", GETDNS_EXTENSION_TRUE);
-this_ret = getdns_dict_set_int(this_extensions, "dnssec_return_status", GETDNS_EXTENSION_TRUE);
-. . .
-if (*this_type == GETDNS_RRTYPE_A)
-{
-    uint32_t * this_dnssec_status;
-    this_ret = getdns_dict_get_int(this_rdata, "dnssec_status", this_dnssec_status);
-    if (&this_dnssec_status != GETDNS_DNSSEC_SECURE)
-    {
-        // Log the DNSSEC status somewhere
-    }
-    else
-    {
-        // Deal with the record however you were going to
-    }
-}
-. . .
-
- -

You can put the DNSSEC status check outside the check for the particular type of record you care about, but -you will then get log messages for bad status on records you might not care about as well.

- -

6.4 Using the API Synchronously with getdns_sync_request()

- -

This example is the same as the earlier examples, but uses getdns_general_sync() -and thus does not use the async code. Note that the processing of the answers is essentially the same -as it is for the synchronous example, it is just done in main().

- -
#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <inttypes.h>
-#include <getdns_core_only.h>
-
-int main()
-{
-    getdns_return_t this_ret;  /* Holder for all function returns */
-    /* Create the DNS context for this call */
-    struct getdns_context *this_context = NULL;
-    getdns_return_t context_create_return = getdns_context_create(&this_context, 1);
-    if (context_create_return != GETDNS_RETURN_GOOD)
-    {
-        fprintf(stderr, "Trying to create the context failed: %d\n", context_create_return);
-        return(GETDNS_RETURN_GENERIC_ERROR);
-    }
-    /* Set up the getdns_sync_request call */
-    const char * this_name  = "www.example.com";
-    uint8_t this_request_type = GETDNS_RRTYPE_A;
-    /* Get the A and AAAA records */
-    struct getdns_dict * this_extensions = getdns_dict_create();
-    this_ret = getdns_dict_set_int(this_extensions, "return_both_v4_and_v6", GETDNS_EXTENSION_TRUE);
-    if (this_ret != GETDNS_RETURN_GOOD)
-    {
-        fprintf(stderr, "Trying to set an extension do both IPv4 and IPv6 failed: %d\n", this_ret);
-        getdns_dict_destroy(this_extensions);
-        getdns_context_destroy(this_context);
-        return(GETDNS_RETURN_GENERIC_ERROR);
-    }
-    struct getdns_dict * this_response = NULL;
-
-    /* Make the call */
-    getdns_return_t dns_request_return = getdns_general_sync(this_context, this_name, this_request_type,
-        this_extensions, &this_response);
-    if (dns_request_return == GETDNS_RETURN_BAD_DOMAIN_NAME)
-    {
-        fprintf(stderr, "A bad domain name was used: %s. Exiting.\n", this_name);
-        getdns_dict_destroy(this_response);
-        getdns_dict_destroy(this_extensions);
-        getdns_context_destroy(this_context);
-        return(GETDNS_RETURN_GENERIC_ERROR);
-    }
-    else
-    {
-        /* Be sure the search returned something */
-        uint32_t this_error;
-        this_ret = getdns_dict_get_int(this_response, "status", &this_error);  // Ignore any error
-        if (this_error != GETDNS_RESPSTATUS_GOOD)  // If the search didn't return "good"
-        {
-            fprintf(stderr, "The search had no results, and a return value of %d. Exiting.\n", this_error);
-            getdns_dict_destroy(this_response);
-            getdns_dict_destroy(this_extensions);
-            getdns_context_destroy(this_context);
-            return(GETDNS_RETURN_GENERIC_ERROR);
-        }
-        struct getdns_list * just_the_addresses_ptr;
-        this_ret = getdns_dict_get_list(this_response, "just_address_answers", &just_the_addresses_ptr);  // Ignore any error
-        size_t num_addresses;
-        this_ret = getdns_list_get_length(just_the_addresses_ptr, &num_addresses);  // Ignore any error
-        /* Go through each record */
-        for ( size_t rec_count = 0; rec_count < num_addresses; ++rec_count )
-        {
-            struct getdns_dict * this_address;
-            this_ret = getdns_list_get_dict(just_the_addresses_ptr, rec_count, &this_address);  // Ignore any error
-            /* Just print the address */
-            struct getdns_bindata * this_address_data;
-            this_ret = getdns_dict_get_bindata(this_address, "address_data", &this_address_data); // Ignore any error
-            char *this_address_str = getdns_display_ip_address(this_address_data);
-            printf("The address is %s\n", this_address_str);
-            free(this_address_str);
-        }
-    }
-    /* Clean up */
-    getdns_dict_destroy(this_response); 
-    getdns_dict_destroy(this_extensions);
-    getdns_context_destroy(this_context);
-    /* Assuming we get here, leave gracefully */
-    exit(EXIT_SUCCESS);
-}
-
- - - -

6.5 Getting Names from the Reverse Tree with getdns_hostname()

- -

This example shows how to use getdns_hostname() to get names from the DNS reverse tree.

- -

[[[[ Something will go here soon ]]]]]

- - -

7. More Helper Functions

- -

The following two functions convert individual labels of IDNs between their Unicode -encoding and their ASCII encoding. They follow the rules for IDNA 2008 described in -RFC 5890-5892.

-
char * -getdns_convert_ulabel_to_alabel( - char *ulabel -); -
-
char * -getdns_convert_alabel_to_ulabel( - char *alabel -); -
- -

If an application wants the API do perform DNSSEC validation without using the extensions, it -can use the getdns_validate_dnssec() helper function.

-
getdns_return_t -getdns_validate_dnssec( - struct getdns_bindata *record_to_validate, - struct getdns_list *bundle_of_support_records, - struct getdns_list *trust_anchor_rdatas -); -
-

The record_to_validate is the resource record being validated. The API -will use the resource records in bundle_of_support_records and the RDATAs in the -trust_ancor_rdatas as trust anchors. The function returns one of -GETDNS_DNSSEC_SECURE, GETDNS_DNSSEC_BOGUS, -GETDNS_DNSSEC_INDETERMINATE, or GETDNS_DNSSEC_INSECURE.

- -

There are two functions that help process data:

- -
-char * -getdns_pretty_print_dict( - struct getdns_dict *some_dict -); -
-

This returns a string that is the nicely-formatted version -of the dict and all of the named elements in it.

- -
-char * -getdns_display_ip_address( - struct getdns_bindata *bindata_of_ipv4_or_ipv6_address -); -
-

This returns a string that is the nicely-formatted version -of the IPv4 or IPv6 address in it. The API determines they type of address -by the length given in the bindata.

- -

8. DNS Contexts

- -

Many calls in the DNS API require a DNS context. A DNS -context contains the information that the API needs in order to process DNS calls, such as the -locations of upstream DNS servers, DNSSEC trust anchors, and so on. The internal structure of the -DNS context is opaque, and might be different on each OS. When a context is passed to any function, -it must be an allocated context; the context must not be NULL.

- -

A typical application using this API doesn't need to know anything about contexts. Basically, -the application creates a default context, uses it in the functions that require a context, and -then deallocates it when done. Context manipulation is available for more DNS-aware programs, -but is unlikely to be of interest to applications that just want the results of lookups for -A, AAAA, SRV, and PTR records.

- -

It is expected that contexts in implementations of the API will not necessarily be thread-safe, -but they will not be thread-hostile. A context should not be used by multiple threads: create a new -context for use on a different thread. It is just fine for an application to have many contexts, -and some DNS-heavy applications will certainly want to have many even if the application uses -a single thread.

- -

See above for the method for creating and destroying -contexts. When the context is used in the API for the first time and set_from_os is -1, the API starts replacing some of the values with values from the OS, such as -those that would be found in res_query(3), /etc/resolv.conf, and so on, then proceeds with the new -function. Some advanced users will not want the API to change the values to the OS's defaults; if -set_from_os is 0, the API will not do any updates to the initial -values based on changes in the OS. For example, this might be useful if the API is acting -as a stub resolver that is using a specific upstream recursive resolver chosen by the -application, not the one that might come back from DHCP.

- -

8.1 Updating the Context Automatically

- -

The context returned by getdns_context_create() is updated by the API by default, -such as when changes are made to /etc/resolv.conf. When there is a change, the callback function -that is set in getdns_context_set_context_update_callback() (described below) is -called.

- -

Many of the defaults for a context come from the operating system under which the API is running. -In specific, it is important that the implementation should try to replicate as best as possible the -logic of a local getaddrinfo() when creating a new context. This includes making -lookups in WINS for NetBIOS, mDNS lookups, nis names, and any other name lookup that -getaddrinfo() normally does automatically. The API should look at nsswitch, the Windows -resolver, and so on.

- -

In the function definitions below, the choice listed in bold is the one used -for the API default context.

- -

8.2 Updating the Context Manually

- -

Setting specific values in a context are done with value-specific -functions shown here. The setting functions all return either GETDNS_RETURN_GOOD for -success, GETDNS_RETURN_BAD_CONTEXT for trying to set a type with a value that -is not allowed, or GETDNS_RETURN_CONTEXT_UPDATE_FAIL for a failure to update the context.

- -

An application can be notified when the context is changed.

- -
-getdns_return_t -getdns_context_set_context_update_callback( - struct getdns_context *context, - void (*value)(struct getdns_context *context, uint16_t changed_item) -);
-

The value is a pointer to the callback function that will be -called when any context is changed. Such changes might be from automatic -changes from the API (such as changes to /etc/resolv.conf), or might be from any of the -API functions in this section being called. The second argument to the callback function -specifies which of the context changed; the context codes are listed -later in this document.

- -

8.3 Contexts for Basic Resolution

- -
-getdns_return_t -getdns_context_set_resolution_type( - struct getdns_context *context, - uint16_t value -);
-

Specifies whether DNS queries are performed with nonrecurive lookups or -as a stub resolver. The value is GETDNS_CONTEXT_RECURSING or -GETDNS_CONTEXT_STUB.

- -

All implementations of this API can act as recursive resolvers, and that must be the -default mode of the default context. -Some implementations of this API are expected to also be able to act as stub resolvers. -If an -implementation of this API is only able to act as a recursive resolver, a call to -getdns_context_set_resolution_type(somecontext, GETDNS_CONTEXT_STUB) will -return GETDNS_RETURN_CONTEXT_UPDATE_FAIL.

- -
-getdns_return_t -getdns_context_set_namespaces( - struct getdns_context *context, - size_t namespace_count, - uint16_t *namespaces -);
-

The namespaces array contains an ordered list -of namespaces that will be queried. -Important: this context setting is ignored for the getdns_general and -getdns_general_sync functions; it is used for the other funtions. -The values -are GETDNS_CONTEXT_NAMESPACE_DNS, -GETDNS_CONTEXT_NAMESPACE_LOCALNAMES, -GETDNS_CONTEXT_NAMESPACE_NETBIOS, -GETDNS_CONTEXT_NAMESPACE_MDNS, and -GETDNS_CONTEXT_NAMESPACE_NIS. When a normal lookup is done, -the API does the lookups in the order given and stops when it gets the -first result; a different method with the same result would be to run -the queries in parallel and return when it gets the first result. -Because lookups might be done over different mechanisms because of the -different namespaces, there can be information leakage that is similar -to that seen with getaddrinfo(). The -default is determined by the OS.

- -
-getdns_return_t -getdns_context_set_dns_transport( - struct getdns_context *context, - uint16_t value -);
-

Specifies what transport is used for DNS lookups. -The value is -GETDNS_CONTEXT_UDP_FIRST_AND_FALL_BACK_TO_TCP, -GETDNS_CONTEXT_UDP_ONLY, -GETDNS_CONTEXT_TCP_ONLY, or -GETDNS_CONTEXT_TCP_ONLY_KEEP_CONNECTIONS_OPEN.

- -
-getdns_return_t -getdns_context_set_limit_outstanding_queries( - struct getdns_context *context, - uint16_t limit -);
-

Specifies limit the number of outstanding DNS queries. -The API will block itself from sending more queries if it is about to exceed -this value, and instead keep those queries in an internal queue. -The a value of 0 indicates that -the number of outstanding DNS queries is unlimited.

- -
-getdns_return_t -getdns_context_set_timeout( - struct getdns_context *context, - uint16_t timeout -);
-

Specifies number of seconds the API will wait for request to return. -The default is not specified.

- -

8.4 Context for Recursive Resolvers

- -
-getdns_return_t -getdns_context_set_follow_redirects( - struct getdns_context *context, - uint16_t value -);
-

Specifies whether or not DNS queries follow redirects. -The value is GETDNS_CONTEXT_FOLLOW_REDIRECTS for normal -following of redirects though CNAME and DNAME; or -GETDNS_CONTEXT_DO_NOT_FOLLOW_REDIRECTS to cause any lookups that would have gone -through CNAME and DNAME to return the CNAME or DNAME, not the eventual target.

- -
-getdns_return_t -getdns_context_set_dns_root_servers( - struct getdns_context *context, - struct getdns_list *addresses -);
-

The list contains dicts that are addresses to be used for looking up top-level -domains; the default is the list of "normal" IANA root servers. Each dict in the list -contains 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).

- -

8.5 Context for Local Naming

- -
-getdns_return_t -getdns_context_set_append_name( - struct getdns_context *context, - uint16_t value -);
-

Specifies whether to append a suffix to the query string -before the API starts resolving a name. -The value is -GETDNS_CONTEXT_APPEND_NAME_ALWAYS, -GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE, -GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE, -or GETDNS_CONTEXT_DO_NOT_APPEND_NAMES. This controls -whether or not to append the suffix given by getdns_context_set_suffix

- -
-getdns_return_t -getdns_context_set_suffix( - struct getdns_context *context, - struct getdns_list *value -);
-

The value is a list of bindatas that are strings that are -to be appended based on getdns_context_set_append_name; the default is an empty list. The values here follow the rules in section 2.1 of RFC 4343 -to allow non-ASCII octets and special characters in labels.

- -

8.6 Context for DNSSEC

- -

These context settings affect queries that have extensions that specify the use of DNSSEC.

- -

Applications that need to specify the DNSSEC trust anchors can use:

-
-getdns_return_t -getdns_context_set_dnssec_trust_anchors( - struct getdns_context *context, - struct getdns_list *value -);
-

The value is a list of bindatas that are the DNSSEC trust anchors. The default -is the trust anchors from the IANA root. The trust anchors -are expressed as RDATAs from DNSKEY resource records.

- -

In the rare case that an application needs to set the DNSSEC skew, it can:

-
-getdns_return_t -getdns_context_set_dnssec_allowed_skew( - struct getdns_context *context, - uint16_t value -);
-

The value is the number of seconds of skew that is allowed in either direction when -checking an RRSIG's Expiration and Inception fields. The default -is 0.

- -

8.7 Context Specific to Stub Resolvers

- -

An application can change the quering mechanism of a context to be to act as a stub -resolver. Such an application might first get the default information to make this change -from the operating system, probably through DHCP.

- -

Note that if a context is changed to being a stub resolver, this automatically prevents the application -from using the extenstions for DNSSEC. An application that wants to both do DNSSEC and stub resolution -must do its own DNSSEC processing, possibly with the getdns_validate_dnssec() function.

- -
-getdns_return_t -getdns_context_set_stub_resolution( - struct getdns_context *context, - struct getdns_list *upstream_list -);
-

The list of dicts define where a stub resolver will send queries. Each dict contains -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). It might also contain -port to specify which port to use to contact these DNS servers; the default is 53. If -the stub and a recursive resolver both support TSIG (RFC 2845), the upstream_list entry -can also contain tsig_algorithm (a bindata) that is the name of the TSIG hash -algorithm, and tsig_secret (a bindata) that is the TSIG key.

- -

8.8 Context for EDNS

- -

These context settings affect queries that have extensions that specify the use of OPT resource records. -These come from RFC 2671.

- -
-getdns_return_t -getdns_context_set_edns_maximum_udp_payload_size( - struct getdns_context *context, - uint16_t value -);
-

The value is between 512 and 65535; the default -is 512.

- -
-getdns_return_t -getdns_context_set_edns_extended_rcode( - struct getdns_context *context, - uint8_t value -);
-

The value is between 0 and 255; the default -is 0.

- -
-getdns_return_t -getdns_context_set_edns_version( - struct getdns_context *context, - uint8_t value -);
-

The value is between 0 and 255; the default -is 0.

- -
-getdns_return_t -getdns_context_set_edns_do_bit( - struct getdns_context *context, - uint8_t value -);
-

The value is between 0 and 1; the default -is 0.

- -

8.9 Context Use of Custom Memory Management Functions

- -
-getdns_return_t -getdns_context_set_memory_functions( - struct getdns_context *context, - void *(*malloc) (size_t), - void *(*realloc) (void *, size_t), - void (*free) (void *) -);
-

The given memory management functions will be used for creating the response dicts. -The response dicts inherit the custom memory management functions from the context and will deallocate themselves (and their members) with the custom deallocator. -By default, the system malloc, realloc, and free are used.

- -
-getdns_return_t -getdns_context_set_extended_memory_functions( - struct getdns_context *context, - void *userarg, - void *(*malloc)(void *userarg, size_t sz), - void *(*realloc)(void *userarg, void *ptr, size_t sz), - void (*free)(void *userarg, void *ptr) -);
-

The given extended memory management functions will be used for creating the response dicts. -The value of userarg argument will be passed to the custom malloc, realloc, and free. -The response dicts inherit the custom memory management functions and the value for userarg from the context and will deallocate themselves (and their members) with the custom deallocator.

- -

8.10 Context Codes

- -

The context codes for getdns_context_set_context_update_callback() are:

- -

GETDNS_CONTEXT_CODE_NAMESPACES

-

Change related to getdns_context_set_namespaces

-

GETDNS_CONTEXT_CODE_RESOLUTION_TYPE

-

Change related to getdns_context_set_resolution_type

-

GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS

-

Change related to getdns_context_set_follow_redirects

-

GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS

-

Change related to getdns_context_set_upstream_recursive_servers

-

GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS

-

Change related to getdns_context_set_dns_root_servers

-

GETDNS_CONTEXT_CODE_DNS_TRANSPORT

-

Change related to getdns_context_set_dns_transport

-

GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES

-

Change related to getdns_context_set_limit_outstanding_queries

-

GETDNS_CONTEXT_CODE_APPEND_NAME

-

Change related to getdns_context_set_append_name

-

GETDNS_CONTEXT_CODE_SUFFIX

-

Change related to getdns_context_set_suffix

-

GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS

-

Change related to getdns_context_set_dnssec_trust_anchors

-

GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE

-

Change related to getdns_context_set_edns_maximum_udp_payload_size

-

GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE

-

Change related to getdns_context_set_edns_extended_rcode

-

GETDNS_CONTEXT_CODE_EDNS_VERSION

-

Change related to getdns_context_set_edns_version

-

GETDNS_CONTEXT_CODE_EDNS_DO_BIT

-

Change related to getdns_context_set_edns_do_bit

-

GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW

-

Change related to getdns_context_set_dnssec_allowed_skew

-

GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS

-

Change related to getdns_context_set_memory_functions

-

GETDNS_CONTEXT_CODE_TIMEOUT

-

Change related to getdns_context_set_timeout

- - -

9. The Generated Files

- -

There is a tarball that includes the .h files, -the examples, and so on. The examples all make, even though there is no API implementation, based -on a pseudo-implementation in the tarball; see make-examples-PLATFORM.sh. Note that this currently builds fine -on the Macintosh and Ubuntu; help is definitely appreciated on making the build process -work on more platforms if it fails there.

- -

10. Commentary

- -

The following description of the API may be of value to those who might implement the design, and -those who are using an implementation of the design.

- -

10.1 API Design Considerations

- -

The genesis of this DNS API design was seeing other DNS API designs flounder. There are other -DNS APIs already available (such as draft-hayatnagarkar-dnsext-validator-api, as well -as DNSSEC APIs in BIND and Unbound), but there has been very little uptake of them. In talking to -application developers, there was a consistent story: that they felt that the APIs were developed by and -for DNS people, not applications developers.

- -

This API design comes from talking to a small handful of applications developers about what they -would want to see in a modern DNS API. Now that the API is public, it would be great to hear from many -more application developers about whether it would meet their needs if it was implemented. My goal -is to create a design that is a natural follow-on to getaddrinfo() that has all the -capabilities that most application developers might want now or in the next few years: access to all -types of DNS records (including those which are yet to be defined), full DNSSEC awareness, IDN -handling, and parity for IPv4 and IPv6 addresses.

- -

Note that this is just a design for a new API: there is no implementation of the design yet, but -at least one is being worked on. The process of designing the API without implementing it at the -same time has the huge advantage that major design changes could be made without any worry about -"but we already coded it the other way". In the early revisions of this document, many fundamental -design choices changed over and over, and even bike-shedding-like changes were allowed because they -didn't involve any programming effort.

- -

This work was done independently, not through the IETF because the IETF generally doesn't take on -API work, and has explicitly avoided DNS API work in the past.

- -

This API design has a Creative Commons license so that it can be -used widely by potential API implementers. This also allows other people who want to fork the design -to do so cleanly. Of course, any implementation of this API can choose whatever kind of license the -API implementer wishes, but it would be fabulous if one or more such implementations had Creative -Commons or BSD-ish licenses.

- -

The API relies heavily on C macros and hopefully has no magic numbers.

- -

10.2 API Implementation Considerations

- -

All implementations of this API must act as recursive resolvers, and some might choose not to be -able to act as stub resolvers. Note that all implementations of this API must be DNSSEC validators.

- -

Because there are many C event libraries available, and they have different calling routines, -it is the implementation of an API that determines which event library is used. This is certainly -not optimal for C programmers, but they appear to have gotten used to is so far. All implementations -of this API must support synchronous calls with getdns_sync_request().

- -

Versions are differentiated by version strings instead of version numbers. The version string for -this API is "getdns April 2013". Each implementation is free to set the implementation string as it -feels fit.

- -

The API's .h file contains a macro called GETDNS_COMPILATION_COMMENT. This can be useful -to an application which will use the API because it can check the string without calling any -functions. Each time the API implementation is compiled, this string should be updated with unique -information about the implementation build.

- -

The implementation of both the async and sync getdns functions will -copy all the values of the parameters into local memory, in case the application changes or -deallocates them.

- -
- -

Creative
-Commons License
This work is licensed under a Creative Commons Attribution 3.0 -Unported License.

- -