1 /* $NetBSD: client.c,v 1.1 2024/02/18 20:57:30 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 #include <stdbool.h>
17 #include <stddef.h>
18
19 #include <isc/app.h>
20 #include <isc/buffer.h>
21 #include <isc/md.h>
22 #include <isc/mem.h>
23 #include <isc/mutex.h>
24 #include <isc/portset.h>
25 #include <isc/refcount.h>
26 #include <isc/safe.h>
27 #include <isc/sockaddr.h>
28 #include <isc/socket.h>
29 #include <isc/task.h>
30 #include <isc/timer.h>
31 #include <isc/util.h>
32
33 #include <dns/adb.h>
34 #include <dns/client.h>
35 #include <dns/db.h>
36 #include <dns/dispatch.h>
37 #include <dns/events.h>
38 #include <dns/forward.h>
39 #include <dns/keytable.h>
40 #include <dns/message.h>
41 #include <dns/name.h>
42 #include <dns/rdata.h>
43 #include <dns/rdatalist.h>
44 #include <dns/rdataset.h>
45 #include <dns/rdatasetiter.h>
46 #include <dns/rdatastruct.h>
47 #include <dns/rdatatype.h>
48 #include <dns/request.h>
49 #include <dns/resolver.h>
50 #include <dns/result.h>
51 #include <dns/tsec.h>
52 #include <dns/tsig.h>
53 #include <dns/view.h>
54
55 #include <dst/dst.h>
56
57 #define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
58 #define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
59
60 #define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
61 #define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
62
63 #define REQCTX_MAGIC ISC_MAGIC('R', 'q', 'c', 'x')
64 #define REQCTX_VALID(c) ISC_MAGIC_VALID(c, REQCTX_MAGIC)
65
66 #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
67 #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
68
69 #define MAX_RESTARTS 16
70
71 #ifdef TUNE_LARGE
72 #define RESOLVER_NTASKS 523
73 #else /* ifdef TUNE_LARGE */
74 #define RESOLVER_NTASKS 31
75 #endif /* TUNE_LARGE */
76
77 #define CHECK(r) \
78 do { \
79 result = (r); \
80 if (result != ISC_R_SUCCESS) \
81 goto cleanup; \
82 } while (0)
83
84 /*%
85 * DNS client object
86 */
87 struct dns_client {
88 /* Unlocked */
89 unsigned int magic;
90 unsigned int attributes;
91 isc_mutex_t lock;
92 isc_mem_t *mctx;
93 isc_appctx_t *actx;
94 isc_taskmgr_t *taskmgr;
95 isc_task_t *task;
96 isc_socketmgr_t *socketmgr;
97 isc_timermgr_t *timermgr;
98 dns_dispatchmgr_t *dispatchmgr;
99 dns_dispatch_t *dispatchv4;
100 dns_dispatch_t *dispatchv6;
101
102 unsigned int update_timeout;
103 unsigned int update_udptimeout;
104 unsigned int update_udpretries;
105 unsigned int find_timeout;
106 unsigned int find_udpretries;
107
108 isc_refcount_t references;
109
110 /* Locked */
111 dns_viewlist_t viewlist;
112 ISC_LIST(struct resctx) resctxs;
113 ISC_LIST(struct reqctx) reqctxs;
114 ISC_LIST(struct updatectx) updatectxs;
115 };
116
117 /*%
118 * Timeout/retry constants for dynamic update borrowed from nsupdate
119 */
120 #define DEF_UPDATE_TIMEOUT 300
121 #define MIN_UPDATE_TIMEOUT 30
122 #define DEF_UPDATE_UDPTIMEOUT 3
123 #define DEF_UPDATE_UDPRETRIES 3
124
125 #define DEF_FIND_TIMEOUT 5
126 #define DEF_FIND_UDPRETRIES 3
127
128 #define DNS_CLIENTATTR_OWNCTX 0x01
129
130 /*%
131 * Internal state for a single name resolution procedure
132 */
133 typedef struct resctx {
134 /* Unlocked */
135 unsigned int magic;
136 isc_mutex_t lock;
137 dns_client_t *client;
138 bool want_dnssec;
139 bool want_validation;
140 bool want_cdflag;
141 bool want_tcp;
142
143 /* Locked */
144 ISC_LINK(struct resctx) link;
145 isc_task_t *task;
146 dns_view_t *view;
147 unsigned int restarts;
148 dns_fixedname_t name;
149 dns_rdatatype_t type;
150 dns_fetch_t *fetch;
151 dns_namelist_t namelist;
152 isc_result_t result;
153 dns_clientresevent_t *event;
154 bool canceled;
155 dns_rdataset_t *rdataset;
156 dns_rdataset_t *sigrdataset;
157 } resctx_t;
158
159 /*%
160 * Argument of an internal event for synchronous name resolution.
161 */
162 typedef struct resarg {
163 /* Unlocked */
164 isc_appctx_t *actx;
165 dns_client_t *client;
166 isc_mutex_t lock;
167
168 /* Locked */
169 isc_result_t result;
170 isc_result_t vresult;
171 dns_namelist_t *namelist;
172 dns_clientrestrans_t *trans;
173 bool canceled;
174 } resarg_t;
175
176 /*%
177 * Internal state for a single DNS request
178 */
179 typedef struct reqctx {
180 /* Unlocked */
181 unsigned int magic;
182 isc_mutex_t lock;
183 dns_client_t *client;
184 unsigned int parseoptions;
185
186 /* Locked */
187 ISC_LINK(struct reqctx) link;
188 bool canceled;
189 dns_tsigkey_t *tsigkey;
190 dns_request_t *request;
191 dns_clientreqevent_t *event;
192 } reqctx_t;
193
194 /*%
195 * Argument of an internal event for synchronous DNS request.
196 */
197 typedef struct reqarg {
198 /* Unlocked */
199 isc_appctx_t *actx;
200 dns_client_t *client;
201 isc_mutex_t lock;
202
203 /* Locked */
204 isc_result_t result;
205 dns_clientreqtrans_t *trans;
206 bool canceled;
207 } reqarg_t;
208
209 /*%
210 * Argument of an internal event for synchronous name resolution.
211 */
212 typedef struct updatearg {
213 /* Unlocked */
214 isc_appctx_t *actx;
215 dns_client_t *client;
216 isc_mutex_t lock;
217
218 /* Locked */
219 isc_result_t result;
220 dns_clientupdatetrans_t *trans;
221 bool canceled;
222 } updatearg_t;
223
224 /*%
225 * Internal state for a single dynamic update procedure
226 */
227 typedef struct updatectx {
228 /* Unlocked */
229 unsigned int magic;
230 isc_mutex_t lock;
231 dns_client_t *client;
232 bool want_tcp;
233
234 /* Locked */
235 dns_request_t *updatereq;
236 dns_request_t *soareq;
237 dns_clientrestrans_t *restrans;
238 dns_clientrestrans_t *restrans2;
239 bool canceled;
240
241 /* Task Locked */
242 ISC_LINK(struct updatectx) link;
243 dns_clientupdatestate_t state;
244 dns_rdataclass_t rdclass;
245 dns_view_t *view;
246 dns_message_t *updatemsg;
247 dns_message_t *soaquery;
248 dns_clientupdateevent_t *event;
249 dns_tsigkey_t *tsigkey;
250 dst_key_t *sig0key;
251 dns_name_t *firstname;
252 dns_name_t soaqname;
253 dns_fixedname_t zonefname;
254 dns_name_t *zonename;
255 isc_sockaddrlist_t servers;
256 unsigned int nservers;
257 isc_sockaddr_t *currentserver;
258 struct updatectx *bp4;
259 struct updatectx *bp6;
260 } updatectx_t;
261
262 static isc_result_t
263 request_soa(updatectx_t *uctx);
264 static void
265 client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
266 static isc_result_t
267 send_update(updatectx_t *uctx);
268
269 /*
270 * Try honoring the operating system's preferred ephemeral port range.
271 */
272 static isc_result_t
setsourceports(isc_mem_t * mctx,dns_dispatchmgr_t * manager)273 setsourceports(isc_mem_t *mctx, dns_dispatchmgr_t *manager) {
274 isc_portset_t *v4portset = NULL, *v6portset = NULL;
275 in_port_t udpport_low, udpport_high;
276 isc_result_t result;
277
278 result = isc_portset_create(mctx, &v4portset);
279 if (result != ISC_R_SUCCESS) {
280 goto cleanup;
281 }
282 result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high);
283 if (result != ISC_R_SUCCESS) {
284 goto cleanup;
285 }
286 isc_portset_addrange(v4portset, udpport_low, udpport_high);
287
288 result = isc_portset_create(mctx, &v6portset);
289 if (result != ISC_R_SUCCESS) {
290 goto cleanup;
291 }
292 result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high);
293 if (result != ISC_R_SUCCESS) {
294 goto cleanup;
295 }
296 isc_portset_addrange(v6portset, udpport_low, udpport_high);
297
298 result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset);
299
300 cleanup:
301 if (v4portset != NULL) {
302 isc_portset_destroy(mctx, &v4portset);
303 }
304 if (v6portset != NULL) {
305 isc_portset_destroy(mctx, &v6portset);
306 }
307
308 return (result);
309 }
310
311 static isc_result_t
getudpdispatch(int family,dns_dispatchmgr_t * dispatchmgr,isc_socketmgr_t * socketmgr,isc_taskmgr_t * taskmgr,bool is_shared,dns_dispatch_t ** dispp,const isc_sockaddr_t * localaddr)312 getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
313 isc_socketmgr_t *socketmgr, isc_taskmgr_t *taskmgr,
314 bool is_shared, dns_dispatch_t **dispp,
315 const isc_sockaddr_t *localaddr) {
316 unsigned int attrs, attrmask;
317 dns_dispatch_t *disp;
318 unsigned buffersize, maxbuffers, maxrequests, buckets, increment;
319 isc_result_t result;
320 isc_sockaddr_t anyaddr;
321
322 attrs = 0;
323 attrs |= DNS_DISPATCHATTR_UDP;
324 switch (family) {
325 case AF_INET:
326 attrs |= DNS_DISPATCHATTR_IPV4;
327 break;
328 case AF_INET6:
329 attrs |= DNS_DISPATCHATTR_IPV6;
330 break;
331 default:
332 UNREACHABLE();
333 }
334 attrmask = 0;
335 attrmask |= DNS_DISPATCHATTR_UDP;
336 attrmask |= DNS_DISPATCHATTR_TCP;
337 attrmask |= DNS_DISPATCHATTR_IPV4;
338 attrmask |= DNS_DISPATCHATTR_IPV6;
339
340 if (localaddr == NULL) {
341 isc_sockaddr_anyofpf(&anyaddr, family);
342 localaddr = &anyaddr;
343 }
344
345 buffersize = 4096;
346 maxbuffers = is_shared ? 1000 : 8;
347 maxrequests = 32768;
348 buckets = is_shared ? 16411 : 3;
349 increment = is_shared ? 16433 : 5;
350
351 disp = NULL;
352 result = dns_dispatch_getudp(dispatchmgr, socketmgr, taskmgr, localaddr,
353 buffersize, maxbuffers, maxrequests,
354 buckets, increment, attrs, attrmask,
355 &disp);
356 if (result == ISC_R_SUCCESS) {
357 *dispp = disp;
358 }
359
360 return (result);
361 }
362
363 static isc_result_t
createview(isc_mem_t * mctx,dns_rdataclass_t rdclass,unsigned int options,isc_taskmgr_t * taskmgr,unsigned int ntasks,isc_socketmgr_t * socketmgr,isc_timermgr_t * timermgr,dns_dispatchmgr_t * dispatchmgr,dns_dispatch_t * dispatchv4,dns_dispatch_t * dispatchv6,dns_view_t ** viewp)364 createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, unsigned int options,
365 isc_taskmgr_t *taskmgr, unsigned int ntasks,
366 isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
367 dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4,
368 dns_dispatch_t *dispatchv6, dns_view_t **viewp) {
369 isc_result_t result;
370 dns_view_t *view = NULL;
371 const char *dbtype;
372
373 result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
374 if (result != ISC_R_SUCCESS) {
375 return (result);
376 }
377
378 /* Initialize view security roots */
379 result = dns_view_initsecroots(view, mctx);
380 if (result != ISC_R_SUCCESS) {
381 dns_view_detach(&view);
382 return (result);
383 }
384
385 result = dns_view_createresolver(view, taskmgr, ntasks, 1, socketmgr,
386 timermgr, 0, dispatchmgr, dispatchv4,
387 dispatchv6);
388 if (result != ISC_R_SUCCESS) {
389 dns_view_detach(&view);
390 return (result);
391 }
392
393 /*
394 * Set cache DB.
395 * XXX: it may be better if specific DB implementations can be
396 * specified via some configuration knob.
397 */
398 if ((options & DNS_CLIENTCREATEOPT_USECACHE) != 0) {
399 dbtype = "rbt";
400 } else {
401 dbtype = "ecdb";
402 }
403 result = dns_db_create(mctx, dbtype, dns_rootname, dns_dbtype_cache,
404 rdclass, 0, NULL, &view->cachedb);
405 if (result != ISC_R_SUCCESS) {
406 dns_view_detach(&view);
407 return (result);
408 }
409
410 *viewp = view;
411 return (ISC_R_SUCCESS);
412 }
413
414
415 isc_result_t
dns_client_create(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,const isc_sockaddr_t * localaddr4,const isc_sockaddr_t * localaddr6)416 dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
417 isc_socketmgr_t *socketmgr, isc_timermgr_t *timermgr,
418 unsigned int options, dns_client_t **clientp,
419 const isc_sockaddr_t *localaddr4,
420 const isc_sockaddr_t *localaddr6) {
421 isc_result_t result;
422 dns_client_t *client;
423 dns_dispatchmgr_t *dispatchmgr = NULL;
424 dns_dispatch_t *dispatchv4 = NULL;
425 dns_dispatch_t *dispatchv6 = NULL;
426 dns_view_t *view = NULL;
427
428 REQUIRE(mctx != NULL);
429 REQUIRE(taskmgr != NULL);
430 REQUIRE(timermgr != NULL);
431 REQUIRE(socketmgr != NULL);
432 REQUIRE(clientp != NULL && *clientp == NULL);
433
434 client = isc_mem_get(mctx, sizeof(*client));
435
436 isc_mutex_init(&client->lock);
437
438 client->actx = actx;
439 client->taskmgr = taskmgr;
440 client->socketmgr = socketmgr;
441 client->timermgr = timermgr;
442
443 client->task = NULL;
444 result = isc_task_create(client->taskmgr, 0, &client->task);
445 if (result != ISC_R_SUCCESS) {
446 goto cleanup_lock;
447 }
448
449 result = dns_dispatchmgr_create(mctx, &dispatchmgr);
450 if (result != ISC_R_SUCCESS) {
451 goto cleanup_task;
452 }
453 client->dispatchmgr = dispatchmgr;
454 (void)setsourceports(mctx, dispatchmgr);
455
456 /*
457 * If only one address family is specified, use it.
458 * If neither family is specified, or if both are, use both.
459 */
460 client->dispatchv4 = NULL;
461 if (localaddr4 != NULL || localaddr6 == NULL) {
462 result = getudpdispatch(AF_INET, dispatchmgr, socketmgr,
463 taskmgr, true, &dispatchv4, localaddr4);
464 if (result == ISC_R_SUCCESS) {
465 client->dispatchv4 = dispatchv4;
466 }
467 }
468
469 client->dispatchv6 = NULL;
470 if (localaddr6 != NULL || localaddr4 == NULL) {
471 result = getudpdispatch(AF_INET6, dispatchmgr, socketmgr,
472 taskmgr, true, &dispatchv6, localaddr6);
473 if (result == ISC_R_SUCCESS) {
474 client->dispatchv6 = dispatchv6;
475 }
476 }
477
478 /* We need at least one of the dispatchers */
479 if (dispatchv4 == NULL && dispatchv6 == NULL) {
480 INSIST(result != ISC_R_SUCCESS);
481 goto cleanup_dispatchmgr;
482 }
483
484 isc_refcount_init(&client->references, 1);
485
486 /* Create the default view for class IN */
487 result = createview(mctx, dns_rdataclass_in, options, taskmgr,
488 RESOLVER_NTASKS, socketmgr, timermgr, dispatchmgr,
489 dispatchv4, dispatchv6, &view);
490 if (result != ISC_R_SUCCESS) {
491 goto cleanup_references;
492 }
493
494 ISC_LIST_INIT(client->viewlist);
495 ISC_LIST_APPEND(client->viewlist, view, link);
496
497 dns_view_freeze(view); /* too early? */
498
499 ISC_LIST_INIT(client->resctxs);
500 ISC_LIST_INIT(client->reqctxs);
501 ISC_LIST_INIT(client->updatectxs);
502
503 client->mctx = NULL;
504 isc_mem_attach(mctx, &client->mctx);
505
506 client->update_timeout = DEF_UPDATE_TIMEOUT;
507 client->update_udptimeout = DEF_UPDATE_UDPTIMEOUT;
508 client->update_udpretries = DEF_UPDATE_UDPRETRIES;
509 client->find_timeout = DEF_FIND_TIMEOUT;
510 client->find_udpretries = DEF_FIND_UDPRETRIES;
511 client->attributes = 0;
512
513 client->magic = DNS_CLIENT_MAGIC;
514
515 *clientp = client;
516
517 return (ISC_R_SUCCESS);
518
519 cleanup_references:
520 isc_refcount_decrementz(&client->references);
521 isc_refcount_destroy(&client->references);
522 cleanup_dispatchmgr:
523 if (dispatchv4 != NULL) {
524 dns_dispatch_detach(&dispatchv4);
525 }
526 if (dispatchv6 != NULL) {
527 dns_dispatch_detach(&dispatchv6);
528 }
529 dns_dispatchmgr_destroy(&dispatchmgr);
530 cleanup_task:
531 isc_task_detach(&client->task);
532 cleanup_lock:
533 isc_mutex_destroy(&client->lock);
534 isc_mem_put(mctx, client, sizeof(*client));
535
536 return (result);
537 }
538
539 static void
destroyclient(dns_client_t * client)540 destroyclient(dns_client_t *client) {
541 dns_view_t *view;
542
543 isc_refcount_destroy(&client->references);
544
545 while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
546 ISC_LIST_UNLINK(client->viewlist, view, link);
547 dns_view_detach(&view);
548 }
549
550 if (client->dispatchv4 != NULL) {
551 dns_dispatch_detach(&client->dispatchv4);
552 }
553 if (client->dispatchv6 != NULL) {
554 dns_dispatch_detach(&client->dispatchv6);
555 }
556
557 dns_dispatchmgr_destroy(&client->dispatchmgr);
558
559 isc_task_detach(&client->task);
560 client->magic = 0;
561
562 isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
563 }
564
565 void
dns_client_destroy(dns_client_t ** clientp)566 dns_client_destroy(dns_client_t **clientp) {
567 dns_client_t *client;
568
569 REQUIRE(clientp != NULL);
570 client = *clientp;
571 *clientp = NULL;
572 REQUIRE(DNS_CLIENT_VALID(client));
573
574 if (isc_refcount_decrement(&client->references) == 1) {
575 destroyclient(client);
576 }
577 }
578
579 isc_result_t
dns_client_setservers(dns_client_t * client,dns_rdataclass_t rdclass,const dns_name_t * name_space,isc_sockaddrlist_t * addrs)580 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
581 const dns_name_t *name_space, isc_sockaddrlist_t *addrs) {
582 isc_result_t result;
583 dns_view_t *view = NULL;
584
585 REQUIRE(DNS_CLIENT_VALID(client));
586 REQUIRE(addrs != NULL);
587
588 if (name_space == NULL) {
589 name_space = dns_rootname;
590 }
591
592 LOCK(&client->lock);
593 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
594 rdclass, &view);
595 if (result != ISC_R_SUCCESS) {
596 UNLOCK(&client->lock);
597 return (result);
598 }
599 UNLOCK(&client->lock);
600
601 result = dns_fwdtable_add(view->fwdtable, name_space, addrs,
602 dns_fwdpolicy_only);
603
604 dns_view_detach(&view);
605
606 return (result);
607 }
608
609 isc_result_t
dns_client_clearservers(dns_client_t * client,dns_rdataclass_t rdclass,const dns_name_t * name_space)610 dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
611 const dns_name_t *name_space) {
612 isc_result_t result;
613 dns_view_t *view = NULL;
614
615 REQUIRE(DNS_CLIENT_VALID(client));
616
617 if (name_space == NULL) {
618 name_space = dns_rootname;
619 }
620
621 LOCK(&client->lock);
622 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
623 rdclass, &view);
624 if (result != ISC_R_SUCCESS) {
625 UNLOCK(&client->lock);
626 return (result);
627 }
628 UNLOCK(&client->lock);
629
630 result = dns_fwdtable_delete(view->fwdtable, name_space);
631
632 dns_view_detach(&view);
633
634 return (result);
635 }
636
637 static isc_result_t
getrdataset(isc_mem_t * mctx,dns_rdataset_t ** rdatasetp)638 getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
639 dns_rdataset_t *rdataset;
640
641 REQUIRE(mctx != NULL);
642 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
643
644 rdataset = isc_mem_get(mctx, sizeof(*rdataset));
645
646 dns_rdataset_init(rdataset);
647
648 *rdatasetp = rdataset;
649
650 return (ISC_R_SUCCESS);
651 }
652
653 static void
putrdataset(isc_mem_t * mctx,dns_rdataset_t ** rdatasetp)654 putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
655 dns_rdataset_t *rdataset;
656
657 REQUIRE(rdatasetp != NULL);
658 rdataset = *rdatasetp;
659 *rdatasetp = NULL;
660 REQUIRE(rdataset != NULL);
661
662 if (dns_rdataset_isassociated(rdataset)) {
663 dns_rdataset_disassociate(rdataset);
664 }
665
666 isc_mem_put(mctx, rdataset, sizeof(*rdataset));
667 }
668
669 static void
fetch_done(isc_task_t * task,isc_event_t * event)670 fetch_done(isc_task_t *task, isc_event_t *event) {
671 resctx_t *rctx = event->ev_arg;
672 dns_fetchevent_t *fevent;
673
674 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
675 REQUIRE(RCTX_VALID(rctx));
676 REQUIRE(rctx->task == task);
677 fevent = (dns_fetchevent_t *)event;
678
679 client_resfind(rctx, fevent);
680 }
681
682 static isc_result_t
start_fetch(resctx_t * rctx)683 start_fetch(resctx_t *rctx) {
684 isc_result_t result;
685 int fopts = 0;
686
687 /*
688 * The caller must be holding the rctx's lock.
689 */
690
691 REQUIRE(rctx->fetch == NULL);
692
693 if (!rctx->want_cdflag) {
694 fopts |= DNS_FETCHOPT_NOCDFLAG;
695 }
696 if (!rctx->want_validation) {
697 fopts |= DNS_FETCHOPT_NOVALIDATE;
698 }
699 if (rctx->want_tcp) {
700 fopts |= DNS_FETCHOPT_TCP;
701 }
702
703 result = dns_resolver_createfetch(
704 rctx->view->resolver, dns_fixedname_name(&rctx->name),
705 rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL,
706 rctx->task, fetch_done, rctx, rctx->rdataset, rctx->sigrdataset,
707 &rctx->fetch);
708
709 return (result);
710 }
711
712 static isc_result_t
view_find(resctx_t * rctx,dns_db_t ** dbp,dns_dbnode_t ** nodep,dns_name_t * foundname)713 view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
714 dns_name_t *foundname) {
715 isc_result_t result;
716 dns_name_t *name = dns_fixedname_name(&rctx->name);
717 dns_rdatatype_t type;
718
719 if (rctx->type == dns_rdatatype_rrsig) {
720 type = dns_rdatatype_any;
721 } else {
722 type = rctx->type;
723 }
724
725 result = dns_view_find(rctx->view, name, type, 0, 0, false, false, dbp,
726 nodep, foundname, rctx->rdataset,
727 rctx->sigrdataset);
728
729 return (result);
730 }
731
732 static void
client_resfind(resctx_t * rctx,dns_fetchevent_t * event)733 client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
734 isc_mem_t *mctx;
735 isc_result_t tresult, result = ISC_R_SUCCESS;
736 isc_result_t vresult = ISC_R_SUCCESS;
737 bool want_restart;
738 bool send_event = false;
739 dns_name_t *name, *prefix;
740 dns_fixedname_t foundname, fixed;
741 dns_rdataset_t *trdataset;
742 dns_rdata_t rdata = DNS_RDATA_INIT;
743 unsigned int nlabels;
744 int order;
745 dns_namereln_t namereln;
746 dns_rdata_cname_t cname;
747 dns_rdata_dname_t dname;
748
749 REQUIRE(RCTX_VALID(rctx));
750
751 LOCK(&rctx->lock);
752
753 mctx = rctx->view->mctx;
754
755 name = dns_fixedname_name(&rctx->name);
756
757 do {
758 dns_name_t *fname = NULL;
759 dns_name_t *ansname = NULL;
760 dns_db_t *db = NULL;
761 dns_dbnode_t *node = NULL;
762
763 rctx->restarts++;
764 want_restart = false;
765
766 if (event == NULL && !rctx->canceled) {
767 fname = dns_fixedname_initname(&foundname);
768 INSIST(!dns_rdataset_isassociated(rctx->rdataset));
769 INSIST(rctx->sigrdataset == NULL ||
770 !dns_rdataset_isassociated(rctx->sigrdataset));
771 result = view_find(rctx, &db, &node, fname);
772 if (result == ISC_R_NOTFOUND) {
773 /*
774 * We don't know anything about the name.
775 * Launch a fetch.
776 */
777 if (node != NULL) {
778 INSIST(db != NULL);
779 dns_db_detachnode(db, &node);
780 }
781 if (db != NULL) {
782 dns_db_detach(&db);
783 }
784 result = start_fetch(rctx);
785 if (result != ISC_R_SUCCESS) {
786 putrdataset(mctx, &rctx->rdataset);
787 if (rctx->sigrdataset != NULL) {
788 putrdataset(mctx,
789 &rctx->sigrdataset);
790 }
791 send_event = true;
792 }
793 goto done;
794 }
795 } else {
796 INSIST(event != NULL);
797 INSIST(event->fetch == rctx->fetch);
798 dns_resolver_destroyfetch(&rctx->fetch);
799 db = event->db;
800 node = event->node;
801 result = event->result;
802 vresult = event->vresult;
803 fname = dns_fixedname_name(&event->foundname);
804 INSIST(event->rdataset == rctx->rdataset);
805 INSIST(event->sigrdataset == rctx->sigrdataset);
806 }
807
808 /*
809 * If we've been canceled, forget about the result.
810 */
811 if (rctx->canceled) {
812 result = ISC_R_CANCELED;
813 } else {
814 /*
815 * Otherwise, get some resource for copying the
816 * result.
817 */
818 dns_name_t *aname = dns_fixedname_name(&rctx->name);
819
820 ansname = isc_mem_get(mctx, sizeof(*ansname));
821 dns_name_init(ansname, NULL);
822
823 dns_name_dup(aname, mctx, ansname);
824 }
825
826 switch (result) {
827 case ISC_R_SUCCESS:
828 send_event = true;
829 /*
830 * This case is handled in the main line below.
831 */
832 break;
833 case DNS_R_CNAME:
834 /*
835 * Add the CNAME to the answer list.
836 */
837 trdataset = rctx->rdataset;
838 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
839 rctx->rdataset = NULL;
840 if (rctx->sigrdataset != NULL) {
841 ISC_LIST_APPEND(ansname->list,
842 rctx->sigrdataset, link);
843 rctx->sigrdataset = NULL;
844 }
845 ISC_LIST_APPEND(rctx->namelist, ansname, link);
846 ansname = NULL;
847
848 /*
849 * Copy the CNAME's target into the lookup's
850 * query name and start over.
851 */
852 tresult = dns_rdataset_first(trdataset);
853 if (tresult != ISC_R_SUCCESS) {
854 goto done;
855 }
856 dns_rdataset_current(trdataset, &rdata);
857 tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
858 dns_rdata_reset(&rdata);
859 if (tresult != ISC_R_SUCCESS) {
860 goto done;
861 }
862 dns_name_copynf(&cname.cname, name);
863 dns_rdata_freestruct(&cname);
864 want_restart = true;
865 goto done;
866 case DNS_R_DNAME:
867 /*
868 * Add the DNAME to the answer list.
869 */
870 trdataset = rctx->rdataset;
871 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
872 rctx->rdataset = NULL;
873 if (rctx->sigrdataset != NULL) {
874 ISC_LIST_APPEND(ansname->list,
875 rctx->sigrdataset, link);
876 rctx->sigrdataset = NULL;
877 }
878 ISC_LIST_APPEND(rctx->namelist, ansname, link);
879 ansname = NULL;
880
881 namereln = dns_name_fullcompare(name, fname, &order,
882 &nlabels);
883 INSIST(namereln == dns_namereln_subdomain);
884 /*
885 * Get the target name of the DNAME.
886 */
887 tresult = dns_rdataset_first(trdataset);
888 if (tresult != ISC_R_SUCCESS) {
889 result = tresult;
890 goto done;
891 }
892 dns_rdataset_current(trdataset, &rdata);
893 tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
894 dns_rdata_reset(&rdata);
895 if (tresult != ISC_R_SUCCESS) {
896 result = tresult;
897 goto done;
898 }
899 /*
900 * Construct the new query name and start over.
901 */
902 prefix = dns_fixedname_initname(&fixed);
903 dns_name_split(name, nlabels, prefix, NULL);
904 tresult = dns_name_concatenate(prefix, &dname.dname,
905 name, NULL);
906 dns_rdata_freestruct(&dname);
907 if (tresult == ISC_R_SUCCESS) {
908 want_restart = true;
909 } else {
910 result = tresult;
911 }
912 goto done;
913 case DNS_R_NCACHENXDOMAIN:
914 case DNS_R_NCACHENXRRSET:
915 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
916 ISC_LIST_APPEND(rctx->namelist, ansname, link);
917 ansname = NULL;
918 rctx->rdataset = NULL;
919 /* What about sigrdataset? */
920 if (rctx->sigrdataset != NULL) {
921 putrdataset(mctx, &rctx->sigrdataset);
922 }
923 send_event = true;
924 goto done;
925 default:
926 if (rctx->rdataset != NULL) {
927 putrdataset(mctx, &rctx->rdataset);
928 }
929 if (rctx->sigrdataset != NULL) {
930 putrdataset(mctx, &rctx->sigrdataset);
931 }
932 send_event = true;
933 goto done;
934 }
935
936 if (rctx->type == dns_rdatatype_any) {
937 int n = 0;
938 dns_rdatasetiter_t *rdsiter = NULL;
939
940 tresult = dns_db_allrdatasets(db, node, NULL, 0, 0,
941 &rdsiter);
942 if (tresult != ISC_R_SUCCESS) {
943 result = tresult;
944 goto done;
945 }
946
947 tresult = dns_rdatasetiter_first(rdsiter);
948 while (tresult == ISC_R_SUCCESS) {
949 dns_rdatasetiter_current(rdsiter,
950 rctx->rdataset);
951 if (rctx->rdataset->type != 0) {
952 ISC_LIST_APPEND(ansname->list,
953 rctx->rdataset, link);
954 n++;
955 rctx->rdataset = NULL;
956 } else {
957 /*
958 * We're not interested in this
959 * rdataset.
960 */
961 dns_rdataset_disassociate(
962 rctx->rdataset);
963 }
964 tresult = dns_rdatasetiter_next(rdsiter);
965
966 if (tresult == ISC_R_SUCCESS &&
967 rctx->rdataset == NULL)
968 {
969 tresult = getrdataset(mctx,
970 &rctx->rdataset);
971 if (tresult != ISC_R_SUCCESS) {
972 result = tresult;
973 POST(result);
974 break;
975 }
976 }
977 }
978 if (rctx->rdataset != NULL) {
979 putrdataset(mctx, &rctx->rdataset);
980 }
981 if (rctx->sigrdataset != NULL) {
982 putrdataset(mctx, &rctx->sigrdataset);
983 }
984 if (n == 0) {
985 /*
986 * We didn't match any rdatasets (which means
987 * something went wrong in this
988 * implementation).
989 */
990 result = DNS_R_SERVFAIL; /* better code? */
991 POST(result);
992 } else {
993 ISC_LIST_APPEND(rctx->namelist, ansname, link);
994 ansname = NULL;
995 }
996 dns_rdatasetiter_destroy(&rdsiter);
997 if (tresult != ISC_R_NOMORE) {
998 result = DNS_R_SERVFAIL; /* ditto */
999 } else {
1000 result = ISC_R_SUCCESS;
1001 }
1002 goto done;
1003 } else {
1004 /*
1005 * This is the "normal" case -- an ordinary question
1006 * to which we've got the answer.
1007 */
1008 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
1009 rctx->rdataset = NULL;
1010 if (rctx->sigrdataset != NULL) {
1011 ISC_LIST_APPEND(ansname->list,
1012 rctx->sigrdataset, link);
1013 rctx->sigrdataset = NULL;
1014 }
1015 ISC_LIST_APPEND(rctx->namelist, ansname, link);
1016 ansname = NULL;
1017 }
1018
1019 done:
1020 /*
1021 * Free temporary resources
1022 */
1023 if (ansname != NULL) {
1024 dns_rdataset_t *rdataset;
1025
1026 while ((rdataset = ISC_LIST_HEAD(ansname->list)) !=
1027 NULL)
1028 {
1029 ISC_LIST_UNLINK(ansname->list, rdataset, link);
1030 putrdataset(mctx, &rdataset);
1031 }
1032 dns_name_free(ansname, mctx);
1033 isc_mem_put(mctx, ansname, sizeof(*ansname));
1034 }
1035
1036 if (node != NULL) {
1037 dns_db_detachnode(db, &node);
1038 }
1039 if (db != NULL) {
1040 dns_db_detach(&db);
1041 }
1042 if (event != NULL) {
1043 isc_event_free(ISC_EVENT_PTR(&event));
1044 }
1045
1046 /*
1047 * Limit the number of restarts.
1048 */
1049 if (want_restart && rctx->restarts == MAX_RESTARTS) {
1050 want_restart = false;
1051 result = ISC_R_QUOTA;
1052 send_event = true;
1053 }
1054
1055 /*
1056 * Prepare further find with new resources
1057 */
1058 if (want_restart) {
1059 INSIST(rctx->rdataset == NULL &&
1060 rctx->sigrdataset == NULL);
1061
1062 result = getrdataset(mctx, &rctx->rdataset);
1063 if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
1064 result = getrdataset(mctx, &rctx->sigrdataset);
1065 if (result != ISC_R_SUCCESS) {
1066 putrdataset(mctx, &rctx->rdataset);
1067 }
1068 }
1069
1070 if (result != ISC_R_SUCCESS) {
1071 want_restart = false;
1072 send_event = true;
1073 }
1074 }
1075 } while (want_restart);
1076
1077 if (send_event) {
1078 isc_task_t *task;
1079
1080 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
1081 ISC_LIST_UNLINK(rctx->namelist, name, link);
1082 ISC_LIST_APPEND(rctx->event->answerlist, name, link);
1083 }
1084
1085 rctx->event->result = result;
1086 rctx->event->vresult = vresult;
1087 task = rctx->event->ev_sender;
1088 rctx->event->ev_sender = rctx;
1089 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
1090 }
1091
1092 UNLOCK(&rctx->lock);
1093 }
1094
1095 static void
suspend(isc_task_t * task,isc_event_t * event)1096 suspend(isc_task_t *task, isc_event_t *event) {
1097 isc_appctx_t *actx = event->ev_arg;
1098
1099 UNUSED(task);
1100
1101 isc_app_ctxsuspend(actx);
1102 isc_event_free(&event);
1103 }
1104
1105 static void
resolve_done(isc_task_t * task,isc_event_t * event)1106 resolve_done(isc_task_t *task, isc_event_t *event) {
1107 resarg_t *resarg = event->ev_arg;
1108 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
1109 dns_name_t *name;
1110 isc_result_t result;
1111
1112 UNUSED(task);
1113
1114 LOCK(&resarg->lock);
1115
1116 resarg->result = rev->result;
1117 resarg->vresult = rev->vresult;
1118 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
1119 ISC_LIST_UNLINK(rev->answerlist, name, link);
1120 ISC_LIST_APPEND(*resarg->namelist, name, link);
1121 }
1122
1123 dns_client_destroyrestrans(&resarg->trans);
1124 isc_event_free(&event);
1125
1126 if (!resarg->canceled) {
1127 UNLOCK(&resarg->lock);
1128
1129 /*
1130 * We may or may not be running. isc__appctx_onrun will
1131 * fail if we are currently running otherwise we post a
1132 * action to call isc_app_ctxsuspend when we do start
1133 * running.
1134 */
1135 result = isc_app_ctxonrun(resarg->actx, resarg->client->mctx,
1136 task, suspend, resarg->actx);
1137 if (result == ISC_R_ALREADYRUNNING) {
1138 isc_app_ctxsuspend(resarg->actx);
1139 }
1140 } else {
1141 /*
1142 * We have already exited from the loop (due to some
1143 * unexpected event). Just clean the arg up.
1144 */
1145 UNLOCK(&resarg->lock);
1146 isc_mutex_destroy(&resarg->lock);
1147 isc_mem_put(resarg->client->mctx, resarg, sizeof(*resarg));
1148 }
1149 }
1150
1151 isc_result_t
dns_client_resolve(dns_client_t * client,const dns_name_t * name,dns_rdataclass_t rdclass,dns_rdatatype_t type,unsigned int options,dns_namelist_t * namelist)1152 dns_client_resolve(dns_client_t *client, const dns_name_t *name,
1153 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1154 unsigned int options, dns_namelist_t *namelist) {
1155 isc_result_t result;
1156 isc_appctx_t *actx;
1157 resarg_t *resarg;
1158
1159 REQUIRE(DNS_CLIENT_VALID(client));
1160 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
1161
1162 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1163 (options & DNS_CLIENTRESOPT_ALLOWRUN) == 0)
1164 {
1165 /*
1166 * If the client is run under application's control, we need
1167 * to create a new running (sub)environment for this
1168 * particular resolution.
1169 */
1170 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1171 } else {
1172 actx = client->actx;
1173 }
1174
1175 resarg = isc_mem_get(client->mctx, sizeof(*resarg));
1176
1177 isc_mutex_init(&resarg->lock);
1178
1179 resarg->actx = actx;
1180 resarg->client = client;
1181 resarg->result = DNS_R_SERVFAIL;
1182 resarg->namelist = namelist;
1183 resarg->trans = NULL;
1184 resarg->canceled = false;
1185 result = dns_client_startresolve(client, name, rdclass, type, options,
1186 client->task, resolve_done, resarg,
1187 &resarg->trans);
1188 if (result != ISC_R_SUCCESS) {
1189 isc_mutex_destroy(&resarg->lock);
1190 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1191 return (result);
1192 }
1193
1194 /*
1195 * Start internal event loop. It blocks until the entire process
1196 * is completed.
1197 */
1198 result = isc_app_ctxrun(actx);
1199
1200 LOCK(&resarg->lock);
1201 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) {
1202 result = resarg->result;
1203 }
1204 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
1205 /*
1206 * If this lookup failed due to some error in DNSSEC
1207 * validation, return the validation error code.
1208 * XXX: or should we pass the validation result separately?
1209 */
1210 result = resarg->vresult;
1211 }
1212 if (resarg->trans != NULL) {
1213 /*
1214 * Unusual termination (perhaps due to signal). We need some
1215 * tricky cleanup process.
1216 */
1217 resarg->canceled = true;
1218 dns_client_cancelresolve(resarg->trans);
1219
1220 UNLOCK(&resarg->lock);
1221
1222 /* resarg will be freed in the event handler. */
1223 } else {
1224 UNLOCK(&resarg->lock);
1225
1226 isc_mutex_destroy(&resarg->lock);
1227 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1228 }
1229
1230 return (result);
1231 }
1232
1233 isc_result_t
dns_client_startresolve(dns_client_t * client,const 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)1234 dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
1235 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1236 unsigned int options, isc_task_t *task,
1237 isc_taskaction_t action, void *arg,
1238 dns_clientrestrans_t **transp) {
1239 dns_view_t *view = NULL;
1240 dns_clientresevent_t *event = NULL;
1241 resctx_t *rctx = NULL;
1242 isc_task_t *tclone = NULL;
1243 isc_mem_t *mctx;
1244 isc_result_t result;
1245 dns_rdataset_t *rdataset, *sigrdataset;
1246 bool want_dnssec, want_validation, want_cdflag, want_tcp;
1247
1248 REQUIRE(DNS_CLIENT_VALID(client));
1249 REQUIRE(transp != NULL && *transp == NULL);
1250
1251 LOCK(&client->lock);
1252 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1253 rdclass, &view);
1254 UNLOCK(&client->lock);
1255 if (result != ISC_R_SUCCESS) {
1256 return (result);
1257 }
1258
1259 mctx = client->mctx;
1260 rdataset = NULL;
1261 sigrdataset = NULL;
1262 want_dnssec = ((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
1263 want_validation = ((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0);
1264 want_cdflag = ((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0);
1265 want_tcp = ((options & DNS_CLIENTRESOPT_TCP) != 0);
1266
1267 /*
1268 * Prepare some intermediate resources
1269 */
1270 tclone = NULL;
1271 isc_task_attach(task, &tclone);
1272 event = (dns_clientresevent_t *)isc_event_allocate(
1273 mctx, tclone, DNS_EVENT_CLIENTRESDONE, action, arg,
1274 sizeof(*event));
1275 event->result = DNS_R_SERVFAIL;
1276 ISC_LIST_INIT(event->answerlist);
1277
1278 rctx = isc_mem_get(mctx, sizeof(*rctx));
1279 isc_mutex_init(&rctx->lock);
1280
1281 result = getrdataset(mctx, &rdataset);
1282 if (result != ISC_R_SUCCESS) {
1283 goto cleanup;
1284 }
1285 rctx->rdataset = rdataset;
1286
1287 if (want_dnssec) {
1288 result = getrdataset(mctx, &sigrdataset);
1289 if (result != ISC_R_SUCCESS) {
1290 goto cleanup;
1291 }
1292 }
1293 rctx->sigrdataset = sigrdataset;
1294
1295 dns_fixedname_init(&rctx->name);
1296 dns_name_copynf(name, dns_fixedname_name(&rctx->name));
1297
1298 rctx->client = client;
1299 ISC_LINK_INIT(rctx, link);
1300 rctx->canceled = false;
1301 rctx->task = client->task;
1302 rctx->type = type;
1303 rctx->view = view;
1304 rctx->restarts = 0;
1305 rctx->fetch = NULL;
1306 rctx->want_dnssec = want_dnssec;
1307 rctx->want_validation = want_validation;
1308 rctx->want_cdflag = want_cdflag;
1309 rctx->want_tcp = want_tcp;
1310 ISC_LIST_INIT(rctx->namelist);
1311 rctx->event = event;
1312
1313 rctx->magic = RCTX_MAGIC;
1314 isc_refcount_increment(&client->references);
1315
1316 LOCK(&client->lock);
1317 ISC_LIST_APPEND(client->resctxs, rctx, link);
1318 UNLOCK(&client->lock);
1319
1320 *transp = (dns_clientrestrans_t *)rctx;
1321 client_resfind(rctx, NULL);
1322
1323 return (ISC_R_SUCCESS);
1324
1325 cleanup:
1326 if (rdataset != NULL) {
1327 putrdataset(client->mctx, &rdataset);
1328 }
1329 if (sigrdataset != NULL) {
1330 putrdataset(client->mctx, &sigrdataset);
1331 }
1332 isc_mutex_destroy(&rctx->lock);
1333 isc_mem_put(mctx, rctx, sizeof(*rctx));
1334 isc_event_free(ISC_EVENT_PTR(&event));
1335 isc_task_detach(&tclone);
1336 dns_view_detach(&view);
1337
1338 return (result);
1339 }
1340
1341 void
dns_client_cancelresolve(dns_clientrestrans_t * trans)1342 dns_client_cancelresolve(dns_clientrestrans_t *trans) {
1343 resctx_t *rctx;
1344
1345 REQUIRE(trans != NULL);
1346 rctx = (resctx_t *)trans;
1347 REQUIRE(RCTX_VALID(rctx));
1348
1349 LOCK(&rctx->lock);
1350
1351 if (!rctx->canceled) {
1352 rctx->canceled = true;
1353 if (rctx->fetch != NULL) {
1354 dns_resolver_cancelfetch(rctx->fetch);
1355 }
1356 }
1357
1358 UNLOCK(&rctx->lock);
1359 }
1360
1361 void
dns_client_freeresanswer(dns_client_t * client,dns_namelist_t * namelist)1362 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
1363 dns_name_t *name;
1364 dns_rdataset_t *rdataset;
1365
1366 REQUIRE(DNS_CLIENT_VALID(client));
1367 REQUIRE(namelist != NULL);
1368
1369 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
1370 ISC_LIST_UNLINK(*namelist, name, link);
1371 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
1372 ISC_LIST_UNLINK(name->list, rdataset, link);
1373 putrdataset(client->mctx, &rdataset);
1374 }
1375 dns_name_free(name, client->mctx);
1376 isc_mem_put(client->mctx, name, sizeof(*name));
1377 }
1378 }
1379
1380 void
dns_client_destroyrestrans(dns_clientrestrans_t ** transp)1381 dns_client_destroyrestrans(dns_clientrestrans_t **transp) {
1382 resctx_t *rctx;
1383 isc_mem_t *mctx;
1384 dns_client_t *client;
1385
1386 REQUIRE(transp != NULL);
1387 rctx = (resctx_t *)*transp;
1388 *transp = NULL;
1389 REQUIRE(RCTX_VALID(rctx));
1390 REQUIRE(rctx->fetch == NULL);
1391 REQUIRE(rctx->event == NULL);
1392 client = rctx->client;
1393 REQUIRE(DNS_CLIENT_VALID(client));
1394
1395 mctx = client->mctx;
1396 dns_view_detach(&rctx->view);
1397
1398 /*
1399 * Wait for the lock in client_resfind to be released before
1400 * destroying the lock.
1401 */
1402 LOCK(&rctx->lock);
1403 UNLOCK(&rctx->lock);
1404
1405 LOCK(&client->lock);
1406
1407 INSIST(ISC_LINK_LINKED(rctx, link));
1408 ISC_LIST_UNLINK(client->resctxs, rctx, link);
1409
1410 UNLOCK(&client->lock);
1411
1412 INSIST(ISC_LIST_EMPTY(rctx->namelist));
1413
1414 isc_mutex_destroy(&rctx->lock);
1415 rctx->magic = 0;
1416
1417 isc_mem_put(mctx, rctx, sizeof(*rctx));
1418
1419 dns_client_destroy(&client);
1420 }
1421
1422 isc_result_t
dns_client_addtrustedkey(dns_client_t * client,dns_rdataclass_t rdclass,dns_rdatatype_t rdtype,const dns_name_t * keyname,isc_buffer_t * databuf)1423 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
1424 dns_rdatatype_t rdtype, const dns_name_t *keyname,
1425 isc_buffer_t *databuf) {
1426 isc_result_t result;
1427 dns_view_t *view = NULL;
1428 dns_keytable_t *secroots = NULL;
1429 dns_name_t *name = NULL;
1430 char rdatabuf[DST_KEY_MAXSIZE];
1431 unsigned char digest[ISC_MAX_MD_SIZE];
1432 dns_rdata_ds_t ds;
1433 dns_decompress_t dctx;
1434 dns_rdata_t rdata;
1435 isc_buffer_t b;
1436
1437 REQUIRE(DNS_CLIENT_VALID(client));
1438
1439 LOCK(&client->lock);
1440 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1441 rdclass, &view);
1442 UNLOCK(&client->lock);
1443 CHECK(result);
1444
1445 CHECK(dns_view_getsecroots(view, &secroots));
1446
1447 DE_CONST(keyname, name);
1448
1449 if (rdtype != dns_rdatatype_dnskey && rdtype != dns_rdatatype_ds) {
1450 result = ISC_R_NOTIMPLEMENTED;
1451 goto cleanup;
1452 }
1453
1454 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1455 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
1456 dns_rdata_init(&rdata);
1457 isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf));
1458 CHECK(dns_rdata_fromwire(&rdata, rdclass, rdtype, databuf, &dctx, 0,
1459 &b));
1460 dns_decompress_invalidate(&dctx);
1461
1462 if (rdtype == dns_rdatatype_ds) {
1463 CHECK(dns_rdata_tostruct(&rdata, &ds, NULL));
1464 } else {
1465 CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
1466 digest, &ds));
1467 }
1468
1469 CHECK(dns_keytable_add(secroots, false, false, name, &ds));
1470
1471 cleanup:
1472 if (view != NULL) {
1473 dns_view_detach(&view);
1474 }
1475 if (secroots != NULL) {
1476 dns_keytable_detach(&secroots);
1477 }
1478 return (result);
1479 }
1480
1481 /*%
1482 * Simple request routines
1483 */
1484 static void
request_done(isc_task_t * task,isc_event_t * event)1485 request_done(isc_task_t *task, isc_event_t *event) {
1486 dns_requestevent_t *reqev = NULL;
1487 dns_request_t *request;
1488 isc_result_t result, eresult;
1489 reqctx_t *ctx;
1490
1491 UNUSED(task);
1492
1493 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1494 reqev = (dns_requestevent_t *)event;
1495 request = reqev->request;
1496 result = eresult = reqev->result;
1497 ctx = reqev->ev_arg;
1498 REQUIRE(REQCTX_VALID(ctx));
1499
1500 isc_event_free(&event);
1501
1502 LOCK(&ctx->lock);
1503
1504 if (eresult == ISC_R_SUCCESS) {
1505 result = dns_request_getresponse(request, ctx->event->rmessage,
1506 ctx->parseoptions);
1507 }
1508
1509 if (ctx->tsigkey != NULL) {
1510 dns_tsigkey_detach(&ctx->tsigkey);
1511 }
1512
1513 if (ctx->canceled) {
1514 ctx->event->result = ISC_R_CANCELED;
1515 } else {
1516 ctx->event->result = result;
1517 }
1518 task = ctx->event->ev_sender;
1519 ctx->event->ev_sender = ctx;
1520 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&ctx->event));
1521
1522 UNLOCK(&ctx->lock);
1523 }
1524
1525 static void
localrequest_done(isc_task_t * task,isc_event_t * event)1526 localrequest_done(isc_task_t *task, isc_event_t *event) {
1527 reqarg_t *reqarg = event->ev_arg;
1528 dns_clientreqevent_t *rev = (dns_clientreqevent_t *)event;
1529
1530 UNUSED(task);
1531
1532 REQUIRE(event->ev_type == DNS_EVENT_CLIENTREQDONE);
1533
1534 LOCK(&reqarg->lock);
1535
1536 reqarg->result = rev->result;
1537 dns_client_destroyreqtrans(&reqarg->trans);
1538 isc_event_free(&event);
1539
1540 if (!reqarg->canceled) {
1541 UNLOCK(&reqarg->lock);
1542
1543 /* Exit from the internal event loop */
1544 isc_app_ctxsuspend(reqarg->actx);
1545 } else {
1546 /*
1547 * We have already exited from the loop (due to some
1548 * unexpected event). Just clean the arg up.
1549 */
1550 UNLOCK(&reqarg->lock);
1551 isc_mutex_destroy(&reqarg->lock);
1552 isc_mem_put(reqarg->client->mctx, reqarg, sizeof(*reqarg));
1553 }
1554 }
1555
1556 isc_result_t
dns_client_request(dns_client_t * client,dns_message_t * qmessage,dns_message_t * rmessage,const isc_sockaddr_t * server,unsigned int options,unsigned int parseoptions,dns_tsec_t * tsec,unsigned int timeout,unsigned int udptimeout,unsigned int udpretries)1557 dns_client_request(dns_client_t *client, dns_message_t *qmessage,
1558 dns_message_t *rmessage, const isc_sockaddr_t *server,
1559 unsigned int options, unsigned int parseoptions,
1560 dns_tsec_t *tsec, unsigned int timeout,
1561 unsigned int udptimeout, unsigned int udpretries) {
1562 isc_appctx_t *actx;
1563 reqarg_t *reqarg;
1564 isc_result_t result;
1565
1566 REQUIRE(DNS_CLIENT_VALID(client));
1567 REQUIRE(qmessage != NULL);
1568 REQUIRE(rmessage != NULL);
1569
1570 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
1571 (options & DNS_CLIENTREQOPT_ALLOWRUN) == 0)
1572 {
1573 /*
1574 * If the client is run under application's control, we need
1575 * to create a new running (sub)environment for this
1576 * particular resolution.
1577 */
1578 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
1579 } else {
1580 actx = client->actx;
1581 }
1582
1583 reqarg = isc_mem_get(client->mctx, sizeof(*reqarg));
1584
1585 isc_mutex_init(&reqarg->lock);
1586
1587 reqarg->actx = actx;
1588 reqarg->client = client;
1589 reqarg->trans = NULL;
1590 reqarg->canceled = false;
1591
1592 result = dns_client_startrequest(
1593 client, qmessage, rmessage, server, options, parseoptions, tsec,
1594 timeout, udptimeout, udpretries, client->task,
1595 localrequest_done, reqarg, &reqarg->trans);
1596 if (result != ISC_R_SUCCESS) {
1597 isc_mutex_destroy(&reqarg->lock);
1598 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1599 return (result);
1600 }
1601
1602 /*
1603 * Start internal event loop. It blocks until the entire process
1604 * is completed.
1605 */
1606 result = isc_app_ctxrun(actx);
1607
1608 LOCK(&reqarg->lock);
1609 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) {
1610 result = reqarg->result;
1611 }
1612 if (reqarg->trans != NULL) {
1613 /*
1614 * Unusual termination (perhaps due to signal). We need some
1615 * tricky cleanup process.
1616 */
1617 reqarg->canceled = true;
1618 dns_client_cancelresolve(reqarg->trans);
1619
1620 UNLOCK(&reqarg->lock);
1621
1622 /* reqarg will be freed in the event handler. */
1623 } else {
1624 UNLOCK(&reqarg->lock);
1625
1626 isc_mutex_destroy(&reqarg->lock);
1627 isc_mem_put(client->mctx, reqarg, sizeof(*reqarg));
1628 }
1629
1630 return (result);
1631 }
1632
1633 isc_result_t
dns_client_startrequest(dns_client_t * client,dns_message_t * qmessage,dns_message_t * rmessage,const 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)1634 dns_client_startrequest(dns_client_t *client, dns_message_t *qmessage,
1635 dns_message_t *rmessage, const isc_sockaddr_t *server,
1636 unsigned int options, unsigned int parseoptions,
1637 dns_tsec_t *tsec, unsigned int timeout,
1638 unsigned int udptimeout, unsigned int udpretries,
1639 isc_task_t *task, isc_taskaction_t action, void *arg,
1640 dns_clientreqtrans_t **transp) {
1641 isc_result_t result;
1642 dns_view_t *view = NULL;
1643 isc_task_t *tclone = NULL;
1644 dns_clientreqevent_t *event = NULL;
1645 reqctx_t *ctx = NULL;
1646 dns_tsectype_t tsectype = dns_tsectype_none;
1647 unsigned int reqoptions;
1648
1649 REQUIRE(DNS_CLIENT_VALID(client));
1650 REQUIRE(qmessage != NULL);
1651 REQUIRE(rmessage != NULL);
1652 REQUIRE(transp != NULL && *transp == NULL);
1653
1654 if (tsec != NULL) {
1655 tsectype = dns_tsec_gettype(tsec);
1656 if (tsectype != dns_tsectype_tsig) {
1657 return (ISC_R_NOTIMPLEMENTED); /* XXX */
1658 }
1659 }
1660
1661 LOCK(&client->lock);
1662 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1663 qmessage->rdclass, &view);
1664 UNLOCK(&client->lock);
1665 if (result != ISC_R_SUCCESS) {
1666 return (result);
1667 }
1668
1669 reqoptions = 0;
1670 if ((options & DNS_CLIENTREQOPT_TCP) != 0) {
1671 reqoptions |= DNS_REQUESTOPT_TCP;
1672 }
1673
1674 tclone = NULL;
1675 isc_task_attach(task, &tclone);
1676 event = (dns_clientreqevent_t *)isc_event_allocate(
1677 client->mctx, tclone, DNS_EVENT_CLIENTREQDONE, action, arg,
1678 sizeof(*event));
1679
1680 ctx = isc_mem_get(client->mctx, sizeof(*ctx));
1681 isc_mutex_init(&ctx->lock);
1682
1683 ctx->client = client;
1684 ISC_LINK_INIT(ctx, link);
1685 ctx->parseoptions = parseoptions;
1686 ctx->canceled = false;
1687 ctx->event = event;
1688 ctx->event->rmessage = rmessage;
1689 ctx->tsigkey = NULL;
1690 if (tsec != NULL) {
1691 dns_tsec_getkey(tsec, &ctx->tsigkey);
1692 }
1693
1694 ctx->magic = REQCTX_MAGIC;
1695
1696 LOCK(&client->lock);
1697 ISC_LIST_APPEND(client->reqctxs, ctx, link);
1698 isc_refcount_increment(&client->references);
1699 UNLOCK(&client->lock);
1700
1701 ctx->request = NULL;
1702 result = dns_request_createvia(view->requestmgr, qmessage, NULL, server,
1703 -1, reqoptions, ctx->tsigkey, timeout,
1704 udptimeout, udpretries, client->task,
1705 request_done, ctx, &ctx->request);
1706 if (result == ISC_R_SUCCESS) {
1707 dns_view_detach(&view);
1708 *transp = (dns_clientreqtrans_t *)ctx;
1709 return (ISC_R_SUCCESS);
1710 }
1711
1712 isc_refcount_decrement1(&client->references);
1713
1714 LOCK(&client->lock);
1715 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1716 UNLOCK(&client->lock);
1717 isc_mutex_destroy(&ctx->lock);
1718 isc_mem_put(client->mctx, ctx, sizeof(*ctx));
1719
1720 isc_event_free(ISC_EVENT_PTR(&event));
1721 isc_task_detach(&tclone);
1722 dns_view_detach(&view);
1723
1724 return (result);
1725 }
1726
1727 void
dns_client_cancelrequest(dns_clientreqtrans_t * trans)1728 dns_client_cancelrequest(dns_clientreqtrans_t *trans) {
1729 reqctx_t *ctx;
1730
1731 REQUIRE(trans != NULL);
1732 ctx = (reqctx_t *)trans;
1733 REQUIRE(REQCTX_VALID(ctx));
1734
1735 LOCK(&ctx->lock);
1736
1737 if (!ctx->canceled) {
1738 ctx->canceled = true;
1739 if (ctx->request != NULL) {
1740 dns_request_cancel(ctx->request);
1741 }
1742 }
1743
1744 UNLOCK(&ctx->lock);
1745 }
1746
1747 void
dns_client_destroyreqtrans(dns_clientreqtrans_t ** transp)1748 dns_client_destroyreqtrans(dns_clientreqtrans_t **transp) {
1749 reqctx_t *ctx;
1750 isc_mem_t *mctx;
1751 dns_client_t *client;
1752
1753 REQUIRE(transp != NULL);
1754 ctx = (reqctx_t *)*transp;
1755 *transp = NULL;
1756 REQUIRE(REQCTX_VALID(ctx));
1757 client = ctx->client;
1758 REQUIRE(DNS_CLIENT_VALID(client));
1759 REQUIRE(ctx->event == NULL);
1760 REQUIRE(ctx->request != NULL);
1761
1762 dns_request_destroy(&ctx->request);
1763 mctx = client->mctx;
1764
1765 LOCK(&client->lock);
1766
1767 INSIST(ISC_LINK_LINKED(ctx, link));
1768 ISC_LIST_UNLINK(client->reqctxs, ctx, link);
1769
1770 UNLOCK(&client->lock);
1771
1772 isc_mutex_destroy(&ctx->lock);
1773 ctx->magic = 0;
1774
1775 isc_mem_put(mctx, ctx, sizeof(*ctx));
1776
1777 dns_client_destroy(&client);
1778 }
1779
1780 /*%
1781 * Dynamic update routines
1782 */
1783 static isc_result_t
rcode2result(dns_rcode_t rcode)1784 rcode2result(dns_rcode_t rcode) {
1785 /* XXX: isn't there a similar function? */
1786 switch (rcode) {
1787 case dns_rcode_formerr:
1788 return (DNS_R_FORMERR);
1789 case dns_rcode_servfail:
1790 return (DNS_R_SERVFAIL);
1791 case dns_rcode_nxdomain:
1792 return (DNS_R_NXDOMAIN);
1793 case dns_rcode_notimp:
1794 return (DNS_R_NOTIMP);
1795 case dns_rcode_refused:
1796 return (DNS_R_REFUSED);
1797 case dns_rcode_yxdomain:
1798 return (DNS_R_YXDOMAIN);
1799 case dns_rcode_yxrrset:
1800 return (DNS_R_YXRRSET);
1801 case dns_rcode_nxrrset:
1802 return (DNS_R_NXRRSET);
1803 case dns_rcode_notauth:
1804 return (DNS_R_NOTAUTH);
1805 case dns_rcode_notzone:
1806 return (DNS_R_NOTZONE);
1807 case dns_rcode_badvers:
1808 return (DNS_R_BADVERS);
1809 }
1810
1811 return (ISC_R_FAILURE);
1812 }
1813
1814 static void
update_sendevent(updatectx_t * uctx,isc_result_t result)1815 update_sendevent(updatectx_t *uctx, isc_result_t result) {
1816 isc_task_t *task;
1817
1818 dns_message_detach(&uctx->updatemsg);
1819 if (uctx->tsigkey != NULL) {
1820 dns_tsigkey_detach(&uctx->tsigkey);
1821 }
1822 if (uctx->sig0key != NULL) {
1823 dst_key_free(&uctx->sig0key);
1824 }
1825
1826 if (uctx->canceled) {
1827 uctx->event->result = ISC_R_CANCELED;
1828 } else {
1829 uctx->event->result = result;
1830 }
1831 uctx->event->state = uctx->state;
1832 task = uctx->event->ev_sender;
1833 uctx->event->ev_sender = uctx;
1834 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&uctx->event));
1835 }
1836
1837 static void
update_done(isc_task_t * task,isc_event_t * event)1838 update_done(isc_task_t *task, isc_event_t *event) {
1839 isc_result_t result;
1840 dns_requestevent_t *reqev = NULL;
1841 dns_request_t *request;
1842 dns_message_t *answer = NULL;
1843 updatectx_t *uctx = event->ev_arg;
1844 dns_client_t *client;
1845 unsigned int timeout, reqoptions;
1846
1847 UNUSED(task);
1848
1849 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
1850 reqev = (dns_requestevent_t *)event;
1851 request = reqev->request;
1852 REQUIRE(UCTX_VALID(uctx));
1853 client = uctx->client;
1854 REQUIRE(DNS_CLIENT_VALID(client));
1855
1856 result = reqev->result;
1857 if (result != ISC_R_SUCCESS) {
1858 goto out;
1859 }
1860
1861 dns_message_create(client->mctx, DNS_MESSAGE_INTENTPARSE, &answer);
1862 uctx->state = dns_clientupdatestate_done;
1863 result = dns_request_getresponse(request, answer,
1864 DNS_MESSAGEPARSE_PRESERVEORDER);
1865 if (result == ISC_R_SUCCESS && answer->rcode != dns_rcode_noerror) {
1866 result = rcode2result(answer->rcode);
1867 }
1868
1869 out:
1870 if (answer != NULL) {
1871 dns_message_detach(&answer);
1872 }
1873 isc_event_free(&event);
1874
1875 LOCK(&uctx->lock);
1876 uctx->currentserver = ISC_LIST_NEXT(uctx->currentserver, link);
1877 dns_request_destroy(&uctx->updatereq);
1878 /*
1879 * Moving on to the next server shouldn't change the result
1880 * for NXDOMAIN, YXDOMAIN, NXRRSET and YXRRSET as they
1881 * indicate a prerequisite failure. REFUSED should also
1882 * be consistent across all servers but often isn't as that
1883 * is policy rather that zone content driven (slaves that
1884 * aren't willing to forward should return NOTIMPL). NOTZONE
1885 * indicates that we stuffed up the request construction so
1886 * don't retry.
1887 */
1888 if (result != ISC_R_SUCCESS && result != DNS_R_NXDOMAIN &&
1889 result != DNS_R_YXDOMAIN && result != DNS_R_YXRRSET &&
1890 result != DNS_R_NXRRSET && result != DNS_R_NOTZONE &&
1891 !uctx->canceled && uctx->currentserver != NULL)
1892 {
1893 dns_message_renderreset(uctx->updatemsg);
1894 dns_message_settsigkey(uctx->updatemsg, NULL);
1895
1896 timeout = client->update_timeout / uctx->nservers;
1897 if (timeout < MIN_UPDATE_TIMEOUT) {
1898 timeout = MIN_UPDATE_TIMEOUT;
1899 }
1900 reqoptions = 0;
1901 if (uctx->want_tcp) {
1902 reqoptions |= DNS_REQUESTOPT_TCP;
1903 }
1904 result = dns_request_createvia(
1905 uctx->view->requestmgr, uctx->updatemsg, NULL,
1906 uctx->currentserver, -1, reqoptions, uctx->tsigkey,
1907 timeout, client->update_udptimeout,
1908 client->update_udpretries, client->task, update_done,
1909 uctx, &uctx->updatereq);
1910 UNLOCK(&uctx->lock);
1911
1912 if (result == ISC_R_SUCCESS) {
1913 /* XXX: should we keep the 'done' state here? */
1914 uctx->state = dns_clientupdatestate_sent;
1915 return;
1916 }
1917 } else {
1918 UNLOCK(&uctx->lock);
1919 }
1920
1921 update_sendevent(uctx, result);
1922 }
1923
1924 static isc_result_t
send_update(updatectx_t * uctx)1925 send_update(updatectx_t *uctx) {
1926 isc_result_t result;
1927 dns_name_t *name = NULL;
1928 dns_rdataset_t *rdataset = NULL;
1929 dns_client_t *client = uctx->client;
1930 unsigned int timeout, reqoptions;
1931
1932 REQUIRE(uctx->zonename != NULL && uctx->currentserver != NULL);
1933
1934 result = dns_message_gettempname(uctx->updatemsg, &name);
1935 if (result != ISC_R_SUCCESS) {
1936 return (result);
1937 }
1938 dns_name_init(name, NULL);
1939 dns_name_clone(uctx->zonename, name);
1940 result = dns_message_gettemprdataset(uctx->updatemsg, &rdataset);
1941 if (result != ISC_R_SUCCESS) {
1942 dns_message_puttempname(uctx->updatemsg, &name);
1943 return (result);
1944 }
1945 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
1946 ISC_LIST_INIT(name->list);
1947 ISC_LIST_APPEND(name->list, rdataset, link);
1948 dns_message_addname(uctx->updatemsg, name, DNS_SECTION_ZONE);
1949 if (uctx->tsigkey == NULL && uctx->sig0key != NULL) {
1950 result = dns_message_setsig0key(uctx->updatemsg, uctx->sig0key);
1951 if (result != ISC_R_SUCCESS) {
1952 return (result);
1953 }
1954 }
1955 timeout = client->update_timeout / uctx->nservers;
1956 if (timeout < MIN_UPDATE_TIMEOUT) {
1957 timeout = MIN_UPDATE_TIMEOUT;
1958 }
1959 reqoptions = 0;
1960 if (uctx->want_tcp) {
1961 reqoptions |= DNS_REQUESTOPT_TCP;
1962 }
1963 result = dns_request_createvia(
1964 uctx->view->requestmgr, uctx->updatemsg, NULL,
1965 uctx->currentserver, -1, reqoptions, uctx->tsigkey, timeout,
1966 client->update_udptimeout, client->update_udpretries,
1967 client->task, update_done, uctx, &uctx->updatereq);
1968 if (result == ISC_R_SUCCESS &&
1969 uctx->state == dns_clientupdatestate_prepare) {
1970 uctx->state = dns_clientupdatestate_sent;
1971 }
1972
1973 return (result);
1974 }
1975
1976 static void
resolveaddr_done(isc_task_t * task,isc_event_t * event)1977 resolveaddr_done(isc_task_t *task, isc_event_t *event) {
1978 isc_result_t result;
1979 int family;
1980 dns_rdatatype_t qtype;
1981 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
1982 dns_name_t *name;
1983 dns_rdataset_t *rdataset;
1984 updatectx_t *uctx;
1985 bool completed = false;
1986
1987 UNUSED(task);
1988
1989 REQUIRE(event->ev_arg != NULL);
1990 uctx = *(updatectx_t **)event->ev_arg;
1991 REQUIRE(UCTX_VALID(uctx));
1992
1993 if (event->ev_arg == &uctx->bp4) {
1994 family = AF_INET;
1995 qtype = dns_rdatatype_a;
1996 LOCK(&uctx->lock);
1997 dns_client_destroyrestrans(&uctx->restrans);
1998 UNLOCK(&uctx->lock);
1999 } else {
2000 INSIST(event->ev_arg == &uctx->bp6);
2001 family = AF_INET6;
2002 qtype = dns_rdatatype_aaaa;
2003 LOCK(&uctx->lock);
2004 dns_client_destroyrestrans(&uctx->restrans2);
2005 UNLOCK(&uctx->lock);
2006 }
2007
2008 result = rev->result;
2009 if (result != ISC_R_SUCCESS) {
2010 goto done;
2011 }
2012
2013 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2014 name = ISC_LIST_NEXT(name, link))
2015 {
2016 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2017 rdataset = ISC_LIST_NEXT(rdataset, link))
2018 {
2019 if (!dns_rdataset_isassociated(rdataset)) {
2020 continue;
2021 }
2022 if (rdataset->type != qtype) {
2023 continue;
2024 }
2025
2026 for (result = dns_rdataset_first(rdataset);
2027 result == ISC_R_SUCCESS;
2028 result = dns_rdataset_next(rdataset))
2029 {
2030 dns_rdata_t rdata;
2031 dns_rdata_in_a_t rdata_a;
2032 dns_rdata_in_aaaa_t rdata_aaaa;
2033 isc_sockaddr_t *sa;
2034
2035 sa = isc_mem_get(uctx->client->mctx,
2036 sizeof(*sa));
2037
2038 dns_rdata_init(&rdata);
2039 switch (family) {
2040 case AF_INET:
2041 dns_rdataset_current(rdataset, &rdata);
2042 result = dns_rdata_tostruct(
2043 &rdata, &rdata_a, NULL);
2044 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2045 isc_sockaddr_fromin(
2046 sa, &rdata_a.in_addr, 53);
2047 dns_rdata_freestruct(&rdata_a);
2048 break;
2049 case AF_INET6:
2050 dns_rdataset_current(rdataset, &rdata);
2051 result = dns_rdata_tostruct(
2052 &rdata, &rdata_aaaa, NULL);
2053 RUNTIME_CHECK(result == ISC_R_SUCCESS);
2054 isc_sockaddr_fromin6(
2055 sa, &rdata_aaaa.in6_addr, 53);
2056 dns_rdata_freestruct(&rdata_aaaa);
2057 break;
2058 }
2059
2060 ISC_LINK_INIT(sa, link);
2061 ISC_LIST_APPEND(uctx->servers, sa, link);
2062 uctx->nservers++;
2063 }
2064 }
2065 }
2066
2067 done:
2068 dns_client_freeresanswer(uctx->client, &rev->answerlist);
2069 isc_event_free(&event);
2070
2071 LOCK(&uctx->lock);
2072 if (uctx->restrans == NULL && uctx->restrans2 == NULL) {
2073 completed = true;
2074 }
2075 UNLOCK(&uctx->lock);
2076
2077 if (completed) {
2078 INSIST(uctx->currentserver == NULL);
2079 uctx->currentserver = ISC_LIST_HEAD(uctx->servers);
2080 if (uctx->currentserver != NULL && !uctx->canceled) {
2081 send_update(uctx);
2082 } else {
2083 if (result == ISC_R_SUCCESS) {
2084 result = ISC_R_NOTFOUND;
2085 }
2086 update_sendevent(uctx, result);
2087 }
2088 }
2089 }
2090
2091 static isc_result_t
process_soa(updatectx_t * uctx,dns_rdataset_t * soaset,const dns_name_t * soaname)2092 process_soa(updatectx_t *uctx, dns_rdataset_t *soaset,
2093 const dns_name_t *soaname) {
2094 isc_result_t result;
2095 dns_rdata_t soarr = DNS_RDATA_INIT;
2096 dns_rdata_soa_t soa;
2097 dns_name_t primary;
2098 unsigned int resoptions;
2099
2100 result = dns_rdataset_first(soaset);
2101 if (result != ISC_R_SUCCESS) {
2102 return (result);
2103 }
2104 dns_rdata_init(&soarr);
2105 dns_rdataset_current(soaset, &soarr);
2106 result = dns_rdata_tostruct(&soarr, &soa, NULL);
2107 if (result != ISC_R_SUCCESS) {
2108 return (result);
2109 }
2110
2111 dns_name_init(&primary, NULL);
2112 dns_name_clone(&soa.origin, &primary);
2113
2114 if (uctx->zonename == NULL) {
2115 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2116 dns_name_copynf(soaname, uctx->zonename);
2117 }
2118
2119 if (uctx->currentserver != NULL) {
2120 result = send_update(uctx);
2121 } else {
2122 /*
2123 * Get addresses of the primary server. We don't use the ADB
2124 * feature so that we could avoid caching data.
2125 */
2126 LOCK(&uctx->lock);
2127 uctx->bp4 = uctx;
2128 resoptions = 0;
2129 if (uctx->want_tcp) {
2130 resoptions |= DNS_CLIENTRESOPT_TCP;
2131 }
2132 result = dns_client_startresolve(
2133 uctx->client, &primary, uctx->rdclass, dns_rdatatype_a,
2134 resoptions, uctx->client->task, resolveaddr_done,
2135 &uctx->bp4, &uctx->restrans);
2136 if (result == ISC_R_SUCCESS) {
2137 uctx->bp6 = uctx;
2138 result = dns_client_startresolve(
2139 uctx->client, &primary, uctx->rdclass,
2140 dns_rdatatype_aaaa, resoptions,
2141 uctx->client->task, resolveaddr_done,
2142 &uctx->bp6, &uctx->restrans2);
2143 }
2144 UNLOCK(&uctx->lock);
2145 }
2146
2147 dns_rdata_freestruct(&soa);
2148
2149 return (result);
2150 }
2151
2152 static void
receive_soa(isc_task_t * task,isc_event_t * event)2153 receive_soa(isc_task_t *task, isc_event_t *event) {
2154 dns_requestevent_t *reqev = NULL;
2155 updatectx_t *uctx;
2156 dns_client_t *client;
2157 isc_result_t result, eresult;
2158 dns_request_t *request;
2159 dns_message_t *rcvmsg = NULL;
2160 dns_section_t section;
2161 dns_rdataset_t *soaset = NULL;
2162 int pass = 0;
2163 dns_name_t *name;
2164 dns_message_t *soaquery = NULL;
2165 isc_sockaddr_t *addr;
2166 bool seencname = false;
2167 bool droplabel = false;
2168 dns_name_t tname;
2169 unsigned int nlabels, reqoptions;
2170
2171 UNUSED(task);
2172
2173 REQUIRE(event->ev_type == DNS_EVENT_REQUESTDONE);
2174 reqev = (dns_requestevent_t *)event;
2175 request = reqev->request;
2176 result = eresult = reqev->result;
2177 POST(result);
2178 uctx = reqev->ev_arg;
2179 client = uctx->client;
2180 soaquery = uctx->soaquery;
2181 addr = uctx->currentserver;
2182 INSIST(addr != NULL);
2183
2184 isc_event_free(&event);
2185
2186 if (eresult != ISC_R_SUCCESS) {
2187 result = eresult;
2188 goto out;
2189 }
2190
2191 dns_message_create(uctx->client->mctx, DNS_MESSAGE_INTENTPARSE,
2192 &rcvmsg);
2193 result = dns_request_getresponse(request, rcvmsg,
2194 DNS_MESSAGEPARSE_PRESERVEORDER);
2195
2196 if (result == DNS_R_TSIGERRORSET) {
2197 dns_request_t *newrequest = NULL;
2198
2199 /* Retry SOA request without TSIG */
2200 dns_message_detach(&rcvmsg);
2201 dns_message_renderreset(uctx->soaquery);
2202 reqoptions = 0;
2203 if (uctx->want_tcp) {
2204 reqoptions |= DNS_REQUESTOPT_TCP;
2205 }
2206 result = dns_request_createvia(
2207 uctx->view->requestmgr, uctx->soaquery, NULL, addr, -1,
2208 reqoptions, NULL, client->find_timeout * 20,
2209 client->find_timeout, 3, uctx->client->task,
2210 receive_soa, uctx, &newrequest);
2211 if (result == ISC_R_SUCCESS) {
2212 LOCK(&uctx->lock);
2213 dns_request_destroy(&uctx->soareq);
2214 uctx->soareq = newrequest;
2215 UNLOCK(&uctx->lock);
2216
2217 return;
2218 }
2219 goto out;
2220 }
2221
2222 section = DNS_SECTION_ANSWER;
2223 POST(section);
2224
2225 if (rcvmsg->rcode != dns_rcode_noerror &&
2226 rcvmsg->rcode != dns_rcode_nxdomain) {
2227 result = rcode2result(rcvmsg->rcode);
2228 goto out;
2229 }
2230
2231 lookforsoa:
2232 if (pass == 0) {
2233 section = DNS_SECTION_ANSWER;
2234 } else if (pass == 1) {
2235 section = DNS_SECTION_AUTHORITY;
2236 } else {
2237 droplabel = true;
2238 goto out;
2239 }
2240
2241 result = dns_message_firstname(rcvmsg, section);
2242 if (result != ISC_R_SUCCESS) {
2243 pass++;
2244 goto lookforsoa;
2245 }
2246 while (result == ISC_R_SUCCESS) {
2247 name = NULL;
2248 dns_message_currentname(rcvmsg, section, &name);
2249 soaset = NULL;
2250 result = dns_message_findtype(name, dns_rdatatype_soa, 0,
2251 &soaset);
2252 if (result == ISC_R_SUCCESS) {
2253 break;
2254 }
2255 if (section == DNS_SECTION_ANSWER) {
2256 dns_rdataset_t *tset = NULL;
2257 if (dns_message_findtype(name, dns_rdatatype_cname, 0,
2258 &tset) == ISC_R_SUCCESS ||
2259 dns_message_findtype(name, dns_rdatatype_dname, 0,
2260 &tset) == ISC_R_SUCCESS)
2261 {
2262 seencname = true;
2263 break;
2264 }
2265 }
2266
2267 result = dns_message_nextname(rcvmsg, section);
2268 }
2269
2270 if (soaset == NULL && !seencname) {
2271 pass++;
2272 goto lookforsoa;
2273 }
2274
2275 if (seencname) {
2276 droplabel = true;
2277 goto out;
2278 }
2279
2280 result = process_soa(uctx, soaset, name);
2281
2282 out:
2283 if (droplabel) {
2284 result = dns_message_firstname(soaquery, DNS_SECTION_QUESTION);
2285 INSIST(result == ISC_R_SUCCESS);
2286 name = NULL;
2287 dns_message_currentname(soaquery, DNS_SECTION_QUESTION, &name);
2288 nlabels = dns_name_countlabels(name);
2289 if (nlabels == 1) {
2290 result = DNS_R_SERVFAIL; /* is there a better error? */
2291 } else {
2292 dns_name_init(&tname, NULL);
2293 dns_name_getlabelsequence(name, 1, nlabels - 1, &tname);
2294 dns_name_clone(&tname, name);
2295 dns_request_destroy(&request);
2296 LOCK(&uctx->lock);
2297 uctx->soareq = NULL;
2298 UNLOCK(&uctx->lock);
2299 dns_message_renderreset(soaquery);
2300 dns_message_settsigkey(soaquery, NULL);
2301 reqoptions = 0;
2302 if (uctx->want_tcp) {
2303 reqoptions |= DNS_REQUESTOPT_TCP;
2304 }
2305 result = dns_request_createvia(
2306 uctx->view->requestmgr, soaquery, NULL,
2307 uctx->currentserver, -1, reqoptions,
2308 uctx->tsigkey, client->find_timeout * 20,
2309 client->find_timeout, 3, client->task,
2310 receive_soa, uctx, &uctx->soareq);
2311 }
2312 }
2313
2314 if (!droplabel || result != ISC_R_SUCCESS) {
2315 dns_message_detach(&uctx->soaquery);
2316 LOCK(&uctx->lock);
2317 dns_request_destroy(&uctx->soareq);
2318 UNLOCK(&uctx->lock);
2319 }
2320
2321 if (rcvmsg != NULL) {
2322 dns_message_detach(&rcvmsg);
2323 }
2324
2325 if (result != ISC_R_SUCCESS) {
2326 update_sendevent(uctx, result);
2327 }
2328 }
2329
2330 static isc_result_t
request_soa(updatectx_t * uctx)2331 request_soa(updatectx_t *uctx) {
2332 isc_result_t result;
2333 dns_message_t *soaquery = uctx->soaquery;
2334 dns_name_t *name = NULL;
2335 dns_rdataset_t *rdataset = NULL;
2336 unsigned int reqoptions;
2337
2338 if (soaquery == NULL) {
2339 dns_message_create(uctx->client->mctx, DNS_MESSAGE_INTENTRENDER,
2340 &soaquery);
2341 }
2342 soaquery->flags |= DNS_MESSAGEFLAG_RD;
2343 result = dns_message_gettempname(soaquery, &name);
2344 if (result != ISC_R_SUCCESS) {
2345 goto fail;
2346 }
2347 result = dns_message_gettemprdataset(soaquery, &rdataset);
2348 if (result != ISC_R_SUCCESS) {
2349 goto fail;
2350 }
2351 dns_rdataset_makequestion(rdataset, uctx->rdclass, dns_rdatatype_soa);
2352 dns_name_clone(uctx->firstname, name);
2353 ISC_LIST_APPEND(name->list, rdataset, link);
2354 dns_message_addname(soaquery, name, DNS_SECTION_QUESTION);
2355 rdataset = NULL;
2356 name = NULL;
2357 reqoptions = 0;
2358 if (uctx->want_tcp) {
2359 reqoptions |= DNS_REQUESTOPT_TCP;
2360 }
2361
2362 result = dns_request_createvia(
2363 uctx->view->requestmgr, soaquery, NULL, uctx->currentserver, -1,
2364 reqoptions, uctx->tsigkey, uctx->client->find_timeout * 20,
2365 uctx->client->find_timeout, 3, uctx->client->task, receive_soa,
2366 uctx, &uctx->soareq);
2367 if (result == ISC_R_SUCCESS) {
2368 uctx->soaquery = soaquery;
2369 return (ISC_R_SUCCESS);
2370 }
2371
2372 fail:
2373 if (rdataset != NULL) {
2374 ISC_LIST_UNLINK(name->list, rdataset, link); /* for safety */
2375 dns_message_puttemprdataset(soaquery, &rdataset);
2376 }
2377 if (name != NULL) {
2378 dns_message_puttempname(soaquery, &name);
2379 }
2380 dns_message_detach(&soaquery);
2381
2382 return (result);
2383 }
2384
2385 static void
resolvesoa_done(isc_task_t * task,isc_event_t * event)2386 resolvesoa_done(isc_task_t *task, isc_event_t *event) {
2387 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
2388 updatectx_t *uctx;
2389 dns_name_t *name, tname;
2390 dns_rdataset_t *rdataset = NULL;
2391 isc_result_t result = rev->result;
2392 unsigned int nlabels, resoptions;
2393
2394 UNUSED(task);
2395
2396 uctx = event->ev_arg;
2397 REQUIRE(UCTX_VALID(uctx));
2398
2399 LOCK(&uctx->lock);
2400 dns_client_destroyrestrans(&uctx->restrans);
2401 UNLOCK(&uctx->lock);
2402
2403 uctx = event->ev_arg;
2404 if (result != ISC_R_SUCCESS && result != DNS_R_NCACHENXDOMAIN &&
2405 result != DNS_R_NCACHENXRRSET)
2406 {
2407 /* XXX: what about DNSSEC failure? */
2408 goto out;
2409 }
2410
2411 for (name = ISC_LIST_HEAD(rev->answerlist); name != NULL;
2412 name = ISC_LIST_NEXT(name, link))
2413 {
2414 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2415 rdataset = ISC_LIST_NEXT(rdataset, link))
2416 {
2417 if (dns_rdataset_isassociated(rdataset) &&
2418 rdataset->type == dns_rdatatype_soa) {
2419 break;
2420 }
2421 }
2422 }
2423
2424 if (rdataset == NULL) {
2425 /* Drop one label and retry resolution. */
2426 nlabels = dns_name_countlabels(&uctx->soaqname);
2427 if (nlabels == 1) {
2428 result = DNS_R_SERVFAIL; /* is there a better error? */
2429 goto out;
2430 }
2431 dns_name_init(&tname, NULL);
2432 dns_name_getlabelsequence(&uctx->soaqname, 1, nlabels - 1,
2433 &tname);
2434 dns_name_clone(&tname, &uctx->soaqname);
2435 resoptions = 0;
2436 if (uctx->want_tcp) {
2437 resoptions |= DNS_CLIENTRESOPT_TCP;
2438 }
2439
2440 result = dns_client_startresolve(
2441 uctx->client, &uctx->soaqname, uctx->rdclass,
2442 dns_rdatatype_soa, resoptions, uctx->client->task,
2443 resolvesoa_done, uctx, &uctx->restrans);
2444 } else {
2445 result = process_soa(uctx, rdataset, &uctx->soaqname);
2446 }
2447
2448 out:
2449 dns_client_freeresanswer(uctx->client, &rev->answerlist);
2450 isc_event_free(&event);
2451
2452 if (result != ISC_R_SUCCESS) {
2453 update_sendevent(uctx, result);
2454 }
2455 }
2456
2457 static isc_result_t
copy_name(isc_mem_t * mctx,dns_message_t * msg,const dns_name_t * name,dns_name_t ** newnamep)2458 copy_name(isc_mem_t *mctx, dns_message_t *msg, const dns_name_t *name,
2459 dns_name_t **newnamep) {
2460 isc_result_t result;
2461 dns_name_t *newname = NULL;
2462 isc_region_t r;
2463 isc_buffer_t *namebuf = NULL, *rdatabuf = NULL;
2464 dns_rdatalist_t *rdatalist;
2465 dns_rdataset_t *rdataset, *newrdataset;
2466 dns_rdata_t rdata = DNS_RDATA_INIT, *newrdata;
2467
2468 result = dns_message_gettempname(msg, &newname);
2469 if (result != ISC_R_SUCCESS) {
2470 return (result);
2471 }
2472 isc_buffer_allocate(mctx, &namebuf, DNS_NAME_MAXWIRE);
2473 dns_name_init(newname, NULL);
2474 dns_name_setbuffer(newname, namebuf);
2475 dns_message_takebuffer(msg, &namebuf);
2476 dns_name_copynf(name, newname);
2477
2478 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
2479 rdataset = ISC_LIST_NEXT(rdataset, link))
2480 {
2481 rdatalist = NULL;
2482 result = dns_message_gettemprdatalist(msg, &rdatalist);
2483 if (result != ISC_R_SUCCESS) {
2484 goto fail;
2485 }
2486 dns_rdatalist_init(rdatalist);
2487 rdatalist->type = rdataset->type;
2488 rdatalist->rdclass = rdataset->rdclass;
2489 rdatalist->covers = rdataset->covers;
2490 rdatalist->ttl = rdataset->ttl;
2491
2492 result = dns_rdataset_first(rdataset);
2493 while (result == ISC_R_SUCCESS) {
2494 dns_rdata_reset(&rdata);
2495 dns_rdataset_current(rdataset, &rdata);
2496
2497 newrdata = NULL;
2498 result = dns_message_gettemprdata(msg, &newrdata);
2499 if (result != ISC_R_SUCCESS) {
2500 goto fail;
2501 }
2502 dns_rdata_toregion(&rdata, &r);
2503 rdatabuf = NULL;
2504 isc_buffer_allocate(mctx, &rdatabuf, r.length);
2505 isc_buffer_putmem(rdatabuf, r.base, r.length);
2506 isc_buffer_usedregion(rdatabuf, &r);
2507 dns_rdata_init(newrdata);
2508 dns_rdata_fromregion(newrdata, rdata.rdclass,
2509 rdata.type, &r);
2510 newrdata->flags = rdata.flags;
2511
2512 ISC_LIST_APPEND(rdatalist->rdata, newrdata, link);
2513 dns_message_takebuffer(msg, &rdatabuf);
2514
2515 result = dns_rdataset_next(rdataset);
2516 }
2517
2518 newrdataset = NULL;
2519 result = dns_message_gettemprdataset(msg, &newrdataset);
2520 if (result != ISC_R_SUCCESS) {
2521 goto fail;
2522 }
2523 dns_rdatalist_tordataset(rdatalist, newrdataset);
2524
2525 ISC_LIST_APPEND(newname->list, newrdataset, link);
2526 }
2527
2528 *newnamep = newname;
2529
2530 return (ISC_R_SUCCESS);
2531
2532 fail:
2533 dns_message_puttempname(msg, &newname);
2534
2535 return (result);
2536 }
2537
2538 static void
internal_update_callback(isc_task_t * task,isc_event_t * event)2539 internal_update_callback(isc_task_t *task, isc_event_t *event) {
2540 updatearg_t *uarg = event->ev_arg;
2541 dns_clientupdateevent_t *uev = (dns_clientupdateevent_t *)event;
2542
2543 UNUSED(task);
2544
2545 LOCK(&uarg->lock);
2546
2547 uarg->result = uev->result;
2548
2549 dns_client_destroyupdatetrans(&uarg->trans);
2550 isc_event_free(&event);
2551
2552 if (!uarg->canceled) {
2553 UNLOCK(&uarg->lock);
2554
2555 /* Exit from the internal event loop */
2556 isc_app_ctxsuspend(uarg->actx);
2557 } else {
2558 /*
2559 * We have already exited from the loop (due to some
2560 * unexpected event). Just clean the arg up.
2561 */
2562 UNLOCK(&uarg->lock);
2563 isc_mutex_destroy(&uarg->lock);
2564 isc_mem_put(uarg->client->mctx, uarg, sizeof(*uarg));
2565 }
2566 }
2567
2568 isc_result_t
dns_client_update(dns_client_t * client,dns_rdataclass_t rdclass,const dns_name_t * zonename,dns_namelist_t * prerequisites,dns_namelist_t * updates,isc_sockaddrlist_t * servers,dns_tsec_t * tsec,unsigned int options)2569 dns_client_update(dns_client_t *client, dns_rdataclass_t rdclass,
2570 const dns_name_t *zonename, dns_namelist_t *prerequisites,
2571 dns_namelist_t *updates, isc_sockaddrlist_t *servers,
2572 dns_tsec_t *tsec, unsigned int options) {
2573 isc_result_t result;
2574 isc_appctx_t *actx;
2575 updatearg_t *uarg;
2576
2577 REQUIRE(DNS_CLIENT_VALID(client));
2578
2579 if ((client->attributes & DNS_CLIENTATTR_OWNCTX) == 0 &&
2580 (options & DNS_CLIENTUPDOPT_ALLOWRUN) == 0)
2581 {
2582 /*
2583 * If the client is run under application's control, we need
2584 * to create a new running (sub)environment for this
2585 * particular update.
2586 */
2587 return (ISC_R_NOTIMPLEMENTED); /* XXXTBD */
2588 } else {
2589 actx = client->actx;
2590 }
2591
2592 uarg = isc_mem_get(client->mctx, sizeof(*uarg));
2593
2594 isc_mutex_init(&uarg->lock);
2595
2596 uarg->actx = actx;
2597 uarg->client = client;
2598 uarg->result = ISC_R_FAILURE;
2599 uarg->trans = NULL;
2600 uarg->canceled = false;
2601
2602 result = dns_client_startupdate(
2603 client, rdclass, zonename, prerequisites, updates, servers,
2604 tsec, options, client->task, internal_update_callback, uarg,
2605 &uarg->trans);
2606 if (result != ISC_R_SUCCESS) {
2607 isc_mutex_destroy(&uarg->lock);
2608 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2609 return (result);
2610 }
2611
2612 /*
2613 * Start internal event loop. It blocks until the entire process
2614 * is completed.
2615 */
2616 result = isc_app_ctxrun(actx);
2617
2618 LOCK(&uarg->lock);
2619 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) {
2620 result = uarg->result;
2621 }
2622
2623 if (uarg->trans != NULL) {
2624 /*
2625 * Unusual termination (perhaps due to signal). We need some
2626 * tricky cleanup process.
2627 */
2628 uarg->canceled = true;
2629 dns_client_cancelupdate(uarg->trans);
2630
2631 UNLOCK(&uarg->lock);
2632
2633 /* uarg will be freed in the event handler. */
2634 } else {
2635 UNLOCK(&uarg->lock);
2636
2637 isc_mutex_destroy(&uarg->lock);
2638 isc_mem_put(client->mctx, uarg, sizeof(*uarg));
2639 }
2640
2641 return (result);
2642 }
2643
2644 static void
startupdate(isc_task_t * task,isc_event_t * event)2645 startupdate(isc_task_t *task, isc_event_t *event) {
2646 updatectx_t *uctx;
2647 isc_result_t result;
2648 unsigned int resoptions;
2649
2650 REQUIRE(event != NULL);
2651
2652 UNUSED(task);
2653
2654 uctx = event->ev_arg;
2655
2656 if (uctx->zonename != NULL && uctx->currentserver != NULL) {
2657 result = send_update(uctx);
2658 if (result != ISC_R_SUCCESS) {
2659 goto fail;
2660 }
2661 } else if (uctx->currentserver != NULL) {
2662 result = request_soa(uctx);
2663 if (result != ISC_R_SUCCESS) {
2664 goto fail;
2665 }
2666 } else {
2667 resoptions = 0;
2668 if (uctx->want_tcp) {
2669 resoptions |= DNS_CLIENTRESOPT_TCP;
2670 }
2671 dns_name_clone(uctx->firstname, &uctx->soaqname);
2672 result = dns_client_startresolve(
2673 uctx->client, &uctx->soaqname, uctx->rdclass,
2674 dns_rdatatype_soa, resoptions, uctx->client->task,
2675 resolvesoa_done, uctx, &uctx->restrans);
2676 if (result != ISC_R_SUCCESS) {
2677 goto fail;
2678 }
2679 }
2680
2681 isc_event_free(&event);
2682
2683 fail:
2684 if (result != ISC_R_SUCCESS) {
2685 update_sendevent(uctx, result);
2686 }
2687 }
2688
2689 isc_result_t
dns_client_startupdate(dns_client_t * client,dns_rdataclass_t rdclass,const dns_name_t * zonename,dns_namelist_t * prerequisites,dns_namelist_t * updates,isc_sockaddrlist_t * servers,dns_tsec_t * tsec,unsigned int options,isc_task_t * task,isc_taskaction_t action,void * arg,dns_clientupdatetrans_t ** transp)2690 dns_client_startupdate(dns_client_t *client, dns_rdataclass_t rdclass,
2691 const dns_name_t *zonename,
2692 dns_namelist_t *prerequisites, dns_namelist_t *updates,
2693 isc_sockaddrlist_t *servers, dns_tsec_t *tsec,
2694 unsigned int options, isc_task_t *task,
2695 isc_taskaction_t action, void *arg,
2696 dns_clientupdatetrans_t **transp) {
2697 dns_view_t *view = NULL;
2698 isc_result_t result;
2699 dns_name_t *name, *newname;
2700 updatectx_t *uctx;
2701 isc_task_t *tclone = NULL;
2702 dns_section_t section = DNS_SECTION_UPDATE;
2703 isc_sockaddr_t *server, *sa = NULL;
2704 dns_tsectype_t tsectype = dns_tsectype_none;
2705 bool want_tcp;
2706
2707 UNUSED(options);
2708
2709 REQUIRE(DNS_CLIENT_VALID(client));
2710 REQUIRE(transp != NULL && *transp == NULL);
2711 REQUIRE(updates != NULL);
2712 REQUIRE(task != NULL);
2713
2714 if (tsec != NULL) {
2715 tsectype = dns_tsec_gettype(tsec);
2716 if (tsectype != dns_tsectype_tsig) {
2717 return (ISC_R_NOTIMPLEMENTED); /* XXX */
2718 }
2719 }
2720
2721 LOCK(&client->lock);
2722 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
2723 rdclass, &view);
2724 UNLOCK(&client->lock);
2725 if (result != ISC_R_SUCCESS) {
2726 return (result);
2727 }
2728
2729 want_tcp = ((options & DNS_CLIENTUPDOPT_TCP) != 0);
2730
2731 /*
2732 * Create a context and prepare some resources.
2733 */
2734
2735 uctx = isc_mem_get(client->mctx, sizeof(*uctx));
2736
2737 isc_mutex_init(&uctx->lock);
2738
2739 tclone = NULL;
2740 isc_task_attach(task, &tclone);
2741 uctx->client = client;
2742 ISC_LINK_INIT(uctx, link);
2743 uctx->state = dns_clientupdatestate_prepare;
2744 uctx->view = view;
2745 uctx->rdclass = rdclass;
2746 uctx->canceled = false;
2747 uctx->updatemsg = NULL;
2748 uctx->soaquery = NULL;
2749 uctx->updatereq = NULL;
2750 uctx->restrans = NULL;
2751 uctx->restrans2 = NULL;
2752 uctx->bp4 = NULL;
2753 uctx->bp6 = NULL;
2754 uctx->soareq = NULL;
2755 uctx->event = NULL;
2756 uctx->tsigkey = NULL;
2757 uctx->sig0key = NULL;
2758 uctx->zonename = NULL;
2759 uctx->want_tcp = want_tcp;
2760 dns_name_init(&uctx->soaqname, NULL);
2761 ISC_LIST_INIT(uctx->servers);
2762 uctx->nservers = 0;
2763 uctx->currentserver = NULL;
2764 dns_fixedname_init(&uctx->zonefname);
2765 if (tsec != NULL) {
2766 dns_tsec_getkey(tsec, &uctx->tsigkey);
2767 }
2768 uctx->event = (dns_clientupdateevent_t *)isc_event_allocate(
2769 client->mctx, tclone, DNS_EVENT_UPDATEDONE, action, arg,
2770 sizeof(*uctx->event));
2771 if (zonename != NULL) {
2772 uctx->zonename = dns_fixedname_name(&uctx->zonefname);
2773 dns_name_copynf(zonename, uctx->zonename);
2774 }
2775 if (servers != NULL) {
2776 for (server = ISC_LIST_HEAD(*servers); server != NULL;
2777 server = ISC_LIST_NEXT(server, link))
2778 {
2779 sa = isc_mem_get(client->mctx, sizeof(*sa));
2780 sa->type = server->type;
2781 sa->length = server->length;
2782 ISC_LINK_INIT(sa, link);
2783 ISC_LIST_APPEND(uctx->servers, sa, link);
2784 if (uctx->currentserver == NULL) {
2785 uctx->currentserver = sa;
2786 }
2787 uctx->nservers++;
2788 }
2789 }
2790
2791 /* Make update message */
2792 dns_message_create(client->mctx, DNS_MESSAGE_INTENTRENDER,
2793 &uctx->updatemsg);
2794 uctx->updatemsg->opcode = dns_opcode_update;
2795
2796 if (prerequisites != NULL) {
2797 for (name = ISC_LIST_HEAD(*prerequisites); name != NULL;
2798 name = ISC_LIST_NEXT(name, link))
2799 {
2800 newname = NULL;
2801 result = copy_name(client->mctx, uctx->updatemsg, name,
2802 &newname);
2803 if (result != ISC_R_SUCCESS) {
2804 goto fail;
2805 }
2806 dns_message_addname(uctx->updatemsg, newname,
2807 DNS_SECTION_PREREQUISITE);
2808 }
2809 }
2810
2811 for (name = ISC_LIST_HEAD(*updates); name != NULL;
2812 name = ISC_LIST_NEXT(name, link))
2813 {
2814 newname = NULL;
2815 result = copy_name(client->mctx, uctx->updatemsg, name,
2816 &newname);
2817 if (result != ISC_R_SUCCESS) {
2818 goto fail;
2819 }
2820 dns_message_addname(uctx->updatemsg, newname,
2821 DNS_SECTION_UPDATE);
2822 }
2823
2824 uctx->firstname = NULL;
2825 result = dns_message_firstname(uctx->updatemsg, section);
2826 if (result == ISC_R_NOMORE) {
2827 section = DNS_SECTION_PREREQUISITE;
2828 result = dns_message_firstname(uctx->updatemsg, section);
2829 }
2830 if (result != ISC_R_SUCCESS) {
2831 goto fail;
2832 }
2833 dns_message_currentname(uctx->updatemsg, section, &uctx->firstname);
2834
2835 uctx->magic = UCTX_MAGIC;
2836
2837 LOCK(&client->lock);
2838 ISC_LIST_APPEND(client->updatectxs, uctx, link);
2839 isc_refcount_increment(&client->references);
2840 UNLOCK(&client->lock);
2841
2842 *transp = (dns_clientupdatetrans_t *)uctx;
2843 result = isc_app_ctxonrun(client->actx, client->mctx, client->task,
2844 startupdate, uctx);
2845 if (result == ISC_R_ALREADYRUNNING) {
2846 isc_event_t *event;
2847 event = isc_event_allocate(client->mctx, dns_client_startupdate,
2848 DNS_EVENT_STARTUPDATE, startupdate,
2849 uctx, sizeof(*event));
2850 result = ISC_R_SUCCESS;
2851 isc_task_send(task, &event);
2852 }
2853 if (result == ISC_R_SUCCESS) {
2854 return (result);
2855 }
2856
2857 isc_refcount_decrement1(&client->references);
2858 *transp = NULL;
2859
2860 fail:
2861 if (ISC_LINK_LINKED(uctx, link)) {
2862 LOCK(&client->lock);
2863 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2864 UNLOCK(&client->lock);
2865 }
2866 if (uctx->updatemsg != NULL) {
2867 dns_message_detach(&uctx->updatemsg);
2868 }
2869 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2870 ISC_LIST_UNLINK(uctx->servers, sa, link);
2871 isc_mem_put(client->mctx, sa, sizeof(*sa));
2872 }
2873 if (uctx->event != NULL) {
2874 isc_event_free(ISC_EVENT_PTR(&uctx->event));
2875 }
2876 if (uctx->tsigkey != NULL) {
2877 dns_tsigkey_detach(&uctx->tsigkey);
2878 }
2879 isc_task_detach(&tclone);
2880 isc_mutex_destroy(&uctx->lock);
2881 uctx->magic = 0;
2882 isc_mem_put(client->mctx, uctx, sizeof(*uctx));
2883 dns_view_detach(&view);
2884
2885 return (result);
2886 }
2887
2888 void
dns_client_cancelupdate(dns_clientupdatetrans_t * trans)2889 dns_client_cancelupdate(dns_clientupdatetrans_t *trans) {
2890 updatectx_t *uctx;
2891
2892 REQUIRE(trans != NULL);
2893 uctx = (updatectx_t *)trans;
2894 REQUIRE(UCTX_VALID(uctx));
2895
2896 LOCK(&uctx->lock);
2897
2898 if (!uctx->canceled) {
2899 uctx->canceled = true;
2900 if (uctx->updatereq != NULL) {
2901 dns_request_cancel(uctx->updatereq);
2902 }
2903 if (uctx->soareq != NULL) {
2904 dns_request_cancel(uctx->soareq);
2905 }
2906 if (uctx->restrans != NULL) {
2907 dns_client_cancelresolve(uctx->restrans);
2908 }
2909 if (uctx->restrans2 != NULL) {
2910 dns_client_cancelresolve(uctx->restrans2);
2911 }
2912 }
2913
2914 UNLOCK(&uctx->lock);
2915 }
2916
2917 void
dns_client_destroyupdatetrans(dns_clientupdatetrans_t ** transp)2918 dns_client_destroyupdatetrans(dns_clientupdatetrans_t **transp) {
2919 updatectx_t *uctx;
2920 isc_mem_t *mctx;
2921 dns_client_t *client;
2922 isc_sockaddr_t *sa;
2923
2924 REQUIRE(transp != NULL);
2925 uctx = (updatectx_t *)*transp;
2926 *transp = NULL;
2927 REQUIRE(UCTX_VALID(uctx));
2928 client = uctx->client;
2929 REQUIRE(DNS_CLIENT_VALID(client));
2930 REQUIRE(uctx->updatereq == NULL && uctx->updatemsg == NULL &&
2931 uctx->soareq == NULL && uctx->soaquery == NULL &&
2932 uctx->event == NULL && uctx->tsigkey == NULL &&
2933 uctx->sig0key == NULL);
2934
2935 mctx = client->mctx;
2936 dns_view_detach(&uctx->view);
2937 while ((sa = ISC_LIST_HEAD(uctx->servers)) != NULL) {
2938 ISC_LIST_UNLINK(uctx->servers, sa, link);
2939 isc_mem_put(mctx, sa, sizeof(*sa));
2940 }
2941
2942 LOCK(&client->lock);
2943
2944 INSIST(ISC_LINK_LINKED(uctx, link));
2945 ISC_LIST_UNLINK(client->updatectxs, uctx, link);
2946
2947 UNLOCK(&client->lock);
2948
2949 isc_mutex_destroy(&uctx->lock);
2950 uctx->magic = 0;
2951
2952 isc_mem_put(mctx, uctx, sizeof(*uctx));
2953
2954 dns_client_destroy(&client);
2955 }
2956
2957 isc_mem_t *
dns_client_mctx(dns_client_t * client)2958 dns_client_mctx(dns_client_t *client) {
2959 REQUIRE(DNS_CLIENT_VALID(client));
2960 return (client->mctx);
2961 }
2962
2963 typedef struct {
2964 isc_buffer_t buffer;
2965 dns_rdataset_t rdataset;
2966 dns_rdatalist_t rdatalist;
2967 dns_rdata_t rdata;
2968 size_t size;
2969 isc_mem_t *mctx;
2970 unsigned char data[FLEXIBLE_ARRAY_MEMBER];
2971 } dns_client_updaterec_t;
2972
2973 isc_result_t
dns_client_updaterec(dns_client_updateop_t op,const dns_name_t * owner,dns_rdatatype_t type,dns_rdata_t * source,dns_ttl_t ttl,dns_name_t * target,dns_rdataset_t * rdataset,dns_rdatalist_t * rdatalist,dns_rdata_t * rdata,isc_mem_t * mctx)2974 dns_client_updaterec(dns_client_updateop_t op, const dns_name_t *owner,
2975 dns_rdatatype_t type, dns_rdata_t *source, dns_ttl_t ttl,
2976 dns_name_t *target, dns_rdataset_t *rdataset,
2977 dns_rdatalist_t *rdatalist, dns_rdata_t *rdata,
2978 isc_mem_t *mctx) {
2979 dns_client_updaterec_t *updaterec = NULL;
2980 size_t size = offsetof(dns_client_updaterec_t, data);
2981
2982 REQUIRE(op < updateop_max);
2983 REQUIRE(owner != NULL);
2984 REQUIRE((rdataset != NULL && rdatalist != NULL && rdata != NULL) ||
2985 (rdataset == NULL && rdatalist == NULL && rdata == NULL &&
2986 mctx != NULL));
2987 if (op == updateop_add) {
2988 REQUIRE(source != NULL);
2989 }
2990 if (source != NULL) {
2991 REQUIRE(source->type == type);
2992 REQUIRE(op == updateop_add || op == updateop_delete ||
2993 op == updateop_exist);
2994 }
2995
2996 size += owner->length;
2997 if (source != NULL) {
2998 size += source->length;
2999 }
3000
3001 if (rdataset == NULL) {
3002 updaterec = isc_mem_get(mctx, size);
3003 rdataset = &updaterec->rdataset;
3004 rdatalist = &updaterec->rdatalist;
3005 rdata = &updaterec->rdata;
3006 dns_rdataset_init(rdataset);
3007 dns_rdatalist_init(&updaterec->rdatalist);
3008 dns_rdata_init(&updaterec->rdata);
3009 isc_buffer_init(
3010 &updaterec->buffer, updaterec->data,
3011 (unsigned int)(size -
3012 offsetof(dns_client_updaterec_t, data)));
3013 dns_name_copy(owner, target, &updaterec->buffer);
3014 if (source != NULL) {
3015 isc_region_t r;
3016 dns_rdata_clone(source, rdata);
3017 dns_rdata_toregion(rdata, &r);
3018 rdata->data = isc_buffer_used(&updaterec->buffer);
3019 isc_buffer_copyregion(&updaterec->buffer, &r);
3020 }
3021 updaterec->mctx = NULL;
3022 isc_mem_attach(mctx, &updaterec->mctx);
3023 } else if (source != NULL) {
3024 dns_rdata_clone(source, rdata);
3025 }
3026
3027 switch (op) {
3028 case updateop_add:
3029 break;
3030 case updateop_delete:
3031 if (source != NULL) {
3032 ttl = 0;
3033 dns_rdata_makedelete(rdata);
3034 } else {
3035 dns_rdata_deleterrset(rdata, type);
3036 }
3037 break;
3038 case updateop_notexist:
3039 dns_rdata_notexist(rdata, type);
3040 break;
3041 case updateop_exist:
3042 if (source == NULL) {
3043 ttl = 0;
3044 dns_rdata_exists(rdata, type);
3045 }
3046 case updateop_none:
3047 break;
3048 default:
3049 INSIST(0);
3050 ISC_UNREACHABLE();
3051 }
3052
3053 rdatalist->type = rdata->type;
3054 rdatalist->rdclass = rdata->rdclass;
3055 if (source != NULL) {
3056 rdatalist->covers = dns_rdata_covers(rdata);
3057 rdatalist->ttl = ttl;
3058 }
3059 ISC_LIST_APPEND(rdatalist->rdata, rdata, link);
3060 dns_rdatalist_tordataset(rdatalist, rdataset);
3061 ISC_LIST_APPEND(target->list, rdataset, link);
3062 if (updaterec != NULL) {
3063 target->attributes |= DNS_NAMEATTR_HASUPDATEREC;
3064 dns_name_setbuffer(target, &updaterec->buffer);
3065 }
3066 if (op == updateop_add || op == updateop_delete) {
3067 target->attributes |= DNS_NAMEATTR_UPDATE;
3068 } else {
3069 target->attributes |= DNS_NAMEATTR_PREREQUISITE;
3070 }
3071 return (ISC_R_SUCCESS);
3072 }
3073
3074 void
dns_client_freeupdate(dns_name_t ** namep)3075 dns_client_freeupdate(dns_name_t **namep) {
3076 dns_client_updaterec_t *updaterec;
3077 dns_rdatalist_t *rdatalist;
3078 dns_rdataset_t *rdataset;
3079 dns_rdata_t *rdata;
3080 dns_name_t *name;
3081
3082 REQUIRE(namep != NULL && *namep != NULL);
3083
3084 name = *namep;
3085 for (rdataset = ISC_LIST_HEAD(name->list); rdataset != NULL;
3086 rdataset = ISC_LIST_HEAD(name->list))
3087 {
3088 ISC_LIST_UNLINK(name->list, rdataset, link);
3089 rdatalist = NULL;
3090 dns_rdatalist_fromrdataset(rdataset, &rdatalist);
3091 if (rdatalist == NULL) {
3092 dns_rdataset_disassociate(rdataset);
3093 continue;
3094 }
3095 for (rdata = ISC_LIST_HEAD(rdatalist->rdata); rdata != NULL;
3096 rdata = ISC_LIST_HEAD(rdatalist->rdata))
3097 {
3098 ISC_LIST_UNLINK(rdatalist->rdata, rdata, link);
3099 }
3100 dns_rdataset_disassociate(rdataset);
3101 }
3102
3103 if ((name->attributes & DNS_NAMEATTR_HASUPDATEREC) != 0) {
3104 updaterec = (dns_client_updaterec_t *)name->buffer;
3105 INSIST(updaterec != NULL);
3106 isc_mem_putanddetach(&updaterec->mctx, updaterec,
3107 updaterec->size);
3108 *namep = NULL;
3109 }
3110 }
3111