<!DOCTYPE html SYSTEM 'about:legacy-compat'> <html><head><title>DNS API Description</title> <meta http-equiv="Content-type" content="text/html;charset=UTF-8"> <!-- Need different returns for getdns_address, getdns_hostname, and getdns_service; also need to fix examples --> <style type="text/css"> <!-- div.forh { white-space: pre; font-family: monospace; margin-top: 0; margin-bottom: 0 } h1 { font-size: 18pt; } h2 { font-size: 14pt; } p { margin-bottom: 0 } p.title { font-size: 24pt; font-weight: bold; margin-top: 0; margin-bottom: 0; text-align: center; } p.title2 { font-size: 12pt; margin-top: 0; text-align: center; } p.define { font-family: monospace; font-weight: bold; margin-bottom: 0; margin-left: 2em; } p.descrip { margin-left: 4em; margin-top: 0; } p.cont { margin-top: 0 } p.bull { margin-top: 0; margin-bottom: 0 } p.bull:before { content: "• " } pre { margin-bottom: 0 } table { border-spacing: 8pt } td, th { vertical-align: top; text-align: left } td.num { font-weight: bold; width: 2em } tr.code { font-family: monospace } .done { background: lightgreen } .wontdo { background: lightpink } .moved { background: lightskyblue } .default { font-weight: bold } /* The following is for Pygments-highlighted code */ .highlight .hll { background-color: #ffffcc } .highlight { background: #ffffff; } .highlight .c { color: #408080; font-style: italic } /* Comment */ .highlight .err { border: 1px solid #FF0000 } /* Error */ .highlight .k { color: #008000; font-weight: bold } /* Keyword */ .highlight .o { color: #666666 } /* Operator */ .highlight .cm { color: #408080; font-style: italic } /* Comment.Multiline */ .highlight .cp { color: #BC7A00 } /* Comment.Preproc */ .highlight .c1 { color: #408080; font-style: italic } /* Comment.Single */ .highlight .cs { color: #408080; font-style: italic } /* Comment.Special */ .highlight .gd { color: #A00000 } /* Generic.Deleted */ .highlight .ge { font-style: italic } /* Generic.Emph */ .highlight .gr { color: #FF0000 } /* Generic.Error */ .highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */ .highlight .gi { color: #00A000 } /* Generic.Inserted */ .highlight .go { color: #808080 } /* Generic.Output */ .highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */ .highlight .gs { font-weight: bold } /* Generic.Strong */ .highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */ .highlight .gt { color: #0040D0 } /* Generic.Traceback */ .highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */ .highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */ .highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */ .highlight .kp { color: #008000 } /* Keyword.Pseudo */ .highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */ .highlight .kt { color: #B00040 } /* Keyword.Type */ .highlight .m { color: #666666 } /* Literal.Number */ .highlight .s { color: #BA2121 } /* Literal.String */ .highlight .na { color: #7D9029 } /* Name.Attribute */ .highlight .nb { color: #008000 } /* Name.Builtin */ .highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */ .highlight .no { color: #880000 } /* Name.Constant */ .highlight .nd { color: #AA22FF } /* Name.Decorator */ .highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ .highlight .ne { color: #D2413A; font-weight: bold } /* Name.Exception */ .highlight .nf { color: #0000FF } /* Name.Function */ .highlight .nl { color: #A0A000 } /* Name.Label */ .highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */ .highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */ .highlight .nv { color: #19177C } /* Name.Variable */ .highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */ .highlight .w { color: #bbbbbb } /* Text.Whitespace */ .highlight .mf { color: #666666 } /* Literal.Number.Float */ .highlight .mh { color: #666666 } /* Literal.Number.Hex */ .highlight .mi { color: #666666 } /* Literal.Number.Integer */ .highlight .mo { color: #666666 } /* Literal.Number.Oct */ .highlight .sb { color: #BA2121 } /* Literal.String.Backtick */ .highlight .sc { color: #BA2121 } /* Literal.String.Char */ .highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */ .highlight .s2 { color: #BA2121 } /* Literal.String.Double */ .highlight .se { color: #BB6622; font-weight: bold } /* Literal.String.Escape */ .highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */ .highlight .si { color: #BB6688; font-weight: bold } /* Literal.String.Interpol */ .highlight .sx { color: #008000 } /* Literal.String.Other */ .highlight .sr { color: #BB6688 } /* Literal.String.Regex */ .highlight .s1 { color: #BA2121 } /* Literal.String.Single */ .highlight .ss { color: #19177C } /* Literal.String.Symbol */ .highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */ .highlight .vc { color: #19177C } /* Name.Variable.Class */ .highlight .vg { color: #19177C } /* Name.Variable.Global */ .highlight .vi { color: #19177C } /* Name.Variable.Instance */ .highlight .il { color: #666666 } /* Literal.Number.Integer.Long */--> </style> </head><body> <p class=title>Description of the <code>getdns</code> API</p> <p class=title2>Paul Hoffman, Editor</p> <p class=title2>Document version: "getdns December 2013"</p> <p>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:</p> <ul> <li>Full support for event-driven programming</li> <li>Supports DNSSEC in multiple ways</li> <li>Mirroring of the resolution in <code>getaddrinfo()</code></li> <li>Easily supports all RRtypes, even those yet to be defined</li> </ul> <p>There is more background into the design and future goals of this API <a href="#Commentary">later in this document</a>.</p> <p>This document was discussed on the <a href="http://www.vpnc.org/mailman/listinfo/getdns-api"> getdns-api mailing list</a>; future versions of the API might be discussed there as well. (If you want to contact the editor off-list, please send mail to <a href="mailto:paul.hoffman@vpnc.org">paul.hoffman@vpnc.org</a>.)</p> <h1>1. The <code>getdns</code> Async Functions</h1> <p>The API has four async functions:</p> <ul> <li><code>getdns_address</code> for doing <code>getaddrinfo()</code>-like address lookups</li> <li><code>getdns_hostname</code> for doing <code>getnameinfo()</code>-like name lookups</li> <li><code>getdns_service</code> for getting results from SRV lookups</li> <li><code>getdns_general</code> for looking up any type of DNS record</li> </ul> <h2>1.1 <code>getdns_general()</code></h2> <div class=forh id="getdnsfuncgeneral">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 ); </div> <p class=define><code><b>context</b></code></p> <p class=descrip>A pointer to the DNS context that is to be used with this call. DNS contexts are described <a href="#Contexts">later in this document</a>. Note that a context <i>must</i> be created before calling the function.</p> <p class=define><code><b>*name</b></code></p> <p class=descrip>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.</p> <p class=define><code><b>request_type</b></code></p> <p class=descrip>Specifies the RRtype for the query; the RRtype numbers are listed in the IANA registry. For example, to get the NS records, <code>request_type</code> would be 2. The API also has defined macros for most of the RRtypes by name; the definition names all start with "<code>GETDNS_RRTYPE_</code>". For example, to get the NS records, you can also set the <code>request_type</code> to <code>GETDNS_RRTYPE_NS</code>. (The full list of request types is always <a href="http://www.iana.org/assignments/dns-parameters/dns-parameters.xml">here</a>.)</p> <p class=define><code><b>*extensions</b></code></p> <p class=descrip>Specifies the extensions for this request; the value may be NULL if there are no extensions. See <a href="#Extensions">the section below</a> for information on how to specify the extensions used for a request.</p> <p class=define><code><b>*userarg</b></code></p> <p class=descrip>A void* that is passed to the function, which the funciton returns to the callback function untouched. <code>userarg</code> can be used by the callback function for any user-specific data needed. This can be NULL.</p> <p class=define><code><b>*transaction_id</b></code></p> <p class=descrip>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 <code>getdns_cancel_callback()</code> function uses the <code>transaction_id</code> to determine which callback is to be cancelled. If the function fails, <code>transaction_id</code> is set to 0.</p> <p class=define><code><b>*callbackfn</b></code></p> <p class=descrip>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.</p> <p>The async <code>getdns</code> functions return <code>GETDNS_RETURN_GOOD</code> if the call was properly formatted. It returns <code>GETDNS_RETURN_BAD_DOMAIN_NAME</code> if the API determines that the name passed to the function was bad, <code>GETDNS_RETURN_BAD_CONTEXT</code> if the context pointer is bad, <code>GETDNS_RETURN_NO_SUCH_EXTENSION</code> if one or more extensions do not exist, or <code>GETDNS_RETURN_EXTENSION_MISFORMAT</code> if the contents of one or more of the extensions is incorrect. All of the return values are given <a href="#ReturnCodes">later in this document</a>.</p> <h2>1.2 <code>getdns_address()</code></h2> <div class=forh id="getdnsfuncaddress">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 ); </div> <p>There are three critical differences between <code>getdns_address()</code> and <code>getdns_general()</code> beyond the missing <code>request_type</code> argument:</p> <ul> <li>In <code>getdns_address()</code>, the <code>name</code> argument can only take a host name.</li> <li>You do not need to include a <code>return_both_v4_and_v6</code> extension with the call in <code>getdns_address()</code>: it will always return both IPv4 and IPv6 addresses.</li> <li><code>getdns_address()</code> always uses all of namespaces from the context (to better emulate <code>getaddrinfo()</code>), while <code>getdns_general()</code> only uses the DNS namespace.</li> </ul> <h2>1.3 <code>getdns_hostname()</code></h2> <div class=forh id="getdnsfunchostname">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 ); </div> <p>The address is given as a <code>getdns_dict</code> data structure (defined below). The list must have two names: <code>address_type</code> (whose value is a bindata; it is currently either "IPv4" or "IPv6" (which are case-sensitive)) and <code>address_data</code> (whose value is a bindata).</p> <h2>1.4 <code>getdns_service()</code></h2> <div class=forh id="getdnsfuncservice">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 ); </div> <p><code>name</code> must be a domain name for an SRV lookup; the call returns the relevant SRV information for the name.</p> <h2>1.5 Callback Functions for <code>getdns</code></h2> <p>A call to the async <code>getdns</code> 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.<p> <p>The <code>getdns</code> calling function calls the callback with the parameters defined as follows:</p> <div class=forh id="getdns_callback_t"> typedef void (*getdns_callback_t)( struct getdns_context *context, uint16_t callback_type, struct getdns_dict *response, void *userarg, getdns_transaction_t transaction_id); </div> <p class=define><code><b>context</b></code></p> <p class=descrip>The DNS context that was used in the calling function. See <a href="#ContextInitial">below</a> for a description of the basic use of contexts, and <a href="#Contexts">later</a> for more advanced use.</p> <p class=define><code><b>callback_type</b></code></p> <p class=descrip>Supplies the reason for the callback. See below for the codes and reasons.</p> <p class=define><code><b>*response</b></code></p> <p class=descrip>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.</p> <p class=define><code><b>*userarg</b></code></p> <p class=descrip>Identical to the <code>*userarg</code> passed to the calling function.</p> <p class=define><code><b>transaction_id</b></code></p> <p class=descrip>The transaction identifier that was assigned by the calling function.</p> <p>The following are the values for callback_type.</p> <p class=define>GETDNS_CALLBACK_COMPLETE</p> <p class=descrip>The response has the requested data in it</p> <p class=define>GETDNS_CALLBACK_CANCEL</p> <p class=descrip>The calling program cancelled the callback; response is NULL</p> <p class=define>GETDNS_CALLBACK_TIMEOUT</p> <p class=descrip>The requested action timed out; response is NULL</p> <p class=define>GETDNS_CALLBACK_ERROR</p> <p class=descrip>The requested action had an error; response is NULL</p> <h2>1.6 <a id="ContextInitial">Setting Up The DNS Context</a></h2> <p>Calls to <code>getdns</code> 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.</p> <p>To create a new DNS context, use the function:</p> <div class=forh>getdns_return_t getdns_context_create( struct getdns_context **context, int set_from_os ); </div> <p class=cont>The call to <code>getdns_context_create</code> immediately returns a context that can be used with other API calls; that context contains the API's default values. Most applications will want <code>set_from_os</code> set to <code>1</code>.</p> <div class=forh>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 *) ); </div> <p>To clean up the context, including cleaning up all outstanding transactions that were called using this context, use the function:</p> <div class=forh>void getdns_context_destroy( struct getdns_context *context ); </div> <p class=cont>When <code>getdns_context_destroy()</code> returns, the application knows that all outstanding transactions associated with this context will have been called; callbacks that had not been called before <code>getdns_context_destroy()</code> was called will be called with a callback_type of <code>GETDNS_CALLBACK_CANCEL</code>. <code>getdns_context_destroy()</code> returns after all of the needed cleanup is done and callbacks are made.</p> <h2>1.7 Canceling a Callback</h2> <p>To cancel an outstanding callback, use the following function.</p> <div class=forh>getdns_return_t getdns_cancel_callback( struct getdns_context *context, getdns_transaction_t transaction_id ); </div> <p class=cont>This causes the API to call the callback with a <code>callback_type</code> of <code>GETDNS_CALLBACK_CANCEL</code> if the callback for this <code>transaction_id</code> 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. <code>getdns_cancel_callback()</code> may return immediately, even before the callback finishes its work and returns. Calling <code>getdns_cancel_callback()</code> with a <code>transaction_id</code> of a callback that has already been called or an unknown <code>transaction_id</code> returns <code>GETDNS_RETURN_UNKNOWN_TRANSACTION</code>; otherwise, <code>getdns_cancel_callback()</code> returns <code>GETDNS_RETURN_GOOD</code>.</p> <h2>1.8 Event-driven Programs</h2> <p>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 <code>getdns</code> functions.</p> <p>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 "<code>getdns_extension_set_libevent_base()</code>" while another might name it "<code>getdns_extension_set_eventbase_for_libevent()</code>"; the two extension functions could have very different calling patterns and return values. Thus, the application developer <i>must</i> 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.</p> <p>The structure of a typical event-driven application might look like the following pseudocode. The code in italics is specific to the event mechanism.</p> <pre> Includes for one or more regular C libraries <i>An include for the getdns library specific to the event library you use</i> Definition of your callback function Get the DNS data from the allocated pointer Process that data Check for errors Definition of main() Create context <i>Set up your event base</i> <i>Point the context to your event base</i> Set up the getdns call arguments Make the getdns call Check if the getdns return is good Destroy the context Exit </pre> <p>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 <code>transaction_id</code> and <code>userarg</code>. The <code>userarg</code> 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 <code>response</code> into application memory, update the data structure based on the <code>transaction_id</code> index, and return from the callback. The polling code could then check the data structure for any updates at its leisure.</p> <h2>1.9 Calling the API Synchronously (Without Events)</h2> <p>Thare are functions parallel to the four <code>getdns</code> 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.</p> <div class=forh>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 ); </div> <div class=forh>getdns_return_t getdns_address_sync( struct getdns_context *context, const char *name, struct getdns_dict *extensions, struct getdns_dict **response ); </div> <div class=forh>getdns_return_t getdns_hostname_sync( struct getdns_context *context, struct getdns_dict *address, struct getdns_dict *extensions, struct getdns_dict **response ); </div> <div class=forh>getdns_return_t getdns_service_sync( struct getdns_context *context, const char *name, struct getdns_dict *extensions, struct getdns_dict **response ); </div> <p>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.</p> <pre>void getdns_dict_destroy( struct getdns_dict *response ); </pre> <h1>2. Data structures in the API</h1> <p>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:</p> <ul> <li><span class=default>list</span> is an ordered list, like JSON and Python lists. The members of the list can be any of the four data types.</li> <li><span class=default>dict</span> is a name-value pair, like a JSON object or Python dict. 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.</li> <li><span class=default>int</span> is an integer compatible with uint32_t.</li> <li><span class=default>bindata</span> is a struct to hold binary data. It is defined as <code>{ size_t size; uint8_t *binary_stuff; }</code>.</li> </ul> <p>The API comes with helper functions to get data from the list and dict data types:</p> <div class=forh id="datagetters"> /* 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); </div> <p>All of these helper getter functions return <code>GETDNS_RETURN_GOOD</code> if the call is successful. The list functions will return <code>GETDNS_RETURN_NO_SUCH_LIST_ITEM</code> if the index argument is out of range; the dict functions will return <code>GETDNS_RETURN_NO_SUCH_DICT_NAME</code> if the name argument doesn't exist in the dict. The functions also return <code>GETDNS_RETURN_WRONG_TYPE_REQUESTED</code> if the requested data type doesn't match the contents of the indexed argument or name.</p> <p>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.</p> <h2>2.1 Creating Data Structures</h2> <p>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:</p> <div class=forh id="datasetters"> /* 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); </div> <p>Lists are extended with the <code>getdns_list_set_</code> calls with the <code>index</code> set to the size of the list (such as 0 for an empty list). Dicts are extended with the <code>getdns_dict_set_</code> calls with the <code>name</code> set to a name that does not yet exist. Name-value pairs are removed with <code>getdns_dict_remove_name()</code>.</p> <p>These helper setter functions return <code>GETDNS_RETURN_GOOD</code> if the call is successful. The functions return <code>GETDNS_RETURN_WRONG_TYPE_REQUESTED</code> if the requested data type doesn't match the contents of the indexed argument or name. The list functions will return <code>GETDNS_RETURN_NO_SUCH_LIST_ITEM</code> if the index argument is higher than the length of the list. <code>getdns_dict_remove_name()</code> will return <code>GETDNS_RETURN_NO_SUCH_DICT_NAME</code> if the name argument doesn't exist in the dict. </p> <h1>3. <a id="Extensions">Extensions</a></h1> <p>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 <code>GETDNS_EXTENSION_TRUE</code>. (There is not currently a good reason to specify an extension name and give it a value of <code>GETDNS_EXTENSION_FALSE</code>, but that is allowed by the API.)</p> <p>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:</p> <pre> /* . . . */ 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); </pre> <p>The extensions described in this section are are: <ul> <li><code>dnssec_return_status</code></li> <li><code>dnssec_return_only_secure</code></li> <li><code>dnssec_return_supporting_responses</code></li> <li><code>return_both_v4_and_v6</code></li> <li><code>add_opt_parameters</code></li> <li><code>add_warning_for_bad_dns</code></li> <li><code>specify_class</code></li> <li><code>return_api_information</code></li> <li><code>return_call_debugging</code></li> </ul> <h2>3.1 Extensions for DNSSEC</h2> <p>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.</p> <p>To return the DNSSEC status for each DNS record in the <code>replies_tree</code> list, use the <code>dnssec_return_status</code> extension. The extension's value (an int) is set to <code>GETDNS_EXTENSION_TRUE</code> to cause the returned status to have the name <code>dnssec_status</code> (an int) added to the other names in the record's dict ("header", "question", and so on). The values for that name are <code>GETDNS_DNSSEC_SECURE</code>, <code>GETDNS_DNSSEC_BOGUS</code>, <code>GETDNS_DNSSEC_INDETERMINATE</code>, and <code>GETDNS_DNSSEC_INSECURE</code>. Thus, a reply might look like:</p> <pre> { # This is the first reply "dnssec_status": GETDNS_DNSSEC_INDETERMINATE, "header": { "id": 23456, "qr": 1, "opcode": 0, ... }, . . . </pre> <p>If instead of returning the status, you want to only see secure results, use the <code>dnssec_return_only_secure</code> extension. The extension's value (an int) is set to <code>GETDNS_EXTENSION_TRUE</code> to cause only records that the API can validate as secure with DNSSEC to be returned in the <code>replies_tree</code> and <code>replies_full</code> 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 <code>GETDNS_RESPSTATUS_NO_SECURE_ANSWERS</code>.</p> <p>Applications that want to do their own validation will want to have the DNSSEC-related records for a particular response. Use the <code>dnssec_return_supporting_responses</code> extension. The extension's value (an int) is set to <code>GETDNS_EXTENSION_TRUE</code> to cause a set of additional DNSSEC-related records needed for validation to be returned in the response object. This set comes as <code>additional_dnssec</code> (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:</p> <pre> { # This is the response object "additional_dnssec": [ <bindata of the first DNSSEC record>, <bindata of the second DNSSEC record> ... ], "replies_tree": [ . . . </pre> <p>If a request is using a context in which stub resolution is set, and that request also has any of the <code>dnssec_return_status</code>, <code>dnssec_return_only_secure</code>, or <code>dnssec_return_supporting_responses</code> extensions specified, the API will not perform the request and will instead return an error of <code>GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED</code>.</p> <h2>3.2 Returning Both IPv4 and IPv6 Responses</h2> <p>Many applications want to get both IPv4 and IPv6 addresses in a single call so that the results can be processed together. The <code>getdns_address</code> and <code>getdns_address_sync</code> functions are able to do this automatically. If you are using the <code>getdns_general</code> or <code>getdns_general_sync</code> function, you can enable this with the <code>return_both_v4_and_v6</code> extension. The extension's value (an int) is set to <code>GETDNS_EXTENSION_TRUE</code> 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.</p> <h2>3.3 Setting Up OPT Resource Records</h2> <p>For lookups that need an OPT resource record in the Additional Data section, use the <code>add_opt_parameters</code> extension. The extension's value (a dict) contains the parameters; these are described in more detail in RFC 2671. They are:</p> <ul> <li><code>maximum_udp_payload_size</code> (an int), a value between 512 and 65535; if not specified, this defaults to those from the DNS context</li> <li><code>extended_rcode</code> (an int), a value between 0 and 255; if not specified, this defaults to those from the DNS context</li> <li><code>version</code> (an int), a value between 0 and 255; if not specified, this defaults to 0</li> <li><code>do_bit</code> (an int), a value between 0 and 1; if not specified, this defaults to those from the DNS context</li> <li><code>options</code> (a list) contains dicts for each option to be specified. Each list time contains two names: <code>option_code</code> (an int) and <code>option_data</code> (a bindata). The API marshalls the entire set of options into a properly-formatted RDATA for the resource record.</li> </ul> <p>It is very important to note that the OPT resource record specified in the <code>add_opt_parameters</code> 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 <code>add_opt_parameters</code> extension.</p> <p>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.</p> <h2>3.4 Getting Warnings for Responses that Violate the DNS Standard</h2> <p>To receive a warning if a particular response violates some parts of the DNS standard, use the <code>add_warning_for_bad_dns</code> extension. The extension's value (an int) is set to <code>GETDNS_EXTENSION_TRUE</code> to cause each reply in the <code>replies_tree</code> to contain an additional name, <code>bad_dns</code> (a list). The list is zero or more ints that indicate types of bad DNS found in that reply. The list of values is: <p class=define>GETDNS_BAD_DNS_CNAME_IN_TARGET</p> <p class=descrip>A DNS query type that does not allow a target to be a CNAME pointed to a CNAME</p> <p class=define>GETDNS_BAD_DNS_ALL_NUMERIC_LABEL</p> <p class=descrip>One or more labels in a returned domain name is all-numeric; this is not legal for a hostname</p> <p class=define>GETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE</p> <p class=descrip>A DNS query for a type other than CNAME returned a CNAME response</p> <h2>3.5 Using Other Class Types</h2> <p>The vast majority of DNS requests are made with the Internet (IN) class. To make a request in a different DNS class, use, the <code>specify_class</code> extension. The extension's value (an int) contains the class number. Few applications will ever use this extension.</p> <h2>3.6 Extensions Relating to the API</h2> <p>An application might want to see information about the API itself. Use the <code>return_api_information</code> 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 <code>GETDNS_EXTENSION_TRUE</code> to add the following to the top level of the response object:</p> <ul> <li><code>version_string</code> (a bindata) represents the version string for this version of the DNS API.</li> <li><code>implementation_string</code> (a bindata) is a string set by the API implementer. It might be human-readable, and it might have information in it useful to an application developer (but it doesn't have to).</li> <li><code>resolver_type</code> (an int) is the type of resolver that the API is acting as in this context: <code>GETDNS_CONTEXT_RECURSING</code> or <code>GETDNS_CONTEXT_STUB</code> (it will be a recursing resolver unless the application changed this in a context.</li> <li><code>all_context</code> (a dict) with names for all the types of context. This can be used with getdns_pretty_print_dict() for debugging.</li> </ul> <p>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 <code>return_call_debugging</code> extension. The extension's value (an int) is set to <code>GETDNS_EXTENSION_TRUE</code> to add the name <code>call_debugging</code> (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:</p> <ul> <li><code>query_name</code> (a bindata) is the name that was sent</li> <li><code>query_type</code> (an int) is the type that was queried for</li> <li><code>query_to</code> (a bindata) is the address to which the query was sent</li> <li><code>start_time</code> (a bindata) is the time the query started in milliseconds since the epoch, represented as a uint64_t</li> <li><code>end_time</code> (a bindata) is the time the query was received in milliseconds since the epoch, represented as a uint64_t</li> <li><code>entire_reply</code> (a bindata) is the entire response received</li> <li><code>dnssec_result</code> (an int) is the DNSSEC status, or <code>GETDNS_DNSSEC_NOT_PERFORMED</code> if DNSSEC validation was not performed</li> </ul> <h1>4. Response Data from Queries</h1> <p>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: <code>replies_full</code> (a list) and <code>replies_tree</code> (a list), and <code>status</code> (an int). <code>replies_full</code> is a list of DNS replies (each is bindata) as they appear on the wire. <code>replies_tree</code> is a list of DNS replies (each is a dict) with the various part of the reply parsed out. <code>status</code> is a status code for the query.</p> <p>Because the API might be extended in the future, a response object might also contain names other than <code>replies_full</code>, <code>replies_tree</code>, and <code>status</code>. 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.</p> <p>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 <code>replies_full</code> and <code>replies_tree</code> will have zero length.</p> <p class=define>GETDNS_RESPSTATUS_GOOD</p> <p class=descrip>At least one response was returned</p> <p class=define>GETDNS_RESPSTATUS_NO_NAME</p> <p class=descrip>Queries for the name yielded all negative responses</p> <p class=define>GETDNS_RESPSTATUS_ALL_TIMEOUT</p> <p class=descrip>All queries for the name timed out</p> <p class=define>GETDNS_RESPSTATUS_NO_SECURE_ANSWERS</p> <p class=descrip>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.</p> <p>The top level of <code>replies_tree</code> can optionally have the following names: <code>canonical_name</code> (a bindata), <code>intermediate_aliases</code> (a list), <code>answer_ipv4_address</code> (a bindata), <code>answer_ipv6_address</code> (a bindata), and <code>answer_type</code> (an int).</p> <ul> <li>The value of <code>canonical_name</code> is the name that the API used for its lookup. It is in FQDN presentation format.</li> <li>The values in the <code>intermediate_aliases</code> 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.</li> <li>The value of <code>answer_ipv4_address</code> and <code>answer_ipv6_address</code> are the addresses of the server from which the answer was received.</li> <li>The value of <code>answer_type</code> is the type of name service that generated the response. The values are:</li> </ul> <p class=define>GETDNS_NAMETYPE_DNS</p> <p class=descrip>Normal DNS (RFC 1035)</p> <p class=define>GETDNS_NAMETYPE_WINS</p> <p class=descrip>The WINS name service (some reference needed)</p> <p>If the call was <code>getdns_address</code> or <code>getdns_address_sync</code>, the top level of <code>replies_tree</code> has an additional name, <code>just_address_answers</code> (a list). The value of <code>just_address_answers</code> 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: <code>address_type</code> (whose value is a bindata; it is currently either "IPv4" or "IPv6") and <code>address_data</code> (whose value is a bindata). Note that the <code>dnssec_return_only_secure</code> extension affects what will appear in the <code>just_address_answers</code> list. Also note if later versions of the DNS return other address types, those types will appear in this list as well.</p> <p>The API can make service discovery through SRV records easier. If the call was <code>getdns_service</code> or <code>getdns_service_sync</code>, the top level of <code>replies_tree</code> has an additional name, <code>srv_addresses</code> (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: <code>port</code> and <code>domain_name</code>. 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 <code>address_type</code> (whose value is a bindata; it is currently either "IPv4" or "IPv6") and <code>address_data</code> (whose value is a bindata). Note that the <code>dnssec_return_only_secure</code> extension affects what will appear in the <code>srv_addresses</code> list.</p> <h2>4.1 Structure of DNS <code>replies_tree</code></h2> <p>The names in each entry in the the <code>replies_tree</code> list for DNS responses include <code>header</code> (a dict), <code>question</code> (a dict), <code>answer</code> (a list), <code>authority</code> (a list), and <code>additional</code> (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.</p> <p>The names in the <code>header</code> dict are all the fields from Section 4.1.1. of RFC 1035. They are: <code>id</code>, <code>qr</code>, <code>opcode</code>, <code>aa</code>, <code>tc</code>, <code>rd</code>, <code>ra</code>, <code>z</code>, <code>rcode</code>, <code>qdcount</code>, <code>ancount</code>, <code>nscount</code>, and <code>arcount</code>. All are ints.</p> <p>The names in the <code>question</code> dict are the three fields from Section 4.1.2. of RFC 1035: <code>qname</code> (a bindata), <code>qtype</code> (an int), and <code>qclass</code> (an int).</p> <p>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 <code>name</code> (a bindata), <code>type</code> (an int), <code>class</code> (an int), <code>ttl</code> (an int) and <code>rdata</code> (a dict); there is no name equivalent to the RDLENGTH field.</p> <p>The <code>rdata</code> dict has different names for each response type. There is a <a href="#TypeList">complete list of the types defined</a> in the API. For names that end in "-obsolete" or "-unknown", the bindata is the entire RDATA field. For example, the <code>rdata</code> for an A record has a name <code>ipv4_address</code> (a bindata); the <code>rdata</code> for an SRV record has the names <code>priority</code> (an int), <code>weight</code> (an int), <code>port</code> (an int), and <code>target</code> (a bindata).</p> <p>Each <code>rdata</code> dict also has a <code>rdata_raw</code> 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 <code>rdata</code> with just a <code>rdata_raw</code>.</p> <p>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.</p> <p>For example, a response to a <code>getdns_address()</code> call for www.example.com would look something like this:</p> <pre> { # This is the response object "replies_full": [ <bindata of the first response>, <bindata of the second response> ], "just_address_answers": [ { "address_type": <bindata of "IPv4">, "address_data": <bindata of 0x0a0b0c01>, }, { "address_type": <bindata of "IPv6">, "address_data": <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": [], }, ] } </pre> <p>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 <code>replies_tree</code>. This conversion happens for <code>qname</code> in <code>question</code>; <code>name</code> in the <code>answer</code>, <code>authority</code>, and <code>additional</code>; and in domain names in the data in names under <code>rdata</code> where the response type is AFSDB, CNAME, MX, NS, PTR, RP, RT, and SOA.</p> <h2>4.2 Converting Domain Names</h2> <p>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 <code>replies_tree</code> to and from the FQDN presentation format.</p> <p><code>getdns_convert_dns_name_to_fqdn()</code> converts a domain name in DNS format to the presentation format. For example, the hex sequence <code>03 77 77 77 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00</code> would be converted to "www.example.com". <code>getdns_convert_fqdn_to_dns_name()</code> does the reverse: it converts a null-terminated string in FQDN format to bytes in DNS format.</p> <div class=forh> char * getdns_convert_dns_name_to_fqdn( char *name_from_dns_response ); char * getdns_convert_fqdn_to_dns_name( char *fqdn_as_string ); </div> <h1>5. Additional Definitions and Descriptions</h1> <h2>5.1 A Few Needed Definitions</h2> <div class=forh id="Various">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; </div> <h2>5.2 <a id="ReturnCodes">Return Codes</a></h2> <p>The return codes for all the functions are:</p> <p class=define>GETDNS_RETURN_GOOD</p> <p class=descrip>Good</p> <p class=define>GETDNS_RETURN_GENERIC_ERROR</p> <p class=descrip>Generic error</p> <p class=define>GETDNS_RETURN_BAD_DOMAIN_NAME</p> <p class=descrip>Badly-formed domain name in first argument</p> <p class=define>GETDNS_RETURN_BAD_CONTEXT</p> <p class=descrip>Bad value for a context type</p> <p class=define>GETDNS_RETURN_CONTEXT_UPDATE_FAIL</p> <p class=descrip>Did not update the context</p> <p class=define>GETDNS_RETURN_UNKNOWN_TRANSACTION</p> <p class=descrip>An attempt was made to cancel a callback with a transaction_id that is not recognized</p> <p class=define>GETDNS_RETURN_NO_SUCH_LIST_ITEM</p> <p class=descrip>A helper function for lists had an index argument that was too high.</p> <p class=define>GETDNS_RETURN_NO_SUCH_DICT_NAME</p> <p class=descrip>A helper function for dicts had a name argument that for a name that is not in the dict.</p> <p class=define>GETDNS_RETURN_WRONG_TYPE_REQUESTED</p> <p class=descrip>A helper function was supposed to return a certain type for an item, but the wrong type was given.</p> <p class=define>GETDNS_RETURN_NO_SUCH_EXTENSION</p> <p class=descrip>A name in the extensions dict is not a valid extension.</p> <p class=define>GETDNS_RETURN_EXTENSION_MISFORMAT</p> <p class=descrip>One or more of the extensions have a bad format.</p> <p class=define>GETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED</p> <p class=descrip>A query was made with a context that is using stub resolution and a DNSSEC extension specified.</p> <p class=define>GETDNS_RETURN_MEMORY_ERROR</p> <p class=descrip>Unable to allocate the memory required.</p> <p class=define>GETDNS_RETURN_INVALID_PARAMETER</p> <p class=descrip>A required parameter had an invalid value.</p> <h2>5.3 <a id="TypeList">Types of RDATA Returned in the API</a></h2> <p>The names in the <code>rdata</code> dicts in replies are:</p> <p class=define>A (1)</p> <p class=descrip><code>ipv4_address</code> (a bindata)</p> <p class=define>NS (2)</p> <p class=descrip><code>nsdname</code> (a bindata)</p> <p class=define>MD (3)</p> <p class=descrip><code>madname</code> (a bindata)</p> <p class=define>MF (4)</p> <p class=descrip><code>madname</code> (a bindata)</p> <p class=define>CNAME (5)</p> <p class=descrip><code>cname</code> (a bindata)</p> <p class=define>SOA (6)</p> <p class=descrip><code>mname</code> (a bindata), <code>rname</code> (a bindata), <code>serial</code> (an int), <code>refresh</code> (an int), <code>refresh</code> (an int), <code>retry</code> (an int), and <code>expire</code> (an int)</p> <p class=define>MB (7)</p> <p class=descrip><code>madname</code> (a bindata)</p> <p class=define>MG (8)</p> <p class=descrip><code>mgmname</code> (a bindata)</p> <p class=define>MR (9)</p> <p class=descrip><code>newname</code> (a bindata)</p> <p class=define>NULL (10)</p> <p class=descrip><code>anything</code> (a bindata)</p> <p class=define>WKS (11)</p> <p class=descrip><code>address</code> (a bindata), <code>protocol</code> (an int), and <code>bitmap</code> (a bindata)</p> <p class=define>PTR (12)</p> <p class=descrip><code>ptrdname</code> (a bindata)</p> <p class=define>HINFO (13)</p> <p class=descrip><code>cpu</code> (a bindata) and <code>os</code> (a bindata)</p> <p class=define>MINFO (14)</p> <p class=descrip><code>rmailbx</code> (a bindata) and <code>emailbx</code> (a bindata)</p> <p class=define>MX (15)</p> <p class=descrip><code>preference</code> (an int) and <code>exchange</code> (a bindata)</p> <p class=define>TXT (16)</p> <p class=descrip><code>txt_strings</code> (a list) which contains zero or more bindata elements that are text strings</p> <p class=define>RP (17)</p> <p class=descrip><code>mbox_dname</code> (a bindata) and <code>txt_dname</code> (a bindata)</p> <p class=define>AFSDB (18)</p> <p class=descrip><code>subtype</code> (an int) and <code>hostname</code> (a bindata)</p> <p class=define>X25 (19)</p> <p class=descrip><code>psdn_address</code> (a bindata)</p> <p class=define>ISDN (20)</p> <p class=descrip><code>isdn_address</code> (a bindata) and <code>sa</code> (a bindata)</p> <p class=define>RT (21)</p> <p class=descrip><code>preference</code> (an int) and <code>intermediate_host</code> (a bindata)</p> <p class=define>NSAP (22)</p> <p class=descrip><code>nsap</code> (a bindata)</p> <p class=define>SIG (24)</p> <p class=descrip><code>sig_obsolete</code> (a bindata)</p> <p class=define>KEY (25)</p> <p class=descrip><code>key_obsolete</code> (a bindata)</p> <p class=define>PX (26)</p> <p class=descrip><code>preference</code> (an int), <code>map822</code> (a bindata), and <code>mapx400</code> (a bindata)</p> <p class=define>GPOS (27)</p> <p class=descrip><code>longitude</code> (a bindata), <code>latitude</code> (a bindata), and <code>altitude</code> (a bindata)</p> <p class=define>AAAA (28)</p> <p class=descrip><code>ipv6_address</code> (a bindata)</p> <p class=define>LOC (29)</p> <p class=descrip><code>loc_obsolete</code> (a bindata)</p> <p class=define>NXT (30)</p> <p class=descrip><code>nxt_obsolete</code> (a bindata)</p> <p class=define>EID (31)</p> <p class=descrip><code>eid_unknown</code> (a bindata)</p> <p class=define>NIMLOC (32)</p> <p class=descrip><code>nimloc_unknown</code> (a bindata)</p> <p class=define>SRV (33)</p> <p class=descrip><code>priority</code> (an int), <code>weight</code> (an int), <code>port</code> (an int), and <code>target</code> (a bindata)</p> <p class=define>ATMA (34)</p> <p class=descrip><code>format</code> (an int) and <code>address</code> (a bindata)</p> <p class=define>NAPTR (35)</p> <p class=descrip><code>order</code> (an int), <code>preference</code> (an int), <code>flags</code> (a bindata), <code>service</code> (a bindata), <code>regexp</code> (a bindata), and <code>replacement</code> (a bindata).</p> <p class=define>KX (36)</p> <p class=descrip><code>preference</code> (an int) and <code>exchanger</code> (a bindata)</p> <p class=define>CERT (37)</p> <p class=descrip><code>type</code> (an int), <code>key_tag</code> (an int), <code>algorithm</code> (an int), and <code>certificate_or_crl</code> (a bindata)</p> <p class=define>A6 (38)</p> <p class=descrip><code>a6_obsolete</code> (a bindata)</p> <p class=define>DNAME (39)</p> <p class=descrip><code>target</code> (a bindata)</p> <p class=define>SINK (40)</p> <p class=descrip><code>sink_unknown</code> (a bindata)</p> <p class=define>OPT (41)</p> <p class=descrip><code>options</code> (a list). Each element of the <code>options</code> list is a dict with two names: <code>option_code</code> (an int) and <code>option_data</code> (a bindata).</p> <p class=define>APL (42)</p> <p class=descrip><code>apitems</code> (a list). Each element of the <code>apitems</code> list is a dict with four names: <code>address_family</code> (an int), <code>prefix</code> (an int), <code>n</code> (an int), and <code>afdpart</code> (a bindata)</p> <p class=define>DS (43)</p> <p class=descrip><code>key_tag</code> (an int), <code>algorithm</code> (an int), <code>digest_type</code> (an int), and <code>digest</code> (a bindata)</p> <p class=define>SSHFP (44)</p> <p class=descrip><code>algorithm</code> (an int), <code>fp_type</code> (an int), and <code>fingerprint</code> (a bindata)</p> <p class=define>IPSECKEY (45)</p> <p class=descrip><code>algorithm</code> (an int), <code>gateway_type</code> (an int), <code>precedence</code> (an int), <code>gateway</code>, and <code>public_key</code> (a bindata)</p> <p class=define>RRSIG (46)</p> <p class=descrip> <code>type_covered</code> (an int), <code>algorithm</code> (an int), <code>labels</code> (an int), <code>original_ttl</code> (an int), <code>signature_expiration</code> (an int), <code>signature_inception</code> (an int), <code>key_tag</code> (an int), <code>signers_name</code> (a bindata), and <code>signature</code> (a bindata)</p> <p class=define>NSEC (47)</p> <p class=descrip><code>next_domain_name</code> (a bindata) and <code>type_bit_maps</code> (a bindata)</p> <p class=define>DNSKEY (48)</p> <p class=descrip><code>flags</code> (an int), <code>protocol</code> (an int), <code>algorithm</code> (an int), and <code>public_key</code> (a bindata)</p> <p class=define>DHCID (49)</p> <p class=descrip><code>dhcid_opaque</code> (a bindata)</p> <p class=define>NSEC3 (50)</p> <p class=descrip><code>hash_algorithm</code> (an int), <code>flags</code> (an int), <code>iterations</code> (an int), <code>salt</code> (a bindata), <code>next_hashed_owner_name</code> (a bindata), and <code>type_bit_maps</code> (a bindata)</p> <p class=define>NSEC3PARAM (51)</p> <p class=descrip><code>hash_algorithm</code> (an int), <code>flags</code> (an int), <code>iterations</code> (an int), and <code>salt</code> (a bindata)</p> <p class=define>TLSA (52)</p> <p class=descrip><code>certificate_usage</code> (an int), <code>selector</code> (an int), <code>matching_type</code> (an int), and <code>certificate_association_data</code> (a bindata).</p> <p class=define>HIP (55)</p> <p class=descrip><code>pk_algorithm</code> (an int), <code>hit</code> (a bindata), <code>public_key</code> (a bindata), and <code>rendezvous_servers</code> (a list) with each element a bindata with the dname of the rendezvous_server.</p> <p class=define>NINFO (56)</p> <p class=descrip><code>ninfo_unknown</code> (a bindata)</p> <p class=define>RKEY (57)</p> <p class=descrip><code>rkey_unknown</code> (a bindata)</p> <p class=define>TALINK (58)</p> <p class=descrip><code>talink_unknown</code> (a bindata)</p> <p class=define>CDS (59)</p> <p class=descrip><code>cds_unknown</code> (a bindata)</p> <p class=define>SPF (99)</p> <p class=descrip><code>text</code> (a bindata)</p> <p class=define>UINFO (100)</p> <p class=descrip><code>uinfo_unknown</code> (a bindata)</p> <p class=define>UID (101)</p> <p class=descrip><code>uid_unknown</code> (a bindata)</p> <p class=define>GID (102)</p> <p class=descrip><code>gid_unknown</code> (a bindata)</p> <p class=define>UNSPEC (103)</p> <p class=descrip><code>unspec_unknown</code> (a bindata)</p> <p class=define>NID (104)</p> <p class=descrip><code>preference</code> (an int) and <code>node_id</code> (a bindata)</p> <p class=define>L32 (105)</p> <p class=descrip><code>preference</code> (an int) and <code>locator32</code> (a bindata)</p> <p class=define>L64 (106)</p> <p class=descrip><code>preference</code> (an int) and <code>locator64</code> (a bindata)</p> <p class=define>LP (107)</p> <p class=descrip><code>preference</code> (an int) and <code>fqdn</code> (a bindata)</p> <p class=define>EUI48 (108)</p> <p class=descrip><code>eui48_address</code> (a bindata)</p> <p class=define>EUI64 (109)</p> <p class=descrip><code>eui64_address</code> (a bindata)</p> <p class=define>TKEY (249)</p> <p class=descrip><code>algorithm</code> (a bindata), <code>inception</code> (an int), <code>expiration</code> (an int), <code>mode</code> (an int), <code>error</code> (an int), <code>key_data</code> (a bindata), and <code>other_data</code> (a bindata)</p> <p class=define>TSIG (250)</p> <p class=descrip><code>algorithm</code> (a bindata), <code>time_signed</code> (a bindata), <code>fudge</code> (an int), <code>mac</code> (a bindata), <code>original_id</code> (an int), <code>error</code> (an int), and <code>other_data</code> (a bindata)</p> <p class=define>MAILB (253)</p> <p class=descrip><code>mailb-unknown</code> (a bindata)</p> <p class=define>MAILA (254)</p> <p class=descrip><code>maila-unknown</code> (a bindata)</p> <p class=define>URI (256)</p> <p class=descrip><code>priority</code> (an int), <code>weight</code> (an int), and <code>target</code> (a bindata)</p> <p class=define>CAA (257)</p> <p class=descrip><code>flags</code> (an int), <code>tag</code> (a bindata), and <code>value</code> (a bindata)</p> <p class=define>TA (32768)</p> <p class=descrip><code>ta_unknown</code> (a bindata)</p> <p class=define>DLV (32769)</p> <p class=descrip>Identical to DS (43)</p> <h1>6. Examples</h1> <p>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.</p> <p>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 <code>getdns_context_set_libevent_base()</code> 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 <code>#include</code> at the beginning of your code, and a different name for the event base function.</p> <h2>6.1 Get Both IPv4 and IPv6 Addresses for a Domain Name Using Quick Results</h2> <p>This is an example of a common call to <code>getdns_address()</code>.</p> <br><div class="highlight"><pre><span class="cp">#include <stdio.h></span> <span class="cp">#include <stdint.h></span> <span class="cp">#include <stdlib.h></span> <span class="cp">#include <string.h></span> <span class="cp">#include <inttypes.h></span> <span class="cp">#include <getdns_libevent.h></span> <span class="cp">#define UNUSED_PARAM(x) ((void)(x))</span> <span class="cm">/* Set up the callback function, which will also do the processing of the results */</span> <span class="kt">void</span> <span class="nf">this_callbackfn</span><span class="p">(</span><span class="k">struct</span> <span class="n">getdns_context</span> <span class="o">*</span><span class="n">this_context</span><span class="p">,</span> <span class="kt">uint16_t</span> <span class="n">this_callback_type</span><span class="p">,</span> <span class="k">struct</span> <span class="n">getdns_dict</span> <span class="o">*</span><span class="n">this_response</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">this_userarg</span><span class="p">,</span> <span class="kt">getdns_transaction_t</span> <span class="n">this_transaction_id</span><span class="p">)</span> <span class="p">{</span> <span class="n">UNUSED_PARAM</span><span class="p">(</span><span class="n">this_userarg</span><span class="p">);</span> <span class="cm">/* Not looking at the userarg for this example */</span> <span class="n">UNUSED_PARAM</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="cm">/* Not looking at the context for this example */</span> <span class="kt">getdns_return_t</span> <span class="n">this_ret</span><span class="p">;</span> <span class="cm">/* Holder for all function returns */</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_callback_type</span> <span class="o">==</span> <span class="n">GETDNS_CALLBACK_COMPLETE</span><span class="p">)</span> <span class="cm">/* This is a callback with data */</span> <span class="p">{</span> <span class="cm">/* Be sure the search returned something */</span> <span class="kt">uint32_t</span> <span class="n">this_error</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_int</span><span class="p">(</span><span class="n">this_response</span><span class="p">,</span> <span class="s">"status"</span><span class="p">,</span> <span class="o">&</span><span class="n">this_error</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_error</span> <span class="o">!=</span> <span class="n">GETDNS_RESPSTATUS_GOOD</span><span class="p">)</span> <span class="c1">// If the search didn't return "good"</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"The search had no results, and a return value of %d. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_error</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="k">struct</span> <span class="n">getdns_list</span> <span class="o">*</span> <span class="n">just_the_addresses_ptr</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_list</span><span class="p">(</span><span class="n">this_response</span><span class="p">,</span> <span class="s">"just_address_answers"</span><span class="p">,</span> <span class="o">&</span><span class="n">just_the_addresses_ptr</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_ret</span> <span class="o">!=</span> <span class="n">GETDNS_RETURN_GOOD</span><span class="p">)</span> <span class="c1">// This check is really not needed, but prevents a compiler error under "pedantic"</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Trying to get the answers failed: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_ret</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kt">size_t</span> <span class="n">num_addresses</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_list_get_length</span><span class="p">(</span><span class="n">just_the_addresses_ptr</span><span class="p">,</span> <span class="o">&</span><span class="n">num_addresses</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="cm">/* Go through each record */</span> <span class="k">for</span> <span class="p">(</span> <span class="kt">size_t</span> <span class="n">rec_count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">rec_count</span> <span class="o"><</span> <span class="n">num_addresses</span><span class="p">;</span> <span class="o">++</span><span class="n">rec_count</span> <span class="p">)</span> <span class="p">{</span> <span class="k">struct</span> <span class="n">getdns_dict</span> <span class="o">*</span> <span class="n">this_address</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_list_get_dict</span><span class="p">(</span><span class="n">just_the_addresses_ptr</span><span class="p">,</span> <span class="n">rec_count</span><span class="p">,</span> <span class="o">&</span><span class="n">this_address</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="cm">/* Just print the address */</span> <span class="k">struct</span> <span class="n">getdns_bindata</span> <span class="o">*</span> <span class="n">this_address_data</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_bindata</span><span class="p">(</span><span class="n">this_address</span><span class="p">,</span> <span class="s">"address_data"</span><span class="p">,</span> <span class="o">&</span><span class="n">this_address_data</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="kt">char</span> <span class="o">*</span><span class="n">this_address_str</span> <span class="o">=</span> <span class="n">getdns_display_ip_address</span><span class="p">(</span><span class="n">this_address_data</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"The address is %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_address_str</span><span class="p">);</span> <span class="n">free</span><span class="p">(</span><span class="n">this_address_str</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_callback_type</span> <span class="o">==</span> <span class="n">GETDNS_CALLBACK_CANCEL</span><span class="p">)</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"The callback with ID %"</span><span class="n">PRIu64</span><span class="s">" was cancelled. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_transaction_id</span><span class="p">);</span> <span class="k">else</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"The callback got a callback_type of %d. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_callback_type</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> <span class="cm">/* Create the DNS context for this call */</span> <span class="k">struct</span> <span class="n">getdns_context</span> <span class="o">*</span><span class="n">this_context</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> <span class="kt">getdns_return_t</span> <span class="n">context_create_return</span> <span class="o">=</span> <span class="n">getdns_context_create</span><span class="p">(</span><span class="o">&</span><span class="n">this_context</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">context_create_return</span> <span class="o">!=</span> <span class="n">GETDNS_RETURN_GOOD</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Trying to create the context failed: %d"</span><span class="p">,</span> <span class="n">context_create_return</span><span class="p">);</span> <span class="k">return</span><span class="p">(</span><span class="n">GETDNS_RETURN_GENERIC_ERROR</span><span class="p">);</span> <span class="p">}</span> <span class="cm">/* Create an event base and put it in the context using the unknown function name */</span> <span class="k">struct</span> <span class="n">event_base</span> <span class="o">*</span><span class="n">this_event_base</span><span class="p">;</span> <span class="n">this_event_base</span> <span class="o">=</span> <span class="n">event_base_new</span><span class="p">();</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_event_base</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Trying to create the event base failed.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="n">getdns_context_destroy</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="k">return</span><span class="p">(</span><span class="n">GETDNS_RETURN_GENERIC_ERROR</span><span class="p">);</span> <span class="p">}</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">getdns_extension_set_libevent_base</span><span class="p">(</span><span class="n">this_context</span><span class="p">,</span> <span class="n">this_event_base</span><span class="p">);</span> <span class="cm">/* Set up the getdns call */</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">this_name</span> <span class="o">=</span> <span class="s">"www.example.com"</span><span class="p">;</span> <span class="kt">char</span><span class="o">*</span> <span class="n">this_userarg</span> <span class="o">=</span> <span class="s">"somestring"</span><span class="p">;</span> <span class="c1">// Could add things here to help identify this call</span> <span class="kt">getdns_transaction_t</span> <span class="n">this_transaction_id</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="cm">/* Make the call */</span> <span class="kt">getdns_return_t</span> <span class="n">dns_request_return</span> <span class="o">=</span> <span class="n">getdns_address</span><span class="p">(</span><span class="n">this_context</span><span class="p">,</span> <span class="n">this_name</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">this_userarg</span><span class="p">,</span> <span class="o">&</span><span class="n">this_transaction_id</span><span class="p">,</span> <span class="n">this_callbackfn</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">dns_request_return</span> <span class="o">==</span> <span class="n">GETDNS_RETURN_BAD_DOMAIN_NAME</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"A bad domain name was used: %s. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_name</span><span class="p">);</span> <span class="n">event_base_free</span><span class="p">(</span><span class="n">this_event_base</span><span class="p">);</span> <span class="n">getdns_context_destroy</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="k">return</span><span class="p">(</span><span class="n">GETDNS_RETURN_GENERIC_ERROR</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="cm">/* Call the event loop */</span> <span class="kt">int</span> <span class="n">dispatch_return</span> <span class="o">=</span> <span class="n">event_base_dispatch</span><span class="p">(</span><span class="n">this_event_base</span><span class="p">);</span> <span class="n">UNUSED_PARAM</span><span class="p">(</span><span class="n">dispatch_return</span><span class="p">);</span> <span class="c1">// TODO: check the return value above</span> <span class="p">}</span> <span class="cm">/* Clean up */</span> <span class="n">event_base_free</span><span class="p">(</span><span class="n">this_event_base</span><span class="p">);</span> <span class="n">getdns_context_destroy</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="cm">/* Assuming we get here, leave gracefully */</span> <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_SUCCESS</span><span class="p">);</span> <span class="p">}</span> </pre></div> <h2>6.2 Get IPv4 and IPv6 Addresses for a Domain Name</h2> <p>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.</p> <br><div class="highlight"><pre><span class="cp">#include <stdio.h></span> <span class="cp">#include <stdint.h></span> <span class="cp">#include <stdlib.h></span> <span class="cp">#include <string.h></span> <span class="cp">#include <inttypes.h></span> <span class="cp">#include <getdns_libevent.h></span> <span class="cp">#define UNUSED_PARAM(x) ((void)(x))</span> <span class="cm">/* Set up the callback function, which will also do the processing of the results */</span> <span class="kt">void</span> <span class="nf">this_callbackfn</span><span class="p">(</span><span class="k">struct</span> <span class="n">getdns_context</span> <span class="o">*</span><span class="n">this_context</span><span class="p">,</span> <span class="kt">getdns_return_t</span> <span class="n">this_callback_type</span><span class="p">,</span> <span class="k">struct</span> <span class="n">getdns_dict</span> <span class="o">*</span><span class="n">this_response</span><span class="p">,</span> <span class="kt">void</span> <span class="o">*</span><span class="n">this_userarg</span><span class="p">,</span> <span class="kt">getdns_transaction_t</span> <span class="n">this_transaction_id</span><span class="p">)</span> <span class="p">{</span> <span class="n">UNUSED_PARAM</span><span class="p">(</span><span class="n">this_userarg</span><span class="p">);</span> <span class="cm">/* Not looking at the userarg for this example */</span> <span class="n">UNUSED_PARAM</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="cm">/* Not looking at the context for this example */</span> <span class="kt">getdns_return_t</span> <span class="n">this_ret</span><span class="p">;</span> <span class="cm">/* Holder for all function returns */</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_callback_type</span> <span class="o">==</span> <span class="n">GETDNS_CALLBACK_COMPLETE</span><span class="p">)</span> <span class="cm">/* This is a callback with data */</span> <span class="p">{</span> <span class="cm">/* Be sure the search returned something */</span> <span class="kt">uint32_t</span> <span class="n">this_error</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_int</span><span class="p">(</span><span class="n">this_response</span><span class="p">,</span> <span class="s">"status"</span><span class="p">,</span> <span class="o">&</span><span class="n">this_error</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_error</span> <span class="o">!=</span> <span class="n">GETDNS_RESPSTATUS_GOOD</span><span class="p">)</span> <span class="c1">// If the search didn't return "good"</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"The search had no results, and a return value of %d. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_error</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="cm">/* Find all the answers returned */</span> <span class="k">struct</span> <span class="n">getdns_list</span> <span class="o">*</span> <span class="n">these_answers</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_list</span><span class="p">(</span><span class="n">this_response</span><span class="p">,</span> <span class="s">"replies_tree"</span><span class="p">,</span> <span class="o">&</span><span class="n">these_answers</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_ret</span> <span class="o">==</span> <span class="n">GETDNS_RETURN_NO_SUCH_DICT_NAME</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Weird: the response had no error, but also no replies_tree. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kt">size_t</span> <span class="n">num_answers</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_list_get_length</span><span class="p">(</span><span class="n">these_answers</span><span class="p">,</span> <span class="o">&</span><span class="n">num_answers</span><span class="p">);</span> <span class="cm">/* Go through each answer */</span> <span class="k">for</span> <span class="p">(</span> <span class="kt">size_t</span> <span class="n">rec_count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">rec_count</span> <span class="o"><</span> <span class="n">num_answers</span><span class="p">;</span> <span class="o">++</span><span class="n">rec_count</span> <span class="p">)</span> <span class="p">{</span> <span class="k">struct</span> <span class="n">getdns_dict</span> <span class="o">*</span> <span class="n">this_record</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_list_get_dict</span><span class="p">(</span><span class="n">these_answers</span><span class="p">,</span> <span class="n">rec_count</span><span class="p">,</span> <span class="o">&</span><span class="n">this_record</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="cm">/* Get the answer section */</span> <span class="k">struct</span> <span class="n">getdns_list</span> <span class="o">*</span> <span class="n">this_answer</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_list</span><span class="p">(</span><span class="n">this_record</span><span class="p">,</span> <span class="s">"answer"</span><span class="p">,</span> <span class="o">&</span><span class="n">this_answer</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="cm">/* Get each RR in the answer section */</span> <span class="kt">size_t</span> <span class="n">num_rrs</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_list_get_length</span><span class="p">(</span><span class="n">this_answer</span><span class="p">,</span> <span class="o">&</span><span class="n">num_rrs</span><span class="p">);</span> <span class="k">for</span> <span class="p">(</span> <span class="kt">size_t</span> <span class="n">rr_count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">rr_count</span> <span class="o"><</span> <span class="n">num_rrs</span><span class="p">;</span> <span class="o">++</span><span class="n">rr_count</span> <span class="p">)</span> <span class="p">{</span> <span class="k">struct</span> <span class="n">getdns_dict</span> <span class="o">*</span><span class="n">this_rr</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_list_get_dict</span><span class="p">(</span><span class="n">this_answer</span><span class="p">,</span> <span class="n">rr_count</span><span class="p">,</span> <span class="o">&</span><span class="n">this_rr</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="cm">/* Get the RDATA */</span> <span class="k">struct</span> <span class="n">getdns_dict</span> <span class="o">*</span> <span class="n">this_rdata</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_dict</span><span class="p">(</span><span class="n">this_rr</span><span class="p">,</span> <span class="s">"rdata"</span><span class="p">,</span> <span class="o">&</span><span class="n">this_rdata</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="cm">/* Get the RDATA type */</span> <span class="kt">uint32_t</span> <span class="n">this_type</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_int</span><span class="p">(</span><span class="n">this_rr</span><span class="p">,</span> <span class="s">"type"</span><span class="p">,</span> <span class="o">&</span><span class="n">this_type</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="cm">/* If it is type A or AAAA, print the value */</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_type</span> <span class="o">==</span> <span class="n">GETDNS_RRTYPE_A</span><span class="p">)</span> <span class="p">{</span> <span class="k">struct</span> <span class="n">getdns_bindata</span> <span class="o">*</span> <span class="n">this_a_record</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_bindata</span><span class="p">(</span><span class="n">this_rdata</span><span class="p">,</span> <span class="s">"ipv4_address"</span><span class="p">,</span> <span class="o">&</span><span class="n">this_a_record</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_ret</span> <span class="o">==</span> <span class="n">GETDNS_RETURN_NO_SUCH_DICT_NAME</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Weird: the A record at %d in record at %d had no address. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">rr_count</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">rec_count</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kt">char</span> <span class="o">*</span><span class="n">this_address_str</span> <span class="o">=</span> <span class="n">getdns_display_ip_address</span><span class="p">(</span><span class="n">this_a_record</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"The IPv4 address is %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_address_str</span><span class="p">);</span> <span class="n">free</span><span class="p">(</span><span class="n">this_address_str</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_type</span> <span class="o">==</span> <span class="n">GETDNS_RRTYPE_AAAA</span><span class="p">)</span> <span class="p">{</span> <span class="k">struct</span> <span class="n">getdns_bindata</span> <span class="o">*</span> <span class="n">this_aaaa_record</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_bindata</span><span class="p">(</span><span class="n">this_rdata</span><span class="p">,</span> <span class="s">"ipv6_address"</span><span class="p">,</span> <span class="o">&</span><span class="n">this_aaaa_record</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_ret</span> <span class="o">==</span> <span class="n">GETDNS_RETURN_NO_SUCH_DICT_NAME</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Weird: the AAAA record at %d in record at %d had no address. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">rr_count</span><span class="p">,</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span> <span class="n">rec_count</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="k">return</span><span class="p">;</span> <span class="p">}</span> <span class="kt">char</span> <span class="o">*</span><span class="n">this_address_str</span> <span class="o">=</span> <span class="n">getdns_display_ip_address</span><span class="p">(</span><span class="n">this_aaaa_record</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"The IPv6 address is %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_address_str</span><span class="p">);</span> <span class="n">free</span><span class="p">(</span><span class="n">this_address_str</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="p">}</span> <span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_callback_type</span> <span class="o">==</span> <span class="n">GETDNS_CALLBACK_CANCEL</span><span class="p">)</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"The callback with ID %"</span><span class="n">PRIu64</span><span class="s">" was cancelled. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_transaction_id</span><span class="p">);</span> <span class="k">else</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"The callback got a callback_type of %d. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_callback_type</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="p">}</span> <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> <span class="cm">/* Create the DNS context for this call */</span> <span class="k">struct</span> <span class="n">getdns_context</span> <span class="o">*</span><span class="n">this_context</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> <span class="kt">getdns_return_t</span> <span class="n">context_create_return</span> <span class="o">=</span> <span class="n">getdns_context_create</span><span class="p">(</span><span class="o">&</span><span class="n">this_context</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">context_create_return</span> <span class="o">!=</span> <span class="n">GETDNS_RETURN_GOOD</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Trying to create the context failed: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">context_create_return</span><span class="p">);</span> <span class="k">return</span><span class="p">(</span><span class="n">GETDNS_RETURN_GENERIC_ERROR</span><span class="p">);</span> <span class="p">}</span> <span class="cm">/* Create an event base and put it in the context using the unknown function name */</span> <span class="k">struct</span> <span class="n">event_base</span> <span class="o">*</span><span class="n">this_event_base</span><span class="p">;</span> <span class="n">this_event_base</span> <span class="o">=</span> <span class="n">event_base_new</span><span class="p">();</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_event_base</span> <span class="o">==</span> <span class="nb">NULL</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Trying to create the event base failed.</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span> <span class="n">getdns_context_destroy</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="k">return</span><span class="p">(</span><span class="n">GETDNS_RETURN_GENERIC_ERROR</span><span class="p">);</span> <span class="p">}</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">getdns_extension_set_libevent_base</span><span class="p">(</span><span class="n">this_context</span><span class="p">,</span> <span class="n">this_event_base</span><span class="p">);</span> <span class="cm">/* Set up the getdns call */</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">this_name</span> <span class="o">=</span> <span class="s">"www.example.com"</span><span class="p">;</span> <span class="kt">char</span><span class="o">*</span> <span class="n">this_userarg</span> <span class="o">=</span> <span class="s">"somestring"</span><span class="p">;</span> <span class="c1">// Could add things here to help identify this call</span> <span class="kt">getdns_transaction_t</span> <span class="n">this_transaction_id</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="cm">/* Make the call */</span> <span class="kt">getdns_return_t</span> <span class="n">dns_request_return</span> <span class="o">=</span> <span class="n">getdns_address</span><span class="p">(</span><span class="n">this_context</span><span class="p">,</span> <span class="n">this_name</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">this_userarg</span><span class="p">,</span> <span class="o">&</span><span class="n">this_transaction_id</span><span class="p">,</span> <span class="n">this_callbackfn</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">dns_request_return</span> <span class="o">==</span> <span class="n">GETDNS_RETURN_BAD_DOMAIN_NAME</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"A bad domain name was used: %s. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_name</span><span class="p">);</span> <span class="n">event_base_free</span><span class="p">(</span><span class="n">this_event_base</span><span class="p">);</span> <span class="n">getdns_context_destroy</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="k">return</span><span class="p">(</span><span class="n">GETDNS_RETURN_GENERIC_ERROR</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="cm">/* Call the event loop */</span> <span class="kt">int</span> <span class="n">dispatch_return</span> <span class="o">=</span> <span class="n">event_base_dispatch</span><span class="p">(</span><span class="n">this_event_base</span><span class="p">);</span> <span class="n">UNUSED_PARAM</span><span class="p">(</span><span class="n">dispatch_return</span><span class="p">);</span> <span class="c1">// TODO: check the return value above</span> <span class="p">}</span> <span class="cm">/* Clean up */</span> <span class="n">event_base_free</span><span class="p">(</span><span class="n">this_event_base</span><span class="p">);</span> <span class="n">getdns_context_destroy</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="cm">/* Assuming we get here, leave gracefully */</span> <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_SUCCESS</span><span class="p">);</span> <span class="p">}</span> </pre></div> <h2>6.3 Get Addresses for a Domain Name And Their Associated DNSSEC Validation Status</h2> <p>This example shows how to check for secure DNSSEC results using the <code>dnssec_return_status</code> 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 <code>extensions</code> argument of the call.</p> <pre> 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 } } . . . </pre> <p>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.</p> <h2>6.4 Using the API Synchronously with <code>getdns_general_sync()</code></h2> <p>This example is the same as the earlier examples, but uses <code>getdns_general_sync()</code> 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 <code>main()</code>.</p> <br><div class="highlight"><pre><span class="cp">#include <stdio.h></span> <span class="cp">#include <stdint.h></span> <span class="cp">#include <stdlib.h></span> <span class="cp">#include <string.h></span> <span class="cp">#include <inttypes.h></span> <span class="cp">#include <getdns_core_only.h></span> <span class="kt">int</span> <span class="nf">main</span><span class="p">()</span> <span class="p">{</span> <span class="kt">getdns_return_t</span> <span class="n">this_ret</span><span class="p">;</span> <span class="cm">/* Holder for all function returns */</span> <span class="cm">/* Create the DNS context for this call */</span> <span class="k">struct</span> <span class="n">getdns_context</span> <span class="o">*</span><span class="n">this_context</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> <span class="kt">getdns_return_t</span> <span class="n">context_create_return</span> <span class="o">=</span> <span class="n">getdns_context_create</span><span class="p">(</span><span class="o">&</span><span class="n">this_context</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">context_create_return</span> <span class="o">!=</span> <span class="n">GETDNS_RETURN_GOOD</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Trying to create the context failed: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">context_create_return</span><span class="p">);</span> <span class="k">return</span><span class="p">(</span><span class="n">GETDNS_RETURN_GENERIC_ERROR</span><span class="p">);</span> <span class="p">}</span> <span class="cm">/* Set up the getdns_sync_request call */</span> <span class="k">const</span> <span class="kt">char</span> <span class="o">*</span> <span class="n">this_name</span> <span class="o">=</span> <span class="s">"www.example.com"</span><span class="p">;</span> <span class="kt">uint8_t</span> <span class="n">this_request_type</span> <span class="o">=</span> <span class="n">GETDNS_RRTYPE_A</span><span class="p">;</span> <span class="cm">/* Get the A and AAAA records */</span> <span class="k">struct</span> <span class="n">getdns_dict</span> <span class="o">*</span> <span class="n">this_extensions</span> <span class="o">=</span> <span class="n">getdns_dict_create</span><span class="p">();</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_set_int</span><span class="p">(</span><span class="n">this_extensions</span><span class="p">,</span> <span class="s">"return_both_v4_and_v6"</span><span class="p">,</span> <span class="n">GETDNS_EXTENSION_TRUE</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_ret</span> <span class="o">!=</span> <span class="n">GETDNS_RETURN_GOOD</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Trying to set an extension do both IPv4 and IPv6 failed: %d</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_ret</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_extensions</span><span class="p">);</span> <span class="n">getdns_context_destroy</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="k">return</span><span class="p">(</span><span class="n">GETDNS_RETURN_GENERIC_ERROR</span><span class="p">);</span> <span class="p">}</span> <span class="k">struct</span> <span class="n">getdns_dict</span> <span class="o">*</span> <span class="n">this_response</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span> <span class="cm">/* Make the call */</span> <span class="kt">getdns_return_t</span> <span class="n">dns_request_return</span> <span class="o">=</span> <span class="n">getdns_general_sync</span><span class="p">(</span><span class="n">this_context</span><span class="p">,</span> <span class="n">this_name</span><span class="p">,</span> <span class="n">this_request_type</span><span class="p">,</span> <span class="n">this_extensions</span><span class="p">,</span> <span class="o">&</span><span class="n">this_response</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">dns_request_return</span> <span class="o">==</span> <span class="n">GETDNS_RETURN_BAD_DOMAIN_NAME</span><span class="p">)</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"A bad domain name was used: %s. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_name</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_extensions</span><span class="p">);</span> <span class="n">getdns_context_destroy</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="k">return</span><span class="p">(</span><span class="n">GETDNS_RETURN_GENERIC_ERROR</span><span class="p">);</span> <span class="p">}</span> <span class="k">else</span> <span class="p">{</span> <span class="cm">/* Be sure the search returned something */</span> <span class="kt">uint32_t</span> <span class="n">this_error</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_int</span><span class="p">(</span><span class="n">this_response</span><span class="p">,</span> <span class="s">"status"</span><span class="p">,</span> <span class="o">&</span><span class="n">this_error</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="k">if</span> <span class="p">(</span><span class="n">this_error</span> <span class="o">!=</span> <span class="n">GETDNS_RESPSTATUS_GOOD</span><span class="p">)</span> <span class="c1">// If the search didn't return "good"</span> <span class="p">{</span> <span class="n">fprintf</span><span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"The search had no results, and a return value of %d. Exiting.</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_error</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_extensions</span><span class="p">);</span> <span class="n">getdns_context_destroy</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="k">return</span><span class="p">(</span><span class="n">GETDNS_RETURN_GENERIC_ERROR</span><span class="p">);</span> <span class="p">}</span> <span class="k">struct</span> <span class="n">getdns_list</span> <span class="o">*</span> <span class="n">just_the_addresses_ptr</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_list</span><span class="p">(</span><span class="n">this_response</span><span class="p">,</span> <span class="s">"just_address_answers"</span><span class="p">,</span> <span class="o">&</span><span class="n">just_the_addresses_ptr</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="kt">size_t</span> <span class="n">num_addresses</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_list_get_length</span><span class="p">(</span><span class="n">just_the_addresses_ptr</span><span class="p">,</span> <span class="o">&</span><span class="n">num_addresses</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="cm">/* Go through each record */</span> <span class="k">for</span> <span class="p">(</span> <span class="kt">size_t</span> <span class="n">rec_count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="n">rec_count</span> <span class="o"><</span> <span class="n">num_addresses</span><span class="p">;</span> <span class="o">++</span><span class="n">rec_count</span> <span class="p">)</span> <span class="p">{</span> <span class="k">struct</span> <span class="n">getdns_dict</span> <span class="o">*</span> <span class="n">this_address</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_list_get_dict</span><span class="p">(</span><span class="n">just_the_addresses_ptr</span><span class="p">,</span> <span class="n">rec_count</span><span class="p">,</span> <span class="o">&</span><span class="n">this_address</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="cm">/* Just print the address */</span> <span class="k">struct</span> <span class="n">getdns_bindata</span> <span class="o">*</span> <span class="n">this_address_data</span><span class="p">;</span> <span class="n">this_ret</span> <span class="o">=</span> <span class="n">getdns_dict_get_bindata</span><span class="p">(</span><span class="n">this_address</span><span class="p">,</span> <span class="s">"address_data"</span><span class="p">,</span> <span class="o">&</span><span class="n">this_address_data</span><span class="p">);</span> <span class="c1">// Ignore any error</span> <span class="kt">char</span> <span class="o">*</span><span class="n">this_address_str</span> <span class="o">=</span> <span class="n">getdns_display_ip_address</span><span class="p">(</span><span class="n">this_address_data</span><span class="p">);</span> <span class="n">printf</span><span class="p">(</span><span class="s">"The address is %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">this_address_str</span><span class="p">);</span> <span class="n">free</span><span class="p">(</span><span class="n">this_address_str</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="cm">/* Clean up */</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_response</span><span class="p">);</span> <span class="n">getdns_dict_destroy</span><span class="p">(</span><span class="n">this_extensions</span><span class="p">);</span> <span class="n">getdns_context_destroy</span><span class="p">(</span><span class="n">this_context</span><span class="p">);</span> <span class="cm">/* Assuming we get here, leave gracefully */</span> <span class="n">exit</span><span class="p">(</span><span class="n">EXIT_SUCCESS</span><span class="p">);</span> <span class="p">}</span> </pre></div> <h2>6.5 Getting Names from the Reverse Tree with <code>getdns_hostname()</code></h2> <p>This example shows how to use <code>getdns_hostname()</code> to get names from the DNS reverse tree.</p> <p>[[[[ Something will go here soon ]]]]]</p> <!--EXAMPLESREVERSE--> <h1>7. More Helper Functions</h1> <p>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.</p> <div class=forh>char * getdns_convert_ulabel_to_alabel( char *ulabel ); </div> <div class=forh>char * getdns_convert_alabel_to_ulabel( char *alabel ); </div> <p>If an application wants the API do perform DNSSEC validation without using the extensions, it can use the <code>getdns_validate_dnssec()</code> helper function.</p> <div class=forh>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 ); </div> <p class=cont>The <code>record_to_validate</code> is the resource record being validated. The API will use the resource records in <code>bundle_of_support_records</code> and the RDATAs in the <code>trust_ancor_rdatas</code> as trust anchors. The function returns one of <code>GETDNS_DNSSEC_SECURE</code>, <code>GETDNS_DNSSEC_BOGUS</code>, <code>GETDNS_DNSSEC_INDETERMINATE</code>, or <code>GETDNS_DNSSEC_INSECURE</code>.</p> <p>There are two functions that help process data:</p> <div class=forh> char * getdns_pretty_print_dict( struct getdns_dict *some_dict ); </div> <p class=cont>This returns a string that is the nicely-formatted version of the dict and all of the named elements in it.</p> <div class=forh> char * getdns_display_ip_address( struct getdns_bindata *bindata_of_ipv4_or_ipv6_address ); </div> <p class=cont>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.</p> <h1>8. <a id="Contexts">DNS Contexts</a></h1> <p>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.</p> <p>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.</p> <p>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.</p> <p>See <a href="#ContextInitial">above</a> for the method for creating and destroying contexts. When the context is used in the API for the first time and <code>set_from_os</code> is <code>1</code>, 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 <code>set_from_os</code> is <code>0</code>, 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.</p> <h2>8.1 Updating the Context Automatically</h2> <p>The context returned by <code>getdns_context_create()</code> 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 <code>getdns_context_set_context_update_callback()</code> (described below) is called.</p> <p>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 <code>getaddrinfo()</code> when creating a new context. This includes making lookups in WINS for NetBIOS, mDNS lookups, nis names, and any other name lookup that <code>getaddrinfo()</code> normally does automatically. The API should look at nsswitch, the Windows resolver, and so on.</p> <p>In the function definitions below, the choice listed <span class=default>in bold</span> is the one used for the API default context.</p> <h2>8.2 Updating the Context Manually</h2> <p>Setting specific values in a context are done with value-specific functions shown here. The setting functions all return either <code>GETDNS_RETURN_GOOD</code> for success, <code>GETDNS_RETURN_BAD_CONTEXT</code> for trying to set a type with a value that is not allowed, or <code>GETDNS_RETURN_CONTEXT_UPDATE_FAIL</code> for a failure to update the context.</p> <p>An application can be notified when the context is changed.</p> <div class=forh> getdns_return_t getdns_context_set_context_update_callback( struct getdns_context *context, void (*value)(struct getdns_context *context, uint16_t changed_item) );</div> <p class=cont>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 <a href="#ContextCodes">later in this document</a>.</p> <h2>8.3 Contexts for Basic Resolution</h2> <div class=forh> getdns_return_t getdns_context_set_resolution_type( struct getdns_context *context, uint16_t value );</div> <p class=cont>Specifies whether DNS queries are performed with nonrecurive lookups or as a stub resolver. The value is <span class=default><code>GETDNS_CONTEXT_RECURSING</code></span> or <code>GETDNS_CONTEXT_STUB</code>.</p> <p>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 <code>getdns_context_set_resolution_type(somecontext, GETDNS_CONTEXT_STUB)</code> will return <code>GETDNS_RETURN_CONTEXT_UPDATE_FAIL</code>.</p> <div class=forh> getdns_return_t getdns_context_set_namespaces( struct getdns_context *context, size_t namespace_count, uint16_t *namespaces );</div> <p class=cont>The <code>namespaces</code> array contains an ordered list of namespaces that will be queried. <b>Important:</b> this context setting is ignored for the <code>getdns_general</code> and <code>getdns_general_sync</code> functions; it is used for the other funtions. The values are <code>GETDNS_CONTEXT_NAMESPACE_DNS</code>, <code>GETDNS_CONTEXT_NAMESPACE_LOCALNAMES</code>, <code>GETDNS_CONTEXT_NAMESPACE_NETBIOS</code>, <code>GETDNS_CONTEXT_NAMESPACE_MDNS</code>, and <code>GETDNS_CONTEXT_NAMESPACE_NIS</code>. 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 <code>getaddrinfo()</code>. The default is <span class=default>determined by the OS</span>.</p> <div class=forh> getdns_return_t getdns_context_set_dns_transport( struct getdns_context *context, uint16_t value );</div> <p class=cont>Specifies what transport is used for DNS lookups. The value is <span class=default> <code>GETDNS_CONTEXT_UDP_FIRST_AND_FALL_BACK_TO_TCP</code></span>, <code>GETDNS_CONTEXT_UDP_ONLY</code>, <code>GETDNS_CONTEXT_TCP_ONLY</code>, or <code>GETDNS_CONTEXT_TCP_ONLY_KEEP_CONNECTIONS_OPEN</code>.</p> <div class=forh> getdns_return_t getdns_context_set_limit_outstanding_queries( struct getdns_context *context, uint16_t limit );</div> <p class=cont>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 <span class=default>0</span> indicates that the number of outstanding DNS queries is unlimited.</p> <div class=forh> getdns_return_t getdns_context_set_timeout( struct getdns_context *context, uint16_t timeout );</div> <p class=cont>Specifies number of seconds the API will wait for request to return. The default is <span class=default>not specified</span>.</p> <h2>8.4 Context for Recursive Resolvers</h2> <div class=forh> getdns_return_t getdns_context_set_follow_redirects( struct getdns_context *context, uint16_t value );</div> <p class=cont>Specifies whether or not DNS queries follow redirects. The value is <span class=default><code>GETDNS_CONTEXT_FOLLOW_REDIRECTS</code></span> for normal following of redirects though CNAME and DNAME; or <code>GETDNS_CONTEXT_DO_NOT_FOLLOW_REDIRECTS</code> to cause any lookups that would have gone through CNAME and DNAME to return the CNAME or DNAME, not the eventual target.</p> <div class=forh> getdns_return_t getdns_context_set_dns_root_servers( struct getdns_context *context, struct getdns_list *addresses );</div> <p class=cont>The list contains dicts that are addresses to be used for looking up top-level domains; the default is the list of <b>"normal" IANA root servers</b>. Each dict in the list contains at least two names: <code>address_type</code> (whose value is a bindata; it is currently either "IPv4" or "IPv6") and <code>address_data</code> (whose value is a bindata).</p> <h2>8.5 Context for Local Naming</h2> <div class=forh> getdns_return_t getdns_context_set_append_name( struct getdns_context *context, uint16_t value );</div> <p class=cont>Specifies whether to append a suffix to the query string before the API starts resolving a name. The value is <span class=default> <code>GETDNS_CONTEXT_APPEND_NAME_ALWAYS</code></span>, <code>GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_SINGLE_LABEL_AFTER_FAILURE</code>, <code>GETDNS_CONTEXT_APPEND_NAME_ONLY_TO_MULTIPLE_LABEL_NAME_AFTER_FAILURE</code>, or <code>GETDNS_CONTEXT_DO_NOT_APPEND_NAMES</code>. This controls whether or not to append the suffix given by <code>getdns_context_set_suffix</code></p> <div class=forh> getdns_return_t getdns_context_set_suffix( struct getdns_context *context, struct getdns_list *value );</div> <p class=cont>The value is a list of bindatas that are strings that are to be appended based on <code>getdns_context_set_append_name</code>; the default is an <span class=default>empty list</span>. The values here follow the rules in section 2.1 of RFC 4343 to allow non-ASCII octets and special characters in labels.</p> <h2>8.6 Context for DNSSEC</h2> <p>These context settings affect queries that have extensions that specify the use of DNSSEC.</p> <p>Applications that need to specify the DNSSEC trust anchors can use:</p> <div class=forh> getdns_return_t getdns_context_set_dnssec_trust_anchors( struct getdns_context *context, struct getdns_list *value );</div> <p class=cont>The value is a list of bindatas that are the DNSSEC trust anchors. The default is the trust anchors from the <span class=default>IANA root</span>. The trust anchors are expressed as RDATAs from DNSKEY resource records.</p> <p>In the rare case that an application needs to set the DNSSEC skew, it can:</p> <div class=forh> getdns_return_t getdns_context_set_dnssec_allowed_skew( struct getdns_context *context, uint16_t value );</div> <p class=cont>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 <span class=default>0</span>.</p> <h2>8.7 Context Specific to Stub Resolvers</h2> <p>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.</p> <p>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 <code>getdns_validate_dnssec()</code> function.</p> <div class=forh> getdns_return_t getdns_context_set_stub_resolution( struct getdns_context *context, struct getdns_list *upstream_list );</div> <p class=cont>The list of dicts define where a stub resolver will send queries. Each dict contains at least two names: <code>address_type</code> (whose value is a bindata; it is currently either "IPv4" or "IPv6") and <code>address_data</code> (whose value is a bindata). It might also contain <code>port</code> 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 <code>upstream_list</code> entry can also contain <code>tsig_algorithm</code> (a bindata) that is the name of the TSIG hash algorithm, and <code>tsig_secret</code> (a bindata) that is the TSIG key.</p> <h2>8.8 Context for EDNS</h2> <p>These context settings affect queries that have extensions that specify the use of OPT resource records. These come from RFC 2671.</p> <div class=forh> getdns_return_t getdns_context_set_edns_maximum_udp_payload_size( struct getdns_context *context, uint16_t value );</div> <p class=cont>The value is between 512 and 65535; the default is <span class=default>512</span>.</p> <div class=forh> getdns_return_t getdns_context_set_edns_extended_rcode( struct getdns_context *context, uint8_t value );</div> <p class=cont>The value is between 0 and 255; the default is <span class=default>0</span>.</p> <div class=forh> getdns_return_t getdns_context_set_edns_version( struct getdns_context *context, uint8_t value );</div> <p class=cont>The value is between 0 and 255; the default is <span class=default>0</span>.</p> <div class=forh> getdns_return_t getdns_context_set_edns_do_bit( struct getdns_context *context, uint8_t value );</div> <p class=cont>The value is between 0 and 1; the default is <span class=default>0</span>.</p> <h2>8.9 Context Use of Custom Memory Management Functions</h2> <div class=forh> getdns_return_t getdns_context_set_memory_functions( struct getdns_context *context, void *(*malloc) (size_t), void *(*realloc) (void *, size_t), void (*free) (void *) );</div> <p class=cont>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 <span class=default>malloc</span>, <span class=default>realloc</span>, and <span>free</span> are used.</p> <div class=forh> 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) );</div> <p class=cont>The given extended memory management functions will be used for creating the response dicts. The value of <code>userarg</code> argument will be passed to the custom <code>malloc</code>, <code>realloc</code>, and <code>free</code>. The response dicts inherit the custom memory management functions and the value for <code>userarg</code> from the context and will deallocate themselves (and their members) with the custom deallocator.</p> <h2>8.10 <a id="ContextCodes">Context Codes</a></h2> <p>The context codes for <code>getdns_context_set_context_update_callback()</code> are:</p> <p class=define>GETDNS_CONTEXT_CODE_NAMESPACES</p> <p class=descrip>Change related to <code>getdns_context_set_namespaces</code></p> <p class=define>GETDNS_CONTEXT_CODE_RESOLUTION_TYPE</p> <p class=descrip>Change related to <code>getdns_context_set_resolution_type</code></p> <p class=define>GETDNS_CONTEXT_CODE_FOLLOW_REDIRECTS</p> <p class=descrip>Change related to <code>getdns_context_set_follow_redirects</code></p> <p class=define>GETDNS_CONTEXT_CODE_UPSTREAM_RECURSIVE_SERVERS</p> <p class=descrip>Change related to <code>getdns_context_set_upstream_recursive_servers</code></p> <p class=define>GETDNS_CONTEXT_CODE_DNS_ROOT_SERVERS</p> <p class=descrip>Change related to <code>getdns_context_set_dns_root_servers</code></p> <p class=define>GETDNS_CONTEXT_CODE_DNS_TRANSPORT</p> <p class=descrip>Change related to <code>getdns_context_set_dns_transport</code></p> <p class=define>GETDNS_CONTEXT_CODE_LIMIT_OUTSTANDING_QUERIES</p> <p class=descrip>Change related to <code>getdns_context_set_limit_outstanding_queries</code></p> <p class=define>GETDNS_CONTEXT_CODE_APPEND_NAME</p> <p class=descrip>Change related to <code>getdns_context_set_append_name</code></p> <p class=define>GETDNS_CONTEXT_CODE_SUFFIX</p> <p class=descrip>Change related to <code>getdns_context_set_suffix</code></p> <p class=define>GETDNS_CONTEXT_CODE_DNSSEC_TRUST_ANCHORS</p> <p class=descrip>Change related to <code>getdns_context_set_dnssec_trust_anchors</code></p> <p class=define>GETDNS_CONTEXT_CODE_EDNS_MAXIMUM_UDP_PAYLOAD_SIZE</p> <p class=descrip>Change related to <code>getdns_context_set_edns_maximum_udp_payload_size</code></p> <p class=define>GETDNS_CONTEXT_CODE_EDNS_EXTENDED_RCODE</p> <p class=descrip>Change related to <code>getdns_context_set_edns_extended_rcode</code></p> <p class=define>GETDNS_CONTEXT_CODE_EDNS_VERSION</p> <p class=descrip>Change related to <code>getdns_context_set_edns_version</code></p> <p class=define>GETDNS_CONTEXT_CODE_EDNS_DO_BIT</p> <p class=descrip>Change related to <code>getdns_context_set_edns_do_bit</code></p> <p class=define>GETDNS_CONTEXT_CODE_DNSSEC_ALLOWED_SKEW</p> <p class=descrip>Change related to <code>getdns_context_set_dnssec_allowed_skew</code></p> <p class=define>GETDNS_CONTEXT_CODE_MEMORY_FUNCTIONS</p> <p class=descrip>Change related to <code>getdns_context_set_memory_functions</code></p> <p class=define>GETDNS_CONTEXT_CODE_TIMEOUT</p> <p class=descrip>Change related to <code>getdns_context_set_timeout</code></p> <h1>9. The Generated Files</h1> <p>There is <a href="getdns-0.374.tgz">a tarball</a> 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.</p> <h1>10. <a id="Commentary">Commentary</a></h1> <p>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.</p> <h2>10.1 API Design Considerations</h2> <p>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.</p> <p>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 <code>getaddrinfo()</code> 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.</p> <p>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.</p> <p>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.</p> <p>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.</p> <p>The API relies heavily on C macros and hopefully has no magic numbers.</p> <h2>10.2 API Implementation Considerations</h2> <p>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.</p> <p>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 <code>getdns_general_sync()</code>.</p> <p>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.</p> <p>The API's .h file contains a macro called <code>GETDNS_COMPILATION_COMMENT</code>. 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.</p> <p>The implementation of both the async and sync <code>getdns</code> functions will copy all the values of the parameters into local memory, in case the application changes or deallocates them.</p> <hr width=90%> <p><a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_US"><img alt="Creative Commons License" style="border-width:0" src="http://i.creativecommons.org/l/by/3.0/80x15.png" /></a><br />This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by/3.0/deed.en_US">Creative Commons Attribution 3.0 Unported License</a>.</p> </body></html>