1 /*
2 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3 *
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
7 *
8 * See the COPYRIGHT file distributed with this work for additional
9 * information regarding copyright ownership.
10 */
11
12 #include <stdbool.h>
13 #include <stddef.h>
14
15 #include <isc/app.h>
16 #include <isc/buffer.h>
17 #include <isc/md.h>
18 #include <isc/mem.h>
19 #include <isc/mutex.h>
20 #include <isc/portset.h>
21 #include <isc/refcount.h>
22 #include <isc/result.h>
23 #include <isc/safe.h>
24 #include <isc/sockaddr.h>
25 #include <isc/socket.h>
26 #include <isc/task.h>
27 #include <isc/timer.h>
28 #include <isc/util.h>
29
30 #include <dns/adb.h>
31 #include <dns/client.h>
32 #include <dns/db.h>
33 #include <dns/dispatch.h>
34 #include <dns/events.h>
35 #include <dns/forward.h>
36 #include <dns/keytable.h>
37 #include <dns/message.h>
38 #include <dns/name.h>
39 #include <dns/rdata.h>
40 #include <dns/rdatalist.h>
41 #include <dns/rdataset.h>
42 #include <dns/rdatasetiter.h>
43 #include <dns/rdatastruct.h>
44 #include <dns/rdatatype.h>
45 #include <dns/request.h>
46 #include <dns/resolver.h>
47 #include <dns/tsec.h>
48 #include <dns/tsig.h>
49 #include <dns/view.h>
50
51 #include <dst/dst.h>
52
53 #define DNS_CLIENT_MAGIC ISC_MAGIC('D', 'N', 'S', 'c')
54 #define DNS_CLIENT_VALID(c) ISC_MAGIC_VALID(c, DNS_CLIENT_MAGIC)
55
56 #define RCTX_MAGIC ISC_MAGIC('R', 'c', 't', 'x')
57 #define RCTX_VALID(c) ISC_MAGIC_VALID(c, RCTX_MAGIC)
58
59 #define UCTX_MAGIC ISC_MAGIC('U', 'c', 't', 'x')
60 #define UCTX_VALID(c) ISC_MAGIC_VALID(c, UCTX_MAGIC)
61
62 #define MAX_RESTARTS 16
63
64 #ifdef TUNE_LARGE
65 #define RESOLVER_NTASKS 523
66 #else /* ifdef TUNE_LARGE */
67 #define RESOLVER_NTASKS 31
68 #endif /* TUNE_LARGE */
69
70 #define CHECK(r) \
71 do { \
72 result = (r); \
73 if (result != ISC_R_SUCCESS) \
74 goto cleanup; \
75 } while (0)
76
77 /*%
78 * DNS client object
79 */
80 struct dns_client {
81 /* Unlocked */
82 unsigned int magic;
83 unsigned int attributes;
84 isc_mutex_t lock;
85 isc_mem_t *mctx;
86 isc_appctx_t *actx;
87 isc_taskmgr_t *taskmgr;
88 isc_task_t *task;
89 isc_nm_t *nm;
90 isc_timermgr_t *timermgr;
91 dns_dispatchmgr_t *dispatchmgr;
92 dns_dispatch_t *dispatchv4;
93 dns_dispatch_t *dispatchv6;
94
95 unsigned int find_timeout;
96 unsigned int find_udpretries;
97
98 isc_refcount_t references;
99
100 /* Locked */
101 dns_viewlist_t viewlist;
102 ISC_LIST(struct resctx) resctxs;
103 };
104
105 #define DEF_FIND_TIMEOUT 5
106 #define DEF_FIND_UDPRETRIES 3
107
108 /*%
109 * Internal state for a single name resolution procedure
110 */
111 typedef struct resctx {
112 /* Unlocked */
113 unsigned int magic;
114 isc_mutex_t lock;
115 dns_client_t *client;
116 bool want_dnssec;
117 bool want_validation;
118 bool want_cdflag;
119 bool want_tcp;
120
121 /* Locked */
122 ISC_LINK(struct resctx) link;
123 isc_task_t *task;
124 dns_view_t *view;
125 unsigned int restarts;
126 dns_fixedname_t name;
127 dns_rdatatype_t type;
128 dns_fetch_t *fetch;
129 dns_namelist_t namelist;
130 isc_result_t result;
131 dns_clientresevent_t *event;
132 bool canceled;
133 dns_rdataset_t *rdataset;
134 dns_rdataset_t *sigrdataset;
135 } resctx_t;
136
137 /*%
138 * Argument of an internal event for synchronous name resolution.
139 */
140 typedef struct resarg {
141 /* Unlocked */
142 isc_appctx_t *actx;
143 dns_client_t *client;
144 isc_mutex_t lock;
145
146 /* Locked */
147 isc_result_t result;
148 isc_result_t vresult;
149 dns_namelist_t *namelist;
150 dns_clientrestrans_t *trans;
151 bool canceled;
152 } resarg_t;
153
154 static void
155 client_resfind(resctx_t *rctx, dns_fetchevent_t *event);
156 static void
157 cancelresolve(dns_clientrestrans_t *trans);
158 static void
159 destroyrestrans(dns_clientrestrans_t **transp);
160
161 /*
162 * Try honoring the operating system's preferred ephemeral port range.
163 */
164 static isc_result_t
setsourceports(isc_mem_t * mctx,dns_dispatchmgr_t * manager)165 setsourceports(isc_mem_t *mctx, dns_dispatchmgr_t *manager) {
166 isc_portset_t *v4portset = NULL, *v6portset = NULL;
167 in_port_t udpport_low, udpport_high;
168 isc_result_t result;
169
170 result = isc_portset_create(mctx, &v4portset);
171 if (result != ISC_R_SUCCESS) {
172 goto cleanup;
173 }
174 result = isc_net_getudpportrange(AF_INET, &udpport_low, &udpport_high);
175 if (result != ISC_R_SUCCESS) {
176 goto cleanup;
177 }
178 isc_portset_addrange(v4portset, udpport_low, udpport_high);
179
180 result = isc_portset_create(mctx, &v6portset);
181 if (result != ISC_R_SUCCESS) {
182 goto cleanup;
183 }
184 result = isc_net_getudpportrange(AF_INET6, &udpport_low, &udpport_high);
185 if (result != ISC_R_SUCCESS) {
186 goto cleanup;
187 }
188 isc_portset_addrange(v6portset, udpport_low, udpport_high);
189
190 result = dns_dispatchmgr_setavailports(manager, v4portset, v6portset);
191
192 cleanup:
193 if (v4portset != NULL) {
194 isc_portset_destroy(mctx, &v4portset);
195 }
196 if (v6portset != NULL) {
197 isc_portset_destroy(mctx, &v6portset);
198 }
199
200 return (result);
201 }
202
203 static isc_result_t
getudpdispatch(int family,dns_dispatchmgr_t * dispatchmgr,dns_dispatch_t ** dispp,const isc_sockaddr_t * localaddr)204 getudpdispatch(int family, dns_dispatchmgr_t *dispatchmgr,
205 dns_dispatch_t **dispp, const isc_sockaddr_t *localaddr) {
206 dns_dispatch_t *disp = NULL;
207 isc_result_t result;
208 isc_sockaddr_t anyaddr;
209
210 if (localaddr == NULL) {
211 isc_sockaddr_anyofpf(&anyaddr, family);
212 localaddr = &anyaddr;
213 }
214
215 result = dns_dispatch_createudp(dispatchmgr, localaddr, &disp);
216 if (result == ISC_R_SUCCESS) {
217 *dispp = disp;
218 }
219
220 return (result);
221 }
222
223 static isc_result_t
createview(isc_mem_t * mctx,dns_rdataclass_t rdclass,isc_taskmgr_t * taskmgr,unsigned int ntasks,isc_nm_t * nm,isc_timermgr_t * timermgr,dns_dispatchmgr_t * dispatchmgr,dns_dispatch_t * dispatchv4,dns_dispatch_t * dispatchv6,dns_view_t ** viewp)224 createview(isc_mem_t *mctx, dns_rdataclass_t rdclass, isc_taskmgr_t *taskmgr,
225 unsigned int ntasks, isc_nm_t *nm, isc_timermgr_t *timermgr,
226 dns_dispatchmgr_t *dispatchmgr, dns_dispatch_t *dispatchv4,
227 dns_dispatch_t *dispatchv6, dns_view_t **viewp) {
228 isc_result_t result;
229 dns_view_t *view = NULL;
230
231 result = dns_view_create(mctx, rdclass, DNS_CLIENTVIEW_NAME, &view);
232 if (result != ISC_R_SUCCESS) {
233 return (result);
234 }
235
236 /* Initialize view security roots */
237 result = dns_view_initsecroots(view, mctx);
238 if (result != ISC_R_SUCCESS) {
239 dns_view_detach(&view);
240 return (result);
241 }
242
243 result = dns_view_createresolver(view, taskmgr, ntasks, 1, nm, timermgr,
244 0, dispatchmgr, dispatchv4,
245 dispatchv6);
246 if (result != ISC_R_SUCCESS) {
247 dns_view_detach(&view);
248 return (result);
249 }
250
251 result = dns_db_create(mctx, "rbt", dns_rootname, dns_dbtype_cache,
252 rdclass, 0, NULL, &view->cachedb);
253 if (result != ISC_R_SUCCESS) {
254 dns_view_detach(&view);
255 return (result);
256 }
257
258 *viewp = view;
259 return (ISC_R_SUCCESS);
260 }
261
262 isc_result_t
dns_client_create(isc_mem_t * mctx,isc_appctx_t * actx,isc_taskmgr_t * taskmgr,isc_nm_t * nm,isc_timermgr_t * timermgr,unsigned int options,dns_client_t ** clientp,const isc_sockaddr_t * localaddr4,const isc_sockaddr_t * localaddr6)263 dns_client_create(isc_mem_t *mctx, isc_appctx_t *actx, isc_taskmgr_t *taskmgr,
264 isc_nm_t *nm, isc_timermgr_t *timermgr, unsigned int options,
265 dns_client_t **clientp, const isc_sockaddr_t *localaddr4,
266 const isc_sockaddr_t *localaddr6) {
267 isc_result_t result;
268 dns_client_t *client = NULL;
269 dns_dispatch_t *dispatchv4 = NULL;
270 dns_dispatch_t *dispatchv6 = NULL;
271 dns_view_t *view = NULL;
272
273 REQUIRE(mctx != NULL);
274 REQUIRE(taskmgr != NULL);
275 REQUIRE(timermgr != NULL);
276 REQUIRE(nm != NULL);
277 REQUIRE(clientp != NULL && *clientp == NULL);
278
279 UNUSED(options);
280
281 client = isc_mem_get(mctx, sizeof(*client));
282 *client = (dns_client_t){
283 .actx = actx, .taskmgr = taskmgr, .timermgr = timermgr, .nm = nm
284 };
285
286 isc_mutex_init(&client->lock);
287
288 result = isc_task_create(client->taskmgr, 0, &client->task);
289 if (result != ISC_R_SUCCESS) {
290 goto cleanup_lock;
291 }
292
293 result = dns_dispatchmgr_create(mctx, nm, &client->dispatchmgr);
294 if (result != ISC_R_SUCCESS) {
295 goto cleanup_task;
296 }
297 (void)setsourceports(mctx, client->dispatchmgr);
298
299 /*
300 * If only one address family is specified, use it.
301 * If neither family is specified, or if both are, use both.
302 */
303 client->dispatchv4 = NULL;
304 if (localaddr4 != NULL || localaddr6 == NULL) {
305 result = getudpdispatch(AF_INET, client->dispatchmgr,
306 &dispatchv4, localaddr4);
307 if (result == ISC_R_SUCCESS) {
308 client->dispatchv4 = dispatchv4;
309 }
310 }
311
312 client->dispatchv6 = NULL;
313 if (localaddr6 != NULL || localaddr4 == NULL) {
314 result = getudpdispatch(AF_INET6, client->dispatchmgr,
315 &dispatchv6, localaddr6);
316 if (result == ISC_R_SUCCESS) {
317 client->dispatchv6 = dispatchv6;
318 }
319 }
320
321 /* We need at least one of the dispatchers */
322 if (dispatchv4 == NULL && dispatchv6 == NULL) {
323 INSIST(result != ISC_R_SUCCESS);
324 goto cleanup_dispatchmgr;
325 }
326
327 isc_refcount_init(&client->references, 1);
328
329 /* Create the default view for class IN */
330 result = createview(mctx, dns_rdataclass_in, taskmgr, RESOLVER_NTASKS,
331 nm, timermgr, client->dispatchmgr, dispatchv4,
332 dispatchv6, &view);
333 if (result != ISC_R_SUCCESS) {
334 goto cleanup_references;
335 }
336
337 ISC_LIST_INIT(client->viewlist);
338 ISC_LIST_APPEND(client->viewlist, view, link);
339
340 dns_view_freeze(view); /* too early? */
341
342 ISC_LIST_INIT(client->resctxs);
343
344 isc_mem_attach(mctx, &client->mctx);
345
346 client->find_timeout = DEF_FIND_TIMEOUT;
347 client->find_udpretries = DEF_FIND_UDPRETRIES;
348
349 client->magic = DNS_CLIENT_MAGIC;
350
351 *clientp = client;
352
353 return (ISC_R_SUCCESS);
354
355 cleanup_references:
356 isc_refcount_decrementz(&client->references);
357 isc_refcount_destroy(&client->references);
358 cleanup_dispatchmgr:
359 if (dispatchv4 != NULL) {
360 dns_dispatch_detach(&dispatchv4);
361 }
362 if (dispatchv6 != NULL) {
363 dns_dispatch_detach(&dispatchv6);
364 }
365 dns_dispatchmgr_detach(&client->dispatchmgr);
366 cleanup_task:
367 isc_task_detach(&client->task);
368 cleanup_lock:
369 isc_mutex_destroy(&client->lock);
370 isc_mem_put(mctx, client, sizeof(*client));
371
372 return (result);
373 }
374
375 static void
destroyclient(dns_client_t * client)376 destroyclient(dns_client_t *client) {
377 dns_view_t *view = NULL;
378
379 isc_refcount_destroy(&client->references);
380
381 while ((view = ISC_LIST_HEAD(client->viewlist)) != NULL) {
382 ISC_LIST_UNLINK(client->viewlist, view, link);
383 dns_view_detach(&view);
384 }
385
386 if (client->dispatchv4 != NULL) {
387 dns_dispatch_detach(&client->dispatchv4);
388 }
389 if (client->dispatchv6 != NULL) {
390 dns_dispatch_detach(&client->dispatchv6);
391 }
392
393 dns_dispatchmgr_detach(&client->dispatchmgr);
394
395 isc_task_detach(&client->task);
396
397 isc_mutex_destroy(&client->lock);
398 client->magic = 0;
399
400 isc_mem_putanddetach(&client->mctx, client, sizeof(*client));
401 }
402
403 void
dns_client_detach(dns_client_t ** clientp)404 dns_client_detach(dns_client_t **clientp) {
405 dns_client_t *client = NULL;
406
407 REQUIRE(clientp != NULL);
408 REQUIRE(DNS_CLIENT_VALID(*clientp));
409
410 client = *clientp;
411 *clientp = NULL;
412
413 if (isc_refcount_decrement(&client->references) == 1) {
414 destroyclient(client);
415 }
416 }
417
418 isc_result_t
dns_client_setservers(dns_client_t * client,dns_rdataclass_t rdclass,const dns_name_t * name_space,isc_sockaddrlist_t * addrs)419 dns_client_setservers(dns_client_t *client, dns_rdataclass_t rdclass,
420 const dns_name_t *name_space, isc_sockaddrlist_t *addrs) {
421 isc_result_t result;
422 dns_view_t *view = NULL;
423
424 REQUIRE(DNS_CLIENT_VALID(client));
425 REQUIRE(addrs != NULL);
426
427 if (name_space == NULL) {
428 name_space = dns_rootname;
429 }
430
431 LOCK(&client->lock);
432 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
433 rdclass, &view);
434 if (result != ISC_R_SUCCESS) {
435 UNLOCK(&client->lock);
436 return (result);
437 }
438 UNLOCK(&client->lock);
439
440 result = dns_fwdtable_add(view->fwdtable, name_space, addrs,
441 dns_fwdpolicy_only);
442
443 dns_view_detach(&view);
444
445 return (result);
446 }
447
448 isc_result_t
dns_client_clearservers(dns_client_t * client,dns_rdataclass_t rdclass,const dns_name_t * name_space)449 dns_client_clearservers(dns_client_t *client, dns_rdataclass_t rdclass,
450 const dns_name_t *name_space) {
451 isc_result_t result;
452 dns_view_t *view = NULL;
453
454 REQUIRE(DNS_CLIENT_VALID(client));
455
456 if (name_space == NULL) {
457 name_space = dns_rootname;
458 }
459
460 LOCK(&client->lock);
461 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
462 rdclass, &view);
463 if (result != ISC_R_SUCCESS) {
464 UNLOCK(&client->lock);
465 return (result);
466 }
467 UNLOCK(&client->lock);
468
469 result = dns_fwdtable_delete(view->fwdtable, name_space);
470
471 dns_view_detach(&view);
472
473 return (result);
474 }
475
476 static isc_result_t
getrdataset(isc_mem_t * mctx,dns_rdataset_t ** rdatasetp)477 getrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
478 dns_rdataset_t *rdataset;
479
480 REQUIRE(mctx != NULL);
481 REQUIRE(rdatasetp != NULL && *rdatasetp == NULL);
482
483 rdataset = isc_mem_get(mctx, sizeof(*rdataset));
484
485 dns_rdataset_init(rdataset);
486
487 *rdatasetp = rdataset;
488
489 return (ISC_R_SUCCESS);
490 }
491
492 static void
putrdataset(isc_mem_t * mctx,dns_rdataset_t ** rdatasetp)493 putrdataset(isc_mem_t *mctx, dns_rdataset_t **rdatasetp) {
494 dns_rdataset_t *rdataset;
495
496 REQUIRE(rdatasetp != NULL);
497 rdataset = *rdatasetp;
498 *rdatasetp = NULL;
499 REQUIRE(rdataset != NULL);
500
501 if (dns_rdataset_isassociated(rdataset)) {
502 dns_rdataset_disassociate(rdataset);
503 }
504
505 isc_mem_put(mctx, rdataset, sizeof(*rdataset));
506 }
507
508 static void
fetch_done(isc_task_t * task,isc_event_t * event)509 fetch_done(isc_task_t *task, isc_event_t *event) {
510 resctx_t *rctx = event->ev_arg;
511 dns_fetchevent_t *fevent;
512
513 REQUIRE(event->ev_type == DNS_EVENT_FETCHDONE);
514 REQUIRE(RCTX_VALID(rctx));
515 REQUIRE(rctx->task == task);
516 fevent = (dns_fetchevent_t *)event;
517
518 client_resfind(rctx, fevent);
519 }
520
521 static inline isc_result_t
start_fetch(resctx_t * rctx)522 start_fetch(resctx_t *rctx) {
523 isc_result_t result;
524 int fopts = 0;
525
526 /*
527 * The caller must be holding the rctx's lock.
528 */
529
530 REQUIRE(rctx->fetch == NULL);
531
532 if (!rctx->want_cdflag) {
533 fopts |= DNS_FETCHOPT_NOCDFLAG;
534 }
535 if (!rctx->want_validation) {
536 fopts |= DNS_FETCHOPT_NOVALIDATE;
537 }
538 if (rctx->want_tcp) {
539 fopts |= DNS_FETCHOPT_TCP;
540 }
541
542 result = dns_resolver_createfetch(
543 rctx->view->resolver, dns_fixedname_name(&rctx->name),
544 rctx->type, NULL, NULL, NULL, NULL, 0, fopts, 0, NULL,
545 rctx->task, fetch_done, rctx, rctx->rdataset, rctx->sigrdataset,
546 &rctx->fetch);
547
548 return (result);
549 }
550
551 static isc_result_t
view_find(resctx_t * rctx,dns_db_t ** dbp,dns_dbnode_t ** nodep,dns_name_t * foundname)552 view_find(resctx_t *rctx, dns_db_t **dbp, dns_dbnode_t **nodep,
553 dns_name_t *foundname) {
554 isc_result_t result;
555 dns_name_t *name = dns_fixedname_name(&rctx->name);
556 dns_rdatatype_t type;
557
558 if (rctx->type == dns_rdatatype_rrsig) {
559 type = dns_rdatatype_any;
560 } else {
561 type = rctx->type;
562 }
563
564 result = dns_view_find(rctx->view, name, type, 0, 0, false, false, dbp,
565 nodep, foundname, rctx->rdataset,
566 rctx->sigrdataset);
567
568 return (result);
569 }
570
571 static void
client_resfind(resctx_t * rctx,dns_fetchevent_t * event)572 client_resfind(resctx_t *rctx, dns_fetchevent_t *event) {
573 isc_mem_t *mctx;
574 isc_result_t tresult, result = ISC_R_SUCCESS;
575 isc_result_t vresult = ISC_R_SUCCESS;
576 bool want_restart;
577 bool send_event = false;
578 dns_name_t *name = NULL, *prefix = NULL;
579 dns_fixedname_t foundname, fixed;
580 dns_rdataset_t *trdataset = NULL;
581 dns_rdata_t rdata = DNS_RDATA_INIT;
582 unsigned int nlabels;
583 int order;
584 dns_namereln_t namereln;
585 dns_rdata_cname_t cname;
586 dns_rdata_dname_t dname;
587
588 REQUIRE(RCTX_VALID(rctx));
589
590 LOCK(&rctx->lock);
591
592 mctx = rctx->view->mctx;
593
594 name = dns_fixedname_name(&rctx->name);
595
596 do {
597 dns_name_t *fname = NULL;
598 dns_name_t *ansname = NULL;
599 dns_db_t *db = NULL;
600 dns_dbnode_t *node = NULL;
601
602 rctx->restarts++;
603 want_restart = false;
604
605 if (event == NULL && !rctx->canceled) {
606 fname = dns_fixedname_initname(&foundname);
607 INSIST(!dns_rdataset_isassociated(rctx->rdataset));
608 INSIST(rctx->sigrdataset == NULL ||
609 !dns_rdataset_isassociated(rctx->sigrdataset));
610 result = view_find(rctx, &db, &node, fname);
611 if (result == ISC_R_NOTFOUND) {
612 /*
613 * We don't know anything about the name.
614 * Launch a fetch.
615 */
616 if (node != NULL) {
617 INSIST(db != NULL);
618 dns_db_detachnode(db, &node);
619 }
620 if (db != NULL) {
621 dns_db_detach(&db);
622 }
623 result = start_fetch(rctx);
624 if (result != ISC_R_SUCCESS) {
625 putrdataset(mctx, &rctx->rdataset);
626 if (rctx->sigrdataset != NULL) {
627 putrdataset(mctx,
628 &rctx->sigrdataset);
629 }
630 send_event = true;
631 }
632 goto done;
633 }
634 } else {
635 INSIST(event != NULL);
636 INSIST(event->fetch == rctx->fetch);
637 dns_resolver_destroyfetch(&rctx->fetch);
638 db = event->db;
639 node = event->node;
640 result = event->result;
641 vresult = event->vresult;
642 fname = event->foundname;
643 INSIST(event->rdataset == rctx->rdataset);
644 INSIST(event->sigrdataset == rctx->sigrdataset);
645 }
646
647 /*
648 * If we've been canceled, forget about the result.
649 */
650 if (rctx->canceled) {
651 result = ISC_R_CANCELED;
652 } else {
653 /*
654 * Otherwise, get some resource for copying the
655 * result.
656 */
657 dns_name_t *aname = dns_fixedname_name(&rctx->name);
658
659 ansname = isc_mem_get(mctx, sizeof(*ansname));
660 dns_name_init(ansname, NULL);
661
662 dns_name_dup(aname, mctx, ansname);
663 }
664
665 switch (result) {
666 case ISC_R_SUCCESS:
667 send_event = true;
668 /*
669 * This case is handled in the main line below.
670 */
671 break;
672 case DNS_R_CNAME:
673 /*
674 * Add the CNAME to the answer list.
675 */
676 trdataset = rctx->rdataset;
677 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
678 rctx->rdataset = NULL;
679 if (rctx->sigrdataset != NULL) {
680 ISC_LIST_APPEND(ansname->list,
681 rctx->sigrdataset, link);
682 rctx->sigrdataset = NULL;
683 }
684 ISC_LIST_APPEND(rctx->namelist, ansname, link);
685 ansname = NULL;
686
687 /*
688 * Copy the CNAME's target into the lookup's
689 * query name and start over.
690 */
691 tresult = dns_rdataset_first(trdataset);
692 if (tresult != ISC_R_SUCCESS) {
693 goto done;
694 }
695 dns_rdataset_current(trdataset, &rdata);
696 tresult = dns_rdata_tostruct(&rdata, &cname, NULL);
697 dns_rdata_reset(&rdata);
698 if (tresult != ISC_R_SUCCESS) {
699 goto done;
700 }
701 dns_name_copy(&cname.cname, name);
702 dns_rdata_freestruct(&cname);
703 want_restart = true;
704 goto done;
705 case DNS_R_DNAME:
706 /*
707 * Add the DNAME to the answer list.
708 */
709 trdataset = rctx->rdataset;
710 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
711 rctx->rdataset = NULL;
712 if (rctx->sigrdataset != NULL) {
713 ISC_LIST_APPEND(ansname->list,
714 rctx->sigrdataset, link);
715 rctx->sigrdataset = NULL;
716 }
717 ISC_LIST_APPEND(rctx->namelist, ansname, link);
718 ansname = NULL;
719
720 namereln = dns_name_fullcompare(name, fname, &order,
721 &nlabels);
722 INSIST(namereln == dns_namereln_subdomain);
723 /*
724 * Get the target name of the DNAME.
725 */
726 tresult = dns_rdataset_first(trdataset);
727 if (tresult != ISC_R_SUCCESS) {
728 result = tresult;
729 goto done;
730 }
731 dns_rdataset_current(trdataset, &rdata);
732 tresult = dns_rdata_tostruct(&rdata, &dname, NULL);
733 dns_rdata_reset(&rdata);
734 if (tresult != ISC_R_SUCCESS) {
735 result = tresult;
736 goto done;
737 }
738 /*
739 * Construct the new query name and start over.
740 */
741 prefix = dns_fixedname_initname(&fixed);
742 dns_name_split(name, nlabels, prefix, NULL);
743 tresult = dns_name_concatenate(prefix, &dname.dname,
744 name, NULL);
745 dns_rdata_freestruct(&dname);
746 if (tresult == ISC_R_SUCCESS) {
747 want_restart = true;
748 } else {
749 result = tresult;
750 }
751 goto done;
752 case DNS_R_NCACHENXDOMAIN:
753 case DNS_R_NCACHENXRRSET:
754 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
755 ISC_LIST_APPEND(rctx->namelist, ansname, link);
756 ansname = NULL;
757 rctx->rdataset = NULL;
758 /* What about sigrdataset? */
759 if (rctx->sigrdataset != NULL) {
760 putrdataset(mctx, &rctx->sigrdataset);
761 }
762 send_event = true;
763 goto done;
764 default:
765 if (rctx->rdataset != NULL) {
766 putrdataset(mctx, &rctx->rdataset);
767 }
768 if (rctx->sigrdataset != NULL) {
769 putrdataset(mctx, &rctx->sigrdataset);
770 }
771 send_event = true;
772 goto done;
773 }
774
775 if (rctx->type == dns_rdatatype_any) {
776 int n = 0;
777 dns_rdatasetiter_t *rdsiter = NULL;
778
779 tresult = dns_db_allrdatasets(db, node, NULL, 0,
780 &rdsiter);
781 if (tresult != ISC_R_SUCCESS) {
782 result = tresult;
783 goto done;
784 }
785
786 tresult = dns_rdatasetiter_first(rdsiter);
787 while (tresult == ISC_R_SUCCESS) {
788 dns_rdatasetiter_current(rdsiter,
789 rctx->rdataset);
790 if (rctx->rdataset->type != 0) {
791 ISC_LIST_APPEND(ansname->list,
792 rctx->rdataset, link);
793 n++;
794 rctx->rdataset = NULL;
795 } else {
796 /*
797 * We're not interested in this
798 * rdataset.
799 */
800 dns_rdataset_disassociate(
801 rctx->rdataset);
802 }
803 tresult = dns_rdatasetiter_next(rdsiter);
804
805 if (tresult == ISC_R_SUCCESS &&
806 rctx->rdataset == NULL) {
807 tresult = getrdataset(mctx,
808 &rctx->rdataset);
809 if (tresult != ISC_R_SUCCESS) {
810 result = tresult;
811 POST(result);
812 break;
813 }
814 }
815 }
816 if (rctx->rdataset != NULL) {
817 putrdataset(mctx, &rctx->rdataset);
818 }
819 if (rctx->sigrdataset != NULL) {
820 putrdataset(mctx, &rctx->sigrdataset);
821 }
822 if (n == 0) {
823 /*
824 * We didn't match any rdatasets (which means
825 * something went wrong in this
826 * implementation).
827 */
828 result = DNS_R_SERVFAIL; /* better code? */
829 POST(result);
830 } else {
831 ISC_LIST_APPEND(rctx->namelist, ansname, link);
832 ansname = NULL;
833 }
834 dns_rdatasetiter_destroy(&rdsiter);
835 if (tresult != ISC_R_NOMORE) {
836 result = DNS_R_SERVFAIL; /* ditto */
837 } else {
838 result = ISC_R_SUCCESS;
839 }
840 goto done;
841 } else {
842 /*
843 * This is the "normal" case -- an ordinary question
844 * to which we've got the answer.
845 */
846 ISC_LIST_APPEND(ansname->list, rctx->rdataset, link);
847 rctx->rdataset = NULL;
848 if (rctx->sigrdataset != NULL) {
849 ISC_LIST_APPEND(ansname->list,
850 rctx->sigrdataset, link);
851 rctx->sigrdataset = NULL;
852 }
853 ISC_LIST_APPEND(rctx->namelist, ansname, link);
854 ansname = NULL;
855 }
856
857 done:
858 /*
859 * Free temporary resources
860 */
861 if (ansname != NULL) {
862 dns_rdataset_t *rdataset;
863
864 while ((rdataset = ISC_LIST_HEAD(ansname->list)) !=
865 NULL) {
866 ISC_LIST_UNLINK(ansname->list, rdataset, link);
867 putrdataset(mctx, &rdataset);
868 }
869 dns_name_free(ansname, mctx);
870 isc_mem_put(mctx, ansname, sizeof(*ansname));
871 }
872
873 if (node != NULL) {
874 dns_db_detachnode(db, &node);
875 }
876 if (db != NULL) {
877 dns_db_detach(&db);
878 }
879 if (event != NULL) {
880 isc_event_free(ISC_EVENT_PTR(&event));
881 }
882
883 /*
884 * Limit the number of restarts.
885 */
886 if (want_restart && rctx->restarts == MAX_RESTARTS) {
887 want_restart = false;
888 result = ISC_R_QUOTA;
889 send_event = true;
890 }
891
892 /*
893 * Prepare further find with new resources
894 */
895 if (want_restart) {
896 INSIST(rctx->rdataset == NULL &&
897 rctx->sigrdataset == NULL);
898
899 result = getrdataset(mctx, &rctx->rdataset);
900 if (result == ISC_R_SUCCESS && rctx->want_dnssec) {
901 result = getrdataset(mctx, &rctx->sigrdataset);
902 if (result != ISC_R_SUCCESS) {
903 putrdataset(mctx, &rctx->rdataset);
904 }
905 }
906
907 if (result != ISC_R_SUCCESS) {
908 want_restart = false;
909 send_event = true;
910 }
911 }
912 } while (want_restart);
913
914 if (send_event) {
915 isc_task_t *task;
916
917 while ((name = ISC_LIST_HEAD(rctx->namelist)) != NULL) {
918 ISC_LIST_UNLINK(rctx->namelist, name, link);
919 ISC_LIST_APPEND(rctx->event->answerlist, name, link);
920 }
921
922 rctx->event->result = result;
923 rctx->event->vresult = vresult;
924 task = rctx->event->ev_sender;
925 rctx->event->ev_sender = rctx;
926 isc_task_sendanddetach(&task, ISC_EVENT_PTR(&rctx->event));
927 }
928
929 UNLOCK(&rctx->lock);
930 }
931
932 static void
suspend(isc_task_t * task,isc_event_t * event)933 suspend(isc_task_t *task, isc_event_t *event) {
934 isc_appctx_t *actx = event->ev_arg;
935
936 UNUSED(task);
937
938 isc_app_ctxsuspend(actx);
939 isc_event_free(&event);
940 }
941
942 static void
resolve_done(isc_task_t * task,isc_event_t * event)943 resolve_done(isc_task_t *task, isc_event_t *event) {
944 resarg_t *resarg = event->ev_arg;
945 dns_clientresevent_t *rev = (dns_clientresevent_t *)event;
946 dns_name_t *name = NULL;
947 dns_client_t *client = resarg->client;
948 isc_result_t result;
949
950 UNUSED(task);
951
952 LOCK(&resarg->lock);
953
954 resarg->result = rev->result;
955 resarg->vresult = rev->vresult;
956 while ((name = ISC_LIST_HEAD(rev->answerlist)) != NULL) {
957 ISC_LIST_UNLINK(rev->answerlist, name, link);
958 ISC_LIST_APPEND(*resarg->namelist, name, link);
959 }
960
961 destroyrestrans(&resarg->trans);
962 isc_event_free(&event);
963 resarg->client = NULL;
964
965 if (!resarg->canceled) {
966 UNLOCK(&resarg->lock);
967
968 /*
969 * We may or may not be running. isc__appctx_onrun will
970 * fail if we are currently running otherwise we post a
971 * action to call isc_app_ctxsuspend when we do start
972 * running.
973 */
974 result = isc_app_ctxonrun(resarg->actx, client->mctx, task,
975 suspend, resarg->actx);
976 if (result == ISC_R_ALREADYRUNNING) {
977 isc_app_ctxsuspend(resarg->actx);
978 }
979 } else {
980 /*
981 * We have already exited from the loop (due to some
982 * unexpected event). Just clean the arg up.
983 */
984 UNLOCK(&resarg->lock);
985 isc_mutex_destroy(&resarg->lock);
986 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
987 }
988
989 dns_client_detach(&client);
990 }
991
992 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)993 dns_client_resolve(dns_client_t *client, const dns_name_t *name,
994 dns_rdataclass_t rdclass, dns_rdatatype_t type,
995 unsigned int options, dns_namelist_t *namelist) {
996 isc_result_t result;
997 resarg_t *resarg = NULL;
998
999 REQUIRE(DNS_CLIENT_VALID(client));
1000 REQUIRE(client->actx != NULL);
1001 REQUIRE(namelist != NULL && ISC_LIST_EMPTY(*namelist));
1002
1003 resarg = isc_mem_get(client->mctx, sizeof(*resarg));
1004
1005 *resarg = (resarg_t){
1006 .actx = client->actx,
1007 .client = client,
1008 .result = DNS_R_SERVFAIL,
1009 .namelist = namelist,
1010 };
1011
1012 isc_mutex_init(&resarg->lock);
1013
1014 result = dns_client_startresolve(client, name, rdclass, type, options,
1015 client->task, resolve_done, resarg,
1016 &resarg->trans);
1017 if (result != ISC_R_SUCCESS) {
1018 isc_mutex_destroy(&resarg->lock);
1019 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1020 return (result);
1021 }
1022
1023 /*
1024 * Start internal event loop. It blocks until the entire process
1025 * is completed.
1026 */
1027 result = isc_app_ctxrun(client->actx);
1028
1029 LOCK(&resarg->lock);
1030 if (result == ISC_R_SUCCESS || result == ISC_R_SUSPEND) {
1031 result = resarg->result;
1032 }
1033 if (result != ISC_R_SUCCESS && resarg->vresult != ISC_R_SUCCESS) {
1034 /*
1035 * If this lookup failed due to some error in DNSSEC
1036 * validation, return the validation error code.
1037 * XXX: or should we pass the validation result separately?
1038 */
1039 result = resarg->vresult;
1040 }
1041 if (resarg->trans != NULL) {
1042 /*
1043 * Unusual termination (perhaps due to signal). We need some
1044 * tricky cleanup process.
1045 */
1046 resarg->canceled = true;
1047 cancelresolve(resarg->trans);
1048
1049 UNLOCK(&resarg->lock);
1050
1051 /* resarg will be freed in the event handler. */
1052 } else {
1053 UNLOCK(&resarg->lock);
1054
1055 isc_mutex_destroy(&resarg->lock);
1056 isc_mem_put(client->mctx, resarg, sizeof(*resarg));
1057 }
1058
1059 return (result);
1060 }
1061
1062 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)1063 dns_client_startresolve(dns_client_t *client, const dns_name_t *name,
1064 dns_rdataclass_t rdclass, dns_rdatatype_t type,
1065 unsigned int options, isc_task_t *task,
1066 isc_taskaction_t action, void *arg,
1067 dns_clientrestrans_t **transp) {
1068 dns_view_t *view = NULL;
1069 dns_clientresevent_t *event = NULL;
1070 resctx_t *rctx = NULL;
1071 isc_task_t *tclone = NULL;
1072 isc_mem_t *mctx;
1073 isc_result_t result;
1074 dns_rdataset_t *rdataset, *sigrdataset;
1075 bool want_dnssec, want_validation, want_cdflag, want_tcp;
1076
1077 REQUIRE(DNS_CLIENT_VALID(client));
1078 REQUIRE(transp != NULL && *transp == NULL);
1079
1080 LOCK(&client->lock);
1081 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1082 rdclass, &view);
1083 UNLOCK(&client->lock);
1084 if (result != ISC_R_SUCCESS) {
1085 return (result);
1086 }
1087
1088 mctx = client->mctx;
1089 rdataset = NULL;
1090 sigrdataset = NULL;
1091 want_dnssec = ((options & DNS_CLIENTRESOPT_NODNSSEC) == 0);
1092 want_validation = ((options & DNS_CLIENTRESOPT_NOVALIDATE) == 0);
1093 want_cdflag = ((options & DNS_CLIENTRESOPT_NOCDFLAG) == 0);
1094 want_tcp = ((options & DNS_CLIENTRESOPT_TCP) != 0);
1095
1096 /*
1097 * Prepare some intermediate resources
1098 */
1099 tclone = NULL;
1100 isc_task_attach(task, &tclone);
1101 event = (dns_clientresevent_t *)isc_event_allocate(
1102 mctx, tclone, DNS_EVENT_CLIENTRESDONE, action, arg,
1103 sizeof(*event));
1104 event->result = DNS_R_SERVFAIL;
1105 ISC_LIST_INIT(event->answerlist);
1106
1107 rctx = isc_mem_get(mctx, sizeof(*rctx));
1108 isc_mutex_init(&rctx->lock);
1109
1110 result = getrdataset(mctx, &rdataset);
1111 if (result != ISC_R_SUCCESS) {
1112 goto cleanup;
1113 }
1114 rctx->rdataset = rdataset;
1115
1116 if (want_dnssec) {
1117 result = getrdataset(mctx, &sigrdataset);
1118 if (result != ISC_R_SUCCESS) {
1119 goto cleanup;
1120 }
1121 }
1122 rctx->sigrdataset = sigrdataset;
1123
1124 dns_fixedname_init(&rctx->name);
1125 dns_name_copy(name, dns_fixedname_name(&rctx->name));
1126
1127 rctx->client = client;
1128 ISC_LINK_INIT(rctx, link);
1129 rctx->canceled = false;
1130 rctx->task = client->task;
1131 rctx->type = type;
1132 rctx->view = view;
1133 rctx->restarts = 0;
1134 rctx->fetch = NULL;
1135 rctx->want_dnssec = want_dnssec;
1136 rctx->want_validation = want_validation;
1137 rctx->want_cdflag = want_cdflag;
1138 rctx->want_tcp = want_tcp;
1139 ISC_LIST_INIT(rctx->namelist);
1140 rctx->event = event;
1141
1142 rctx->magic = RCTX_MAGIC;
1143 isc_refcount_increment(&client->references);
1144
1145 LOCK(&client->lock);
1146 ISC_LIST_APPEND(client->resctxs, rctx, link);
1147 UNLOCK(&client->lock);
1148
1149 *transp = (dns_clientrestrans_t *)rctx;
1150 client_resfind(rctx, NULL);
1151
1152 return (ISC_R_SUCCESS);
1153
1154 cleanup:
1155 if (rdataset != NULL) {
1156 putrdataset(client->mctx, &rdataset);
1157 }
1158 if (sigrdataset != NULL) {
1159 putrdataset(client->mctx, &sigrdataset);
1160 }
1161 isc_mutex_destroy(&rctx->lock);
1162 isc_mem_put(mctx, rctx, sizeof(*rctx));
1163 isc_event_free(ISC_EVENT_PTR(&event));
1164 isc_task_detach(&tclone);
1165 dns_view_detach(&view);
1166
1167 return (result);
1168 }
1169
1170 /*%<
1171 * Cancel an ongoing resolution procedure started via
1172 * dns_client_startresolve().
1173 *
1174 * If the resolution procedure has not completed, post its CLIENTRESDONE
1175 * event with a result code of #ISC_R_CANCELED.
1176 */
1177 static void
cancelresolve(dns_clientrestrans_t * trans)1178 cancelresolve(dns_clientrestrans_t *trans) {
1179 resctx_t *rctx = NULL;
1180
1181 REQUIRE(trans != NULL);
1182 rctx = (resctx_t *)trans;
1183 REQUIRE(RCTX_VALID(rctx));
1184
1185 LOCK(&rctx->lock);
1186
1187 if (!rctx->canceled) {
1188 rctx->canceled = true;
1189 if (rctx->fetch != NULL) {
1190 dns_resolver_cancelfetch(rctx->fetch);
1191 }
1192 }
1193
1194 UNLOCK(&rctx->lock);
1195 }
1196
1197 void
dns_client_freeresanswer(dns_client_t * client,dns_namelist_t * namelist)1198 dns_client_freeresanswer(dns_client_t *client, dns_namelist_t *namelist) {
1199 dns_name_t *name;
1200 dns_rdataset_t *rdataset;
1201
1202 REQUIRE(DNS_CLIENT_VALID(client));
1203 REQUIRE(namelist != NULL);
1204
1205 while ((name = ISC_LIST_HEAD(*namelist)) != NULL) {
1206 ISC_LIST_UNLINK(*namelist, name, link);
1207 while ((rdataset = ISC_LIST_HEAD(name->list)) != NULL) {
1208 ISC_LIST_UNLINK(name->list, rdataset, link);
1209 putrdataset(client->mctx, &rdataset);
1210 }
1211 dns_name_free(name, client->mctx);
1212 isc_mem_put(client->mctx, name, sizeof(*name));
1213 }
1214 }
1215
1216 /*%
1217 * Destroy name resolution transaction state identified by '*transp'.
1218 *
1219 * The caller must have received the CLIENTRESDONE event (either because the
1220 * resolution completed or because cancelresolve() was called).
1221 */
1222 static void
destroyrestrans(dns_clientrestrans_t ** transp)1223 destroyrestrans(dns_clientrestrans_t **transp) {
1224 resctx_t *rctx = NULL;
1225 isc_mem_t *mctx = NULL;
1226 dns_client_t *client = NULL;
1227
1228 REQUIRE(transp != NULL);
1229
1230 rctx = (resctx_t *)*transp;
1231 *transp = NULL;
1232
1233 REQUIRE(RCTX_VALID(rctx));
1234 REQUIRE(rctx->fetch == NULL);
1235 REQUIRE(rctx->event == NULL);
1236
1237 client = rctx->client;
1238
1239 REQUIRE(DNS_CLIENT_VALID(client));
1240
1241 mctx = client->mctx;
1242 dns_view_detach(&rctx->view);
1243
1244 /*
1245 * Wait for the lock in client_resfind to be released before
1246 * destroying the lock.
1247 */
1248 LOCK(&rctx->lock);
1249 UNLOCK(&rctx->lock);
1250
1251 LOCK(&client->lock);
1252
1253 INSIST(ISC_LINK_LINKED(rctx, link));
1254 ISC_LIST_UNLINK(client->resctxs, rctx, link);
1255
1256 UNLOCK(&client->lock);
1257
1258 INSIST(ISC_LIST_EMPTY(rctx->namelist));
1259
1260 isc_mutex_destroy(&rctx->lock);
1261 rctx->magic = 0;
1262
1263 isc_mem_put(mctx, rctx, sizeof(*rctx));
1264 }
1265
1266 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)1267 dns_client_addtrustedkey(dns_client_t *client, dns_rdataclass_t rdclass,
1268 dns_rdatatype_t rdtype, const dns_name_t *keyname,
1269 isc_buffer_t *databuf) {
1270 isc_result_t result;
1271 dns_view_t *view = NULL;
1272 dns_keytable_t *secroots = NULL;
1273 dns_name_t *name = NULL;
1274 char rdatabuf[DST_KEY_MAXSIZE];
1275 unsigned char digest[ISC_MAX_MD_SIZE];
1276 dns_rdata_ds_t ds;
1277 dns_decompress_t dctx;
1278 dns_rdata_t rdata;
1279 isc_buffer_t b;
1280
1281 REQUIRE(DNS_CLIENT_VALID(client));
1282
1283 LOCK(&client->lock);
1284 result = dns_viewlist_find(&client->viewlist, DNS_CLIENTVIEW_NAME,
1285 rdclass, &view);
1286 UNLOCK(&client->lock);
1287 CHECK(result);
1288
1289 CHECK(dns_view_getsecroots(view, &secroots));
1290
1291 DE_CONST(keyname, name);
1292
1293 if (rdtype != dns_rdatatype_dnskey && rdtype != dns_rdatatype_ds) {
1294 result = ISC_R_NOTIMPLEMENTED;
1295 goto cleanup;
1296 }
1297
1298 isc_buffer_init(&b, rdatabuf, sizeof(rdatabuf));
1299 dns_decompress_init(&dctx, -1, DNS_DECOMPRESS_NONE);
1300 dns_rdata_init(&rdata);
1301 isc_buffer_setactive(databuf, isc_buffer_usedlength(databuf));
1302 CHECK(dns_rdata_fromwire(&rdata, rdclass, rdtype, databuf, &dctx, 0,
1303 &b));
1304 dns_decompress_invalidate(&dctx);
1305
1306 if (rdtype == dns_rdatatype_ds) {
1307 CHECK(dns_rdata_tostruct(&rdata, &ds, NULL));
1308 } else {
1309 CHECK(dns_ds_fromkeyrdata(name, &rdata, DNS_DSDIGEST_SHA256,
1310 digest, &ds));
1311 }
1312
1313 CHECK(dns_keytable_add(secroots, false, false, name, &ds));
1314
1315 cleanup:
1316 if (view != NULL) {
1317 dns_view_detach(&view);
1318 }
1319 if (secroots != NULL) {
1320 dns_keytable_detach(&secroots);
1321 }
1322 return (result);
1323 }
1324