xref: /netbsd-src/external/mpl/dhcp/bind/dist/lib/dns/include/dns/client.h (revision 4afad4b7fa6d4a0d3dedf41d1587a7250710ae54)
1 /*	$NetBSD: client.h,v 1.1 2024/02/18 20:57:35 christos Exp $	*/
2 
3 /*
4  * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5  *
6  * SPDX-License-Identifier: MPL-2.0
7  *
8  * This Source Code Form is subject to the terms of the Mozilla Public
9  * License, v. 2.0. If a copy of the MPL was not distributed with this
10  * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11  *
12  * See the COPYRIGHT file distributed with this work for additional
13  * information regarding copyright ownership.
14  */
15 
16 #ifndef DNS_CLIENT_H
17 #define DNS_CLIENT_H 1
18 
19 /*****
20 ***** Module Info
21 *****/
22 
23 /*! \file
24  *
25  * \brief
26  * The DNS client module provides convenient programming interfaces to various
27  * DNS services, such as name resolution with or without DNSSEC validation or
28  * dynamic DNS update.  This module is primarily expected to be used by other
29  * applications than BIND9-related ones that need such advanced DNS features.
30  *
31  * MP:
32  *\li	In the typical usage of this module, application threads will not share
33  *	the same data structures created and manipulated in this module.
34  *	However, the module still ensures appropriate synchronization of such
35  *	data structures.
36  *
37  * Resources:
38  *\li	TBS
39  *
40  * Security:
41  *\li	This module does not handle any low-level data directly, and so no
42  *	security issue specific to this module is anticipated.
43  */
44 
45 #include <isc/event.h>
46 #include <isc/sockaddr.h>
47 
48 #include <dns/tsig.h>
49 #include <dns/types.h>
50 
51 #include <dst/dst.h>
52 
53 typedef enum {
54 	updateop_none = 0,
55 	updateop_add = 1,
56 	updateop_delete = 2,
57 	updateop_exist = 3,
58 	updateop_notexist = 4,
59 	updateop_max = 5
60 } dns_client_updateop_t;
61 
62 ISC_LANG_BEGINDECLS
63 
64 /***
65  *** Types
66  ***/
67 
68 /*%
69  * Optional flags for dns_client_create(x).
70  */
71 /*%< Enable caching resolution results (experimental). */
72 #define DNS_CLIENTCREATEOPT_USECACHE 0x8000
73 
74 /*%
75  * Optional flags for dns_client_(start)resolve.
76  */
77 /*%< Do not return DNSSEC data (e.g. RRSIGS) with response. */
78 #define DNS_CLIENTRESOPT_NODNSSEC 0x01
79 /*%< Allow running external context. */
80 #define DNS_CLIENTRESOPT_ALLOWRUN 0x02
81 /*%< Don't validate responses. */
82 #define DNS_CLIENTRESOPT_NOVALIDATE 0x04
83 /*%< Don't set the CD flag on upstream queries. */
84 #define DNS_CLIENTRESOPT_NOCDFLAG 0x08
85 /*%< Use TCP transport. */
86 #define DNS_CLIENTRESOPT_TCP 0x10
87 
88 /*%
89  * Optional flags for dns_client_(start)request.
90  */
91 /*%< Allow running external context. */
92 #define DNS_CLIENTREQOPT_ALLOWRUN 0x01
93 /*%< Use TCP transport. */
94 #define DNS_CLIENTREQOPT_TCP 0x02
95 
96 /*%
97  * Optional flags for dns_client_(start)update.
98  */
99 /*%< Allow running external context. */
100 #define DNS_CLIENTUPDOPT_ALLOWRUN 0x01
101 /*%< Use TCP transport. */
102 #define DNS_CLIENTUPDOPT_TCP 0x02
103 
104 /*%
105  * View name used in dns_client.
106  */
107 #define DNS_CLIENTVIEW_NAME "_dnsclient"
108 
109 /*%
110  * A dns_clientresevent_t is sent when name resolution performed by a client
111  * completes.  'result' stores the result code of the entire resolution
112  * procedure.  'vresult' specifically stores the result code of DNSSEC
113  * validation if it is performed.  When name resolution successfully completes,
114  * 'answerlist' is typically non empty, containing answer names along with
115  * RRsets.  It is the receiver's responsibility to free this list by calling
116  * dns_client_freeresanswer() before freeing the event structure.
117  */
118 typedef struct dns_clientresevent {
119 	ISC_EVENT_COMMON(struct dns_clientresevent);
120 	isc_result_t   result;
121 	isc_result_t   vresult;
122 	dns_namelist_t answerlist;
123 } dns_clientresevent_t; /* too long? */
124 
125 /*%
126  * Status of a dynamic update procedure.
127  */
128 typedef enum {
129 	dns_clientupdatestate_prepare, /*%< no updates have been sent */
130 	dns_clientupdatestate_sent,    /*%< updates were sent, no response */
131 	dns_clientupdatestate_done     /*%< update was sent and succeeded */
132 } dns_clientupdatestate_t;
133 
134 /*%
135  * A dns_clientreqevent_t is sent when a DNS request is completed by a client.
136  * 'result' stores the result code of the entire transaction.
137  * If the transaction is successfully completed but the response packet cannot
138  * be parsed, 'result' will store the result code of dns_message_parse().
139  * If the response packet is received, 'rmessage' will contain the response
140  * message, whether it is successfully parsed or not.
141  */
142 typedef struct dns_clientreqevent {
143 	ISC_EVENT_COMMON(struct dns_clientreqevent);
144 	isc_result_t   result;
145 	dns_message_t *rmessage;
146 } dns_clientreqevent_t; /* too long? */
147 
148 /*%
149  * A dns_clientupdateevent_t is sent when dynamic update performed by a client
150  * completes.  'result' stores the result code of the entire update procedure.
151  * 'state' specifies the status of the update procedure when this event is
152  * sent.  This can be used as a hint by the receiver to determine whether
153  * the update attempt was ever made.  In particular, if the state is
154  * dns_clientupdatestate_prepare, the receiver can be sure that the requested
155  * update was not applied.
156  */
157 typedef struct dns_clientupdateevent {
158 	ISC_EVENT_COMMON(struct dns_clientupdateevent);
159 	isc_result_t		result;
160 	dns_clientupdatestate_t state;
161 } dns_clientupdateevent_t; /* too long? */
162 
163 isc_result_t
164 dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
165 		  isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
166 		  unsigned int options, dns_client_t **clientp,
167 		  const isc_sockaddr_t *localaddr4,
168 		  const isc_sockaddr_t *localaddr6);
169 /*%<
170  * Create a DNS client.  These functions create a new client object with
171  * minimal internal resources such as the default 'view' for the IN class and
172  * IPv4/IPv6 dispatches for the view.
173  *
174  * dns_client_createx() takes 'manager' arguments so that the caller can
175  * control the behavior of the client through the underlying event framework.
176  * On the other hand, dns_client_create() simplifies the interface and creates
177  * the managers internally.  A DNS client object created via
178  * dns_client_create() is expected to be used by an application that only needs
179  * simple synchronous services or by a thread-based application.
180  *
181  * dns_client_createx2 takes two additional parameters, 'localaddr4' and
182  * 'localaddr6', to specify the local address to use for each family. If
183  * both are set to NULL, then wildcard addresses will be used for both
184  * families. If only one is NULL, then the other address will be used
185  * as the local address, and the other protocol family will not be used.
186  *
187  * If the DNS_CLIENTCREATEOPT_USECACHE flag is set in 'options',
188  * dns_client_create(x) will create a cache database with the view.
189  *
190  * Requires:
191  *
192  *\li	'mctx' is a valid memory context.
193  *
194  *\li	'actx' is a valid application context.
195  *
196  *\li	'taskmgr' is a valid task manager.
197  *
198  *\li	'socketmgr' is a valid socket manager.
199  *
200  *\li	'timermgr' is a valid timer manager.
201  *
202  *\li	clientp != NULL && *clientp == NULL.
203  *
204  * Returns:
205  *
206  *\li	#ISC_R_SUCCESS				On success.
207  *
208  *\li	Anything else				Failure.
209  */
210 
211 void
212 dns_client_destroy(dns_client_t **clientp);
213 /*%<
214  * Destroy 'client'.
215  *
216  * Requires:
217  *
218  *\li	'*clientp' is a valid client.
219  *
220  * Ensures:
221  *
222  *\li	*clientp == NULL.
223  */
224 
225 isc_result_t
226 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
227 		      const dns_name_t *name_space, isc_sockaddrlist_t *addrs);
228 /*%<
229  * Specify a list of addresses of recursive name servers that the client will
230  * use for name resolution.  A view for the 'rdclass' class must be created
231  * beforehand.  If 'name_space' is non NULL, the specified server will be used
232  * if and only if the query name is a subdomain of 'name_space'.  When servers
233  * for multiple 'name_space's are provided, and a query name is covered by
234  * more than one 'name_space', the servers for the best (longest) matching
235  * name_space will be used.  If 'name_space' is NULL, it works as if
236  * dns_rootname (.) were specified.
237  *
238  * Requires:
239  *
240  *\li	'client' is a valid client.
241  *
242  *\li	'name_space' is NULL or a valid name.
243  *
244  *\li	'addrs' != NULL.
245  *
246  * Returns:
247  *
248  *\li	#ISC_R_SUCCESS				On success.
249  *
250  *\li	Anything else				Failure.
251  */
252 
253 isc_result_t
254 dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
255 			const dns_name_t *name_space);
256 /*%<
257  * Remove configured recursive name servers for the 'rdclass' and 'name_space'
258  * from the client.  See the description of dns_client_setservers() for
259  * the requirements about 'rdclass' and 'name_space'.
260  *
261  * Requires:
262  *
263  *\li	'client' is a valid client.
264  *
265  *\li	'name_space' is NULL or a valid name.
266  *
267  * Returns:
268  *
269  *\li	#ISC_R_SUCCESS				On success.
270  *
271  *\li	Anything else				Failure.
272  */
273 
274 isc_result_t
275 dns_client_resolve(dns_client_t *client, const dns_name_t *name,
276 		   dns_rdataclass_t rdclass, dns_rdatatype_t type,
277 		   unsigned int options, dns_namelist_t *namelist);
278 
279 isc_result_t
280 dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
281 			dns_rdataclass_t rdclass, dns_rdatatype_t type,
282 			unsigned int options, isc_task_t *task,
283 			isc_taskaction_t action, void *arg,
284 			dns_clientrestrans_t **transp);
285 /*%<
286  * Perform name resolution for 'name', 'rdclass', and 'type'.
287  *
288  * If any trusted keys are configured and the query name is considered to
289  * belong to a secure zone, these functions also validate the responses
290  * using DNSSEC by default.  If the DNS_CLIENTRESOPT_NOVALIDATE flag is set
291  * in 'options', DNSSEC validation is disabled regardless of the configured
292  * trusted keys or the query name. With DNS_CLIENTRESOPT_NODNSSEC
293  * DNSSEC data is not returned with response. DNS_CLIENTRESOPT_NOCDFLAG
294  * disables the CD flag on queries, DNS_CLIENTRESOPT_TCP switches to
295  * the TCP (vs. UDP) transport.
296  *
297  * dns_client_resolve() provides a synchronous service.  This function starts
298  * name resolution internally and blocks until it completes.  On success,
299  * 'namelist' will contain a list of answer names, each of which has
300  * corresponding RRsets.  The caller must provide a valid empty list, and
301  * is responsible for freeing the list content via dns_client_freeresanswer().
302  * If the name resolution fails due to an error in DNSSEC validation,
303  * dns_client_resolve() returns the result code indicating the validation
304  * error. Otherwise, it returns the result code of the entire resolution
305  * process, either success or failure.
306  *
307  * It is typically expected that the client object passed to
308  * dns_client_resolve() was created via dns_client_create() and has its own
309  * managers and contexts.  However, if the DNS_CLIENTRESOPT_ALLOWRUN flag is
310  * set in 'options', this function performs the synchronous service even if
311  * it does not have its own manager and context structures.
312  *
313  * dns_client_startresolve() is an asynchronous version of dns_client_resolve()
314  * and does not block.  When name resolution is completed, 'action' will be
315  * called with the argument of a 'dns_clientresevent_t' object, which contains
316  * the resulting list of answer names (on success).  On return, '*transp' is
317  * set to an opaque transaction ID so that the caller can cancel this
318  * resolution process.
319  *
320  * Requires:
321  *
322  *\li	'client' is a valid client.
323  *
324  *\li	'addrs' != NULL.
325  *
326  *\li	'name' is a valid name.
327  *
328  *\li	'namelist' != NULL and is not empty.
329  *
330  *\li	'task' is a valid task.
331  *
332  *\li	'transp' != NULL && *transp == NULL;
333  *
334  * Returns:
335  *
336  *\li	#ISC_R_SUCCESS				On success.
337  *
338  *\li	Anything else				Failure.
339  */
340 
341 void
342 dns_client_cancelresolve(dns_clientrestrans_t *trans);
343 /*%<
344  * Cancel an ongoing resolution procedure started via
345  * dns_client_startresolve().
346  *
347  * Notes:
348  *
349  *\li	If the resolution procedure has not completed, post its CLIENTRESDONE
350  *	event with a result code of #ISC_R_CANCELED.
351  *
352  * Requires:
353  *
354  *\li	'trans' is a valid transaction ID.
355  */
356 
357 void
358 dns_client_destroyrestrans(dns_clientrestrans_t **transp);
359 /*%<
360  * Destroy name resolution transaction state identified by '*transp'.
361  *
362  * Requires:
363  *
364  *\li	'*transp' is a valid transaction ID.
365  *
366  *\li	The caller has received the CLIENTRESDONE event (either because the
367  *	resolution completed or because dns_client_cancelresolve() was called).
368  *
369  * Ensures:
370  *
371  *\li	*transp == NULL.
372  */
373 
374 void
375 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist);
376 /*%<
377  * Free resources allocated for the content of 'namelist'.
378  *
379  * Requires:
380  *
381  *\li	'client' is a valid client.
382  *
383  *\li	'namelist' != NULL.
384  */
385 
386 isc_result_t
387 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
388 			 dns_rdatatype_t rdtype, const dns_name_t *keyname,
389 			 isc_buffer_t *keydatabuf);
390 /*%<
391  * Add a DNSSEC trusted key for the 'rdclass' class.  A view for the 'rdclass'
392  * class must be created beforehand.  'rdtype' is the type of the RR data
393  * for the key, either DNSKEY or DS.  'keyname' is the DNS name of the key,
394  * and 'keydatabuf' stores the RR data.
395  *
396  * Requires:
397  *
398  *\li	'client' is a valid client.
399  *
400  *\li	'keyname' is a valid name.
401  *
402  *\li	'keydatabuf' is a valid buffer.
403  *
404  * Returns:
405  *
406  *\li	#ISC_R_SUCCESS				On success.
407  *
408  *\li	Anything else				Failure.
409  */
410 
411 isc_result_t
412 dns_client_request(dns_client_t *client, dns_message_t *qmessage,
413 		   dns_message_t *rmessage, const isc_sockaddr_t *server,
414 		   unsigned int options, unsigned int parseoptions,
415 		   dns_tsec_t *tsec, unsigned int timeout,
416 		   unsigned int udptimeout, unsigned int udpretries);
417 
418 isc_result_t
419 dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
420 			dns_message_t *rmessage, const isc_sockaddr_t *server,
421 			unsigned int options, unsigned int parseoptions,
422 			dns_tsec_t *tsec, unsigned int timeout,
423 			unsigned int udptimeout, unsigned int udpretries,
424 			isc_task_t *task, isc_taskaction_t action, void *arg,
425 			dns_clientreqtrans_t **transp);
426 
427 /*%<
428  * Send a DNS request containing a query message 'query' to 'server'.
429  *
430  * 'parseoptions' will be used when the response packet is parsed, and will be
431  * passed to dns_message_parse() via dns_request_getresponse().  See
432  * dns_message_parse() for more details.
433  *
434  * 'tsec' is a transaction security object containing, e.g. a TSIG key for
435  * authenticating the request/response transaction.  This is optional and can
436  * be NULL, in which case this library performs the transaction  without any
437  * transaction authentication.
438  *
439  * 'timeout', 'udptimeout', and 'udpretries' are passed to
440  * dns_request_createvia3().  See dns_request_createvia3() for more details.
441  *
442  * dns_client_request() provides a synchronous service.  This function sends
443  * the request and blocks until a response is received.  On success,
444  * 'rmessage' will contain the response message.  The caller must provide a
445  * valid initialized message.
446  *
447  * It is usually expected that the client object passed to
448  * dns_client_request() was created via dns_client_create() and has its own
449  * managers and contexts.  However, if the DNS_CLIENTREQOPT_ALLOWRUN flag is
450  * set in 'options', this function performs the synchronous service even if
451  * it does not have its own manager and context structures.
452  *
453  * dns_client_startrequest() is an asynchronous version of dns_client_request()
454  * and does not block.  When the transaction is completed, 'action' will be
455  * called with the argument of a 'dns_clientreqevent_t' object, which contains
456  * the response message (on success).  On return, '*transp' is set to an opaque
457  * transaction ID so that the caller can cancel this request.
458  *
459  * DNS_CLIENTREQOPT_TCP switches to the TCP (vs. UDP) transport.
460  *
461  * Requires:
462  *
463  *\li	'client' is a valid client.
464  *
465  *\li	'qmessage' and 'rmessage' are valid initialized message.
466  *
467  *\li	'server' is a valid socket address structure.
468  *
469  *\li	'task' is a valid task.
470  *
471  *\li	'transp' != NULL && *transp == NULL;
472  *
473  * Returns:
474  *
475  *\li	#ISC_R_SUCCESS				On success.
476  *
477  *\li	Anything else				Failure.
478  *
479  *\li	Any result that dns_message_parse() can return.
480  */
481 
482 void
483 dns_client_cancelrequest(dns_clientreqtrans_t *transp);
484 /*%<
485  * Cancel an ongoing DNS request procedure started via
486  * dns_client_startrequest().
487  *
488  * Notes:
489  *
490  *\li	If the request procedure has not completed, post its CLIENTREQDONE
491  *	event with a result code of #ISC_R_CANCELED.
492  *
493  * Requires:
494  *
495  *\li	'trans' is a valid transaction ID.
496  */
497 
498 void
499 dns_client_destroyreqtrans(dns_clientreqtrans_t **transp);
500 /*%
501  * Destroy DNS request transaction state identified by '*transp'.
502  *
503  * Requires:
504  *
505  *\li	'*transp' is a valid transaction ID.
506  *
507  *\li	The caller has received the CLIENTREQDONE event (either because the
508  *	request completed or because dns_client_cancelrequest() was called).
509  *
510  * Ensures:
511  *
512  *\li	*transp == NULL.
513  */
514 
515 isc_result_t
516 dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
517 		  const dns_name_t *zonename, dns_namelist_t *prerequisites,
518 		  dns_namelist_t *updates, isc_sockaddrlist_t *servers,
519 		  dns_tsec_t *tsec, unsigned int options);
520 
521 isc_result_t
522 dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
523 		       const dns_name_t *zonename,
524 		       dns_namelist_t *prerequisites, dns_namelist_t *updates,
525 		       isc_sockaddrlist_t *servers, dns_tsec_t *tsec,
526 		       unsigned int options, isc_task_t *task,
527 		       isc_taskaction_t action, void *arg,
528 		       dns_clientupdatetrans_t **transp);
529 /*%<
530  * Perform DNS dynamic update for 'updates' of the 'rdclass' class with
531  * optional 'prerequisites'.
532  *
533  * 'updates' are a list of names with associated RRsets to be updated.
534  *
535  * 'prerequisites' are a list of names with associated RRsets corresponding to
536  * the prerequisites of the updates.  This is optional and can be NULL, in
537  * which case the prerequisite section of the update message will be empty.
538  *
539  * Both 'updates' and 'prerequisites' must be constructed as specified in
540  * RFC2136.
541  *
542  * 'zonename' is the name of the zone in which the updated names exist.
543  * This is optional and can be NULL.  In this case, these functions internally
544  * identify the appropriate zone through some queries for the SOA RR starting
545  * with the first name in prerequisites or updates.
546  *
547  * 'servers' is a list of authoritative servers to which the update message
548  * should be sent.  This is optional and can be NULL.  In this case, these
549  * functions internally identify the appropriate primary server name and its
550  * addresses through some queries for the SOA RR (like the case of zonename)
551  * and supplemental A/AAAA queries for the server name.
552  * Note: The client module generally assumes the given addresses are of the
553  * primary server of the corresponding zone.  It will work even if a secondary
554  * server address is specified as long as the server allows update forwarding,
555  * it is generally discouraged to include secondary server addresses unless
556  * there's strong reason to do so.
557  *
558  * 'tsec' is a transaction security object containing, e.g. a TSIG key for
559  * authenticating the update transaction (and the supplemental query/response
560  * transactions if the server is specified).  This is optional and can be
561  * NULL, in which case the library tries the update without any transaction
562  * authentication.
563  *
564  * It is typically expected that the client object passed to
565  * dns_client_update() was created via dns_client_create() and has its own
566  * managers and contexts.  However, if the DNS_CLIENTUPDOPT_ALLOWRUN flag is
567  * set in 'options', this function performs the synchronous service even if
568  * it does not have its own manager and context structures.
569  *
570  * dns_client_update() provides a synchronous service.  This function blocks
571  * until the entire update procedure completes, including the additional
572  * queries when necessary.
573  *
574  * dns_client_startupdate() is an asynchronous version of dns_client_update().
575  * It immediately returns (typically with *transp being set to a non-NULL
576  * pointer), and performs the update procedure through a set of internal
577  * events.  All transactions including the additional query exchanges are
578  * performed as a separate event, so none of these events cause blocking
579  * operation.  When the update procedure completes, the specified function
580  * 'action' will be called with the argument of a 'dns_clientupdateevent_t'
581  * structure.  On return, '*transp' is set to an opaque transaction ID so that
582  * the caller can cancel this update process.
583  *
584  * DNS_CLIENTUPDOPT_TCP switches to the TCP (vs. UDP) transport.
585  *
586  * Requires:
587  *
588  *\li	'client' is a valid client.
589  *
590  *\li	'updates' != NULL.
591  *
592  *\li	'task' is a valid task.
593  *
594  *\li	'transp' != NULL && *transp == NULL;
595  *
596  * Returns:
597  *
598  *\li	#ISC_R_SUCCESS				On success.
599  *
600  *\li	Anything else				Failure.
601  */
602 
603 void
604 dns_client_cancelupdate(dns_clientupdatetrans_t *trans);
605 /*%<
606  * Cancel an ongoing dynamic update procedure started via
607  * dns_client_startupdate().
608  *
609  * Notes:
610  *
611  *\li	If the update procedure has not completed, post its UPDATEDONE
612  *	event with a result code of #ISC_R_CANCELED.
613  *
614  * Requires:
615  *
616  *\li	'trans' is a valid transaction ID.
617  */
618 
619 void
620 dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp);
621 /*%<
622  * Destroy dynamic update transaction identified by '*transp'.
623  *
624  * Requires:
625  *
626  *\li	'*transp' is a valid transaction ID.
627  *
628  *\li	The caller has received the UPDATEDONE event (either because the
629  *	update completed or because dns_client_cancelupdate() was called).
630  *
631  * Ensures:
632  *
633  *\li	*transp == NULL.
634  */
635 
636 isc_result_t
637 dns_client_updaterec(dns_client_updateop_t op, const dns_name_t *owner,
638 		     dns_rdatatype_t type, dns_rdata_t *source, dns_ttl_t ttl,
639 		     dns_name_t *target, dns_rdataset_t *rdataset,
640 		     dns_rdatalist_t *rdatalist, dns_rdata_t *rdata,
641 		     isc_mem_t *mctx);
642 /*%<
643  * TBD
644  */
645 
646 void
647 dns_client_freeupdate(dns_name_t **namep);
648 /*%<
649  * TBD
650  */
651 
652 isc_mem_t *
653 dns_client_mctx(dns_client_t *client);
654 
655 ISC_LANG_ENDDECLS
656 
657 #endif /* DNS_CLIENT_H */
658