libgetdns(3)
π libgetdns(3) β getdns π
okay bestie, buckle UP, because we're about to get into libgetdns, which lives in the getdns manual section, and it is literally the moment. This page is the big-picture one: the library, the β¨conceptsβ¨, and the shared bits of the public interface. Every single entry point and every spicy data type gets its own man page, so this is like the group chat intro, not the whole saga. π«Ά
π LIBRARY
DNS Resolver library (libgetdns, -lgetdns) β no cap, that's the vibe.
π SYNOPSIS
libgetdns
So this man page is the lore drop for the getdns library: the general concepts behind the API plus some of the common elements of the public interface. Each public entry point and the more complicated data types? They each get their own separate man page. iykyk. π
β¨ DESCRIPTION
getdns is a modern asynchronous DNS API made to be useful to application developers and operating system distributors, as a way of making all types of DNS information easily available in loads of different kinds of programs. And the major features of this new API are, in no particular order of iconicity:
- Full support for event-driven programming
- Supports DNSSEC in multiple ways
- Mirroring of the resolution in
getaddrinfo() - Easily supports all RRtypes, even those yet to be defined π
Every single entry point shows up in both an asynchronous and a synchronous signature. The async functions rely on event handling and callback via libevent. And yes, the functions are thread safe, we stay safe out here. π§
A context structure keeps the DNS query and response data, and it's what holds state during calls to the public entry points.
The project page for this implementation is at
http://getdnsapi.net
The specification is maintained at
http://getdnsapi.net/spec
The git repository for this implementation is at
http://github.com/getdnsapi/getdns
π DATA STRUCTURES
The API uses a few data structures to pass data into and return data from the public entry points. Four of them, and they're all doing their thing:
listβ an ordered list, and the members of the list can be any of the four data types.dictβ a name-value pair. The name is a string literal, and the value can be any of the four data types. The order of the name-value pairs in a dict is not important, so don't stress about it.intβ an integer compatible withuint32_t.bindataβ a struct used to hold binary data, defined as{ size_t size; uint8_t *binary_stuff; }.
π¦ ASYNCHRONOUS USE
The getdns specification is highkey obsessed with the asynchronous nature of the API, and it lets implementations define their own approach. This page documents this implementation's decisions and the facilities provided to the developer. π
This implementation provides asynchronous support via the following mechanisms:
- File Descriptor Polling
- Event Loop Integrations:
- libevent
- libuv
- libev
- Custom Event Loop Integrations
All functions and types discussed in this page are declared in getdns_extra.h.
π₯ Build-in Event loop
The library has an built in event loop that you can use if none of the extensions for external event loops are used. The library will execute requests and dispatch callbacks with a call to getdns_context_run(). And if an event loop extension is used, this will run the extension's eventloop instead. slay.
void getdns_context_run(getdns_context *context)
- Run the context's event loop until nothing more to do.
uint32_t getdns_context_get_num_pending_requests(getdns_context* context, struct timeval* next_timeout)
- Get the number of outstanding asynchronous requests for a given context, plus the the amount of time until the next timeout. The
next_timeoutstruct can beNULL. If it's supplied and the number of outstanding requests is> 0, then the timeout represents the relative time until the next timeout.
getdns_return_t getdns_context_process_async(getdns_context* context)
- Inform the context to process its outstanding requests. You should call this when either a timeout has occurred or the file descriptor signals that it's ready. User callbacks are fired during this call. π«
πΈ Included Event Loop Integrations
A number of applications achieve asynchronous behavior by leveraging event loop abstraction libraries. If the build system discovers a supported event loop, the event loop extension gets built in addition to the getdns library. Extensions are built as an additional shared library. The following event loop libraries are supported:
libevent1 and libevent2
The libevent extension lets a context attach to a event_base. The event loop is then run like any other application using libevent, via event_base_dispatch or event_base_loop, and you can expect getdns callbacks to fire.
Heads up bestie: if both libevent1 and libevent2 live on the system, the extension uses libevent2.
Extension library: libgetdns_ext_event.[shared_lib_ext]
Extension header: getdns/getdns_ext_libevent.h
libuv
The libuv extension lets a context attach to a uv_loop_s. The event loop can then be run like any other application using libuv, via uv_run, and you can expect getdns callbacks to fire.
Extension library: libgetdns_ext_uv.[shared_lib_ext]
Extension header: getdns_ext_libuv.h
libev
The libev extension lets a context attach to a ev_loop. The event loop can then be run like any other application using libev, via ev_run, and you can expect getdns callbacks to fire.
Extension library: libgetdns_ext_ev.[shared_lib_ext]
Extension header: getdns_ext_libev.h
π getdns_context event loop extension functions
These are the functions used by the extension entry point to attach to a particular context.
The application sets an event loop extension on a context. The extension_data is optional data that gets passed into the extension methods. And okay, important: if an event loop is already set on a context, then it is cleaned up. All outstanding requests are also canceled. π
getdns_return_t getdns_extension_set_eventloop(struct getdns_context* context, getdns_eventloop_extension* extension, void* extension_data);
The application gets the extension data associated with a context.
void* getdns_context_get_extension_data(struct getdns_context* context);
When no more work must be done, the application detaches an event loop from a context.
getdns_return_t getdns_extension_detach_eventloop(struct getdns_context* context);
β SYNCHRONOUS USE
There are four synchronous functions parallel to the four getdns async functions, except there's no callback parameter. When an application calls one of these synchronous functions, the API gathers all the required information and then returns the result. And the value returned is exactly the same as the response returned in the callback if you'd used the async version of the function. fr fr.
When you're done with the data in the response, call getdns_free_sync_request_memory so the API can free the memory from its internal pool. please do this, bestie, we're not leaking. π
π EXTENSIONS
Applications may populate an extension dictionary when making a call to the public entry points. To use an extension, add it to the extension dictionary prior to making the call to the public entry point and set the value depending on the behavior you expect. These extensions include:
"dnssec_return_status"(int) β set toGETDNS_EXTENSION_TRUEto include the DNSSEC status for each DNS record in thereplies_tree."dnssec_return_only_secure"(int) β set toGETDNS_EXTENSION_TRUEto cause only records that the API can validate as secure with DNSSEC to be returned in thereplies_treeandreplies_fulllists."dnssec_return_validation_chain"(int) β set toGETDNS_EXTENSION_TRUEto cause the set of additional DNSSEC-related records needed for validation to be returned in the response object as the list namedadditional_dnssecat the top level of the response object."return_both_v4_and_v6"(int) β set toGETDNS_EXTENSION_TRUEto cause the results of both A and AAAA records for the queried name to be included in the response object."add_opt_parameters"(dict) β TBD (complicated). π«"add_warning_for_bad_dns"β set toGETDNS_EXTENSION_TRUEto cause each reply in thereplies_treeto contain an additional name whose data type is a list,bad_dns, which contains zero or more ints that indicate the types of bad DNS found in the reply.GETDNS_BAD_DNS_CNAME_IN_TARGET: query type does not allow a CNAME pointed to a CNAMEGETDNS_BAD_DNS_ALL_NUMERIC_LABEL: one or more labels is all numericGETDNS_BAD_DNS_CNAME_RETURNED_FOR_OTHER_TYPE: query type for other than CNAME returned a CNAME
"specify_class"(int) β set to the DNS class number (other than Internet (IN) class) desired in query."return_call_reporting"(int) β set toGETDNS_EXTENSION_TRUEto add the namecall_reporting(list) to the top level of the response object, which includes a dict for each call made to the API. TBD: more detail.
This implementation of the getdns API is licensed under the BSD license. π
π¦ DNSSEC π¦
So if your app wants the API to actually do DNSSEC validation for a request, you have to set one or more of the DNSSEC-related extensions. Heads up bestie: the default is that none of these are set, and the API will not do DNSSEC. And lowkey, getting DNSSEC results can take longer in a few circumstances, so don't come for us about the timing okay π
If you want the DNSSEC status for each DNS record in the replies_tree list, use the dnssec_return_status extension. Its value (an int) gets set to GETDNS_EXTENSION_TRUE, which makes the returned status show up as a name called dnssec_status (an int) added alongside the other names in the record's dict ("header", "question", and so on). The values for that name are GETDNS_DNSSEC_SECURE, GETDNS_DNSSEC_BOGUS, GETDNS_DNSSEC_INDETERMINATE, and GETDNS_DNSSEC_INSECURE. So like, a reply might look like:
{ # This is the first reply
"dnssec_status": GETDNS_DNSSEC_INDETERMINATE,
"header": { "id": 23456, "qr": 1, "opcode": 0, ... },
. . .
If instead of returning the status you only wanna see secure results, use the dnssec_return_only_secure extension. Its value (an int) is set to GETDNS_EXTENSION_TRUE to cause only records that the API can validate as secure with DNSSEC to be returned in the replies_tree and replies_full lists. No extra names get added to the record's dict β the change is just that some records might not appear in the results. When this context option is set, and the API receives DNS replies but none are determined to be secure, the error code at the top level of the response object is GETDNS_RESPSTATUS_NO_SECURE_ANSWERS.
Applications that wanna do their own validation are gonna want the DNSSEC-related records for a particular response. Use the dnssec_return_validation_chain extension. Its value (an int) is set to GETDNS_EXTENSION_TRUE to cause a set of additional DNSSEC-related records needed for validation to be returned in the response object. This set arrives as validation_chain (a list) at the top level of the response object. This list includes all resource record dicts for all the resource records (DS, DNSKEY and their RRSIGs) that are needed to perform the validation from the root up. So a reply might look like:
{ # This is the response object
"validation_chain":
[ { "name": <bindata for .>,
"type": GETDNS_RRTYPE_DNSKEY,
"rdata": { "flags": 256, . . . },
. . .
},
{ "name": <bindata for .>,
"type": GETDNS_RRTYPE_DNSKEY,
"rdata": { "flags": 257, . . . },
. . .
},
{ "name": <bindata for .>,
"type": GETDNS_RRTYPE_RRSIG,
"rdata": { "signers_name": <bindata for .>,
"type_covered": GETDNS_RRTYPE_DNSKEY,
. . .
},
},
{ "name": <bindata for com.>,
"type": GETDNS_RRTYPE_DS,
. . .
},
{ "name": <bindata for com.>,
"type": GETDNS_RRTYPE_RRSIG
"rdata": { "signers_name": <bindata for .>,
"type_covered": GETDNS_RRTYPE_DS,
. . .
},
. . .
},
{ "name": <bindata for com.>,
"type": GETDNS_RRTYPE_DNSKEY
"rdata": { "flags": 256, . . . },
. . .
},
{ "name": <bindata for com.>,
"type": GETDNS_RRTYPE_DNSKEY
"rdata": { "flags": 257, . . . },
. . .
},
{ "name": <bindata for com.>,
"type": GETDNS_RRTYPE_RRSIG
"rdata": { "signers_name": <bindata for com.>,
"type_covered": GETDNS_RRTYPE_DNSKEY,
. . .
},
. . .
},
{ "name": <bindata for example.com.>,
"type": GETDNS_RRTYPE_DS,
. . .
},
{ "name": <bindata for example.com.>,
"type": GETDNS_RRTYPE_RRSIG
"rdata": { "signers_name": <bindata for com.>,
"type_covered": GETDNS_RRTYPE_DS,
. . .
},
. . .
},
{ "name": <bindata for example.com.>,
"type": GETDNS_RRTYPE_DNSKEY
"rdata": { "flags": 257, ... },
. . .
},
. . .
]
"replies_tree":
[
. . .
Okay so important vibe check π¨ β if a request is using a context where stub resolution is set, and that same request also has any of thednssec_return_status,dnssec_return_only_secure, ordnssec_return_validation_chainextensions specified, the API will not perform the request and will instead return an error ofGETDNS_RETURN_DNSSEC_WITH_STUB_DISALLOWED. It's giving "pick a struggle."
β¨ OPT RESOURCE RECORDS β¨
For lookups that need an OPT resource record in the Additional Data section, use the add_opt_parameters extension. Its value (a dict) holds the parameters, and they're described in more detail in RFC 2671. Here's the lineup:
maximum_udp_payload_size(anint) between 512 and 65535; if you don't specify it, it defaults to those from the DNS contextextended_rcode(anint) between 0 and 255; if you don't specify it, it defaults to those from the DNS contextversion(anint) between 0 and 255; if you don't specify it, it defaults to 0do_bit(anint) between 0 and 1; if you don't specify it, it defaults to those from the DNS contextoptions(alist) contains dicts for each option to be specified. Each list item contains two names:option_code(anint) andoption_data(abindata). The API marshalls the entire set of options into a properly-formatted RDATA for the resource record.
π«Ά Very important to note: the OPT resource record specified in theadd_opt_parametersextension might not be the same one that the API sends in the query. Like, for example, if the application also includes any of the DNSSEC extensions, the API will make sure the OPT resource record sets the resource record appropriately, making the needed changes to the settings from theadd_opt_parametersextension.
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 that 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. Prioritize yourself first, periodt π
π RESPONSE DATA π
The callback function contains a pointer to a response object. A response object is always a dict. It always contains at least three names: replies_full (a list), replies_tree (a list), and status (an int). replies_full is a list of DNS replies (each is bindata) as they appear on the wire. replies_tree is a list of DNS replies (each is a dict) with the various parts of the reply parsed out. status is a status code for the query.
Because the API might be extended in the future, a response object might also contain names other than replies_full, replies_tree, and status. Same energy for any of the dicts described here β they might be extended in later versions of the API. So an application using the API must not assume it knows all possible names in a dict. Stay humble, stay flexible β¨
The following lists the status codes for response objects. And note: if the status is that there are no responses for the query, the lists in replies_full and replies_tree will have zero length.
GETDNS_RESPSTATUS_GOODβ At least one response was returnedGETDNS_RESPSTATUS_NO_NAMEβ Queries for the name yielded all negative responsesGETDNS_RESPSTATUS_ALL_TIMEOUTβ All queries for the name timed outGETDNS_RESPSTATUS_NO_SECURE_ANSWERSβ The context setting for getting only secure responses was specified, and at least one DNS response was received, but no DNS response was determined to be secure through DNSSEC.
The top level of replies_tree can optionally have the following names: canonical_name (a bindata), intermediate_aliases (a list), answer_ipv4_address (a bindata), answer_ipv6_address (a bindata), and answer_type (an int).
The value of canonical_name is the name that the API used for its lookup. It is in FQDN presentation format. The values in the intermediate_aliases list are domain names from any CNAME or unsynthesized DNAME found when resolving the original query. The list might have zero entries if there were no CNAMEs in the path. These may be useful, for example, for name comparisons when following the rules in RFC 6125. The value of answer_ipv4_address and answer_ipv6_address are the addresses of the server from which the answer was received. The value of answer_type is the type of name service that generated the response. The values are:
GETDNS_NAMETYPE_DNSβ Normal DNS (RFC 1035)GETDNS_NAMETYPE_WINSβ The WINS name service (some reference needed)
If the call was getdns_address or getdns_address_sync, the top level of replies_tree has an additional name, just_address_answers (a list). The value of just_address_answers is a list that contains all of the A and AAAA records from the answer sections of any of the replies, in the order they appear in the replies. Each item in the list is a dict with at least two names: address_type (whose value is a bindata; it is currently either "IPv4" or "IPv6") and address_data (whose value is a bindata). Note that the dnssec_return_only_secure extension affects what will appear in the just_address_answers list. If the DNS returns other address types, those types will appear in this list as well.
The API can make service discovery through SRV records easier. If the call was getdns_service or getdns_service_sync, the top level of replies_tree has an additional name, srv_addresses (a list). The list is ordered by priority and weight based on the weighting algorithm in RFC 2782, lowest priority value first. Each element of the list is a dict with at least two names: port and domain_name. If the API was able to determine the address of the target domain name (such as from its cache or from the Additional section of responses), the dict for an element will also contain address_type (whose value is a bindata; it is currently either "IPv4" or "IPv6") and address_data (whose value is a bindata). Note that the dnssec_return_only_secure extension affects what will appear in the srv_addresses list. π¦
π¦ STRUCTURE OF DNS REPLIES_TREE π¦
okay so bestie, picture each entry in the replies_tree list for DNS responses β it's got header (a dict), question (a dict), answer (a list), authority (a list), and additional (a list). These line up perfectly with the sections of the DNS message format, no notes. π
The answer, authority, and additional lists each contain zero or more dicts, and every single dict in those lists is one resource record. Periodt. π
the header dict πΈ
The names inside the header dict are all the fields from Section 4.1.1. of RFC 1035. They are: id, qr, opcode, aa, tc, rd, ra, z, rcode, qdcount, ancount, nscount, and arcount. All of them are ints. π§
the question dict π
The names in the question dict are the three fields from Section 4.1.2. of RFC 1035:
qnameβ abindataqtypeβ anintqclassβ anint
resource records β¨
Resource records are a little different from headers and question sections, because the RDATA portion often has its own whole structure. The other names in the resource record dicts are:
nameβ abindatatypeβ anintclassβ anintttlβ anintrdataβ adict
and note: there is no name equivalent to the RDLENGTH field. Just so you know. π
The rdata dict has different names for each response type. There's a complete list of the types defined in the API. For names that end in -obsolete or -unknown, the bindata is the entire RDATA field. For example:
- the
rdatafor anArecord hasipv4_address(abindata) - the
rdatafor anSRVrecord haspriority(anint),weight(anint),port(anint), andtarget(abindata)
Each rdata dict also has an rdata_raw field (a bindata). This is super 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. So basically: doing a query for types not known by the API still will return a result β an rdata with just an rdata_raw. π
Heads up: it is expected that later extensions to the API will give some DNS types different names. It's also possible that later extensions will change the names for some of the DNS types listed above. So don't get too attached, bestie. π
π CALLBACK FUNCTIONS π
A call to the async getdns functions typically returns before any network or file I/O even happens. After the API marshalls all the needed information, it calls the callback function that was passed by the application. And the callback function might be called at any time β even before the calling function has returned. π³
The API guarantees that the callback will be called exactly once unless the calling function returned an error, in which case the callback function is never called.
The getdns calling function calls the callback with the parameters defined as follows:
typedef void (*getdns_callback_t)(
getdns_context_t context,
uint16_t callback_type,
getdns_dict *response,
void *userarg,
getdns_transaction_t transaction_id)
contextβ seegetdns_context(3)callback_typeβ supplies the reason for the callback. And the vibes are:GETDNS_CALLBACK_COMPLETEβ the response has the requested data in it πGETDNS_CALLBACK_CANCELβ the calling program canceled the callback;responseisNULLGETDNS_CALLBACK_TIMEOUTβ the requested action timed out;responseisNULLGETDNS_CALLBACK_ERRORβ the requested action had an error;responseisNULL
responseβ a response object with the response data. This is described in the section titled "RESPONSE DATA" elsewhere in this manual page. The response object is part of the API's memory space, and will be freed by the API when the callback returns.userargβ identical to theuserargpassed to the calling function.transaction_idβ the transaction identified assigned by the calling function, used to associate a DNS response to a specific DNS request.
To cancel an outstanding callback, use the following function:
getdns_return_t
getdns_cancel_callback (getdns_context_t context,
getdns_transaction_t transaction_id)
This causes the API to call the callback with a callback_type of GETDNS_CALLBACK_CANCEL if the callback for this transaction_id has not already been called. The callback code for cancellation should clean up any memory related to the identified call, such as to deallocate the memory for the userarg.
getdns_cancel_callback() may return immediately, even before the callback finishes its work and returns. Calling getdns_cancel_callback() with a transaction_id of a callback that has already been called or an unknown transaction_id returns GETDNS_RETURN_UNKNOWN_TRANSACTION; otherwise, getdns_cancel_callback() returns GETDNS_RETURN_GOOD. π
π FILES π
(nothing listed here in the original, bestie π)
π EXAMPLES π
TBD
π©Ί DIAGNOSTICS π©Ί
TBD
π SEE ALSO π
getdns_address(3)getdns_bindata(3)getdns_context(3)getdns_convert(3)getdns_dict(3)getdns_general(3)getdns_hostname(3)getdns_list(3)getdns_root_trust_anchor(3)getdns_service(3)getdns_validate_dnssec(3)
π REPORTING PROBLEMS π
Bug reports should be sent to getdns-bugs@getdns.net β so if something's broken, tell them, not me. π
π AUTHORS π
The getdns API was documented by Paul Hoffman. This implementation of the getdns API was written by:
- Craig Despeaux, Verisign Inc.
- John Dickinson, Sinodun
- Sara Dickinson, Sinodun
- Neel Goyal, Verisign Inc.
- Shumon Huque, Verisign Labs
- Olaf Kolkman, NLnet Labs
- Allison Mankin, Verisign Inc. - Verisign Labs.
- Melinda Shore, No Mountain Software LLC
- Willem Toorop, NLnet Labs
- Gowri Visweswaran, Verisign Labs
- Wouter Wijngaards, NLnet Labs
- Glen Wiley, Verisign Inc.
and that's a wrap on libgetdns(3) π this page is from getdns 1.7.3, dated December 2015, and it lives in section 3. slay, go write some DNS code bestie π«Ά
π¦ where this page comes from
- alpine 3.24: getdns-doc 1.7.3-r0 Β· BSD-3-Clause
- arch rolling: getdns 1.7.3-2 Β· BSD
- epel 10: getdns-devel 1.7.3-9.el10_2 Β· BSD-3-Clause
- epel 9: getdns-devel 1.7.3-1.el9 Β· BSD-3-Clause
- fedora 43: getdns-devel 1.7.3-9.fc43 Β· BSD-3-Clause
- fedora 43: getdns-devel 1.7.3-9.fc43 Β· BSD-3-Clause
- fedora 44: getdns-devel 1.7.3-10.fc44 Β· BSD-3-Clause
- fedora 44: getdns-devel 1.7.3-10.fc44 Β· BSD-3-Clause
- nixpkgs unstable: getdns 1.7.3
- ubuntu resolute: libgetdns-dev 1.7.3-3 Β· BSD-3-Clause
- ubuntu stonking: libgetdns-dev 1.7.3-5build1 Β· BSD-3-Clause
- Copyright (c) 2013, NLnet Labs, Verisign, Inc
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms