]> git.saurik.com Git - apple/libresolv.git/blob - dns.c
b121691fdfd55c185df58ea8134c368d1bb5af75
[apple/libresolv.git] / dns.c
1 /*
2 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25 #include "dns.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <time.h>
31 #include <netdb.h>
32 #include <stdarg.h>
33 #include <sys/stat.h>
34 #include <sys/dir.h>
35 #include <errno.h>
36 #include <ifaddrs.h>
37 #include <net/if.h>
38 #include <pthread.h>
39 #include <netinet/in.h>
40 #include <arpa/nameser.h>
41 #include <resolv.h>
42 #include <fcntl.h>
43 #include <notify.h>
44 #include <dnsinfo.h>
45 #include "dns_private.h"
46 #include "res_private.h"
47
48 #define INET_NTOP_AF_INET_OFFSET 4
49 #define INET_NTOP_AF_INET6_OFFSET 8
50
51 #define SEARCH_COUNT_INIT -1
52
53 #define DNS_RESOLVER_DIR "/etc/resolver"
54
55 #define NOTIFY_DIR_NAME "com.apple.system.dns.resolver.dir"
56 #define DNS_DELAY_NAME "com.apple.system.dns.delay"
57
58 #define DNS_DELAY_INTERVAL 4
59
60 #define DNS_PRIVATE_HANDLE_TYPE_SUPER 0
61 #define DNS_PRIVATE_HANDLE_TYPE_PLAIN 1
62
63 #define MDNS_MIN_TTL 2
64
65 extern uint32_t notify_monitor_file(int token, const char *name, int flags);
66
67 extern void res_client_close(res_state res);
68 extern res_state res_state_new();
69 extern int res_nquery_soa_min(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, int *fromlen, int *min);
70 extern int res_nsearch_2(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, uint32_t *fromlen);
71 extern int __res_nsearch_list_2(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, uint32_t *fromlen, int nsearch, char **search);
72
73 extern char *res_next_word(char **p);
74 extern res_state res_build_start(res_state res);
75 extern int res_build(res_state res, uint16_t port, uint32_t *nsrch, char *key, char *val);
76 extern int res_build_sortlist(res_state res, struct in_addr addr, struct in_addr mask);
77
78 static void
79 _pdns_set_name(pdns_handle_t *pdns, const char *name)
80 {
81 int n;
82
83 if (pdns == NULL) return;
84 if (name == NULL) return;
85
86 /* only set the name once */
87 if (pdns->name != NULL) return;
88
89 /* strip trailing dots */
90 n = strlen(name) - 1;
91 while ((n >= 0) && (name[n] == '.')) n--;
92
93 if (n < 0) return;
94
95 n++;
96 pdns->name = calloc(n + 1, sizeof(char));
97 if (pdns->name == NULL) return;
98 memcpy(pdns->name, name, n);
99 }
100
101 static pdns_handle_t *
102 _pdns_build_start(char *name)
103 {
104 pdns_handle_t *pdns;
105
106 pdns = (pdns_handle_t *)calloc(1, sizeof(pdns_handle_t));
107 if (pdns == NULL) return NULL;
108
109 pdns->res = res_build_start(NULL);
110 if (pdns->res == NULL)
111 {
112 free(pdns);
113 return NULL;
114 }
115
116 _pdns_set_name(pdns, name);
117 pdns->port = NS_DEFAULTPORT;
118
119 return pdns;
120 }
121
122 static int
123 _pdns_build_finish(pdns_handle_t *pdns)
124 {
125 uint32_t n;
126
127 if (pdns == NULL) return -1;
128
129 n = pdns->res->nscount;
130 if (n == 0) n = 1;
131
132 if (pdns->total_timeout == 0)
133 {
134 if (pdns->send_timeout == 0) pdns->total_timeout = RES_MAXRETRANS;
135 else pdns->total_timeout = pdns->send_timeout * pdns->res->retry * n;
136 }
137
138 if (pdns->total_timeout == 0) pdns->res->retrans = RES_MAXRETRANS;
139 else pdns->res->retrans = pdns->total_timeout;
140
141 pdns->res->options |= RES_INIT;
142
143 return 0;
144 }
145
146 static int
147 _pdns_build_sortlist(pdns_handle_t *pdns, struct in_addr addr, struct in_addr mask)
148 {
149 if (pdns == NULL) return -1;
150 return res_build_sortlist(pdns->res, addr, mask);
151 }
152
153 static void
154 _pdns_free(pdns_handle_t *pdns)
155 {
156 int i;
157
158 if (pdns == NULL) return;
159
160 if ((pdns->search_count != SEARCH_COUNT_INIT) && (pdns->search_count > 0) && (pdns->search_list != NULL))
161 {
162 for (i = 0; i < pdns->search_count; i++) free(pdns->search_list[i]);
163 free(pdns->search_list);
164 }
165
166 if (pdns->name != NULL) free(pdns->name);
167 if (pdns->res != NULL) res_client_close(pdns->res);
168
169 free(pdns);
170 }
171
172 static int
173 _pdns_build(pdns_handle_t *pdns, char *key, char *val)
174 {
175 struct in6_addr addr6;
176 int32_t status;
177 char *dupval;
178
179 if (pdns == NULL) return -1;
180
181 /*
182 * Detect IPv6 server addresses.
183 */
184 if (((pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) == 0) && (!strcmp(key, "nameserver")))
185 {
186 memset(&addr6, 0, sizeof(struct in6_addr));
187 status = inet_pton(AF_INET6, val, &addr6);
188 if (status == 1) pdns->flags |= DNS_FLAG_HAVE_IPV6_SERVER;
189 }
190
191 /*
192 * We handle some keys here.
193 * Other keys get passed on to res_build.
194 */
195 if (!strcmp(key, "default"))
196 {
197 pdns->flags |= DNS_FLAG_DEFAULT_RESOLVER;
198 return 0;
199 }
200
201 if (!strcmp(key, "port"))
202 {
203 pdns->port = atoi(val);
204 return 0;
205 }
206
207 if (!strcmp(key, "search"))
208 {
209 dupval = strdup(val);
210 if (dupval == NULL) return -1;
211
212 if (pdns->search_count == SEARCH_COUNT_INIT) pdns->search_count = 0;
213 if (pdns->search_count == 0)
214 {
215 pdns->search_list = (char **)calloc(1, sizeof(char *));
216 }
217 else
218 {
219 pdns->search_list = (char **)reallocf(pdns->search_list, (pdns->search_count + 1) * sizeof(char *));
220 }
221
222 if (pdns->search_list == NULL)
223 {
224 free(dupval);
225 _pdns_free(pdns);
226 return -1;
227 }
228
229 pdns->search_list[pdns->search_count] = dupval;
230 pdns->search_count++;
231 return 0;
232 }
233
234 if (!strcmp(key, "total_timeout"))
235 {
236 pdns->total_timeout = atoi(val);
237 return 0;
238 }
239
240 if (!strcmp(key, "timeout"))
241 {
242 pdns->send_timeout = atoi(val);
243 return 0;
244 }
245
246 if (!strcmp(key, "search_order"))
247 {
248 pdns->search_order = atoi(val);
249 return 0;
250 }
251
252 if (!strcmp(key, "pdns"))
253 {
254 pdns->flags |= DNS_FLAG_FORWARD_TO_MDNSRESPONDER;
255 return 0;
256 }
257
258 if (!strcmp(key, "mdns"))
259 {
260 pdns->flags |= DNS_FLAG_FORWARD_TO_MDNSRESPONDER;
261 return 0;
262 }
263
264 /* pass on to res_build */
265 return res_build(pdns->res, pdns->port, &(pdns->search_count), key, val);
266 }
267
268 static pdns_handle_t *
269 _pdns_convert_sc(dns_resolver_t *r)
270 {
271 pdns_handle_t *pdns;
272 char *val, *p, *x;
273 int i;
274
275 pdns = _pdns_build_start(r->domain);
276 if (r->domain == NULL) _pdns_build(pdns, "default", NULL);
277
278 p = getenv("RES_RETRY_TIMEOUT");
279 if (p != NULL) pdns->send_timeout = atoi(p);
280
281 p = getenv("RES_RETRY");
282 if (p != NULL) pdns->res->retry= atoi(p);
283
284 if (r->port != 0)
285 {
286 val = NULL;
287 asprintf(&val, "%hu", r->port);
288 if (val == NULL)
289 {
290 _pdns_free(pdns);
291 return NULL;
292 }
293
294 _pdns_build(pdns, "port", val);
295 free(val);
296 }
297
298 if (r->n_nameserver > MAXNS) r->n_nameserver = MAXNS;
299 for (i = 0; i < r->n_nameserver; i++)
300 {
301 if (r->nameserver[i]->sa_family == AF_INET)
302 {
303 val = calloc(1, 256);
304 if (val == NULL)
305 {
306 _pdns_free(pdns);
307 return NULL;
308 }
309
310 inet_ntop(AF_INET, (char *)(r->nameserver[i]) + INET_NTOP_AF_INET_OFFSET, val, 256);
311 _pdns_build(pdns, "nameserver", val);
312 free(val);
313 }
314 else if (r->nameserver[i]->sa_family == AF_INET6)
315 {
316 pdns->flags |= DNS_FLAG_HAVE_IPV6_SERVER;
317 val = calloc(1, 256);
318 if (val == NULL)
319 {
320 _pdns_free(pdns);
321 return NULL;
322 }
323
324 inet_ntop(AF_INET6, (char *)(r->nameserver[i]) + INET_NTOP_AF_INET6_OFFSET, val, 256);
325 _pdns_build(pdns, "nameserver", val);
326 free(val);
327 }
328 }
329
330 if (r->n_search > MAXDNSRCH) r->n_search = MAXDNSRCH;
331 for (i = 0; i < r->n_search; i++)
332 {
333 val = NULL;
334 asprintf(&val, "%s", r->search[i]);
335 if (val == NULL)
336 {
337 _pdns_free(pdns);
338 return NULL;
339 }
340
341 _pdns_build(pdns, "search", val);
342 free(val);
343 }
344
345 if (r->timeout > 0)
346 {
347 val = NULL;
348 asprintf(&val, "%d", r->timeout);
349 if (val == NULL)
350 {
351 _pdns_free(pdns);
352 return NULL;
353 }
354
355 _pdns_build(pdns, "total_timeout", val);
356 free(val);
357 }
358
359 val = NULL;
360 asprintf(&val, "%d", r->search_order);
361 if (val == NULL)
362 {
363 _pdns_free(pdns);
364 return NULL;
365 }
366
367 _pdns_build(pdns, "search_order", val);
368 free(val);
369
370 if (r->n_sortaddr > MAXRESOLVSORT) r->n_sortaddr = MAXRESOLVSORT;
371 for (i = 0; i < r->n_sortaddr; i++)
372 {
373 _pdns_build_sortlist(pdns, r->sortaddr[i]->address, r->sortaddr[i]->mask);
374 }
375
376 p = r->options;
377 while (NULL != (x = res_next_word(&p)))
378 {
379 /* search for and process individual options */
380 if (!strncmp(x, "ndots:", 6))
381 {
382 _pdns_build(pdns, "ndots", x+6);
383 }
384
385 else if (!strncmp(x, "nibble:", 7))
386 {
387 _pdns_build(pdns, "nibble", x+7);
388 }
389
390 else if (!strncmp(x, "nibble2:", 8))
391 {
392 _pdns_build(pdns, "nibble2", x+8);
393 }
394
395 else if (!strncmp(x, "timeout:", 8))
396 {
397 _pdns_build(pdns, "timeout", x+8);
398 }
399
400 else if (!strncmp(x, "attempts:", 9))
401 {
402 _pdns_build(pdns, "attempts", x+9);
403 }
404
405 else if (!strncmp(x, "bitstring:", 10))
406 {
407 _pdns_build(pdns, "bitstring", x+10);
408 }
409
410 else if (!strncmp(x, "v6revmode:", 10))
411 {
412 _pdns_build(pdns, "v6revmode", x+10);
413 }
414
415 else if (!strcmp(x, "debug"))
416 {
417 _pdns_build(pdns, "debug", NULL);
418 }
419
420 else if (!strcmp(x, "no_tld_query"))
421 {
422 _pdns_build(pdns, "no_tld_query", NULL);
423 }
424
425 else if (!strcmp(x, "inet6"))
426 {
427 _pdns_build(pdns, "inet6", NULL);
428 }
429
430 else if (!strcmp(x, "rotate"))
431 {
432 _pdns_build(pdns, "rotate", NULL);
433 }
434
435 else if (!strcmp(x, "no-check-names"))
436 {
437 _pdns_build(pdns, "no-check-names", NULL);
438 }
439
440 #ifdef RES_USE_EDNS0
441 else if (!strcmp(x, "edns0"))
442 {
443 _pdns_build(pdns, "edns0", NULL);
444 }
445 #endif
446 else if (!strcmp(x, "a6"))
447 {
448 _pdns_build(pdns, "a6", NULL);
449 }
450
451 else if (!strcmp(x, "dname"))
452 {
453 _pdns_build(pdns, "dname", NULL);
454 }
455
456 else if (!strcmp(x, "default"))
457 {
458 _pdns_build(pdns, "default", NULL);
459 }
460
461 else if (!strcmp(x, "pdns"))
462 {
463 _pdns_build(pdns, "pdns", NULL);
464 }
465
466 else if (!strcmp(x, "mdns"))
467 {
468 _pdns_build(pdns, "mdns", NULL);
469 }
470 }
471
472 _pdns_build_finish(pdns);
473 return pdns;
474 }
475
476 /*
477 * Open a named resolver client from the system config data.
478 */
479 static pdns_handle_t *
480 _pdns_sc_open(const char *name)
481 {
482 pdns_handle_t *pdns;
483 int i;
484 dns_config_t *sc_dns;
485 dns_resolver_t *sc_res;
486
487 sc_dns = dns_configuration_copy();
488 if (sc_dns == NULL) return NULL;
489
490 sc_res = NULL;
491
492 if (name == NULL)
493 {
494 if (sc_dns->n_resolver != 0) sc_res = sc_dns->resolver[0];
495 }
496 else
497 {
498 for (i = 0; (sc_res == NULL) && (i < sc_dns->n_resolver); i++)
499 {
500 if (sc_dns->resolver[i] == NULL) continue;
501 if (sc_dns->resolver[i]->domain == NULL) continue;
502 if (!strcasecmp(name, sc_dns->resolver[i]->domain)) sc_res = sc_dns->resolver[i];
503 }
504 }
505
506 if (sc_res == NULL)
507 {
508 dns_configuration_free(sc_dns);
509 return NULL;
510 }
511
512 pdns = (pdns_handle_t *)calloc(1, sizeof(pdns_handle_t));
513 if (pdns == NULL)
514 {
515 dns_configuration_free(sc_dns);
516 return NULL;
517 }
518
519 pdns = _pdns_convert_sc(sc_res);
520
521 dns_configuration_free(sc_dns);
522
523 if (pdns == NULL) return NULL;
524
525 if (pdns->res == NULL)
526 {
527 free(pdns);
528 return NULL;
529 }
530
531 pdns->name = NULL;
532 if (pdns->res->defdname[0] != '\0') _pdns_set_name(pdns, pdns->res->defdname);
533 else if (name != NULL) _pdns_set_name(pdns, name);
534
535 if (name != NULL) pdns->search_count = SEARCH_COUNT_INIT;
536
537 return pdns;
538 }
539
540 /*
541 * Open a named resolver client from file.
542 */
543 static pdns_handle_t *
544 _pdns_file_open(const char *name)
545 {
546 pdns_handle_t *pdns;
547 char *path, buf[1024];
548 char *p, *x, *y;
549 FILE *fp;
550
551 path = NULL;
552 if (name == NULL)
553 {
554 asprintf(&path, "%s", _PATH_RESCONF);
555 }
556 else if ((name[0] == '.') || (name[0] == '/'))
557 {
558 asprintf(&path, "%s", name);
559 }
560 else
561 {
562 asprintf(&path, "%s/%s", DNS_RESOLVER_DIR, name);
563 }
564
565 if (path == NULL) return NULL;
566
567 fp = fopen(path, "r");
568 free(path);
569 if (fp == NULL) return NULL;
570
571 pdns = _pdns_build_start(NULL);
572 if (pdns == NULL)
573 {
574 fclose(fp);
575 return NULL;
576 }
577
578 p = getenv("RES_RETRY_TIMEOUT");
579 if (p != NULL) pdns->send_timeout = atoi(p);
580
581 p = getenv("RES_RETRY");
582 if (p != NULL) pdns->res->retry= atoi(p);
583
584 while (fgets(buf, sizeof(buf), fp) != NULL)
585 {
586 /* skip comments */
587 if ((buf[0] == ';') || (buf[0] == '#')) continue;
588 p = buf;
589 x = res_next_word(&p);
590 if (x == NULL) continue;
591 if (!strcmp(x, "sortlist"))
592 {
593 while (NULL != (x = res_next_word(&p)))
594 {
595 _pdns_build(pdns, "sortlist", x);
596 }
597 }
598 else if (!strcmp(x, "timeout"))
599 {
600 x = res_next_word(&p);
601 if (x != NULL) _pdns_build(pdns, "total_timeout", x);
602 }
603 else if (!strcmp(x, "options"))
604 {
605 while (NULL != (x = res_next_word(&p)))
606 {
607 y = strchr(x, ':');
608 if (y != NULL)
609 {
610 *y = '\0';
611 y++;
612 }
613 _pdns_build(pdns, x, y);
614 }
615 }
616 else
617 {
618 y = res_next_word(&p);
619 _pdns_build(pdns, x, y);
620
621 if ((!strcmp(x, "domain")) && (pdns->name == NULL)) _pdns_set_name(pdns, y);
622 }
623 }
624
625 fclose(fp);
626
627 if (pdns->name == NULL) _pdns_set_name(pdns, name);
628
629 _pdns_build_finish(pdns);
630
631 return pdns;
632 }
633
634 /*
635 * If there was no search list, use domain name and parent domain components.
636 *
637 * N.B. This code deals with multiple trailing dots, but does not deal with
638 * multiple internal dots, e.g. "foo.....com".
639 */
640 static void
641 _pdns_check_search_list(pdns_handle_t *pdns)
642 {
643 int n;
644 char *p;
645
646 if (pdns == NULL) return;
647 if (pdns->name == NULL) return;
648 if (pdns->search_count > 0) return;
649
650 /* Count dots */
651 n = 0;
652 for (p = pdns->name; *p != '\0'; p++)
653 {
654 if (*p == '.') n++;
655 }
656
657 /* Back up over any trailing dots and cut them out of the name */
658 for (p--; (p >= pdns->name) && (*p == '.'); p--)
659 {
660 *p = '\0';
661 n--;
662 }
663
664 /* This will be true if name was all dots */
665 if (p < pdns->name) return;
666
667 /* dots are separators, so number of components is one larger */
668 n++;
669
670 _pdns_build(pdns, "search", pdns->name);
671
672 /* Include parent domains with at least LOCALDOMAINPARTS components */
673 p = pdns->name;
674 while (n > LOCALDOMAINPARTS)
675 {
676 /* Find next component */
677 while ((*p != '.') && (*p != '\0')) p++;
678 if (*p == '\0') break;
679 p++;
680
681 n--;
682 _pdns_build(pdns, "search", p);
683 }
684 }
685
686 __private_extern__ void
687 _check_cache(sdns_handle_t *sdns)
688 {
689 int i, n, status, refresh, sc_dns_count;
690 DIR *dp;
691 struct direct *d;
692 pdns_handle_t *c;
693 dns_config_t *sc_dns;
694
695 if (sdns == NULL) return;
696
697 refresh = 0;
698
699 if (sdns->stattime == 0) refresh = 1;
700
701 if (refresh == 0)
702 {
703 if (sdns->notify_sys_config_token == -1) refresh = 1;
704 else
705 {
706 n = 1;
707 status = notify_check(sdns->notify_sys_config_token, &n);
708 if ((status != NOTIFY_STATUS_OK) || (n == 1)) refresh = 1;
709 }
710 }
711
712 if (refresh == 0)
713 {
714 if (sdns->notify_dir_token == -1) refresh = 1;
715 else
716 {
717 n = 1;
718 status = notify_check(sdns->notify_dir_token, &n);
719 if ((status != NOTIFY_STATUS_OK) || (n == 1)) refresh = 1;
720 }
721 }
722
723 if (refresh == 0) return;
724
725 /* Free old clients */
726 sdns->pdns_primary = NULL;
727
728 for (i = 0; i < sdns->client_count; i++)
729 {
730 _pdns_free(sdns->client[i]);
731 }
732
733 sdns->client_count = 0;
734 if (sdns->client != NULL) free(sdns->client);
735 sdns->client = NULL;
736
737 /* Fetch clients from System Configuration */
738 sc_dns = dns_configuration_copy();
739
740 /* Set up Primary resolver. It's the one we consult for a search list */
741 sc_dns_count = 0;
742 if ((sc_dns != NULL) && (sc_dns->n_resolver > 0))
743 {
744 sc_dns_count = sc_dns->n_resolver;
745 sdns->pdns_primary = _pdns_convert_sc(sc_dns->resolver[0]);
746 _pdns_check_search_list(sdns->pdns_primary);
747 }
748 else
749 {
750 sdns->pdns_primary = _pdns_file_open(_PATH_RESCONF);
751 }
752
753 if (sdns->pdns_primary != NULL)
754 {
755 if ((sdns->flags & DNS_FLAG_DEBUG) && (sdns->pdns_primary->res != NULL)) sdns->pdns_primary->res->options |= RES_DEBUG;
756 if (sdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) sdns->pdns_primary->flags |= DNS_FLAG_OK_TO_SKIP_AAAA;
757 sdns->pdns_primary->flags |= DNS_FLAG_DEFAULT_RESOLVER;
758
759 sdns->client = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *));
760 if (sdns->client == NULL)
761 {
762 if (sc_dns != NULL) dns_configuration_free(sc_dns);
763 return;
764 }
765
766 sdns->client[sdns->client_count] = sdns->pdns_primary;
767 sdns->client_count++;
768 }
769
770 /* Convert System Configuration resolvers */
771 for (i = 1; i < sc_dns_count; i++)
772 {
773 c = _pdns_convert_sc(sc_dns->resolver[i]);
774 if (c == NULL) continue;
775
776 if (sdns->flags & DNS_FLAG_DEBUG) c->res->options |= RES_DEBUG;
777 if (sdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) c->flags |= DNS_FLAG_OK_TO_SKIP_AAAA;
778
779 if (sdns->client_count == 0)
780 {
781 sdns->client = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *));
782 }
783 else
784 {
785 sdns->client = (pdns_handle_t **)reallocf(sdns->client, (sdns->client_count + 1) * sizeof(pdns_handle_t *));
786 }
787
788 if (sdns->client == NULL)
789 {
790 sdns->client_count = 0;
791 dns_configuration_free(sc_dns);
792 return;
793 }
794
795 sdns->client[sdns->client_count] = c;
796 sdns->client_count++;
797 }
798
799 if (sc_dns != NULL) dns_configuration_free(sc_dns);
800
801 if (sdns->flags & DNS_FLAG_CHECK_RESOLVER_DIR)
802 {
803 /* Read /etc/resolvers clients */
804 dp = opendir(DNS_RESOLVER_DIR);
805 if (dp == NULL)
806 {
807 sdns->flags &= ~DNS_FLAG_CHECK_RESOLVER_DIR;
808 }
809 else
810 {
811 while (NULL != (d = readdir(dp)))
812 {
813 if (d->d_name[0] == '.') continue;
814
815 c = _pdns_file_open(d->d_name);
816 if (c == NULL) continue;
817 if (sdns->flags & DNS_FLAG_DEBUG) c->res->options |= RES_DEBUG;
818 if (sdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) c->flags |= DNS_FLAG_OK_TO_SKIP_AAAA;
819
820 if (sdns->client_count == 0)
821 {
822 sdns->client = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *));
823 }
824 else
825 {
826 sdns->client = (pdns_handle_t **)reallocf(sdns->client, (sdns->client_count + 1) * sizeof(pdns_handle_t *));
827 }
828
829 if (sdns->client == NULL)
830 {
831 sdns->client_count = 0;
832 return;
833 }
834
835 sdns->client[sdns->client_count] = c;
836 sdns->client_count++;
837 }
838 closedir(dp);
839 }
840 }
841
842 sdns->stattime = 1;
843 }
844
845 static uint32_t
846 _pdns_get_default_handles(sdns_handle_t *sdns, pdns_handle_t ***pdns)
847 {
848 int i, j, k, count;
849
850 if (sdns == NULL) return 0;
851 if (pdns == NULL) return 0;
852
853 count = 0;
854
855 for (i = 0; i < sdns->client_count; i++)
856 {
857 if (sdns->client[i]->flags & DNS_FLAG_DEFAULT_RESOLVER)
858 {
859 if (count == 0)
860 {
861 *pdns = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *));
862 }
863 else
864 {
865 *pdns = (pdns_handle_t **)reallocf((*pdns), (count + 1) * sizeof(pdns_handle_t *));
866 }
867
868 if (*pdns == NULL) return 0;
869
870 /* Insert sorted by search_order */
871 for (j = 0; j < count; j++)
872 {
873 if (sdns->client[i]->search_order < (*pdns)[j]->search_order) break;
874 }
875
876 for (k = count; k > j; k--) (*pdns)[k] = (*pdns)[k-1];
877 (*pdns)[j] = sdns->client[i];
878 count++;
879 }
880 }
881
882 return count;
883 }
884
885 static uint32_t
886 _pdns_get_handles_for_name(sdns_handle_t *sdns, const char *name, pdns_handle_t ***pdns)
887 {
888 char *p, *vname;
889 int i, j, k, count;
890
891 if (sdns == NULL) return 0;
892 if (pdns == NULL) return 0;
893
894 if (name == NULL) return _pdns_get_default_handles(sdns, pdns);
895 else if (name[0] == '\0') return _pdns_get_default_handles(sdns, pdns);
896
897 count = 0;
898
899 vname = strdup(name);
900 i = strlen(vname) - 1;
901 if ((i >= 0) && (vname[i] == '.')) vname[i] = '\0';
902
903 p = vname;
904 while (p != NULL)
905 {
906 for (i = 0; i < sdns->client_count; i++)
907 {
908 if (sdns->client[i]->name == NULL) continue;
909
910 if (!strcasecmp(sdns->client[i]->name, p))
911 {
912 if (count == 0)
913 {
914 *pdns = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *));
915 }
916 else
917 {
918 *pdns = (pdns_handle_t **)reallocf((*pdns), (count + 1) * sizeof(pdns_handle_t *));
919 }
920
921 if (*pdns == NULL) return 0;
922
923 /* Insert sorted by search_order */
924 for (j = 0; j < count; j++)
925 {
926 if (sdns->client[i]->search_order < (*pdns)[j]->search_order) break;
927 }
928
929 for (k = count; k > j; k--) (*pdns)[k] = (*pdns)[k-1];
930 (*pdns)[j] = sdns->client[i];
931 count++;
932 }
933 }
934
935 p = strchr(p, '.');
936 if (p != NULL) p++;
937 }
938
939 free(vname);
940
941 if (count != 0) return count;
942
943 return _pdns_get_default_handles(sdns, pdns);;
944 }
945
946 static void
947 _pdns_process_res_search_list(pdns_handle_t *pdns)
948 {
949 if (pdns->search_count != SEARCH_COUNT_INIT) return;
950 for (pdns->search_count = 0; (pdns->res->dnsrch[pdns->search_count] != NULL) && (pdns->res->dnsrch[pdns->search_count][0] != '\0'); pdns->search_count++);
951 }
952
953 static char *
954 _pdns_search_list_domain(pdns_handle_t *pdns, uint32_t i)
955 {
956 char *s;
957
958 if (pdns == NULL) return NULL;
959 if (pdns->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(pdns);
960 if (i >= pdns->search_count) return NULL;
961
962 s = pdns->search_list[i];
963 if (s == NULL) return NULL;
964 return strdup(s);
965 }
966
967 static void
968 _dns_open_notify(sdns_handle_t *sdns)
969 {
970 int status, n;
971
972 if (sdns == NULL) return;
973
974 if (sdns->notify_delay_token == -1)
975 {
976 status = notify_register_check(DNS_DELAY_NAME, &(sdns->notify_delay_token));
977 if (status != NOTIFY_STATUS_OK) sdns->notify_delay_token = -1;
978 else status = notify_check(sdns->notify_delay_token, &n);
979 }
980
981 if (sdns->notify_sys_config_token == -1)
982 {
983 status = notify_register_check(dns_configuration_notify_key(), &(sdns->notify_sys_config_token));
984 if (status != NOTIFY_STATUS_OK) sdns->notify_sys_config_token = -1;
985 }
986
987 if (sdns->notify_dir_token == -1)
988 {
989 status = notify_register_check(NOTIFY_DIR_NAME, &(sdns->notify_dir_token));
990 if (status == NOTIFY_STATUS_OK)
991 {
992 status = notify_monitor_file(sdns->notify_dir_token, "/private/etc/resolver", 0);
993 if (status != NOTIFY_STATUS_OK)
994 {
995 notify_cancel(sdns->notify_dir_token);
996 sdns->notify_dir_token = -1;
997 }
998 }
999 else
1000 {
1001 sdns->notify_dir_token = -1;
1002 }
1003 }
1004 }
1005
1006 static void
1007 _dns_close_notify(sdns_handle_t *sdns)
1008 {
1009 if (sdns == NULL) return;
1010
1011 if (sdns->notify_delay_token != -1) notify_cancel(sdns->notify_delay_token);
1012 sdns->notify_delay_token = -1;
1013
1014 if (sdns->notify_sys_config_token != -1) notify_cancel(sdns->notify_sys_config_token);
1015 sdns->notify_sys_config_token = -1;
1016
1017 if (sdns->notify_dir_token != -1) notify_cancel(sdns->notify_dir_token);
1018 sdns->notify_dir_token = -1;
1019 }
1020
1021 dns_handle_t
1022 dns_open(const char *name)
1023 {
1024 dns_private_handle_t *dns;
1025
1026 dns = (dns_private_handle_t *)calloc(1, sizeof(dns_private_handle_t));
1027 if (dns == NULL) return NULL;
1028
1029 if (name == NULL)
1030 {
1031 dns->handle_type = DNS_PRIVATE_HANDLE_TYPE_SUPER;
1032 dns->sdns = (sdns_handle_t *)calloc(1, sizeof(sdns_handle_t));
1033 if (dns->sdns == NULL)
1034 {
1035 free(dns);
1036 return NULL;
1037 }
1038
1039 dns->sdns->flags |= DNS_FLAG_CHECK_RESOLVER_DIR;
1040 dns->sdns->notify_sys_config_token = -1;
1041 dns->sdns->notify_dir_token = -1;
1042 dns->sdns->notify_delay_token = -1;
1043 _dns_open_notify(dns->sdns);
1044
1045 return (dns_handle_t)dns;
1046 }
1047
1048 dns->handle_type = DNS_PRIVATE_HANDLE_TYPE_PLAIN;
1049
1050 /* Look for name in System Configuration first */
1051 dns->pdns = _pdns_sc_open(name);
1052 if (dns->pdns == NULL) dns->pdns = _pdns_file_open(name);
1053
1054 if (dns->pdns == NULL)
1055 {
1056 free(dns);
1057 return NULL;
1058 }
1059
1060 return (dns_handle_t)dns;
1061 }
1062
1063 /*
1064 * Release a DNS client handle
1065 */
1066 void
1067 dns_free(dns_handle_t d)
1068 {
1069 dns_private_handle_t *dns;
1070 int i;
1071
1072 if (d == NULL) return;
1073
1074 dns = (dns_private_handle_t *)d;
1075
1076 if (dns->recvbuf != NULL) free(dns->recvbuf);
1077
1078 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
1079 {
1080 if (dns->sdns == NULL) return;
1081
1082 _dns_close_notify(dns->sdns);
1083
1084 for (i = 0; i < dns->sdns->client_count; i++)
1085 {
1086 _pdns_free(dns->sdns->client[i]);
1087 }
1088
1089 dns->sdns->client_count = 0;
1090 if (dns->sdns->client != NULL) free(dns->sdns->client);
1091
1092 free(dns->sdns);
1093 }
1094 else
1095 {
1096 _pdns_free(dns->pdns);
1097 }
1098
1099 free(dns);
1100 }
1101
1102 static void
1103 _pdns_debug(pdns_handle_t *pdns, uint32_t flag)
1104 {
1105 if (pdns == NULL) return;
1106
1107 if (flag == 0)
1108 {
1109 pdns->res->options &= ~RES_DEBUG;
1110 }
1111 else
1112 {
1113 pdns->res->options |= RES_DEBUG;
1114 }
1115 }
1116
1117 static void
1118 _sdns_debug(sdns_handle_t *sdns, uint32_t flag)
1119 {
1120 int i;
1121
1122 if (sdns == NULL) return;
1123
1124 if (flag == 0)
1125 {
1126 sdns->flags &= ~ DNS_FLAG_DEBUG;
1127
1128 for (i = 0; i < sdns->client_count; i++)
1129 {
1130 sdns->client[i]->res->options &= ~RES_DEBUG;
1131 }
1132 }
1133 else
1134 {
1135 sdns->flags |= DNS_FLAG_DEBUG;
1136
1137 for (i = 0; i < sdns->client_count; i++)
1138 {
1139 sdns->client[i]->res->options |= RES_DEBUG;
1140 }
1141 }
1142 }
1143
1144 /*
1145 * Enable / Disable debugging
1146 */
1147 void
1148 dns_set_debug(dns_handle_t d, uint32_t flag)
1149 {
1150 dns_private_handle_t *dns;
1151
1152 if (d == NULL) return;
1153
1154 dns = (dns_private_handle_t *)d;
1155
1156 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
1157 {
1158 _sdns_debug(dns->sdns, flag);
1159 }
1160 else
1161 {
1162 _pdns_debug(dns->pdns, flag);
1163 }
1164 }
1165
1166 /*
1167 * Returns the number of names in the search list
1168 */
1169 uint32_t
1170 dns_search_list_count(dns_handle_t d)
1171 {
1172 dns_private_handle_t *dns;
1173 pdns_handle_t *pdns;
1174
1175 if (d == NULL) return 0;
1176
1177 dns = (dns_private_handle_t *)d;
1178
1179 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
1180 {
1181 _check_cache(dns->sdns);
1182 pdns = dns->sdns->pdns_primary;
1183 }
1184 else
1185 {
1186 pdns = dns->pdns;
1187 }
1188
1189 if (pdns->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(pdns);
1190 return pdns->search_count;
1191 }
1192
1193 /*
1194 * Returns the domain name at index i in the search list.
1195 * Returns NULL if there are no names in the search list.
1196 * Caller must free the returned name.
1197 */
1198 char *
1199 dns_search_list_domain(dns_handle_t d, uint32_t i)
1200 {
1201 dns_private_handle_t *dns;
1202 pdns_handle_t *pdns;
1203
1204 if (d == NULL) return NULL;
1205
1206 dns = (dns_private_handle_t *)d;
1207
1208 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
1209 {
1210 _check_cache(dns->sdns);
1211 pdns = dns->sdns->pdns_primary;
1212 }
1213 else
1214 {
1215 pdns = dns->pdns;
1216 }
1217
1218 return _pdns_search_list_domain(pdns, i);
1219 }
1220
1221 static int
1222 _pdns_delay(sdns_handle_t *sdns)
1223 {
1224 int status, n, snooze;
1225 time_t tick;
1226
1227 if (sdns == NULL) return 0;
1228
1229 snooze = 0;
1230 n = 0;
1231
1232 /* No delay if we are not receiving notifications */
1233 if (sdns->notify_delay_token == -1) return 0;
1234
1235 if (sdns->dns_delay == 0)
1236 {
1237 status = notify_check(sdns->notify_delay_token, &n);
1238 if ((status == NOTIFY_STATUS_OK) && (n == 1))
1239 {
1240 /*
1241 * First thread to hit this condition sleeps for DNS_DELAY_INTERVAL seconds
1242 */
1243 sdns->dns_delay = time(NULL) + DNS_DELAY_INTERVAL;
1244 snooze = DNS_DELAY_INTERVAL;
1245 }
1246 }
1247 else
1248 {
1249 tick = time(NULL);
1250 /*
1251 * Subsequent threads sleep for the remaining duration.
1252 * We add one to round up the interval since our garnularity is coarse.
1253 */
1254 snooze = 1 + (sdns->dns_delay - tick);
1255 if (snooze < 0) snooze = 0;
1256 }
1257
1258 if (snooze == 0) return 0;
1259
1260 sleep(snooze);
1261
1262 /* When exiting, first thread in resets the delay condition */
1263 if (n == 1) sdns->dns_delay = 0;
1264
1265 return 0;
1266 }
1267
1268 static int
1269 _pdns_query(sdns_handle_t *sdns, pdns_handle_t *pdns, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min)
1270 {
1271 int n;
1272
1273 if (name == NULL) return -1;
1274 if (pdns == NULL) return -1;
1275
1276 if (pdns->flags & DNS_FLAG_FORWARD_TO_MDNSRESPONDER)
1277 {
1278 n = res_query_mDNSResponder(pdns->res, name, class, type, (u_char *)buf, len, from, fromlen);
1279 if ((n < 0) && (min != NULL)) *min = MDNS_MIN_TTL;
1280 return n;
1281 }
1282
1283 if (pdns->res == NULL) return -1;
1284 if (pdns->res->nscount == 0) return -1;
1285
1286 if ((type == ns_t_aaaa) && ((pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) == 0) && (pdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA)) return -1;
1287
1288 _pdns_delay(sdns);
1289
1290 /* BIND_9 API */
1291 return res_nquery_soa_min(pdns->res, name, class, type, (u_char *)buf, len, from, (int32_t *)fromlen, min);
1292 }
1293
1294 __private_extern__ int
1295 _pdns_search(sdns_handle_t *sdns, pdns_handle_t *pdns, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen)
1296 {
1297 char *dot, *qname;
1298 int append, status;
1299
1300 if (name == NULL) return -1;
1301 if (pdns == NULL) return -1;
1302 if (pdns->res == NULL) return -1;
1303 if (pdns->res->nscount == 0) return -1;
1304
1305 if ((type == ns_t_aaaa) && ((pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) == 0) && (pdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA)) return -1;
1306
1307 qname = NULL;
1308 append = 1;
1309
1310 /*
1311 * don't append my name if:
1312 * - my name is NULL
1313 * - input name is qualified (i.e. not single component)
1314 * - there is a search list
1315 * - there is a domain name
1316 */
1317
1318 if (pdns->name == NULL) append = 0;
1319
1320 if (append == 1)
1321 {
1322 dot = strrchr(name, '.');
1323 if (dot != NULL) append = 0;
1324 }
1325
1326 if (append == 1)
1327 {
1328 if (pdns->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(pdns);
1329 if (pdns->search_count > 0) append = 0;
1330 }
1331
1332 if ((append == 1) && (pdns->res->defdname != NULL) && (pdns->res->defdname[0] != '\0')) append = 0;
1333
1334 status = -1;
1335 if (append == 0)
1336 {
1337 /* BIND_9 API */
1338 _pdns_delay(sdns);
1339
1340 status = __res_nsearch_list_2(pdns->res, name, class, type, (u_char *)buf, len, from, fromlen, pdns->search_count, pdns->search_list);
1341 }
1342 else
1343 {
1344 _pdns_delay(sdns);
1345
1346 qname = NULL;
1347 asprintf(&qname, "%s.%s.", name, pdns->name);
1348 if (qname == NULL) return -1;
1349
1350 /* BIND_9 API */
1351 status = res_nsearch_2(pdns->res, qname, class, type, (u_char *)buf, len, from, fromlen);
1352 free(qname);
1353 }
1354
1355 return status;
1356 }
1357
1358 static int
1359 _sdns_send(sdns_handle_t *sdns, const char *name, uint32_t class, uint32_t type, uint32_t fqdn, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min)
1360 {
1361 char *qname;
1362 pdns_handle_t **pdns;
1363 uint32_t pdns_count;
1364 int i, n, m;
1365
1366 pdns = NULL;
1367 pdns_count = 0;
1368 n = -1;
1369
1370 pdns_count = _pdns_get_handles_for_name(sdns, name, &pdns);
1371
1372 if (pdns_count == 0) return -1;
1373
1374 qname = NULL;
1375 asprintf(&qname, "%s%s", name, (fqdn == 0) ? "." : "");
1376 if (qname == NULL) return -1;
1377
1378 for (i = 0; i < pdns_count; i++)
1379 {
1380 m = -1;
1381 n = _pdns_query(sdns, pdns[i], qname, class, type, buf, len, from, fromlen, &m);
1382 if (min != NULL)
1383 {
1384 if (*min == -1) *min = m;
1385 else if ((m >= 0) && (m < *min)) *min = m;
1386 }
1387
1388 if (n > 0) break;
1389 }
1390
1391 free(pdns);
1392 free(qname);
1393 return n;
1394 }
1395
1396 __private_extern__ int
1397 _sdns_search(sdns_handle_t *sdns, const char *name, uint32_t class, uint32_t type, uint32_t fqdn, uint32_t recurse, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min)
1398 {
1399 pdns_handle_t *primary, **pdns;
1400 int i, n, ndots, status, m;
1401 char *dot, *qname;
1402 uint32_t pdns_count;
1403
1404 if (sdns == NULL) return -1;
1405 if (name == NULL) return -1;
1406
1407 /* ndots is the threshold for trying a qualified name "as is" */
1408 ndots = 1;
1409 primary = sdns->pdns_primary;
1410 if ((primary != NULL) && (primary->res != NULL)) ndots = primary->res->ndots;
1411
1412 /* count dots in input name, and keep track of the location of the last dot */
1413 n = 0;
1414 dot = NULL;
1415
1416 for (i = 0; name[i] != '\0'; i++)
1417 {
1418 if (name[i] == '.')
1419 {
1420 n++;
1421 dot = (char *)(name + i);
1422 }
1423 }
1424
1425 /* the last dot is the last character, name is fully qualified */
1426 if ((fqdn == 0) && (dot != NULL) && (*(dot + 1) == '\0')) fqdn = 1;
1427
1428 /*
1429 * If n >= ndots, or it's a FQDN, or if it's a PTR query,
1430 * we try a query with the name "as is".
1431 */
1432 if ((n >= ndots) || (fqdn == 1) || (type == ns_t_ptr))
1433 {
1434 status = _sdns_send(sdns, name, class, type, fqdn, buf, len, from, fromlen, min);
1435 if (status > 0) return status;
1436 }
1437
1438 /* end of the line for FQDNs or PTR queries */
1439 if (fqdn == 1) return -1;
1440 if (type == ns_t_ptr) return -1;
1441
1442 if (recurse == 0) return -1;
1443 if (primary == NULL) return -1;
1444
1445 /* Try appending names from the search list */
1446 if (primary->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(primary);
1447 n = primary->search_count;
1448 if (n > 0)
1449 {
1450 /* Try qualifying with each name in the search list */
1451 for (i = 0; i < n ; i++)
1452 {
1453 qname = NULL;
1454 asprintf(&qname, "%s.%s", name, primary->search_list[i]);
1455 if (qname == NULL) return -1;
1456
1457 m = -1;
1458 status = _sdns_search(sdns, qname, class, type, fqdn, 0, buf, len, from, fromlen, &m);
1459 {
1460 if (*min == -1) *min = m;
1461 else if ((m >= 0) && (m < *min)) *min = m;
1462 }
1463
1464 free(qname);
1465 if (status > 0) return status;
1466 }
1467
1468 return -1;
1469 }
1470
1471 /*
1472 * We get here if the name is not fully qualified (no trailing dot), and there is no search list.
1473 * Try each default client, qualifying with that client's name.
1474 */
1475 pdns = NULL;
1476 pdns_count = _pdns_get_default_handles(sdns, &pdns);
1477 status = -1;
1478
1479 if (pdns_count == 0) return -1;
1480
1481 for (i = 0; i < pdns_count; i++)
1482 {
1483 qname = NULL;
1484 if (pdns[i]->name == NULL) asprintf(&qname, "%s", name);
1485 else asprintf(&qname, "%s.%s", name, pdns[i]->name);
1486 if (qname == NULL) return -1;
1487
1488 m = -1;
1489 status = _pdns_query(sdns, pdns[i], qname, class, type, buf, len, from, fromlen, min);
1490 {
1491 if (*min == -1) *min = m;
1492 else if ((m >= 0) && (m < *min)) *min = m;
1493 }
1494
1495 free(qname);
1496 if (status > 0) break;
1497 }
1498
1499 free(pdns);
1500 return status;
1501 }
1502
1503 int
1504 dns_query(dns_handle_t d, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen)
1505 {
1506 dns_private_handle_t *dns;
1507 int status, unused;
1508
1509 if (d == NULL) return -1;
1510 if (name == NULL) return -1;
1511 dns = (dns_private_handle_t *)d;
1512
1513 status = -1;
1514 unused = 0;
1515
1516 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
1517 {
1518 _check_cache(dns->sdns);
1519 status = _sdns_search(dns->sdns, name, class, type, 1, 1, buf, len, from, fromlen, &unused);
1520 }
1521 else
1522 {
1523 status = _pdns_query(dns->sdns, dns->pdns, name, class, type, buf, len, from, fromlen, &unused);
1524 }
1525
1526 return status;
1527 }
1528
1529
1530 int
1531 dns_search(dns_handle_t d, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen)
1532 {
1533 dns_private_handle_t *dns;
1534 int status, unused;
1535
1536 if (d == NULL) return -1;
1537 if (name == NULL) return -1;
1538 dns = (dns_private_handle_t *)d;
1539
1540 status = -1;
1541 unused = 0;
1542
1543 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER)
1544 {
1545 _check_cache(dns->sdns);
1546 status = _sdns_search(dns->sdns, name, class, type, 0, 1, buf, len, from, fromlen, &unused);
1547 }
1548 else
1549 {
1550 status = _pdns_search(dns->sdns, dns->pdns, name, class, type, buf, len, from, fromlen);
1551 }
1552
1553 return status;
1554 }
1555
1556 /*
1557 * PRIVATE
1558 */
1559
1560 uint32_t
1561 dns_server_list_count(dns_handle_t d)
1562 {
1563 dns_private_handle_t *dns;
1564 res_state r;
1565
1566 if (d == NULL) return 0;
1567 dns = (dns_private_handle_t *)d;
1568
1569 if (dns->handle_type != DNS_PRIVATE_HANDLE_TYPE_PLAIN) return 0;
1570
1571 if (dns->pdns == NULL) return 0;
1572
1573 r = dns->pdns->res;
1574 if (r == NULL) return 0;
1575
1576 return r->nscount;
1577 }
1578
1579 struct sockaddr *
1580 dns_server_list_address(dns_handle_t d, uint32_t i)
1581 {
1582 dns_private_handle_t *dns;
1583 res_state r;
1584 struct sockaddr_storage *s;
1585 struct sockaddr *sa;
1586
1587 if (d == NULL) return NULL;
1588 dns = (dns_private_handle_t *)d;
1589
1590 if (dns->handle_type != DNS_PRIVATE_HANDLE_TYPE_PLAIN) return NULL;
1591
1592 if (dns->pdns == NULL) return NULL;
1593
1594 r = dns->pdns->res;
1595 if (r == NULL) return NULL;
1596
1597 if (i >= r->nscount) return NULL;
1598 sa = get_nsaddr(r, i);
1599 if (sa == NULL) return NULL;
1600
1601 s = (struct sockaddr_storage *)calloc(1, sizeof(struct sockaddr_storage));
1602 if (s == NULL) return NULL;
1603
1604 memcpy(s, sa, sizeof(struct sockaddr_storage));
1605 return (struct sockaddr *)s;
1606 }