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