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