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
53typedef 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
62ISC_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 */
118typedef 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 */
128typedef 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 */
142typedef 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 */
157typedef 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
163isc_result_t
164dns_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
211void
212dns_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
225isc_result_t
226dns_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
253isc_result_t
254dns_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
274isc_result_t
275dns_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
279isc_result_t
280dns_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
341void
342dns_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
357void
358dns_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
374void
375dns_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
386isc_result_t
387dns_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
411isc_result_t
412dns_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
418isc_result_t
419dns_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
482void
483dns_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
498void
499dns_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
515isc_result_t
516dns_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
521isc_result_t
522dns_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
603void
604dns_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
619void
620dns_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
636isc_result_t
637dns_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
646void
647dns_client_freeupdate(dns_name_t **namep);
648/*%<
649 * TBD
650 */
651
652isc_mem_t *
653dns_client_mctx(dns_client_t *client);
654
655ISC_LANG_ENDDECLS
656
657#endif /* DNS_CLIENT_H */
658