* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
* The DNS client module provides convenient programming interfaces to various
* DNS services, such as name resolution with or without DNSSEC validation or
* dynamic DNS update. This module is primarily expected to be used by other
* applications than BIND9-related ones that need such advanced DNS features.
*\li In the typical usage of this module, application threads will not share
* the same data structures created and manipulated in this module.
* However, the module still ensures appropriate synchronization of such
*\li This module does not handle any low-level data directly, and so no
* security issue specific to this module is anticipated.
#include <isc/sockaddr.h>
* Optional flags for dns_client_create(x).
/*%< Enable caching resolution results (experimental). */
#define DNS_CLIENTCREATEOPT_USECACHE 0x8000
* Optional flags for dns_client_(start)resolve.
/*%< Do not return DNSSEC data (e.g. RRSIGS) with response. */
#define DNS_CLIENTRESOPT_NODNSSEC 0x01
/*%< Allow running external context. */
#define DNS_CLIENTRESOPT_ALLOWRUN 0x02
/*%< Don't validate responses. */
#define DNS_CLIENTRESOPT_NOVALIDATE 0x04
/*%< Don't set the CD flag on upstream queries. */
#define DNS_CLIENTRESOPT_NOCDFLAG 0x08
/*%< Use TCP transport. */
#define DNS_CLIENTRESOPT_TCP 0x10
* Optional flags for dns_client_(start)request.
/*%< Allow running external context. */
#define DNS_CLIENTREQOPT_ALLOWRUN 0x01
/*%< Use TCP transport. */
#define DNS_CLIENTREQOPT_TCP 0x02
* Optional flags for dns_client_(start)update.
/*%< Allow running external context. */
#define DNS_CLIENTUPDOPT_ALLOWRUN 0x01
/*%< Use TCP transport. */
#define DNS_CLIENTUPDOPT_TCP 0x02
* A dns_clientresevent_t is sent when name resolution performed by a client
* completes. 'result' stores the result code of the entire resolution
* procedure. 'vresult' specifically stores the result code of DNSSEC
* validation if it is performed. When name resolution successfully completes,
* 'answerlist' is typically non empty, containing answer names along with
* RRsets. It is the receiver's responsibility to free this list by calling
* dns_client_freeresanswer() before freeing the event structure.
typedef struct dns_clientresevent {
ISC_EVENT_COMMON(struct dns_clientresevent);
dns_namelist_t answerlist;
} dns_clientresevent_t; /* too long? */
* Status of a dynamic update procedure.
dns_clientupdatestate_prepare, /*%< no updates have been sent */
dns_clientupdatestate_sent, /*%< updates were sent, no response */
dns_clientupdatestate_done /*%< update was sent and succeeded */
} dns_clientupdatestate_t;
* A dns_clientreqevent_t is sent when a DNS request is completed by a client.
* 'result' stores the result code of the entire transaction.
* If the transaction is successfully completed but the response packet cannot
* be parsed, 'result' will store the result code of dns_message_parse().
* If the response packet is received, 'rmessage' will contain the response
* message, whether it is successfully parsed or not.
typedef struct dns_clientreqevent {
ISC_EVENT_COMMON(struct dns_clientreqevent);
} dns_clientreqevent_t; /* too long? */
* A dns_clientupdateevent_t is sent when dynamic update performed by a client
* completes. 'result' stores the result code of the entire update procedure.
* 'state' specifies the status of the update procedure when this event is
* sent. This can be used as a hint by the receiver to determine whether
* the update attempt was ever made. In particular, if the state is
* dns_clientupdatestate_prepare, the receiver can be sure that the requested
* update was not applied.
typedef struct dns_clientupdateevent {
ISC_EVENT_COMMON(struct dns_clientupdateevent);
dns_clientupdatestate_t state;
} dns_clientupdateevent_t; /* too long? */
dns_client_create(dns_client_t **clientp, unsigned int options);
dns_client_createx(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
unsigned int options, dns_client_t **clientp);
dns_client_createx2(isc_mem_t *mctx, isc_appctx_t *actx,
isc_taskmgr_t *taskmgr, isc_socketmgr_t *socketmgr,
isc_timermgr_t *timermgr, unsigned int options,
isc_sockaddr_t *localaddr4, isc_sockaddr_t *localaddr6);
* Create a DNS client. These functions create a new client object with
* minimal internal resources such as the default 'view' for the IN class and
* IPv4/IPv6 dispatches for the view.
* dns_client_createx() takes 'manager' arguments so that the caller can
* control the behavior of the client through the underlying event framework.
* On the other hand, dns_client_create() simplifies the interface and creates
* the managers internally. A DNS client object created via
* dns_client_create() is expected to be used by an application that only needs
* simple synchronous services or by a thread-based application.
* dns_client_createx2 takes two additional parameters, 'localaddr4' and
* 'localaddr6', to specify the local address to use for each family. If
* both are set to NULL, then wildcard addresses will be used for both
* families. If only one is NULL, then the other address will be used
* as the local address, and the other protocol family will not be used.
* If the DNS_CLIENTCREATEOPT_USECACHE flag is set in 'options',
* dns_client_create(x) will create a cache database with the view.
*\li 'mctx' is a valid memory context.
*\li 'actx' is a valid application context.
*\li 'taskmgr' is a valid task manager.
*\li 'socketmgr' is a valid socket manager.
*\li 'timermgr' is a valid timer manager.
*\li clientp != NULL && *clientp == NULL.
*\li #ISC_R_SUCCESS On success.
*\li Anything else Failure.
dns_client_destroy(dns_client_t **clientp);
*\li '*clientp' is a valid client.
dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
dns_name_t *name_space, isc_sockaddrlist_t *addrs);
* Specify a list of addresses of recursive name servers that the client will
* use for name resolution. A view for the 'rdclass' class must be created
* beforehand. If 'name_space' is non NULL, the specified server will be used
* if and only if the query name is a subdomain of 'name_space'. When servers
* for multiple 'name_space's are provided, and a query name is covered by
* more than one 'name_space', the servers for the best (longest) matching
* name_space will be used. If 'name_space' is NULL, it works as if
* dns_rootname (.) were specified.
*\li 'client' is a valid client.
*\li 'name_space' is NULL or a valid name.
*\li #ISC_R_SUCCESS On success.
*\li Anything else Failure.
dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
* Remove configured recursive name servers for the 'rdclass' and 'name_space'
* from the client. See the description of dns_client_setservers() for
* the requirements about 'rdclass' and 'name_space'.
*\li 'client' is a valid client.
*\li 'name_space' is NULL or a valid name.
*\li #ISC_R_SUCCESS On success.
*\li Anything else Failure.
dns_client_setdlv(dns_client_t *client, dns_rdataclass_t rdclass,
* Specify a name to use for DNSSEC lookaside validation.
* If a trusted key has been added for that name, then DLV will be
* used during validation. If 'dlvname' is NULL, then DLV will no
* longer be used for this client.
*\li 'client' is a valid client.
*\li #ISC_R_SUCCESS On success.
*\li Anything else Failure.
dns_client_resolve(dns_client_t *client, dns_name_t *name,
dns_rdataclass_t rdclass, dns_rdatatype_t type,
unsigned int options, dns_namelist_t *namelist);
dns_client_startresolve(dns_client_t *client, dns_name_t *name,
dns_rdataclass_t rdclass, dns_rdatatype_t type,
unsigned int options, isc_task_t *task,
isc_taskaction_t action, void *arg,
dns_clientrestrans_t **transp);
* Perform name resolution for 'name', 'rdclass', and 'type'.
* If any trusted keys are configured and the query name is considered to
* belong to a secure zone, these functions also validate the responses
* using DNSSEC by default. If the DNS_CLIENTRESOPT_NOVALIDATE flag is set
* in 'options', DNSSEC validation is disabled regardless of the configured
* trusted keys or the query name. With DNS_CLIENTRESOPT_NODNSSEC
* DNSSEC data is not returned with response. DNS_CLIENTRESOPT_NOCDFLAG
* disables the CD flag on queries, DNS_CLIENTRESOPT_TCP switches to
* the TCP (vs. UDP) transport.
* dns_client_resolve() provides a synchronous service. This function starts
* name resolution internally and blocks until it completes. On success,
* 'namelist' will contain a list of answer names, each of which has
* corresponding RRsets. The caller must provide a valid empty list, and
* is responsible for freeing the list content via dns_client_freeresanswer().
* If the name resolution fails due to an error in DNSSEC validation,
* dns_client_resolve() returns the result code indicating the validation
* error. Otherwise, it returns the result code of the entire resolution
* process, either success or failure.
* It is typically expected that the client object passed to
* dns_client_resolve() was created via dns_client_create() and has its own
* managers and contexts. However, if the DNS_CLIENTRESOPT_ALLOWRUN flag is
* set in 'options', this function performs the synchronous service even if
* it does not have its own manager and context structures.
* dns_client_startresolve() is an asynchronous version of dns_client_resolve()
* and does not block. When name resolution is completed, 'action' will be
* called with the argument of a 'dns_clientresevent_t' object, which contains
* the resulting list of answer names (on success). On return, '*transp' is
* set to an opaque transaction ID so that the caller can cancel this
*\li 'client' is a valid client.
*\li 'name' is a valid name.
*\li 'namelist' != NULL and is not empty.
*\li 'task' is a valid task.
*\li 'transp' != NULL && *transp == NULL;
*\li #ISC_R_SUCCESS On success.
*\li Anything else Failure.
dns_client_cancelresolve(dns_clientrestrans_t *trans);
* Cancel an ongoing resolution procedure started via
* dns_client_startresolve().
*\li If the resolution procedure has not completed, post its CLIENTRESDONE
* event with a result code of #ISC_R_CANCELED.
*\li 'trans' is a valid transaction ID.
dns_client_destroyrestrans(dns_clientrestrans_t **transp);
* Destroy name resolution transaction state identified by '*transp'.
*\li '*transp' is a valid transaction ID.
*\li The caller has received the CLIENTRESDONE event (either because the
* resolution completed or because dns_client_cancelresolve() was called).
dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist);
* Free resources allocated for the content of 'namelist'.
*\li 'client' is a valid client.
dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
dns_name_t *keyname, isc_buffer_t *keydatabuf);
* Add a DNSSEC trusted key for the 'rdclass' class. A view for the 'rdclass'
* class must be created beforehand. 'keyname' is the DNS name of the key,
* and 'keydatabuf' stores the resource data of the key.
*\li 'client' is a valid client.
*\li 'keyname' is a valid name.
*\li 'keydatabuf' is a valid buffer.
*\li #ISC_R_SUCCESS On success.
*\li Anything else Failure.
dns_client_request(dns_client_t *client, dns_message_t *qmessage,
dns_message_t *rmessage, isc_sockaddr_t *server,
unsigned int options, unsigned int parseoptions,
dns_tsec_t *tsec, unsigned int timeout,
unsigned int udptimeout, unsigned int udpretries);
dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
dns_message_t *rmessage, isc_sockaddr_t *server,
unsigned int options, unsigned int parseoptions,
dns_tsec_t *tsec, unsigned int timeout,
unsigned int udptimeout, unsigned int udpretries,
isc_task_t *task, isc_taskaction_t action, void *arg,
dns_clientreqtrans_t **transp);
* Send a DNS request containing a query message 'query' to 'server'.
* 'parseoptions' will be used when the response packet is parsed, and will be
* passed to dns_message_parse() via dns_request_getresponse(). See
* dns_message_parse() for more details.
* 'tsec' is a transaction security object containing, e.g. a TSIG key for
* authenticating the request/response transaction. This is optional and can
* be NULL, in which case this library performs the transaction without any
* transaction authentication.
* 'timeout', 'udptimeout', and 'udpretries' are passed to
* dns_request_createvia3(). See dns_request_createvia3() for more details.
* dns_client_request() provides a synchronous service. This function sends
* the request and blocks until a response is received. On success,
* 'rmessage' will contain the response message. The caller must provide a
* valid initialized message.
* It is usually expected that the client object passed to
* dns_client_request() was created via dns_client_create() and has its own
* managers and contexts. However, if the DNS_CLIENTREQOPT_ALLOWRUN flag is
* set in 'options', this function performs the synchronous service even if
* it does not have its own manager and context structures.
* dns_client_startrequest() is an asynchronous version of dns_client_request()
* and does not block. When the transaction is completed, 'action' will be
* called with the argument of a 'dns_clientreqevent_t' object, which contains
* the response message (on success). On return, '*transp' is set to an opaque
* transaction ID so that the caller can cancel this request.
* DNS_CLIENTREQOPT_TCP switches to the TCP (vs. UDP) transport.
*\li 'client' is a valid client.
*\li 'qmessage' and 'rmessage' are valid initialized message.
*\li 'server' is a valid socket address structure.
*\li 'task' is a valid task.
*\li 'transp' != NULL && *transp == NULL;
*\li #ISC_R_SUCCESS On success.
*\li Anything else Failure.
*\li Any result that dns_message_parse() can return.